Skip to content

Commit

Permalink
Merge pull request MahApps#3666 from MahApps/3623_Fix_styling_for_Win…
Browse files Browse the repository at this point in the history
…dowCommands_WindowButtonCommands

Fix theme based styling for WindowCommands and WindowButtonCommands
  • Loading branch information
punker76 committed Nov 2, 2019
2 parents 85a5f78 + 4719ef0 commit d1cee9c
Show file tree
Hide file tree
Showing 22 changed files with 358 additions and 125 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
</Controls:WindowCommands>
</Controls:MetroWindow.RightWindowCommands>

<Controls:MetroWindow.WindowButtonCommands>
<Controls:WindowButtonCommands Style="{DynamicResource MahApps.Styles.WindowButtonCommands.Clean.Win10}" />
</Controls:MetroWindow.WindowButtonCommands>

<Controls:MetroWindow.Flyouts>
<Controls:FlyoutsControl>
<Controls:Flyout x:Name="settingsFlyout"
Expand Down
97 changes: 48 additions & 49 deletions src/MahApps.Metro/Controls/MetroWindowHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,84 +105,83 @@ public static void HandleWindowCommandsForFlyouts(this MetroWindow window, IEnum

public static void ResetAllWindowCommandsBrush(this MetroWindow window)
{
window.ChangeAllWindowCommandsBrush(window.OverrideDefaultWindowCommandsBrush);
window.ChangeAllWindowButtonCommandsBrush(window.OverrideDefaultWindowCommandsBrush);
var currentAppTheme = ThemeManager.DetectTheme(window)
?? (Application.Current.MainWindow is MetroWindow metroWindow ? ThemeManager.DetectTheme(metroWindow) : null)
?? ThemeManager.DetectTheme(Application.Current);

window.ChangeAllWindowCommandsBrush(window.OverrideDefaultWindowCommandsBrush, currentAppTheme);
window.ChangeAllWindowButtonCommandsBrush(window.OverrideDefaultWindowCommandsBrush, currentAppTheme);
}

public static void UpdateWindowCommandsForFlyout(this MetroWindow window, Flyout flyout)
{
window.ChangeAllWindowCommandsBrush(window.OverrideDefaultWindowCommandsBrush);
window.ChangeAllWindowButtonCommandsBrush(window.OverrideDefaultWindowCommandsBrush ?? flyout.Foreground, flyout.Position);
var currentAppTheme = ThemeManager.DetectTheme(window)
?? (Application.Current.MainWindow is MetroWindow metroWindow ? ThemeManager.DetectTheme(metroWindow) : null)
?? ThemeManager.DetectTheme(Application.Current);

window.ChangeAllWindowCommandsBrush(window.OverrideDefaultWindowCommandsBrush, currentAppTheme);
window.ChangeAllWindowButtonCommandsBrush(window.OverrideDefaultWindowCommandsBrush ?? flyout.Foreground, currentAppTheme, flyout.Theme, flyout.Position);
}

private static bool NeedLightTheme(this Brush brush)
private static void ChangeAllWindowCommandsBrush(this MetroWindow window, Brush foregroundBrush, Metro.Theme currentAppTheme)
{
if (brush == null)
if (foregroundBrush == null)
{
return true;
window.LeftWindowCommands?.ClearValue(Control.ForegroundProperty);
window.RightWindowCommands?.ClearValue(Control.ForegroundProperty);
}

// calculate brush color lightness
var color = ((SolidColorBrush)brush).Color;

var r = color.R / 255.0f;
var g = color.G / 255.0f;
var b = color.B / 255.0f;

var max = r;
var min = r;

if (g > max) max = g;
if (b > max) max = b;

if (g < min) min = g;
if (b < min) min = b;

var lightness = (max + min) / 2;

return lightness > 0.1;
}

private static void ChangeAllWindowCommandsBrush(this MetroWindow window, Brush brush)
{
// set the theme based on color lightness
var theme = brush.NeedLightTheme() ? Theme.Light : Theme.Dark;
// set the theme based on current application or window theme
var theme = currentAppTheme != null && currentAppTheme.Type == ThemeType.Dark
? Theme.Dark
: Theme.Light;

// set the theme to light by default
window.LeftWindowCommands?.SetValue(WindowCommands.ThemeProperty, theme);
window.RightWindowCommands?.SetValue(WindowCommands.ThemeProperty, theme);

// clear or set the foreground property
if (brush != null)
if (foregroundBrush != null)
{
window.LeftWindowCommands?.SetValue(Control.ForegroundProperty, brush);
window.RightWindowCommands?.SetValue(Control.ForegroundProperty, brush);
}
else
{
window.LeftWindowCommands?.ClearValue(Control.ForegroundProperty);
window.RightWindowCommands?.ClearValue(Control.ForegroundProperty);
window.LeftWindowCommands?.SetValue(Control.ForegroundProperty, foregroundBrush);
window.RightWindowCommands?.SetValue(Control.ForegroundProperty, foregroundBrush);
}
}

private static void ChangeAllWindowButtonCommandsBrush(this MetroWindow window, Brush brush, Position position = Position.Top)
private static void ChangeAllWindowButtonCommandsBrush(this MetroWindow window, Brush foregroundBrush, Metro.Theme currentAppTheme, FlyoutTheme flyoutTheme = FlyoutTheme.Adapt, Position position = Position.Top)
{
// set the theme to light by default
if (position == Position.Right || position == Position.Top)
{
if (foregroundBrush == null)
{
window.WindowButtonCommands?.ClearValue(Control.ForegroundProperty);
}

// set the theme based on color lightness
var theme = brush.NeedLightTheme() ? Theme.Light : Theme.Dark;
// otherwise set the theme based on current application or window theme
var theme = currentAppTheme != null && currentAppTheme.Type == ThemeType.Dark
? Theme.Dark
: Theme.Light;

if (flyoutTheme == FlyoutTheme.Light)
{
theme = Theme.Light;
}
else if (flyoutTheme == FlyoutTheme.Dark)
{
theme = Theme.Dark;
}
else if (flyoutTheme == FlyoutTheme.Inverse)
{
theme = theme == Theme.Light ? Theme.Dark : Theme.Light;
}

window.WindowButtonCommands?.SetValue(WindowButtonCommands.ThemeProperty, theme);

// clear or set the foreground property
if (brush != null)
{
window.WindowButtonCommands?.SetValue(Control.ForegroundProperty, brush);
}
else
if (foregroundBrush != null)
{
window.WindowButtonCommands?.ClearValue(Control.ForegroundProperty);
window.WindowButtonCommands?.SetValue(Control.ForegroundProperty, foregroundBrush);
}
}
}
Expand Down
34 changes: 27 additions & 7 deletions src/MahApps.Metro/Controls/SplitButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,10 @@ private void ListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
e.Handled = true;
}

