mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
dock: shift around the padding for fitts law (#45834)
This makes the buttons hitbox extend all the way to the edges of the dock, but the visual presentation of these buttons is unchanged. This lets us adhere to fitts law appropriately. Closes #45596 Closes #45590
This commit is contained in:
@@ -182,7 +182,7 @@
|
||||
<Grid
|
||||
x:Name="ContentGrid"
|
||||
Margin="4"
|
||||
Padding="4,0,4,0"
|
||||
Padding="0,0,0,0"
|
||||
Background="Transparent"
|
||||
RightTapped="RootGrid_RightTapped">
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -334,12 +334,16 @@
|
||||
<VisualState.StateTriggers>
|
||||
<ui:IsEqualStateTrigger Value="{x:Bind DockSide, Mode=OneWay}" To="Top" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentGrid.Margin" Value="4,0,4,4" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DockOnBottom">
|
||||
<VisualState.StateTriggers>
|
||||
<ui:IsEqualStateTrigger Value="{x:Bind DockSide, Mode=OneWay}" To="Bottom" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentGrid.Margin" Value="4,4,4,0" />
|
||||
<Setter Target="RootGrid.BorderThickness" Value="0,1,0,0" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
@@ -373,7 +377,8 @@
|
||||
<Setter Target="EndScroller.(Grid.ColumnSpan)" Value="3" />
|
||||
<Setter Target="EndScroller.HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Target="EndScroller.VerticalAlignment" Value="Bottom" />
|
||||
<Setter Target="ContentGrid.Padding" Value="4,8,4,8" />
|
||||
<Setter Target="ContentGrid.Margin" Value="0,4,4,4" />
|
||||
<Setter Target="ContentGrid.Padding" Value="0,8,4,8" />
|
||||
<Setter Target="RootGrid.BorderThickness" Value="0,0,1,0" />
|
||||
|
||||
<Setter Target="StartListView.ItemsPanel" Value="{StaticResource VerticalItemsPanel}" />
|
||||
@@ -411,7 +416,8 @@
|
||||
<Setter Target="EndScroller.(Grid.ColumnSpan)" Value="3" />
|
||||
<Setter Target="EndScroller.HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Target="EndScroller.VerticalAlignment" Value="Bottom" />
|
||||
<Setter Target="ContentGrid.Padding" Value="4,8,4,8" />
|
||||
<Setter Target="ContentGrid.Margin" Value="4,4,0,4" />
|
||||
<Setter Target="ContentGrid.Padding" Value="4,8,0,8" />
|
||||
<Setter Target="RootGrid.BorderThickness" Value="1,0,0,0" />
|
||||
|
||||
<Setter Target="StartListView.ItemsPanel" Value="{StaticResource VerticalItemsPanel}" />
|
||||
|
||||
@@ -58,62 +58,67 @@
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:DockItemControl">
|
||||
<Grid
|
||||
x:Name="PART_RootGrid"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
x:Name="PART_HitTestGrid"
|
||||
Background="Transparent"
|
||||
ToolTipService.ToolTip="{TemplateBinding ToolTip}">
|
||||
<Grid
|
||||
x:Name="ContentGrid"
|
||||
AutomationProperties.Name="{TemplateBinding Title}"
|
||||
Background="Transparent"
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
x:Name="PART_RootGrid"
|
||||
Margin="{TemplateBinding InnerMargin}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<Grid
|
||||
x:Name="ContentGrid"
|
||||
AutomationProperties.Name="{TemplateBinding Title}"
|
||||
Background="Transparent"
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Icon -->
|
||||
<ContentPresenter
|
||||
x:Name="IconPresenter"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Icon}" />
|
||||
<!-- Icon -->
|
||||
<ContentPresenter
|
||||
x:Name="IconPresenter"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Icon}" />
|
||||
|
||||
<!-- Text (Title + Subtitle) -->
|
||||
<StackPanel
|
||||
x:Name="TextPanel"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{TemplateBinding TextVisibility}">
|
||||
<TextBlock
|
||||
x:Name="TitleText"
|
||||
MinWidth="24"
|
||||
MaxWidth="100"
|
||||
HorizontalAlignment="Left"
|
||||
<!-- Text (Title + Subtitle) -->
|
||||
<StackPanel
|
||||
x:Name="TextPanel"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="12"
|
||||
Text="{TemplateBinding Title}"
|
||||
TextAlignment="Left"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap" />
|
||||
<TextBlock
|
||||
x:Name="SubtitleText"
|
||||
MaxWidth="100"
|
||||
Margin="0,-4,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="10"
|
||||
Foreground="{ThemeResource TextFillColorTertiary}"
|
||||
Text="{TemplateBinding Subtitle}"
|
||||
TextAlignment="Center"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap" />
|
||||
</StackPanel>
|
||||
Visibility="{TemplateBinding TextVisibility}">
|
||||
<TextBlock
|
||||
x:Name="TitleText"
|
||||
MinWidth="24"
|
||||
MaxWidth="100"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="12"
|
||||
Text="{TemplateBinding Title}"
|
||||
TextAlignment="Left"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap" />
|
||||
<TextBlock
|
||||
x:Name="SubtitleText"
|
||||
MaxWidth="100"
|
||||
Margin="0,-4,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="10"
|
||||
Foreground="{ThemeResource TextFillColorTertiary}"
|
||||
Text="{TemplateBinding Subtitle}"
|
||||
TextAlignment="Center"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
using Microsoft.CmdPal.UI.Controls;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Dock;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Settings;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Dock;
|
||||
|
||||
@@ -56,6 +58,15 @@ public sealed partial class DockItemControl : Control
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty InnerMarginProperty =
|
||||
DependencyProperty.Register(nameof(InnerMargin), typeof(Thickness), typeof(DockItemControl), new PropertyMetadata(new Thickness(0)));
|
||||
|
||||
public Thickness InnerMargin
|
||||
{
|
||||
get => (Thickness)GetValue(InnerMarginProperty);
|
||||
set => SetValue(InnerMarginProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextVisibilityProperty =
|
||||
DependencyProperty.Register(nameof(TextVisibility), typeof(Visibility), typeof(DockItemControl), new PropertyMetadata(null, OnTextPropertyChanged));
|
||||
|
||||
@@ -68,6 +79,8 @@ public sealed partial class DockItemControl : Control
|
||||
private const string IconPresenterName = "IconPresenter";
|
||||
|
||||
private FrameworkElement? _iconPresenter;
|
||||
private DockControl? _parentDock;
|
||||
private long _dockSideCallbackToken = -1;
|
||||
|
||||
private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
@@ -174,9 +187,13 @@ public sealed partial class DockItemControl : Control
|
||||
|
||||
PointerEntered -= Control_PointerEntered;
|
||||
PointerExited -= Control_PointerExited;
|
||||
Loaded -= DockItemControl_Loaded;
|
||||
Unloaded -= DockItemControl_Unloaded;
|
||||
|
||||
PointerEntered += Control_PointerEntered;
|
||||
PointerExited += Control_PointerExited;
|
||||
Loaded += DockItemControl_Loaded;
|
||||
Unloaded += DockItemControl_Unloaded;
|
||||
|
||||
IsEnabledChanged += OnIsEnabledChanged;
|
||||
|
||||
@@ -187,6 +204,62 @@ public sealed partial class DockItemControl : Control
|
||||
UpdateAllVisibility();
|
||||
}
|
||||
|
||||
private void DockItemControl_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Walk the visual tree to find our parent DockControl and watch its DockSide.
|
||||
// This lets us extend the hit-test area toward the screen edge.
|
||||
DependencyObject? parent = VisualTreeHelper.GetParent(this);
|
||||
while (parent is not null and not DockControl)
|
||||
{
|
||||
parent = VisualTreeHelper.GetParent(parent);
|
||||
}
|
||||
|
||||
if (parent is DockControl dock)
|
||||
{
|
||||
_parentDock = dock;
|
||||
UpdateInnerMarginForDockSide(dock.DockSide);
|
||||
_dockSideCallbackToken = dock.RegisterPropertyChangedCallback(
|
||||
DockControl.DockSideProperty,
|
||||
OnParentDockSideChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void DockItemControl_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_parentDock is not null && _dockSideCallbackToken >= 0)
|
||||
{
|
||||
_parentDock.UnregisterPropertyChangedCallback(
|
||||
DockControl.DockSideProperty,
|
||||
_dockSideCallbackToken);
|
||||
_dockSideCallbackToken = -1;
|
||||
_parentDock = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnParentDockSideChanged(DependencyObject sender, DependencyProperty dp)
|
||||
{
|
||||
if (sender is DockControl dock)
|
||||
{
|
||||
UpdateInnerMarginForDockSide(dock.DockSide);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateInnerMarginForDockSide(DockSide side)
|
||||
{
|
||||
// Push the visual (PART_RootGrid) inward on the screen-edge side so
|
||||
// the transparent hit-test area extends all the way to the edge.
|
||||
// The values here compensate for the margin/padding removed from the
|
||||
// DockControl's ContentGrid on the screen-edge side.
|
||||
InnerMargin = side switch
|
||||
{
|
||||
DockSide.Top => new Thickness(0, 4, 0, 0),
|
||||
DockSide.Bottom => new Thickness(0, 0, 0, 4),
|
||||
DockSide.Left => new Thickness(8, 0, 0, 0),
|
||||
DockSide.Right => new Thickness(0, 0, 8, 0),
|
||||
_ => new Thickness(0),
|
||||
};
|
||||
}
|
||||
|
||||
private void Control_PointerEntered(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
VisualStateManager.GoToState(this, "PointerOver", true);
|
||||
|
||||
Reference in New Issue
Block a user