docs: add dock layout system design spec
This commit is contained in:
75
docs/superpowers/specs/2026-03-28-dock-layout-design.md
Normal file
75
docs/superpowers/specs/2026-03-28-dock-layout-design.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# DockLayout System Design
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
To create a fully-featured docking layout system for the Ghost Engine Editor using WinUI 3, supporting tab tearing, window popping, and dynamic splitting of regions in a style similar to Unity or Blender.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
The DockLayout will be entirely driven by a C# data model that represents a tree of nodes. The UI (`DockLayout` control) will observe this tree and recursively generate the corresponding XAML `Grid` and `TabView` elements.
|
||||||
|
|
||||||
|
### Core Data Model (The Node Tree)
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public abstract class DockNode : INotifyPropertyChanged { }
|
||||||
|
|
||||||
|
// Represents a split region (Grid)
|
||||||
|
public class DockGroupNode : DockNode
|
||||||
|
{
|
||||||
|
public Orientation Orientation { get; set; } // Horizontal or Vertical
|
||||||
|
public ObservableCollection<DockNode> Children { get; }
|
||||||
|
public ObservableCollection<GridLength> Sizes { get; } // Replaces Ratios for better WinUI 3 Grid binding
|
||||||
|
}
|
||||||
|
|
||||||
|
// Represents a leaf node containing a TabView
|
||||||
|
public class DockPanelNode : DockNode
|
||||||
|
{
|
||||||
|
// The items shown in the TabView
|
||||||
|
public ObservableCollection<object> Items { get; }
|
||||||
|
public int SelectedIndex { get; set; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Visual Components
|
||||||
|
|
||||||
|
1. **`DockLayout` (Control)**
|
||||||
|
* The root control.
|
||||||
|
* Takes a `DockNode` (usually a `DockGroupNode`) as its `Root`.
|
||||||
|
* Listens to Drag/Drop events to render the transparent drop target overlay over the layout.
|
||||||
|
|
||||||
|
2. **Node Renderers**
|
||||||
|
* A recursive template selector or code-behind builder that converts `DockGroupNode` into a `Grid` with `GridSplitter`s.
|
||||||
|
* Converts `DockPanelNode` into a `NavigationTabView` (or standard `TabView` with customized drag behaviors).
|
||||||
|
|
||||||
|
3. **`DockDropTarget` (Visual Overlay)**
|
||||||
|
* A simple XAML structure (e.g., a colored `Border` with opacity) that highlights a portion of a `DockPanelNode` based on mouse position during a drag operation (Left/Right/Top/Bottom 25% for splitting, Center 50% for merging).
|
||||||
|
|
||||||
|
## Interactions & Data Flow
|
||||||
|
|
||||||
|
### 1. Internal Dragging (Within the same window)
|
||||||
|
* User starts dragging a tab.
|
||||||
|
* The `DockLayout` tracks the mouse pointer `DragOver` events.
|
||||||
|
* It determines which `DockPanelNode` the mouse is currently hovering over.
|
||||||
|
* It calculates relative coordinates to show the Unity-style drop highlight.
|
||||||
|
* On **Drop**:
|
||||||
|
* If dropped in the **center**: The tab object is moved from its source `DockPanelNode.Items` to the target `DockPanelNode.Items`.
|
||||||
|
* If dropped on an **edge** (e.g., Right): The target `DockPanelNode` is removed from its parent `DockGroupNode`. A new `DockGroupNode` (Horizontal) is created to replace it. The target node and a *new* `DockPanelNode` (containing the dragged tab) are added as children to this new group.
|
||||||
|
|
||||||
|
### 2. Window Tear-Off (Full Docking)
|
||||||
|
* User drags a tab completely outside the main window.
|
||||||
|
* `TabView.TabDroppedOutside` is triggered.
|
||||||
|
* The system creates a new WinUI 3 `Window`.
|
||||||
|
* A new `DockLayout` instance is placed in this window.
|
||||||
|
* The dragged tab object is removed from its original tree and added to a new `DockPanelNode` inside the new window's tree.
|
||||||
|
* *Note: Because WinUI 3 supports multiple windows on the same UI thread, we don't have to worry about cross-thread marshaling of UI elements, making this much simpler than UWP.*
|
||||||
|
|
||||||
|
### 3. Empty Node Cleanup
|
||||||
|
* When a `DockPanelNode`'s `Items` collection reaches 0 (the last tab is dragged away), it is removed from the tree.
|
||||||
|
* If its parent `DockGroupNode` now only has 1 child remaining, that `DockGroupNode` is removed and replaced by its single child, collapsing the tree.
|
||||||
|
|
||||||
|
## Implementation Phases
|
||||||
|
1. Define the Data Model (`DockNode` structure).
|
||||||
|
2. Implement the recursive UI generation (binding the tree to nested Grids and TabViews).
|
||||||
|
3. Implement basic tab moving (Merge) between existing `DockPanelNode`s.
|
||||||
|
4. Implement edge dropping (Split) and the drop target highlight overlay.
|
||||||
|
5. Implement empty node cleanup logic.
|
||||||
|
6. Implement multi-window tear-off via `TabDroppedOutside`.
|
||||||
Reference in New Issue
Block a user