Add floating close button to split panes

- Each pane now has a floating × button in top-right corner
- Semi-transparent black background with white text
- Tooltip shows keyboard shortcut
- Auto-positions when resizing
- Makes closing panes more intuitive
This commit is contained in:
2026-01-31 23:37:49 +00:00
parent c42c1c7a2d
commit cae91fec8c
3 changed files with 39 additions and 0 deletions

View File

@@ -565,6 +565,7 @@ class MainWindowController: NSWindowController {
// Move current session to split view
currentSession.scrollView.removeFromSuperview()
addCloseButtonToPane(currentSession.scrollView, index: 0)
splitView?.addArrangedSubview(currentSession.scrollView)
panes = [currentSession]
}
@@ -574,6 +575,7 @@ class MainWindowController: NSWindowController {
newSession.setupTextView(frame: CGRect(x: 0, y: 0, width: contentView.bounds.width / 2, height: contentView.bounds.height))
newSession.startShell()
addCloseButtonToPane(newSession.scrollView, index: panes.count)
splitView?.addArrangedSubview(newSession.scrollView)
panes.append(newSession)
activePaneIndex = panes.count - 1
@@ -607,6 +609,7 @@ class MainWindowController: NSWindowController {
// Move current session to split view
currentSession.scrollView.removeFromSuperview()
addCloseButtonToPane(currentSession.scrollView, index: 0)
splitView?.addArrangedSubview(currentSession.scrollView)
panes = [currentSession]
}
@@ -616,6 +619,7 @@ class MainWindowController: NSWindowController {
newSession.setupTextView(frame: CGRect(x: 0, y: 0, width: contentView.bounds.width, height: contentView.bounds.height / 2))
newSession.startShell()
addCloseButtonToPane(newSession.scrollView, index: panes.count)
splitView?.addArrangedSubview(newSession.scrollView)
panes.append(newSession)
activePaneIndex = panes.count - 1
@@ -629,6 +633,41 @@ class MainWindowController: NSWindowController {
newSession.textView.window?.makeFirstResponder(newSession.textView)
}
private func addCloseButtonToPane(_ scrollView: NSScrollView, index: Int) {
// Remove any existing close button
scrollView.subviews.filter { $0.tag == 9999 }.forEach { $0.removeFromSuperview() }
// Create close button
let closeButton = NSButton(frame: NSRect(x: scrollView.bounds.width - 30, y: scrollView.bounds.height - 30, width: 24, height: 24))
closeButton.title = "×"
closeButton.bezelStyle = .circular
closeButton.font = NSFont.systemFont(ofSize: 16, weight: .bold)
closeButton.tag = 9999 // Special tag to identify close buttons
closeButton.target = self
closeButton.action = #selector(closePaneFromButton(_:))
closeButton.toolTip = "Close pane (Cmd+Shift+W)"
closeButton.autoresizingMask = [.minXMargin, .minYMargin]
closeButton.wantsLayer = true
closeButton.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.5).cgColor
closeButton.layer?.cornerRadius = 12
closeButton.contentTintColor = .white
// Store the pane index
objc_setAssociatedObject(closeButton, "paneIndex", index, .OBJC_ASSOCIATION_RETAIN)
scrollView.addSubview(closeButton)
}
@objc func closePaneFromButton(_ sender: NSButton) {
guard let index = objc_getAssociatedObject(sender, "paneIndex") as? Int else { return }
// Find the actual current index (it might have changed)
guard index < panes.count else { return }
activePaneIndex = index
closePane()
}
@objc func closePane() {
// Only close panes if we have splits
guard panes.count > 1 else {