import AppKit
|
import AlignerCore
|
|
@MainActor
|
final class Round0DebugOverlayController {
|
static let overlayTitle = "Aligner Round0 Debug Overlay"
|
static let settingsTitle = "Aligner Round0 Debug Settings"
|
|
private let overlayHost: QuickSwitchOverlayHost
|
private var settingsWindow: NSWindow?
|
|
init() {
|
overlayHost = QuickSwitchOverlayHost(
|
title: Self.overlayTitle,
|
contentView: Self.makeOverlayView()
|
)
|
}
|
|
func show(includeSettingsChild: Bool) {
|
overlayHost.show(context: OverlayContext(entryPoint: .quickSwitch))
|
|
if includeSettingsChild {
|
attachSettingsChild()
|
}
|
}
|
|
func hide() {
|
if let settingsWindow {
|
overlayHost.detachChild(settingsWindow)
|
settingsWindow.orderOut(nil)
|
}
|
settingsWindow = nil
|
overlayHost.hide(reason: .userClosed)
|
}
|
|
private func attachSettingsChild() {
|
if settingsWindow == nil {
|
settingsWindow = Self.makeSettingsWindow()
|
}
|
|
guard let settingsWindow else { return }
|
settingsWindow.center()
|
overlayHost.attachChild(settingsWindow)
|
settingsWindow.orderFrontRegardless()
|
}
|
|
private static func makeOverlayView() -> NSView {
|
let root = NSVisualEffectView()
|
root.material = .hudWindow
|
root.blendingMode = .behindWindow
|
root.state = .active
|
root.translatesAutoresizingMaskIntoConstraints = false
|
|
let label = NSTextField(labelWithString: "Round0 Debug Overlay")
|
label.font = .systemFont(ofSize: 24, weight: .semibold)
|
label.textColor = .white
|
label.alignment = .center
|
label.translatesAutoresizingMaskIntoConstraints = false
|
|
root.addSubview(label)
|
NSLayoutConstraint.activate([
|
label.centerXAnchor.constraint(equalTo: root.centerXAnchor),
|
label.centerYAnchor.constraint(equalTo: root.centerYAnchor)
|
])
|
|
return root
|
}
|
|
private static func makeSettingsWindow() -> NSWindow {
|
let window = NSWindow(
|
contentRect: NSRect(x: 0, y: 0, width: 360, height: 180),
|
styleMask: [.titled, .closable],
|
backing: .buffered,
|
defer: false
|
)
|
window.title = settingsTitle
|
window.isReleasedWhenClosed = false
|
|
let label = NSTextField(wrappingLabelWithString: "Round0 Settings Child Window")
|
label.font = .systemFont(ofSize: 17, weight: .semibold)
|
label.alignment = .center
|
label.translatesAutoresizingMaskIntoConstraints = false
|
|
let content = NSView()
|
content.addSubview(label)
|
NSLayoutConstraint.activate([
|
label.centerXAnchor.constraint(equalTo: content.centerXAnchor),
|
label.centerYAnchor.constraint(equalTo: content.centerYAnchor),
|
label.leadingAnchor.constraint(greaterThanOrEqualTo: content.leadingAnchor, constant: 24),
|
label.trailingAnchor.constraint(lessThanOrEqualTo: content.trailingAnchor, constant: -24)
|
])
|
window.contentView = content
|
return window
|
}
|
}
|
|
struct Round0DebugLaunchOptions {
|
let skipPermissions: Bool
|
let showOverlay: Bool
|
let showSettingsChild: Bool
|
let autoHideAfter: TimeInterval?
|
let quitAfter: TimeInterval?
|
|
static func parse(arguments: [String]) -> Round0DebugLaunchOptions {
|
Round0DebugLaunchOptions(
|
skipPermissions: arguments.contains("--round0-skip-permissions"),
|
showOverlay: arguments.contains("--round0-debug-overlay"),
|
showSettingsChild: arguments.contains("--round0-debug-settings-child"),
|
autoHideAfter: timeInterval(for: "--round0-debug-auto-hide-after", in: arguments),
|
quitAfter: timeInterval(for: "--round0-debug-quit-after", in: arguments)
|
)
|
}
|
|
private static func timeInterval(for key: String, in arguments: [String]) -> TimeInterval? {
|
let prefix = "\(key)="
|
guard let argument = arguments.first(where: { $0.hasPrefix(prefix) }) else {
|
return nil
|
}
|
|
return TimeInterval(argument.dropFirst(prefix.count))
|
}
|
}
|