More refactoring

This commit is contained in:
Niels Laute
2025-07-31 15:10:16 +02:00
parent 47401f29a2
commit 68a3a114e7
10 changed files with 333 additions and 349 deletions

View File

@@ -24,6 +24,7 @@
<None Remove="Assets\Settings\Modules\APDialog.light.png" />
<None Remove="SettingsXAML\Controls\Dashboard\CheckUpdateControl.xaml" />
<None Remove="SettingsXAML\Controls\Dashboard\ShortcutConflictControl.xaml" />
<None Remove="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml" />
</ItemGroup>
<ItemGroup>
<Page Remove="SettingsXAML\App.xaml" />
@@ -134,6 +135,9 @@
<None Update="Assets\Settings\Scripts\DisableModule.ps1">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Page Update="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="SettingsXAML\Controls\Dashboard\ShortcutConflictControl.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>

View File

@@ -9,7 +9,8 @@
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<ResourceDictionary Source="/SettingsXAML/Controls/KeyVisual.xaml" />
<ResourceDictionary Source="/SettingsXAML/Controls/KeyVisual/KeyVisual.xaml" />
<ResourceDictionary Source="/SettingsXAML/Controls/KeyVisual/KeyCharPresenter.xaml" />
<ResourceDictionary Source="/SettingsXAML/Styles/TextBlock.xaml" />
<ResourceDictionary Source="/SettingsXAML/Styles/Button.xaml" />
<ResourceDictionary Source="/SettingsXAML/Styles/InfoBadge.xaml" />
@@ -75,9 +76,6 @@
<!-- Smoothly animates individual cards upon whenever Expanders are expanded/collapsed -->
</TransitionCollection>
<!-- Windows Icon -->
<x:String x:Key="WindowsLogoData">M683 1229H0V546h683v683zm819 0H819V546h683v683zm-819 819H0v-683h683v683zm819 0H819v-683h683v683z</x:String>
<!-- Additional resources or settings can be added here -->
</ResourceDictionary>

View File

