Skip to content

Commit

Permalink
Merge pull request #10149 from AvaloniaUI/theme-variant-changes
Browse files Browse the repository at this point in the history
ThemeVariant property definitions to ThemeVariantScope + fix DataGrid theme variant switch
  • Loading branch information
maxkatz6 authored Feb 21, 2023
2 parents 025177d + 74ef92a commit 827402d
Show file tree
Hide file tree
Showing 17 changed files with 305 additions and 250 deletions.
39 changes: 17 additions & 22 deletions src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,18 @@ public ResourceObservable(IResourceHost target, object key, Func<object?, object
protected override void Initialize()
{
_target.ResourcesChanged += ResourcesChanged;
if (_target is StyledElement themeStyleable)
if (_target is IThemeVariantHost themeVariantHost)
{
themeStyleable.PropertyChanged += PropertyChanged;
themeVariantHost.ActualThemeVariantChanged += ActualThemeVariantChanged;
}
}

protected override void Deinitialize()
{
_target.ResourcesChanged -= ResourcesChanged;
if (_target is StyledElement themeStyleable)
if (_target is IThemeVariantHost themeVariantHost)
{
themeStyleable.PropertyChanged -= PropertyChanged;
themeVariantHost.ActualThemeVariantChanged -= ActualThemeVariantChanged;
}
}

Expand All @@ -163,18 +163,15 @@ private void ResourcesChanged(object? sender, ResourcesChangedEventArgs e)
PublishNext(GetValue());
}

private void PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
private void ActualThemeVariantChanged(object? sender, EventArgs e)
{
if (e.Property == StyledElement.ActualThemeVariantProperty)
{
PublishNext(GetValue());
}
PublishNext(GetValue());
}

private object? GetValue()
{
if (_target is not StyledElement themeStyleable
|| !_target.TryFindResource(_key, themeStyleable.ActualThemeVariant, out var value))
if (_target is not IThemeVariantHost themeVariantHost
|| !_target.TryFindResource(_key, themeVariantHost.ActualThemeVariant, out var value))
{
value = _target.FindResource(_key) ?? AvaloniaProperty.UnsetValue;
}
Expand Down Expand Up @@ -236,9 +233,9 @@ private void OwnerChanged(object? sender, EventArgs e)
{
_owner.ResourcesChanged -= ResourcesChanged;
}
if (_owner is StyledElement styleable)
if (_owner is IThemeVariantHost themeVariantHost)
{
styleable.PropertyChanged += PropertyChanged;
themeVariantHost.ActualThemeVariantChanged += ActualThemeVariantChanged;
}

_owner = _target.Owner;
Expand All @@ -247,20 +244,18 @@ private void OwnerChanged(object? sender, EventArgs e)
{
_owner.ResourcesChanged += ResourcesChanged;
}
if (_owner is StyledElement styleable2)
if (_owner is IThemeVariantHost themeVariantHost2)
{
styleable2.PropertyChanged += PropertyChanged;
themeVariantHost2.ActualThemeVariantChanged -= ActualThemeVariantChanged;
}


PublishNext();
}

private void PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
private void ActualThemeVariantChanged(object? sender, EventArgs e)
{
if (e.Property == StyledElement.ActualThemeVariantProperty)
{
PublishNext();
}
PublishNext();
}

private void ResourcesChanged(object? sender, ResourcesChangedEventArgs e)
Expand All @@ -270,8 +265,8 @@ private void ResourcesChanged(object? sender, ResourcesChangedEventArgs e)

private object? GetValue()
{
if (!(_target.Owner is StyledElement themeStyleable)
|| !_target.Owner.TryFindResource(_key, themeStyleable.ActualThemeVariant, out var value))
if (!(_target.Owner is IThemeVariantHost themeVariantHost)
|| !_target.Owner.TryFindResource(_key, themeVariantHost.ActualThemeVariant, out var value))
{
value = _target.Owner?.FindResource(_key) ?? AvaloniaProperty.UnsetValue;
}
Expand Down
46 changes: 16 additions & 30 deletions src/Avalonia.Base/StyledElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace Avalonia
public class StyledElement : Animatable,
IDataContextProvider,
ILogical,
IResourceHost,
IThemeVariantHost,
IStyleHost,
IStyleable,
ISetLogicalParent,
Expand Down Expand Up @@ -75,23 +75,6 @@ public class StyledElement : Animatable,
public static readonly StyledProperty<ControlTheme?> ThemeProperty =
AvaloniaProperty.Register<StyledElement, ControlTheme?>(nameof(Theme));

/// <summary>
/// Defines the <see cref="ActualThemeVariant"/> property.
/// </summary>
public static readonly StyledProperty<ThemeVariant> ActualThemeVariantProperty =
AvaloniaProperty.Register<StyledElement, ThemeVariant>(
nameof(ThemeVariant),
inherits: true,
defaultValue: ThemeVariant.Light);

/// <summary>
/// Defines the RequestedThemeVariant property.
/// </summary>
public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
AvaloniaProperty.Register<StyledElement, ThemeVariant?>(
nameof(ThemeVariant),
defaultValue: ThemeVariant.Default);

private static readonly ControlTheme s_invalidTheme = new ControlTheme();
private int _initCount;
private string? _name;
Expand Down Expand Up @@ -160,6 +143,9 @@ public StyledElement()
/// </summary>
public event EventHandler<ResourcesChangedEventArgs>? ResourcesChanged;

/// <inheritdoc />
public event EventHandler? ActualThemeVariantChanged;

/// <summary>
/// Gets or sets the name of the styled element.
/// </summary>
Expand Down Expand Up @@ -278,15 +264,6 @@ public ControlTheme? Theme
set => SetValue(ThemeProperty, value);
}

