Browse Source

Add support for shortcuts in WPF menus.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0wpf@3387 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
7a636e57d3
  1. 42
      src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs
  2. 2
      src/Main/Base/Project/Src/Gui/App.xaml
  3. 3
      src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs
  4. 27
      src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs
  5. 2
      src/Main/Base/Project/Src/TextEditor/Gui/Dialogs/GotoDialog.cs
  6. 47
      src/Main/ICSharpCode.Core.Presentation/CommandService.cs
  7. 1
      src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj
  8. 6
      src/Main/ICSharpCode.Core.Presentation/Menu/CoreMenuItem.cs
  9. 12
      src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs
  10. 24
      src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs
  11. 6
      src/Main/ICSharpCode.Core.Presentation/PixelSnapper.cs
  12. 15
      src/Main/ICSharpCode.Core.Presentation/PresentationResourceService.cs
  13. 6
      src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs

42
src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs

@ -9,6 +9,7 @@ using System; @@ -9,6 +9,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using ICSharpCode.Core;
@ -260,8 +261,8 @@ namespace ICSharpCode.SharpDevelop.Commands @@ -260,8 +261,8 @@ namespace ICSharpCode.SharpDevelop.Commands
}
if (tool.PromptForArguments) {
args = MessageService.ShowInputBox(tool.MenuCommand, "${res:XML.MainMenu.ToolMenu.ExternalTools.EnterArguments}", args);
if (args == null)
args = MessageService.ShowInputBox(tool.MenuCommand, "${res:XML.MainMenu.ToolMenu.ExternalTools.EnterArguments}", args);
if (args == null)
return;
}
@ -479,27 +480,26 @@ namespace ICSharpCode.SharpDevelop.Commands @@ -479,27 +480,26 @@ namespace ICSharpCode.SharpDevelop.Commands
padDescriptor.BringPadToFront();
}
}
class MyWpfMenuItem : System.Windows.Controls.MenuItem
class BringPadToFrontCommand : System.Windows.Input.ICommand
{
PadDescriptor padDescriptor;
public MyWpfMenuItem(PadDescriptor padDescriptor)
public BringPadToFrontCommand(PadDescriptor padDescriptor)
{
this.padDescriptor = padDescriptor;
this.Header = ICSharpCode.Core.Presentation.MenuService.ConvertLabel(StringParser.Parse(padDescriptor.Title));
if (!string.IsNullOrEmpty(padDescriptor.Icon)) {
this.Icon = PresentationResourceService.GetImage(padDescriptor.Icon);
}
if (padDescriptor.Shortcut != null) {
this.InputGestureText = padDescriptor.Shortcut;
}
}
protected override void OnClick()
public event EventHandler CanExecuteChanged { add {} remove {} }
public void Execute(object parameter)
{
base.OnClick();
padDescriptor.BringPadToFront();
}
public bool CanExecute(object parameter)
{
return true;
}
}
protected abstract string Category {
@ -522,7 +522,21 @@ namespace ICSharpCode.SharpDevelop.Commands @@ -522,7 +522,21 @@ namespace ICSharpCode.SharpDevelop.Commands
ArrayList list = new ArrayList();
foreach (PadDescriptor padContent in WorkbenchSingleton.Workbench.PadContentCollection) {
if (padContent.Category == Category) {
list.Add(new MyWpfMenuItem(padContent));
var item = new System.Windows.Controls.MenuItem();
item.Header = ICSharpCode.Core.Presentation.MenuService.ConvertLabel(StringParser.Parse(padContent.Title));
if (!string.IsNullOrEmpty(padContent.Icon)) {
item.Icon = PresentationResourceService.GetPixelSnappedImage(padContent.Icon);
}
item.Command = new BringPadToFrontCommand(padContent);
if (!string.IsNullOrEmpty(padContent.Shortcut)) {
var kg = Core.Presentation.MenuService.ParseShortcut(padContent.Shortcut);
WorkbenchSingleton.MainWindow.InputBindings.Add(
new System.Windows.Input.InputBinding(item.Command, kg)
);
item.InputGestureText = kg.GetDisplayStringForCulture(Thread.CurrentThread.CurrentUICulture);
}
list.Add(item);
}
}
return list;

2
src/Main/Base/Project/Src/Gui/App.xaml

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
<Style TargetType="{x:Type Image}" x:Key="{x:Static core:ToolBarService.ImageStyleKey}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type Button}, AncestorLevel=1}, Path=IsEnabled}" Value="False">
<Setter Property="Opacity" Value="0.50" />
<Setter Property="Opacity" Value="0.30" />
</DataTrigger>
</Style.Triggers>
</Style>

3
src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs

@ -13,6 +13,7 @@ using System.IO; @@ -13,6 +13,7 @@ using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using AvalonDock;
@ -89,6 +90,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -89,6 +90,7 @@ namespace ICSharpCode.SharpDevelop.Gui
ActiveViewContentChanged(this, EventArgs.Empty);
}
oldActiveViewContent = newActiveViewContent;
CommandManager.InvalidateRequerySuggested();
}
sealed class ViewContentCollection : Collection<IViewContent>
@ -342,6 +344,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -342,6 +344,7 @@ namespace ICSharpCode.SharpDevelop.Gui
dockLayout.DocumentPane.Items.Remove(this);
Dispose();
CommandManager.InvalidateRequerySuggested();
return true;
}