private void ExpanderClick(object sender, RoutedEventArgs e)
private void ExpanderMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.SetCurrentValue(IsExpandedProperty, !this.IsExpanded);
e.Handled = true;
}

public override void OnApplyTemplate()
Expand Down Expand Up @@ -320,14 +321,14 @@ private T EnforceInstance<T>(string partName) where T : FrameworkElement, new()

private void InitializeVisualElementsContainer()
{
this._expander.Click -= this.ExpanderClick;
this._expander.PreviewMouseLeftButtonDown -= this.ExpanderMouseLeftButtonDown;
this._clickButton.Click -= this.ButtonClick;
this._listBox.SelectionChanged -= this.ListBoxSelectionChanged;
this._listBox.PreviewMouseLeftButtonDown -= this.ListBoxPreviewMouseLeftButtonDown;
this._popup.Opened -= this.PopupOpened;
this._popup.Closed -= this.PopupClosed;

this._expander.Click += this.ExpanderClick;
this._expander.PreviewMouseLeftButtonDown += this.ExpanderMouseLeftButtonDown;
this._clickButton.Click += this.ButtonClick;
this._listBox.SelectionChanged += this.ListBoxSelectionChanged;
this._listBox.PreviewMouseLeftButtonDown += this.ListBoxPreviewMouseLeftButtonDown;
Expand All @@ -350,6 +351,11 @@ private void ListBoxPreviewMouseLeftButtonDown(object sender, MouseButtonEventAr
}

private void PopupClosed(object sender, EventArgs e)
{
this.OnPopupClose();
}

private void OnPopupClose()
{
this.SetCurrentValue(IsExpandedProperty, false);
this.ReleaseMouseCapture();
Expand All @@ -362,14 +368,28 @@ private void PopupClosed(object sender, EventArgs e)

private void PopupOpened(object sender, EventArgs e)
{
Mouse.Capture(this, CaptureMode.SubTree);
this.NavigateToContainer();

// Mouse capture can be lost on 'this' when the user clicks on the scroll bar, which can cause
// OutsideCapturedElementHandler to never be called. If we monitor the popup for lost mouse capture
// (which the popup gains on mouse down of the scroll bar), then we can recapture the mouse at that point
// to cause OutsideCapturedElementHandler to be called again.
Mouse.AddLostMouseCaptureHandler(this._popup, this.LostMouseCaptureHandler);
}

private void NavigateToContainer()
{
Mouse.Capture(this, CaptureMode.SubTree);
if (this._listBox.Focusable)
{
Keyboard.Focus(this._listBox);
}
else
{
this._listBox.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}

private void LostMouseCaptureHandler(object sender, MouseEventArgs e)
{
// If the list is still expanded, recapture the SplitButton subtree
Expand All @@ -378,13 +398,13 @@ private void LostMouseCaptureHandler(object sender, MouseEventArgs e)
// at all.
if (this.IsExpanded)
{
Mouse.Capture(this, CaptureMode.SubTree);
this.NavigateToContainer();
}
}

private void OutsideCapturedElementHandler(object sender, MouseButtonEventArgs e)
{
this.PopupClosed(sender, e);
this.OnPopupClose();
}

protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
Expand All @@ -393,7 +413,7 @@ protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChanged
// To hide the popup when the user e.g. alt+tabs, monitor for when the window becomes a background window.
if (!(bool)e.NewValue)
{
this.SetCurrentValue(IsExpandedProperty, false);
this.OnPopupClose();
}
}

Expand Down
1 change: 0 additions & 1 deletion src/MahApps.Metro/Styles/Clean/CleanWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

<Style x:Key="MahApps.Styles.MetroWindow.Clean" TargetType="{x:Type Controls:MetroWindow}">
<Setter Property="NonActiveWindowTitleBrush" Value="{DynamicResource MahApps.Brushes.TransparentWhite}" />
<Setter Property="OverrideDefaultWindowCommandsBrush" Value="{DynamicResource MahApps.Brushes.Black}" />
<Setter Property="TitleAlignment" Value="Center" />
<Setter Property="TitleForeground" Value="{DynamicResource MahApps.Brushes.Black}" />
<Setter Property="WindowTitleBrush" Value="{DynamicResource MahApps.Brushes.TransparentWhite}" />
Expand Down
17 changes: 16 additions & 1 deletion src/MahApps.Metro/Styles/Clean/CleanWindowButtonCommands.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,27 @@
xmlns:Controls="clr-namespace:MahApps.Metro.Controls">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Themes/WindowButtonCommands.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Clean/CleanWindowButtons.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style x:Key="MahApps.Styles.WindowButtonCommands.Clean" TargetType="{x:Type Controls:WindowButtonCommands}">
<Style x:Key="MahApps.Styles.WindowButtonCommands.Clean"
BasedOn="{StaticResource MahApps.Styles.WindowButtonCommands.Base}"
TargetType="{x:Type Controls:WindowButtonCommands}">
<Setter Property="DarkCloseButtonStyle" Value="{StaticResource MahApps.Styles.Button.CleanWindowClose.Dark}" />
<Setter Property="DarkMaxButtonStyle" Value="{DynamicResource MahApps.Styles.Button.CleanWindow.Dark}" />
<Setter Property="DarkMinButtonStyle" Value="{DynamicResource MahApps.Styles.Button.CleanWindow.Dark}" />
<Setter Property="LightCloseButtonStyle" Value="{StaticResource MahApps.Styles.Button.CleanWindowClose.Light}" />
<Setter Property="LightMaxButtonStyle" Value="{DynamicResource MahApps.Styles.Button.CleanWindow.Light}" />
<Setter Property="LightMinButtonStyle" Value="{DynamicResource MahApps.Styles.Button.CleanWindow.Light}" />
</Style>

<Style x:Key="MahApps.Styles.WindowButtonCommands.Clean.Win10"
BasedOn="{StaticResource MahApps.Styles.WindowButtonCommands.Clean}"
TargetType="{x:Type Controls:WindowButtonCommands}">
<Setter Property="DarkCloseButtonStyle" Value="{DynamicResource MahApps.Styles.Button.CleanWindow.Close.Dark.Win10}" />
<Setter Property="LightCloseButtonStyle" Value="{DynamicResource MahApps.Styles.Button.CleanWindow.Close.Light.Win10}" />
<Setter Property="Template" Value="{StaticResource MahApps.Templates.WindowButtonCommands.Win10}" />
</Style>

</ResourceDictionary>
72 changes: 69 additions & 3 deletions src/MahApps.Metro/Styles/Clean/CleanWindowButtons.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,50 @@
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.Buttons.xaml" />
</ResourceDictionary.MergedDictionaries>

<!-- light button style for min, max and close window buttons -->
<Style x:Key="MahApps.Styles.Button.CleanWindow.Light"
BasedOn="{StaticResource MahApps.Styles.Button.MetroWindow.Light}"
TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.SemiTransparentGray}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.Accent}" />
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.IdealForeground}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.IdealForegroundDisabled}" />
</Trigger>
</Style.Triggers>
</Style>

