Skip to content

Commit ab4fca5

Browse files
committed
Improved focus visuals
1 parent 69ccdcd commit ab4fca5

File tree

20 files changed

+164
-50
lines changed

20 files changed

+164
-50
lines changed

source/iNKORE.UI.WPF.Modern.Controls/Controls/Community/SettingsControls/SettingsCard/SettingsCard.xaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
</ResourceDictionary>
7979

8080
</ControlTemplate.Resources>
81-
<ui:ElevationBorder x:Name="PART_RootBorder"
81+
<Border x:Name="PART_RootBorder"
8282
MinWidth="{TemplateBinding MinWidth}"
8383
MinHeight="{TemplateBinding MinHeight}"
8484
MaxWidth="{TemplateBinding MaxWidth}"
@@ -88,7 +88,8 @@
8888
Background="{TemplateBinding Background}"
8989
BorderBrush="{TemplateBinding BorderBrush}"
9090
BorderThickness="{TemplateBinding BorderThickness}"
91-
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}">
91+
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}"
92+
ui:FocusVisualHelper.IsTemplateFocusTarget="True">
9293
<VisualStateManager.VisualStateGroups>
9394
<VisualStateGroup x:Name="CommonStates">
9495
<ui:VisualStateGroupListener.Listener>
@@ -382,7 +383,7 @@
382383
ToolTipService.ToolTip="{TemplateBinding ActionIconToolTip}" />
383384
</Viewbox>
384385
</Grid>
385-
</ui:ElevationBorder>
386+
</Border>
386387

387388

388389
<ControlTemplate.Triggers>

source/iNKORE.UI.WPF.Modern.Controls/Controls/Community/SettingsControls/SettingsExpander/SettingsExpander.xaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,14 @@
5353
<Setter.Value>
5454
<ControlTemplate TargetType="ToggleButton">
5555

56-
<ui:ElevationBorder
56+
<Border
5757
x:Name="Background"
5858
Background="{TemplateBinding Background}"
5959
BorderBrush="{TemplateBinding BorderBrush}"
6060
BorderThickness="{TemplateBinding BorderThickness}"
6161
CornerRadius="{TemplateBinding chelper:ControlHelper.CornerRadius}"
62-
SnapsToDevicePixels="True">
62+
SnapsToDevicePixels="True"
63+
ui:FocusVisualHelper.IsTemplateFocusTarget="True">
6364
<Border
6465
x:Name="Border"
6566
Padding="{TemplateBinding Padding}"
@@ -116,7 +117,7 @@
116117
</VisualStateGroup>
117118
</VisualStateManager.VisualStateGroups>
118119

119-
</ui:ElevationBorder>
120+
</Border>
120121
<ControlTemplate.Triggers>
121122
<Trigger Property="IsMouseOver" Value="True">
122123
<Setter TargetName="Background" Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />

source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/CommandBar/CommandBar.xaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
-->
4949
<ContentControl
5050
x:Name="ContentControl"
51+
Margin="{TemplateBinding Padding}"
5152
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
5253
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
5354
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
@@ -76,14 +77,15 @@
7677
IsChecked="{Binding Path=IsOverflowOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
7778
IsEnabled="{TemplateBinding HasOverflowItems}"
7879
Style="{DynamicResource EllipsisButton}"
80+
ui:FocusVisualHelper.IsTemplateFocusTarget="True"
7981
Visibility="{TemplateBinding EffectiveOverflowButtonVisibility}">
8082
<ui:FontIcon
8183
x:Name="EllipsisIcon"
8284
Height="{DynamicResource AppBarExpandButtonCircleDiameter}"
8385
VerticalAlignment="Center"
84-
FontFamily="{DynamicResource FluentSystemIcons}"
86+
FontFamily="{DynamicResource SymbolThemeFontFamily}"
8587
FontSize="20"
86-
Glyph="&#xE826;" />
88+
Glyph="&#xE712;" />
8789
</ToggleButton>
8890
<Rectangle
8991
x:Name="HighContrastBorder"
@@ -129,6 +131,7 @@
129131
</primitives:CommandBarOverflowPresenter.Resources>
130132
<primitives:CommandBarOverflowPanel
131133
x:Name="PART_ToolBarOverflowPanel"
134+
Margin="{DynamicResource CommandBarOverflowPresenterMargin}"
132135
FocusVisualStyle="{x:Null}"
133136
Focusable="true"
134137
KeyboardNavigation.DirectionalNavigation="Cycle"
@@ -210,7 +213,6 @@
210213
SnapsToDevicePixels="True">
211214
<Border Padding="{TemplateBinding Padding}" CornerRadius="{TemplateBinding CornerRadius}">
212215
<ui:ScrollViewerEx
213-
Padding="{DynamicResource CommandBarOverflowPresenterMargin}"
214216
Content="{TemplateBinding Content}"
215217
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
216218
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"

