Monospaced font and semantic colors (dark-mode correct), visible vertical scroller (was missing), text inset, centered window with a proper title. Autoscroll now only follows the tail when already at the bottom instead of yanking the scroll position on every log line. Also sets isReleasedWhenClosed = false, fixing a latent crash on close-then-reopen (the settings window already had this guard). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
55 lines
1.9 KiB
Swift
55 lines
1.9 KiB
Swift
import Cocoa
|
|
|
|
class LogWindowController: NSWindowController {
|
|
var textView: NSTextView!
|
|
|
|
convenience init() {
|
|
let contentRect = NSRect(x: 0, y: 0, width: 600, height: 400)
|
|
let styleMask: NSWindow.StyleMask = [.titled, .closable, .resizable]
|
|
|
|
let window = NSWindow(contentRect: contentRect,
|
|
styleMask: styleMask,
|
|
backing: .buffered,
|
|
defer: false)
|
|
|
|
self.init(window: window)
|
|
|
|
window.title = "BrewBar Logs"
|
|
// the controller keeps the window alive; without this, closing the
|
|
// window would deallocate it and reopening would crash
|
|
window.isReleasedWhenClosed = false
|
|
window.center()
|
|
|
|
let scrollView = NSScrollView(frame: window.contentView!.bounds)
|
|
scrollView.autoresizingMask = [.width, .height]
|
|
scrollView.hasVerticalScroller = true
|
|
|
|
textView = NSTextView(frame: scrollView.bounds)
|
|
textView.isEditable = false
|
|
textView.autoresizingMask = [.width, .height]
|
|
textView.font = .monospacedSystemFont(ofSize: 12, weight: .regular)
|
|
textView.textColor = .textColor // adapts to light/dark mode
|
|
textView.backgroundColor = .textBackgroundColor
|
|
textView.textContainerInset = NSSize(width: 8, height: 8)
|
|
|
|
scrollView.documentView = textView
|
|
window.contentView?.addSubview(scrollView)
|
|
}
|
|
|
|
func update(text: String) {
|
|
// only follow the tail if the user is already at the bottom — don't
|
|
// yank the scroll position away while they are reading older output
|
|
let wasAtBottom: Bool = if let scrollView = textView.enclosingScrollView {
|
|
scrollView.contentView.bounds.maxY >= textView.frame.height - 30
|
|
} else {
|
|
true
|
|
}
|
|
|
|
textView.string = text
|
|
|
|
if wasAtBottom {
|
|
textView.scrollToEndOfDocument(nil)
|
|
}
|
|
}
|
|
}
|