Every Terminality UI is a tree of nodes. The framework owns the tree throughDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Rikitav/Terminality/llms.txt
Use this file to discover all available pages before exploring further.
VisualTree, a process-global singleton. Each node in the tree is a VisualTreeNode, and every concrete control you write or use inherits from ControlBase, which extends VisualTreeNode with layout, input handling, focus management, and the reactive property system.
Core types
VisualTree
The process-global root of the UI. Holds a stack of
UILayer objects, runs the layout pipeline, and dispatches dirty-rect rendering to a RenderBuffer.VisualTreeNode
Abstract base class for every node. Declares the
Measure / Arrange / Render contract, dirty flags, parent pointer, and focus/input callbacks.UILayer
A
VisualTree layer owns one root VisualTreeNode and a FocusManager. Layers stack — pushing a modal dialog pushes a new layer; popping removes it.ControlBase
The concrete base class for all user-facing controls. Adds the
Property<> system, Event<> members (PropertyChanged, KeyDown, KeyUp), alignment, margin, colours, focus, and hotkey registration.VisualTree and UILayer
VisualTree::Current() returns the singleton. The framework starts a UI loop by pushing one root control as a UILayer:
PeekLayer() returns the topmost active layer’s root node.
VisualTreeNode
VisualTreeNode is the abstract interface that VisualTree operates on. It carries three dirty flags:
| Flag | Cleared by |
|---|---|
measureDirty_ | Measure() |
arrangeDirty_ | Arrange() |
visualDirty_ | Render() |
InvalidateMeasure(), InvalidateArrange(), or InvalidateVisual() on a node bubbles the notification up to the tree via OnChildInvalidated(), so the framework knows which subtree needs re-layout.
Each node exposes VisualChildrenCount() and GetVisualChild(index) so the tree can traverse its children without knowing the concrete type.
ControlBase
ControlBase derives from VisualTreeNode and is the class you subclass to write your own controls. It provides:
- Layout properties —
MinSize,MaxSize,ExpSize,Margin,HorizontalAlignment,VerticalAlignment - Colour properties —
ForegroundColor,BackgroundColor,FocusedForegroundColor,FocusedBackgroundColor - Visibility —
IsVisible - Reactive callbacks —
PropertyChanged,KeyDown,KeyUp - Focus/tab order —
SetFocusable(),SetTabStop(),SetTabIndex() - Hotkey registration —
OnHotkey(modifier, key, callback) - Tree query —
QueryByTag<T>() - Child iteration —
child_begin()/child_end()
MeasureOverride / ArrangeOverride / RenderOverride
The three protected pure virtuals are the extension points you override in every control:The init<T>() factory helper
Building a widget tree by hand with std::make_unique and sequential setter calls produces verbose, hard-to-read code. The init<T>() helper template solves this:
T, passes the raw pointer to the lambda so you can configure it, then returns the unique_ptr. The overload without a lambda just allocates:
AddChild
Panel controls such asGrid and StackPanel expose AddChild(). Grid::AddChild takes a row, column, and optionally row/column spans:
StackPanel::AddChild takes only the child pointer because panels stack children sequentially along their orientation axis.
QueryByTag
Every control has aTag property (a std::string). QueryByTag<T>(tag) performs a depth-first search from any node and returns the first match cast to T*, or nullptr:
Child iteration
ControlBase exposes a standard forward iterator over its visual children:
GetVisualChild(index) internally, so it works uniformly across Grid, StackPanel, Border, and any custom panel you create.
VisualTreeNode does not support copy or move semantics — controls are exclusively owned by their parent through std::unique_ptr. Never store a raw pointer to a control that outlives its tree.