source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/HyperlinkButton/HyperlinkButton.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
BorderBrush="{TemplateBinding BorderBrush}"
3131
BorderThickness="{TemplateBinding BorderThickness}"
3232
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}"
33+
ui:FocusVisualHelper.IsTemplateFocusTarget="True"
3334
SnapsToDevicePixels="True">
3435
<Border
3536
x:Name="Border"

source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/RadioMenuItem/RadioMenuItem.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<Setter Property="BorderThickness" Value="{DynamicResource MenuFlyoutItemRevealBorderThickness}" />
1515
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemForeground}" />
1616
<Setter Property="Padding" Value="{DynamicResource MenuFlyoutItemThemePadding}" />
17+
<Setter Property="ui:ControlHelper.CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
1718
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
1819
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
1920
<Setter Property="VerticalContentAlignment" Value="Center" />

source/iNKORE.UI.WPF.Modern.Controls/Controls/Windows/ToggleSwitch/ToggleSwitch.xaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<Setter Property="MinWidth" Value="{DynamicResource ToggleSwitchThemeMinWidth}" />
3333
<Setter Property="FocusVisualStyle" Value="{DynamicResource {x:Static SystemParameters.FocusVisualStyleKey}}" />
3434
<Setter Property="ui:FocusVisualHelper.FocusVisualMargin" Value="-7,-3,-7,-3" />
35+
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
3536
<Setter Property="Template">
3637
<Setter.Value>
3738
<ControlTemplate TargetType="local:ToggleSwitch">
@@ -123,6 +124,8 @@
123124
Visibility="Collapsed" />
124125
<Grid
125126
Grid.Row="1"
127+
ui:FocusVisualHelper.IsTemplateFocusTarget="True"
128+
ui:ControlHelper.CornerRadius="{TemplateBinding CornerRadius}"
126129
HorizontalAlignment="Left"
127130
VerticalAlignment="Top">
128131

@@ -144,7 +147,6 @@
144147
Grid.RowSpan="3"
145148
Grid.ColumnSpan="5"
146149
Margin="0,5"
147-
ui:FocusVisualHelper.IsTemplateFocusTarget="True"
148150
Background="{DynamicResource ToggleSwitchContainerBackground}"
149151
CornerRadius="{TemplateBinding CornerRadius}" />
150152
<ui:ContentPresenterEx

source/iNKORE.UI.WPF.Modern.Gallery/Controls/ControlExample.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<sys:Double x:Key="ExampleMaxWidth">1000</sys:Double>
1414

1515
<Style TargetType="local:ControlExample">
16+
<Setter Property="IsTabStop" Value="False"/>
1617
<Setter Property="Template">
1718
<Setter.Value>
1819
<ControlTemplate TargetType="local:ControlExample">

source/iNKORE.UI.WPF.Modern/Controls/Helpers/FocusVisualHelper.cs

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Windows.Controls;
1111
using System.Windows.Documents;
1212
using System.Windows.Media;
13+
using iNKORE.UI.WPF.Helpers;
1314

