Eigenes Symbol für den Mixer in der Menüleiste
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 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
9EC9D57A96489F5578000822 /* NetworkProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FF4E99C8BF0D8944C314A8AF /* NetworkProvider */; };
|
9EC9D57A96489F5578000822 /* NetworkProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FF4E99C8BF0D8944C314A8AF /* NetworkProvider */; };
|
||||||
A529046C33E6B00C0E9508FF /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 508DECB5C05264E6130C373E /* Localizable.xcstrings */; };
|
A529046C33E6B00C0E9508FF /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 508DECB5C05264E6130C373E /* Localizable.xcstrings */; };
|
||||||
A9617230F602C5D52F63A7E2 /* ShelfProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FA6C9F90DF47DC0DFB9ED55D /* ShelfProvider */; };
|
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 */; };
|
B309DD8966B5348250CEC6BD /* LaunchAtLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41C778876BEF3D8B04F7C3C9 /* LaunchAtLogin.swift */; };
|
||||||
B6CD48B41866A468AE7A1BC7 /* OnyxWidgetKit in Frameworks */ = {isa = PBXBuildFile; productRef = E66577A40689DF225BCED184 /* OnyxWidgetKit */; };
|
B6CD48B41866A468AE7A1BC7 /* OnyxWidgetKit in Frameworks */ = {isa = PBXBuildFile; productRef = E66577A40689DF225BCED184 /* OnyxWidgetKit */; };
|
||||||
C041F171FB69F4381309D978 /* AppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83C4E3CB821F903F3977E88 /* AppModel.swift */; };
|
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 = "<group>"; };
|
87597F09E971C14CF1E475DB /* Onyx.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Onyx.entitlements; sourceTree = "<group>"; };
|
||||||
89309D9F5722FA1B91CF2905 /* FanWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FanWidget.swift; sourceTree = "<group>"; };
|
89309D9F5722FA1B91CF2905 /* FanWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FanWidget.swift; sourceTree = "<group>"; };
|
||||||
8B7ECCFCBA1BAAC6583D4A39 /* OnyxHelper */ = {isa = PBXFileReference; includeInIndex = 0; path = OnyxHelper; sourceTree = BUILT_PRODUCTS_DIR; };
|
8B7ECCFCBA1BAAC6583D4A39 /* OnyxHelper */ = {isa = PBXFileReference; includeInIndex = 0; path = OnyxHelper; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */ = {isa = PBXFileReference; path = "sound-waves.svg"; sourceTree = "<group>"; };
|
||||||
8E43384BA603C866D148D9D8 /* SettingsWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsWindowController.swift; sourceTree = "<group>"; };
|
8E43384BA603C866D148D9D8 /* SettingsWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsWindowController.swift; sourceTree = "<group>"; };
|
||||||
B442E8A39C37C8FD92B4CA83 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
B442E8A39C37C8FD92B4CA83 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||||
B83C4E3CB821F903F3977E88 /* AppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppModel.swift; sourceTree = "<group>"; };
|
B83C4E3CB821F903F3977E88 /* AppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppModel.swift; sourceTree = "<group>"; };
|
||||||
@@ -168,6 +170,7 @@
|
|||||||
F89CAC2A7DA89B8707D45D65 /* OnyxApp.swift */,
|
F89CAC2A7DA89B8707D45D65 /* OnyxApp.swift */,
|
||||||
45BD2DF1B775C733C8F75635 /* SettingsView.swift */,
|
45BD2DF1B775C733C8F75635 /* SettingsView.swift */,
|
||||||
8E43384BA603C866D148D9D8 /* SettingsWindowController.swift */,
|
8E43384BA603C866D148D9D8 /* SettingsWindowController.swift */,
|
||||||
|
8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */,
|
||||||
);
|
);
|
||||||
path = Onyx;
|
path = Onyx;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -280,6 +283,7 @@
|
|||||||
FF97F56CE1C734E59F1B40F4 /* AppIcon.icon in Resources */,
|
FF97F56CE1C734E59F1B40F4 /* AppIcon.icon in Resources */,
|
||||||
A529046C33E6B00C0E9508FF /* Localizable.xcstrings in Resources */,
|
A529046C33E6B00C0E9508FF /* Localizable.xcstrings in Resources */,
|
||||||
7CE2EDC6BC58678269BF27AD /* MenuBarIcon.svg in Resources */,
|
7CE2EDC6BC58678269BF27AD /* MenuBarIcon.svg in Resources */,
|
||||||
|
B0FCCD92AF22F1636482EACD /* sound-waves.svg in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -108,8 +108,23 @@ private final class MixerStatusView: NSView {
|
|||||||
// liegt oft ein heller Schreibtischhintergrund, und ein zu 55 % blasses
|
// liegt oft ein heller Schreibtischhintergrund, und ein zu 55 % blasses
|
||||||
// Glyph ist dort praktisch weg. Ob der Mixer läuft, erfährt man beim
|
// Glyph ist dort praktisch weg. Ob der Mixer läuft, erfährt man beim
|
||||||
// Klick — dafür muss man das Symbol aber erst finden.
|
// Klick — dafür muss man das Symbol aber erst finden.
|
||||||
MenuBarText.drawSymbol("slider.horizontal.3", color: .labelColor,
|
let rect = NSRect(x: bounds.midX - 8, y: bounds.midY - 8, width: 16, height: 16)
|
||||||
in: NSRect(x: bounds.midX - 7.5, y: bounds.midY - 7.5,
|
|
||||||
width: 15, height: 15))
|
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)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
1
Onyx/sound-waves.svg
Normal file
1
Onyx/sound-waves.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Bahan_copy_2" height="512" viewBox="0 0 64 64" width="512" xmlns="http://www.w3.org/2000/svg" data-name="Bahan copy 2"><g fill="rgb(0,0,0)"><path d="m7.72 24.83a3.72574 3.72574 0 0 0 -3.72 3.72v6.9a3.715 3.715 0 1 0 7.43 0v-6.9a3.7172 3.7172 0 0 0 -3.71-3.72z"/><path d="m19.86 19a3.72575 3.72575 0 0 0 -3.72 3.72v18.56a3.715 3.715 0 1 0 7.43 0v-18.56a3.71725 3.71725 0 0 0 -3.71-3.72z"/><path d="m32 5.04a3.72579 3.72579 0 0 0 -3.72 3.72v46.48a3.72 3.72 0 1 0 7.43994 0v-46.48a3.72579 3.72579 0 0 0 -3.71994-3.72z"/><path d="m44.14 11.92a3.7173 3.7173 0 0 0 -3.71 3.72v32.72a3.715 3.715 0 1 0 7.43 0v-32.72a3.7258 3.7258 0 0 0 -3.72-3.72z"/><path d="m56.28 17.99a3.71721 3.71721 0 0 0 -3.71 3.72v20.58a3.715 3.715 0 1 0 7.43 0v-20.58a3.72575 3.72575 0 0 0 -3.72-3.72z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 790 B |
@@ -78,6 +78,31 @@ public enum MenuBarText {
|
|||||||
return fittedSize(of: image, height: height).width
|
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? {
|
private static func symbol(_ name: String, color: NSColor, height: CGFloat) -> NSImage? {
|
||||||
guard let image = NSImage(systemSymbolName: name, accessibilityDescription: nil)
|
guard let image = NSImage(systemSymbolName: name, accessibilityDescription: nil)
|
||||||
else { return nil }
|
else { return nil }
|
||||||
|
|||||||
Reference in New Issue
Block a user