Add keyboard shortcuts for Display As options

This commit is contained in:
Benjamin Popp 2021-05-09 22:24:06 -05:00
parent 08472cb0a0
commit 5d3fdfdab3
9 changed files with 149 additions and 14 deletions

View File

@ -107,6 +107,7 @@
<Compile Include="ViewModels\QuickEditItems\QuickEditItemDecorator.cs" />
<Compile Include="ViewModels\QuickEditItems\UpdateDexConversionTable.cs" />
<Compile Include="ViewModels\QuickEditItems\ReorderDex.cs" />
<Compile Include="ViewModels\Shortcuts.cs" />
<Compile Include="ViewModels\Tools\BitListArrayElementViewModel.cs" />
<Compile Include="ViewModels\Tools\ButtonArrayElementViewModel.cs" />
<Compile Include="ViewModels\Tools\CodeTool.cs" />

View File

@ -62,6 +62,10 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
resetTheme = new StubCommand(),
clearError = new StubCommand(),
clearMessage = new StubCommand(),
displayAsText = new StubCommand(),
displayAsEventScript = new StubCommand(),
displayAsSprite = new StubCommand(),
displayAsColorPalette = new StubCommand(),
toggleMatrix = new StubCommand(),
toggleScrollAnimation = new StubCommand(),
toggleTableHeaders = new StubCommand();
@ -104,6 +108,10 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public ICommand ResetTheme => resetTheme;
public ICommand ClearError => clearError;
public ICommand ClearMessage => clearMessage;
public ICommand DisplayAsText => displayAsText;
public ICommand DisplayAsEventScript => displayAsEventScript;
public ICommand DisplayAsSprite => displayAsSprite;
public ICommand DisplayAsColorPalette => displayAsColorPalette;
public ICommand ToggleMatrix => toggleMatrix;
public ICommand ToggleScrollAnimation => toggleScrollAnimation;
public ICommand ToggleTableHeaders => toggleTableHeaders;
@ -423,6 +431,10 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
back = CreateWrapperForSelected(tab => tab.Back);
forward = CreateWrapperForSelected(tab => tab.Forward);
resetAlignment = CreateWrapperForSelected(tab => tab.ResetAlignment);
displayAsText = CreateWrapperForSelected(tab => (tab as ViewPort)?.Shortcuts.DisplayAsText);
displayAsEventScript = CreateWrapperForSelected(tab => (tab as ViewPort)?.Shortcuts.DisplayAsEventScript);
displayAsSprite = CreateWrapperForSelected(tab => (tab as ViewPort)?.Shortcuts.DisplayAsSprite);
displayAsColorPalette = CreateWrapperForSelected(tab => (tab as ViewPort)?.Shortcuts.DisplayAsColorPalette);
saveAll = CreateWrapperForAll(tab => tab.Save);
closeAll = CreateWrapperForAll(tab => tab.Close);
@ -442,6 +454,10 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
{ tab => tab.Back, (sender, e) => back.CanExecuteChanged.Invoke(this, e) },
{ tab => tab.Forward, (sender, e) => forward.CanExecuteChanged.Invoke(this, e) },
{ tab => tab.ResetAlignment, (sender, e) => resetAlignment.CanExecuteChanged.Invoke(this, e) },
{ tab => (tab as ViewPort)?.Shortcuts.DisplayAsText, (sender, e) => displayAsText.RaiseCanExecuteChanged() },
{ tab => (tab as ViewPort)?.Shortcuts.DisplayAsEventScript, (sender, e) => displayAsEventScript.RaiseCanExecuteChanged() },
{ tab => (tab as ViewPort)?.Shortcuts.DisplayAsSprite, (sender, e) => displayAsSprite.RaiseCanExecuteChanged() },
{ tab => (tab as ViewPort)?.Shortcuts.DisplayAsColorPalette, (sender, e) => displayAsColorPalette.RaiseCanExecuteChanged() },
};
var metadata = fileSystem.MetadataFor(ApplicationName) ?? new string[0];

View File

