diff --git a/src/AtomUI.Theme/IThemeManagerBuilder.cs b/src/AtomUI.Theme/IThemeManagerBuilder.cs index c57a1ab66..a4b41f3bb 100644 --- a/src/AtomUI.Theme/IThemeManagerBuilder.cs +++ b/src/AtomUI.Theme/IThemeManagerBuilder.cs @@ -1,5 +1,6 @@ using System.Globalization; using AtomUI.Theme.Language; +using AtomUI.Theme.Styling; using Avalonia; namespace AtomUI.Theme; @@ -23,4 +24,5 @@ public interface IThemeManagerBuilder void WithDefaultTheme(string themeId); void WithDefaultCultureInfo(CultureInfo cultureInfo); void WithDefaultLanguageVariant(LanguageVariant languageVariant); + void WithThemeVariantCalculatorFactory(IThemeVariantCalculatorFactory factory); } \ No newline at end of file diff --git a/src/AtomUI.Theme/Styling/IThemeVariantCalculatorFactory.cs b/src/AtomUI.Theme/Styling/IThemeVariantCalculatorFactory.cs new file mode 100644 index 000000000..51db2bb68 --- /dev/null +++ b/src/AtomUI.Theme/Styling/IThemeVariantCalculatorFactory.cs @@ -0,0 +1,6 @@ +namespace AtomUI.Theme.Styling; + +public interface IThemeVariantCalculatorFactory +{ + IThemeVariantCalculator Create(ThemeAlgorithm algorithm, IThemeVariantCalculator? baseAlgorithm); +} \ No newline at end of file diff --git a/src/AtomUI.Theme/Theme.cs b/src/AtomUI.Theme/Theme.cs index dfbf26665..ae6a70fa0 100644 --- a/src/AtomUI.Theme/Theme.cs +++ b/src/AtomUI.Theme/Theme.cs @@ -47,8 +47,9 @@ internal class Theme : AvaloniaObject, ITheme private bool _isBuiltIn; private bool _isPrimary; private IList _algorithms; + private ThemeManager _themeManager; - public Theme(string id, string defFilePath, ISet requestAlgorithms, bool isBuiltIn = false) + public Theme(ThemeManager themeManager, string id, string defFilePath, ISet requestAlgorithms, bool isBuiltIn = false) { _id = id; _isBuiltIn = isBuiltIn; @@ -71,6 +72,7 @@ internal class Theme : AvaloniaObject, ITheme } _themeVariant = BuildThemeVariant(id, _algorithms); + _themeManager = themeManager; } public List ThemeResourceKeys => ResourceDictionary.Keys.Select(s => s.ToString()!).ToList(); @@ -122,7 +124,7 @@ internal class Theme : AvaloniaObject, ITheme IThemeVariantCalculator? calculator = null; foreach (var algorithmId in algorithms) { - calculator = CreateThemeVariantCalculator(algorithmId, baseCalculator); + calculator = _themeManager.CreateThemeVariantCalculator(algorithmId, baseCalculator); baseCalculator = calculator; } @@ -217,7 +219,7 @@ internal class Theme : AvaloniaObject, ITheme BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy) - .Select(p => p.Name).ToHashSet(); + .Select(p => p.Name).ToHashSet(); foreach (var entry in controlTokenConfigInfo.Tokens) { if (!tokenProperties.Contains(entry.Key)) @@ -244,29 +246,6 @@ internal class Theme : AvaloniaObject, ITheme return algorithms; } - internal static IThemeVariantCalculator CreateThemeVariantCalculator(ThemeAlgorithm algorithm, IThemeVariantCalculator? baseAlgorithm) - { - IThemeVariantCalculator calculator; - if (algorithm == DefaultThemeVariantCalculator.Algorithm) - { - calculator = new DefaultThemeVariantCalculator(); - } - else if (algorithm == DarkThemeVariantCalculator.Algorithm) - { - calculator = new DarkThemeVariantCalculator(baseAlgorithm!); - } - else if (algorithm == CompactThemeVariantCalculator.Algorithm) - { - calculator = new CompactThemeVariantCalculator(baseAlgorithm!); - } - else - { - throw new ThemeLoadException($"Algorithm: {algorithm} is not supported."); - } - - return calculator; - } - protected void CollectControlTokens() { ControlTokens.Clear(); diff --git a/src/AtomUI.Theme/ThemeConfigProvider.cs b/src/AtomUI.Theme/ThemeConfigProvider.cs index d483838bc..57f7143e4 100644 --- a/src/AtomUI.Theme/ThemeConfigProvider.cs +++ b/src/AtomUI.Theme/ThemeConfigProvider.cs @@ -140,7 +140,7 @@ public class ThemeConfigProvider : Control, IThemeConfigProvider IThemeVariantCalculator? calculator = null; foreach (var algorithm in algorithms) { - calculator = AtomUITheme.CreateThemeVariantCalculator(algorithm, baseCalculator); + calculator = ThemeManager.Current.CreateThemeVariantCalculator(algorithm, baseCalculator); baseCalculator = calculator; } diff --git a/src/AtomUI.Theme/ThemeManager.cs b/src/AtomUI.Theme/ThemeManager.cs index b32ca0b24..28f624037 100644 --- a/src/AtomUI.Theme/ThemeManager.cs +++ b/src/AtomUI.Theme/ThemeManager.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using AtomUI.Theme.Language; +using AtomUI.Theme.Styling; using Avalonia; using Avalonia.Controls; using Avalonia.Platform; @@ -37,7 +38,8 @@ internal class ThemeManager : Styles, IThemeManager public string DefaultThemeId { get; set; } internal List ControlTokenTypes { get; set; } - + internal IThemeVariantCalculatorFactory? ThemeVariantCalculatorFactory { get; set; } + public event EventHandler? ThemeCreated; public event EventHandler? ThemeAboutToLoad; public event EventHandler? ThemeLoaded; @@ -61,8 +63,8 @@ internal class ThemeManager : Styles, IThemeManager internal ThemeManager() { - _themePool = new Dictionary(); - _customThemeDirs = new List(); + _themePool = new Dictionary(); + _customThemeDirs = new List(); var appName = Application.Current?.Name ?? DEFAULT_APP_NAME; _builtInThemeDirs = [Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), appName), THEME_DIR)]; @@ -284,7 +286,7 @@ internal class ThemeManager : Styles, IThemeManager var themeId = Path.GetFileNameWithoutExtension(filePath); foreach (var algorithms in algorithmsCombination) { - var theme = new Theme(themeId, filePath, algorithms ,isBuiltIn); + var theme = new Theme(this, themeId, filePath, algorithms ,isBuiltIn); var themeVariant = theme.ThemeVariant; if (themes.ContainsKey(themeVariant)) { @@ -362,6 +364,31 @@ internal class ThemeManager : Styles, IThemeManager Resources.MergedDictionaries.Add(languageResource); } } + + internal IThemeVariantCalculator CreateThemeVariantCalculator(ThemeAlgorithm algorithm, IThemeVariantCalculator? baseCalculator) + { + if (ThemeVariantCalculatorFactory != null) + { + return ThemeVariantCalculatorFactory.Create(algorithm, baseCalculator); + } + + if (algorithm == ThemeAlgorithm.Default) + { + return new DefaultThemeVariantCalculator(); + } + if (algorithm == ThemeAlgorithm.Dark) + { + Debug.Assert(baseCalculator is not null); + return new DarkThemeVariantCalculator(baseCalculator); + } + if (algorithm == ThemeAlgorithm.Compact) + { + Debug.Assert(baseCalculator is not null); + return new CompactThemeVariantCalculator(baseCalculator); + } + + throw new ArgumentOutOfRangeException(nameof(algorithm), $"Unsupported theme variant algorithm: {algorithm}"); + } } public class ThemeOperateEventArgs : EventArgs diff --git a/src/AtomUI.Theme/ThemeManagerBuilder.cs b/src/AtomUI.Theme/ThemeManagerBuilder.cs index 1ca4d41d3..c797d099c 100644 --- a/src/AtomUI.Theme/ThemeManagerBuilder.cs +++ b/src/AtomUI.Theme/ThemeManagerBuilder.cs @@ -1,5 +1,6 @@ using System.Globalization; using AtomUI.Theme.Language; +using AtomUI.Theme.Styling; using Avalonia; namespace AtomUI.Theme; @@ -12,6 +13,8 @@ internal class ThemeManagerBuilder : IThemeManagerBuilder public IList ControlThemesProviders { get; } public IList LanguageProviders { get; } public IList InitializedHandlers { get; } + + public IThemeVariantCalculatorFactory? ThemeVariantCalculatorFactory { get; internal set; } public LanguageVariant LanguageVariant { get; private set; } public string ThemeId { get; private set; } @@ -101,7 +104,8 @@ internal class ThemeManagerBuilder : IThemeManagerBuilder internal ThemeManager Build() { var themeManager = new ThemeManager(); - themeManager.DefaultThemeId = ThemeId; + themeManager.DefaultThemeId = ThemeId; + themeManager.ThemeVariantCalculatorFactory = ThemeVariantCalculatorFactory; foreach (var controlThemesProvider in ControlThemesProviders) { themeManager.RegisterControlThemesProvider(controlThemesProvider); @@ -129,4 +133,9 @@ internal class ThemeManagerBuilder : IThemeManagerBuilder return themeManager; } + + public void WithThemeVariantCalculatorFactory(IThemeVariantCalculatorFactory factory) + { + ThemeVariantCalculatorFactory = factory; + } } \ No newline at end of file