Merge pull request #166 from irihitech/issue/162-theme
Theme toggler update
This commit is contained in:
@@ -23,6 +23,15 @@ public abstract class ThemeSelectorBase: TemplatedControl
|
||||
set => SetValue(SelectedThemeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<ThemeSelectorMode> ModeProperty = AvaloniaProperty.Register<ThemeSelectorBase, ThemeSelectorMode>(
|
||||
nameof(Mode));
|
||||
|
||||
public ThemeSelectorMode Mode
|
||||
{
|
||||
get => GetValue(ModeProperty);
|
||||
set => SetValue(ModeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<ThemeVariantScope?> TargetScopeProperty =
|
||||
AvaloniaProperty.Register<ThemeSelectorBase, ThemeVariantScope?>(
|
||||
nameof(TargetScope));
|
||||
@@ -57,15 +66,21 @@ public abstract class ThemeSelectorBase: TemplatedControl
|
||||
_syncFromScope = true;
|
||||
if (this.TargetScope is { } target)
|
||||
{
|
||||
SyncThemeFromScope(target.ActualThemeVariant);
|
||||
SyncThemeFromScope(Mode == ThemeSelectorMode.Controller
|
||||
? target.RequestedThemeVariant
|
||||
: target.ActualThemeVariant);
|
||||
}
|
||||
else if (this._scope is { } scope)
|
||||
{
|
||||
SyncThemeFromScope(scope.ActualThemeVariant);
|
||||
SyncThemeFromScope(Mode == ThemeSelectorMode.Controller
|
||||
? scope.RequestedThemeVariant
|
||||
: scope.ActualThemeVariant);
|
||||
}
|
||||
else if (_application is { } app)
|
||||
{
|
||||
SyncThemeFromScope(app.ActualThemeVariant);
|
||||
SyncThemeFromScope(Mode == ThemeSelectorMode.Controller
|
||||
? app.RequestedThemeVariant
|
||||
: app.ActualThemeVariant);
|
||||
}
|
||||
_syncFromScope = false;
|
||||
}
|
||||
@@ -79,21 +94,29 @@ public abstract class ThemeSelectorBase: TemplatedControl
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
_application = Application.Current;
|
||||
_syncFromScope = true;
|
||||
if (_application is not null)
|
||||
{
|
||||
_application.ActualThemeVariantChanged += OnScopeThemeChanged;
|
||||
SyncThemeFromScope(_application.ActualThemeVariant);
|
||||
SyncThemeFromScope(Mode == ThemeSelectorMode.Controller
|
||||
? _application.RequestedThemeVariant
|
||||
: _application.ActualThemeVariant);
|
||||
}
|
||||
_scope = this.GetLogicalAncestors().FirstOrDefault(a => a is ThemeVariantScope) as ThemeVariantScope;
|
||||
if (_scope is not null)
|
||||
{
|
||||
_scope.ActualThemeVariantChanged += OnScopeThemeChanged;
|
||||
SyncThemeFromScope(_scope.ActualThemeVariant);
|
||||
SyncThemeFromScope(Mode == ThemeSelectorMode.Controller
|
||||
? _scope.RequestedThemeVariant
|
||||
: _scope.ActualThemeVariant);
|
||||
}
|
||||
if (TargetScope is not null)
|
||||
{
|
||||
SyncThemeFromScope(TargetScope.ActualThemeVariant);
|
||||
SyncThemeFromScope(Mode == ThemeSelectorMode.Controller
|
||||
? TargetScope.RequestedThemeVariant
|
||||
: TargetScope.ActualThemeVariant);
|
||||
}
|
||||
_syncFromScope = false;
|
||||
}
|
||||
|
||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
@@ -113,7 +136,6 @@ public abstract class ThemeSelectorBase: TemplatedControl
|
||||
{
|
||||
if (_syncFromScope) return;
|
||||
ThemeVariant? newTheme = args.NewValue.Value;
|
||||
if (newTheme is null) return;
|
||||
if (TargetScope is not null)
|
||||
{
|
||||
TargetScope.RequestedThemeVariant = newTheme;
|
||||
|
||||
7
src/Ursa/Controls/ThemeSelector/ThemeSelectorMode.cs
Normal file
7
src/Ursa/Controls/ThemeSelector/ThemeSelectorMode.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public enum ThemeSelectorMode
|
||||
{
|
||||
Controller,
|
||||
Indicator,
|
||||
}
|
||||
@@ -9,42 +9,90 @@ using Ursa.Common;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
[TemplatePart(PART_ThemeToggleButton, typeof(ToggleButton))]
|
||||
[TemplatePart(PART_ThemeButton, typeof(Button))]
|
||||
[PseudoClasses(PC_Dark, PC_Light, PC_Default)]
|
||||
public class ThemeToggleButton: ThemeSelectorBase
|
||||
{
|
||||
public const string PART_ThemeToggleButton = "PART_ThemeToggleButton";
|
||||
|
||||
/// <summary>
|
||||
/// This button IsChecked=true means ThemeVariant.Light, IsChecked=false means ThemeVariant.Dark.
|
||||
/// </summary>
|
||||
private ToggleButton? _button;
|
||||
private ThemeVariant? _currentTheme;
|
||||
public const string PART_ThemeButton = "PART_ThemeButton";
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
_currentTheme = this.ActualThemeVariant;
|
||||
}
|
||||
public const string PC_Light = ":light";
|
||||
public const string PC_Dark = ":dark";
|
||||
public const string PC_Default = ":default";
|
||||
|
||||
private Button? _button;
|
||||
private bool? _state;
|
||||
|
||||
public static readonly StyledProperty<bool> IsThreeStateProperty = AvaloniaProperty.Register<ThemeToggleButton, bool>(
|
||||
nameof(IsThreeState));
|
||||
|
||||
public bool IsThreeState
|
||||
{
|
||||
get => GetValue(IsThreeStateProperty);
|
||||
set => SetValue(IsThreeStateProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
Button.ClickEvent.RemoveHandler(OnButtonClickedChanged, _button);
|
||||
_button = e.NameScope.Get<ToggleButton>(PART_ThemeToggleButton);
|
||||
Button.ClickEvent.AddHandler(OnButtonClickedChanged, _button);
|
||||
ToggleButton.IsCheckedProperty.SetValue(_currentTheme == ThemeVariant.Light, _button);
|
||||
Button.ClickEvent.RemoveHandler(OnButtonClicked, _button);
|
||||
_button = e.NameScope.Get<Button>(PART_ThemeButton);
|
||||
Button.ClickEvent.AddHandler(OnButtonClicked, _button);
|
||||
// ToggleButton.IsCheckedProperty.SetValue(_currentTheme == ThemeVariant.Light, _button);
|
||||
}
|
||||
|
||||
private void OnButtonClickedChanged(object sender, RoutedEventArgs e)
|
||||
private void OnButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var newTheme = (sender as ToggleButton)!.IsChecked;
|
||||
if (newTheme is null) return;
|
||||
SetCurrentValue(SelectedThemeProperty, newTheme.Value ? ThemeVariant.Light : ThemeVariant.Dark);
|
||||
bool? currentState = _state;
|
||||
if (IsThreeState)
|
||||
{
|
||||
_state = currentState switch
|
||||
{
|
||||
true => false,
|
||||
false => null,
|
||||
null => true,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = currentState switch
|
||||
{
|
||||
true => false,
|
||||
false => true,
|
||||
null => true,
|
||||
};
|
||||
}
|
||||
if (_state == true)
|
||||
{
|
||||
SelectedTheme = ThemeVariant.Light;
|
||||
}
|
||||
else if (_state == false)
|
||||
{
|
||||
SelectedTheme = ThemeVariant.Dark;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedTheme = ThemeVariant.Default;
|
||||
}
|
||||
|
||||
if (Mode == ThemeSelectorMode.Controller)
|
||||
{
|
||||
PseudoClasses.Set(PC_Light, SelectedTheme == ThemeVariant.Light);
|
||||
PseudoClasses.Set(PC_Dark, SelectedTheme == ThemeVariant.Dark);
|
||||
PseudoClasses.Set(PC_Default, SelectedTheme == null || SelectedTheme == ThemeVariant.Default);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SyncThemeFromScope(ThemeVariant? theme)
|
||||
{
|
||||
base.SyncThemeFromScope(theme);
|
||||
ToggleButton.IsCheckedProperty.SetValue(theme == ThemeVariant.Light, _button);
|
||||
if (Mode == ThemeSelectorMode.Indicator)
|
||||
{
|
||||
PseudoClasses.Set(PC_Light, theme == ThemeVariant.Light);
|
||||
PseudoClasses.Set(PC_Dark, theme == ThemeVariant.Dark);
|
||||
PseudoClasses.Set(PC_Default, theme == null || SelectedTheme == ThemeVariant.Default);
|
||||
if (theme == ThemeVariant.Dark) _state = false;
|
||||
else if (theme == ThemeVariant.Light) _state = true;
|
||||
else _state = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user