From 200c32b8303f2da5c44cf603e42ed1bd5444c16e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 16 Mar 2025 14:52:55 +0800 Subject: [PATCH] Code cleanup --- Flow.Launcher.Core/Resource/Theme.cs | 668 ++++++++++++++------------- 1 file changed, 342 insertions(+), 326 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index c1fac0a23..60ae046e3 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -14,13 +14,19 @@ using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Microsoft.Win32; using Flow.Launcher.Plugin; -using TextBox = System.Windows.Controls.TextBox; using System.Windows.Threading; +using TextBox = System.Windows.Controls.TextBox; namespace Flow.Launcher.Core.Resource { public class Theme { + #region Properties & Fields + + public string CurrentTheme => _settings.Theme; + + public bool BlurEnabled { get; set; } + private const string ThemeMetadataNamePrefix = "Name:"; private const string ThemeMetadataIsDarkPrefix = "IsDark:"; private const string ThemeMetadataHasBlurPrefix = "HasBlur:"; @@ -37,9 +43,7 @@ namespace Flow.Launcher.Core.Resource private static string DirectoryPath => Path.Combine(Constant.ProgramDirectory, Folder); private static string UserDirectoryPath => Path.Combine(DataLocation.DataDirectory(), Folder); - public string CurrentTheme => _settings.Theme; - - public bool BlurEnabled { get; set; } + #endregion public Theme(IPublicAPI publicAPI, Settings settings) { @@ -67,6 +71,339 @@ namespace Flow.Launcher.Core.Resource _oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath); } + #region Theme Resources + + private void MakeSureThemeDirectoriesExist() + { + foreach (var dir in _themeDirectories.Where(dir => !Directory.Exists(dir))) + { + try + { + Directory.CreateDirectory(dir); + } + catch (Exception e) + { + Log.Exception($"|Theme.MakesureThemeDirectoriesExist|Exception when create directory <{dir}>", e); + } + } + } + + private void UpdateResourceDictionary(ResourceDictionary dictionaryToUpdate) + { + var dicts = Application.Current.Resources.MergedDictionaries; + + dicts.Remove(_oldResource); + dicts.Add(dictionaryToUpdate); + _oldResource = dictionaryToUpdate; + } + + private ResourceDictionary GetThemeResourceDictionary(string theme) + { + var uri = GetThemePath(theme); + var dict = new ResourceDictionary + { + Source = new Uri(uri, UriKind.Absolute) + }; + + return dict; + } + + private ResourceDictionary GetResourceDictionary(string theme) + { + var dict = GetThemeResourceDictionary(theme); + + if (dict["QueryBoxStyle"] is Style queryBoxStyle && + dict["QuerySuggestionBoxStyle"] is Style querySuggestionBoxStyle) + { + var fontFamily = new FontFamily(_settings.QueryBoxFont); + var fontStyle = FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.QueryBoxFontStyle); + var fontWeight = FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.QueryBoxFontWeight); + var fontStretch = FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.QueryBoxFontStretch); + + queryBoxStyle.Setters.Add(new Setter(TextBox.FontFamilyProperty, fontFamily)); + queryBoxStyle.Setters.Add(new Setter(TextBox.FontStyleProperty, fontStyle)); + queryBoxStyle.Setters.Add(new Setter(TextBox.FontWeightProperty, fontWeight)); + queryBoxStyle.Setters.Add(new Setter(TextBox.FontStretchProperty, fontStretch)); + + var caretBrushPropertyValue = queryBoxStyle.Setters.OfType().Any(x => x.Property.Name == "CaretBrush"); + var foregroundPropertyValue = queryBoxStyle.Setters.OfType().Where(x => x.Property.Name == "Foreground") + .Select(x => x.Value).FirstOrDefault(); + if (!caretBrushPropertyValue && foregroundPropertyValue != null) //otherwise BaseQueryBoxStyle will handle styling + queryBoxStyle.Setters.Add(new Setter(TextBox.CaretBrushProperty, foregroundPropertyValue)); + + // Query suggestion box's font style is aligned with query box + querySuggestionBoxStyle.Setters.Add(new Setter(TextBox.FontFamilyProperty, fontFamily)); + querySuggestionBoxStyle.Setters.Add(new Setter(TextBox.FontStyleProperty, fontStyle)); + querySuggestionBoxStyle.Setters.Add(new Setter(TextBox.FontWeightProperty, fontWeight)); + querySuggestionBoxStyle.Setters.Add(new Setter(TextBox.FontStretchProperty, fontStretch)); + } + + if (dict["ItemTitleStyle"] is Style resultItemStyle && + dict["ItemTitleSelectedStyle"] is Style resultItemSelectedStyle && + dict["ItemHotkeyStyle"] is Style resultHotkeyItemStyle && + dict["ItemHotkeySelectedStyle"] is Style resultHotkeyItemSelectedStyle) + { + Setter fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(_settings.ResultFont)); + Setter fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.ResultFontStyle)); + Setter fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.ResultFontWeight)); + Setter fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.ResultFontStretch)); + + Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch }; + Array.ForEach( + new[] { resultItemStyle, resultItemSelectedStyle, resultHotkeyItemStyle, resultHotkeyItemSelectedStyle }, o + => Array.ForEach(setters, p => o.Setters.Add(p))); + } + + if ( + dict["ItemSubTitleStyle"] is Style resultSubItemStyle && + dict["ItemSubTitleSelectedStyle"] is Style resultSubItemSelectedStyle) + { + Setter fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(_settings.ResultSubFont)); + Setter fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.ResultSubFontStyle)); + Setter fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.ResultSubFontWeight)); + Setter fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.ResultSubFontStretch)); + + Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch }; + Array.ForEach( + new[] { resultSubItemStyle, resultSubItemSelectedStyle }, o + => Array.ForEach(setters, p => o.Setters.Add(p))); + } + + /* Ignore Theme Window Width and use setting */ + var windowStyle = dict["WindowStyle"] as Style; + var width = _settings.WindowSize; + windowStyle.Setters.Add(new Setter(Window.WidthProperty, width)); + return dict; + } + + private ResourceDictionary GetCurrentResourceDictionary() + { + return GetResourceDictionary(_settings.Theme); + } + + private ThemeData GetThemeDataFromPath(string path) + { + using var reader = XmlReader.Create(path); + reader.Read(); + + var extensionlessName = Path.GetFileNameWithoutExtension(path); + + if (reader.NodeType is not XmlNodeType.Comment) + return new ThemeData(extensionlessName, extensionlessName); + + var commentLines = reader.Value.Trim().Split('\n').Select(v => v.Trim()); + + var name = extensionlessName; + bool? isDark = null; + bool? hasBlur = null; + foreach (var line in commentLines) + { + if (line.StartsWith(ThemeMetadataNamePrefix, StringComparison.OrdinalIgnoreCase)) + { + name = line[ThemeMetadataNamePrefix.Length..].Trim(); + } + else if (line.StartsWith(ThemeMetadataIsDarkPrefix, StringComparison.OrdinalIgnoreCase)) + { + isDark = bool.Parse(line[ThemeMetadataIsDarkPrefix.Length..].Trim()); + } + else if (line.StartsWith(ThemeMetadataHasBlurPrefix, StringComparison.OrdinalIgnoreCase)) + { + hasBlur = bool.Parse(line[ThemeMetadataHasBlurPrefix.Length..].Trim()); + } + } + + return new ThemeData(extensionlessName, name, isDark, hasBlur); + } + + private string GetThemePath(string themeName) + { + foreach (string themeDirectory in _themeDirectories) + { + string path = Path.Combine(themeDirectory, themeName + Extension); + if (File.Exists(path)) + { + return path; + } + } + + return string.Empty; + } + + #endregion + + #region Load & Change + + public List LoadAvailableThemes() + { + List themes = new List(); + foreach (var themeDirectory in _themeDirectories) + { + var filePaths = Directory + .GetFiles(themeDirectory) + .Where(filePath => filePath.EndsWith(Extension) && !filePath.EndsWith("Base.xaml")) + .Select(GetThemeDataFromPath); + themes.AddRange(filePaths); + } + + return themes.OrderBy(o => o.Name).ToList(); + } + + public bool ChangeTheme(string theme) + { + const string defaultTheme = Constant.DefaultTheme; + + string path = GetThemePath(theme); + try + { + if (string.IsNullOrEmpty(path)) + throw new DirectoryNotFoundException("Theme path can't be found <{path}>"); + + // reload all resources even if the theme itself hasn't changed in order to pickup changes + // to things like fonts + UpdateResourceDictionary(GetResourceDictionary(theme)); + + _settings.Theme = theme; + + //always allow re-loading default theme, in case of failure of switching to a new theme from default theme + if (_oldTheme != theme || theme == defaultTheme) + { + _oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath); + } + + BlurEnabled = IsBlurTheme(); + //if (_settings.UseDropShadowEffect) + // AddDropShadowEffectToCurrentTheme(); + //Win32Helper.SetBlurForWindow(Application.Current.MainWindow, BlurEnabled); + SetBlurForWindow(); + } + catch (DirectoryNotFoundException) + { + Log.Error($"|Theme.ChangeTheme|Theme <{theme}> path can't be found"); + if (theme != defaultTheme) + { + _api.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_path_not_exists"), theme)); + ChangeTheme(defaultTheme); + } + return false; + } + catch (XamlParseException) + { + Log.Error($"|Theme.ChangeTheme|Theme <{theme}> fail to parse"); + if (theme != defaultTheme) + { + _api.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_parse_error"), theme)); + ChangeTheme(defaultTheme); + } + return false; + } + return true; + } + + #endregion + + #region Shadow Effect + + public void AddDropShadowEffectToCurrentTheme() + { + var dict = GetCurrentResourceDictionary(); + + var windowBorderStyle = dict["WindowBorderStyle"] as Style; + + var effectSetter = new Setter + { + Property = Border.EffectProperty, + Value = new DropShadowEffect + { + Opacity = 0.3, + ShadowDepth = 12, + Direction = 270, + BlurRadius = 30 + } + }; + + if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) is not Setter marginSetter) + { + var margin = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin); + marginSetter = new Setter() + { + Property = Border.MarginProperty, + Value = margin, + }; + windowBorderStyle.Setters.Add(marginSetter); + + SetResizeBoarderThickness(margin); + } + else + { + var baseMargin = (Thickness)marginSetter.Value; + var newMargin = new Thickness( + baseMargin.Left + ShadowExtraMargin, + baseMargin.Top + ShadowExtraMargin, + baseMargin.Right + ShadowExtraMargin, + baseMargin.Bottom + ShadowExtraMargin); + marginSetter.Value = newMargin; + + SetResizeBoarderThickness(newMargin); + } + + windowBorderStyle.Setters.Add(effectSetter); + + UpdateResourceDictionary(dict); + } + + public void RemoveDropShadowEffectFromCurrentTheme() + { + var dict = GetCurrentResourceDictionary(); + var windowBorderStyle = dict["WindowBorderStyle"] as Style; + + if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.EffectProperty) is Setter effectSetter) + { + windowBorderStyle.Setters.Remove(effectSetter); + } + + if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) is Setter marginSetter) + { + var currentMargin = (Thickness)marginSetter.Value; + var newMargin = new Thickness( + currentMargin.Left - ShadowExtraMargin, + currentMargin.Top - ShadowExtraMargin, + currentMargin.Right - ShadowExtraMargin, + currentMargin.Bottom - ShadowExtraMargin); + marginSetter.Value = newMargin; + } + + SetResizeBoarderThickness(null); + + UpdateResourceDictionary(dict); + } + + // because adding drop shadow effect will change the margin of the window, + // we need to update the window chrome thickness to correct set the resize border + private static void SetResizeBoarderThickness(Thickness? effectMargin) + { + var window = Application.Current.MainWindow; + if (WindowChrome.GetWindowChrome(window) is WindowChrome windowChrome) + { + Thickness thickness; + if (effectMargin == null) + { + thickness = SystemParameters.WindowResizeBorderThickness; + } + else + { + thickness = new Thickness( + effectMargin.Value.Left + SystemParameters.WindowResizeBorderThickness.Left, + effectMargin.Value.Top + SystemParameters.WindowResizeBorderThickness.Top, + effectMargin.Value.Right + SystemParameters.WindowResizeBorderThickness.Right, + effectMargin.Value.Bottom + SystemParameters.WindowResizeBorderThickness.Bottom); + } + + windowChrome.ResizeBorderThickness = thickness; + } + } + + #endregion + #region Blur Handling public void RefreshFrame() @@ -314,7 +651,7 @@ namespace Flow.Launcher.Core.Resource // Apply DWM Dark Mode Win32Helper.DWMSetDarkModeForWindow(mainWindow, useDarkMode); - + Color LightBG; Color DarkBG; @@ -375,327 +712,6 @@ namespace Flow.Launcher.Core.Resource #endregion - private void MakeSureThemeDirectoriesExist() - { - foreach (var dir in _themeDirectories.Where(dir => !Directory.Exists(dir))) - { - try - { - Directory.CreateDirectory(dir); - } - catch (Exception e) - { - Log.Exception($"|Theme.MakesureThemeDirectoriesExist|Exception when create directory <{dir}>", e); - } - } - } - - public bool ChangeTheme(string theme) - { - const string defaultTheme = Constant.DefaultTheme; - - string path = GetThemePath(theme); - try - { - if (string.IsNullOrEmpty(path)) - throw new DirectoryNotFoundException("Theme path can't be found <{path}>"); - - // reload all resources even if the theme itself hasn't changed in order to pickup changes - // to things like fonts - UpdateResourceDictionary(GetResourceDictionary(theme)); - - _settings.Theme = theme; - - //always allow re-loading default theme, in case of failure of switching to a new theme from default theme - if (_oldTheme != theme || theme == defaultTheme) - { - _oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath); - } - - BlurEnabled = IsBlurTheme(); - //if (_settings.UseDropShadowEffect) - // AddDropShadowEffectToCurrentTheme(); - //Win32Helper.SetBlurForWindow(Application.Current.MainWindow, BlurEnabled); - SetBlurForWindow(); - } - catch (DirectoryNotFoundException) - { - Log.Error($"|Theme.ChangeTheme|Theme <{theme}> path can't be found"); - if (theme != defaultTheme) - { - _api.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_path_not_exists"), theme)); - ChangeTheme(defaultTheme); - } - return false; - } - catch (XamlParseException) - { - Log.Error($"|Theme.ChangeTheme|Theme <{theme}> fail to parse"); - if (theme != defaultTheme) - { - _api.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_parse_error"), theme)); - ChangeTheme(defaultTheme); - } - return false; - } - return true; - } - - private void UpdateResourceDictionary(ResourceDictionary dictionaryToUpdate) - { - var dicts = Application.Current.Resources.MergedDictionaries; - - dicts.Remove(_oldResource); - dicts.Add(dictionaryToUpdate); - _oldResource = dictionaryToUpdate; - } - - private ResourceDictionary GetThemeResourceDictionary(string theme) - { - var uri = GetThemePath(theme); - var dict = new ResourceDictionary - { - Source = new Uri(uri, UriKind.Absolute) - }; - - return dict; - } - - public ResourceDictionary GetResourceDictionary(string theme) - { - var dict = GetThemeResourceDictionary(theme); - - if (dict["QueryBoxStyle"] is Style queryBoxStyle && - dict["QuerySuggestionBoxStyle"] is Style querySuggestionBoxStyle) - { - var fontFamily = new FontFamily(_settings.QueryBoxFont); - var fontStyle = FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.QueryBoxFontStyle); - var fontWeight = FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.QueryBoxFontWeight); - var fontStretch = FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.QueryBoxFontStretch); - - queryBoxStyle.Setters.Add(new Setter(TextBox.FontFamilyProperty, fontFamily)); - queryBoxStyle.Setters.Add(new Setter(TextBox.FontStyleProperty, fontStyle)); - queryBoxStyle.Setters.Add(new Setter(TextBox.FontWeightProperty, fontWeight)); - queryBoxStyle.Setters.Add(new Setter(TextBox.FontStretchProperty, fontStretch)); - - var caretBrushPropertyValue = queryBoxStyle.Setters.OfType().Any(x => x.Property.Name == "CaretBrush"); - var foregroundPropertyValue = queryBoxStyle.Setters.OfType().Where(x => x.Property.Name == "Foreground") - .Select(x => x.Value).FirstOrDefault(); - if (!caretBrushPropertyValue && foregroundPropertyValue != null) //otherwise BaseQueryBoxStyle will handle styling - queryBoxStyle.Setters.Add(new Setter(TextBox.CaretBrushProperty, foregroundPropertyValue)); - - // Query suggestion box's font style is aligned with query box - querySuggestionBoxStyle.Setters.Add(new Setter(TextBox.FontFamilyProperty, fontFamily)); - querySuggestionBoxStyle.Setters.Add(new Setter(TextBox.FontStyleProperty, fontStyle)); - querySuggestionBoxStyle.Setters.Add(new Setter(TextBox.FontWeightProperty, fontWeight)); - querySuggestionBoxStyle.Setters.Add(new Setter(TextBox.FontStretchProperty, fontStretch)); - } - - if (dict["ItemTitleStyle"] is Style resultItemStyle && - dict["ItemTitleSelectedStyle"] is Style resultItemSelectedStyle && - dict["ItemHotkeyStyle"] is Style resultHotkeyItemStyle && - dict["ItemHotkeySelectedStyle"] is Style resultHotkeyItemSelectedStyle) - { - Setter fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(_settings.ResultFont)); - Setter fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.ResultFontStyle)); - Setter fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.ResultFontWeight)); - Setter fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.ResultFontStretch)); - - Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch }; - Array.ForEach( - new[] { resultItemStyle, resultItemSelectedStyle, resultHotkeyItemStyle, resultHotkeyItemSelectedStyle }, o - => Array.ForEach(setters, p => o.Setters.Add(p))); - } - - if ( - dict["ItemSubTitleStyle"] is Style resultSubItemStyle && - dict["ItemSubTitleSelectedStyle"] is Style resultSubItemSelectedStyle) - { - Setter fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(_settings.ResultSubFont)); - Setter fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.ResultSubFontStyle)); - Setter fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.ResultSubFontWeight)); - Setter fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.ResultSubFontStretch)); - - Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch }; - Array.ForEach( - new[] { resultSubItemStyle,resultSubItemSelectedStyle}, o - => Array.ForEach(setters, p => o.Setters.Add(p))); - } - - /* Ignore Theme Window Width and use setting */ - var windowStyle = dict["WindowStyle"] as Style; - var width = _settings.WindowSize; - windowStyle.Setters.Add(new Setter(Window.WidthProperty, width)); - return dict; - } - - private ResourceDictionary GetCurrentResourceDictionary() - { - return GetResourceDictionary(_settings.Theme); - } - - public List LoadAvailableThemes() - { - List themes = new List(); - foreach (var themeDirectory in _themeDirectories) - { - var filePaths = Directory - .GetFiles(themeDirectory) - .Where(filePath => filePath.EndsWith(Extension) && !filePath.EndsWith("Base.xaml")) - .Select(GetThemeDataFromPath); - themes.AddRange(filePaths); - } - - return themes.OrderBy(o => o.Name).ToList(); - } - - private ThemeData GetThemeDataFromPath(string path) - { - using var reader = XmlReader.Create(path); - reader.Read(); - - var extensionlessName = Path.GetFileNameWithoutExtension(path); - - if (reader.NodeType is not XmlNodeType.Comment) - return new ThemeData(extensionlessName, extensionlessName); - - var commentLines = reader.Value.Trim().Split('\n').Select(v => v.Trim()); - - var name = extensionlessName; - bool? isDark = null; - bool? hasBlur = null; - foreach (var line in commentLines) - { - if (line.StartsWith(ThemeMetadataNamePrefix, StringComparison.OrdinalIgnoreCase)) - { - name = line[ThemeMetadataNamePrefix.Length..].Trim(); - } - else if (line.StartsWith(ThemeMetadataIsDarkPrefix, StringComparison.OrdinalIgnoreCase)) - { - isDark = bool.Parse(line[ThemeMetadataIsDarkPrefix.Length..].Trim()); - } - else if (line.StartsWith(ThemeMetadataHasBlurPrefix, StringComparison.OrdinalIgnoreCase)) - { - hasBlur = bool.Parse(line[ThemeMetadataHasBlurPrefix.Length..].Trim()); - } - } - - return new ThemeData(extensionlessName, name, isDark, hasBlur); - } - - private string GetThemePath(string themeName) - { - foreach (string themeDirectory in _themeDirectories) - { - string path = Path.Combine(themeDirectory, themeName + Extension); - if (File.Exists(path)) - { - return path; - } - } - - return string.Empty; - } - - public void AddDropShadowEffectToCurrentTheme() - { - var dict = GetCurrentResourceDictionary(); - - var windowBorderStyle = dict["WindowBorderStyle"] as Style; - - var effectSetter = new Setter - { - Property = Border.EffectProperty, - Value = new DropShadowEffect - { - Opacity = 0.3, - ShadowDepth = 12, - Direction = 270, - BlurRadius = 30 - } - }; - - if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) is not Setter marginSetter) - { - var margin = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin); - marginSetter = new Setter() - { - Property = Border.MarginProperty, - Value = margin, - }; - windowBorderStyle.Setters.Add(marginSetter); - - SetResizeBoarderThickness(margin); - } - else - { - var baseMargin = (Thickness)marginSetter.Value; - var newMargin = new Thickness( - baseMargin.Left + ShadowExtraMargin, - baseMargin.Top + ShadowExtraMargin, - baseMargin.Right + ShadowExtraMargin, - baseMargin.Bottom + ShadowExtraMargin); - marginSetter.Value = newMargin; - - SetResizeBoarderThickness(newMargin); - } - - windowBorderStyle.Setters.Add(effectSetter); - - UpdateResourceDictionary(dict); - } - - public void RemoveDropShadowEffectFromCurrentTheme() - { - var dict = GetCurrentResourceDictionary(); - var windowBorderStyle = dict["WindowBorderStyle"] as Style; - - if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.EffectProperty) is Setter effectSetter) - { - windowBorderStyle.Setters.Remove(effectSetter); - } - - if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) is Setter marginSetter) - { - var currentMargin = (Thickness)marginSetter.Value; - var newMargin = new Thickness( - currentMargin.Left - ShadowExtraMargin, - currentMargin.Top - ShadowExtraMargin, - currentMargin.Right - ShadowExtraMargin, - currentMargin.Bottom - ShadowExtraMargin); - marginSetter.Value = newMargin; - } - - SetResizeBoarderThickness(null); - - UpdateResourceDictionary(dict); - } - - // because adding drop shadow effect will change the margin of the window, - // we need to update the window chrome thickness to correct set the resize border - private static void SetResizeBoarderThickness(Thickness? effectMargin) - { - var window = Application.Current.MainWindow; - if (WindowChrome.GetWindowChrome(window) is WindowChrome windowChrome) - { - Thickness thickness; - if (effectMargin == null) - { - thickness = SystemParameters.WindowResizeBorderThickness; - } - else - { - thickness = new Thickness( - effectMargin.Value.Left + SystemParameters.WindowResizeBorderThickness.Left, - effectMargin.Value.Top + SystemParameters.WindowResizeBorderThickness.Top, - effectMargin.Value.Right + SystemParameters.WindowResizeBorderThickness.Right, - effectMargin.Value.Bottom + SystemParameters.WindowResizeBorderThickness.Bottom); - } - - windowChrome.ResizeBorderThickness = thickness; - } - } - public record ThemeData(string FileNameWithoutExtension, string Name, bool? IsDark = null, bool? HasBlur = null); } }