<!-- dark button style for min, max and close window buttons -->
<Style x:Key="MahApps.Styles.Button.CleanWindow.Dark"
BasedOn="{StaticResource MahApps.Styles.Button.MetroWindow.Light}"
TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.SemiTransparentGray}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.Accent}" />
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.IdealForeground}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.DarkIdealForegroundDisabled}" />
</Trigger>
</Style.Triggers>
</Style>

<!-- light button style for close window button (clean style) -->
<Style x:Key="MahApps.Styles.Button.CleanWindowClose.Light"
BasedOn="{StaticResource MahApps.Styles.Button.MetroWindow.Light}"
BasedOn="{StaticResource MahApps.Styles.Button.CleanWindow.Light}"
TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.CleanWindowCloseButton.Background}" />
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.White}" />
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.Black}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.CleanWindowCloseButton.PressedBackground}" />
Expand All @@ -22,7 +58,7 @@

<!-- dark button style for close window button (clean style) -->
<Style x:Key="MahApps.Styles.Button.CleanWindowClose.Dark"
BasedOn="{StaticResource MahApps.Styles.Button.MetroWindow.Dark}"
BasedOn="{StaticResource MahApps.Styles.Button.CleanWindow.Dark}"
TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
Expand All @@ -35,4 +71,34 @@
</Style.Triggers>
</Style>

