Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 82 additions & 46 deletions Flow.Launcher.Core/Resource/Theme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,76 +477,114 @@

public void AddDropShadowEffectToCurrentTheme()
{
var dict = GetCurrentResourceDictionary();
// Get current theme's WindowBorderStyle
var theme = _settings.Theme;
var dict = GetThemeResourceDictionary(theme);
var windowBorderStyle = dict.Contains("WindowBorderStyle") ? dict["WindowBorderStyle"] as Style : null;
if (windowBorderStyle == null) return;

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

var effectSetter = new Setter
// Identify existing Margin to calculate new Margin, and copy other setters
Setter existingMarginSetter = null;
foreach (var setterBase in windowBorderStyle.Setters)
{
Property = UIElement.EffectProperty,
Value = new DropShadowEffect
if (setterBase is Setter setter)
{
Opacity = 0.3,
ShadowDepth = 12,
Direction = 270,
BlurRadius = 30
// Skip existing Margin (we'll replace it)
if (setter.Property == FrameworkElement.MarginProperty)
{
existingMarginSetter = setter;
continue;
}

// Skip existing Effect (we'll ensure strictly one is added)
if (setter.Property == UIElement.EffectProperty) continue;
}
};

if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == FrameworkElement.MarginProperty) is not Setter marginSetter)
{
var margin = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin);
marginSetter = new Setter()
{
Property = FrameworkElement.MarginProperty,
Value = margin,
};
windowBorderStyle.Setters.Add(marginSetter);
// Add other setters (e.g. Background, BorderThickness)
newWindowBorderStyle.Setters.Add(setterBase);
}

SetResizeBoarderThickness(margin);
// Calculate new Margin
Thickness newMargin;
if (existingMarginSetter == null)
{
newMargin = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin);
}
else
{
var baseMargin = (Thickness)marginSetter.Value;
var newMargin = new Thickness(
var baseMargin = (Thickness)existingMarginSetter.Value;
newMargin = new Thickness(
baseMargin.Left + ShadowExtraMargin,
baseMargin.Top + ShadowExtraMargin,
baseMargin.Right + ShadowExtraMargin,
baseMargin.Bottom + ShadowExtraMargin);
marginSetter.Value = newMargin;

SetResizeBoarderThickness(newMargin);
}

windowBorderStyle.Setters.Add(effectSetter);
// Add new Margin Setter
ThemeHelper.ReplaceSetter(newWindowBorderStyle, new Setter(FrameworkElement.MarginProperty, newMargin));

UpdateResourceDictionary(dict);
// Add Drop Shadow Effect Setter
ThemeHelper.ReplaceSetter(newWindowBorderStyle, new Setter
{
Property = UIElement.EffectProperty,
Value = new DropShadowEffect
{
Opacity = 0.3,
ShadowDepth = 12,
Direction = 270,
BlurRadius = 30
}
});

SetResizeBoarderThickness(newMargin);

Application.Current.Resources["WindowBorderStyle"] = newWindowBorderStyle;
}

public void RemoveDropShadowEffectFromCurrentTheme()
{
var dict = GetCurrentResourceDictionary();
var windowBorderStyle = dict["WindowBorderStyle"] as Style;
// Get current theme's WindowBorderStyle
var theme = _settings.Theme;
var dict = GetThemeResourceDictionary(theme);
var windowBorderStyle = dict.Contains("WindowBorderStyle") ? dict["WindowBorderStyle"] as Style : null;
if (windowBorderStyle == null) return;

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

if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == FrameworkElement.MarginProperty) is Setter marginSetter)
// Copy Setters, excluding the Effect setter and updating the Margin setter
foreach (var setterBase in windowBorderStyle.Setters)
{
var currentMargin = (Thickness)marginSetter.Value;
var newMargin = new Thickness(
currentMargin.Left - ShadowExtraMargin,
currentMargin.Top - ShadowExtraMargin,
currentMargin.Right - ShadowExtraMargin,
currentMargin.Bottom - ShadowExtraMargin);
marginSetter.Value = newMargin;
if (setterBase is Setter setter)
{
// Skip existing Effect (We'll remove it)
if (setter.Property == UIElement.EffectProperty) continue;

// Update Margin by subtracting the extra margin we added for the shadow
if (setter.Property == FrameworkElement.MarginProperty)
{
var currentMargin = (Thickness)setter.Value;
var newMargin = new Thickness(
currentMargin.Left - ShadowExtraMargin,
currentMargin.Top - ShadowExtraMargin,
currentMargin.Right - ShadowExtraMargin,
currentMargin.Bottom - ShadowExtraMargin);
ThemeHelper.ReplaceSetter(newWindowBorderStyle, new Setter(FrameworkElement.MarginProperty, newMargin));
continue;
}
}

newWindowBorderStyle.Setters.Add(setterBase);
}

