diff --git a/src/Avalonia.Base/Platform/PlatformColorValues.cs b/src/Avalonia.Base/Platform/PlatformColorValues.cs
index d14b58e939..b328e1304b 100644
--- a/src/Avalonia.Base/Platform/PlatformColorValues.cs
+++ b/src/Avalonia.Base/Platform/PlatformColorValues.cs
@@ -61,6 +61,37 @@ public record PlatformColorValues
init => _accentColor3 = value;
}
+ ///
+ /// Dark shade 1 of , when the platform provides one (Windows does).
+ /// Null when the platform only reports the base accent color; consumers are expected to compute a shade instead.
+ ///
+ public Color? AccentColorDark1 { get; init; }
+
+ ///
+ /// Dark shade 2 of , when the platform provides one. See .
+ ///
+ public Color? AccentColorDark2 { get; init; }
+
+ ///
+ /// Dark shade 3 of , when the platform provides one. See .
+ ///
+ public Color? AccentColorDark3 { get; init; }
+
+ ///
+ /// Light shade 1 of , when the platform provides one. See .
+ ///
+ public Color? AccentColorLight1 { get; init; }
+
+ ///
+ /// Light shade 2 of , when the platform provides one. See .
+ ///
+ public Color? AccentColorLight2 { get; init; }
+
+ ///
+ /// Light shade 3 of , when the platform provides one. See .
+ ///
+ public Color? AccentColorLight3 { get; init; }
+
public PlatformColorValues()
{
AccentColor1 = DefaultAccent;
diff --git a/src/Avalonia.Themes.Fluent2/Accents/SystemAccentColors.cs b/src/Avalonia.Themes.Fluent2/Accents/SystemAccentColors.cs
index 5d6749f9cd..5cbee992c1 100644
--- a/src/Avalonia.Themes.Fluent2/Accents/SystemAccentColors.cs
+++ b/src/Avalonia.Themes.Fluent2/Accents/SystemAccentColors.cs
@@ -20,7 +20,8 @@ internal sealed class SystemAccentColors : ResourceProvider
private static readonly Color s_defaultSystemAccentColor = Color.FromRgb(0, 120, 215);
// Static shade values from WinUI (matching the Uno/WinUI SystemResources defaults). Used when
// the platform provides no accent color, so the out-of-the-box palette matches WinUI exactly.
- // OS-provided accent colors get computed shades instead.
+ // When the platform reports the OS-computed shades (Windows does, via UISettings) those are
+ // used verbatim; otherwise an OS-provided base accent gets HSL-computed shades.
private static readonly Color s_defaultSystemAccentColorDark1 = Color.FromUInt32(0xFF005A9E);
private static readonly Color s_defaultSystemAccentColorDark2 = Color.FromUInt32(0xFF004275);
private static readonly Color s_defaultSystemAccentColorDark3 = Color.FromUInt32(0xFF002642);
@@ -117,11 +118,22 @@ internal sealed class SystemAccentColors : ResourceProvider
{
_invalidateColors = false;
- var platformSettings = GetFromOwner(Owner);
+ var colorValues = GetFromOwner(Owner)?.GetColorValues();
- _systemAccentColor = platformSettings?.GetColorValues().AccentColor1 ?? s_defaultSystemAccentColor;
+ _systemAccentColor = colorValues?.AccentColor1 ?? s_defaultSystemAccentColor;
- if (_systemAccentColor == s_defaultSystemAccentColor)
+ if (colorValues is
+ {
+ AccentColorDark1: { } dark1, AccentColorDark2: { } dark2, AccentColorDark3: { } dark3,
+ AccentColorLight1: { } light1, AccentColorLight2: { } light2, AccentColorLight3: { } light3
+ })
+ {
+ // The platform reported the OS-computed shades (Windows, via UISettings);
+ // use them verbatim so the palette matches the OS exactly.
+ (_systemAccentColorDark1, _systemAccentColorDark2, _systemAccentColorDark3) = (dark1, dark2, dark3);
+ (_systemAccentColorLight1, _systemAccentColorLight2, _systemAccentColorLight3) = (light1, light2, light3);
+ }
+ else if (_systemAccentColor == s_defaultSystemAccentColor)
{
// Platforms without a real accent color report the default; use WinUI's static
// shade values so the out-of-the-box palette matches WinUI exactly.
diff --git a/src/Avalonia.Themes.Fluent2/Controls/CheckBox.xaml b/src/Avalonia.Themes.Fluent2/Controls/CheckBox.xaml
index db1a3df3bb..0bdb0776ad 100644
--- a/src/Avalonia.Themes.Fluent2/Controls/CheckBox.xaml
+++ b/src/Avalonia.Themes.Fluent2/Controls/CheckBox.xaml
@@ -14,11 +14,15 @@
M5.5 10.586 1.707 6.793A1 1 0 0 0 .293 8.207l4.5 4.5a1 1 0 0 0 1.414 0l11-11A1 1 0 0 0 15.793.293L5.5 10.586Z
32
- 120
+
+ 0
-
+
+
diff --git a/src/Avalonia.Themes.Fluent2/Controls/RadioButton.xaml b/src/Avalonia.Themes.Fluent2/Controls/RadioButton.xaml
index 3fbbea3f17..307f42447a 100644
--- a/src/Avalonia.Themes.Fluent2/Controls/RadioButton.xaml
+++ b/src/Avalonia.Themes.Fluent2/Controls/RadioButton.xaml
@@ -12,7 +12,9 @@
32
- 120
+
+ 0
12
14
10
@@ -28,7 +30,9 @@
-
+
+
diff --git a/src/Avalonia.Themes.Fluent2/README.md b/src/Avalonia.Themes.Fluent2/README.md
index e687956a73..634900e3c7 100644
--- a/src/Avalonia.Themes.Fluent2/README.md
+++ b/src/Avalonia.Themes.Fluent2/README.md
@@ -48,6 +48,12 @@ Migrating from `Avalonia.Themes.Fluent`: change the package reference and swap
| Scroll bars | 16 px rail | **12 px rail, 2 px collapsed thumb** |
| Window background | AltHigh | **SolidBackgroundFillColorBase** (#F3F3F3/#202020) |
| Default accent shades | HSL-computed | **WinUI static values** (when no OS accent) |
+| OS accent shades (Windows) | HSL-computed | **read from the OS** (`UISettings` Light1–3/Dark1–3) |
+
+One deliberate deviation from WinUI (following FluentAvalonia's lead): CheckBox
+and RadioButton do **not** get WinUI's forced 120 px `MinWidth` — they size to
+content plus 8 px trailing padding, as in v1. Set the `CheckBoxMinWidth` /
+`RadioButtonMinWidth` resources to restore the WinUI metric.
The full WinUI 3 token family (`TextFillColor*`, `ControlFillColor*`,
`SubtleFillColor*`, `ControlStrokeColor*`, `CardBackgroundFillColor*`,
@@ -64,8 +70,10 @@ legacy `SystemControl*` aliases.
- No HighContrast variant yet (same as v1).
- AnimatedIcon glyph animations are approximated with static glyphs and simple
transitions.
-- OS-provided accent colors still use HSL-computed shades, which can deviate
- slightly from Windows' palette algorithm.
+- On Windows the six accent shades (`SystemAccentColorDark1`…`Light3`) come
+ straight from the OS; on platforms that report only a base accent color
+ (macOS, Linux) the shades are HSL-computed and can deviate slightly from
+ Windows' palette algorithm.
## Compatibility tests
diff --git a/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs b/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs
index c4b016c1b9..b1395bd510 100644
--- a/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs
+++ b/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs
@@ -73,8 +73,14 @@ internal class Win32PlatformSettings : DefaultPlatformSettings
PlatformThemeVariant.Dark :
PlatformThemeVariant.Light,
ContrastPreference = ColorContrastPreference.NoPreference,
- AccentColor1 = accent
- };
+ AccentColor1 = accent,
+ AccentColorDark1 = uiSettings.GetColorValue(UIColorType.AccentDark1).ToAvalonia(),
+ AccentColorDark2 = uiSettings.GetColorValue(UIColorType.AccentDark2).ToAvalonia(),
+ AccentColorDark3 = uiSettings.GetColorValue(UIColorType.AccentDark3).ToAvalonia(),
+ AccentColorLight1 = uiSettings.GetColorValue(UIColorType.AccentLight1).ToAvalonia(),
+ AccentColorLight2 = uiSettings.GetColorValue(UIColorType.AccentLight2).ToAvalonia(),
+ AccentColorLight3 = uiSettings.GetColorValue(UIColorType.AccentLight3).ToAvalonia()
+ };
}
}
diff --git a/tests/Avalonia.Themes.Fluent2.UnitTests/ControlDefaultsTests.cs b/tests/Avalonia.Themes.Fluent2.UnitTests/ControlDefaultsTests.cs
new file mode 100644
index 0000000000..53b8fb865b
--- /dev/null
+++ b/tests/Avalonia.Themes.Fluent2.UnitTests/ControlDefaultsTests.cs
@@ -0,0 +1,50 @@
+using Avalonia.Controls;
+using Avalonia.Threading;
+
+namespace Avalonia.Themes.Fluent2.UnitTests;
+
+///
+/// Guards the deliberate desktop-ergonomic deviations from the WinUI metrics.
+///
+public class ControlDefaultsTests
+{
+ [AvaloniaFact]
+ public void CheckBox_and_RadioButton_do_not_force_winui_min_width()
+ {
+ var theme = new Fluent2Theme();
+ var app = Application.Current!;
+ app.Styles.Add(theme);
+ try
+ {
+ var checkBox = new CheckBox { Content = "Ok" };
+ var radioButton = new RadioButton { Content = "Ok" };
+ var window = new Window
+ {
+ Width = 400,
+ Height = 300,
+ Content = new StackPanel { Children = { checkBox, radioButton } },
+ };
+ window.Show();
+ try
+ {
+ Dispatcher.UIThread.RunJobs();
+
+ // WinUI forces MinWidth=120 on both; v1 never did, and neither does Fluent2.
+ Assert.Equal(0d, checkBox.MinWidth);
+ Assert.Equal(0d, radioButton.MinWidth);
+ Assert.True(checkBox.Bounds.Width < 120,
+ $"CheckBox width {checkBox.Bounds.Width} should hug its content.");
+ Assert.True(radioButton.Bounds.Width < 120,
+ $"RadioButton width {radioButton.Bounds.Width} should hug its content.");
+ }
+ finally
+ {
+ window.Close();
+ }
+ }
+ finally
+ {
+ app.Styles.Remove(theme);
+ }
+ }
+}
diff --git a/tests/Avalonia.Themes.Fluent2.UnitTests/PaletteTests.cs b/tests/Avalonia.Themes.Fluent2.UnitTests/PaletteTests.cs
index 1acfdc0a29..27d04d2cae 100644
--- a/tests/Avalonia.Themes.Fluent2.UnitTests/PaletteTests.cs
+++ b/tests/Avalonia.Themes.Fluent2.UnitTests/PaletteTests.cs
@@ -1,5 +1,6 @@
using Avalonia.Controls;
using Avalonia.Media;
+using Avalonia.Platform;
using Avalonia.Styling;
namespace Avalonia.Themes.Fluent2.UnitTests;
@@ -65,6 +66,48 @@ public class PaletteTests
}
}
+ [AvaloniaFact]
+ public void Platform_provided_accent_shades_take_precedence_over_computed_ones()
+ {
+ var originalSettings = AvaloniaLocator.Current.GetService();
+ Assert.NotNull(originalSettings);
+ AvaloniaLocator.CurrentMutable.Bind().ToConstant(new ShadeReportingPlatformSettings());
+
+ var theme = new Fluent2Theme();
+ var app = Application.Current!;
+ app.Styles.Add(theme);
+ try
+ {
+ Assert.True(app.TryGetResource("SystemAccentColor", ThemeVariant.Light, out var accent));
+ Assert.Equal(Colors.Crimson, Assert.IsType(accent));
+
+ // The OS-reported shades are used verbatim, not HSL-computed from the base color.
+ Assert.True(app.TryGetResource("SystemAccentColorDark1", ThemeVariant.Light, out var dark1));
+ Assert.Equal(Colors.DarkRed, Assert.IsType(dark1));
+ Assert.True(app.TryGetResource("SystemAccentColorLight3", ThemeVariant.Light, out var light3));
+ Assert.Equal(Colors.MistyRose, Assert.IsType(light3));
+ }
+ finally
+ {
+ app.Styles.Remove(theme);
+ AvaloniaLocator.CurrentMutable.Bind().ToConstant(originalSettings);
+ }
+ }
+
+ private sealed class ShadeReportingPlatformSettings : DefaultPlatformSettings
+ {
+ public override PlatformColorValues GetColorValues() => new()
+ {
+ AccentColor1 = Colors.Crimson,
+ AccentColorDark1 = Colors.DarkRed,
+ AccentColorDark2 = Colors.Maroon,
+ AccentColorDark3 = Colors.Brown,
+ AccentColorLight1 = Colors.Salmon,
+ AccentColorLight2 = Colors.LightSalmon,
+ AccentColorLight3 = Colors.MistyRose,
+ };
+ }
+
[AvaloniaFact]
public void Legacy_palette_colors_derive_fluent2_tokens()
{