<Style x:Key="MahApps.Styles.Button.CleanWindow.Close.Light.Win10"
BasedOn="{StaticResource MahApps.Styles.Button.CleanWindow.Light}"
TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E81123" />
<Setter Property="Foreground" Value="White" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#F1707A" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
</Style.Triggers>
</Style>

<Style x:Key="MahApps.Styles.Button.CleanWindow.Close.Dark.Win10"
BasedOn="{StaticResource MahApps.Styles.Button.CleanWindow.Dark}"
TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E81123" />
<Setter Property="Foreground" Value="White" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#F1707A" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
</Style.Triggers>
</Style>

</ResourceDictionary>
8 changes: 7 additions & 1 deletion src/MahApps.Metro/Styles/Clean/CleanWindowCommands.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls">

<Style x:Key="MahApps.Styles.WindowCommands.Clean" TargetType="{x:Type Controls:WindowCommands}">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Themes/WindowCommands.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style x:Key="MahApps.Styles.WindowCommands.Clean"
BasedOn="{StaticResource MahApps.Styles.WindowCommands.Base}"
TargetType="{x:Type Controls:WindowCommands}">
<Setter Property="Controls:ControlsHelper.ContentCharacterCasing" Value="Upper" />
<Setter Property="SeparatorHeight" Value="11" />
<Setter Property="ShowLastSeparator" Value="False" />
Expand Down

0 comments on commit d1cee9c

Please sign in to comment.