macos: move TerminalTabColor to its own file

pull/9784/head
Mitchell Hashimoto 2025-12-11 07:23:50 -08:00
parent 1a65c1aae2
commit 51589a4e02
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
5 changed files with 126 additions and 124 deletions

View File

@ -115,6 +115,7 @@
Features/Terminal/ErrorView.swift,
Features/Terminal/TerminalController.swift,
Features/Terminal/TerminalRestorable.swift,
Features/Terminal/TerminalTabColor.swift,
Features/Terminal/TerminalView.swift,
"Features/Terminal/Window Styles/HiddenTitlebarTerminalWindow.swift",
"Features/Terminal/Window Styles/Terminal.xib",

View File

@ -55,7 +55,7 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
private(set) var derivedConfig: DerivedConfig
/// The accent color that should be rendered for this tab.
var tabColor: TerminalWindow.TabColor = .none {
var tabColor: TerminalTabColor = .none {
didSet {
guard tabColor != oldValue else { return }
if let terminalWindow = window as? TerminalWindow {
@ -863,7 +863,7 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
let focusedSurface: UUID?
let tabIndex: Int?
weak var tabGroup: NSWindowTabGroup?
let tabColor: TerminalWindow.TabColor
let tabColor: TerminalTabColor
}
convenience init(_ ghostty: Ghostty.App,
@ -1196,7 +1196,7 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
}
func setTabColor(_ color: TerminalWindow.TabColor) {
func setTabColor(_ color: TerminalTabColor) {
tabColor = color
}

View File

@ -97,7 +97,7 @@ class TerminalWindowRestoration: NSObject, NSWindowRestoration {
return
}
c.tabColor = TerminalWindow.TabColor(rawValue: state.tabColorRawValue) ?? .none
c.tabColor = TerminalTabColor(rawValue: state.tabColorRawValue) ?? .none
// Setup our restored state on the controller
// Find the focused surface in surfaceTree

View File

@ -0,0 +1,110 @@
import AppKit
enum TerminalTabColor: Int, CaseIterable {
case none
case blue
case purple
case pink
case red
case orange
case yellow
case green
case teal
case graphite
static let paletteRows: [[TerminalTabColor]] = [
[.none, .blue, .purple, .pink, .red],
[.orange, .yellow, .green, .teal, .graphite],
]
var localizedName: String {
switch self {
case .none:
return "None"
case .blue:
return "Blue"
case .purple:
return "Purple"
case .pink:
return "Pink"
case .red:
return "Red"
case .orange:
return "Orange"
case .yellow:
return "Yellow"
case .green:
return "Green"
case .teal:
return "Teal"
case .graphite:
return "Graphite"
}
}
var displayColor: NSColor? {
switch self {
case .none:
return nil
case .blue:
return .systemBlue
case .purple:
return .systemPurple
case .pink:
return .systemPink
case .red:
return .systemRed
case .orange:
return .systemOrange
case .yellow:
return .systemYellow
case .green:
return .systemGreen
case .teal:
if #available(macOS 13.0, *) {
return .systemMint
} else {
return .systemTeal
}
case .graphite:
return .systemGray
}
}
func swatchImage(selected: Bool) -> NSImage {
let size = NSSize(width: 18, height: 18)
return NSImage(size: size, flipped: false) { rect in
let circleRect = rect.insetBy(dx: 1, dy: 1)
let circlePath = NSBezierPath(ovalIn: circleRect)
if let fillColor = self.displayColor {
fillColor.setFill()
circlePath.fill()
} else {
NSColor.clear.setFill()
circlePath.fill()
NSColor.quaternaryLabelColor.setStroke()
circlePath.lineWidth = 1
circlePath.stroke()
}
if self == .none {
let slash = NSBezierPath()
slash.move(to: NSPoint(x: circleRect.minX + 2, y: circleRect.minY + 2))
slash.line(to: NSPoint(x: circleRect.maxX - 2, y: circleRect.maxY - 2))
slash.lineWidth = 1.5
NSColor.secondaryLabelColor.setStroke()
slash.stroke()
}
if selected {
let highlight = NSBezierPath(ovalIn: rect.insetBy(dx: 0.5, dy: 0.5))
highlight.lineWidth = 2
NSColor.controlAccentColor.setStroke()
highlight.stroke()
}
return true
}
}
}

View File

@ -30,7 +30,7 @@ class TerminalWindow: NSWindow {
/// The configuration derived from the Ghostty config so we don't need to rely on references.
private(set) var derivedConfig: DerivedConfig = .init()
private var tabMenuObserver: NSObjectProtocol? = nil
private var tabColorSelection: TabColor = .none {
private var tabColorSelection: TerminalTabColor = .none {
didSet { tabColorIndicator.tabColor = tabColorSelection }
}
@ -46,7 +46,7 @@ class TerminalWindow: NSWindow {
windowController as? TerminalController
}
func display(tabColor: TabColor) {
func display(tabColor: TerminalTabColor) {
tabColorSelection = tabColor
}
@ -741,119 +741,10 @@ extension TerminalWindow {
}
extension TerminalWindow {
enum TabColor: Int, CaseIterable {
case none
case blue
case purple
case pink
case red
case orange
case yellow
case green
case teal
case graphite
static let paletteRows: [[TabColor]] = [
[.none, .blue, .purple, .pink, .red],
[.orange, .yellow, .green, .teal, .graphite],
]
var localizedName: String {
switch self {
case .none:
return NSLocalizedString("None", comment: "Tab color option label")
case .blue:
return NSLocalizedString("Blue", comment: "Tab color option label")
case .purple:
return NSLocalizedString("Purple", comment: "Tab color option label")
case .pink:
return NSLocalizedString("Pink", comment: "Tab color option label")
case .red:
return NSLocalizedString("Red", comment: "Tab color option label")
case .orange:
return NSLocalizedString("Orange", comment: "Tab color option label")
case .yellow:
return NSLocalizedString("Yellow", comment: "Tab color option label")
case .green:
return NSLocalizedString("Green", comment: "Tab color option label")
case .teal:
return NSLocalizedString("Teal", comment: "Tab color option label")
case .graphite:
return NSLocalizedString("Graphite", comment: "Tab color option label")
}
}
var displayColor: NSColor? {
switch self {
case .none:
return nil
case .blue:
return .systemBlue
case .purple:
return .systemPurple
case .pink:
return .systemPink
case .red:
return .systemRed
case .orange:
return .systemOrange
case .yellow:
return .systemYellow
case .green:
return .systemGreen
case .teal:
if #available(macOS 13.0, *) {
return .systemMint
} else {
return .systemTeal
}
case .graphite:
return .systemGray
}
}
func swatchImage(selected: Bool) -> NSImage {
let size = NSSize(width: 18, height: 18)
return NSImage(size: size, flipped: false) { rect in
let circleRect = rect.insetBy(dx: 1, dy: 1)
let circlePath = NSBezierPath(ovalIn: circleRect)
if let fillColor = self.displayColor {
fillColor.setFill()
circlePath.fill()
} else {
NSColor.clear.setFill()
circlePath.fill()
NSColor.quaternaryLabelColor.setStroke()
circlePath.lineWidth = 1
circlePath.stroke()
}
if self == .none {
let slash = NSBezierPath()
slash.move(to: NSPoint(x: circleRect.minX + 2, y: circleRect.minY + 2))
slash.line(to: NSPoint(x: circleRect.maxX - 2, y: circleRect.maxY - 2))
slash.lineWidth = 1.5
NSColor.secondaryLabelColor.setStroke()
slash.stroke()
}
if selected {
let highlight = NSBezierPath(ovalIn: rect.insetBy(dx: 0.5, dy: 0.5))
highlight.lineWidth = 2
NSColor.controlAccentColor.setStroke()
highlight.stroke()
}
return true
}
}
}
}
private final class TabColorIndicator: NSView {
var tabColor: TerminalWindow.TabColor = .none {
var tabColor: TerminalTabColor = .none {
didSet { updateAppearance() }
}
@ -892,12 +783,12 @@ private final class TabColorIndicator: NSView {
private final class TabColorPaletteView: NSView {
private let stackView = NSStackView()
private var selectedColor: TerminalWindow.TabColor
private let selectionHandler: (TerminalWindow.TabColor) -> Void
private var selectedColor: TerminalTabColor
private let selectionHandler: (TerminalTabColor) -> Void
private var buttons: [NSButton] = []
init(selectedColor: TerminalWindow.TabColor,
selectionHandler: @escaping (TerminalWindow.TabColor) -> Void) {
init(selectedColor: TerminalTabColor,
selectionHandler: @escaping (TerminalTabColor) -> Void) {
self.selectedColor = selectedColor
self.selectionHandler = selectionHandler
super.init(frame: NSRect(origin: .zero, size: NSSize(width: 180, height: 60)))
@ -906,7 +797,7 @@ private final class TabColorPaletteView: NSView {
stackView.spacing = 6
addSubview(stackView)
for row in TerminalWindow.TabColor.paletteRows {
for row in TerminalTabColor.paletteRows {
let rowStack = NSStackView()
rowStack.orientation = .horizontal
rowStack.spacing = 6
@ -937,7 +828,7 @@ private final class TabColorPaletteView: NSView {
stackView.frame = bounds.insetBy(dx: 10, dy: 6)
}
private func makeButton(for color: TerminalWindow.TabColor) -> NSButton {
private func makeButton(for color: TerminalTabColor) -> NSButton {
let button = NSButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.imagePosition = .imageOnly
@ -960,7 +851,7 @@ private final class TabColorPaletteView: NSView {
}
@objc private func onSelectColor(_ sender: NSButton) {
guard let color = TerminalWindow.TabColor(rawValue: sender.tag) else { return }
guard let color = TerminalTabColor(rawValue: sender.tag) else { return }
selectedColor = color
updateButtonImages()
selectionHandler(color)
@ -968,7 +859,7 @@ private final class TabColorPaletteView: NSView {
private func updateButtonImages() {
for button in buttons {
guard let color = TerminalWindow.TabColor(rawValue: button.tag) else { continue }
guard let color = TerminalTabColor(rawValue: button.tag) else { continue }
button.image = color.swatchImage(selected: color == selectedColor)
}
}