mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 10:46:33 +02:00
CmdPal: Transparent window (#45159)
## Summary This PR adds: - Backdrop material customization - Alongside acrylic, the following options are now available: - Transparent background - Mica background - Background material opacity - Lets you control how transparent the background is ## Pictures? Pictures! <img width="1491" height="928" alt="image" src="https://github.com/user-attachments/assets/ff4e9e06-fcf1-4f05-bc0a-fb70dc4f39be" /> https://github.com/user-attachments/assets/84e83279-afab-481e-b904-f054318c5d2f <img width="977" height="628" alt="image" src="https://github.com/user-attachments/assets/241a228d-af3f-448a-94a6-0a282218bd8c" /> ## PR Checklist - [x] Closes: #44197 <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
using CommunityToolkit.WinUI.Helpers;
|
||||
using Microsoft.CmdPal.UI.Helpers;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.UI;
|
||||
@@ -34,7 +35,7 @@ internal sealed class ColorfulThemeProvider : IThemeProvider
|
||||
_uiSettings = uiSettings;
|
||||
}
|
||||
|
||||
public AcrylicBackdropParameters GetAcrylicBackdrop(ThemeContext context)
|
||||
public BackdropParameters GetBackdropParameters(ThemeContext context)
|
||||
{
|
||||
var isLight = context.Theme == ElementTheme.Light ||
|
||||
(context.Theme == ElementTheme.Default &&
|
||||
@@ -53,7 +54,26 @@ internal sealed class ColorfulThemeProvider : IThemeProvider
|
||||
var colorIntensity = isLight ? 0.6f * colorIntensityUser : colorIntensityUser;
|
||||
var effectiveBgColor = ColorBlender.Blend(baseColor, blended, colorIntensity);
|
||||
|
||||
return new AcrylicBackdropParameters(effectiveBgColor, effectiveBgColor, 0.8f, 0.8f);
|
||||
var transparencyMode = context.BackdropStyle ?? BackdropStyle.Acrylic;
|
||||
var config = BackdropStyles.Get(transparencyMode);
|
||||
|
||||
// For colorful theme, boost tint opacity to show color better through blur
|
||||
// But not for styles with fixed opacity (Mica) - they handle their own opacity
|
||||
var baseTintOpacity = config.ControllerKind == BackdropControllerKind.Solid || !config.SupportsOpacity
|
||||
? (float?)null // Use default
|
||||
: Math.Max(config.BaseTintOpacity, 0.8f);
|
||||
|
||||
var effectiveOpacity = config.ComputeEffectiveOpacity(context.BackdropOpacity, baseTintOpacity);
|
||||
var effectiveLuminosityOpacity = config.SupportsOpacity
|
||||
? config.BaseLuminosityOpacity * context.BackdropOpacity
|
||||
: config.BaseLuminosityOpacity;
|
||||
|
||||
return new BackdropParameters(
|
||||
TintColor: effectiveBgColor,
|
||||
FallbackColor: effectiveBgColor,
|
||||
EffectiveOpacity: effectiveOpacity,
|
||||
EffectiveLuminosityOpacity: effectiveLuminosityOpacity,
|
||||
Style: transparencyMode);
|
||||
}
|
||||
|
||||
private static class ColorBlender
|
||||
|
||||
@@ -8,14 +8,14 @@ using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
namespace Microsoft.CmdPal.UI.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Provides theme identification, resource path resolution, and creation of acrylic
|
||||
/// backdrop parameters based on the current <see cref="ThemeContext"/>.
|
||||
/// Provides theme identification, resource path resolution, and creation of backdrop
|
||||
/// parameters based on the current <see cref="ThemeContext"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implementations should expose a stable <see cref="ThemeKey"/> and a valid XAML resource
|
||||
/// dictionary path via <see cref="ResourcePath"/>. The
|
||||
/// <see cref="GetAcrylicBackdrop(ThemeContext)"/> method computes
|
||||
/// <see cref="AcrylicBackdropParameters"/> using the supplied theme context.
|
||||
/// <see cref="GetBackdropParameters(ThemeContext)"/> method computes
|
||||
/// <see cref="BackdropParameters"/> using the supplied theme context.
|
||||
/// </remarks>
|
||||
internal interface IThemeProvider
|
||||
{
|
||||
@@ -30,9 +30,9 @@ internal interface IThemeProvider
|
||||
string ResourcePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates acrylic backdrop parameters based on the provided theme context.
|
||||
/// Creates backdrop parameters based on the provided theme context.
|
||||
/// </summary>
|
||||
/// <param name="context">The current theme context, including theme, tint, and optional background details.</param>
|
||||
/// <returns>The computed <see cref="AcrylicBackdropParameters"/> for the backdrop.</returns>
|
||||
AcrylicBackdropParameters GetAcrylicBackdrop(ThemeContext context);
|
||||
/// <param name="context">The current theme context, including theme, tint, transparency mode, and optional background details.</param>
|
||||
/// <returns>The computed <see cref="BackdropParameters"/> for the backdrop.</returns>
|
||||
BackdropParameters GetBackdropParameters(ThemeContext context);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.UI;
|
||||
@@ -28,16 +29,28 @@ internal sealed class NormalThemeProvider : IThemeProvider
|
||||
|
||||
public string ResourcePath => "ms-appx:///Styles/Theme.Normal.xaml";
|
||||
|
||||
public AcrylicBackdropParameters GetAcrylicBackdrop(ThemeContext context)
|
||||
public BackdropParameters GetBackdropParameters(ThemeContext context)
|
||||
{
|
||||
var isLight = context.Theme == ElementTheme.Light ||
|
||||
(context.Theme == ElementTheme.Default &&
|
||||
_uiSettings.GetColorValue(UIColorType.Background).R > 128);
|
||||
|
||||
return new AcrylicBackdropParameters(
|
||||
var backdropStyle = context.BackdropStyle ?? BackdropStyle.Acrylic;
|
||||
var config = BackdropStyles.Get(backdropStyle);
|
||||
|
||||
// Apply light/dark theme adjustment to luminosity
|
||||
var baseLuminosityOpacity = isLight
|
||||
? config.BaseLuminosityOpacity
|
||||
: Math.Min(config.BaseLuminosityOpacity + 0.06f, 1.0f);
|
||||
|
||||
var effectiveOpacity = config.ComputeEffectiveOpacity(context.BackdropOpacity);
|
||||
var effectiveLuminosityOpacity = baseLuminosityOpacity * context.BackdropOpacity;
|
||||
|
||||
return new BackdropParameters(
|
||||
TintColor: isLight ? LightBaseColor : DarkBaseColor,
|
||||
FallbackColor: isLight ? LightBaseColor : DarkBaseColor,
|
||||
TintOpacity: 0.5f,
|
||||
LuminosityOpacity: isLight ? 0.9f : 0.96f);
|
||||
EffectiveOpacity: effectiveOpacity,
|
||||
EffectiveLuminosityOpacity: effectiveLuminosityOpacity,
|
||||
Style: backdropStyle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Windows.UI;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Input parameters for theme computation, passed to theme providers.
|
||||
/// </summary>
|
||||
internal sealed record ThemeContext
|
||||
{
|
||||
public ElementTheme Theme { get; init; }
|
||||
@@ -21,4 +25,8 @@ internal sealed record ThemeContext
|
||||
public double BackgroundImageOpacity { get; init; }
|
||||
|
||||
public int? ColorIntensity { get; init; }
|
||||
|
||||
public BackdropStyle? BackdropStyle { get; init; }
|
||||
|
||||
public float BackdropOpacity { get; init; } = 1.0f;
|
||||
}
|
||||
|
||||
@@ -72,10 +72,13 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
}
|
||||
|
||||
// provider selection
|
||||
var intensity = Math.Clamp(_settings.CustomThemeColorIntensity, 0, 100);
|
||||
IThemeProvider provider = intensity > 0 && _settings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor or ColorizationMode.Image
|
||||
? _colorfulThemeProvider
|
||||
: _normalThemeProvider;
|
||||
var themeColorIntensity = Math.Clamp(_settings.CustomThemeColorIntensity, 0, 100);
|
||||
var imageTintIntensity = Math.Clamp(_settings.BackgroundImageTintIntensity, 0, 100);
|
||||
var effectiveColorIntensity = _settings.ColorizationMode == ColorizationMode.Image
|
||||
? imageTintIntensity
|
||||
: themeColorIntensity;
|
||||
|
||||
IThemeProvider provider = UseColorfulProvider(effectiveColorIntensity) ? _colorfulThemeProvider : _normalThemeProvider;
|
||||
|
||||
// Calculate values
|
||||
var tint = _settings.ColorizationMode switch
|
||||
@@ -96,32 +99,39 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
};
|
||||
var opacity = Math.Clamp(_settings.BackgroundImageOpacity, 0, 100) / 100.0;
|
||||
|
||||
// create context and offload to actual theme provider
|
||||
// create input and offload to actual theme provider
|
||||
var context = new ThemeContext
|
||||
{
|
||||
Tint = tint,
|
||||
ColorIntensity = intensity,
|
||||
ColorIntensity = effectiveColorIntensity,
|
||||
Theme = effectiveTheme,
|
||||
BackgroundImageSource = imageSource,
|
||||
BackgroundImageStretch = stretch,
|
||||
BackgroundImageOpacity = opacity,
|
||||
BackdropStyle = _settings.BackdropStyle,
|
||||
BackdropOpacity = Math.Clamp(_settings.BackdropOpacity, 0, 100) / 100f,
|
||||
};
|
||||
var backdrop = provider.GetAcrylicBackdrop(context);
|
||||
var backdrop = provider.GetBackdropParameters(context);
|
||||
var blur = _settings.BackgroundImageBlurAmount;
|
||||
var brightness = _settings.BackgroundImageBrightness;
|
||||
|
||||
// Create public snapshot (no provider!)
|
||||
var hasColorization = effectiveColorIntensity > 0
|
||||
&& _settings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor or ColorizationMode.Image;
|
||||
|
||||
var snapshot = new ThemeSnapshot
|
||||
{
|
||||
Tint = tint,
|
||||
TintIntensity = intensity / 100f,
|
||||
TintIntensity = effectiveColorIntensity / 100f,
|
||||
Theme = effectiveTheme,
|
||||
BackgroundImageSource = imageSource,
|
||||
BackgroundImageStretch = stretch,
|
||||
BackgroundImageOpacity = opacity,
|
||||
BackdropParameters = backdrop,
|
||||
BackdropOpacity = context.BackdropOpacity,
|
||||
BlurAmount = blur,
|
||||
BackgroundBrightness = brightness / 100f,
|
||||
HasColorization = hasColorization,
|
||||
};
|
||||
|
||||
// Bundle with provider for internal use
|
||||
@@ -138,6 +148,12 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
ThemeChanged?.Invoke(this, new ThemeChangedEventArgs());
|
||||
}
|
||||
|
||||
private bool UseColorfulProvider(int effectiveColorIntensity)
|
||||
{
|
||||
return _settings.ColorizationMode == ColorizationMode.Image
|
||||
|| (effectiveColorIntensity > 0 && _settings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor);
|
||||
}
|
||||
|
||||
private static BitmapImage? LoadImageSafe(string? path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
@@ -195,13 +211,15 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
{
|
||||
Tint = Colors.Transparent,
|
||||
Theme = ElementTheme.Light,
|
||||
BackdropParameters = new AcrylicBackdropParameters(Colors.Black, Colors.Black, 0.5f, 0.5f),
|
||||
BackdropParameters = new BackdropParameters(Colors.Black, Colors.Black, EffectiveOpacity: 0.5f, EffectiveLuminosityOpacity: 0.5f),
|
||||
BackdropOpacity = 1.0f,
|
||||
BackgroundImageOpacity = 1,
|
||||
BackgroundImageSource = null,
|
||||
BackgroundImageStretch = Stretch.Fill,
|
||||
BlurAmount = 0,
|
||||
TintIntensity = 1.0f,
|
||||
BackgroundBrightness = 0,
|
||||
HasColorization = false,
|
||||
},
|
||||
Provider = _normalThemeProvider,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user