Skip to content

Commit 5bcaaee

Browse files
authored
Refactor drop shadow handling for window border style (#4318)
1 parent f7a937e commit 5bcaaee

File tree

2 files changed

+93
-48
lines changed

2 files changed

+93
-48
lines changed

Flow.Launcher.Core/Resource/Theme.cs

Lines changed: 82 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -473,76 +473,114 @@ public bool ChangeTheme(string theme = null)
473473

474474
public void AddDropShadowEffectToCurrentTheme()
475475
{
476-
var dict = GetCurrentResourceDictionary();
476+
// Get current theme's WindowBorderStyle
477+
var theme = _settings.Theme;
478+
var dict = GetThemeResourceDictionary(theme);
479+
var windowBorderStyle = dict.Contains("WindowBorderStyle") ? dict["WindowBorderStyle"] as Style : null;
480+
if (windowBorderStyle == null) return;
477481

478-
var windowBorderStyle = dict["WindowBorderStyle"] as Style;
482+
// Get a new unsealed style based on the old one, and copy Resources and Triggers
483+
var newWindowBorderStyle = new Style(typeof(Border));
484+
ThemeHelper.CopyStyle(windowBorderStyle, newWindowBorderStyle);
479485

480-
var effectSetter = new Setter
486+
// Identify existing Margin to calculate new Margin, and copy other setters
487+
Setter existingMarginSetter = null;
488+
foreach (var setterBase in windowBorderStyle.Setters)
481489
{
482-
Property = UIElement.EffectProperty,
483-
Value = new DropShadowEffect
490+
if (setterBase is Setter setter)
484491
{
485-
Opacity = 0.3,
486-
ShadowDepth = 12,
487-
Direction = 270,
488-
BlurRadius = 30
492+
// Skip existing Margin (we'll replace it)
493+
if (setter.Property == FrameworkElement.MarginProperty)
494+
{
495+
existingMarginSetter = setter;
496+
continue;
497+
}
498+
499+
// Skip existing Effect (we'll ensure strictly one is added)
500+
if (setter.Property == UIElement.EffectProperty) continue;
489501
}
490-
};
491502

492-
if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == FrameworkElement.MarginProperty) is not Setter marginSetter)
493-
{
494-
var margin = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin);
495-
marginSetter = new Setter()
496-
{
497-
Property = FrameworkElement.MarginProperty,
498-
Value = margin,
499-
};
500-
windowBorderStyle.Setters.Add(marginSetter);
503+
// Add other setters (e.g. Background, BorderThickness)
504+
newWindowBorderStyle.Setters.Add(setterBase);
505+
}
501506

502-
SetResizeBoarderThickness(margin);
507+
// Calculate new Margin
508+
Thickness newMargin;
509+
if (existingMarginSetter == null)
510+
{
511+
newMargin = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin);
503512
}
504513
else
505514
{
506-
var baseMargin = (Thickness)marginSetter.Value;
507-
var newMargin = new Thickness(
515+
var baseMargin = (Thickness)existingMarginSetter.Value;
516+
newMargin = new Thickness(
508517
baseMargin.Left + ShadowExtraMargin,
509518
baseMargin.Top + ShadowExtraMargin,
510519
baseMargin.Right + ShadowExtraMargin,
511520
baseMargin.Bottom + ShadowExtraMargin);
512-
marginSetter.Value = newMargin;
513-
514-
SetResizeBoarderThickness(newMargin);
515521
}
516522

517-
windowBorderStyle.Setters.Add(effectSetter);
523+
// Add new Margin Setter
524+
ThemeHelper.ReplaceSetter(newWindowBorderStyle, new Setter(FrameworkElement.MarginProperty, newMargin));
518525

519-
UpdateResourceDictionary(dict);
526+
// Add Drop Shadow Effect Setter
527+
ThemeHelper.ReplaceSetter(newWindowBorderStyle, new Setter
528+
{
529+
Property = UIElement.EffectProperty,
530+
Value = new DropShadowEffect
531+
{
532+
Opacity = 0.3,
533+
ShadowDepth = 12,
534+
Direction = 270,
535+
BlurRadius = 30
536+
}
537+
});
538+
539+
SetResizeBoarderThickness(newMargin);
540+
541+
Application.Current.Resources["WindowBorderStyle"] = newWindowBorderStyle;
520542
}
521543

522544
public void RemoveDropShadowEffectFromCurrentTheme()
523545
{
524-
var dict = GetCurrentResourceDictionary();
525-
var windowBorderStyle = dict["WindowBorderStyle"] as Style;
546+
// Get current theme's WindowBorderStyle
547+
var theme = _settings.Theme;
548+
var dict = GetThemeResourceDictionary(theme);
549+
var windowBorderStyle = dict.Contains("WindowBorderStyle") ? dict["WindowBorderStyle"] as Style : null;
550+
if (windowBorderStyle == null) return;
526551

527-
if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == UIElement.EffectProperty) is Setter effectSetter)
528-
{
529-
windowBorderStyle.Setters.Remove(effectSetter);
530-
}
552+
// Get a new unsealed style based on the old one, and copy Resources and Triggers
553+
var newWindowBorderStyle = new Style(typeof(Border));
554+
ThemeHelper.CopyStyle(windowBorderStyle, newWindowBorderStyle);
531555

