macos: fix state handling of terminal surface in split

This commit is contained in:
Mitchell Hashimoto
2023-03-06 10:40:08 -08:00
parent eef41aa6de
commit 1a4fabc2e5
2 changed files with 48 additions and 32 deletions

View File

@ -49,52 +49,70 @@ struct TerminalSplittableView: View {
case BottomRight case BottomRight
} }
/// The stored state between invocations.
class ViewState: ObservableObject {
/// The direction of the split currently
@Published var direction: Direction = .none
/// The top or left view. This is always set.
@Published var topLeft: TerminalSurfaceView
/// The bottom or right view. This can be nil if the direction == .none.
@Published var bottomRight: TerminalSurfaceView? = nil
/// Initialize the view state for the first time. This will create our topLeft view from new.
init(_ app: ghostty_app_t) {
self.topLeft = TerminalSurfaceView(app)
}
/// Initialize the view state using an existing top left. This is usually used when a split happens and
/// the child view inherits the top left.
init(topLeft: TerminalSurfaceView) {
self.topLeft = topLeft
}
}
let app: ghostty_app_t
@StateObject private var state: ViewState
@FocusState private var focusedSide: Side? @FocusState private var focusedSide: Side?
let app: ghostty_app_t;
@State private var topLeft: TerminalSurfaceView
/// The bottom or right surface. This is private because in a splittable view it is only possible that we set
/// this, because it is triggered from a split event.
@State private var bottomRight: TerminalSurfaceView? = nil
/// Direction of the current split. If this is "nil" then the terminal is not currently split at all.
@State private var splitDirection: Direction = .none
init(_ app: ghostty_app_t) { init(_ app: ghostty_app_t) {
self.app = app self.app = app
_topLeft = State(wrappedValue: TerminalSurfaceView(app)) _state = StateObject(wrappedValue: ViewState(app))
} }
init(_ app: ghostty_app_t, topLeft: TerminalSurfaceView) { init(_ app: ghostty_app_t, topLeft: TerminalSurfaceView) {
self.app = app self.app = app
_topLeft = State(wrappedValue: topLeft) _state = StateObject(wrappedValue: ViewState(topLeft: topLeft))
} }
func split(to: Direction) { func split(to: Direction) {
assert(to != .none) assert(to != .none)
assert(splitDirection == .none) assert(state.direction == .none)
splitDirection = to
bottomRight = TerminalSurfaceView(app) // Make the split the desired value
state.direction = to
// Create the new split which always goes to the bottom right.
state.bottomRight = TerminalSurfaceView(app)
} }
func closeTopLeft() { func closeTopLeft() {
assert(splitDirection != .none) assert(state.direction != .none)
assert(bottomRight != nil) assert(state.bottomRight != nil)
topLeft = bottomRight! state.topLeft = state.bottomRight!
splitDirection = .none state.direction = .none
} }
func closeBottomRight() { func closeBottomRight() {
assert(splitDirection != .none) assert(state.direction != .none)
assert(bottomRight != nil) assert(state.bottomRight != nil)
bottomRight = nil state.bottomRight = nil
splitDirection = .none state.direction = .none
} }
var body: some View { var body: some View {
switch (splitDirection) { switch (state.direction) {
case .none: case .none:
VStack { VStack {
HStack { HStack {
@ -102,7 +120,7 @@ struct TerminalSplittableView: View {
Button("Split Vertical") { split(to: .vertical) } Button("Split Vertical") { split(to: .vertical) }
} }
TerminalView(surface: topLeft) TerminalView(surface: state.topLeft)
.focused($focusedSide, equals: .TopLeft) .focused($focusedSide, equals: .TopLeft)
} }
case .horizontal: case .horizontal:
@ -113,9 +131,9 @@ struct TerminalSplittableView: View {
} }
HSplitView { HSplitView {
TerminalSplittableView(app, topLeft: topLeft) TerminalSplittableView(app, topLeft: state.topLeft)
.focused($focusedSide, equals: .TopLeft) .focused($focusedSide, equals: .TopLeft)
TerminalSplittableView(app, topLeft: bottomRight!) TerminalSplittableView(app, topLeft: state.bottomRight!)
.focused($focusedSide, equals: .BottomRight) .focused($focusedSide, equals: .BottomRight)
} }
} }
@ -127,9 +145,9 @@ struct TerminalSplittableView: View {
} }
VSplitView { VSplitView {
TerminalSplittableView(app, topLeft: topLeft) TerminalSplittableView(app, topLeft: state.topLeft)
.focused($focusedSide, equals: .TopLeft) .focused($focusedSide, equals: .TopLeft)
TerminalSplittableView(app, topLeft: bottomRight!) TerminalSplittableView(app, topLeft: state.bottomRight!)
.focused($focusedSide, equals: .BottomRight) .focused($focusedSide, equals: .BottomRight)
} }
} }

View File

@ -59,7 +59,6 @@ class WindowObserver: ObservableObject {
object: window, object: window,
queue: .main queue: .main
) { (n) in ) { (n) in
print("KEY WINDOW YES")
self.isKeyWindow = true self.isKeyWindow = true
} }
@ -68,7 +67,6 @@ class WindowObserver: ObservableObject {
object: window, object: window,
queue: .main queue: .main
) { (n) in ) { (n) in
print("KEY WINDOW RESIGN")
self.isKeyWindow = false self.isKeyWindow = false
} }
} }