Skip to content

Commit

Permalink
Better error handling for WinRT + Better accent color handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
Simnico99 committed Nov 14, 2023
1 parent 4dd78a9 commit 192a17a
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 123 deletions.
49 changes: 47 additions & 2 deletions src/MicaWPF.Core/Helpers/WindowsAccentHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// </copyright>

using System.Windows.Media;
using MicaWPF.Core.Enums;
using MicaWPF.Core.Interop;
using MicaWPF.Core.Models;
using Microsoft.Win32;
Expand All @@ -17,6 +18,26 @@ public class WindowsAccentHelper
protected const string _registryKeyPath = @"Software\Microsoft\Windows\DWM";
protected const string _registryValueName = "ColorPrevalence";

/// <summary>
/// Convert a <see cref="Color"/> to a <see cref="AccentColors"/> object."/>.
/// </summary>
/// <param name="systemAccent">The current color.</param>
/// <returns>The <see cref="AccentColors"/> with color variations from the provided color.</returns>
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));
}

/// <summary>
/// Determines whether the title bar and window borders are accented.
/// </summary>
Expand Down Expand Up @@ -46,8 +67,8 @@ public virtual bool AreTitleBarAndBordersAccented()
/// </returns>
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)
Expand All @@ -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)),
};
}
}
43 changes: 1 addition & 42 deletions src/MicaWPF.Core/Services/AccentColorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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" };
Expand Down
93 changes: 93 additions & 0 deletions src/MicaWPF/Helpers/WinRTHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// <copyright file="WinRTHelper.cs" company="Zircon Technology">
// This software is distributed under the MIT license and its code is open-source and free for use, modification, and distribution.
// </copyright>

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
}
85 changes: 6 additions & 79 deletions src/MicaWPF/Helpers/WindowsAccentHelperWinRT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
// </copyright>

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;

Expand All @@ -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
}

0 comments on commit 192a17a

Please sign in to comment.