/// <summary>
/// Gets the UI theme that is currently used by the element, which might be different than the <see cref="RequestedThemeVariantProperty"/>.
/// </summary>
/// <returns>
/// If current control is contained in the ThemeVariantScope, TopLevel or Application with non-default RequestedThemeVariant, that value will be returned.
/// Otherwise, current OS theme variant is returned.
/// </returns>
public ThemeVariant ActualThemeVariant => GetValue(ActualThemeVariantProperty);

/// <summary>
/// Gets the styled element's logical children.
/// </summary>
Expand Down Expand Up @@ -325,6 +302,9 @@ protected internal IAvaloniaList<ILogical> LogicalChildren
/// </summary>
public StyledElement? Parent { get; private set; }

/// <inheritdoc />
public ThemeVariant ActualThemeVariant => GetValue(ThemeVariant.ActualThemeVariantProperty);

/// <summary>
/// Gets the styled element's logical parent.
/// </summary>
Expand Down Expand Up @@ -644,13 +624,19 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
base.OnPropertyChanged(change);

if (change.Property == ThemeProperty)
{
OnControlThemeChanged();
else if (change.Property == RequestedThemeVariantProperty)
}
else if (change.Property == ThemeVariant.RequestedThemeVariantProperty)
{
if (change.GetNewValue<ThemeVariant>() is {} themeVariant && themeVariant != ThemeVariant.Default)
SetValue(ActualThemeVariantProperty, themeVariant);
SetValue(ThemeVariant.ActualThemeVariantProperty, themeVariant);
else
ClearValue(ActualThemeVariantProperty);
ClearValue(ThemeVariant.ActualThemeVariantProperty);
}
else if (change.Property == ThemeVariant.ActualThemeVariantProperty)
{
ActualThemeVariantChanged?.Invoke(this, EventArgs.Empty);
}
}

Expand Down
22 changes: 0 additions & 22 deletions src/Avalonia.Base/Styling/IGlobalThemeVariantProvider.cs

This file was deleted.

26 changes: 26 additions & 0 deletions src/Avalonia.Base/Styling/IThemeVariantHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Avalonia.Controls;
using Avalonia.Metadata;

namespace Avalonia.Styling;

/// <summary>
/// Interface for the host element with a theme variant.
/// </summary>
[Unstable]
public interface IThemeVariantHost : IResourceHost
{
/// <summary>
/// Gets the UI theme that is currently used by the element, which might be different than the RequestedThemeVariantProperty.
/// </summary>
/// <returns>
/// If current control is contained in the ThemeVariantScope, TopLevel or Application with non-default RequestedThemeVariant, that value will be returned.
/// Otherwise, current OS theme variant is returned.
/// </returns>
ThemeVariant ActualThemeVariant { get; }

/// <summary>
/// Raised when the theme variant is changed on the element or an ancestor of the element.
/// </summary>
event EventHandler? ActualThemeVariantChanged;
}
17 changes: 16 additions & 1 deletion src/Avalonia.Base/Styling/ThemeVariant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,26 @@
namespace Avalonia.Styling;

