Files
PowerToys/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockControl.xaml
Mike Griese 543399b62b 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
2026-03-01 13:03:40 +01:00

455 lines
25 KiB
XML

<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="Microsoft.CmdPal.UI.Dock.DockControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
xmlns:coreVm="using:Microsoft.CmdPal.Core.ViewModels"
xmlns:cpcontrols="using:Microsoft.CmdPal.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dockVm="using:Microsoft.CmdPal.UI.ViewModels.Dock"
xmlns:help="using:Microsoft.CmdPal.UI.Helpers"
xmlns:local="using:Microsoft.CmdPal.UI.Dock"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:CommunityToolkit.WinUI"
xmlns:vm="using:Microsoft.CmdPal.UI.ViewModels"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<StackLayout
x:Key="ItemsOrientationLayout"
Orientation="{x:Bind ItemsOrientation, Mode=OneWay}"
Spacing="4" />
<ItemsPanelTemplate x:Key="HorizontalItemsPanel">
<StackPanel Orientation="Horizontal" Spacing="4" />
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="VerticalItemsPanel">
<StackPanel Orientation="Vertical" Spacing="4" />
</ItemsPanelTemplate>
<DataTemplate x:Key="DockBandTemplate" x:DataType="dockVm:DockBandViewModel">
<ItemsRepeater ItemsSource="{x:Bind Items, Mode=OneWay}" Layout="{StaticResource ItemsOrientationLayout}">
<ItemsRepeater.Transitions>
<TransitionCollection />
</ItemsRepeater.Transitions>
<ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="dockVm:DockItemViewModel">
<local:DockItemControl
Title="{x:Bind Title, Mode=OneWay}"
RightTapped="BandItem_RightTapped"
Subtitle="{x:Bind Subtitle, Mode=OneWay}"
Tag="{x:Bind}"
Tapped="BandItem_Tapped"
ToolTip="{x:Bind Tooltip, Mode=OneWay}">
<local:DockItemControl.Icon>
<cpcontrols:IconBox
x:Name="IconBorder"
Width="16"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
SourceKey="{x:Bind Icon, Mode=OneWay}"
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested16}" />
</local:DockItemControl.Icon>
</local:DockItemControl>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</DataTemplate>
<Style x:Key="DockBandListViewStyle" TargetType="ListView">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Padding" Value="0" />
<Setter Property="IsItemClickEnabled" Value="False" />
<Setter Property="SelectionMode" Value="None" />
<!-- Drag properties controlled by code-behind based on IsEditMode -->
<Setter Property="CanDragItems" Value="False" />
<Setter Property="CanReorderItems" Value="False" />
<Setter Property="AllowDrop" Value="False" />
</Style>
<Style x:Key="DockBandListViewItemStyle" TargetType="ListViewItem">
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0,0,4,0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
<Style
x:Name="ContextMenuFlyoutStyle"
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}"
TargetType="FlyoutPresenter">
<Style.Setters>
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="Background" Value="{ThemeResource DesktopAcrylicTransparentBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource DividerStrokeColorDefaultBrush}" />
</Style.Setters>
</Style>
<!-- Backdrop requires ShouldConstrainToRootBounds="False" -->
<Flyout
x:Name="ContextMenuFlyout"
FlyoutPresenterStyle="{StaticResource ContextMenuFlyoutStyle}"
Opened="ContextMenuFlyout_Opened"
ShouldConstrainToRootBounds="False"
SystemBackdrop="{ThemeResource AcrylicBackgroundFillColorDefaultBackdrop}">
<cpcontrols:ContextMenu x:Name="ContextControl" />
</Flyout>
<!-- Edit mode context menu for dock bands -->
<MenuFlyout x:Name="EditModeContextMenu" ShouldConstrainToRootBounds="False">
<MenuFlyoutSubItem x:Name="LabelsSubMenu" Text="Labels">
<MenuFlyoutSubItem.Icon>
<FontIcon Glyph="&#xE8EC;" />
</MenuFlyoutSubItem.Icon>
<ToggleMenuFlyoutItem
x:Name="ShowTitlesMenuItem"
Click="ShowTitlesMenuItem_Click"
Text="Show titles" />
<ToggleMenuFlyoutItem
x:Name="ShowSubtitlesMenuItem"
Click="ShowSubtitlesMenuItem_Click"
Text="Show subtitles" />
</MenuFlyoutSubItem>
<MenuFlyoutSeparator />
<MenuFlyoutItem
x:Name="UnpinBandMenuItem"
Click="UnpinBandMenuItem_Click"
Text="Unpin">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE77A;" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
</MenuFlyout>
<!-- Add band flyout - used in edit mode to add bands to dock sections -->
<Flyout
x:Name="AddBandFlyout"
Placement="Bottom"
ShouldConstrainToRootBounds="False">
<StackPanel Width="320">
<TextBlock
x:Name="NoAvailableBandsText"
Padding="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="No commands available to pin"
TextAlignment="Center"
Visibility="Collapsed" />
<ListView
x:Name="AddBandListView"
MaxHeight="300"
HorizontalAlignment="Stretch"
IsItemClickEnabled="True"
ItemClick="AddBandListView_ItemClick"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate x:DataType="vm:TopLevelViewModel">
<Grid Padding="4" ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<cpcontrols:IconBox
Width="20"
Height="20"
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
SourceKey="{x:Bind IconViewModel, Mode=OneWay}"
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested20}" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Text="{x:Bind Title, Mode=OneWay}"
TextTrimming="CharacterEllipsis" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Flyout>
</ResourceDictionary>
</UserControl.Resources>
<Grid
x:Name="RootGrid"
BorderThickness="0,0,0,1"
RightTapped="RootGrid_RightTapped">
<!-- Edit Mode Overlay - shown when in edit mode -->
<Grid
x:Name="ContentGrid"
Margin="4"
Padding="0,0,0,0"
Background="Transparent"
RightTapped="RootGrid_RightTapped">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<cpcontrols:ScrollContainer
x:Name="StartScroller"
Grid.Row="0"
Grid.RowSpan="3"
HorizontalAlignment="Left"
VerticalAlignment="Stretch">
<cpcontrols:ScrollContainer.ActionButton>
<Button
x:Name="StartAddButton"
Click="AddBandButton_Click"
Style="{StaticResource SubtleButtonStyle}"
Tag="Start"
ToolTipService.ToolTip="Add band to Start">
<FontIcon FontSize="12" Glyph="&#xE710;" />
</Button>
</cpcontrols:ScrollContainer.ActionButton>
<cpcontrols:ScrollContainer.Source>
<ListView
x:Name="StartListView"
HorizontalAlignment="Stretch"
DragItemsCompleted="BandListView_DragItemsCompleted"
DragItemsStarting="BandListView_DragItemsStarting"
DragOver="BandListView_DragOver"
Drop="StartListView_Drop"
ItemContainerStyle="{StaticResource DockBandListViewItemStyle}"
ItemTemplate="{StaticResource DockBandTemplate}"
ItemsPanel="{StaticResource HorizontalItemsPanel}"
ItemsSource="{x:Bind ViewModel.StartItems, Mode=OneWay}"
SelectionMode="None"
Style="{StaticResource DockBandListViewStyle}" />
</cpcontrols:ScrollContainer.Source>
</cpcontrols:ScrollContainer>
<cpcontrols:ScrollContainer
x:Name="CenterScroller"
Grid.Row="0"
Grid.RowSpan="3"
Grid.Column="1"
MinWidth="48"
HorizontalAlignment="Center"
VerticalAlignment="Stretch">
<cpcontrols:ScrollContainer.ActionButton>
<Button
x:Name="CenterAddButton"
Click="AddBandButton_Click"
Style="{StaticResource SubtleButtonStyle}"
Tag="Center"
ToolTipService.ToolTip="Add band to Center">
<FontIcon FontSize="12" Glyph="&#xE710;" />
</Button>
</cpcontrols:ScrollContainer.ActionButton>
<cpcontrols:ScrollContainer.Source>
<ListView
x:Name="CenterListView"
HorizontalAlignment="Stretch"
DragItemsCompleted="BandListView_DragItemsCompleted"
DragItemsStarting="BandListView_DragItemsStarting"
DragOver="BandListView_DragOver"
Drop="CenterListView_Drop"
ItemContainerStyle="{StaticResource DockBandListViewItemStyle}"
ItemTemplate="{StaticResource DockBandTemplate}"
ItemsPanel="{StaticResource HorizontalItemsPanel}"
ItemsSource="{x:Bind ViewModel.CenterItems, Mode=OneWay}"
SelectionMode="None"
Style="{StaticResource DockBandListViewStyle}" />
</cpcontrols:ScrollContainer.Source>
</cpcontrols:ScrollContainer>
<cpcontrols:ScrollContainer
x:Name="EndScroller"
Grid.Row="0"
Grid.RowSpan="3"
Grid.Column="2"
HorizontalAlignment="Right"
VerticalAlignment="Stretch"
ContentAlignment="End">
<cpcontrols:ScrollContainer.ActionButton>
<Button
x:Name="EndAddButton"
Click="AddBandButton_Click"
Style="{StaticResource SubtleButtonStyle}"
Tag="End"
ToolTipService.ToolTip="Add band to End">
<FontIcon FontSize="12" Glyph="&#xE710;" />
</Button>
</cpcontrols:ScrollContainer.ActionButton>
<cpcontrols:ScrollContainer.Source>
<ListView
x:Name="EndListView"
DragItemsCompleted="BandListView_DragItemsCompleted"
DragItemsStarting="BandListView_DragItemsStarting"
DragOver="BandListView_DragOver"
Drop="EndListView_Drop"
ItemContainerStyle="{StaticResource DockBandListViewItemStyle}"
ItemTemplate="{StaticResource DockBandTemplate}"
ItemsPanel="{StaticResource HorizontalItemsPanel}"
ItemsSource="{x:Bind ViewModel.EndItems, Mode=OneWay}"
SelectionMode="None"
Style="{StaticResource DockBandListViewStyle}">
<ListView.ItemContainerTransitions>
<TransitionCollection />
</ListView.ItemContainerTransitions>
</ListView>
</cpcontrols:ScrollContainer.Source>
</cpcontrols:ScrollContainer>
<TeachingTip
x:Name="EditButtonsTeachingTip"
MinWidth="0"
PreferredPlacement="Bottom"
ShouldConstrainToRootBounds="False"
Style="{StaticResource TeachingTipWithoutCloseButtonStyle}"
Target="{x:Bind ContentGrid}">
<TeachingTip.Content>
<StackPanel
x:Name="EditButtonsPanel"
HorizontalAlignment="Stretch"
Orientation="Vertical"
Spacing="4">
<Button
HorizontalAlignment="Stretch"
Click="DoneEditingButton_Click"
Content="Save"
Style="{StaticResource AccentButtonStyle}" />
<Button
HorizontalAlignment="Stretch"
Click="DiscardEditingButton_Click"
Content="Discard" />
</StackPanel>
</TeachingTip.Content>
</TeachingTip>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="DockOrientation">
<VisualState x:Name="DockOnTop">
<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>
<VisualState x:Name="DockOnLeft">
<VisualState.StateTriggers>
<ui:IsEqualStateTrigger Value="{x:Bind DockSide, Mode=OneWay}" To="Left" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="StartScroller.(Grid.Row)" Value="0" />
<Setter Target="StartScroller.(Grid.RowSpan)" Value="1" />
<Setter Target="StartScroller.(Grid.Column)" Value="0" />
<Setter Target="StartScroller.(Grid.ColumnSpan)" Value="3" />
<Setter Target="StartScroller.Orientation" Value="Vertical" />
<Setter Target="StartScroller.HorizontalAlignment" Value="Stretch" />
<Setter Target="StartScroller.VerticalAlignment" Value="Top" />
<Setter Target="StartScroller.Orientation" Value="Vertical" />
<Setter Target="CenterScroller.(Grid.Row)" Value="1" />
<Setter Target="CenterScroller.(Grid.RowSpan)" Value="1" />
<Setter Target="CenterScroller.(Grid.Column)" Value="0" />
<Setter Target="CenterScroller.(Grid.ColumnSpan)" Value="3" />
<Setter Target="CenterScroller.Orientation" Value="Vertical" />
<Setter Target="CenterScroller.HorizontalAlignment" Value="Stretch" />
<Setter Target="CenterScroller.VerticalAlignment" Value="Center" />
<Setter Target="CenterScroller.Orientation" Value="Vertical" />
<Setter Target="EndScroller.Orientation" Value="Vertical" />
<Setter Target="EndScroller.(Grid.Row)" Value="2" />
<Setter Target="EndScroller.(Grid.RowSpan)" Value="1" />
<Setter Target="EndScroller.(Grid.Column)" Value="0" />
<Setter Target="EndScroller.(Grid.ColumnSpan)" Value="3" />
<Setter Target="EndScroller.HorizontalAlignment" Value="Stretch" />
<Setter Target="EndScroller.VerticalAlignment" Value="Bottom" />
<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}" />
<Setter Target="CenterListView.ItemsPanel" Value="{StaticResource VerticalItemsPanel}" />
<Setter Target="EndListView.ItemsPanel" Value="{StaticResource VerticalItemsPanel}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="DockOnRight">
<VisualState.StateTriggers>
<ui:IsEqualStateTrigger Value="{x:Bind DockSide, Mode=OneWay}" To="Right" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="StartScroller.(Grid.Row)" Value="0" />
<Setter Target="StartScroller.(Grid.RowSpan)" Value="1" />
<Setter Target="StartScroller.(Grid.Column)" Value="0" />
<Setter Target="StartScroller.(Grid.ColumnSpan)" Value="3" />
<Setter Target="StartScroller.Orientation" Value="Vertical" />
<Setter Target="StartScroller.HorizontalAlignment" Value="Stretch" />
<Setter Target="StartScroller.VerticalAlignment" Value="Top" />
<Setter Target="StartScroller.Orientation" Value="Vertical" />
<Setter Target="CenterScroller.(Grid.Row)" Value="1" />
<Setter Target="CenterScroller.(Grid.RowSpan)" Value="1" />
<Setter Target="CenterScroller.(Grid.Column)" Value="0" />
<Setter Target="CenterScroller.(Grid.ColumnSpan)" Value="3" />
<Setter Target="CenterScroller.Orientation" Value="Vertical" />
<Setter Target="CenterScroller.HorizontalAlignment" Value="Stretch" />
<Setter Target="CenterScroller.VerticalAlignment" Value="Center" />
<Setter Target="CenterScroller.Orientation" Value="Vertical" />
<Setter Target="EndScroller.Orientation" Value="Vertical" />
<Setter Target="EndScroller.(Grid.Row)" Value="2" />
<Setter Target="EndScroller.(Grid.RowSpan)" Value="1" />
<Setter Target="EndScroller.(Grid.Column)" Value="0" />
<Setter Target="EndScroller.(Grid.ColumnSpan)" Value="3" />
<Setter Target="EndScroller.HorizontalAlignment" Value="Stretch" />
<Setter Target="EndScroller.VerticalAlignment" Value="Bottom" />
<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}" />
<Setter Target="CenterListView.ItemsPanel" Value="{StaticResource VerticalItemsPanel}" />
<Setter Target="EndListView.ItemsPanel" Value="{StaticResource VerticalItemsPanel}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<!-- Edit Mode Visual States -->
<VisualStateGroup x:Name="EditModeStates">
<VisualState x:Name="EditModeOff" />
<VisualState x:Name="EditModeOn">
<VisualState.Setters>
<Setter Target="StartScroller.BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" />
<Setter Target="StartScroller.Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" />
<Setter Target="StartScroller.BorderThickness" Value="1" />
<Setter Target="StartScroller.CornerRadius" Value="{StaticResource OverlayCornerRadius}" />
<Setter Target="CenterScroller.BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" />
<Setter Target="CenterScroller.Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" />
<Setter Target="CenterScroller.BorderThickness" Value="1" />
<Setter Target="CenterScroller.CornerRadius" Value="{StaticResource OverlayCornerRadius}" />
<Setter Target="EndScroller.BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" />
<Setter Target="EndScroller.Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" />
<Setter Target="EndScroller.BorderThickness" Value="1" />
<Setter Target="EndScroller.CornerRadius" Value="{StaticResource OverlayCornerRadius}" />
<Setter Target="StartScroller.ActionButtonVisibility" Value="Visible" />
<Setter Target="CenterScroller.ActionButtonVisibility" Value="Visible" />
<Setter Target="EndScroller.ActionButtonVisibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</UserControl>