27
src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs

@ -5,14 +5,16 @@ @@ -5,14 +5,16 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.Core.Presentation;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using System.Windows.Input;
namespace ICSharpCode.SharpDevelop.Gui
{
@ -62,7 +64,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -62,7 +64,7 @@ namespace ICSharpCode.SharpDevelop.Gui
}
}
mainMenu.ItemsSource = MenuService.CreateMenuItems(this, mainMenuPath);
mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath);
toolBars = ToolBarService.CreateToolBars(this, "/SharpDevelop/Workbench/ToolBar");
foreach (ToolBar tb in toolBars) {
@ -72,12 +74,29 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -72,12 +74,29 @@ namespace ICSharpCode.SharpDevelop.Gui
DockPanel.SetDock(StatusBarService.Control, Dock.Bottom);
dockPanel.Children.Insert(dockPanel.Children.Count - 2, StatusBarService.Control);
UpdateMenu();
requerySuggestedEventHandler = new EventHandler(CommandManager_RequerySuggested);
CommandManager.RequerySuggested += requerySuggestedEventHandler;
StatusBarService.SetMessage("${res:MainWindow.StatusBar.ReadyMessage}");
}
// keep a reference to the event handler to prevent it from being gargabe collected
// (CommandManager.RequerySuggested only keeps weak references to the event handlers)
EventHandler requerySuggestedEventHandler;
void CommandManager_RequerySuggested(object sender, EventArgs e)
{
UpdateMenu();
}
void UpdateMenu()
{
MenuService.UpdateStatus(mainMenu.ItemsSource);
foreach (ToolBar tb in toolBars) {
ToolBarService.UpdateStatus(tb.ItemsSource);
}
StatusBarService.SetMessage("${res:MainWindow.StatusBar.ReadyMessage}");
}
public ICollection<IViewContent> ViewContentCollection {

2
src/Main/Base/Project/Src/TextEditor/Gui/Dialogs/GotoDialog.cs

@ -56,7 +56,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -56,7 +56,7 @@ namespace ICSharpCode.SharpDevelop.Gui
this.Content = new StackPanel {
Orientation = Orientation.Horizontal,
Children = {
PresentationResourceService.GetImage(ClassBrowserIconService.ResourceNames[imageIndex]),
PresentationResourceService.GetPixelSnappedImage(ClassBrowserIconService.ResourceNames[imageIndex]),
new TextBlock {
Text = text,
Margin = new Thickness(4, 0, 0, 0)

47
src/Main/ICSharpCode.Core.Presentation/CommandService.cs

@ -1,47 +0,0 @@ @@ -1,47 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace ICSharpCode.Core.Presentation
{
/// <summary>
/// Provides access to the RoutedUICommand objects for commands defined in the addin-tree.
/// </summary>
public static class CommandService
{
static Dictionary<string, RoutedUICommand> dict = new Dictionary<string, RoutedUICommand>();
public static RoutedUICommand GetCommand(string className)
{
if (className == null)
throw new ArgumentNullException("className");
if (className.Length == 0)
throw new ArgumentException("className must not be the empty string");
lock (dict) {
RoutedUICommand cmd;
if (!dict.TryGetValue(className, out cmd)) {
dict[className] = cmd = new RoutedUICommand(className, className, typeof(CommandService));
}
return cmd;
}
}
public static RoutedUICommand GetCommand(Type commandClass)
{
if (commandClass == null)
throw new ArgumentNullException("commandClass");
if (!typeof(ICommand).IsAssignableFrom(commandClass))
throw new ArgumentException("commandClass must implement ICommand", "commandClass");
return GetCommand(commandClass.FullName);
}
}
}

1
src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj

@ -59,7 +59,6 @@ @@ -59,7 +59,6 @@
<Compile Include="..\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="CommandService.cs" />
<Compile Include="ConditionalSeparator.cs" />
<Compile Include="GetBitmapExtension.cs" />
<Compile Include="IStatusUpdate.cs" />

6
src/Main/ICSharpCode.Core.Presentation/Menu/CoreMenuItem.cs

@ -28,11 +28,9 @@ namespace ICSharpCode.Core.Presentation @@ -28,11 +28,9 @@ namespace ICSharpCode.Core.Presentation
if (codon.Properties.Contains("icon")) {
try {
Image image = PresentationResourceService.GetImage(codon.Properties["icon"]);
var image = PresentationResourceService.GetImage(codon.Properties["icon"]);
image.Height = 16;
this.Icon = new PixelSnapper {
Child = image
};
this.Icon = new PixelSnapper(image);
} catch (ResourceNotFoundException) {}
}
this.SubmenuOpened += CoreMenuItem_SubmenuOpened;

12
src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
using System;
using System.Collections;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@ -72,7 +73,7 @@ namespace ICSharpCode.Core.Presentation @@ -72,7 +73,7 @@ namespace ICSharpCode.Core.Presentation
if (canExecuteChanged == null && value != null) {
//LoggingService.Debug("Attach CommandManager_RequerySuggested " + codon.Id);
if (requerySuggestedEventHandler == null)
requerySuggestedEventHandler = CommandManager_RequerySuggested;
requerySuggestedEventHandler = new EventHandler(CommandManager_RequerySuggested);
CommandManager.RequerySuggested += requerySuggestedEventHandler;
}
canExecuteChanged += value;
@ -117,9 +118,16 @@ namespace ICSharpCode.Core.Presentation @@ -117,9 +118,16 @@ namespace ICSharpCode.Core.Presentation
class MenuCommand : CoreMenuItem
{
public MenuCommand(Codon codon, object caller, bool createCommand) : base(codon, caller)
public MenuCommand(UIElement inputBindingOwner, Codon codon, object caller, bool createCommand) : base(codon, caller)
{
this.Command = new CommandWrapper(codon, caller, createCommand);
if (!string.IsNullOrEmpty(codon.Properties["shortcut"])) {
KeyGesture kg = MenuService.ParseShortcut(codon.Properties["shortcut"]);
inputBindingOwner.InputBindings.Add(
new InputBinding(this.Command, kg)
);
this.InputGestureText = kg.GetDisplayStringForCulture(Thread.CurrentThread.CurrentUICulture);
}
}
}
}

24
src/Main/ICSharpCode.Core.Presentation/Menu/MenuService.cs

@ -8,7 +8,9 @@ @@ -8,7 +8,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace ICSharpCode.Core.Presentation
{
@ -33,16 +35,16 @@ namespace ICSharpCode.Core.Presentation @@ -33,16 +35,16 @@ namespace ICSharpCode.Core.Presentation
return null;
}
public static IList CreateMenuItems(object owner, string addInTreePath)
public static IList CreateMenuItems(UIElement inputBindingOwner, object owner, string addInTreePath)
{
return CreateMenuItems(AddInTree.BuildItems<MenuItemDescriptor>(addInTreePath, owner, false));
return CreateMenuItems(inputBindingOwner, AddInTree.BuildItems<MenuItemDescriptor>(addInTreePath, owner, false));
}
internal static IList CreateMenuItems(IEnumerable descriptors)
internal static IList CreateMenuItems(UIElement inputBindingOwner, IEnumerable descriptors)
{
ArrayList result = new ArrayList();
foreach (MenuItemDescriptor descriptor in descriptors) {
object item = CreateMenuItemFromDescriptor(descriptor);
object item = CreateMenuItemFromDescriptor(inputBindingOwner, descriptor);
if (item is IMenuItemBuilder) {
IMenuItemBuilder submenuBuilder = (IMenuItemBuilder)item;
result.AddRange(submenuBuilder.BuildItems(descriptor.Codon, descriptor.Caller));
@ -53,7 +55,7 @@ namespace ICSharpCode.Core.Presentation @@ -53,7 +55,7 @@ namespace ICSharpCode.Core.Presentation
return result;
}
static object CreateMenuItemFromDescriptor(MenuItemDescriptor descriptor)
static object CreateMenuItemFromDescriptor(UIElement inputBindingOwner, MenuItemDescriptor descriptor)
{
Codon codon = descriptor.Codon;
string type = codon.Properties.Contains("type") ? codon.Properties["type"] : "Command";
@ -67,10 +69,10 @@ namespace ICSharpCode.Core.Presentation @@ -67,10 +69,10 @@ namespace ICSharpCode.Core.Presentation
//return new MenuCheckBox(codon, descriptor.Caller);
case "Item":
case "Command":
return new MenuCommand(codon, descriptor.Caller, createCommand);
return new MenuCommand(inputBindingOwner, codon, descriptor.Caller, createCommand);
case "Menu":
return new CoreMenuItem(codon, descriptor.Caller) {
ItemsSource = CreateMenuItems(descriptor.SubItems)
ItemsSource = CreateMenuItems(inputBindingOwner, descriptor.SubItems)
};
case "Builder":
return codon.AddIn.CreateObject(codon.Properties["class"]);
@ -86,5 +88,13 @@ namespace ICSharpCode.Core.Presentation @@ -86,5 +88,13 @@ namespace ICSharpCode.Core.Presentation
// HACK: find a better way to allow the host app to process link commands
public static Converter<string, ICommand> LinkCommandCreator;
/// <summary>
/// Creates an KeyGesture for a shortcut.
/// </summary>
public static KeyGesture ParseShortcut(string text)
{
return (KeyGesture)new KeyGestureConverter().ConvertFromInvariantString(text.Replace(',', '+').Replace('|', '+'));
}
}
}

6
src/Main/ICSharpCode.Core.Presentation/PixelSnapper.cs

@ -21,6 +21,12 @@ namespace ICSharpCode.Core.Presentation @@ -21,6 +21,12 @@ namespace ICSharpCode.Core.Presentation
LayoutUpdated += new EventHandler(OnLayoutUpdated);
}
public PixelSnapper(UIElement visualChild)
: this()
{
this.Child = visualChild;
}
UIElement _visualChild;
/// <summary>

15
src/Main/ICSharpCode.Core.Presentation/PresentationResourceService.cs

@ -38,6 +38,21 @@ namespace ICSharpCode.Core.Presentation @@ -38,6 +38,21 @@ namespace ICSharpCode.Core.Presentation
};
}
/// <summary>
/// Creates a new PixelSnapper object containing the image with the
/// specified resource name.
/// </summary>
/// <param name="name">
/// The name of the requested bitmap.
/// </param>
/// <exception cref="ResourceNotFoundException">
/// Is thrown when the GlobalResource manager can't find a requested resource.
/// </exception>
public static PixelSnapper GetPixelSnappedImage(string name)
{
return new PixelSnapper(GetImage(name));
}
/// <summary>
/// Returns a BitmapSource from the resource database, it handles localization
/// transparent for the user.

6
src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs

@ -29,12 +29,10 @@ namespace ICSharpCode.Core.Presentation @@ -29,12 +29,10 @@ namespace ICSharpCode.Core.Presentation
this.Command = new CommandWrapper(codon, caller, createCommand);
if (codon.Properties.Contains("icon")) {
Image image = PresentationResourceService.GetImage(StringParser.Parse(codon.Properties["icon"]));
var image = PresentationResourceService.GetImage(StringParser.Parse(codon.Properties["icon"]));
image.Height = 16;
image.SetResourceReference(StyleProperty, ToolBarService.ImageStyleKey);
this.Content = new PixelSnapper {
Child = image
};
this.Content = new PixelSnapper(image);
}
UpdateText();

Loading…
Cancel
Save