mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-10-28 08:36:04 +08:00
[CmdPal] Add Mica and Mica Alt materials to the Dock (#51470)
## Summary of the Pull Request The Dock currently offers Acrylic and Transparent, while the main Command Palette window also supports Mica materials. This adds **Mica** and **Mica Alt** to **Dock > Appearance > Material**, with live switching and an independent saved selection. ## PR Checklist - [ ] **Closes:** No linked issue yet; this is a feature proposal. - [ ] **Communication:** Seeking maintainer feedback; prior agreement has not been obtained. - [x] **Tests:** Added persistence coverage; all 262 focused Dock and settings-page tests pass. - [x] **Localization:** Reuses existing localized material labels and Mica explanation. - [ ] **Dev docs:** Not applicable; no developer documentation changes. - [x] **New binaries:** None; no dependency or installer changes. - [ ] **Documentation updated:** The separate MicrosoftDocs user guide is not updated in this PR. ## Detailed Description of the Pull Request / Additional comments - Render Mica and Mica Alt with native `MicaController` instances using `MicaKind.Base` and `MicaKind.BaseAlt`. - Synchronize the system backdrop with the Dock's theme and dispose the previous controller when switching materials or closing the Dock. - Preserve the existing Acrylic and Transparent rendering paths and enum values. - Disable background colorization and images while a Mica material is selected. Retain those settings for switching back to Acrylic or Transparent. - Keep the Dock material independent of the main palette's material. - Show the Mica explanation inside the Material expander, using the same card and text styling as the Appearance page. - Fall back from unsupported Mica/Mica Alt to Acrylic, then Transparent if Acrylic is also unsupported. Keep Acrylic tint and opacity parameters ready for the fallback. ## Validation Steps Performed - Built the x64 Release Command Palette UI successfully with Visual Studio MSBuild and .NET 10. - Ran the focused Dock and settings-page tests through VSTest: **262 passed, 0 failed**, including four new save/reload cases covering every material and palette independence. - Exercised the production backdrop methods with native support results simulated: **19 cases passed**, covering both Mica variants, Acrylic/Transparent fallbacks, configuration availability, repeated updates, theme changes and controller cleanup. This checks control flow, not rendering on an older OS. - Verified the Dock Mica explanation uses the same text styling and SettingsCard-inside-SettingsExpander layout as the Appearance page. - Manually validated the four-item Material dropdown and Mica/Mica Alt in an installed local test build on Windows 11 x64; the requester confirmed the feature works. - `git diff --cached --check`: passed. Build limitation: unchanged native components were reused from the installed PowerToys package because the local C++ toolchain is unavailable. This was a non-AOT app build; a full native/AOT build and multi-monitor/ARM64 validation remain for CI or maintainer testing. Actual fallback rendering on Windows 10 (including build 19041) has not been tested; that still needs an older supported system. ## Video: Dock material with another app focused Tested Mica and Mica Alt on Windows 11 x64 with Notepad focused. The Dock retained its appearance in both cases; no switch to a flat fallback background was observed. The recording below shows the material settings and switching to Notepad. https://github.com/user-attachments/assets/3cf8df62-a67c-4cdd-b261-5527b29b126e
This commit is contained in:
1 parent
f0a6c26738
commit
5868a0a124
7 files changed
+128
-7
No files matched your search
@@ -71,11 +71,17 @@ public sealed partial class DockAppearanceSettingsViewModel : ObservableObject,
|
||||
_settingsService.UpdateSettings(s => s with { DockSettings = s.DockSettings with { Backdrop = value } });
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(BackdropIndex));
|
||||
OnPropertyChanged(nameof(IsMicaBackdrop));
|
||||
OnPropertyChanged(nameof(SupportsColorization));
|
||||
DebouncedReapply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsMicaBackdrop => Backdrop is DockBackdrop.Mica or DockBackdrop.MicaAlt;
|
||||
|
||||
public bool SupportsColorization => !IsMicaBackdrop;
|
||||
|
||||
public ColorizationMode ColorizationMode
|
||||
{
|
||||
get => _settingsService.Settings.DockSettings.ColorizationMode;
|
||||
|
||||
@@ -475,6 +475,8 @@ public enum DockBackdrop
|
||||
{
|
||||
Transparent,
|
||||
Acrylic,
|
||||
Mica,
|
||||
MicaAlt,
|
||||
}
|
||||
|
||||
#pragma warning restore SA1402 // File may only contain a single type
|
||||
@@ -80,9 +80,11 @@ public sealed partial class DockWindow : WindowEx,
|
||||
private DockViewModel viewModel;
|
||||
private DockControl _dock;
|
||||
private DesktopAcrylicController? _acrylicController;
|
||||
private MicaController? _micaController;
|
||||
private SystemBackdropConfiguration? _configurationSource;
|
||||
private bool _isUpdatingBackdrop;
|
||||
private BackdropParameters? _lastAppliedAcrylicBackdrop;
|
||||
private MicaKind? _lastAppliedMicaKind;
|
||||
private DockSize _lastSize;
|
||||
private bool _isDisposed;
|
||||
private DockAppBarMode _appBarMode;
|
||||
@@ -316,7 +318,7 @@ public sealed partial class DockWindow : WindowEx,
|
||||
|
||||
private void InitializeBackdropSupport()
|
||||
{
|
||||
if (DesktopAcrylicController.IsSupported())
|
||||
if (DesktopAcrylicController.IsSupported() || MicaController.IsSupported())
|
||||
{
|
||||
_configurationSource = new SystemBackdropConfiguration
|
||||
{
|
||||
@@ -337,6 +339,16 @@ public sealed partial class DockWindow : WindowEx,
|
||||
|
||||
try
|
||||
{
|
||||
if (_configurationSource is not null)
|
||||
{
|
||||
_configurationSource.Theme = _themeService.CurrentDockTheme.Theme switch
|
||||
{
|
||||
ElementTheme.Light => SystemBackdropTheme.Light,
|
||||
ElementTheme.Dark => SystemBackdropTheme.Dark,
|
||||
_ => SystemBackdropTheme.Default,
|
||||
};
|
||||
}
|
||||
|
||||
switch (_settings.Backdrop)
|
||||
{
|
||||
case DockBackdrop.Transparent:
|
||||
@@ -348,6 +360,14 @@ public sealed partial class DockWindow : WindowEx,
|
||||
|
||||
break;
|
||||
|
||||
case DockBackdrop.Mica:
|
||||
SetupMica(MicaKind.Base);
|
||||
break;
|
||||
|
||||
case DockBackdrop.MicaAlt:
|
||||
SetupMica(MicaKind.BaseAlt);
|
||||
break;
|
||||
|
||||
case DockBackdrop.Acrylic:
|
||||
default:
|
||||
SetupDesktopAcrylic(_themeService.CurrentDockTheme.BackdropParameters);
|
||||
@@ -376,6 +396,15 @@ public sealed partial class DockWindow : WindowEx,
|
||||
|
||||
private void CleanupBackdropControllers()
|
||||
{
|
||||
if (_micaController is not null)
|
||||
{
|
||||
_micaController.RemoveAllSystemBackdropTargets();
|
||||
_micaController.Dispose();
|
||||
_micaController = null;
|
||||
}
|
||||
|
||||
_lastAppliedMicaKind = null;
|
||||
|
||||
if (_acrylicController is not null)
|
||||
{
|
||||
_acrylicController.RemoveAllSystemBackdropTargets();
|
||||
@@ -422,7 +451,29 @@ public sealed partial class DockWindow : WindowEx,
|
||||
_lastAppliedAcrylicBackdrop = backdrop;
|
||||
}
|
||||
|
||||
private void DisposeAcrylic()
|
||||
private void SetupMica(MicaKind kind)
|
||||
{
|
||||
if (_configurationSource is null || !MicaController.IsSupported())
|
||||
{
|
||||
// Try Acrylic before the transparent fallback on systems without Mica support.
|
||||
SetupDesktopAcrylic(_themeService.CurrentDockTheme.BackdropParameters);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_micaController is not null && _lastAppliedMicaKind == kind)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CleanupBackdropControllers();
|
||||
SystemBackdrop = null;
|
||||
_micaController = new MicaController { Kind = kind };
|
||||
_micaController.AddSystemBackdropTarget(this.As<ICompositionSupportsSystemBackdrop>());
|
||||
_micaController.SetSystemBackdropConfiguration(_configurationSource);
|
||||
_lastAppliedMicaKind = kind;
|
||||
}
|
||||
|
||||
private void DisposeBackdrop()
|
||||
{
|
||||
CleanupBackdropControllers();
|
||||
_configurationSource = null;
|
||||
@@ -1841,7 +1892,7 @@ public sealed partial class DockWindow : WindowEx,
|
||||
WeakReferenceMessenger.Default.UnregisterAll(this);
|
||||
|
||||
StopCollapseTimer();
|
||||
DisposeAcrylic();
|
||||
DisposeBackdrop();
|
||||
_dock.Dispose();
|
||||
_windowViewModel.Dispose();
|
||||
|
||||
|
||||
@@ -151,7 +151,8 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
|
||||
// Compute DockThemeSnapshot from DockSettings
|
||||
var dockSettings = _settingsService.Settings.DockSettings;
|
||||
var dockIntensity = Math.Clamp(dockSettings.CustomThemeColorIntensity, 0, 100);
|
||||
var isMicaDock = dockSettings.Backdrop is DockBackdrop.Mica or DockBackdrop.MicaAlt;
|
||||
var dockIntensity = isMicaDock ? 0 : Math.Clamp(dockSettings.CustomThemeColorIntensity, 0, 100);
|
||||
IThemeProvider dockProvider = dockIntensity > 0 && dockSettings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor or ColorizationMode.Image
|
||||
? _colorfulThemeProvider
|
||||
: _normalThemeProvider;
|
||||
@@ -164,7 +165,7 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
var dockEffectiveTheme = GetElementTheme((ElementTheme)dockSettings.Theme);
|
||||
var dockImageSource = dockSettings.ColorizationMode == ColorizationMode.Image
|
||||
var dockImageSource = !isMicaDock && dockSettings.ColorizationMode == ColorizationMode.Image
|
||||
? LoadImageSafe(dockSettings.BackgroundImagePath)
|
||||
: null;
|
||||
var dockStretch = dockSettings.BackgroundImageFit switch
|
||||
@@ -176,6 +177,8 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
|
||||
var dockContext = new ThemeContext
|
||||
{
|
||||
// Mica uses system defaults; keep Acrylic parameters ready for its fallback.
|
||||
BackdropStyle = BackdropStyle.Acrylic,
|
||||
Tint = dockTint,
|
||||
ColorIntensity = dockIntensity,
|
||||
Theme = dockEffectiveTheme,
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
</controls:SettingsCard>
|
||||
|
||||
<!-- Backdrop Style -->
|
||||
<controls:SettingsCard
|
||||
<controls:SettingsExpander
|
||||
x:Uid="DockAppearance_Backdrop_SettingsCard"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
local:SettingsPageTarget.Id="backdrop">
|
||||
@@ -184,13 +184,32 @@
|
||||
SelectedIndex="{x:Bind ViewModel.DockAppearance.BackdropIndex, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="DockAppearance_Backdrop_Transparent" />
|
||||
<ComboBoxItem x:Uid="DockAppearance_Backdrop_Acrylic" />
|
||||
<ComboBoxItem x:Uid="Settings_GeneralPage_BackdropStyle_Mica" />
|
||||
<ComboBoxItem x:Uid="Settings_GeneralPage_BackdropStyle_MicaAlt" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard
|
||||
x:Uid="Settings_GeneralPage_MicaBackdrop_SettingsCard"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ContentAlignment="Vertical"
|
||||
Visibility="{x:Bind ViewModel.DockAppearance.IsMicaBackdrop, Mode=OneWay}">
|
||||
<TextBlock
|
||||
x:Uid="Settings_GeneralPage_MicaBackdrop_DescriptionTextBlock"
|
||||
Margin="24"
|
||||
HorizontalAlignment="Stretch"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
HorizontalTextAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
|
||||
<!-- Background / Colorization Section -->
|
||||
<controls:SettingsExpander
|
||||
x:Uid="DockAppearance_Background_SettingsExpander"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.DockAppearance.SupportsColorization, Mode=OneWay}"
|
||||
IsExpanded="{x:Bind ViewModel.DockAppearance.IsColorizationDetailsExpanded, Mode=TwoWay}"
|
||||
local:SettingsPageTarget.Id="background">
|
||||
<ComboBox
|
||||
|
||||
@@ -246,6 +246,8 @@ public sealed partial class DockSettingsPage : Page, IDisposable
|
||||
{
|
||||
DockBackdrop.Transparent => 0,
|
||||
DockBackdrop.Acrylic => 1,
|
||||
DockBackdrop.Mica => 2,
|
||||
DockBackdrop.MicaAlt => 3,
|
||||
_ => 1,
|
||||
};
|
||||
|
||||
@@ -253,6 +255,8 @@ public sealed partial class DockSettingsPage : Page, IDisposable
|
||||
{
|
||||
0 => DockBackdrop.Transparent,
|
||||
1 => DockBackdrop.Acrylic,
|
||||
2 => DockBackdrop.Mica,
|
||||
3 => DockBackdrop.MicaAlt,
|
||||
_ => DockBackdrop.Acrylic,
|
||||
};
|
||||
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Settings;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.ViewModels.UnitTests;
|
||||
|
||||
[TestClass]
|
||||
public class DockMaterialPersistenceTests
|
||||
{
|
||||
[TestMethod]
|
||||
[DataRow(DockBackdrop.Transparent, "Transparent")]
|
||||
[DataRow(DockBackdrop.Acrylic, "Acrylic")]
|
||||
[DataRow(DockBackdrop.Mica, "Mica")]
|
||||
[DataRow(DockBackdrop.MicaAlt, "MicaAlt")]
|
||||
public void SaveAndReload_PreservesDockMaterialIndependentlyOfPalette(DockBackdrop material, string persistedName)
|
||||
{
|
||||
var settings = new SettingsModel
|
||||
{
|
||||
BackdropStyle = BackdropStyle.MicaAlt,
|
||||
DockSettings = new DockSettings { Backdrop = material },
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(settings, JsonSerializationContext.Default.SettingsModel);
|
||||
using var document = JsonDocument.Parse(json);
|
||||
Assert.AreEqual(persistedName, document.RootElement.GetProperty("DockSettings").GetProperty("Backdrop").GetString());
|
||||
|
||||
var reloaded = JsonSerializer.Deserialize(json, JsonSerializationContext.Default.SettingsModel);
|
||||
Assert.IsNotNull(reloaded);
|
||||
Assert.AreEqual(material, reloaded.DockSettings.Backdrop);
|
||||
Assert.AreEqual(BackdropStyle.MicaAlt, reloaded.BackdropStyle, "Changing the Dock material must not change the palette material.");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user