using System.Drawing.Drawing2D; using SwyxTray.Swyx; namespace SwyxTray; /// /// Erzeugt die Symbole zur Laufzeit (Kreis mit Hoererbogen), damit keine /// .ico-Dateien mitgeliefert werden muessen. Wer eigene Symbole verwenden /// will, ersetzt einfach durch das Laden aus Ressourcen. /// /// Die Symbole werden einmal je Zustand erzeugt und zwischengespeichert — /// GDI-Handles sind eine begrenzte Ressource. /// internal static class TrayIcons { private static readonly Dictionary Cache = new(); private static readonly Dictionary Colors = new() { [SwyxOverallState.Offline] = Color.FromArgb(0x9E, 0x9E, 0x9E), // grau [SwyxOverallState.ServerDown] = Color.FromArgb(0xE5, 0x39, 0x35), // rot [SwyxOverallState.Idle] = Color.FromArgb(0x43, 0xA0, 0x47), // gruen [SwyxOverallState.Ringing] = Color.FromArgb(0x1E, 0x88, 0xE5), // blau [SwyxOverallState.Dialing] = Color.FromArgb(0x00, 0xAC, 0xC1), // tuerkis [SwyxOverallState.InCall] = Color.FromArgb(0xFB, 0x8C, 0x00), // orange [SwyxOverallState.OnHold] = Color.FromArgb(0x8E, 0x24, 0xAA) // violett }; public static Icon For(SwyxOverallState state) { if (Cache.TryGetValue(state, out var cached)) { return cached; } var icon = Render(Colors.TryGetValue(state, out var c) ? c : Color.Gray); Cache[state] = icon; return icon; } private static Icon Render(Color color) { // 32x32 zeichnen und Windows herunterskalieren lassen — sieht auf // hochaufloesenden Anzeigen besser aus als 16x16. const int size = 32; using var bitmap = new Bitmap(size, size); using (var g = Graphics.FromImage(bitmap)) { g.SmoothingMode = SmoothingMode.AntiAlias; g.Clear(Color.Transparent); using (var brush = new SolidBrush(color)) { g.FillEllipse(brush, 1, 1, size - 3, size - 3); } // Hoerer: ein dicker Bogen mit runden Enden liest sich bei kleiner // Darstellung zuverlaessiger als eine ausmodellierte Silhouette. using var pen = new Pen(Color.White, 5f) { StartCap = LineCap.Round, EndCap = LineCap.Round }; g.DrawArc(pen, 9f, 9f, 14f, 14f, 130f, 200f); } // Icon.FromHandle borgt sich das Handle nur; ueber Clone entsteht eine // eigenstaendige Kopie, damit das HICON sofort freigegeben werden kann. var hIcon = bitmap.GetHicon(); try { using var borrowed = Icon.FromHandle(hIcon); return (Icon)borrowed.Clone(); } finally { NativeMethods.DestroyIcon(hIcon); } } public static void DisposeAll() { foreach (var icon in Cache.Values) { icon.Dispose(); } Cache.Clear(); } }