Skip to content

Commit

Permalink
Added Shortcut Popup
Browse files Browse the repository at this point in the history
  • Loading branch information
CPKreu committed Mar 19, 2021
1 parent c9eaa70 commit fca0b25
Show file tree
Hide file tree
Showing 15 changed files with 494 additions and 65 deletions.
35 changes: 35 additions & 0 deletions PixiEditor/Helpers/Converters/KeyToStringConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Input;

namespace PixiEditor.Helpers.Converters
{
public class KeyToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Key key)
{
return InputKeyHelpers.GetCharFromKey(key);
}
else if (value is ModifierKeys)
{
return value.ToString();
}
else
{
return string.Empty;
}
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
17 changes: 17 additions & 0 deletions PixiEditor/Helpers/Extensions/EnumHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PixiEditor.Helpers.Extensions
{
public static class EnumHelpers
{
public static IEnumerable<T> GetFlags<T>(this T e)
where T : Enum
{
return Enum.GetValues(e.GetType()).Cast<T>().Where(x => e.HasFlag(x));
}
}
}
82 changes: 82 additions & 0 deletions PixiEditor/Helpers/InputKeyHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace PixiEditor.Helpers
{
public static class InputKeyHelpers
{
public static string GetCharFromKey(Key key)
{
int virtualKey = KeyInterop.VirtualKeyFromKey(key);
byte[] keyboardState = new byte[256];
GetKeyboardState(keyboardState);

uint scanCode = MapVirtualKeyW((uint)virtualKey, MapType.MAPVK_VK_TO_VSC);
StringBuilder stringBuilder = new (3);

int result = ToUnicode((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0);

switch (result)
{
case 0:
{
return key.ToString();
}

case -1:
{
return stringBuilder.ToString().ToUpper();
}

default:
{
return stringBuilder[result - 1].ToString().ToUpper();
}
}
}

private enum MapType : uint
{
/// <summary>
/// The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.
/// </summary>
MAPVK_VK_TO_VSC = 0x0,

/// <summary>
/// The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.
/// </summary>
MAPVK_VSC_TO_VK = 0x1,

/// <summary>
/// The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0.
/// </summary>
MAPVK_VK_TO_CHAR = 0x2,

/// <summary>
/// The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0.
/// </summary>
MAPVK_VSC_TO_VK_EX = 0x3,
}

[DllImport("user32.dll")]
private static extern int ToUnicode(
uint wVirtKey,
uint wScanCode,
byte[] lpKeyState,
[Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)]
StringBuilder pwszBuff,
int cchBuff,
uint wFlags);

[DllImport("user32.dll")]
private static extern bool GetKeyboardState(byte[] lpKeyState);

[DllImport("user32.dll")]
private static extern uint MapVirtualKeyW(uint uCode, MapType uMapType);
}
}
17 changes: 16 additions & 1 deletion PixiEditor/Models/Controllers/Shortcuts/Shortcut.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Windows.Input;
using System.Linq;
using System.Windows.Input;
using PixiEditor.Helpers.Extensions;

