refactor: unify custom shortcut indicators across the app

This commit is contained in:
2026-10-13 17:29:06 +02:00
parent adf40d4161
commit 7cfd8096a4
6 changed files with 72 additions and 78 deletions
+6 -54
View File
@@ -1,6 +1,5 @@
import AppKit
import ConjureKit
import CoreText
@MainActor
final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSearchFieldDelegate, NSTableViewDataSource, NSTableViewDelegate {
@@ -268,12 +267,8 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
actionsButton.toolTip = "Actions for the selected application (Command-K)"
actionsButton.isEnabled = false
openButton.toolTip = "Open the selected application (Return). Use ↑ and ↓ to select."
let returnKey = shortcutBadge("↵")
let commandKey = shortcutBadge("⌘")
let kKey = shortcutBadge("K")
for badge in [returnKey, commandKey, kKey] {
badge.font = openButton.font
}
let returnKey = ShortcutIndicator("↵")
let actionKeys = ShortcutIndicator("⌘", "K")
let actionPill = NSVisualEffectView()
actionPill.material = .popover
@@ -281,7 +276,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
actionPill.state = .active
roundMaterialCorners(actionPill, radius: 18)
actionPill.layer?.borderWidth = 0.5
for view in [openButton, returnKey, actionsButton, commandKey, kKey] {
for view in [openButton, returnKey, actionsButton, actionKeys] {
view.translatesAutoresizingMaskIntoConstraints = false
actionPill.addSubview(view)
}
@@ -320,20 +315,15 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
openButton.centerYAnchor.constraint(equalTo: actionPill.centerYAnchor),
returnKey.leadingAnchor.constraint(equalTo: openButton.trailingAnchor, constant: 8),
actionsButton.leadingAnchor.constraint(equalTo: returnKey.trailingAnchor, constant: 14),
commandKey.leadingAnchor.constraint(equalTo: actionsButton.trailingAnchor, constant: 8),
commandKey.centerYAnchor.constraint(equalTo: actionPill.centerYAnchor),
kKey.leadingAnchor.constraint(equalTo: commandKey.trailingAnchor, constant: 2),
kKey.centerYAnchor.constraint(equalTo: actionPill.centerYAnchor),
kKey.trailingAnchor.constraint(equalTo: actionPill.trailingAnchor, constant: -12),
actionKeys.leadingAnchor.constraint(equalTo: actionsButton.trailingAnchor, constant: 8),
actionKeys.centerYAnchor.constraint(equalTo: actionPill.centerYAnchor),
actionKeys.trailingAnchor.constraint(equalTo: actionPill.trailingAnchor, constant: -12),
actionsButton.centerYAnchor.constraint(equalTo: actionPill.centerYAnchor),
returnKey.centerYAnchor.constraint(equalTo: actionPill.centerYAnchor),
returnKey.widthAnchor.constraint(equalToConstant: 18),
returnKey.heightAnchor.constraint(equalToConstant: 18),
])
window.effectiveAppearance.performAsCurrentDrawingAppearance {
let border = SunsetPalette.secondaryText.withAlphaComponent(0.22).cgColor
content.layer?.borderColor = border
returnKey.layer?.borderColor = SunsetPalette.secondaryText.withAlphaComponent(0.35).cgColor
actionPill.layer?.borderColor = SunsetPalette.accent.withAlphaComponent(0.35).cgColor
actionPill.layer?.backgroundColor = SunsetPalette.accent.withAlphaComponent(0.08).cgColor
}
@@ -704,41 +694,3 @@ func roundMaterialCorners(_ view: NSVisualEffectView, radius: CGFloat) {
view.maskImage = mask
}
@MainActor
func shortcutBadge(_ title: String) -> NSTextField {
let badge = ShortcutBadge(labelWithString: title)
badge.font = .systemFont(ofSize: 14)
badge.textColor = SunsetPalette.secondaryText
badge.alignment = .center
badge.wantsLayer = true
badge.layer?.cornerRadius = 5
badge.layer?.borderWidth = 1
badge.layer?.borderColor = SunsetPalette.secondaryText.withAlphaComponent(0.35).cgColor
badge.setAccessibilityElement(false)
badge.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
badge.widthAnchor.constraint(equalToConstant: 18),
badge.heightAnchor.constraint(equalToConstant: 18)
])
return badge
}
@MainActor
private final class ShortcutBadge: NSTextField {
// NSTextField's horizontal alignment insets otherwise make an 18-point badge 22 points wide.
override var alignmentRectInsets: NSEdgeInsets { NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) }
override func draw(_ dirtyRect: NSRect) {
guard let context = NSGraphicsContext.current?.cgContext else { return }
let line = CTLineCreateWithAttributedString(attributedStringValue)
let ink = CTLineGetBoundsWithOptions(line, .useGlyphPathBounds)
context.saveGState()
context.textMatrix = .identity
// Center visible ink, not the font's asymmetric ascender/descender line box.
context.translateBy(x: bounds.midX - ink.midX, y: bounds.midY + ink.midY)
context.scaleBy(x: 1, y: -1)
context.textPosition = .zero
CTLineDraw(line, context)
context.restoreGState()
}
}