Docking Architecture
The complete architecture of the Beep docking system — layout tree, panels, groups, positions, floating windows, auto-hide, persistence, and the painter pipeline
Table of Contents
Overview
The Beep docking system provides a complete Visual-Studio-style docking experience. At its heart is BeepDockingManager, a non-visual component that orchestrates a network of DockPanel components, BeepDockspace controls, FloatWindow forms, and AutoHideSlidePanel controls.
The system spans ~48 source files organized into subsystems:
- Models — DockPanel, DockGroup, DockLayoutTree, serialization types
- Runtime — FloatWindow, AutoHideSlidePanel, AutoHideStrip, BeepDockspace, splitters
- Layout — DockingLayoutController, LayoutCalculator, LayoutValidator
- Drag-Drop — DockDragController, DockGuideController, DockDragGhost, guide overlay
- Painters — IDockingPainter, caption/splitter/auto-hide renderers, adapter
- Animation — DockAnimator, AnimationTrack, easing functions
System Architecture
BeepDockingManager (IComponent, IDockDragHost)
├── HostForm (Form)
├── LayoutTree (DockLayoutTree)
│ └── Root (DockGroup) — tree of nested groups
│ ├── DockGroup (Id="left", Position=Left)
│ │ ├── DockPanel ("solution-explorer")
│ │ └── DockPanel ("properties")
│ ├── DockGroup (Id="main", Position=Fill)
│ │ ├── DockGroup (split child, Horizontal)
│ │ │ ├── DockPanel ("editor1")
│ │ │ └── DockPanel ("editor2")
│ │ └── DockPanel ("output")
│ └── DockGroup (Id="right", Position=Right)
│ └── DockPanel ("toolbox")
├── LayoutController (DockingLayoutController)
│ ├── LayoutCalculator (ratio-based split math)
│ └── LayoutValidator (post-layout checks)
├── Dockspaces (BeepDockspace[]) — visual containers
├── FloatWindows (FloatWindow[]) — floating windows
├── AutoHideStrips (AutoHideStrip[]) — edge strips
├── Painter (IDockingPainter) — theme-aware rendering
└── DragController (DockDragController)
├── DockDragGhost (ghost window during drag)
├── DockGuideController (diamond overlay)
└── DockTargetResolver (drop target logic)Core Types
| Type | Base | Role |
|---|---|---|
| BeepDockingManager | Component | Central orchestrator — panel registry, layout, theming, events |
| DockPanel | Panel | Dockable content container — Title, Key, Content, State, Capabilities |
| DockGroup | object | Tree node — contains panels and child groups, split ratios |
| DockLayoutTree | object | In-memory layout — Root group, panel/group registries, ToDefinition() |
| BeepDockspace | Panel | Visual container — tab strip, caption, panel content area |
| FloatWindow | Form | Floating window — borderless, caption drag, edge snap |
| AutoHideSlidePanel | Panel | Slide-out panel — animated reveal from edge strip |
| AutoHideStrip | Panel | Edge strip — tab-like buttons for collapsed panels |
| DockingLayoutController | object | Computes pixel rectangles for every group/dockspace |
| DockLayoutDefinition | object | Serialization format — Groups, Floating, AutoHidden collections |
Layout Tree
The layout tree is a hierarchical structure where each DockGroup node can contain panels and child groups:
- Leaf groups contain one or more DockPanel (rendered as a BeepDockspace with tabs)
- Split groups contain two or more child groups (rendered side-by-side with splitters)
- The Root group always has Position=Fill and may contain child groups
- Each group has a SplitRatio (0.1-0.9, default 0.5) controlling proportional space
The DockingLayoutController traverses this tree to compute pixel rectangles, handling min-width/height constraints and splitter positions.
Panel States & Lifecycle
| State | Description | Visual |
|---|---|---|
| Docked | Panel occupies a region of the form (Left/Right/Top/Bottom/Fill) | Tab in a dockspace with caption bar |
| Tabbed | Multiple panels share a dockspace (stacked tabs) | Tabs with active indicator |
| Floating | Panel detached in a separate FloatWindow form | Borderless window with title bar |
| Auto-Hidden | Panel collapsed to an edge strip | Tab button on edge; hover reveals slide panel |
| Closed | Panel in the closed store (can be reopened) | Not visible |
State transitions are managed by BeepDockingManager. Cancelable request events (PageCloseRequest, PageFloatingRequest, etc.) let applications veto transitions.
Painter Pipeline
Docking chrome rendering uses a two-layer abstraction:
- DockingPainterAdapter — Bridges BeepTheme tokens to docking-specific colors
- DockingRendererSet — Concrete renderers for each element type
| Renderer | Class | Responsibility |
|---|---|---|
| Caption | CaptionRenderer | Draws title bar, tab strip, action buttons (close/float/pin) |
| Splitter | SplitterRenderer | Draws resize handle between docked groups |
| Auto-Hide | AutoHideStripRenderer | Draws edge strip tabs and slide panel chrome |
Drag-Drop System
The drag-drop pipeline:
- Initiation — User starts dragging a tab header or caption
- Ghost — DockDragGhost creates a semi-transparent window tracking the mouse
- Guide Overlay — DockingGuideOverlay shows a 5-diamond guide (Left/Right/Top/Bottom/Fill)
- Target Resolution — DockTargetResolver determines valid drop positions
- Completion — Panel is moved to the new position; layout recalculates
Layout Persistence
// Save
var def = manager.LayoutTree.ToDefinition();
string json = JsonConvert.SerializeObject(def);
// Restore
var def = JsonConvert.DeserializeObject<DockLayoutDefinition>(json);
manager.LoadLayout(def);The DockLayoutDefinition contains three serializable collections:
- Groups — List of DockGroupDefinition (position, orientation, split ratio, panel keys)
- Floating — List of FloatingPanelInfo (key, bounds, last dock position)
- AutoHidden — List of AutoHiddenPanelInfo (key, edge)
Code Example
var mgr = new BeepDockingManager();
mgr.ManageControl(this);
mgr.AddPanel("explorer", "Solution Explorer",
DockPosition.Right, new TreeView());
mgr.AddPanel("editor", "Main.cs",
DockPosition.Fill, new RichTextBox());
mgr.AddPanel("output", "Output",
DockPosition.Bottom, new TextBox { Multiline = true });
// Float and re-dock
mgr.FloatPanel("output",
new Rectangle(100, 100, 600, 400));
mgr.DockFloatingPanel("output",
DockPosition.Right);
// Auto-hide
mgr.AutoHidePanel("explorer");
mgr.RestoreAutoHiddenPanel("explorer");