diff --git a/.DS_Store b/.DS_Store index 0887bdd..0034b68 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/EnhancedTerminal.app/Contents/MacOS/EnhancedTerminal b/EnhancedTerminal.app/Contents/MacOS/EnhancedTerminal index 6a39916..759a01a 100755 Binary files a/EnhancedTerminal.app/Contents/MacOS/EnhancedTerminal and b/EnhancedTerminal.app/Contents/MacOS/EnhancedTerminal differ diff --git a/MainWindowController.swift b/MainWindowController.swift index 6fe38ae..63ff880 100644 --- a/MainWindowController.swift +++ b/MainWindowController.swift @@ -1,5 +1,44 @@ import Cocoa +// MARK: - Hover Close Button +class HoverCloseButton: NSButton { + override func mouseEntered(with event: NSEvent) { + super.mouseEntered(with: event) + NSAnimationContext.runAnimationGroup { context in + context.duration = 0.15 + self.layer?.backgroundColor = NSColor(white: 0.3, alpha: 0.85).cgColor + self.contentTintColor = NSColor.white + } + } + + override func mouseExited(with event: NSEvent) { + super.mouseExited(with: event) + NSAnimationContext.runAnimationGroup { context in + context.duration = 0.15 + self.layer?.backgroundColor = NSColor(white: 0.2, alpha: 0.6).cgColor + self.contentTintColor = NSColor(white: 0.8, alpha: 0.9) + } + } + + override func updateTrackingAreas() { + super.updateTrackingAreas() + + // Remove old tracking areas + for trackingArea in trackingAreas { + removeTrackingArea(trackingArea) + } + + // Add new tracking area + let trackingArea = NSTrackingArea( + rect: bounds, + options: [.mouseEnteredAndExited, .activeAlways, .inVisibleRect], + owner: self, + userInfo: nil + ) + addTrackingArea(trackingArea) + } +} + class MainWindowController: NSWindowController { var tabManager = TabManager() var tabBar: NSStackView! @@ -511,9 +550,8 @@ class MainWindowController: NSWindowController { File: Cmd+T - New Tab Cmd+W - Close Tab - Cmd+D - Split Pane Vertically - Cmd+Shift+D - Split Pane Horizontally - Cmd+Shift+W - Close Pane + Cmd+D - Split Pane Vertically (side-by-side) + Cmd+Shift+D - Split Pane Horizontally (top-bottom) Cmd+K - Clear Screen Cmd+Shift+K - Clear Scrollback @@ -538,7 +576,9 @@ class MainWindowController: NSWindowController { Terminal: Tab - Accept Auto-suggestion + Up/Down - Navigate Command History Double-click Tab - Rename Tab + Click × button - Close split pane """ alert.alertStyle = .informational alert.addButton(withTitle: "OK") @@ -563,10 +603,10 @@ class MainWindowController: NSWindowController { splitView?.dividerStyle = .thin splitView?.autoresizingMask = [.width, .height] - // Move current session to split view + // Move current session to split view with close button currentSession.scrollView.removeFromSuperview() - addCloseButtonToPane(currentSession.scrollView, index: 0) - splitView?.addArrangedSubview(currentSession.scrollView) + let containerView = addCloseButtonToPane(currentSession.scrollView, index: 0) + splitView?.addArrangedSubview(containerView) panes = [currentSession] } @@ -575,8 +615,8 @@ 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) + let newContainerView = addCloseButtonToPane(newSession.scrollView, index: panes.count) + splitView?.addArrangedSubview(newContainerView) panes.append(newSession) activePaneIndex = panes.count - 1 @@ -607,10 +647,10 @@ class MainWindowController: NSWindowController { splitView?.dividerStyle = .thin splitView?.autoresizingMask = [.width, .height] - // Move current session to split view + // Move current session to split view with close button currentSession.scrollView.removeFromSuperview() - addCloseButtonToPane(currentSession.scrollView, index: 0) - splitView?.addArrangedSubview(currentSession.scrollView) + let containerView = addCloseButtonToPane(currentSession.scrollView, index: 0) + splitView?.addArrangedSubview(containerView) panes = [currentSession] } @@ -619,8 +659,8 @@ 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) + let newContainerView = addCloseButtonToPane(newSession.scrollView, index: panes.count) + splitView?.addArrangedSubview(newContainerView) panes.append(newSession) activePaneIndex = panes.count - 1 @@ -633,29 +673,39 @@ 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() } + private func addCloseButtonToPane(_ scrollView: NSScrollView, index: Int) -> NSView { + // Create a container view that will hold both the scroll view and the close button + let containerView = NSView(frame: scrollView.frame) + containerView.autoresizingMask = [.width, .height] + containerView.wantsLayer = true - // Create close button - let closeButton = NSButton(frame: NSRect(x: scrollView.bounds.width - 30, y: scrollView.bounds.height - 30, width: 24, height: 24)) + // Adjust scroll view frame to fill container + scrollView.frame = containerView.bounds + scrollView.autoresizingMask = [.width, .height] + containerView.addSubview(scrollView) + + // Create close button with subtle styling + let closeButton = HoverCloseButton(frame: NSRect(x: containerView.bounds.width - 35, y: containerView.bounds.height - 35, 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.font = NSFont.systemFont(ofSize: 16, weight: .medium) + closeButton.tag = 9999 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?.backgroundColor = NSColor(white: 0.2, alpha: 0.6).cgColor closeButton.layer?.cornerRadius = 12 - closeButton.contentTintColor = .white + closeButton.contentTintColor = NSColor(white: 0.8, alpha: 0.9) // Store the pane index objc_setAssociatedObject(closeButton, "paneIndex", index, .OBJC_ASSOCIATION_RETAIN) - scrollView.addSubview(closeButton) + // Add button on top of scroll view + containerView.addSubview(closeButton) + + return containerView } @objc func closePaneFromButton(_ sender: NSButton) { diff --git a/TerminalSession.swift b/TerminalSession.swift index 48cca60..f94c9c7 100644 --- a/TerminalSession.swift +++ b/TerminalSession.swift @@ -568,6 +568,8 @@ class TerminalSession: NSObject, NSTextViewDelegate, NSMenuDelegate { Keyboard Shortcuts: • Cmd+T - New tab • Cmd+W - Close tab + • Cmd+D - Split pane vertically (side-by-side) + • Cmd+Shift+D - Split pane horizontally (top-bottom) • Cmd+R - Search command history (fuzzy search) • Cmd+K - AI command generator • Cmd+P - Command snippets