Documentation 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.
ControlBase is the concrete base class that all Terminality widgets inherit from. It wires together the reactive Property<T> system, the three-phase layout pipeline (Measure → Arrange → Render), keyboard events and hotkeys, focus management, and child iteration. You never instantiate ControlBase directly — you subclass it and implement the three pure-virtual override points, or use one of the built-in controls such as Button, TextBox, or Grid.
Creating controls with init<T>
Theinit<T> factory helper creates a widget, runs an optional initialization lambda over it, and returns a unique_ptr<T>. It is the idiomatic way to build widget trees in Terminality:
init<T> overloads
init<T>(lambda) — create and initialize
init<T>(lambda) — create and initialize
T with make_unique<T>(), calls init(widget.get()) if the function is non-null, and returns the unique_ptr. Ownership passes to the caller.init<T>() — create without initialization
init<T>() — create without initialization
std::make_unique<T>().Properties
Every property is an instance ofProperty<ControlBase, T>. Assigning to a property automatically fires PropertyChanged and schedules the appropriate invalidation pass (measure, arrange, or visual).
Identity and tagging
Tag — string identifier
Tag — string identifier
QueryByTag<T>() to locate a specific node in the tree. Does not trigger any invalidation when changed (InvalidationKind::None).Default: ""Sizing
MinSize, MaxSize, ExpSize — size constraints
MinSize, MaxSize, ExpSize — size constraints
MinSize clamps the measured content size from below; MaxSize clamps from above. Setting ExpSize is a shorthand that writes the same value to both MinSize and MaxSize, pinning the control to an exact size.Use Size::Auto (negative component values) to indicate no constraint. All three properties trigger a measure pass on change.Layout
Margin — external spacing
Margin — external spacing
Thickness has Left, Top, Right, Bottom fields.Default: Thickness::ZeroHorizontalAlignment — horizontal placement
HorizontalAlignment — horizontal placement
| Value | Behavior |
|---|---|
HorizontalAlign::Left | Anchors to the left edge |
HorizontalAlign::Center | Centers within the slot |
HorizontalAlign::Right | Anchors to the right edge |
HorizontalAlign::Stretch | Expands to fill the slot (clamped by MinSize/MaxSize) |
HorizontalAlign::StretchVerticalAlignment — vertical placement
VerticalAlignment — vertical placement
| Value | Behavior |
|---|---|
VerticalAlign::Top | Anchors to the top edge |
VerticalAlign::Center | Centers within the slot |
VerticalAlign::Bottom | Anchors to the bottom edge |
VerticalAlign::Stretch | Expands to fill the slot (clamped by MinSize/MaxSize) |
VerticalAlign::StretchColors
ForegroundColor, BackgroundColor — normal state
ForegroundColor, BackgroundColor — normal state
FocusedForegroundColor, FocusedBackgroundColor — focused state
FocusedForegroundColor, FocusedBackgroundColor — focused state
Visibility and context menu
IsVisible — show or hide
IsVisible — show or hide
false, the control is hidden. This triggers a visual invalidation but does not remove the control from the layout tree.Default: trueCtxMenu — right-click context menu
CtxMenu — right-click context menu
Events
Events use theEvent<Args...> template. Subscribe with operator+= for fire-and-forget handlers, or Connect() for a scoped EventConnection that auto-disconnects on destruction.
| Event | Signature | Description |
|---|---|---|
PropertyChanged | Event<const char*> | Fires after any property or internal field changes. The argument is the property name string. |
KeyDown | Event<InputEvent> | Fires when a key-down event is dispatched to this control. |
KeyUp | Event<InputEvent> | Fires when a key-up event is dispatched to this control. |
Methods
Tree attachment
SetParent(parent) — attach to a parent node
SetParent(parent) — attach to a parent node
parent_ and fires PropertyChanged("Parent"). Passing nullptr detaches the control and calls OnDettachedFromTree().nullptr to detach.SetLayer(layer) — bind to a UILayer
SetLayer(layer) — bind to a UILayer
UILayer reference down to this control and all of its visual children. Called automatically when the root node of a layer is constructed.nullptr to clear.Focus configuration
SetFocusable, SetTabStop, SetTabIndex
SetFocusable, SetTabStop, SetTabIndex
PropertyChanged when the value actually changes.false, the control cannot receive focus at all.true, the control is included in the Tab/Shift-Tab cycle.Layout pipeline
Measure(availableSize) → Size
Measure(availableSize) → Size
Margin, MinSize, and MaxSize constraints to availableSize, then delegates to MeasureOverride for the content size. Returns the total desired size including margins.Arrange(finalRect)
Arrange(finalRect)
finalRect, applies HorizontalAlignment and VerticalAlignment to compute the actual drawing rectangle, then calls ArrangeOverride with the result.Render(context)
Render(context)
ForegroundColor and BackgroundColor, clears the visual-dirty flag, then calls RenderOverride for content drawing.Invalidation
ApplyInvalidation(kind) — schedule a layout pass
ApplyInvalidation(kind) — schedule a layout pass
| Value | Effect |
|---|---|
InvalidationKind::None | No invalidation |
InvalidationKind::Visual | Redraws this control’s pixels |
InvalidationKind::Arrange | Reruns arrange and render |
InvalidationKind::Measure | Reruns measure, arrange, and render |
Input handling
OnKeyDown(input), OnKeyUp(input) — receive key events
OnKeyDown(input), OnKeyUp(input) — receive key events
OnKeyDown emits the KeyDown event, checks registered hotkeys, and handles arrow-key focus movement. OnKeyUp emits the KeyUp event. Return true to indicate the event was consumed and should not bubble to the parent.Key, Modifier, and Pressed fields.true if the event was handled; false to let it bubble up the tree.OnHotkey(modifier, key, callback) — register a keyboard shortcut
OnHotkey(modifier, key, callback) — register a keyboard shortcut
modifier + key combination is pressed, callback is invoked with a pointer to this control. Throws std::runtime_error if the same combination is registered twice.InputModifier::None, InputModifier::LeftCtrl).std::function<void(ControlBase*)> invoked when the shortcut fires.Context menu
OpenContextMenu() — show the CtxMenu overlay
OpenContextMenu() — show the CtxMenu overlay
Tree queries
QueryByTag<T>(tag) — find a descendant by tag
QueryByTag<T>(tag) — find a descendant by tag
ControlBase whose Tag property equals tag, cast to T*. Returns nullptr if no match is found or if the found node cannot be cast to T.nullptr.child_begin(), child_end() — iterate visual children
child_begin(), child_end() — iterate visual children
ChildIterator dereferences to VisualTreeNode*. The base ControlBase implementation returns empty iterators (zero children); container subclasses override VisualChildrenCount() and GetVisualChild() to expose their children.Navigation
Close() — stop the owning layer's loop
Close() — stop the owning layer's loop
layer_->Running to false, causing the NestUILoop that owns this layer to exit on the next tick. This is how modal dialogs and overlay controls close themselves.Virtual override points
SubclassControlBase and implement all three pure-virtual methods:
MeasureOverride(availableSize) → Size
MeasureOverride(availableSize) → Size
availableSize by the time this is called. Use negative component values (Size::Auto) to indicate that an axis is unconstrained.MaxSize constraints have been applied.ArrangeOverride(finalRect)
ArrangeOverride(finalRect)
finalRect. For leaf controls this is often a no-op. Container controls forward finalRect slices to each child via their Arrange methods.RenderOverride(context)
RenderOverride(context)
context. The base Render() has already cleared the background. Use context.BeginText() to write characters, or delegate to children by calling their Render methods.