Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

Refine piano waveform naming

authored by

Esteban Uribe and committed by
prompt.ac/@jeffrey
9a2eb9ef 577ef037

+240 -239
+67 -66
slab/menuband/Sources/MenuBand/AppDelegate.swift
··· 9 9 private var trackingArea: NSTrackingArea? 10 10 private var typeModeHotkey: GlobalHotkey? 11 11 private var focusCaptureHotkey: GlobalHotkey? 12 - private var playPaletteHotkey: GlobalHotkey? 12 + private var pianoWaveformHotkey: GlobalHotkey? 13 13 private var layoutToggleHotkey: GlobalHotkey? 14 14 private let popover = NSPopover() 15 15 private var popoverVC: MenuBandPopoverViewController? 16 - private lazy var pianoWaveformPalette = UnifiedPianoWaveformPalette(menuBand: menuBand) 17 - private var floatingPlayPalette: UnifiedPianoWaveformPalette { pianoWaveformPalette } 18 - private var waveformStrip: UnifiedPianoWaveformPalette { pianoWaveformPalette } 16 + private lazy var pianoWaveformPalette = PianoWaveformPalette(menuBand: menuBand) 17 + private var pianoWaveformOverlay: PianoWaveformPalette { pianoWaveformPalette } 18 + private var pianoWaveformStrip: PianoWaveformPalette { pianoWaveformPalette } 19 19 private var appBeforePopover: NSRunningApplication? 20 20 private var appBeforeFocusCapture: NSRunningApplication? 21 21 private var focusCaptureArmedByShortcut = false ··· 150 150 self.kickIconAnim(slide: dir, flash: 1.0) 151 151 } 152 152 self.updateIcon() 153 - self.floatingPlayPalette.refresh() 153 + self.pianoWaveformOverlay.refresh() 154 154 // Refresh the popover too so live state changes 155 155 // (octave shift via , / . , MIDI mode flip, etc.) 156 156 // reflect immediately while the popover is open. ··· 171 171 self.lastLitCount = cur 172 172 self.updateIcon() 173 173 self.popoverVC?.refreshHeldNotes() 174 - self.floatingPlayPalette.refresh() 175 - self.waveformStrip.refresh() 174 + self.pianoWaveformOverlay.refresh() 175 + self.pianoWaveformStrip.refresh() 176 176 self.updateWaveformStrip() 177 177 } 178 178 menuBand.onInstrumentVisualChange = { [weak self] in 179 179 DispatchQueue.main.async { 180 180 guard let self = self else { return } 181 181 self.updateIcon() 182 - self.floatingPlayPalette.refresh() 183 - self.waveformStrip.refreshAppearance() 182 + self.pianoWaveformOverlay.refresh() 183 + self.pianoWaveformStrip.refreshAppearance() 184 184 } 185 185 } 186 186 menuBand.bootstrap() 187 187 lastKnownOctaveShift = menuBand.octaveShift 188 - floatingPlayPalette.onDismiss = { [weak self] in 188 + pianoWaveformOverlay.onDismiss = { [weak self] in 189 189 self?.updateIcon() 190 190 self?.popoverVC?.syncFromController() 191 191 self?.updateWaveformStripSuppression() 192 192 } 193 - floatingPlayPalette.isPianoFocusActive = { [weak self] in 193 + pianoWaveformOverlay.isPianoFocusActive = { [weak self] in 194 194 self?.localCapture.isArmed ?? false 195 195 } 196 - floatingPlayPalette.onFocusRelease = { [weak self] in 197 - self?.finishFloatingPaletteKeyboardFocus() 196 + pianoWaveformOverlay.onFocusRelease = { [weak self] in 197 + self?.finishPianoWaveformKeyboardFocus() 198 198 } 199 - floatingPlayPalette.onToggleKeymap = { [weak self] in 199 + pianoWaveformOverlay.onToggleKeymap = { [weak self] in 200 200 self?.toggleKeyboardLayoutShortcut() 201 201 } 202 202 ··· 229 229 230 230 // Pre-build the waveform strip panel so the first note press 231 231 // doesn't stall on panel + Metal pipeline construction. 232 - waveformStrip.reposition(statusItemButton: statusItem.button) 233 - waveformStrip.onStepBackward = { [weak self] in 232 + pianoWaveformStrip.reposition(statusItemButton: statusItem.button) 233 + pianoWaveformStrip.onStepBackward = { [weak self] in 234 234 self?.menuBand.stepMelodicProgram(delta: -1) 235 235 } 236 - waveformStrip.onStepForward = { [weak self] in 236 + pianoWaveformStrip.onStepForward = { [weak self] in 237 237 self?.menuBand.stepMelodicProgram(delta: +1) 238 238 } 239 - waveformStrip.onStepUp = { [weak self] in 239 + pianoWaveformStrip.onStepUp = { [weak self] in 240 240 self?.menuBand.stepMelodicProgram(delta: -InstrumentListView.cols) 241 241 } 242 - waveformStrip.onStepDown = { [weak self] in 242 + pianoWaveformStrip.onStepDown = { [weak self] in 243 243 self?.menuBand.stepMelodicProgram(delta: +InstrumentListView.cols) 244 244 } 245 - waveformStrip.warmUp() 245 + pianoWaveformStrip.warmUp() 246 246 247 247 registerTypeModeHotkey() 248 248 _ = registerFocusCaptureHotkey(MenuBandShortcutPreferences.focusShortcut) 249 - _ = registerPlayPaletteHotkey(MenuBandShortcutPreferences.playPaletteShortcut) 249 + _ = registerPianoWaveformHotkey(MenuBandShortcutPreferences.playPaletteShortcut) 250 250 registerLayoutToggleHotkey() 251 251 252 252 // Dev affordance: post the ··· 280 280 self.toggleKeyboardLayoutShortcut() 281 281 return true 282 282 } 283 - if self.popover.isShown == false && self.floatingPlayPalette.isShown == false { 283 + if self.popover.isShown == false && self.pianoWaveformOverlay.isShown == false { 284 284 switch keyCode { 285 285 case 123: // kVK_LeftArrow 286 286 if isDown { 287 - self.waveformStrip.registerArrowInput() 287 + self.pianoWaveformStrip.registerArrowInput() 288 288 if !isRepeat { self.menuBand.stepMelodicProgram(delta: -1) } 289 289 } 290 290 return true 291 291 case 124: // kVK_RightArrow 292 292 if isDown { 293 - self.waveformStrip.registerArrowInput() 293 + self.pianoWaveformStrip.registerArrowInput() 294 294 if !isRepeat { self.menuBand.stepMelodicProgram(delta: +1) } 295 295 } 296 296 return true 297 297 case 125: // kVK_DownArrow 298 298 if isDown { 299 - self.waveformStrip.registerArrowInput() 299 + self.pianoWaveformStrip.registerArrowInput() 300 300 if !isRepeat { self.menuBand.stepMelodicProgram(delta: +InstrumentListView.cols) } 301 301 } 302 302 return true 303 303 case 126: // kVK_UpArrow 304 304 if isDown { 305 - self.waveformStrip.registerArrowInput() 305 + self.pianoWaveformStrip.registerArrowInput() 306 306 if !isRepeat { self.menuBand.stepMelodicProgram(delta: -InstrumentListView.cols) } 307 307 } 308 308 return true ··· 315 315 ) 316 316 if consumed && isDown { 317 317 if !self.menuBand.litNotes.isEmpty { 318 - self.waveformStrip.showIfNeeded() 318 + self.pianoWaveformStrip.showIfNeeded() 319 319 } 320 320 // Use the most-recent lit display note as the wave pivot 321 321 // so the ripple emanates from whichever key the user just ··· 387 387 self?.setShortcutRecording(isRecording) 388 388 } 389 389 vc.onPlayPaletteToggle = { [weak self] in 390 - self?.togglePlayPaletteFromCommand() 390 + self?.togglePianoWaveformFromCommand() 391 391 } 392 392 vc.onPlayPaletteShortcutChange = { [weak self] shortcut in 393 393 self?.applyPlayPaletteShortcut(shortcut) ?? false ··· 396 396 self?.setShortcutRecording(isRecording) 397 397 } 398 398 vc.isPlayPaletteShown = { [weak self] in 399 - self?.floatingPlayPalette.isShown ?? false 399 + self?.pianoWaveformOverlay.isShown ?? false 400 400 } 401 401 popoverVC = vc 402 402 popover.contentViewController = vc ··· 449 449 } 450 450 451 451 @discardableResult 452 - private func registerPlayPaletteHotkey(_ shortcut: MenuBandShortcut) -> Bool { 452 + private func registerPianoWaveformHotkey(_ shortcut: MenuBandShortcut) -> Bool { 453 453 let hotkey = GlobalHotkey( 454 454 signature: OSType(0x4D425050), // 'MBPP' 455 455 id: 1 456 456 ) { [weak self] in 457 - self?.togglePlayPaletteFromShortcut() 457 + self?.togglePianoWaveformFromShortcut() 458 458 } 459 459 guard hotkey.register(keyCode: shortcut.keyCode, modifiers: shortcut.modifiers) else { 460 460 return false 461 461 } 462 - playPaletteHotkey = hotkey 462 + pianoWaveformHotkey = hotkey 463 463 return true 464 464 } 465 465 ··· 503 503 return false 504 504 } 505 505 let previous = MenuBandShortcutPreferences.playPaletteShortcut 506 - playPaletteHotkey?.unregister() 507 - playPaletteHotkey = nil 508 - guard registerPlayPaletteHotkey(shortcut) else { 509 - _ = registerPlayPaletteHotkey(previous) 506 + pianoWaveformHotkey?.unregister() 507 + pianoWaveformHotkey = nil 508 + guard registerPianoWaveformHotkey(shortcut) else { 509 + _ = registerPianoWaveformHotkey(previous) 510 510 return false 511 511 } 512 512 MenuBandShortcutPreferences.playPaletteShortcut = shortcut ··· 519 519 typeModeHotkey = nil 520 520 focusCaptureHotkey?.unregister() 521 521 focusCaptureHotkey = nil 522 - playPaletteHotkey?.unregister() 523 - playPaletteHotkey = nil 522 + pianoWaveformHotkey?.unregister() 523 + pianoWaveformHotkey = nil 524 524 layoutToggleHotkey?.unregister() 525 525 layoutToggleHotkey = nil 526 526 } else { ··· 528 528 if focusCaptureHotkey == nil { 529 529 _ = registerFocusCaptureHotkey(MenuBandShortcutPreferences.focusShortcut) 530 530 } 531 - if playPaletteHotkey == nil { 532 - _ = registerPlayPaletteHotkey(MenuBandShortcutPreferences.playPaletteShortcut) 531 + if pianoWaveformHotkey == nil { 532 + _ = registerPianoWaveformHotkey(MenuBandShortcutPreferences.playPaletteShortcut) 533 533 } 534 534 if layoutToggleHotkey == nil { registerLayoutToggleHotkey() } 535 535 } 536 536 } 537 537 538 - private func togglePlayPaletteFromShortcut() { 539 - if floatingPlayPalette.isShown { 540 - floatingPlayPalette.toggleFromShortcut() 538 + private func togglePianoWaveformFromShortcut() { 539 + if pianoWaveformOverlay.isShown { 540 + pianoWaveformOverlay.toggleFromShortcut() 541 541 updateWaveformStripSuppression() 542 542 return 543 543 } 544 - beginFloatingPlayPalette() 545 - floatingPlayPalette.toggleFromShortcut() 544 + beginPianoWaveformPresentation() 545 + pianoWaveformOverlay.toggleFromShortcut() 546 546 updateWaveformStripSuppression() 547 547 } 548 548 549 - private func togglePlayPaletteFromCommand() { 549 + private func togglePianoWaveformFromCommand() { 550 550 let appToRestore = appBeforePopover 551 - beginFloatingPlayPalette() 551 + beginPianoWaveformPresentation() 552 552 appBeforePopover = nil 553 - floatingPlayPalette.showFromCommand(restoringTo: appToRestore) 553 + pianoWaveformOverlay.showFromCommand(restoringTo: appToRestore) 554 554 updateWaveformStripSuppression() 555 555 } 556 556 557 - private func beginFloatingPlayPalette() { 557 + private func beginPianoWaveformPresentation() { 558 558 closePopover() 559 559 if localCapture.isArmed { 560 560 localCapture.disarm(reason: .resignedKey) ··· 566 566 } 567 567 568 568 private func toggleFocusCaptureFromShortcut() { 569 - if floatingPlayPalette.isKeyboardFocused { 570 - finishFloatingPaletteKeyboardFocus() 569 + if pianoWaveformOverlay.isKeyboardFocused { 570 + finishPianoWaveformKeyboardFocus() 571 571 return 572 572 } 573 573 if localCapture.isArmed, focusCaptureArmedByShortcut { ··· 591 591 focusCaptureArmedByShortcut = true 592 592 localCapture.arm() 593 593 updateIcon() 594 - floatingPlayPalette.refresh() 594 + pianoWaveformOverlay.refresh() 595 595 } 596 596 597 597 private func finishLocalCapture(reason: LocalKeyCapture.EndReason) { ··· 602 602 ghostRefreshTimer?.invalidate() 603 603 ghostRefreshTimer = nil 604 604 updateIcon() 605 - floatingPlayPalette.refresh() 605 + pianoWaveformOverlay.refresh() 606 606 if shouldRestoreFocus { 607 607 restorePreviousAppFocus() 608 608 } ··· 616 616 app.activate(options: [.activateIgnoringOtherApps]) 617 617 } 618 618 619 - private func finishFloatingPaletteKeyboardFocus() { 619 + private func finishPianoWaveformKeyboardFocus() { 620 620 menuBand.releaseAllHeldNotes() 621 - floatingPlayPalette.clearInteraction() 622 - floatingPlayPalette.releaseKeyboardFocus() 621 + pianoWaveformOverlay.clearInteraction() 622 + pianoWaveformOverlay.releaseKeyboardFocus() 623 623 updateIcon() 624 - floatingPlayPalette.refresh() 624 + pianoWaveformOverlay.refresh() 625 625 } 626 626 627 627 private func toggleKeyboardLayoutShortcut() { ··· 824 824 } 825 825 826 826 func applicationWillTerminate(_ notification: Notification) { 827 - floatingPlayPalette.dismiss(reason: .programmatic) 827 + pianoWaveformOverlay.dismiss(reason: .programmatic) 828 828 menuBand.shutdown() 829 829 } 830 830 ··· 1199 1199 // palette window). Same target the popover's WaveformView 1200 1200 // routes to, so the user gets one entry point regardless of 1201 1201 // where they tap. 1202 - floatingPlayPalette.show() 1202 + pianoWaveformOverlay.show() 1203 1203 return 1204 1204 case .note(let n): 1205 1205 startDisplayNote = n ··· 1220 1220 displayNote: startDisplayNote, 1221 1221 linger: initialShift 1222 1222 ) 1223 - waveformStrip.showIfNeeded() 1223 + pianoWaveformStrip.showIfNeeded() 1224 1224 // Arm sandbox-friendly local capture on a real piano click. We 1225 1225 // skip arming when global TYPE mode is already on — the global 1226 1226 // tap is already handling keys, doubling up would re-trigger ··· 1229 1229 // when you're just tapping the piano with the mouse. 1230 1230 if !menuBand.typeMode { 1231 1231 localCapture.arm() 1232 - floatingPlayPalette.refresh() 1232 + pianoWaveformOverlay.refresh() 1233 1233 } 1234 1234 var currentDisplay: UInt8? = startDisplayNote 1235 1235 var currentPlayed: UInt8? = startNote ··· 1262 1262 displayNote: nxtDisplay, 1263 1263 linger: shiftNow 1264 1264 ) 1265 - waveformStrip.showIfNeeded() 1265 + pianoWaveformStrip.showIfNeeded() 1266 1266 currentPlayed = nxtPlayed 1267 1267 } else { 1268 1268 currentPlayed = nil ··· 1372 1372 // MARK: - Menubar waveform strip 1373 1373 1374 1374 private func updateWaveformStrip() { 1375 - guard waveformStrip.isCollapsedState else { return } 1375 + guard pianoWaveformStrip.isCollapsedState else { return } 1376 1376 if !menuBand.litNotes.isEmpty { 1377 - waveformStrip.showIfNeeded() 1377 + pianoWaveformStrip.showIfNeeded() 1378 1378 } else { 1379 - waveformStrip.scheduleHide() 1379 + pianoWaveformStrip.scheduleHide() 1380 1380 } 1381 1381 } 1382 1382 1383 1383 private func updateWaveformStripSuppression() { 1384 - waveformStrip.suppressed = waveformStrip.isDocked && (popover.isShown || floatingPlayPalette.isShown) 1384 + pianoWaveformStrip.isCollapsedPresentationSuppressed = 1385 + pianoWaveformStrip.isDocked && (popover.isShown || pianoWaveformOverlay.isShown) 1385 1386 } 1386 1387 }
+79 -79
slab/menuband/Sources/MenuBand/FloatingPlayPalette.swift
··· 1 1 import AppKit 2 2 3 - private enum FloatingPaletteVisualStyleOverride: String { 3 + private enum PianoWaveformVisualStyleOverride: String { 4 4 case automatic 5 5 case liquid 6 6 case legacy ··· 18 18 } 19 19 20 20 @available(macOS 26.0, *) 21 - private final class FloatingPaletteGlassEffectView: NSGlassEffectView { 21 + private final class PianoWaveformOverlayGlassEffectView: NSGlassEffectView { 22 22 override func acceptsFirstMouse(for event: NSEvent?) -> Bool { true } 23 23 } 24 24 25 - final class FloatingPlayPaletteViewController: NSViewController { 26 - enum DisplayMode { 25 + final class PianoWaveformViewController: NSViewController { 26 + enum PresentationMode { 27 27 case expanded 28 28 case collapsed 29 29 } ··· 31 31 private static let panelCornerRadius: CGFloat = 18 32 32 33 33 private let containerView = NSView() 34 - private let paletteView: FloatingPlayPaletteView 35 - private let stripView: UnifiedWaveformStripView 34 + private let expandedView: ExpandedPianoWaveformView 35 + private let collapsedView: CollapsedPianoWaveformView 36 36 private let closeButton = NSButton() 37 37 private let dockButton = NSButton() 38 38 private let expandCollapseButton = NSButton() 39 - private var displayedView: NSView? 40 - private var displayMode: DisplayMode = .expanded 39 + private var activeContentView: NSView? 40 + private var presentationMode: PresentationMode = .expanded 41 41 private var isPresented = false 42 42 private var trackingArea: NSTrackingArea? 43 43 private var isMouseInsideView = false ··· 55 55 var onTogglePresentationMode: (() -> Void)? 56 56 57 57 var onStepBackward: (() -> Void)? { 58 - get { stripView.onStepBackward } 59 - set { stripView.onStepBackward = newValue } 58 + get { collapsedView.onStepBackward } 59 + set { collapsedView.onStepBackward = newValue } 60 60 } 61 61 62 62 var onStepForward: (() -> Void)? { 63 - get { stripView.onStepForward } 64 - set { stripView.onStepForward = newValue } 63 + get { collapsedView.onStepForward } 64 + set { collapsedView.onStepForward = newValue } 65 65 } 66 66 67 67 var onStepUp: (() -> Void)? { 68 - get { stripView.onStepUp } 69 - set { stripView.onStepUp = newValue } 68 + get { collapsedView.onStepUp } 69 + set { collapsedView.onStepUp = newValue } 70 70 } 71 71 72 72 var onStepDown: (() -> Void)? { 73 - get { stripView.onStepDown } 74 - set { stripView.onStepDown = newValue } 73 + get { collapsedView.onStepDown } 74 + set { collapsedView.onStepDown = newValue } 75 75 } 76 76 77 77 var isPianoFocusActive: (() -> Bool)? { 78 - get { paletteView.isPianoFocusActive } 79 - set { paletteView.isPianoFocusActive = newValue } 78 + get { expandedView.isPianoFocusActive } 79 + set { expandedView.isPianoFocusActive = newValue } 80 80 } 81 81 82 82 init(menuBand: MenuBandController) { 83 - self.paletteView = FloatingPlayPaletteView(menuBand: menuBand) 84 - self.stripView = UnifiedWaveformStripView(menuBand: menuBand) 83 + self.expandedView = ExpandedPianoWaveformView(menuBand: menuBand) 84 + self.collapsedView = CollapsedPianoWaveformView(menuBand: menuBand) 85 85 super.init(nibName: nil, bundle: nil) 86 - preferredContentSize = preferredSize(for: displayMode) 86 + preferredContentSize = preferredSize(for: presentationMode) 87 87 } 88 88 89 89 @available(*, unavailable) ··· 119 119 NSLayoutConstraint.activate([ 120 120 closeButton.topAnchor.constraint( 121 121 equalTo: containerView.topAnchor, 122 - constant: Self.panelCornerRadius - closeButtonSize / 2 + closeButtonCornerInset 122 + constant: PianoWaveformViewController.panelCornerRadius - closeButtonSize / 2 + closeButtonCornerInset 123 123 ), 124 124 closeButton.leadingAnchor.constraint( 125 125 equalTo: containerView.leadingAnchor, 126 - constant: Self.panelCornerRadius - closeButtonSize / 2 + closeButtonCornerInset 126 + constant: PianoWaveformViewController.panelCornerRadius - closeButtonSize / 2 + closeButtonCornerInset 127 127 ), 128 128 closeButton.widthAnchor.constraint(equalToConstant: closeButtonSize), 129 129 closeButton.heightAnchor.constraint(equalToConstant: closeButtonSize), ··· 131 131 expandCollapseButton.topAnchor.constraint(equalTo: closeButton.topAnchor), 132 132 expandCollapseButton.trailingAnchor.constraint( 133 133 equalTo: containerView.trailingAnchor, 134 - constant: -(Self.panelCornerRadius - closeButtonSize / 2 + closeButtonCornerInset) 134 + constant: -(PianoWaveformViewController.panelCornerRadius - closeButtonSize / 2 + closeButtonCornerInset) 135 135 ), 136 136 expandCollapseButton.widthAnchor.constraint(equalToConstant: closeButtonSize), 137 137 expandCollapseButton.heightAnchor.constraint(equalToConstant: closeButtonSize), ··· 148 148 } 149 149 150 150 func refresh() { 151 - paletteView.refresh() 152 - stripView.refresh() 153 - preferredContentSize = preferredSize(for: displayMode) 151 + expandedView.refresh() 152 + collapsedView.refresh() 153 + preferredContentSize = preferredSize(for: presentationMode) 154 154 } 155 155 156 156 func clearInteraction() { 157 - paletteView.clearInteraction() 157 + expandedView.clearInteraction() 158 158 } 159 159 160 160 func setPresented(_ isPresented: Bool) { ··· 162 162 updatePresentationState() 163 163 } 164 164 165 - func setDisplayMode(_ displayMode: DisplayMode) { 166 - guard self.displayMode != displayMode else { 167 - preferredContentSize = preferredSize(for: displayMode) 165 + func setPresentationMode(_ presentationMode: PresentationMode) { 166 + guard self.presentationMode != presentationMode else { 167 + preferredContentSize = preferredSize(for: presentationMode) 168 168 updatePresentationState() 169 169 return 170 170 } 171 - self.displayMode = displayMode 171 + self.presentationMode = presentationMode 172 172 if isViewLoaded { 173 173 installDisplayedView() 174 174 } 175 - preferredContentSize = preferredSize(for: displayMode) 175 + preferredContentSize = preferredSize(for: presentationMode) 176 176 updatePresentationState() 177 177 } 178 178 179 179 private func installDisplayedView() { 180 180 let nextView: NSView 181 - switch displayMode { 181 + switch presentationMode { 182 182 case .expanded: 183 - nextView = paletteView 183 + nextView = expandedView 184 184 case .collapsed: 185 - nextView = stripView 185 + nextView = collapsedView 186 186 } 187 187 188 - guard displayedView !== nextView else { return } 189 - displayedView?.removeFromSuperview() 188 + guard activeContentView !== nextView else { return } 189 + activeContentView?.removeFromSuperview() 190 190 nextView.translatesAutoresizingMaskIntoConstraints = false 191 191 containerView.addSubview(nextView, positioned: .below, relativeTo: nil) 192 192 NSLayoutConstraint.activate([ ··· 195 195 nextView.topAnchor.constraint(equalTo: containerView.topAnchor), 196 196 nextView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), 197 197 ]) 198 - displayedView = nextView 198 + activeContentView = nextView 199 199 } 200 200 201 - private func preferredSize(for displayMode: DisplayMode) -> NSSize { 202 - switch displayMode { 201 + private func preferredSize(for presentationMode: PresentationMode) -> NSSize { 202 + switch presentationMode { 203 203 case .expanded: 204 - return paletteView.fittingSize 204 + return expandedView.fittingSize 205 205 case .collapsed: 206 - return stripView.fittingSize 206 + return collapsedView.fittingSize 207 207 } 208 208 } 209 209 210 210 private func updatePresentationState() { 211 - paletteView.setPresented(isPresented && displayMode == .expanded) 212 - stripView.setLive(isPresented && displayMode == .collapsed) 211 + expandedView.setPresented(isPresented && presentationMode == .expanded) 212 + collapsedView.setLive(isPresented && presentationMode == .collapsed) 213 213 let controlsHidden = false 214 214 [closeButton, dockButton, expandCollapseButton, closeButtonGlassView, dockButtonGlassView, expandCollapseButtonGlassView] 215 215 .compactMap { $0 } ··· 246 246 } 247 247 248 248 private func installOverlayGlassBackgrounds() { 249 - guard FloatingPlayPaletteView.shouldUseLiquidGlass, #available(macOS 26.0, *) else { return } 249 + guard ExpandedPianoWaveformView.shouldUseLiquidGlass, #available(macOS 26.0, *) else { return } 250 250 self.closeButtonGlassView = installGlassBackground(for: closeButton) 251 251 self.dockButtonGlassView = installGlassBackground(for: dockButton) 252 252 self.expandCollapseButtonGlassView = installGlassBackground(for: expandCollapseButton) ··· 254 254 255 255 @available(macOS 26.0, *) 256 256 private func installGlassBackground(for target: NSView) -> NSView { 257 - let glassView = FloatingPaletteGlassEffectView() 257 + let glassView = PianoWaveformOverlayGlassEffectView() 258 258 glassView.translatesAutoresizingMaskIntoConstraints = false 259 259 glassView.cornerRadius = closeButtonSize / 2 260 260 containerView.addSubview(glassView, positioned: .below, relativeTo: target) ··· 318 318 319 319 private func applyOverlayButtonAppearance() { 320 320 let effectiveView: NSView 321 - switch displayMode { 321 + switch presentationMode { 322 322 case .expanded: 323 - effectiveView = paletteView 323 + effectiveView = expandedView 324 324 case .collapsed: 325 - effectiveView = stripView 325 + effectiveView = collapsedView 326 326 } 327 327 let isDark = effectiveView.effectiveAppearance.bestMatch(from: [.aqua, .darkAqua]) == .darkAqua 328 - let tintColor = paletteView.paletteTintColor 329 - if FloatingPlayPaletteView.shouldUseLiquidGlass, #available(macOS 26.0, *) { 328 + let tintColor = expandedView.paletteTintColor 329 + if ExpandedPianoWaveformView.shouldUseLiquidGlass, #available(macOS 26.0, *) { 330 330 for view in [closeButtonGlassView, dockButtonGlassView, expandCollapseButtonGlassView] { 331 331 (view as? NSGlassEffectView)?.style = .clear 332 332 (view as? NSGlassEffectView)?.tintColor = tintColor.withAlphaComponent(0.34) ··· 346 346 } 347 347 348 348 private func updateExpandCollapseButtonAppearance() { 349 - let symbolName = displayMode == .expanded ? "square.resize.down" : "square.resize.up" 350 - let toolTip = displayMode == .expanded ? "Collapse" : "Expand floating piano" 349 + let symbolName = presentationMode == .expanded ? "square.resize.down" : "square.resize.up" 350 + let toolTip = presentationMode == .expanded ? "Collapse" : "Expand floating piano" 351 351 let config = NSImage.SymbolConfiguration(pointSize: 12, weight: .semibold) 352 352 expandCollapseButton.image = NSImage(systemSymbolName: symbolName, accessibilityDescription: toolTip)? 353 353 .withSymbolConfiguration(config) ··· 367 367 } 368 368 } 369 369 370 - private final class FloatingPlayPaletteView: NSView { 370 + private final class ExpandedPianoWaveformView: NSView { 371 371 private static let defaultsDomain = "computer.aestheticcomputer.menuband" 372 372 private static let styleOverrideDefaultsKey = "MenuBandFloatingPlayPaletteStyle" 373 373 private static let styleOverrideEnvironmentKey = "MENUBAND_FLOATING_PLAY_PALETTE_STYLE" 374 374 375 - private static var visualStyleOverride: FloatingPaletteVisualStyleOverride { 375 + private static var visualStyleOverride: PianoWaveformVisualStyleOverride { 376 376 let environmentValue = ProcessInfo.processInfo.environment[styleOverrideEnvironmentKey] 377 377 if environmentValue != nil { 378 - return FloatingPaletteVisualStyleOverride(rawValue: environmentValue) 378 + return PianoWaveformVisualStyleOverride(rawValue: environmentValue) 379 379 } 380 380 let defaultsValue = UserDefaults(suiteName: defaultsDomain)?.string(forKey: styleOverrideDefaultsKey) 381 381 ?? UserDefaults.standard.string(forKey: styleOverrideDefaultsKey) 382 - return FloatingPaletteVisualStyleOverride(rawValue: defaultsValue) 382 + return PianoWaveformVisualStyleOverride(rawValue: defaultsValue) 383 383 } 384 384 385 385 static var shouldUseLiquidGlass: Bool { ··· 408 408 private var lastCompleteChordNames: Set<String> = [] 409 409 private let instrumentReadout = NSTextField(labelWithString: "") 410 410 private let instrumentTitleRow: NSStackView 411 - private let pianoView: FloatingPianoView 411 + private let pianoView: PianoKeyboardView 412 412 private let shortcutHintRow = NSStackView() 413 413 private let focusHintLabel = NSTextField(labelWithString: "") 414 414 private let layoutHintLabel = NSTextField(labelWithString: "") ··· 446 446 titleLeftSpacer.setContentHuggingPriority(.defaultLow, for: .horizontal) 447 447 titleRightSpacer.setContentHuggingPriority(.defaultLow, for: .horizontal) 448 448 self.instrumentTitleRow = NSStackView(views: [titleLeftSpacer, instrumentReadout, titleRightSpacer]) 449 - self.pianoView = FloatingPianoView(menuBand: menuBand, pianoScale: pianoScale) 449 + self.pianoView = PianoKeyboardView(menuBand: menuBand, pianoScale: pianoScale) 450 450 super.init(frame: NSRect(origin: .zero, size: .zero)) 451 451 wantsLayer = true 452 452 ··· 639 639 private func installLiquidGlassBackgrounds() { 640 640 guard Self.shouldUseLiquidGlass, #available(macOS 26.0, *) else { return } 641 641 642 - let paletteGlassView = FloatingPaletteGlassEffectView() 642 + let paletteGlassView = PianoWaveformOverlayGlassEffectView() 643 643 paletteGlassView.translatesAutoresizingMaskIntoConstraints = false 644 644 paletteGlassView.cornerRadius = Self.panelCornerRadius 645 645 addSubview(paletteGlassView, positioned: .below, relativeTo: waveformSection) ··· 677 677 private func installGlassBackground(matchedTo target: NSView, 678 678 below anchor: NSView, 679 679 cornerRadius: CGFloat) -> NSView { 680 - let glassView = FloatingPaletteGlassEffectView() 680 + let glassView = PianoWaveformOverlayGlassEffectView() 681 681 glassView.translatesAutoresizingMaskIntoConstraints = false 682 682 glassView.cornerRadius = cornerRadius 683 683 addSubview(glassView, positioned: .below, relativeTo: anchor) ··· 818 818 } 819 819 820 820 private func keyboardSize() -> NSSize { 821 - withFloatingPaletteKeyboard(menuBand: menuBand) { 821 + withPianoWaveformKeyboard(menuBand: menuBand) { 822 822 let piano = KeyboardIconRenderer.pianoImageSize(layout: .tightActiveRange) 823 823 return NSSize(width: piano.width * pianoScale, height: piano.height * pianoScale) 824 824 } ··· 959 959 960 960 } 961 961 962 - private final class FloatingPianoView: NSView { 962 + private final class PianoKeyboardView: NSView { 963 963 private static let rendererLayout: KeyboardIconRenderer.Layout = .tightActiveRange 964 964 965 965 private weak var menuBand: MenuBandController? ··· 999 999 } 1000 1000 1001 1001 private func preferredSize() -> NSSize { 1002 - withFloatingPaletteKeyboard(menuBand: menuBand) { 1002 + withPianoWaveformKeyboard(menuBand: menuBand) { 1003 1003 let piano = KeyboardIconRenderer.pianoImageSize(layout: Self.rendererLayout) 1004 1004 return NSSize( 1005 1005 width: piano.width * pianoScale, ··· 1027 1027 super.draw(dirtyRect) 1028 1028 guard let menuBand = menuBand else { return } 1029 1029 1030 - withFloatingPaletteKeyboard(menuBand: menuBand) { 1030 + withPianoWaveformKeyboard(menuBand: menuBand) { 1031 1031 KeyboardIconRenderer.activeKeymap = menuBand.keymap 1032 1032 let image = KeyboardIconRenderer.image( 1033 1033 litNotes: menuBand.litNotes, ··· 1056 1056 window?.makeKey() 1057 1057 guard let menuBand = menuBand, 1058 1058 let point = rendererPoint(from: event), 1059 - let displayNote = withFloatingPaletteKeyboard( 1059 + let displayNote = withPianoWaveformKeyboard( 1060 1060 menuBand: menuBand, 1061 1061 { KeyboardIconRenderer.noteAt(point, layout: Self.rendererLayout) } 1062 1062 ), 1063 1063 let playedNote = playedNote(for: displayNote, menuBand: menuBand) 1064 1064 else { return } 1065 - let expression = withFloatingPaletteKeyboard(menuBand: menuBand) { 1065 + let expression = withPianoWaveformKeyboard(menuBand: menuBand) { 1066 1066 NoteExpression.values(for: displayNote, at: point, layout: Self.rendererLayout) 1067 1067 } 1068 1068 currentDisplayNote = displayNote ··· 1080 1080 override func mouseDragged(with event: NSEvent) { 1081 1081 guard let menuBand = menuBand, 1082 1082 let point = rendererPoint(from: event) else { return } 1083 - let hovered = withFloatingPaletteKeyboard( 1083 + let hovered = withPianoWaveformKeyboard( 1084 1084 menuBand: menuBand, 1085 1085 { KeyboardIconRenderer.noteAt(point, layout: Self.rendererLayout) } 1086 1086 ) ··· 1092 1092 } 1093 1093 if let nextDisplay = hovered, 1094 1094 let nextPlayed = playedNote(for: nextDisplay, menuBand: menuBand) { 1095 - let expression = withFloatingPaletteKeyboard(menuBand: menuBand) { 1095 + let expression = withPianoWaveformKeyboard(menuBand: menuBand) { 1096 1096 NoteExpression.values(for: nextDisplay, at: point, layout: Self.rendererLayout) 1097 1097 } 1098 1098 menuBand.startTapNote( ··· 1108 1108 currentDisplayNote = hovered 1109 1109 } else if let current = currentDisplayNote, 1110 1110 currentPlayedNote != nil { 1111 - let expression = withFloatingPaletteKeyboard(menuBand: menuBand) { 1111 + let expression = withPianoWaveformKeyboard(menuBand: menuBand) { 1112 1112 NoteExpression.values(for: current, at: point, layout: Self.rendererLayout) 1113 1113 } 1114 1114 if let playedNote = currentPlayedNote { ··· 1142 1142 } 1143 1143 return 1144 1144 } 1145 - let next = withFloatingPaletteKeyboard( 1145 + let next = withPianoWaveformKeyboard( 1146 1146 menuBand: menuBand, 1147 1147 { KeyboardIconRenderer.noteAt(point, layout: Self.rendererLayout) } 1148 1148 ) ··· 1159 1159 x: (local.x - target.minX) / pianoScale, 1160 1160 y: (local.y - target.minY) / pianoScale 1161 1161 ) 1162 - let piano = withFloatingPaletteKeyboard(menuBand: menuBand) { 1162 + let piano = withPianoWaveformKeyboard(menuBand: menuBand) { 1163 1163 KeyboardIconRenderer.pianoImageSize(layout: Self.rendererLayout) 1164 1164 } 1165 1165 guard point.x >= -KeyboardIconRenderer.whiteW, ··· 1170 1170 } 1171 1171 1172 1172 private func pianoTargetRect() -> NSRect { 1173 - let piano = withFloatingPaletteKeyboard(menuBand: menuBand) { 1173 + let piano = withPianoWaveformKeyboard(menuBand: menuBand) { 1174 1174 KeyboardIconRenderer.pianoImageSize(layout: Self.rendererLayout) 1175 1175 } 1176 1176 let size = NSSize(width: piano.width * pianoScale, height: piano.height * pianoScale) ··· 1189 1189 } 1190 1190 } 1191 1191 1192 - private final class FloatingPaletteDragHandleView: NSView { 1192 + private final class PianoWaveformDragHandleView: NSView { 1193 1193 private var dragStartMouse: NSPoint? 1194 1194 private var dragStartWindowOrigin: NSPoint? 1195 1195 ··· 1256 1256 /// Tall traditional-piano aspect for the floating overlay. Multiplies 1257 1257 /// white-key height (and black-key height proportionally) so the keys 1258 1258 /// read like a real keyboard instead of menubar squares. 1259 - private let floatingPaletteKeyHeightScale: CGFloat = 2.4 1259 + private let pianoWaveformKeyHeightScale: CGFloat = 2.4 1260 1260 1261 - private func withFloatingPaletteKeyboard<T>(menuBand: MenuBandController?, _ body: () -> T) -> T { 1261 + private func withPianoWaveformKeyboard<T>(menuBand: MenuBandController?, _ body: () -> T) -> T { 1262 1262 let oldLayout = KeyboardIconRenderer.displayLayout 1263 1263 let oldKeymap = KeyboardIconRenderer.activeKeymap 1264 1264 let oldScale = KeyboardIconRenderer.keyHeightScale 1265 1265 KeyboardIconRenderer.displayLayout = .full 1266 - KeyboardIconRenderer.keyHeightScale = floatingPaletteKeyHeightScale 1266 + KeyboardIconRenderer.keyHeightScale = pianoWaveformKeyHeightScale 1267 1267 if let menuBand = menuBand { 1268 1268 KeyboardIconRenderer.activeKeymap = menuBand.keymap 1269 1269 } ··· 1275 1275 return body() 1276 1276 } 1277 1277 1278 - private final class FloatingPlayPalettePanel: NSPanel { 1278 + private final class PianoWaveformPanel: NSPanel { 1279 1279 override var canBecomeKey: Bool { true } 1280 1280 override var canBecomeMain: Bool { false } 1281 1281 }
+94 -94
slab/menuband/Sources/MenuBand/UnifiedPianoWaveformPalette.swift
··· 1 1 import AppKit 2 2 3 - final class UnifiedPianoWaveformPalette: NSObject, NSWindowDelegate { 3 + final class PianoWaveformPalette: NSObject, NSWindowDelegate { 4 4 enum State { 5 5 case collapsed 6 6 case expanded ··· 22 22 } 23 23 24 24 private let menuBand: MenuBandController 25 - private let paletteController: FloatingPlayPaletteViewController 26 - private var panel: UnifiedPianoWaveformPalettePanel? 25 + private let pianoWaveformViewController: PianoWaveformViewController 26 + private var panel: PianoWaveformPanel? 27 27 private weak var statusItemButton: NSStatusBarButton? 28 - private var state: State = .collapsed 29 - private var preferredState: State 28 + private var presentationState: State = .collapsed 29 + private var preferredPresentationState: State 30 30 private var keyMonitor: Any? 31 31 private var appBeforeOpen: NSRunningApplication? 32 32 private var dismissHandler: (() -> Void)? ··· 55 55 var onToggleKeymap: (() -> Void)? 56 56 57 57 var isPianoFocusActive: (() -> Bool)? { 58 - get { paletteController.isPianoFocusActive } 59 - set { paletteController.isPianoFocusActive = newValue } 58 + get { pianoWaveformViewController.isPianoFocusActive } 59 + set { pianoWaveformViewController.isPianoFocusActive = newValue } 60 60 } 61 61 62 62 var isShown: Bool { 63 - state == .expanded && panel?.isVisible == true 63 + presentationState == .expanded && panel?.isVisible == true 64 64 } 65 65 66 66 var isKeyboardFocused: Bool { 67 - state == .expanded && panel?.isKeyWindow == true 67 + presentationState == .expanded && panel?.isKeyWindow == true 68 68 } 69 69 70 - var isCollapsedState: Bool { state == .collapsed } 70 + var isCollapsedState: Bool { presentationState == .collapsed } 71 71 72 72 var isFeatureEnabled: Bool { isEnabled } 73 73 74 74 var onStepBackward: (() -> Void)? { 75 - get { paletteController.onStepBackward } 76 - set { paletteController.onStepBackward = newValue } 75 + get { pianoWaveformViewController.onStepBackward } 76 + set { pianoWaveformViewController.onStepBackward = newValue } 77 77 } 78 78 79 79 var onStepForward: (() -> Void)? { 80 - get { paletteController.onStepForward } 81 - set { paletteController.onStepForward = newValue } 80 + get { pianoWaveformViewController.onStepForward } 81 + set { pianoWaveformViewController.onStepForward = newValue } 82 82 } 83 83 84 84 var onStepUp: (() -> Void)? { 85 - get { paletteController.onStepUp } 86 - set { paletteController.onStepUp = newValue } 85 + get { pianoWaveformViewController.onStepUp } 86 + set { pianoWaveformViewController.onStepUp = newValue } 87 87 } 88 88 89 89 var onStepDown: (() -> Void)? { 90 - get { paletteController.onStepDown } 91 - set { paletteController.onStepDown = newValue } 90 + get { pianoWaveformViewController.onStepDown } 91 + set { pianoWaveformViewController.onStepDown = newValue } 92 92 } 93 93 94 - var suppressed: Bool = false { 94 + var isCollapsedPresentationSuppressed: Bool = false { 95 95 didSet { 96 - guard suppressed != oldValue else { return } 97 - if suppressed && state == .collapsed { 96 + guard isCollapsedPresentationSuppressed != oldValue else { return } 97 + if isCollapsedPresentationSuppressed && presentationState == .collapsed { 98 98 dismissCollapsedPanel() 99 99 } 100 100 } ··· 104 104 105 105 init(menuBand: MenuBandController) { 106 106 self.menuBand = menuBand 107 - self.paletteController = FloatingPlayPaletteViewController(menuBand: menuBand) 108 - self.preferredState = Self.loadPreferredState() 107 + self.pianoWaveformViewController = PianoWaveformViewController(menuBand: menuBand) 108 + self.preferredPresentationState = Self.loadPreferredState() 109 109 self.isEnabled = Self.loadEnabledState() 110 110 self.savedExpandedOrigin = Self.loadOrigin( 111 111 xKey: Self.expandedOriginXKey, ··· 117 117 ) 118 118 super.init() 119 119 120 - paletteController.onCloseRequested = { [weak self] in 120 + pianoWaveformViewController.onCloseRequested = { [weak self] in 121 121 self?.disable(reason: .closeButton) 122 122 } 123 - paletteController.onDockRequested = { [weak self] in 123 + pianoWaveformViewController.onDockRequested = { [weak self] in 124 124 self?.dockOnMenu() 125 125 } 126 - paletteController.onTogglePresentationMode = { [weak self] in 126 + pianoWaveformViewController.onTogglePresentationMode = { [weak self] in 127 127 self?.togglePresentationMode() 128 128 } 129 129 } ··· 138 138 139 139 func showFromCommand(restoringTo previousApp: NSRunningApplication? = nil) { 140 140 setEnabled(true) 141 - preferredState = .expanded 141 + preferredPresentationState = .expanded 142 142 persistPreferredState() 143 143 transitionToExpanded() 144 144 showExpanded(restoringTo: previousApp) ··· 146 146 147 147 func show(restoringTo previousApp: NSRunningApplication? = nil) { 148 148 setEnabled(true) 149 - preferredState = .expanded 149 + preferredPresentationState = .expanded 150 150 persistPreferredState() 151 151 transitionToExpanded() 152 152 showExpanded(restoringTo: previousApp) 153 153 } 154 154 155 155 func dismiss(reason: DismissReason = .programmatic) { 156 - guard state == .expanded else { return } 156 + guard presentationState == .expanded else { return } 157 157 dismissExpanded(reason: reason) 158 158 } 159 159 160 160 func refresh() { 161 - switch state { 161 + switch presentationState { 162 162 case .expanded: 163 - paletteController.setDisplayMode(.expanded) 164 - paletteController.refresh() 163 + pianoWaveformViewController.setPresentationMode(.expanded) 164 + pianoWaveformViewController.refresh() 165 165 if let panel, panel.isVisible { 166 166 setPanelFrame(expandedFrame( 167 - size: paletteController.preferredContentSize, 167 + size: pianoWaveformViewController.preferredContentSize, 168 168 fallbackOrigin: panel.frame.origin 169 169 )) 170 170 } 171 171 case .collapsed: 172 - paletteController.setDisplayMode(.collapsed) 173 - paletteController.refresh() 172 + pianoWaveformViewController.setPresentationMode(.collapsed) 173 + pianoWaveformViewController.refresh() 174 174 if let panel, panel.isVisible { 175 - setPanelFrame(collapsedFrame(size: paletteController.preferredContentSize)) 175 + setPanelFrame(collapsedFrame(size: pianoWaveformViewController.preferredContentSize)) 176 176 } 177 177 } 178 178 } 179 179 180 180 func clearInteraction() { 181 - paletteController.clearInteraction() 181 + pianoWaveformViewController.clearInteraction() 182 182 } 183 183 184 184 func releaseKeyboardFocus() { 185 - guard state == .expanded else { return } 185 + guard presentationState == .expanded else { return } 186 186 restorePreviousAppFocus() 187 187 } 188 188 ··· 190 190 if panel == nil { 191 191 buildPanel() 192 192 } 193 - paletteController.setDisplayMode(.collapsed) 194 - paletteController.refresh() 193 + pianoWaveformViewController.setPresentationMode(.collapsed) 194 + pianoWaveformViewController.refresh() 195 195 } 196 196 197 197 func showIfNeeded() { 198 - guard state == .collapsed, !suppressed, isEnabled, preferredState == .collapsed else { return } 198 + guard presentationState == .collapsed, !isCollapsedPresentationSuppressed, isEnabled, preferredPresentationState == .collapsed else { return } 199 199 cancelPendingHide() 200 200 if panel == nil { 201 201 buildPanel() 202 202 } 203 - paletteController.setDisplayMode(.collapsed) 204 - paletteController.refresh() 203 + pianoWaveformViewController.setPresentationMode(.collapsed) 204 + pianoWaveformViewController.refresh() 205 205 showCollapsedIfNeeded() 206 206 if !menuBand.litNotes.isEmpty { 207 207 focusCollapsedPaletteIfNeeded() ··· 209 209 } 210 210 211 211 func scheduleHide() { 212 - guard state == .collapsed else { return } 212 + guard presentationState == .collapsed else { return } 213 213 cancelPendingHide() 214 214 let work = DispatchWorkItem { [weak self] in 215 215 self?.dismissCollapsedPanel() ··· 220 220 221 221 func reposition(statusItemButton: NSStatusBarButton?) { 222 222 self.statusItemButton = statusItemButton 223 - guard state == .collapsed, let panel, panel.isVisible else { return } 224 - setPanelFrame(collapsedFrame(size: paletteController.preferredContentSize)) 223 + guard presentationState == .collapsed, let panel, panel.isVisible else { return } 224 + setPanelFrame(collapsedFrame(size: pianoWaveformViewController.preferredContentSize)) 225 225 } 226 226 227 227 func refreshAppearance() { 228 - guard state == .collapsed else { return } 229 - paletteController.setDisplayMode(.collapsed) 230 - paletteController.refresh() 228 + guard presentationState == .collapsed else { return } 229 + pianoWaveformViewController.setPresentationMode(.collapsed) 230 + pianoWaveformViewController.refresh() 231 231 if let panel, panel.isVisible { 232 - setPanelFrame(collapsedFrame(size: paletteController.preferredContentSize)) 232 + setPanelFrame(collapsedFrame(size: pianoWaveformViewController.preferredContentSize)) 233 233 } 234 234 } 235 235 236 236 func registerArrowInput() { 237 - guard state == .collapsed, !suppressed, isEnabled else { return } 237 + guard presentationState == .collapsed, !isCollapsedPresentationSuppressed, isEnabled else { return } 238 238 showIfNeeded() 239 - paletteController.refresh() 239 + pianoWaveformViewController.refresh() 240 240 focusCollapsedPaletteIfNeeded() 241 241 if menuBand.litNotes.isEmpty { 242 242 scheduleHide() ··· 245 245 246 246 func windowDidMove(_ notification: Notification) { 247 247 guard let panel, !isPositioningPanel else { return } 248 - switch state { 248 + switch presentationState { 249 249 case .expanded: 250 250 savedExpandedOrigin = panel.frame.origin 251 251 persistOrigin(savedExpandedOrigin, xKey: Self.expandedOriginXKey, yKey: Self.expandedOriginYKey) ··· 256 256 } 257 257 258 258 private func buildPanel() { 259 - let panel = UnifiedPianoWaveformPalettePanel( 260 - contentRect: NSRect(origin: .zero, size: paletteController.preferredContentSize), 259 + let panel = PianoWaveformPanel( 260 + contentRect: NSRect(origin: .zero, size: pianoWaveformViewController.preferredContentSize), 261 261 styleMask: [.titled, .closable, .fullSizeContentView], 262 262 backing: .buffered, 263 263 defer: false ··· 276 276 panel.titleVisibility = .hidden 277 277 panel.titlebarAppearsTransparent = true 278 278 panel.isReleasedWhenClosed = false 279 - panel.contentViewController = paletteController 279 + panel.contentViewController = pianoWaveformViewController 280 280 if let button = panel.standardWindowButton(.closeButton) { 281 281 button.isHidden = true 282 282 } ··· 297 297 cancelPendingHide() 298 298 setEnabled(true) 299 299 appBeforeOpen = previousApp ?? currentFrontmostOtherApp() 300 - paletteController.setDisplayMode(.expanded) 301 - paletteController.refresh() 300 + pianoWaveformViewController.setPresentationMode(.expanded) 301 + pianoWaveformViewController.refresh() 302 302 panel.ignoresMouseEvents = false 303 303 setPanelFrame(expandedFrame( 304 - size: paletteController.preferredContentSize, 304 + size: pianoWaveformViewController.preferredContentSize, 305 305 fallbackOrigin: panel.frame.origin 306 306 )) 307 307 NSApp.activate(ignoringOtherApps: true) 308 308 panel.makeKeyAndOrderFront(nil) 309 - paletteController.setPresented(true) 309 + pianoWaveformViewController.setPresented(true) 310 310 installMonitors() 311 311 } 312 312 313 313 private func showCollapsedIfNeeded() { 314 314 guard let panel else { return } 315 - paletteController.setDisplayMode(.collapsed) 315 + pianoWaveformViewController.setPresentationMode(.collapsed) 316 316 panel.ignoresMouseEvents = false 317 - setPanelFrame(collapsedFrame(size: paletteController.preferredContentSize)) 317 + setPanelFrame(collapsedFrame(size: pianoWaveformViewController.preferredContentSize)) 318 318 if !panel.isVisible { 319 319 panel.orderFrontRegardless() 320 320 } 321 - paletteController.setPresented(true) 321 + pianoWaveformViewController.setPresented(true) 322 322 } 323 323 324 324 private func focusCollapsedPaletteIfNeeded() { 325 - guard state == .collapsed, let panel else { return } 325 + guard presentationState == .collapsed, let panel else { return } 326 326 NSApp.activate(ignoringOtherApps: true) 327 327 panel.makeKeyAndOrderFront(nil) 328 - paletteController.setPresented(true) 328 + pianoWaveformViewController.setPresented(true) 329 329 } 330 330 331 331 private func dismissExpanded(reason: DismissReason) { ··· 333 333 guard panel?.isVisible == true || keyMonitor != nil else { return } 334 334 isDismissing = true 335 335 removeMonitors() 336 - paletteController.setPresented(false) 337 - paletteController.clearInteraction() 336 + pianoWaveformViewController.setPresented(false) 337 + pianoWaveformViewController.clearInteraction() 338 338 menuBand.releaseAllHeldNotes() 339 339 panel?.ignoresMouseEvents = false 340 340 panel?.orderOut(nil) 341 - state = .collapsed 341 + presentationState = .collapsed 342 342 dismissHandler?() 343 343 if reason.shouldRestoreFocus { 344 344 restorePreviousAppFocus() ··· 349 349 350 350 private func dismissCollapsedPanel() { 351 351 cancelPendingHide() 352 - paletteController.setPresented(false) 352 + pianoWaveformViewController.setPresented(false) 353 353 panel?.ignoresMouseEvents = false 354 354 panel?.orderOut(nil) 355 355 } 356 356 357 357 private func togglePresentationMode() { 358 - switch state { 358 + switch presentationState { 359 359 case .collapsed: 360 360 expandFromStrip() 361 361 case .expanded: ··· 368 368 persistOrigin(nil, xKey: Self.collapsedOriginXKey, yKey: Self.collapsedOriginYKey) 369 369 collapseToStrip() 370 370 if let panel, panel.isVisible { 371 - setPanelFrame(collapsedFrame(size: paletteController.preferredContentSize)) 371 + setPanelFrame(collapsedFrame(size: pianoWaveformViewController.preferredContentSize)) 372 372 } 373 373 } 374 374 ··· 376 376 if panel == nil { 377 377 buildPanel() 378 378 } 379 - state = .expanded 380 - preferredState = .expanded 379 + presentationState = .expanded 380 + preferredPresentationState = .expanded 381 381 persistPreferredState() 382 382 panel?.ignoresMouseEvents = false 383 - paletteController.setDisplayMode(.expanded) 383 + pianoWaveformViewController.setPresentationMode(.expanded) 384 384 } 385 385 386 386 private func collapseToStrip() { 387 - guard state != .collapsed else { 388 - preferredState = .collapsed 387 + guard presentationState != .collapsed else { 388 + preferredPresentationState = .collapsed 389 389 persistPreferredState() 390 - paletteController.setDisplayMode(.collapsed) 391 - paletteController.refresh() 390 + pianoWaveformViewController.setPresentationMode(.collapsed) 391 + pianoWaveformViewController.refresh() 392 392 showIfNeeded() 393 393 if menuBand.litNotes.isEmpty { 394 394 scheduleHide() ··· 396 396 return 397 397 } 398 398 removeMonitors() 399 - paletteController.setPresented(false) 400 - paletteController.clearInteraction() 401 - state = .collapsed 402 - preferredState = .collapsed 399 + pianoWaveformViewController.setPresented(false) 400 + pianoWaveformViewController.clearInteraction() 401 + presentationState = .collapsed 402 + preferredPresentationState = .collapsed 403 403 persistPreferredState() 404 - paletteController.setDisplayMode(.collapsed) 405 - paletteController.refresh() 404 + pianoWaveformViewController.setPresentationMode(.collapsed) 405 + pianoWaveformViewController.refresh() 406 406 showCollapsedIfNeeded() 407 407 if menuBand.litNotes.isEmpty { 408 408 scheduleHide() ··· 417 417 private func installMonitors() { 418 418 if keyMonitor == nil { 419 419 keyMonitor = NSEvent.addLocalMonitorForEvents(matching: [.keyDown, .keyUp]) { [weak self] event in 420 - guard let self, self.state == .expanded, self.panel?.isKeyWindow == true else { return event } 420 + guard let self, self.presentationState == .expanded, self.panel?.isKeyWindow == true else { return event } 421 421 let isDown = event.type == .keyDown 422 422 if isDown && event.keyCode == 53 { 423 423 self.onFocusRelease?() ··· 544 544 545 545 private func enableAndShowPreferred(restoringTo previousApp: NSRunningApplication?) { 546 546 setEnabled(true) 547 - switch preferredState { 547 + switch preferredPresentationState { 548 548 case .expanded: 549 549 transitionToExpanded() 550 550 showExpanded(restoringTo: previousApp) 551 551 case .collapsed: 552 - state = .collapsed 552 + presentationState = .collapsed 553 553 showIfNeeded() 554 554 focusCollapsedPaletteIfNeeded() 555 555 } ··· 557 557 558 558 private func disable(reason: DismissReason) { 559 559 setEnabled(false) 560 - switch state { 560 + switch presentationState { 561 561 case .expanded: 562 562 dismissExpanded(reason: reason) 563 563 case .collapsed: ··· 572 572 } 573 573 574 574 private func persistPreferredState() { 575 - let value = preferredState == .expanded ? "expanded" : "collapsed" 575 + let value = preferredPresentationState == .expanded ? "expanded" : "collapsed" 576 576 UserDefaults.standard.set(value, forKey: Self.preferredStateKey) 577 577 } 578 578 ··· 621 621 } 622 622 } 623 623 624 - private final class UnifiedPianoWaveformPalettePanel: NSPanel { 624 + private final class PianoWaveformPanel: NSPanel { 625 625 override var canBecomeKey: Bool { true } 626 626 override var canBecomeMain: Bool { false } 627 627 } 628 628 629 629 @available(macOS 26.0, *) 630 - private final class UnifiedWaveformStripGlassEffectView: NSGlassEffectView { 630 + private final class PianoWaveformStripGlassEffectView: NSGlassEffectView { 631 631 override func acceptsFirstMouse(for event: NSEvent?) -> Bool { true } 632 632 } 633 633 634 - final class UnifiedWaveformStripView: NSView { 634 + final class CollapsedPianoWaveformView: NSView { 635 635 private static var shouldUseLiquidGlass: Bool { 636 636 if #available(macOS 26.0, *) { return true } 637 637 return false ··· 933 933 private func installLiquidGlassBackgrounds() { 934 934 guard Self.shouldUseLiquidGlass, #available(macOS 26.0, *) else { return } 935 935 936 - let paletteGlassView = UnifiedWaveformStripGlassEffectView() 936 + let paletteGlassView = PianoWaveformStripGlassEffectView() 937 937 paletteGlassView.translatesAutoresizingMaskIntoConstraints = false 938 938 paletteGlassView.cornerRadius = 10 939 939 addSubview(paletteGlassView, positioned: .below, relativeTo: contentContainer) ··· 961 961 private func installGlassBackground(matchedTo target: NSView, 962 962 below anchor: NSView, 963 963 cornerRadius: CGFloat) -> NSView { 964 - let glassView = UnifiedWaveformStripGlassEffectView() 964 + let glassView = PianoWaveformStripGlassEffectView() 965 965 glassView.translatesAutoresizingMaskIntoConstraints = false 966 966 glassView.cornerRadius = cornerRadius 967 967 addSubview(glassView, positioned: .below, relativeTo: anchor)