SetResizeBoarderThickness(null);

UpdateResourceDictionary(dict);
Application.Current.Resources["WindowBorderStyle"] = newWindowBorderStyle;
}

public void SetResizeBorderThickness(WindowChrome windowChrome, bool fixedWindowSize)
Expand Down Expand Up @@ -602,7 +640,7 @@
var (backdropType, useDropShadowEffect) = GetActualValue();

// Remove OS minimizing/maximizing animation
// Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3);

Check warning on line 643 in Flow.Launcher.Core/Resource/Theme.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`FORCEDISABLED` is not a recognized word. (unrecognized-spelling)

Check warning on line 643 in Flow.Launcher.Core/Resource/Theme.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`DWMWA` is not a recognized word. (unrecognized-spelling)

Check warning on line 643 in Flow.Launcher.Core/Resource/Theme.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`DWMWINDOWATTRIBUTE` is not a recognized word. (unrecognized-spelling)

// The timing of adding the shadow effect should vary depending on whether the theme is transparent.
if (BlurEnabled)
Expand Down Expand Up @@ -646,7 +684,7 @@
backdropType = BackdropTypes.None;
}

// Dropshadow on and control disabled.(user can't change dropshadow with blur theme)

Check warning on line 687 in Flow.Launcher.Core/Resource/Theme.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`dropshadow` is not a recognized word. (unrecognized-spelling)

Check warning on line 687 in Flow.Launcher.Core/Resource/Theme.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Dropshadow` is not a recognized word. (unrecognized-spelling)
if (BlurEnabled)
{
useDropShadowEffect = true;
Expand All @@ -670,16 +708,14 @@
var hasBlur = IsThemeBlurEnabled(dict);
if (BlurEnabled && hasBlur && Win32Helper.IsBackdropSupported())
{
// If the BackdropType is Mica or MicaAlt, set the windowborderstyle's background to transparent

Check warning on line 711 in Flow.Launcher.Core/Resource/Theme.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`windowborderstyle` is not a recognized word. (unrecognized-spelling)
if (backdropType is BackdropTypes.Mica or BackdropTypes.MicaAlt)
{
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property == Control.BackgroundProperty));
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, ThemeHelper.GetFrozenSolidColorBrush(Color.FromArgb(1, 0, 0, 0))));
ThemeHelper.ReplaceSetter(windowBorderStyle, new Setter(Border.BackgroundProperty, ThemeHelper.GetFrozenSolidColorBrush(Color.FromArgb(1, 0, 0, 0))));
}
else if (backdropType == BackdropTypes.Acrylic)
{
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property == Control.BackgroundProperty));
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, Brushes.Transparent));
ThemeHelper.ReplaceSetter(windowBorderStyle, new Setter(Border.BackgroundProperty, Brushes.Transparent));
}

// For themes with blur enabled, the window border is rendered by the system, so it's treated as a simple rectangle regardless of thickness.
Expand Down
13 changes: 11 additions & 2 deletions Flow.Launcher.Core/Resource/ThemeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ public static class ThemeHelper
{
public static void CopyStyle(Style originalStyle, Style targetStyle)
{
// If the style is based on another style, copy the base style first
// If the style is based on another style, use the same base style for the target style
if (originalStyle.BasedOn != null)
{
CopyStyle(originalStyle.BasedOn, targetStyle);
targetStyle.BasedOn = originalStyle.BasedOn;
}

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

public static void ReplaceSetter(Style style, Setter setter)
{
var existingSetter = style.Setters.OfType<Setter>().FirstOrDefault(s => s.Property == setter.Property);
if (existingSetter != null)
style.Setters.Remove(existingSetter);

style.Setters.Add(setter);
}

public static SolidColorBrush GetFrozenSolidColorBrush(Color color)
{
var brush = new SolidColorBrush(color);
Expand Down
Loading