namespace PixiEditor.Models.Controllers.Shortcuts
{
Expand All @@ -12,12 +14,25 @@ public Shortcut(Key shortcutKey, ICommand command, object commandParameter = nul
CommandParameter = commandParameter;
}

public Shortcut(Key shortcutKey, ICommand command, string description, object commandParameter = null, ModifierKeys modifier = ModifierKeys.None)
: this(shortcutKey, command, commandParameter, modifier)
{
Description = description;
}

public Key ShortcutKey { get; set; }

public ModifierKeys Modifier { get; set; }

/// <summary>
/// Gets all <see cref="ModifierKeys"/> as an array.
/// </summary>
public ModifierKeys[] Modifiers { get => Modifier.GetFlags().Except(new ModifierKeys[] { ModifierKeys.None }).ToArray(); }

public ICommand Command { get; set; }

public string Description { get; set; }

public object CommandParameter { get; set; }

public void Execute()
Expand Down
9 changes: 5 additions & 4 deletions PixiEditor/Models/Controllers/Shortcuts/ShortcutController.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;

namespace PixiEditor.Models.Controllers.Shortcuts
{
public class ShortcutController
{
public ShortcutController()
public ShortcutController(params ShortcutGroup[] shortcutGroups)
{
Shortcuts = new List<Shortcut>();
ShortcutGroups = new ObservableCollection<ShortcutGroup>(shortcutGroups);
}

public static bool BlockShortcutExecution { get; set; }

public List<Shortcut> Shortcuts { get; set; }
public ObservableCollection<ShortcutGroup> ShortcutGroups { get; init; }

public Shortcut LastShortcut { get; private set; }

public void KeyPressed(Key key, ModifierKeys modifiers)
{
if (!BlockShortcutExecution)
{
Shortcut[] shortcuts = Shortcuts.FindAll(x => x.ShortcutKey == key).ToArray();
Shortcut[] shortcuts = ShortcutGroups.SelectMany(x => x.Shortcuts).ToList().FindAll(x => x.ShortcutKey == key).ToArray();
if (shortcuts.Length < 1)
{
return;
Expand Down
43 changes: 43 additions & 0 deletions PixiEditor/Models/Controllers/Shortcuts/ShortcutGroup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PixiEditor.Models.Controllers.Shortcuts
{
public class ShortcutGroup
{
/// <summary>
/// Gets or sets the shortcuts in the shortcuts group.
/// </summary>
public ObservableCollection<Shortcut> Shortcuts { get; set; }

/// <summary>
/// Gets or sets the name of the shortcut group.
/// </summary>
public string Name { get; set; }

/// <summary>
/// Gets or sets a value indicating whether gets or sets the shortcut group visible in the shortcut popup.
/// </summary>
public bool IsVisible { get; set; }

public ShortcutGroup(string name, params Shortcut[] shortcuts)
{
Name = name;
Shortcuts = new ObservableCollection<Shortcut>(shortcuts);
IsVisible = true;
}

/// <param name="name">The name of the group.</param>
/// <param name="shortcuts">The shortcuts that belong in the group.</param>
/// <param name="isVisible">Is the group visible in the shortcut popup.</param>
public ShortcutGroup(string name, bool isVisible = true, params Shortcut[] shortcuts)
: this(name, shortcuts)
{
IsVisible = isVisible;
}
}
}
37 changes: 36 additions & 1 deletion PixiEditor/Styles/Titlebar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="LayoutRoot" Background="Transparent" Width="44" Height="30">
<Grid x:Name="LayoutRoot" Background="Transparent" Width="44" Height="35">
<TextBlock x:Name="txt" Text="{TemplateBinding Content}" FontFamily="Segoe MDL2 Assets"
FontSize="10"
Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"
Expand Down Expand Up @@ -43,4 +43,39 @@
<Setter Property="Content" Value="&#xE106;" />
</Style>

<Style x:Key="CaptionToggleButton" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid x:Name="LayoutRoot" Background="Transparent" Width="44" Height="35">
<TextBlock x:Name="txt" Text="{TemplateBinding Content}" FontFamily="Segoe MDL2 Assets"
FontSize="10"
Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"
RenderOptions.ClearTypeHint="Auto" TextOptions.TextRenderingMode="Aliased"
TextOptions.TextFormattingMode="Display" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="LayoutRoot" Property="Background">
<Setter.Value>
<SolidColorBrush Color="White" Opacity="0.1" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="LayoutRoot" Property="Background">
<Setter.Value>
<SolidColorBrush Color="White" Opacity=".3"/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="PinToggleStyle" TargetType="ToggleButton" BasedOn="{StaticResource CaptionToggleButton}">
<Setter Property="Content" Value="&#xE840;"/>
</Style>
</ResourceDictionary>
12 changes: 12 additions & 0 deletions PixiEditor/ViewModels/SubViewModels/Main/MiscViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,18 @@ public class MiscViewModel : SubViewModel<ViewModelMain>

public RelayCommand OpenSettingsWindowCommand { get; set; }

public RelayCommand OpenShortcutWindowCommand { get; set; }

public ShortcutPopup ShortcutPopup { get; set; }

public MiscViewModel(ViewModelMain owner)
: base(owner)
{
OpenHyperlinkCommand = new RelayCommand(OpenHyperlink);
OpenSettingsWindowCommand = new RelayCommand(OpenSettingsWindow);
OpenShortcutWindowCommand = new RelayCommand(OpenShortcutWindow);

ShortcutPopup = new ShortcutPopup(owner.ShortcutController);
}

private void OpenSettingsWindow(object parameter)
Expand All @@ -43,5 +50,10 @@ private void OpenHyperlink(object parameter)
};
Process.Start(processInfo);
}

private void OpenShortcutWindow(object parameter)
{
ShortcutPopup.Show();
}
}
}
Loading

0 comments on commit fca0b25

Please sign in to comment.