@@ -1,241 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes;
using Windows.System;
using Windows.UI;
namespace Microsoft.PowerToys.Settings.UI.Controls
{
[TemplatePart(Name = KeyPresenter, Type = typeof(ContentPresenter))]
[TemplateVisualState(Name = NormalState, GroupName = "CommonStates")]
[TemplateVisualState(Name = DisabledState, GroupName = "CommonStates")]
[TemplateVisualState(Name = InvalidState, GroupName = "CommonStates")]
public sealed partial class KeyVisual : Control
{
private const string KeyPresenter = "KeyPresenter";
private const string NormalState = "Normal";
private const string DisabledState = "Disabled";
private const string InvalidState = "Invalid";
private ContentPresenter _keyPresenter;
public object Content
{
get => (object)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(object), typeof(KeyVisual), new PropertyMetadata(default(string), OnContentChanged));
public bool IsInvalid
{
get => (bool)GetValue(IsInvalidProperty);
set => SetValue(IsInvalidProperty, value);
}
public static readonly DependencyProperty IsInvalidProperty = DependencyProperty.Register(nameof(IsInvalid), typeof(bool), typeof(KeyVisual), new PropertyMetadata(false, OnIsInvalidChanged));
public string AccessibleName
{
get => (string)GetValue(AccessibleNameProperty);
set => SetValue(AccessibleNameProperty, value);
}
public static readonly DependencyProperty AccessibleNameProperty = DependencyProperty.Register(nameof(AccessibleName), typeof(string), typeof(KeyVisual), new PropertyMetadata(string.Empty, OnAccessibleNameChanged));
public KeyVisual()
{
this.DefaultStyleKey = typeof(KeyVisual);
}
protected override void OnApplyTemplate()
{
IsEnabledChanged -= KeyVisual_IsEnabledChanged;
_keyPresenter = (ContentPresenter)this.GetTemplateChild(KeyPresenter);
Update();
SetVisualStates();
IsEnabledChanged += KeyVisual_IsEnabledChanged;
base.OnApplyTemplate();
}
private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((KeyVisual)d).SetVisualStates();
}
private static void OnIsInvalidChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((KeyVisual)d).SetVisualStates();
}
private static void OnAccessibleNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (KeyVisual)d;
if (control._keyPresenter != null)
{
AutomationProperties.SetName(control._keyPresenter, (string)e.NewValue);
}
}
private void SetVisualStates()
{
if (this != null)
{
if (IsInvalid)
{
VisualStateManager.GoToState(this, InvalidState, true);
}
else if (!IsEnabled)
{
VisualStateManager.GoToState(this, DisabledState, true);
}
else
{
VisualStateManager.GoToState(this, NormalState, true);
}
}
}
private void Update()
{
if (this != null && this.Content != null)
{
FrameworkElement contentElement = null;
string accessibleName = string.Empty;
if (Content.GetType() == typeof(string))
{
// For plain strings, set directly
_keyPresenter.Content = Content;
_keyPresenter.Margin = new Thickness(0, -1, 0, 0);
AutomationProperties.SetName(_keyPresenter, Content.ToString());
return;
}
switch ((int)Content)
{
case 13: // Enter key
accessibleName = ResourceLoaderInstance.ResourceLoader.GetString("KeyEnter");
contentElement = CreateGlyphTextBlock("\uE751", accessibleName);
break;
case 8: // Back key
accessibleName = ResourceLoaderInstance.ResourceLoader.GetString("KeyBack");
contentElement = CreateGlyphTextBlock("\uE750", accessibleName);
break;
case 16: // Right Shift
case 160: // Left Shift
case 161: // Shift key
accessibleName = ResourceLoaderInstance.ResourceLoader.GetString("KeyShift");
contentElement = CreateGlyphTextBlock("\uE752", accessibleName);
break;
case 38: // Up arrow
accessibleName = ResourceLoaderInstance.ResourceLoader.GetString("KeyUpArrow");
contentElement = CreateGlyphTextBlock("\uE0E4", accessibleName);
break;
case 40: // Down arrow
accessibleName = ResourceLoaderInstance.ResourceLoader.GetString("KeyDownArrow");
contentElement = CreateGlyphTextBlock("\uE0E5", accessibleName);
break;
case 37: // Left arrow
accessibleName = ResourceLoaderInstance.ResourceLoader.GetString("KeyLeftArrow");
contentElement = CreateGlyphTextBlock("\uE0E2", accessibleName);
break;
case 39: // Right arrow
accessibleName = ResourceLoaderInstance.ResourceLoader.GetString("KeyRightArrow");
contentElement = CreateGlyphTextBlock("\uE0E3", accessibleName);
break;
case 91: // Left Windows key
case 92: // Right Windows key
accessibleName = ResourceLoaderInstance.ResourceLoader.GetString("KeyWindows");
Geometry geometry = GetGeometryFromAppResources("WindowsLogoData");
var brush = (Brush)Application.Current.Resources["TextFillColorPrimaryBrush"];
Path winIcon = new()
{
Data = geometry,
Fill = brush,
Stretch = Stretch.Uniform,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
};
Viewbox winIconContainer = new()
{
Child = winIcon,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Height = FontSize * 0.8,
Width = FontSize * 0.8,
};
AutomationProperties.SetName(winIconContainer, accessibleName);
contentElement = winIconContainer;
break;
default:
accessibleName = ((VirtualKey)Content).ToString();
contentElement = new TextBlock
{
Text = accessibleName,
FontSize = FontSize * 0.8,
};
AutomationProperties.SetName(contentElement, accessibleName);
break;
}
_keyPresenter.Content = contentElement;
AccessibleName = accessibleName;
}
}
private TextBlock CreateGlyphTextBlock(string glyph, string accessibleName)
{
var tb = new TextBlock
{
Text = glyph,
FontFamily = new FontFamily("Segoe Fluent Icons, Segoe MDL2 Assets"),
FontSize = FontSize * 0.8,
};
AutomationProperties.SetName(tb, accessibleName);
return tb;
}
private Geometry GetGeometryFromAppResources(string key)
{
if (Application.Current.Resources.TryGetValue(key, out var value) && value is string pathData)
{
return GetGeometryFromString(pathData);
}
throw new InvalidOperationException($"Resource with key '{key}' not found or not a string.");
}
private Geometry GetGeometryFromString(string pathData)
{
return (Geometry)XamlBindingHelper.ConvertValue(typeof(Geometry), pathData);
}
private void KeyVisual_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
SetVisualStates();
}
}
}

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Controls"
xmlns:ui="using:CommunityToolkit.WinUI">
<Style BasedOn="{StaticResource DefaultKeyCharPresenterStyle}" TargetType="local:KeyCharPresenter" />
<Style x:Key="DefaultKeyCharPresenterStyle" TargetType="local:KeyCharPresenter">
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyCharPresenter">
<Grid Height="{TemplateBinding FontSize}">
<TextBlock
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Text="{TemplateBinding Content}"
TextLineBounds="Tight" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="WindowsKeyCharPresenterStyle"
BasedOn="{StaticResource DefaultKeyCharPresenterStyle}"
TargetType="local:KeyCharPresenter">
<!-- Scale to visually align the height of the Windows logo and text -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyCharPresenter">
<Grid Height="{TemplateBinding FontSize}">
<Viewbox>
<PathIcon Data="M9 20H0V11H9V20ZM20 20H11V11H20V20ZM9 9H0V0H9V9ZM20 9H11V0H20V9Z" />
</Viewbox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="GlyphKeyCharPresenterStyle"
BasedOn="{StaticResource DefaultKeyCharPresenterStyle}"
TargetType="local:KeyCharPresenter">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:KeyCharPresenter">
<Grid>
<Viewbox>
<FontIcon
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Glyph="{TemplateBinding Content}" />
</Viewbox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Documents;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
namespace Microsoft.PowerToys.Settings.UI.Controls;
public sealed partial class KeyCharPresenter : Control
{
public KeyCharPresenter()
{
DefaultStyleKey = typeof(KeyCharPresenter);
}
public object Content
{
get => (object)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(object), typeof(KeyCharPresenter), new PropertyMetadata(default(string)));
}

