From 192a17a0c45b38221c1bc498b5fb6f9850f17597 Mon Sep 17 00:00:00 2001 From: Simnico99 Date: Tue, 14 Nov 2023 15:06:31 -0500 Subject: [PATCH] Better error handling for WinRT + Better accent color handling. --- .../Helpers/WindowsAccentHelper.cs | 49 +++++++++- .../Services/AccentColorService.cs | 43 +-------- src/MicaWPF/Helpers/WinRTHelper.cs | 93 +++++++++++++++++++ .../Helpers/WindowsAccentHelperWinRT.cs | 85 ++--------------- 4 files changed, 147 insertions(+), 123 deletions(-) create mode 100644 src/MicaWPF/Helpers/WinRTHelper.cs diff --git a/src/MicaWPF.Core/Helpers/WindowsAccentHelper.cs b/src/MicaWPF.Core/Helpers/WindowsAccentHelper.cs index 8cc5d0f..10a7cdc 100644 --- a/src/MicaWPF.Core/Helpers/WindowsAccentHelper.cs +++ b/src/MicaWPF.Core/Helpers/WindowsAccentHelper.cs @@ -3,6 +3,7 @@ // using System.Windows.Media; +using MicaWPF.Core.Enums; using MicaWPF.Core.Interop; using MicaWPF.Core.Models; using Microsoft.Win32; @@ -17,6 +18,26 @@ public class WindowsAccentHelper protected const string _registryKeyPath = @"Software\Microsoft\Windows\DWM"; protected const string _registryValueName = "ColorPrevalence"; + /// + /// Convert a to a object."/>. + /// + /// The current color. + /// The with color variations from the provided color. + public static AccentColors GetWindowsColorVariations(Color systemAccent) + { + var drawingColor = System.Drawing.Color.FromArgb(systemAccent.R, systemAccent.G, systemAccent.B); + var hsvColor = HSVColorHelper.ConvertToHSVColor(drawingColor); + + return new AccentColors( + systemAccent, + GetThemeColorVariation(hsvColor, WindowsTheme.Dark, AccentBrushType.Secondary), + GetThemeColorVariation(hsvColor, WindowsTheme.Dark, AccentBrushType.Tertiary), + GetThemeColorVariation(hsvColor, WindowsTheme.Dark, AccentBrushType.Quaternary), + GetThemeColorVariation(hsvColor, WindowsTheme.Light, AccentBrushType.Secondary), + GetThemeColorVariation(hsvColor, WindowsTheme.Light, AccentBrushType.Tertiary), + GetThemeColorVariation(hsvColor, WindowsTheme.Light, AccentBrushType.Quaternary)); + } + /// /// Determines whether the title bar and window borders are accented. /// @@ -46,8 +67,8 @@ public virtual bool AreTitleBarAndBordersAccented() /// public virtual AccentColors GetAccentColor() { - InteropMethods.DwmGetColorizationParameters(out var colors); - return new(ParseColor(colors.clrColor), default, default, default, default, default, default, true); + var colors = InteropMethods.GetDwmGetColorizationParameters(); + return GetWindowsColorVariations(ParseColor(colors.clrColor)); } protected static Color ParseColor(uint color) @@ -60,4 +81,28 @@ protected static Color ParseColor(uint color) (byte)(color >> 8 & 0xff), (byte)((byte)color & 0xff)); } + + protected static Color GetThemeColorVariation((double Hue, double Saturation, double Value) hsv, WindowsTheme windowsTheme, AccentBrushType accentBrushType) + { + var hueCoefficient = 1 - hsv.Value < 0.15 ? 1 : 0; + + return accentBrushType switch + { + AccentBrushType.Primary => HSVColorHelper.RGBFromHSV(hsv.Hue, hsv.Saturation, hsv.Value), + AccentBrushType.Secondary => GetOffSet(hsv.Hue, hueCoefficient, hsv.Saturation, hsv.Value, 0.3, windowsTheme), + AccentBrushType.Tertiary => GetOffSet(hsv.Hue, hueCoefficient, hsv.Saturation, hsv.Value, 0.35, windowsTheme), + AccentBrushType.Quaternary => GetOffSet(hsv.Hue, hueCoefficient, hsv.Saturation, hsv.Value, 0.65, windowsTheme), + _ => throw new ArgumentOutOfRangeException(nameof(accentBrushType)), + }; + } + + protected static Color GetOffSet(double hue, double hueCoefficient, double saturation, double value, double valueCoefficient, WindowsTheme windowsTheme) + { + return windowsTheme switch + { + WindowsTheme.Dark => HSVColorHelper.RGBFromHSV(Math.Min(hue + hueCoefficient, 360), saturation, Math.Min(value + valueCoefficient, 1)), + WindowsTheme.Light => HSVColorHelper.RGBFromHSV(Math.Min(hue + hueCoefficient, 360), saturation, Math.Min(value - (valueCoefficient / 2), 1)), + _ => throw new ArgumentOutOfRangeException(nameof(windowsTheme)), + }; + } } diff --git a/src/MicaWPF.Core/Services/AccentColorService.cs b/src/MicaWPF.Core/Services/AccentColorService.cs index 3aba615..7436401 100644 --- a/src/MicaWPF.Core/Services/AccentColorService.cs +++ b/src/MicaWPF.Core/Services/AccentColorService.cs @@ -59,59 +59,18 @@ public void RefreshAccentsColors() public void UpdateAccentsColors(Color systemAccent) { AccentColorsUpdateFromWindows = false; - var drawingColor = System.Drawing.Color.FromArgb(systemAccent.R, systemAccent.G, systemAccent.B); - var hsvColor = HSVColorHelper.ConvertToHSVColor(drawingColor); - - AccentColors = new AccentColors( - systemAccent, - GetThemeColorVariation(hsvColor, WindowsTheme.Dark, AccentBrushType.Secondary), - GetThemeColorVariation(hsvColor, WindowsTheme.Dark, AccentBrushType.Tertiary), - GetThemeColorVariation(hsvColor, WindowsTheme.Dark, AccentBrushType.Quaternary), - GetThemeColorVariation(hsvColor, WindowsTheme.Light, AccentBrushType.Secondary), - GetThemeColorVariation(hsvColor, WindowsTheme.Light, AccentBrushType.Tertiary), - GetThemeColorVariation(hsvColor, WindowsTheme.Light, AccentBrushType.Quaternary)); + AccentColors = WindowsAccentHelper.GetWindowsColorVariations(systemAccent); UpdateFromInternalColors(); } public void UpdateAccentsColorsFromWindows() { - AccentColorsUpdateFromWindows = true; - AccentColors = WindowsAccentHelper.GetAccentColor(); - if (OsHelper.IsWindows10 || AccentColors.IsFallBack) - { - UpdateAccentsColors(AccentColors.SystemAccentColor); - } - UpdateFromInternalColors(); } - private static Color GetThemeColorVariation((double Hue, double Saturation, double Value) hsv, WindowsTheme windowsTheme, AccentBrushType accentBrushType) - { - var hueCoefficient = 1 - hsv.Value < 0.15 ? 1 : 0; - - return accentBrushType switch - { - AccentBrushType.Primary => HSVColorHelper.RGBFromHSV(hsv.Hue, hsv.Saturation, hsv.Value), - AccentBrushType.Secondary => GetOffSet(hsv.Hue, hueCoefficient, hsv.Saturation, hsv.Value, 0.3, windowsTheme), - AccentBrushType.Tertiary => GetOffSet(hsv.Hue, hueCoefficient, hsv.Saturation, hsv.Value, 0.35, windowsTheme), - AccentBrushType.Quaternary => GetOffSet(hsv.Hue, hueCoefficient, hsv.Saturation, hsv.Value, 0.65, windowsTheme), - _ => throw new ArgumentOutOfRangeException(nameof(accentBrushType)), - }; - } - - private static Color GetOffSet(double hue, double hueCoefficient, double saturation, double value, double valueCoefficient, WindowsTheme windowsTheme) - { - return windowsTheme switch - { - WindowsTheme.Dark => HSVColorHelper.RGBFromHSV(Math.Min(hue + hueCoefficient, 360), saturation, Math.Min(value + valueCoefficient, 1)), - WindowsTheme.Light => HSVColorHelper.RGBFromHSV(Math.Min(hue + hueCoefficient, 360), saturation, Math.Min(value - (valueCoefficient / 2), 1)), - _ => throw new ArgumentOutOfRangeException(nameof(windowsTheme)), - }; - } - private void UpdateColorResources(Color primaryAccent, Color secondaryAccent, Color tertiaryAccent) { var colorKeys = new string[] { "Primary", "Secondary", "Tertiary", "Light3", "Light2", "Light1", string.Empty, "Dark1", "Dark2", "Dark3" }; diff --git a/src/MicaWPF/Helpers/WinRTHelper.cs b/src/MicaWPF/Helpers/WinRTHelper.cs new file mode 100644 index 0000000..b991308 --- /dev/null +++ b/src/MicaWPF/Helpers/WinRTHelper.cs @@ -0,0 +1,93 @@ +// +// This software is distributed under the MIT license and its code is open-source and free for use, modification, and distribution. +// + +using System.Windows.Media; +using MicaWPF.Core.Models; +#if NET5_0_OR_GREATER +using MicaWPFRuntimeComponent; +#endif +#if NETFRAMEWORK || NETCOREAPP3_1 +using Windows.UI.ViewManagement; +#endif + +namespace MicaWPF.Helpers; + +public static class WinRTHelper +{ + public static AccentColors GetSystemAccentColor() + { +#if NET5_0_OR_GREATER + var tempColorAccent = default(Color); + var tempColorAccentLight1 = default(Color); + var tempColorAccentLight2 = default(Color); + var tempColorAccentLight3 = default(Color); + var tempColorAccentDark1 = default(Color); + var tempColorAccentDark2 = default(Color); + var tempColorAccentDark3 = default(Color); + + var uwpColors = new UWPColors(); + var colorsLongString = uwpColors.GetSystemColors(); + + foreach (var colors in colorsLongString) + { + var colorValues = colors.Split(','); + var colorResult = Color.FromArgb(byte.Parse(colorValues[0]), byte.Parse(colorValues[1]), byte.Parse(colorValues[2]), byte.Parse(colorValues[3])); + switch (colorValues[4].ToString()) + { + case "SystemAccentColor": + tempColorAccent = colorResult; + break; + case "SystemAccentColorLight1": + tempColorAccentLight1 = colorResult; + break; + case "SystemAccentColorLight2": + tempColorAccentLight2 = colorResult; + break; + case "SystemAccentColorLight3": + tempColorAccentLight3 = colorResult; + break; + case "SystemAccentColorDark1": + tempColorAccentDark1 = colorResult; + break; + case "SystemAccentColorDark2": + tempColorAccentDark2 = colorResult; + break; + case "SystemAccentColorDark3": + tempColorAccentDark3 = colorResult; + break; + default: + break; + } + } + + return new( + tempColorAccent, + tempColorAccentLight1, + tempColorAccentLight2, + tempColorAccentLight3, + tempColorAccentDark1, + tempColorAccentDark2, + tempColorAccentDark3); +#endif +#if NETFRAMEWORK || NETCOREAPP3_1 + return new AccentColors( + UIColorConverter(UIColorType.Accent), + UIColorConverter(UIColorType.AccentLight1), + UIColorConverter(UIColorType.AccentLight2), + UIColorConverter(UIColorType.AccentLight3), + UIColorConverter(UIColorType.AccentDark1), + UIColorConverter(UIColorType.AccentDark2), + UIColorConverter(UIColorType.AccentDark3)); +#endif + } + +#if NETFRAMEWORK || NETCOREAPP3_1 + private static Color UIColorConverter(UIColorType colorType) + { + var uiSettings = new UISettings(); + var color = uiSettings.GetColorValue(colorType); + return Color.FromArgb(color.A, color.R, color.G, color.B); + } +#endif +} diff --git a/src/MicaWPF/Helpers/WindowsAccentHelperWinRT.cs b/src/MicaWPF/Helpers/WindowsAccentHelperWinRT.cs index 371beaa..29c12d4 100644 --- a/src/MicaWPF/Helpers/WindowsAccentHelperWinRT.cs +++ b/src/MicaWPF/Helpers/WindowsAccentHelperWinRT.cs @@ -2,18 +2,10 @@ // This software is distributed under the MIT license and its code is open-source and free for use, modification, and distribution. // -using System.Runtime.InteropServices; -using System.Windows.Media; using MicaWPF.Core.Helpers; using MicaWPF.Core.Interop; using MicaWPF.Core.Models; using Microsoft.Win32; -#if NET5_0_OR_GREATER -using MicaWPFRuntimeComponent; -#endif -#if NETFRAMEWORK || NETCOREAPP3_1 -using Windows.UI.ViewManagement; -#endif namespace MicaWPF.Helpers; @@ -38,84 +30,19 @@ public override AccentColors GetAccentColor() { try { -#if NET5_0_OR_GREATER - var tempColorAccent = default(Color); - var tempColorAccentLight1 = default(Color); - var tempColorAccentLight2 = default(Color); - var tempColorAccentLight3 = default(Color); - var tempColorAccentDark1 = default(Color); - var tempColorAccentDark2 = default(Color); - var tempColorAccentDark3 = default(Color); + var colors = WinRTHelper.GetSystemAccentColor(); - var uwpColors = new UWPColors(); - var colorsLongString = uwpColors.GetSystemColors(); - - foreach (var colors in colorsLongString) + if (OsHelper.IsWindows11_OrGreater) { - var colorValues = colors.Split(','); - var colorResult = Color.FromArgb(byte.Parse(colorValues[0]), byte.Parse(colorValues[1]), byte.Parse(colorValues[2]), byte.Parse(colorValues[3])); - switch (colorValues[4].ToString()) - { - case "SystemAccentColor": - tempColorAccent = colorResult; - break; - case "SystemAccentColorLight1": - tempColorAccentLight1 = colorResult; - break; - case "SystemAccentColorLight2": - tempColorAccentLight2 = colorResult; - break; - case "SystemAccentColorLight3": - tempColorAccentLight3 = colorResult; - break; - case "SystemAccentColorDark1": - tempColorAccentDark1 = colorResult; - break; - case "SystemAccentColorDark2": - tempColorAccentDark2 = colorResult; - break; - case "SystemAccentColorDark3": - tempColorAccentDark3 = colorResult; - break; - default: - break; - } + return colors; } - return new( - tempColorAccent, - tempColorAccentLight1, - tempColorAccentLight2, - tempColorAccentLight3, - tempColorAccentDark1, - tempColorAccentDark2, - tempColorAccentDark3); - } -#endif -#if NETFRAMEWORK || NETCOREAPP3_1 - return new AccentColors( - UIColorConverter(UIColorType.Accent), - UIColorConverter(UIColorType.AccentLight1), - UIColorConverter(UIColorType.AccentLight2), - UIColorConverter(UIColorType.AccentLight3), - UIColorConverter(UIColorType.AccentDark1), - UIColorConverter(UIColorType.AccentDark2), - UIColorConverter(UIColorType.AccentDark3)); + return GetWindowsColorVariations(colors.SystemAccentColor); } -#endif - catch (Exception e) when (e is TypeInitializationException or COMException) + catch { var colors = InteropMethods.GetDwmGetColorizationParameters(); - return new(ParseColor(colors.clrColor), default, default, default, default, default, default, true); + return GetWindowsColorVariations(ParseColor(colors.clrColor)); } } - -#if NETFRAMEWORK || NETCOREAPP3_1 - private static Color UIColorConverter(UIColorType colorType) - { - var uiSettings = new UISettings(); - var color = uiSettings.GetColorValue(colorType); - return Color.FromArgb(color.A, color.R, color.G, color.B); - } -#endif }