diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj index 458feec34..08cc344a4 100644 --- a/macos/Ghostty.xcodeproj/project.pbxproj +++ b/macos/Ghostty.xcodeproj/project.pbxproj @@ -65,6 +65,7 @@ A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */; }; A5E112972AF7401B00C6E0C2 /* ClipboardConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */; }; A5FEB3002ABB69450068369E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5FEB2FF2ABB69450068369E /* main.swift */; }; + C159E81D2B66A06B00FDFE9C /* NSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C159E81C2B66A06B00FDFE9C /* NSColor+Extension.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -123,6 +124,7 @@ A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationController.swift; sourceTree = ""; }; A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationView.swift; sourceTree = ""; }; A5FEB2FF2ABB69450068369E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + C159E81C2B66A06B00FDFE9C /* NSColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Extension.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -187,6 +189,7 @@ 8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */, A59630962AEE163600D64628 /* HostingWindow.swift */, A59FB5D02AE0DEA7009128F3 /* MetalView.swift */, + C159E81C2B66A06B00FDFE9C /* NSColor+Extension.swift */, A5CEAFDA29B8005900646FDA /* SplitView */, ); path = Helpers; @@ -489,6 +492,7 @@ A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */, 8503D7C72A549C66006CFF3D /* FullScreenHandler.swift in Sources */, A596309E2AEE1D6C00D64628 /* TerminalView.swift in Sources */, + C159E81D2B66A06B00FDFE9C /* NSColor+Extension.swift in Sources */, A5CEAFDE29B8058B00646FDA /* SplitView.Divider.swift in Sources */, A5E112972AF7401B00C6E0C2 /* ClipboardConfirmationView.swift in Sources */, A514C8D82B54DC6800493A16 /* Ghostty.App.swift in Sources */, diff --git a/macos/Sources/Ghostty/Ghostty.App.swift b/macos/Sources/Ghostty/Ghostty.App.swift index f988c553c..1be89ea4e 100644 --- a/macos/Sources/Ghostty/Ghostty.App.swift +++ b/macos/Sources/Ghostty/Ghostty.App.swift @@ -30,7 +30,7 @@ extension Ghostty { /// The global app configuration. This defines the app level configuration plus any behavior /// for new windows, tabs, etc. Note that when creating a new window, it may inherit some /// configuration (i.e. font size) from the previously focused window. This would override this. - private(set) var config: Config + @Published private(set) var config: Config /// The ghostty app instance. We only have one of these for the entire app, although I guess /// in theory you can have multiple... I don't know why you would... diff --git a/macos/Sources/Ghostty/Ghostty.Config.swift b/macos/Sources/Ghostty/Ghostty.Config.swift index 641cca917..df9df686c 100644 --- a/macos/Sources/Ghostty/Ghostty.Config.swift +++ b/macos/Sources/Ghostty/Ghostty.Config.swift @@ -258,5 +258,14 @@ extension Ghostty { blue: blue / 255 ) } + + // This isn't actually a configurable value currently but it could be done day. + // We put it here because it is a color that changes depending on the configuration. + var splitDividerColor: Color { + let backgroundColor = NSColor(backgroundColor) + let isLightBackground = backgroundColor.isLightColor + let newColor = isLightBackground ? backgroundColor.shadow(withLevel: 0.1) : backgroundColor.shadow(withLevel: 0.4) + return Color(nsColor: newColor ?? .gray.withAlphaComponent(0.5)) + } } } diff --git a/macos/Sources/Ghostty/Ghostty.TerminalSplit.swift b/macos/Sources/Ghostty/Ghostty.TerminalSplit.swift index e7edb041c..88b352748 100644 --- a/macos/Sources/Ghostty/Ghostty.TerminalSplit.swift +++ b/macos/Sources/Ghostty/Ghostty.TerminalSplit.swift @@ -280,6 +280,8 @@ extension Ghostty { /// This represents a split view that is in the horizontal or vertical split state. private struct TerminalSplitContainer: View { + @EnvironmentObject var ghostty: Ghostty.App + let neighbors: SplitNode.Neighbors @Binding var node: SplitNode? @StateObject var container: SplitNode.Container @@ -288,6 +290,7 @@ extension Ghostty { SplitView( container.direction, $container.split, + dividerColor: ghostty.config.splitDividerColor, resizeIncrements: .init(width: 1, height: 1), resizePublisher: container.resizeEvent, left: { diff --git a/macos/Sources/Ghostty/InspectorView.swift b/macos/Sources/Ghostty/InspectorView.swift index 074431274..cfc65bca0 100644 --- a/macos/Sources/Ghostty/InspectorView.swift +++ b/macos/Sources/Ghostty/InspectorView.swift @@ -6,6 +6,8 @@ import GhosttyKit extension Ghostty { /// InspectableSurface is a type of Surface view that allows an inspector to be attached. struct InspectableSurface: View { + @EnvironmentObject var ghostty: Ghostty.App + /// Same as SurfaceWrapper, see the doc comments there. @ObservedObject var surfaceView: SurfaceView var isSplit: Bool = false @@ -24,7 +26,7 @@ extension Ghostty { if (!surfaceView.inspectorVisible) { SurfaceWrapper(surfaceView: surfaceView, isSplit: isSplit) } else { - SplitView(.vertical, $split, left: { + SplitView(.vertical, $split, dividerColor: ghostty.config.splitDividerColor, left: { SurfaceWrapper(surfaceView: surfaceView, isSplit: isSplit) }, right: { InspectorViewRepresentable(surfaceView: surfaceView) diff --git a/macos/Sources/Helpers/NSColor+Extension.swift b/macos/Sources/Helpers/NSColor+Extension.swift new file mode 100644 index 000000000..a1f371f96 --- /dev/null +++ b/macos/Sources/Helpers/NSColor+Extension.swift @@ -0,0 +1,14 @@ +import AppKit + +extension NSColor { + var isLightColor: Bool { + var r: CGFloat = 0 + var g: CGFloat = 0 + var b: CGFloat = 0 + var a: CGFloat = 0 + + self.getRed(&r, green: &g, blue: &b, alpha: &a) + let luminance = (0.299 * r) + (0.587 * g) + (0.114 * b) + return luminance > 0.5 + } +} diff --git a/macos/Sources/Helpers/SplitView/SplitView.Divider.swift b/macos/Sources/Helpers/SplitView/SplitView.Divider.swift index aba1c48f4..67aecb79d 100644 --- a/macos/Sources/Helpers/SplitView/SplitView.Divider.swift +++ b/macos/Sources/Helpers/SplitView/SplitView.Divider.swift @@ -6,6 +6,7 @@ extension SplitView { let direction: SplitViewDirection let visibleSize: CGFloat let invisibleSize: CGFloat + let color: Color private var visibleWidth: CGFloat? { switch (direction) { @@ -42,13 +43,13 @@ extension SplitView { return visibleSize + invisibleSize } } - + var body: some View { ZStack { Color.clear .frame(width: invisibleWidth, height: invisibleHeight) Rectangle() - .fill(Color.gray) + .fill(color) .frame(width: visibleWidth, height: visibleHeight) } .onHover { isHovered in diff --git a/macos/Sources/Helpers/SplitView/SplitView.swift b/macos/Sources/Helpers/SplitView/SplitView.swift index ecfb68d03..3fad805e1 100644 --- a/macos/Sources/Helpers/SplitView/SplitView.swift +++ b/macos/Sources/Helpers/SplitView/SplitView.swift @@ -10,6 +10,9 @@ struct SplitView: View { /// Direction of the split let direction: SplitViewDirection + /// Divider color + let dividerColor: Color + /// If set, the split view supports programmatic resizing via events sent via the publisher. /// Minimum increment (in points) that this split can be resized by, in /// each direction. Both `height` and `width` should be whole numbers @@ -45,7 +48,10 @@ struct SplitView: View { right .frame(width: rightRect.size.width, height: rightRect.size.height) .offset(x: rightRect.origin.x, y: rightRect.origin.y) - Divider(direction: direction, visibleSize: splitterVisibleSize, invisibleSize: splitterInvisibleSize) + Divider(direction: direction, + visibleSize: splitterVisibleSize, + invisibleSize: splitterInvisibleSize, + color: dividerColor) .position(splitterPoint) .gesture(dragGesture(geo.size, splitterPoint: splitterPoint)) } @@ -57,10 +63,15 @@ struct SplitView: View { /// Initialize a split view. This view isn't programmatically resizable; it can only be resized /// by manually dragging the divider. - init(_ direction: SplitViewDirection, _ split: Binding, @ViewBuilder left: (() -> L), @ViewBuilder right: (() -> R)) { + init(_ direction: SplitViewDirection, + _ split: Binding, + dividerColor: Color, + @ViewBuilder left: (() -> L), + @ViewBuilder right: (() -> R)) { self.init( direction, split, + dividerColor: dividerColor, resizeIncrements: .init(width: 1, height: 1), resizePublisher: .init(), left: left, @@ -72,6 +83,7 @@ struct SplitView: View { init( _ direction: SplitViewDirection, _ split: Binding, + dividerColor: Color, resizeIncrements: NSSize, resizePublisher: PassthroughSubject, @ViewBuilder left: (() -> L), @@ -79,6 +91,7 @@ struct SplitView: View { ) { self.direction = direction self._split = split + self.dividerColor = dividerColor self.resizeIncrements = resizeIncrements self.resizePublisher = resizePublisher self.left = left()