View File

@@ -1,20 +1,22 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls">
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Controls">
<Style BasedOn="{StaticResource DefaultKeyVisualStyle}" TargetType="controls:KeyVisual" />
<Style BasedOn="{StaticResource DefaultKeyVisualStyle}" TargetType="local:KeyVisual" />
<Style x:Key="DefaultKeyVisualStyle" TargetType="controls:KeyVisual">
<Style x:Key="DefaultKeyVisualStyle" TargetType="local:KeyVisual">
<Setter Property="MinWidth" Value="16" />
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="MinHeight" Value="16" />
<Setter Property="Background" Value="{ThemeResource SubtleFillColorTransparentBrush}" />
<Setter Property="Foreground" Value="{ThemeResource TextFillColorPrimaryBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource ControlStrokeColorDefaultBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="4,0,4,0" />
<Setter Property="Padding" Value="4,4,4,4" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontSize" Value="14" />
<Setter Property="CornerRadius" Value="2" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="HorizontalAlignment" Value="Left" />
@@ -23,51 +25,51 @@
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:KeyVisual">
<ContentPresenter
x:Name="KeyPresenter"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
<ControlTemplate TargetType="local:KeyVisual">
<Grid
x:Name="KeyHolder"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
CornerRadius="{TemplateBinding CornerRadius}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
TextLineBounds="Tight">
<ContentPresenter.BackgroundTransition>
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</ContentPresenter.BackgroundTransition>
</Grid.BackgroundTransition>
<local:KeyCharPresenter
x:Name="KeyPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Content}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="ContentHolder.Background" Value="{ThemeResource SubtleFillColorTransparentBrush}" />
<Setter Target="ContentHolder.BorderBrush" Value="{ThemeResource CardStrokeColorDefaultSolidBrush}" />
<Setter Target="KeyHolder.Background" Value="{ThemeResource SubtleFillColorTransparentBrush}" />
<Setter Target="KeyHolder.BorderBrush" Value="{ThemeResource CardStrokeColorDefaultSolidBrush}" />
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource ControlStrokeColorDefaultBrush}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Invalid">
<VisualState.Setters>
<Setter Target="ContentHolder.Background" Value="{ThemeResource SystemFillColorCriticalBackgroundBrush}" />
<Setter Target="ContentHolder.BorderBrush" Value="{ThemeResource SystemFillColorCriticalBrush}" />
<Setter Target="ContentHolder.BorderThickness" Value="2" />
<Setter Target="KeyHolder.Background" Value="{ThemeResource SystemFillColorCriticalBackgroundBrush}" />
<Setter Target="KeyHolder.BorderBrush" Value="{ThemeResource SystemFillColorCriticalBrush}" />
<Setter Target="KeyHolder.BorderThickness" Value="2" />
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
@@ -76,35 +78,35 @@
<Style
x:Key="SubtleKeyVisualStyle"
BasedOn="{StaticResource DefaultKeyVisualStyle}"
TargetType="controls:KeyVisual">
TargetType="local:KeyVisual">
<Setter Property="Background" Value="{ThemeResource SubtleFillColorTransparentBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource SubtleFillColorTransparentBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:KeyVisual">
<ContentPresenter
x:Name="KeyPresenter"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
<ControlTemplate TargetType="local:KeyVisual">
<Grid
x:Name="KeyHolder"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
CornerRadius="{TemplateBinding CornerRadius}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
TextLineBounds="Tight">
<ContentPresenter.BackgroundTransition>
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</ContentPresenter.BackgroundTransition>
</Grid.BackgroundTransition>
<local:KeyCharPresenter
x:Name="KeyPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Content}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
@@ -120,7 +122,7 @@
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
@@ -129,58 +131,59 @@
<Style
x:Key="AccentKeyVisualStyle"
BasedOn="{StaticResource DefaultKeyVisualStyle}"
TargetType="controls:KeyVisual">
TargetType="local:KeyVisual">
<Setter Property="Background" Value="{ThemeResource AccentFillColorDefaultBrush}" />
<Setter Property="Foreground" Value="{ThemeResource TextOnAccentFillColorPrimaryBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource AccentControlElevationBorderBrush}" />
<Setter Property="BackgroundSizing" Value="OuterBorderEdge" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:KeyVisual">
<ContentPresenter
x:Name="KeyPresenter"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
<ControlTemplate TargetType="local:KeyVisual">
<Grid
x:Name="KeyHolder"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
CornerRadius="{TemplateBinding CornerRadius}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
TextLineBounds="Tight">
<ContentPresenter.BackgroundTransition>
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</ContentPresenter.BackgroundTransition>
</Grid.BackgroundTransition>
<local:KeyCharPresenter
x:Name="KeyPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="ContentHolder.Background" Value="{ThemeResource AccentButtonBackgroundDisabled}" />
<Setter Target="ContentHolder.BorderBrush" Value="{ThemeResource AccentButtonBorderBrushDisabled}" />
<Setter Target="KeyHolder.Background" Value="{ThemeResource AccentButtonBackgroundDisabled}" />
<Setter Target="KeyHolder.BorderBrush" Value="{ThemeResource AccentButtonBorderBrushDisabled}" />
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource AccentButtonForegroundDisabled}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Invalid">
<VisualState.Setters>
<Setter Target="ContentHolder.Background" Value="{ThemeResource SystemFillColorCriticalBackgroundBrush}" />
<Setter Target="ContentHolder.BorderBrush" Value="{ThemeResource SystemFillColorCriticalBrush}" />
<Setter Target="ContentHolder.BorderThickness" Value="2" />
<Setter Target="KeyHolder.Background" Value="{ThemeResource SystemFillColorCriticalBackgroundBrush}" />
<Setter Target="KeyHolder.BorderBrush" Value="{ThemeResource SystemFillColorCriticalBrush}" />
<Setter Target="KeyHolder.BorderThickness" Value="2" />
<Setter Target="KeyPresenter.Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>