@ -0,0 +1,42 @@
using HavenSoft.HexManiac.Core.Models.Runs;
using System.Windows.Input;
using static HavenSoft.HexManiac.Core.ICommandExtensions;
namespace HavenSoft.HexManiac.Core.ViewModels {
public class Shortcuts : ViewModelCore {
private StubCommand displayAsEventScript, displayAsText, displayAsSprite, displayAsColorPalette;
public ViewPort ViewPort { get; }
public ICommand DisplayAsEventScript => StubCommand(ref displayAsEventScript, ExecuteDisplayAsEventScript, CanExecuteDisplayAs);
public ICommand DisplayAsText=> StubCommand(ref displayAsText, ExecuteDisplayAsText, CanExecuteDisplayAs);
public ICommand DisplayAsSprite=> StubCommand(ref displayAsSprite, ExecuteDisplayAsSprite, CanExecuteDisplayAs);
public ICommand DisplayAsColorPalette=> StubCommand(ref displayAsColorPalette, ExecuteDisplayAsColorPalette, CanExecuteDisplayAs);
public Shortcuts(ViewPort viewPort) => ViewPort = viewPort;
private bool CanExecuteDisplayAs() {
var spot = ViewPort.ConvertViewPointToAddress(ViewPort.SelectionStart);
var nextRun = ViewPort.Model.GetNextRun(spot);
return nextRun.Start > spot || nextRun is NoInfoRun;
}
private void ExecuteDisplayAsEventScript() {
ViewPort.Tools.CodeTool.IsEventScript.Execute();
ViewPort.Refresh();
ViewPort.UpdateToolsFromSelection(ViewPort.ConvertViewPointToAddress(ViewPort.SelectionStart));
}
private void ExecuteDisplayAsText() {
ViewPort.IsText.Execute();
}
private void ExecuteDisplayAsSprite() {
ViewPort.Tools.SpriteTool.IsSprite.Execute();
}
private void ExecuteDisplayAsColorPalette() {
ViewPort.Tools.SpriteTool.IsPalette.Execute();
}
}
}

View File

@ -675,6 +675,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public event EventHandler RequestMenuClose;
#pragma warning restore 0067
public Shortcuts Shortcuts { get; }
#region Constructors
public ViewPort() : this(new LoadedFile(string.Empty, new byte[0])) { }
@ -712,6 +714,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
ImplementCommands();
if (changeHistory == null) CascadeScripts(); // if we're sharing history with another viewmodel, our model has already been updated like this.
RefreshBackingData();
Shortcuts = new Shortcuts(this);
}
public ViewPort(LoadedFile file) : this(file.Name, new BasicModel(file.Contents), InstantDispatch.Instance) { }

View File

