From 43ce40676b1a7f1fb85586355ce22074cda2eab6 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Thu, 13 Aug 2026 13:23:21 +0200 Subject: [PATCH] =?UTF-8?q?Eigenes=20Symbol=20f=C3=BCr=20den=20Mixer=20in?= =?UTF-8?q?=20der=20Men=C3=BCleiste?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die Datei lag im Projektstamm; von dort wird nichts mitgeliefert. Jetzt in Onyx/ und damit im Bundle. Gezeichnet wird sie in `labelColor`, nicht in Weiß: unter einer hellen Menüleiste wäre ein weißes Symbol unsichtbar. Auf dunklem Grund ist labelColor weiß, also genau das Gewünschte — und auf hellem Grund schwarz, statt zu verschwinden. Eigene Vorlagen lassen sich nicht wie SF-Symbole einfärben: dort greift die Symbolkonfiguration nicht, und `color.set()` allein färbt ein Template-Bild ohnehin nicht. Der Weg ist, das Bild zu zeichnen und die Farbe mit `sourceAtop` darüberzulegen — das trifft die deckenden Bildpunkte und lässt den Rest frei. Co-Authored-By: Claude Opus 5 --- Onyx.xcodeproj/project.pbxproj | 4 +++ Onyx/MixerMenuBarModule.swift | 21 +++++++++++++--- Onyx/sound-waves.svg | 1 + .../Sources/OnyxMenuBar/MenuBarText.swift | 25 +++++++++++++++++++ 4 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 Onyx/sound-waves.svg diff --git a/Onyx.xcodeproj/project.pbxproj b/Onyx.xcodeproj/project.pbxproj index dbd2164..b514387 100644 --- a/Onyx.xcodeproj/project.pbxproj +++ b/Onyx.xcodeproj/project.pbxproj @@ -26,6 +26,7 @@ 9EC9D57A96489F5578000822 /* NetworkProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FF4E99C8BF0D8944C314A8AF /* NetworkProvider */; }; A529046C33E6B00C0E9508FF /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 508DECB5C05264E6130C373E /* Localizable.xcstrings */; }; A9617230F602C5D52F63A7E2 /* ShelfProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FA6C9F90DF47DC0DFB9ED55D /* ShelfProvider */; }; + B0FCCD92AF22F1636482EACD /* sound-waves.svg in Resources */ = {isa = PBXBuildFile; fileRef = 8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */; }; B309DD8966B5348250CEC6BD /* LaunchAtLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41C778876BEF3D8B04F7C3C9 /* LaunchAtLogin.swift */; }; B6CD48B41866A468AE7A1BC7 /* OnyxWidgetKit in Frameworks */ = {isa = PBXBuildFile; productRef = E66577A40689DF225BCED184 /* OnyxWidgetKit */; }; C041F171FB69F4381309D978 /* AppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83C4E3CB821F903F3977E88 /* AppModel.swift */; }; @@ -65,6 +66,7 @@ 87597F09E971C14CF1E475DB /* Onyx.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Onyx.entitlements; sourceTree = ""; }; 89309D9F5722FA1B91CF2905 /* FanWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FanWidget.swift; sourceTree = ""; }; 8B7ECCFCBA1BAAC6583D4A39 /* OnyxHelper */ = {isa = PBXFileReference; includeInIndex = 0; path = OnyxHelper; sourceTree = BUILT_PRODUCTS_DIR; }; + 8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */ = {isa = PBXFileReference; path = "sound-waves.svg"; sourceTree = ""; }; 8E43384BA603C866D148D9D8 /* SettingsWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsWindowController.swift; sourceTree = ""; }; B442E8A39C37C8FD92B4CA83 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; B83C4E3CB821F903F3977E88 /* AppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppModel.swift; sourceTree = ""; }; @@ -168,6 +170,7 @@ F89CAC2A7DA89B8707D45D65 /* OnyxApp.swift */, 45BD2DF1B775C733C8F75635 /* SettingsView.swift */, 8E43384BA603C866D148D9D8 /* SettingsWindowController.swift */, + 8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */, ); path = Onyx; sourceTree = ""; @@ -280,6 +283,7 @@ FF97F56CE1C734E59F1B40F4 /* AppIcon.icon in Resources */, A529046C33E6B00C0E9508FF /* Localizable.xcstrings in Resources */, 7CE2EDC6BC58678269BF27AD /* MenuBarIcon.svg in Resources */, + B0FCCD92AF22F1636482EACD /* sound-waves.svg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Onyx/MixerMenuBarModule.swift b/Onyx/MixerMenuBarModule.swift index c6e9ad5..4a8214f 100644 --- a/Onyx/MixerMenuBarModule.swift +++ b/Onyx/MixerMenuBarModule.swift @@ -108,8 +108,23 @@ private final class MixerStatusView: NSView { // liegt oft ein heller Schreibtischhintergrund, und ein zu 55 % blasses // Glyph ist dort praktisch weg. Ob der Mixer läuft, erfährt man beim // Klick — dafür muss man das Symbol aber erst finden. - MenuBarText.drawSymbol("slider.horizontal.3", color: .labelColor, - in: NSRect(x: bounds.midX - 7.5, y: bounds.midY - 7.5, - width: 15, height: 15)) + let rect = NSRect(x: bounds.midX - 8, y: bounds.midY - 8, width: 16, height: 16) + + if let glyph = Self.glyph { + // `labelColor` und nicht Weiß: unter einer hellen Menüleiste wäre + // ein weißes Symbol unsichtbar. Auf dunklem Grund ist labelColor + // weiß, also genau das Gewünschte. + MenuBarText.drawTemplate(glyph, color: .labelColor, in: rect) + return + } + MenuBarText.drawSymbol("slider.horizontal.3", color: .labelColor, in: rect) } + + /// Die eigene Vorlage aus dem Bundle. Einmal geladen und behalten — das + /// Zeichnen läuft bei jeder Änderung, das Einlesen einer SVG nicht. + private static let glyph: NSImage? = { + guard let url = Bundle.main.url(forResource: "sound-waves", withExtension: "svg") + else { return nil } + return NSImage(contentsOf: url) + }() } diff --git a/Onyx/sound-waves.svg b/Onyx/sound-waves.svg new file mode 100644 index 0000000..e4b4672 --- /dev/null +++ b/Onyx/sound-waves.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Packages/OnyxKit/Sources/OnyxMenuBar/MenuBarText.swift b/Packages/OnyxKit/Sources/OnyxMenuBar/MenuBarText.swift index 79eda0b..6de01d1 100644 --- a/Packages/OnyxKit/Sources/OnyxMenuBar/MenuBarText.swift +++ b/Packages/OnyxKit/Sources/OnyxMenuBar/MenuBarText.swift @@ -78,6 +78,31 @@ public enum MenuBarText { return fittedSize(of: image, height: height).width } + /// Zeichnet ein beliebiges Bild in der gewünschten Farbe. + /// + /// Für eigene Vorlagen statt SF-Symbole: dort greift die + /// Symbolkonfiguration nicht, und `color.set()` allein färbt ein + /// Template-Bild nicht. Der Weg ist, das Bild zu zeichnen und die Farbe + /// mit `sourceAtop` darüberzulegen — das trifft genau die deckenden + /// Bildpunkte und lässt den Rest frei. + public static func drawTemplate(_ image: NSImage, color: NSColor, in rect: NSRect) { + let natural = image.size + let fitted: NSSize = natural.height > 0 + ? NSSize(width: (natural.width / natural.height) * rect.height, height: rect.height) + : rect.size + let target = NSRect(x: rect.midX - fitted.width / 2, + y: rect.midY - fitted.height / 2, + width: fitted.width, height: fitted.height) + + let tinted = NSImage(size: target.size, flipped: false) { bounds in + image.draw(in: bounds, from: .zero, operation: .sourceOver, fraction: 1) + color.set() + bounds.fill(using: .sourceAtop) + return true + } + tinted.draw(in: target) + } + private static func symbol(_ name: String, color: NSColor, height: CGFloat) -> NSImage? { guard let image = NSImage(systemSymbolName: name, accessibilityDescription: nil) else { return nil }