View File

@@ -0,0 +1,148 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
using Microsoft.UI.Xaml.Media;
namespace Microsoft.PowerToys.Settings.UI.Controls
{
[TemplatePart(Name = KeyPresenter, Type = typeof(KeyCharPresenter))]
[TemplateVisualState(Name = NormalState, GroupName = "CommonStates")]
[TemplateVisualState(Name = DisabledState, GroupName = "CommonStates")]
[TemplateVisualState(Name = InvalidState, GroupName = "CommonStates")]
public sealed partial class KeyVisual : Control
{
private const string KeyPresenter = "KeyPresenter";
private const string NormalState = "Normal";
private const string DisabledState = "Disabled";
private const string InvalidState = "Invalid";
private KeyCharPresenter _keyPresenter;
public object Content
{
get => (object)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(object), typeof(KeyVisual), new PropertyMetadata(default(string), OnContentChanged));
public bool IsInvalid
{
get => (bool)GetValue(IsInvalidProperty);
set => SetValue(IsInvalidProperty, value);
}
public static readonly DependencyProperty IsInvalidProperty = DependencyProperty.Register(nameof(IsInvalid), typeof(bool), typeof(KeyVisual), new PropertyMetadata(false, OnIsInvalidChanged));
public KeyVisual()
{
this.DefaultStyleKey = typeof(KeyVisual);
}
protected override void OnApplyTemplate()
{
IsEnabledChanged -= KeyVisual_IsEnabledChanged;
_keyPresenter = (KeyCharPresenter)this.GetTemplateChild(KeyPresenter);
Update();
SetVisualStates();
IsEnabledChanged += KeyVisual_IsEnabledChanged;
base.OnApplyTemplate();
}
private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((KeyVisual)d).SetVisualStates();
}
private static void OnIsInvalidChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((KeyVisual)d).SetVisualStates();
}
private void SetVisualStates()
{
if (this != null)
{
if (IsInvalid)
{
VisualStateManager.GoToState(this, InvalidState, true);
}
else if (!IsEnabled)
{
VisualStateManager.GoToState(this, DisabledState, true);
}
else
{
VisualStateManager.GoToState(this, NormalState, true);
}
}
}
private void Update()
{
if (this != null && this.Content != null)
{
string accessibleName = string.Empty;
_keyPresenter.Content = Content;
if (Content is int symbol)
{
_keyPresenter.Style = (Style)Application.Current.Resources["GlyphKeyCharPresenterStyle"];
switch (symbol)
{
case 13: // Enter key
_keyPresenter.Content = "\uE751";
break;
case 8: // Back key
_keyPresenter.Content = "\uE750";
break;
case 16: // Right Shift
case 160: // Left Shift
case 161: // Shift key
_keyPresenter.Content = "\uE752";
break;
case 38: // Up arrow
_keyPresenter.Content = "\uE0E4";
break;
case 40: // Down arrow
_keyPresenter.Content = "\uE0E5";
break;
case 37: // Left arrow
_keyPresenter.Content = "\uE0E2";
break;
case 39: // Right arrow
_keyPresenter.Content = "\uE0E3";
break;
case 91: // Left Windows key
case 92: // Right Windows key
_keyPresenter.Style = (Style)Application.Current.Resources["WindowsKeyCharPresenterStyle"];
break;
}
}
else
{
_keyPresenter.Style = (Style)Application.Current.Resources["DefaultKeyCharPresenterStyle"];
}
}
}
private void KeyVisual_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
SetVisualStates();
}
}
}