@ -68,14 +68,10 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Visitors {
public void Visit(None dataFormat, byte data) {
Results.Add(new ContextItemGroup("Display As...") {
new ContextItem("Text", ViewPort.IsText.Execute),
new ContextItem("Sprite", ViewPort.Tools.SpriteTool.IsSprite.Execute),
new ContextItem("Palette", ViewPort.Tools.SpriteTool.IsPalette.Execute),
new ContextItem("Event Script", arg => {
ViewPort.Tools.CodeTool.IsEventScript.Execute();
ViewPort.Refresh();
ViewPort.UpdateToolsFromSelection(ViewPort.ConvertViewPointToAddress(ViewPort.SelectionStart));
}),
new ContextItem("Text", ViewPort.Shortcuts.DisplayAsText.Execute) { ShortcutText = "Ctrl+D, T" },
new ContextItem("Sprite", ViewPort.Shortcuts.DisplayAsSprite.Execute) { ShortcutText = "Ctrl+D, S" },
new ContextItem("Color Palette", ViewPort.Shortcuts.DisplayAsColorPalette.Execute) { ShortcutText = "Ctrl+D, C" },
new ContextItem("Event Script", ViewPort.Shortcuts.DisplayAsEventScript.Execute) { ShortcutText = "Ctrl+D, E" },
});
if (data == 0xFF && ViewPort.SelectionEnd == ViewPort.SelectionStart && ViewPort[ViewPort.SelectionStart].Format is None) Results.Add(new ContextItemGroup("Create New...") {

View File

@ -363,7 +363,7 @@ namespace HavenSoft.HexManiac.Tests {
ViewPort.Edit("^bob @20 ^tom @bob ");
var items = ViewPort.GetContextMenuItems(new Point(0, 0));
var item = items.Single(element => element.Text == "Display As...");
item = ((ContextItemGroup)item).Single(element => element.Text == "Palette");
item = ((ContextItemGroup)item).Single(element => element.Text == "Color Palette");
item.Command.Execute();
var anchor = Model.GetAnchorFromAddress(-1, 0);
@ -485,7 +485,7 @@ namespace HavenSoft.HexManiac.Tests {
var items = ViewPort.GetContextMenuItems(new Point(0, 0));
var item = items.Single(element => element.Text == "Display As...");
item = ((ContextItemGroup)item).Single(element => element.Text == "Palette");
item = ((ContextItemGroup)item).Single(element => element.Text == "Color Palette");
var makePalette = item.Command;
makePalette.Execute();
@ -498,7 +498,7 @@ namespace HavenSoft.HexManiac.Tests {
var items = ViewPort.GetContextMenuItems(new Point(0, 0));
var item = items.Single(element => element.Text == "Display As...");
item = ((ContextItemGroup)item).Single(element => element.Text == "Palette");
item = ((ContextItemGroup)item).Single(element => element.Text == "Color Palette");
var makePalette = item.Command;
makePalette.Execute();
@ -654,7 +654,7 @@ namespace HavenSoft.HexManiac.Tests {
ViewPort.SelectionStart = new Point(1, 0);
var group = (ContextItemGroup)ViewPort.GetContextMenuItems(new Point(1, 0)).Single(item => item.Text == "Display As...");
var contextItem = group.Single(item => item.Text == "Palette");
var contextItem = group.Single(item => item.Text == "Color Palette");
contextItem.Command.Execute();
Assert.Equal(ViewPort.Tools.SpriteTool, ViewPort.Tools.SelectedTool);

View File

@ -91,6 +91,7 @@
<DependentUpon>TextBoxLookAlike.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\TileImage.cs" />
<Compile Include="Resources\MultiKeyGesture.cs" />
<Compile Include="Windows\OptionDialog.xaml.cs">
<DependentUpon>OptionDialog.xaml</DependentUpon>
</Compile>

View File

@ -0,0 +1,65 @@
using HavenSoft.HexManiac.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using System.Windows.Markup;
namespace HavenSoft.HexManiac.WPF.Resources {
public class MultiKeyGesture : KeyGesture {
private readonly ModifierKeys mods;
private readonly IReadOnlyList<Key> keys;
private int nextKey;
public MultiKeyGesture(ModifierKeys mods, params Key[] keys) : base(keys[0], mods) {
this.mods = mods;
this.keys = keys;
}
public override bool Matches(object targetElement, InputEventArgs inputEventArgs) {
if (!(inputEventArgs is KeyEventArgs keyArgs)) return false;
if (keyArgs.IsRepeat) return false;
if (nextKey == 0) {
if (new KeyGesture(keys[0], mods).Matches(targetElement, keyArgs)) {
nextKey += 1;
} else {
nextKey = 0;
}
return false;
} else if (nextKey == keys.Count - 1) {
nextKey = 0;
return keyArgs.Key == keys[keys.Count - 1];
} else {
nextKey = keyArgs.Key == keys[nextKey] ? nextKey + 1 : 0;
return false;
}
}
}
public class MultiKeyGestureExtension : MarkupExtension {
private static readonly KeyConverter keyConverter = new KeyConverter();
private static readonly ModifierKeysConverter modifierConverter = new ModifierKeysConverter();
private readonly ModifierKeys mods;
private readonly Key[] keys;
public MultiKeyGestureExtension(string first, string second) : this(new[] { first, second }) { }
public MultiKeyGestureExtension(params string[] textPieces) {
var text = ", ".Join(textPieces);
if (text.Contains("+")) {
var parts = text.Split('+');
text = parts[1];
mods = (ModifierKeys)modifierConverter.ConvertFromString(parts[0]);
} else {
mods = ModifierKeys.None;
}
keys = text.Split(',').Select(k => (Key)keyConverter.ConvertFromString(k.Trim())).ToArray();
}
public override object ProvideValue(IServiceProvider serviceProvider) {
return new MultiKeyGesture(mods, keys);
}
}
}

View File

@ -12,6 +12,11 @@
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</Window.Resources>
<Window.InputBindings>
<KeyBinding Gesture="{hsv:MultiKeyGesture Ctrl+D, T}" Command="{Binding DisplayAsText}"/>
<KeyBinding Gesture="{hsv:MultiKeyGesture Ctrl+D, E}" Command="{Binding DisplayAsEventScript}"/>
<KeyBinding Gesture="{hsv:MultiKeyGesture Ctrl+D, S}" Command="{Binding DisplayAsSprite}"/>
<KeyBinding Gesture="{hsv:MultiKeyGesture Ctrl+D, C}" Command="{Binding DisplayAsColorPalette}"/>
<KeyBinding Key="N" Modifiers="Ctrl" Command="{Binding New}" />
<KeyBinding Key="O" Modifiers="Ctrl" Command="{Binding Open}" />
<KeyBinding Key="S" Modifiers="Ctrl" Command="{Binding Save}" />
@ -29,7 +34,7 @@
<KeyBinding Key="C" Modifiers="Ctrl+Shift" Command="{Binding DeepCopy}" />
<KeyBinding Key="V" Modifiers="Ctrl" Command="{Binding Paste}" />
<KeyBinding Key="B" Modifiers="Ctrl" Command="{Binding Paste}" />
<KeyBinding Key="D" Modifiers="Ctrl" Command="{Binding DiffSinceLastSave}" />
<KeyBinding Key="D" Modifiers="Ctrl+Shift" Command="{Binding DiffSinceLastSave}" />
<KeyBinding Key="Delete" Command="{Binding Delete}" />
<KeyBinding Key="F" Modifiers="Ctrl" Command="{Binding ShowFind}">
<KeyBinding.CommandParameter>
@ -112,6 +117,12 @@
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Display As...">
<MenuItem Header="Text" Command="{Binding DisplayAsText}" InputGestureText="Ctrl+D, T"/>
<MenuItem Header="Event Script" Command="{Binding DisplayAsEventScript}" InputGestureText="Ctrl+D, E"/>
<MenuItem Header="Sprite" Command="{Binding DisplayAsSprite}" InputGestureText="Ctrl+D, S"/>
<MenuItem Header="Color Palette" Command="{Binding DisplayAsColorPalette}" InputGestureText="Ctrl+D, C"/>
</MenuItem>
<MenuItem Header="Cu_t" Command="{Binding Cut}" InputGestureText="Ctrl+X"/>
<MenuItem Header="_Copy" Command="{Binding Copy}" InputGestureText="Ctrl+C"/>
<MenuItem Header="D_eep Copy" Command="{Binding DeepCopy}" InputGestureText="Ctrl+Shift+C"/>
@ -141,7 +152,7 @@
</MenuItem>
</MenuItem>
<MenuItem Header="_View">
<MenuItem Header="_Diff Since Last Save" Command="{Binding DiffSinceLastSave}" InputGestureText="Ctrl+D"/>
<MenuItem Header="_Diff Since Last Save" Command="{Binding DiffSinceLastSave}" InputGestureText="Ctrl+Shift+D"/>
<Separator/>
<MenuItem Header="Show _Matrix Grid" IsCheckable="True" IsChecked="{Binding ShowMatrix}" InputGestureText="Ctrl+M"/>
<MenuItem Header="_Animate when Scrolling" IsCheckable="True" IsChecked="{Binding AnimateScroll}"/>