532-
if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == FrameworkElement.MarginProperty) is Setter marginSetter)
556+
// Copy Setters, excluding the Effect setter and updating the Margin setter
557+
foreach (var setterBase in windowBorderStyle.Setters)
533558
{
534-
var currentMargin = (Thickness)marginSetter.Value;
535-
var newMargin = new Thickness(
536-
currentMargin.Left - ShadowExtraMargin,
537-
currentMargin.Top - ShadowExtraMargin,
538-
currentMargin.Right - ShadowExtraMargin,
539-
currentMargin.Bottom - ShadowExtraMargin);
540-
marginSetter.Value = newMargin;
559+
if (setterBase is Setter setter)
560+
{
561+
// Skip existing Effect (We'll remove it)
562+
if (setter.Property == UIElement.EffectProperty) continue;
563+
564+
// Update Margin by subtracting the extra margin we added for the shadow
565+
if (setter.Property == FrameworkElement.MarginProperty)
566+
{
567+
var currentMargin = (Thickness)setter.Value;
568+
var newMargin = new Thickness(
569+
currentMargin.Left - ShadowExtraMargin,
570+
currentMargin.Top - ShadowExtraMargin,
571+
currentMargin.Right - ShadowExtraMargin,
572+
currentMargin.Bottom - ShadowExtraMargin);
573+
ThemeHelper.ReplaceSetter(newWindowBorderStyle, new Setter(FrameworkElement.MarginProperty, newMargin));
574+
continue;
575+
}
576+
}
577+
578+
newWindowBorderStyle.Setters.Add(setterBase);
541579
}
542580

543581
SetResizeBoarderThickness(null);
544582

545-
UpdateResourceDictionary(dict);
583+
Application.Current.Resources["WindowBorderStyle"] = newWindowBorderStyle;
546584
}
547585

548586
public void SetResizeBorderThickness(WindowChrome windowChrome, bool fixedWindowSize)
@@ -669,13 +707,11 @@ private void SetBlurForWindow(string theme, BackdropTypes backdropType)
669707
// If the BackdropType is Mica or MicaAlt, set the windowborderstyle's background to transparent
670708
if (backdropType is BackdropTypes.Mica or BackdropTypes.MicaAlt)
671709
{
672-
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property == Control.BackgroundProperty));
673-
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, ThemeHelper.GetFrozenSolidColorBrush(Color.FromArgb(1, 0, 0, 0))));
710+
ThemeHelper.ReplaceSetter(windowBorderStyle, new Setter(Border.BackgroundProperty, ThemeHelper.GetFrozenSolidColorBrush(Color.FromArgb(1, 0, 0, 0))));
674711
}
675712
else if (backdropType == BackdropTypes.Acrylic)
676713
{
677-
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property == Control.BackgroundProperty));
678-
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, Brushes.Transparent));
714+
ThemeHelper.ReplaceSetter(windowBorderStyle, new Setter(Border.BackgroundProperty, Brushes.Transparent));
679715
}
680716

681717
// For themes with blur enabled, the window border is rendered by the system, so it's treated as a simple rectangle regardless of thickness.

Flow.Launcher.Core/Resource/ThemeHelper.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ public static class ThemeHelper
88
{
99
public static void CopyStyle(Style originalStyle, Style targetStyle)
1010
{
11-
// If the style is based on another style, copy the base style first
11+
// If the style is based on another style, use the same base style for the target style
1212
if (originalStyle.BasedOn != null)
1313
{
14-
CopyStyle(originalStyle.BasedOn, targetStyle);
14+
targetStyle.BasedOn = originalStyle.BasedOn;
1515
}
1616

1717
// Copy the setters from the original style
@@ -21,6 +21,15 @@ public static void CopyStyle(Style originalStyle, Style targetStyle)
2121
}
2222
}
2323

24+
public static void ReplaceSetter(Style style, Setter setter)
25+
{
26+
var existingSetter = style.Setters.OfType<Setter>().FirstOrDefault(s => s.Property == setter.Property);
27+
if (existingSetter != null)
28+
style.Setters.Remove(existingSetter);
29+
30+
style.Setters.Add(setter);
31+
}
32+
2433
public static SolidColorBrush GetFrozenSolidColorBrush(Color color)
2534
{
2635
var brush = new SolidColorBrush(color);

0 commit comments

Comments
 (0)