View File

@@ -33,8 +33,7 @@
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:KeyVisual
Height="30 "
Padding="12,4,12,4"
Padding="12,8,12,8"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
Content="{Binding}"

View File

@@ -14,9 +14,6 @@
<RowDefinition MinHeight="110" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" />
<ItemsControl
x:Name="KeysControl"
Grid.Row="1"
@@ -34,12 +31,11 @@
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:KeyVisual
Height="56"
Padding="20,8,20,8"
Padding="20,16"
AutomationProperties.AccessibilityView="Raw"
Content="{Binding}"
CornerRadius="{StaticResource ControlCornerRadius}"
FontSize="19"
FontSize="16"
FontWeight="SemiBold"
IsInvalid="{Binding ElementName=ShortcutContentControl, Path=IsError, Mode=OneWay}"
IsTabStop="False"

View File

@@ -5124,35 +5124,7 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
<data name="GeneralPage_EnableViewDiagnosticDataText.Text" xml:space="preserve">
<value>Stores diagnostic data locally in .xml format; folder may include .etl files as well. May use up 1GB or more of disk space.</value>
</data>
<data name="KeyEnter" xml:space="preserve">
<value>Enter key</value>
<comment>"Key" as in hardware on the keyboard</comment>
</data>
<data name="KeyBack" xml:space="preserve">
<value>Back key</value>
</data>
<data name="KeyShift" xml:space="preserve">
<value>Shift key</value>
<comment>"Key" as in hardware on the keyboard</comment>
</data>
<data name="KeyUpArrow" xml:space="preserve">
<value>Up arrow key</value>
<comment>"Key" as in hardware on the keyboard</comment>
</data>
<data name="KeyDownArrow" xml:space="preserve">
<value>Down arrow key</value>
<comment>"Key" as in hardware on the keyboard</comment>
</data>
<data name="KeyLeftArrow" xml:space="preserve">
<value>Left arrow key</value>
<comment>"Key" as in hardware on the keyboard</comment>
</data>
<data name="KeyRightArrow" xml:space="preserve">
<value>Right arrow key</value>
<comment>"Key" as in hardware on the keyboard</comment>
</data>
<data name="KeyWindows" xml:space="preserve">
<value>Windows key</value>
<comment>"Key" as in hardware on the keyboard</comment>
</data>
</root>