/// <summary>
/// Specifies a UI theme variant that should be used for the
/// Specifies a UI theme variant that should be used for the Control and Application types.
/// </summary>
[TypeConverter(typeof(ThemeVariantTypeConverter))]
public sealed record ThemeVariant
{
/// <summary>
/// Defines the ActualThemeVariant property.
/// </summary>
internal static readonly StyledProperty<ThemeVariant> ActualThemeVariantProperty =
AvaloniaProperty.Register<StyledElement, ThemeVariant>(
"ActualThemeVariant",
inherits: true);

/// <summary>
/// Defines the RequestedThemeVariant property.
/// </summary>
internal static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
AvaloniaProperty.Register<StyledElement, ThemeVariant?>(
"RequestedThemeVariant", defaultValue: Default);

/// <summary>
/// Creates a new instance of the <see cref="ThemeVariant"/>
/// </summary>
Expand Down
71 changes: 44 additions & 27 deletions src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,48 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:collections="using:Avalonia.Collections">
<Styles.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="DataGridColumnHeaderForegroundBrush" Color="{DynamicResource SystemBaseMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{DynamicResource SystemAltHighColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderDraggedBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderBackgroundBrush" Color="{DynamicResource SystemChromeMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderForegroundBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowHoveredBackgroundColor" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush" Color="{DynamicResource SystemAltMediumColor}" />
<SolidColorBrush x:Key="DataGridCellInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridGridLinesBrush" Opacity="0.4" Color="{DynamicResource SystemBaseMediumLowColor}" />
<SolidColorBrush x:Key="DataGridDetailsPresenterBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />

</ResourceDictionary>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="DataGridColumnHeaderForegroundBrush" Color="{DynamicResource SystemBaseMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{DynamicResource SystemAltHighColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderDraggedBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderBackgroundBrush" Color="{DynamicResource SystemChromeMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderForegroundBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowHoveredBackgroundColor" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush" Color="{DynamicResource SystemAltMediumColor}" />
<SolidColorBrush x:Key="DataGridCellInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridGridLinesBrush" Opacity="0.4" Color="{DynamicResource SystemBaseMediumLowColor}" />
<SolidColorBrush x:Key="DataGridDetailsPresenterBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />

</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>

<x:Double x:Key="ListAccentLowOpacity">0.6</x:Double>
<x:Double x:Key="ListAccentMediumOpacity">0.8</x:Double>

Expand All @@ -9,43 +51,17 @@
<StreamGeometry x:Key="DataGridRowGroupHeaderIconClosedPath">M515 93l930 931l-930 931l90 90l1022 -1021l-1022 -1021z</StreamGeometry>
<StreamGeometry x:Key="DataGridRowGroupHeaderIconOpenedPath">M109 486 19 576 1024 1581 2029 576 1939 486 1024 1401z</StreamGeometry>

<SolidColorBrush x:Key="DataGridColumnHeaderForegroundBrush" Color="{DynamicResource SystemBaseMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{DynamicResource SystemAltHighColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderDraggedBackgroundBrush"
Color="{DynamicResource SystemChromeMediumLowColor}" />

<SolidColorBrush x:Key="DataGridRowGroupHeaderBackgroundBrush" Color="{DynamicResource SystemChromeMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderPressedBackgroundBrush"
Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderForegroundBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />

<StaticResource x:Key="DataGridRowBackgroundBrush" ResourceKey="SystemControlTransparentBrush" />
<SolidColorBrush x:Key="DataGridRowSelectedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedBackgroundOpacity" ResourceKey="ListAccentLowOpacity" />
<SolidColorBrush x:Key="DataGridRowSelectedHoveredBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedHoveredBackgroundOpacity" ResourceKey="ListAccentMediumOpacity" />
<SolidColorBrush x:Key="DataGridRowSelectedUnfocusedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedUnfocusedBackgroundOpacity" ResourceKey="ListAccentLowOpacity" />
<SolidColorBrush x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundBrush"
Color="{DynamicResource SystemAccentColor}" />
<SolidColorBrush x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundOpacity" ResourceKey="ListAccentMediumOpacity" />
<SolidColorBrush x:Key="DataGridRowHoveredBackgroundColor" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />

<StaticResource x:Key="DataGridCellBackgroundBrush" ResourceKey="SystemControlTransparentBrush" />
<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush" Color="{DynamicResource SystemAltMediumColor}" />
<SolidColorBrush x:Key="DataGridCellInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />

<SolidColorBrush x:Key="DataGridGridLinesBrush"
Opacity="0.4"
Color="{DynamicResource SystemBaseMediumLowColor}" />
<StaticResource x:Key="DataGridCurrencyVisualPrimaryBrush" ResourceKey="SystemControlTransparentBrush" />
<SolidColorBrush x:Key="DataGridDetailsPresenterBackgroundBrush"
Color="{DynamicResource SystemChromeMediumLowColor}" />
<StaticResource x:Key="DataGridFillerColumnGridLinesBrush" ResourceKey="SystemControlTransparentBrush" />

<ControlTheme x:Key="DataGridCellTextBlockTheme" TargetType="TextBlock">
Expand Down Expand Up @@ -565,5 +581,6 @@
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>
</Styles.Resources>
</Styles>
Loading

0 comments on commit 827402d

Please sign in to comment.