using System.Windows;
using System.Windows.Media;
using Microsoft.Win32;
namespace DeskCore;
/// Übernimmt Hell/Dunkel-Modus und Akzentfarbe von Windows – auch live, wenn man sie ändert.
public static class Theme
{
public static bool IsLight { get; private set; } = true;
/// Vom Benutzer gewählter Modus; "System" folgt der Windows-Einstellung.
public static DesignMode Mode => AppSettings.Current.Design;
public static void Init()
{
Apply();
SystemEvents.UserPreferenceChanged += (_, e) =>
{
if (e.Category is UserPreferenceCategory.General or UserPreferenceCategory.Color or UserPreferenceCategory.VisualStyle)
Application.Current.Dispatcher.BeginInvoke(Apply);
};
}
public static void Apply()
{
IsLight = Mode switch
{
DesignMode.Light => true,
DesignMode.Dark => false,
_ => ReadDword(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme") != 0,
};
var res = Application.Current.Resources;
res.MergedDictionaries[0] = new ResourceDictionary
{
Source = new Uri($"pack://application:,,,/Themes/Colors.{(IsLight ? "Light" : "Dark")}.xaml")
};
// DWM speichert die Akzentfarbe als ABGR
int abgr = ReadDword(@"Software\Microsoft\Windows\DWM", "AccentColor") is var v and not -1 ? v : unchecked((int)0xFFD77800);
var accent = Color.FromRgb((byte)abgr, (byte)(abgr >> 8), (byte)(abgr >> 16));
// Wie Windows 11: im Hellmodus etwas dunkler + weiße Schrift, im Dunkelmodus deutlich heller + schwarze Schrift
var a = IsLight ? Mix(accent, Colors.Black, 0.12) : Mix(accent, Colors.White, 0.45);
res["AccentBrush"] = Brush(a);
res["AccentHoverBrush"] = Brush(IsLight ? Mix(a, Colors.White, 0.1) : Mix(a, Colors.Black, 0.1));
res["OnAccentBrush"] = Brush(IsLight ? Colors.White : Colors.Black);
res["AccentSubtleBrush"] = Brush(Color.FromArgb(IsLight ? (byte)0x22 : (byte)0x30, a.R, a.G, a.B));
res["AccentSubtleStrokeBrush"] = Brush(Color.FromArgb(IsLight ? (byte)0x55 : (byte)0x60, a.R, a.G, a.B));
Changed?.Invoke();
}
public static event Action? Changed;
private static int ReadDword(string key, string name)
{
try
{
using var k = Registry.CurrentUser.OpenSubKey(key);
return k?.GetValue(name) is int i ? i : -1;
}
catch { return -1; }
}
private static Color Mix(Color c, Color with, double t) => Color.FromRgb(
(byte)(c.R + (with.R - c.R) * t), (byte)(c.G + (with.G - c.G) * t), (byte)(c.B + (with.B - c.B) * t));
private static SolidColorBrush Brush(Color c)
{
var b = new SolidColorBrush(c);
b.Freeze();
return b;
}
}