Skip to content

Commit 2a1a427

Browse files
authored
Feature: Improved the display of keyboard shortcuts in the Command Palette (#15106)
1 parent a0acba3 commit 2a1a427

File tree

12 files changed

+550
-23
lines changed

12 files changed

+550
-23
lines changed

src/Files.App/Data/Commands/HotKey/HotKey.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ namespace Files.App.Data.Commands
1111
[DebuggerDisplay("{Code}")]
1212
public readonly struct HotKey : IEquatable<HotKey>
1313
{
14-
private static readonly FrozenDictionary<KeyModifiers, string> modifiers = new Dictionary<KeyModifiers, string>()
14+
public static readonly FrozenDictionary<KeyModifiers, string> modifiers = new Dictionary<KeyModifiers, string>()
1515
{
1616
[KeyModifiers.Menu] = GetKeyString("Menu"),
1717
[KeyModifiers.Ctrl] = GetKeyString("Control"),
1818
[KeyModifiers.Shift] = GetKeyString("Shift"),
1919
[KeyModifiers.Win] = GetKeyString("Windows"),
2020
}.ToFrozenDictionary();
2121

22-
private static readonly FrozenDictionary<Keys, string> keys = new Dictionary<Keys, string>()
22+
public static readonly FrozenDictionary<Keys, string> keys = new Dictionary<Keys, string>()
2323
{
2424
[Keys.Enter] = GetKeyString("Enter"),
2525
[Keys.Space] = GetKeyString("Space"),

src/Files.App/Data/Items/NavigationBarSuggestionItem.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ public string? SupplementaryDisplay
6969
set => SetProperty(ref _SupplementaryDisplay, value);
7070
}
7171

72+
private HotKeyCollection _HotKeys = new();
73+
public HotKeyCollection HotKeys
74+
{
75+
get => _HotKeys;
76+
set => SetProperty(ref _HotKeys, value);
77+
}
78+
7279
private void UpdatePrimaryDisplay()
7380
{
7481
if (SearchText is null || PrimaryDisplay is null)

src/Files.App/UserControls/AddressToolbar.xaml

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
xmlns:extensions="using:CommunityToolkit.WinUI.UI"
1313
xmlns:helpers="using:Files.App.Helpers"
1414
xmlns:items="using:Files.App.Data.Items"
15+
xmlns:keyboard="using:Files.App.UserControls.KeyboardShortcut"
1516
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
1617
xmlns:triggers="using:CommunityToolkit.WinUI.UI.Triggers"
1718
xmlns:uc="using:Files.App.UserControls"
@@ -28,6 +29,8 @@
2829
<converters1:BoolNegationConverter x:Key="BoolNegationConverter" />
2930

3031
<ResourceDictionary.MergedDictionaries>
32+
<ResourceDictionary Source="ms-appx:///UserControls/KeyboardShortcut/KeyboardShortcut.xaml" />
33+
3134
<ResourceDictionary>
3235
<SolidColorBrush x:Key="ButtonBorderBrushDisabled" Color="Transparent" />
3336
<SolidColorBrush x:Key="ButtonBackgroundDisabled" Color="Transparent" />
@@ -313,34 +316,39 @@
313316
<AutoSuggestBox.ItemTemplate>
314317
<DataTemplate x:DataType="items:NavigationBarSuggestionItem">
315318
<StackPanel Margin="0,4">
316-
<Grid>
319+
<Grid ColumnSpacing="8">
317320
<Grid.ColumnDefinitions>
318321
<ColumnDefinition Width="*" />
319322
<ColumnDefinition Width="Auto" />
320323
</Grid.ColumnDefinitions>
321324

322-
<!-- Primary Display -->
323-
<!-- This is used to display paths or command descriptions. -->
324-
<TextBlock Grid.Column="0" Foreground="{ThemeResource TextFillColorPrimaryBrush}">
325+
<!-- Primary Title -->
326+
<TextBlock
327+
x:Name="PrimaryDisplayBlock"
328+
Grid.Column="0"
329+
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
330+
MaxLines="1"
331+
TextTrimming="CharacterEllipsis"
332+
TextWrapping="NoWrap">
325333
<Run FontWeight="Normal" Text="{x:Bind PrimaryDisplayPreMatched, Mode=OneWay}" /><Run FontWeight="Bold" Text="{x:Bind PrimaryDisplayMatched, Mode=OneWay}" /><Run FontWeight="Normal" Text="{x:Bind PrimaryDisplayPostMatched, Mode=OneWay}" />
326334
</TextBlock>
327335

328-
<!-- Supplementary Display -->
329-
<!-- This is used to display command hotkeys. -->
336+
<!-- Secondary Title -->
330337
<TextBlock
331-
Grid.Column="1"
338+
x:Name="SecondaryDisplayBlock"
339+
Grid.Column="0"
340+
x:Load="{x:Bind SecondaryDisplay, Mode=OneWay, Converter={StaticResource NullToFalseConverter}}"
332341
FontWeight="Normal"
333-
Foreground="{ThemeResource TextFillColorTertiaryBrush}"
334-
Text="{x:Bind SupplementaryDisplay, Mode=OneWay}" />
335-
</Grid>
342+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
343+
Text="{x:Bind SecondaryDisplay, Mode=OneWay}" />
336344

337-
<!-- Secondary Display -->
338-
<TextBlock
339-
x:Name="SecondaryDisplayBlock"
340-
x:Load="{x:Bind SecondaryDisplay, Mode=OneWay, Converter={StaticResource NullToFalseConverter}}"
341-
FontWeight="Normal"
342-
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
343-
Text="{x:Bind SecondaryDisplay, Mode=OneWay}" />
345+
<!-- Keyboard Shortcuts -->
346+
<keyboard:KeyboardShortcut
347+
x:Name="RightAlignedKeyboardShortcut"
348+
Grid.Column="1"
349+
HotKeys="{x:Bind HotKeys, Mode=OneWay}" />
350+
351+
</Grid>
344352
</StackPanel>
345353
</DataTemplate>
346354
</AutoSuggestBox.ItemTemplate>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) 2023 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using Microsoft.UI.Xaml;
5+
using Microsoft.UI.Xaml.Controls;
6+
7+
namespace Files.App.UserControls.KeyboardShortcut
8+
{
9+
public sealed partial class KeyboardShortcut
10+
{
11+
public static readonly DependencyProperty ItemTypeProperty =
12+
DependencyProperty.Register(
13+
nameof(ItemType),
14+
typeof(KeyboardShortcutItemKind),
15+
typeof(KeyboardShortcutItem),
16+
new PropertyMetadata(defaultValue: KeyboardShortcutItemKind.Outlined, (d, e) => ((KeyboardShortcutItem)d).OnItemTypePropertyChanged()));
17+
18+
public KeyboardShortcutItemKind ItemType
19+
{
20+
get => (KeyboardShortcutItemKind)GetValue(ItemTypeProperty);
21+
set => SetValue(ItemTypeProperty, value);
22+
}
23+
24+
public static readonly DependencyProperty SizeProperty =
25+
DependencyProperty.Register(
26+
nameof(Size),
27+
typeof(KeyboardShortcutItemSize),
28+
typeof(KeyboardShortcutItem),
29+
new PropertyMetadata(defaultValue: KeyboardShortcutItemSize.Small, (d, e) => ((KeyboardShortcutItem)d).OnSizePropertyChanged()));
30+
31+
public KeyboardShortcutItemSize Size
32+
{
33+
get => (KeyboardShortcutItemSize)GetValue(SizeProperty);
34+
set => SetValue(SizeProperty, value);
35+
}
36+
37+
public static readonly DependencyProperty HotKeysProperty =
38+
DependencyProperty.Register(
39+
nameof(HotKeys),
40+
typeof(HotKeyCollection),
41+
typeof(KeyboardShortcut),
42+
new PropertyMetadata(defaultValue: new(), (d, e) => ((KeyboardShortcut)d).OnHotKeysPropertyChanged()));
43+
44+
public HotKeyCollection HotKeys
45+
{
46+
get => (HotKeyCollection)GetValue(HotKeysProperty);
47+
set => SetValue(HotKeysProperty, value);
48+
}
49+
50+
public void OnItemTypePropertyChanged()
51+
{
52+
OnItemTypeChanged();
53+
}
54+
55+
public void OnSizePropertyChanged()
56+
{
57+
OnSizeChanged();
58+
}
59+
60+
private void OnHotKeysPropertyChanged()
61+
{
62+
OnHotKeysChanged();
63+
}
64+
}
65+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright (c) 2023 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using CommunityToolkit.WinUI.UI;
5+
using Microsoft.UI.Input;
6+
using Microsoft.UI.Xaml;
7+
using Microsoft.UI.Xaml.Automation;
8+
using Microsoft.UI.Xaml.Automation.Peers;
9+
using Microsoft.UI.Xaml.Controls;
10+
using Microsoft.UI.Xaml.Controls.Primitives;
11+
12+
namespace Files.App.UserControls.KeyboardShortcut
13+
{
14+
public sealed partial class KeyboardShortcut : Control
15+
{
16+
internal const string KeyboardShortcutItemsControl = "PART_KeyboardShortcutItemsControl";
17+
18+
public KeyboardShortcut()
19+
{
20+
DefaultStyleKey = typeof(KeyboardShortcut);
21+
}
22+
23+
private void OnItemTypeChanged()
24+
{
25+
}
26+
27+
private void OnSizeChanged()
28+
{
29+
}
30+
31+
private void OnHotKeysChanged()
32+
{
33+
if (HotKeys.IsEmpty)
34+
return;
35+
36+
List<KeyboardShortcutItem> items = new();
37+
38+
foreach (var item in HotKeys)
39+
{
40+
if (items.Any())
41+
{
42+
items.Add(new() { Text = ",", ItemType = KeyboardShortcutItemKind.TextOnly, Size = Size });
43+
}
44+
45+
switch(item.Key, item.Modifier)
46+
{
47+
// No keys or modifiers specified
48+
case (Keys.None, KeyModifiers.None):
49+
break;
50+
51+
// Key modifiers only
52+
case (Keys.None, _):
53+
GetModifierCode(item.Modifier);
54+
items.RemoveAt(items.Count - 1);
55+
break;
56+
57+
// Keys only
58+
case (_, KeyModifiers.None):
59+
var key = HotKey.keys[item.Key];
60+
items.Add(new() { Text = key, ItemType = ItemType, Size = Size });
61+
break;
62+
63+
// Others
64+
default:
65+
GetModifierCode(item.Modifier);
66+
key = HotKey.keys[item.Key];
67+
items.Add(new() { Text = key, ItemType = ItemType, Size = Size });
68+
break;
69+
}
70+
71+
void GetModifierCode(KeyModifiers modifier)
72+
{
73+
if (modifier.HasFlag(KeyModifiers.Menu))
74+
{
75+
items.Add(new() { Text = HotKey.modifiers[KeyModifiers.Menu], ItemType = ItemType, Size = Size });
76+
items.Add(new() { Text = "+", ItemType = KeyboardShortcutItemKind.TextOnly, Size = Size });
77+
}
78+
if (modifier.HasFlag(KeyModifiers.Ctrl))
79+
{
80+
items.Add(new() { Text = HotKey.modifiers[KeyModifiers.Ctrl], ItemType = ItemType, Size = Size });
81+
items.Add(new() { Text = "+", ItemType = KeyboardShortcutItemKind.TextOnly, Size = Size });
82+
}
83+
if (modifier.HasFlag(KeyModifiers.Shift))
84+
{
85+
items.Add(new() { Text = HotKey.modifiers[KeyModifiers.Shift], ItemType = ItemType, Size = Size });
86+
items.Add(new() { Text = "+", ItemType = KeyboardShortcutItemKind.TextOnly, Size = Size });
87+
}
88+
if (modifier.HasFlag(KeyModifiers.Win))
89+
{
90+
items.Add(new() { Text = HotKey.modifiers[KeyModifiers.Win], ItemType = ItemType, Size = Size });
91+
items.Add(new() { Text = "+", ItemType = KeyboardShortcutItemKind.TextOnly, Size = Size });
92+
}
93+
}
94+
}
95+
96+
// Set value
97+
if (GetTemplateChild(KeyboardShortcutItemsControl) is ItemsControl keyboardShortcutItemsControl)
98+
{
99+
keyboardShortcutItemsControl.ItemsSource = items;
100+
}
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)