Overview
Implement the split-pane terminal grid matching macOS PaneGridController.swift. A recursive binary tree of splits, up to 6 panes.
Data Structure
enum PaneSplitNode {
Leaf { id: String, entry: Option<TabEntry> },
Split {
direction: SplitDirection, // Horizontal | Vertical
first: Box<PaneSplitNode>,
second: Box<PaneSplitNode>,
ratio: f64, // 0.0 to 1.0, default 0.5
},
}
GTK Implementation
Each Split node renders as a gtk::Paned:
Horizontal → gtk::Orientation::Vertical (top/bottom)
Vertical → gtk::Orientation::Horizontal (left/right)
ratio maps to Paned::set_position() based on allocated size
Each Leaf node contains either a TerminalPane (VTE) or a PlaceholderView with "New Agent" / "New Terminal" buttons.
Operations
- Split focused pane (Ctrl+D horizontal, Ctrl+Shift+D vertical): Split the leaf, create new empty leaf
- Close focused pane (Ctrl+W): Remove leaf, promote sibling
- Move focus (Ctrl+Arrow): Navigate directionally through the tree
- Max 6 leaves: Enforce limit, max 2 rows × 3 columns
Focus Management
Track focused_leaf_id. Highlight focused pane with a subtle border. Mouse click updates focus. Keyboard shortcuts navigate focus.
Hover Overlay
Each pane cell shows translucent overlay on hover with:
- Split horizontal button (⊟)
- Split vertical button (⊞)
- Close button (✕)
Use gtk::Overlay with a gtk::EventControllerMotion for hover detection.
Session Persistence
Serialize PaneSplitNode to GridLayoutNode (Codable/serde) and persist in .ppg/dashboard-sessions.json under gridLayouts[entryId]. Restore on app relaunch.
References
- macOS:
PPG CLI/PPG CLI/PaneGridController.swift (1158 lines)
- Persistence:
PPG CLI/PPG CLI/DashboardSession.swift (GridLayoutNode)
Acceptance Criteria
Overview
Implement the split-pane terminal grid matching macOS
PaneGridController.swift. A recursive binary tree of splits, up to 6 panes.Data Structure
GTK Implementation
Each
Splitnode renders as agtk::Paned:Horizontal→gtk::Orientation::Vertical(top/bottom)Vertical→gtk::Orientation::Horizontal(left/right)ratiomaps toPaned::set_position()based on allocated sizeEach
Leafnode contains either aTerminalPane(VTE) or aPlaceholderViewwith "New Agent" / "New Terminal" buttons.Operations
Focus Management
Track
focused_leaf_id. Highlight focused pane with a subtle border. Mouse click updates focus. Keyboard shortcuts navigate focus.Hover Overlay
Each pane cell shows translucent overlay on hover with:
Use
gtk::Overlaywith agtk::EventControllerMotionfor hover detection.Session Persistence
Serialize
PaneSplitNodetoGridLayoutNode(Codable/serde) and persist in.ppg/dashboard-sessions.jsonundergridLayouts[entryId]. Restore on app relaunch.References
PPG CLI/PPG CLI/PaneGridController.swift(1158 lines)PPG CLI/PPG CLI/DashboardSession.swift(GridLayoutNode)Acceptance Criteria
gtk::PanedwidgetsPanedhandles