1415
namespace iNKORE.UI.WPF.Modern.Controls.Helpers
1516
{
@@ -163,6 +164,20 @@ public static void SetFocusVisualSecondaryThickness(FrameworkElement element, Th
163164

164165
#endregion
165166

167+
#region FocusVisualPrimaryCornerRadius
168+
169+
public static CornerRadius GetFocusVisualPrimaryCornerRadius(FrameworkElement element) => (CornerRadius)element.GetValue(FocusVisualPrimaryCornerRadiusProperty);
170+
private static void SetFocusVisualPrimaryCornerRadius(FrameworkElement element, CornerRadius value) => element.SetValue(FocusVisualPrimaryCornerRadiusProperty, value);
171+
172+
public static readonly DependencyProperty FocusVisualPrimaryCornerRadiusProperty =
173+
DependencyProperty.RegisterAttached(
174+
"FocusVisualPrimaryCornerRadius",
175+
typeof(CornerRadius),
176+
typeof(FocusVisualHelper),
177+
new FrameworkPropertyMetadata(new CornerRadius(0)));
178+
179+
#endregion
180+
166181
#region FocusVisualMargin
167182

168183
/// <summary>
@@ -393,7 +408,7 @@ static void ShowFocusVisual(Control control, FrameworkElement target)
393408
{
394409
HideFocusVisual();
395410

396-
AdornerLayer adornerlayer = AdornerLayer.GetAdornerLayer(target);
411+
AdornerLayer adornerlayer = GetAdornerLayer(target);
397412
if (adornerlayer == null)
398413
return;
399414

@@ -414,6 +429,17 @@ static void ShowFocusVisual(Control control, FrameworkElement target)
414429
}
415430
}
416431

432+
static AdornerLayer? GetAdornerLayer(FrameworkElement element)
433+
{
434+
var scrollPresenter = element.FindAscendant<ScrollContentPresenter>();
435+
if (scrollPresenter?.Parent is AdornerDecorator adornerDecorator)
436+
{
437+
return adornerDecorator.AdornerLayer;
438+
}
439+
440+
return AdornerLayer.GetAdornerLayer(element);
441+
}
442+
417443
static void OnControlIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
418444
{
419445
((Control)sender).IsVisibleChanged -= OnControlIsVisibleChanged;
@@ -483,11 +509,15 @@ private static void OnFocusVisualIsVisibleChanged(object sender, DependencyPrope
483509
}
484510
else
485511
{
512+
var focusVisualMargin = GetFocusVisualMargin(focusedElement);
513+
514+
ApplyCornerRadiusToFocusVisual(focusVisual, focusedElement, focusVisualMargin);
515+
486516
TransferValue(focusedElement, focusVisual, FocusVisualPrimaryBrushProperty);
487517
TransferValue(focusedElement, focusVisual, FocusVisualPrimaryThicknessProperty);
488518
TransferValue(focusedElement, focusVisual, FocusVisualSecondaryBrushProperty);
489519
TransferValue(focusedElement, focusVisual, FocusVisualSecondaryThicknessProperty);
490-
focusVisual.Margin = GetFocusVisualMargin(focusedElement);
520+
focusVisual.Margin = focusVisualMargin;
491521
}
492522

493523
SetFocusedElement(focusVisual, focusedElement);
@@ -510,6 +540,39 @@ private static void OnFocusVisualIsVisibleChanged(object sender, DependencyPrope
510540
}
511541
}
512542

543+
private static void ApplyCornerRadiusToFocusVisual(Control focusVisual, FrameworkElement focusedElement, Thickness focusVisualMargin)
544+
{
545+
var cornerRadius = GetCornerRadiusForFocusedElement(focusedElement);
546+
if (cornerRadius is CornerRadius focusedCornerRadius && focusedCornerRadius != default)
547+
{
548+
var focusVisualCornerRadius = new CornerRadius(
549+
GetSumIfSourceIsNonZero(focusedCornerRadius.TopLeft, -(focusVisualMargin.Left + focusVisualMargin.Top) / 2),
550+
GetSumIfSourceIsNonZero(focusedCornerRadius.TopRight, -(focusVisualMargin.Right + focusVisualMargin.Top) / 2),
551+
GetSumIfSourceIsNonZero(focusedCornerRadius.BottomLeft, -(focusVisualMargin.Left + focusVisualMargin.Bottom) / 2),
552+
GetSumIfSourceIsNonZero(focusedCornerRadius.BottomRight, -(focusVisualMargin.Right + focusVisualMargin.Bottom) / 2));
553+
554+
ControlHelper.SetCornerRadius(focusVisual, focusVisualCornerRadius);
555+
var topLeftRadius = GetSumIfSourceIsNonZero(focusVisualCornerRadius.TopLeft, GetFocusVisualSecondaryThickness(focusedElement).Left);
556+
var topRightRadius = GetSumIfSourceIsNonZero(focusVisualCornerRadius.TopRight, GetFocusVisualSecondaryThickness(focusedElement).Right);
557+
var bottomRightRadius = GetSumIfSourceIsNonZero(focusVisualCornerRadius.BottomLeft, GetFocusVisualSecondaryThickness(focusedElement).Left);
558+
var bottomLeftRadius = GetSumIfSourceIsNonZero(focusVisualCornerRadius.BottomRight, GetFocusVisualSecondaryThickness(focusedElement).Right);
559+
560+
SetFocusVisualPrimaryCornerRadius(focusVisual, new CornerRadius(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius));
561+
}
562+
}
563+
564+
private static CornerRadius? GetCornerRadiusForFocusedElement(FrameworkElement focusedElement)
565+
{
566+
var cornerRadiusTarget = focusedElement.GetValue(TemplateFocusTargetProperty) as FrameworkElement;
567+
cornerRadiusTarget ??= focusedElement;
568+
return cornerRadiusTarget switch
569+
{
570+
var _ when cornerRadiusTarget.GetValue(Border.CornerRadiusProperty) is CornerRadius borderResult && borderResult != default => borderResult,
571+
var _ when cornerRadiusTarget.GetValue(ControlHelper.CornerRadiusProperty) is CornerRadius controlResult => controlResult,
572+
_ => null
573+
};
574+
}
575+
513576
private static void TransferValue(DependencyObject source, DependencyObject target, DependencyProperty dp)
514577
{
515578
if (!source.HasDefaultValue(dp))
@@ -518,6 +581,12 @@ private static void TransferValue(DependencyObject source, DependencyObject targ
518581
}
519582
}
520583

584+
private static double GetSumIfSourceIsNonZero(double source, double adjustment) => source switch
585+
{
586+
0 => 0,
587+
_ => source + adjustment
588+
};
589+
521590
private sealed class FocusVisualAdorner : Adorner
522591
{
523592
public FocusVisualAdorner(Control focusedElement, UIElement adornedElement, Style focusVisualStyle) : base(adornedElement)
@@ -531,13 +600,18 @@ public FocusVisualAdorner(Control focusedElement, UIElement adornedElement, Styl
531600
Control control = new Control();
532601
SetIsSystemFocusVisual(control, false);
533602
control.Style = focusVisualStyle;
534-
control.Margin = GetFocusVisualMargin(focusedElement);
603+
604+
var focusVisualMargin = GetFocusVisualMargin(focusedElement);
605+
control.Margin = focusVisualMargin;
606+
607+
ApplyCornerRadiusToFocusVisual(control, focusedElement, focusVisualMargin);
608+
535609
TransferValue(focusedElement, control, FocusVisualPrimaryBrushProperty);
536610
TransferValue(focusedElement, control, FocusVisualPrimaryThicknessProperty);
537611
TransferValue(focusedElement, control, FocusVisualSecondaryBrushProperty);
538612
TransferValue(focusedElement, control, FocusVisualSecondaryThicknessProperty);
539613
_adorderChild = control;
540-
IsClipEnabled = true;
614+
IsClipEnabled = false;
541615
IsHitTestVisible = false;
542616
IsEnabled = false;
543617
AddVisualChild(_adorderChild);

source/iNKORE.UI.WPF.Modern/Themes/Controls/ComboBox.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@
396396
Background="{DynamicResource ComboBoxBackgroundFocused}"
397397
BorderBrush="{DynamicResource ComboBoxBackgroundBorderBrushFocused}"
398398
BorderThickness="{DynamicResource ComboBoxBackgroundBorderThicknessFocused}"
399-
CornerRadius="{TemplateBinding chelper:ControlHelper.CornerRadius}"
399+
CornerRadius="{DynamicResource ComboBoxHiglightBorderCornerRadius}"
400400
Opacity="0" />
401401
<local:ElevationBorder
402402
x:Name="Background"

source/iNKORE.UI.WPF.Modern/Themes/Controls/CommandBar.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
BorderBrush="{TemplateBinding BorderBrush}"
4444
BorderThickness="{TemplateBinding BorderThickness}"
4545
CornerRadius="{TemplateBinding chelper:ControlHelper.CornerRadius}"
46+
chelper:FocusVisualHelper.IsTemplateFocusTarget="True"
4647
SnapsToDevicePixels="True">
4748
<local:ContentPresenterEx
4849
x:Name="ContentPresenter"

0 commit comments

Comments
 (0)