diff --git a/src/AtomUI.Base/AtomUI.Base.csproj b/src/AtomUI.Base/AtomUI.Base.csproj
index f59805d27..b79f39bcc 100644
--- a/src/AtomUI.Base/AtomUI.Base.csproj
+++ b/src/AtomUI.Base/AtomUI.Base.csproj
@@ -17,6 +17,7 @@
+
diff --git a/src/AtomUI.Base/Common.cs b/src/AtomUI.Base/Common.cs
index a7222efcf..5e5f80920 100644
--- a/src/AtomUI.Base/Common.cs
+++ b/src/AtomUI.Base/Common.cs
@@ -59,4 +59,11 @@ public enum ColorNameFormat
{
HexRgb,
HexArgb
+}
+
+internal static class AtomUILogArea
+{
+ public const string Theme = "Theme";
+ public const string Control = "Control";
+ public const string System = "System";
}
\ No newline at end of file
diff --git a/src/AtomUI.Controls/Input/LineEdit.cs b/src/AtomUI.Controls/Input/LineEdit.cs
index 3ff1ef276..659d6d1a6 100644
--- a/src/AtomUI.Controls/Input/LineEdit.cs
+++ b/src/AtomUI.Controls/Input/LineEdit.cs
@@ -1,6 +1,8 @@
using AtomUI.Controls.Utils;
+using AtomUI.Theme;
using Avalonia;
using Avalonia.Controls;
+using Avalonia.LogicalTree;
namespace AtomUI.Controls;
@@ -28,6 +30,27 @@ public class LineEdit : TextBox
#endregion
+ #region 内部属性定义
+
+ private ControlTokenResourceRegister _controlTokenResourceRegister;
+ private bool _initialized;
+ #endregion
+
+ public LineEdit()
+ {
+ _controlTokenResourceRegister = new ControlTokenResourceRegister(this, LineEditToken.ID);
+ }
+
+ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToLogicalTree(e);
+ if (!_initialized)
+ {
+ _controlTokenResourceRegister.RegisterResources();
+ _initialized = true;
+ }
+ }
+
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
diff --git a/src/AtomUI.Controls/Utils/WaveSpiritAdorner.cs b/src/AtomUI.Controls/Utils/WaveSpiritAdorner.cs
index 5c37a63fd..1fde77748 100644
--- a/src/AtomUI.Controls/Utils/WaveSpiritAdorner.cs
+++ b/src/AtomUI.Controls/Utils/WaveSpiritAdorner.cs
@@ -1,3 +1,4 @@
+using AtomUI.Theme.Styling;
using AtomUI.Theme.Utils;
using Avalonia;
using Avalonia.Animation;
@@ -115,7 +116,59 @@ internal class WaveSpiritAdorner : Control, IDisposable
{
_targetControl = targetControl;
_targetControl.PropertyChanged += HandleTargetControlChanged;
- var sharedToken = TokenFinderUtils.FindSharedToken(_targetControl!);
+ var sharedToken = TokenFinderUtils.FindSharedToken(_targetControl!);
+ var themeVariant = TokenFinderUtils.FindThemeVariant(_targetControl);
+
+ CornerRadius? borderRadius = null;
+ // 获取相关值
+ {
+ if (_targetControl.TryGetResource(SharedTokenKey.BorderRadius, themeVariant, out var value))
+ {
+ if (value is CornerRadius cornerRadius)
+ {
+ borderRadius = cornerRadius;
+ }
+ }
+ }
+
+ borderRadius ??= sharedToken.BorderRadius;
+
+ TimeSpan? motionDurationSlow = null;
+ {
+ if (_targetControl.TryGetResource(SharedTokenKey.MotionDurationSlow, themeVariant, out var value))
+ {
+ if (value is TimeSpan timeSpan)
+ {
+ motionDurationSlow = timeSpan;
+ }
+ }
+ }
+ motionDurationSlow ??= sharedToken.MotionDurationSlow;
+
+ double? waveStartOpacity = null;
+ {
+ if (_targetControl.TryGetResource(SharedTokenKey.WaveStartOpacity, themeVariant, out var value))
+ {
+ if (value is double dvalue)
+ {
+ waveStartOpacity = dvalue;
+ }
+ }
+ }
+ waveStartOpacity ??= sharedToken.WaveStartOpacity;
+
+ double? waveAnimationRange = null;
+ {
+ if (_targetControl.TryGetResource(SharedTokenKey.WaveAnimationRange, themeVariant, out var value))
+ {
+ if (value is double dvalue)
+ {
+ waveAnimationRange = dvalue;
+ }
+ }
+ }
+ waveAnimationRange ??= sharedToken.WaveAnimationRange;
+
if (waveType == WaveType.CircleWave)
{
_wavePainter = new CircleWavePainter();
@@ -127,24 +180,34 @@ internal class WaveSpiritAdorner : Control, IDisposable
else
{
var roundWavePainter = new RoundRectWavePainter();
- roundWavePainter.CornerRadius = sharedToken.BorderRadius;
+ roundWavePainter.CornerRadius = borderRadius.Value;
_wavePainter = roundWavePainter;
}
-
- var motionDurationSlow = sharedToken.MotionDurationSlow;
+
_wavePainter.SizeEasingCurve = new CubicEaseOut();
_wavePainter.OpacityEasingCurve = new CubicEaseOut();
- _wavePainter.OriginOpacity = Math.Clamp(sharedToken.WaveStartOpacity, 0.0, 1.0);
- _wavePainter.SizeMotionDuration = motionDurationSlow;
- _wavePainter.OpacityMotionDuration = motionDurationSlow.Add(TimeSpan.FromMilliseconds(50));
- _wavePainter.WaveRange = Math.Min(sharedToken.WaveAnimationRange, 8);
+ _wavePainter.OriginOpacity = Math.Clamp(waveStartOpacity.Value, 0.0, 1.0);
+ _wavePainter.SizeMotionDuration = motionDurationSlow.Value;
+ _wavePainter.OpacityMotionDuration = motionDurationSlow.Value.Add(TimeSpan.FromMilliseconds(50));
+ _wavePainter.WaveRange = Math.Min(waveAnimationRange.Value, 8);
if (waveColor is not null)
{
_wavePainter.WaveColor = waveColor.Value;
}
else
{
- _wavePainter.WaveColor = sharedToken.ColorPrimary;
+ Color? colorPrimary = null;
+ {
+ if (_targetControl.TryGetResource(SharedTokenKey.ColorPrimary, themeVariant, out var value))
+ {
+ if (value is Color color)
+ {
+ colorPrimary = color;
+ }
+ }
+ }
+ colorPrimary ??= sharedToken.ColorPrimary;
+ _wavePainter.WaveColor = colorPrimary.Value;
}
LayoutUpdated += HandleLayoutUpdated;
diff --git a/src/AtomUI.Theme/ControlTokenInfoSetter.cs b/src/AtomUI.Theme/ControlTokenInfoSetter.cs
index 569a32303..b19b71ed5 100644
--- a/src/AtomUI.Theme/ControlTokenInfoSetter.cs
+++ b/src/AtomUI.Theme/ControlTokenInfoSetter.cs
@@ -1,9 +1,12 @@
+using Avalonia.Metadata;
+
namespace AtomUI.Theme;
public class ControlTokenInfoSetter
{
public bool EnableAlgorithm { get; set; } = false;
+ [Content]
public List Setters { get; set; } = new ();
public string? Catalog { get; set; }
diff --git a/src/AtomUI.Theme/ControlTokenResourceRegister.cs b/src/AtomUI.Theme/ControlTokenResourceRegister.cs
index cdd985914..88b79b82e 100644
--- a/src/AtomUI.Theme/ControlTokenResourceRegister.cs
+++ b/src/AtomUI.Theme/ControlTokenResourceRegister.cs
@@ -11,7 +11,7 @@ public class ControlTokenResourceRegister
private Control _target;
private string _tokenId;
private string? _resourceCatalog;
- private IResourceDictionary? _resourceDictionary;
+ private ResourceDictionary? _resourceDictionary;
public ControlTokenResourceRegister(Control target, string tokenId, string? resourceCatalog = null)
{
@@ -34,8 +34,9 @@ public class ControlTokenResourceRegister
{
_resourceDictionary.Add(entry.Key, entry.Value);
}
-
- _target.Resources.MergedDictionaries.Add(_resourceDictionary);
+
+ var themeVariant = TokenFinderUtils.FindThemeVariant(_target);
+ _target.Resources.ThemeDictionaries.Add(themeVariant, _resourceDictionary);
}
private IControlDesignToken? FindControlToken()
diff --git a/src/AtomUI.Theme/IThemeConfigProvider.cs b/src/AtomUI.Theme/IThemeConfigProvider.cs
index 27605a7c0..2382265a9 100644
--- a/src/AtomUI.Theme/IThemeConfigProvider.cs
+++ b/src/AtomUI.Theme/IThemeConfigProvider.cs
@@ -1,4 +1,5 @@
using AtomUI.Theme.TokenSystem;
+using Avalonia.Styling;
namespace AtomUI.Theme;
@@ -9,4 +10,5 @@ public interface IThemeConfigProvider
IControlDesignToken? GetControlToken(string tokenId, string? catalog = null);
List Algorithms { get; }
bool IsDarkMode { get; }
+ ThemeVariant ThemeVariant { get; }
}
\ No newline at end of file
diff --git a/src/AtomUI.Theme/TokenSystem/AbstractControlDesignToken.cs b/src/AtomUI.Theme/TokenSystem/AbstractControlDesignToken.cs
index de74d7d6e..364a4a064 100644
--- a/src/AtomUI.Theme/TokenSystem/AbstractControlDesignToken.cs
+++ b/src/AtomUI.Theme/TokenSystem/AbstractControlDesignToken.cs
@@ -83,7 +83,7 @@ public abstract class AbstractControlDesignToken : AbstractDesignToken, IControl
}
}
- _sharedResourceDeltaDictionary.Add(name, localSharedTokenValue);
+ _sharedResourceDeltaDictionary.Add(new TokenResourceKey(name), localSharedTokenValue);
}
}
diff --git a/src/AtomUI.Theme/TokenSystem/AbstractDesignToken.cs b/src/AtomUI.Theme/TokenSystem/AbstractDesignToken.cs
index c8ab54338..a1f5d07a0 100644
--- a/src/AtomUI.Theme/TokenSystem/AbstractDesignToken.cs
+++ b/src/AtomUI.Theme/TokenSystem/AbstractDesignToken.cs
@@ -1,5 +1,7 @@
-using System.Reflection;
+using System.Diagnostics;
+using System.Reflection;
using Avalonia.Controls;
+using Avalonia.Logging;
using Avalonia.Media;
namespace AtomUI.Theme.TokenSystem;
@@ -33,28 +35,33 @@ public abstract class AbstractDesignToken : IDesignToken
try
{
var type = GetType();
- var tokenProperties =
- type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
- foreach (var property in tokenProperties)
+ var tokenPropertyMap =
+ type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
+ .ToDictionary(p => p.Name);
+ foreach (var tokenInfo in tokenConfigInfo)
{
- var tokenName = property.Name;
- if (tokenConfigInfo.ContainsKey(tokenName))
+ var tokenName = tokenInfo.Key;
+ if (!tokenPropertyMap.ContainsKey(tokenInfo.Key))
{
- var propertyType = property.PropertyType;
- if (_valueConverters.ContainsKey(propertyType))
+ var logger = Logger.TryGet(LogEventLevel.Warning, AtomUILogArea.Theme);
+ logger?.Log(this, $"Token property: '{tokenInfo.Key}' found in token {type.Name}.'");
+ continue;
+ }
+ var property = tokenPropertyMap[tokenName];
+ var propertyType = property.PropertyType;
+ if (_valueConverters.ContainsKey(propertyType))
+ {
+ property.SetValue(this, _valueConverters[propertyType].Convert(tokenConfigInfo[tokenName]));
+ }
+ else
+ {
+ try
{
- property.SetValue(this, _valueConverters[propertyType].Convert(tokenConfigInfo[tokenName]));
+ property.SetValue(tokenName, tokenConfigInfo[tokenName]);
}
- else
+ catch (Exception ex)
{
- try
- {
- property.SetValue(tokenName, tokenConfigInfo[tokenName]);
- }
- catch (Exception ex)
- {
- throw new InvalidOperationException($"Unable to set token property: {tokenName}, maybe value type mismatch.", ex);
- }
+ throw new InvalidOperationException($"Unable to set token property: {tokenName}, maybe value type mismatch.", ex);
}
}
}
diff --git a/src/AtomUI.Theme/Utils/TokenFinderUtils.cs b/src/AtomUI.Theme/Utils/TokenFinderUtils.cs
index c4b37df36..d813be2fd 100644
--- a/src/AtomUI.Theme/Utils/TokenFinderUtils.cs
+++ b/src/AtomUI.Theme/Utils/TokenFinderUtils.cs
@@ -60,4 +60,28 @@ internal static class TokenFinderUtils
return token;
}
+
+ public static ThemeVariant FindThemeVariant(Control control)
+ {
+ ThemeVariant? themeVariant = null;
+ var current = control;
+ while (current != null)
+ {
+ if (current is IThemeConfigProvider configProvider)
+ {
+ themeVariant = configProvider.ThemeVariant;
+ break;
+ }
+
+ current = (current as IStyleHost).StylingParent as Control;
+ }
+
+ if (themeVariant is null)
+ {
+ var theme = ThemeManager.Current.ActivatedTheme;
+ Debug.Assert(theme != null);
+ themeVariant = theme.ThemeVariant;
+ }
+ return themeVariant;
+ }
}
\ No newline at end of file