TUI Layout
Anchoring-first responsive layout for TUI applications.
Anchoring is the default mode - every control behaves correctly on terminal resize without special containers.
Basic Principle
Anchoring-first means:
- Terminal resize must not break layout, focus, or rendering
- Controls maintain stable spatial relationships
- Predictable expansion/shrinking rules
Anchor Semantics
Available Anchors
| Anchor | Meaning |
| Left | Distance to left edge stays constant |
| Top | Distance to top edge stays constant |
| Right | Distance to right edge stays constant |
| Bottom | Distance to bottom edge stays constant |
Combinations
Default: Left + Top
→ Position stays stable, size constant
Left + Right:
→ Width stretches/shrinks with parent width
Top + Bottom:
→ Height stretches/shrinks with parent height
All four (Left + Top + Right + Bottom):
→ Rect stretches in both directions
No Anchors:
→ Treat as Left + Top (no "floating" ambiguity)
PXAML Examples
<!-- Fixed position top left -->
<Button Anchors="Left,Top" Text="OK" />
<!-- Full width, fixed height -->
<TextEdit Anchors="Left,Top,Right" Height="3" />
<!-- Fills entire available area -->
<ListView Anchors="Left,Top,Right,Bottom" />
<!-- Status bar at bottom -->
<StatusBar Anchors="Left,Right,Bottom" Height="1" />
Resize Behavior
Flow on Resize
1. Receive resize event
└─ Update root available rect
2. Invalidate layout
└─ Perform measure/arrange pass
3. Preserve focus
└─ Same logical control keeps focus
4. Re-render
└─ Paint → DiffFlush
Deterministic
REQUIRED:
- Same input → Same layout
- No flicker during rapid resize
- No cursor corruption
- Focus stays on logical control
Breakpoints
Optional but recommended resize thresholds:
Standard Breakpoints
| Breakpoint | Width | Typical Layout |
| Narrow | < 80 | Single-column, stacked |
| Medium | 80-119 | Sidebar collapsed to tabs |
| Wide | >= 120 | Sidebar + content side-by-side |
PXAML Configuration
<Panel ResponsiveMode="Auto" Breakpoints="80,120">
<!-- Automatic reflow when breakpoint crossed -->
</Panel>
Breakpoint Rules
REQUIRED:
- Breakpoints NOT "magic" - define in PXAML or theme config
- Document breakpoints
- Clearly define behavior at each breakpoint
Layout Containers
Stack
Orientation: Vertical or Horizontal
Children are arranged sequentially
<Stack Orientation="Vertical">
<Label Text="Name:" />
<TextEdit />
<Label Text="Email:" />
<TextEdit />
</Stack>
Dock
Positions: Left, Top, Right, Bottom, Fill
Children dock to sides, remainder fills center
<Dock>
<MenuBar Dock="Top" />
<StatusBar Dock="Bottom" />
<Sidebar Dock="Left" Width="20" />
<Content Dock="Fill" />
</Dock>
Overlay
For popups, modals, tooltips
Overlays other controls
Must stay within screen bounds (clamped)
<Overlay>
<Dialog X="10" Y="5" Width="40" Height="10">
<!-- Modal content -->
</Dialog>
</Overlay>
Grid (later)
Define rows and columns
Place controls in cells
Anchoring Precedence
Order of layout calculation:
1. Container layout (if explicit)
└─ Stack/Grid/Dock/Overlay calculates child rects
2. Apply anchors
└─ Refine within container rect
└─ Respect min/max
└─ Preserve margins/padding
3. Clipping last
└─ Clip final bounds
When Content Larger Than Area
PREFERRED:
- Use ScrollViewer container
- Make content scrollable
NOT as default:
- Text "shrink to fit"
REQUIRED:
- Controls can render in smaller rect (clip + ellipsis)
- State must not be lost
<ScrollViewer Anchors="Left,Top,Right,Bottom">
<Stack Orientation="Vertical">
<!-- Long list of controls -->
</Stack>
</ScrollViewer>
Focus Under Reflow
REQUIRED:
- Focus tracked by control identity (not screen position)
- After reflow:
- If focused control still focusable and visible → keep
- Otherwise: Fallback to next focusable sibling in focus order
Focus Stability
procedure TLayoutEngine.ApplyReflow;
var
PreviousFocus: TWvdSControl;
begin
(* Remember focus *)
PreviousFocus := FocusManager.FocusedControl;
(* Recalculate layout *)
MeasureAndArrange(RootControl);
(* Restore focus *)
if (PreviousFocus <> nil) and
PreviousFocus.CanFocus and
PreviousFocus.IsVisible then
FocusManager.SetFocus(PreviousFocus)
else
FocusManager.FocusNextAvailable;
end;
Verification
Resize Tests
[ ] Narrow <-> Wide repeatedly: no flicker
[ ] Cursor not corrupt after resize
[ ] Focus stays on same control
[ ] Anchored stretch controls don't overlap
[ ] Popups/Overlays stay within screen bounds
Breakpoint Tests
[ ] Layout switches correctly when breakpoint crossed
[ ] No flicker during breakpoint switch
[ ] All breakpoints documented
Container Tests
[ ] Stack arranges children correctly
[ ] Dock fills correctly (Left, Top, Right, Bottom, Fill)
[ ] Overlay stays in bounds
[ ] Nested containers work
PXAML Reference
Control Attributes
| Attribute | Values | Meaning |
| Anchors | Left,Top,Right,Bottom | Anchor combinations |
| Margin | „l,t,r,b“ or „all“ | Outer spacing |
| Padding | „l,t,r,b“ or „all“ | Inner spacing |
| MinWidth | Integer | Minimum width |
| MaxWidth | Integer | Maximum width |
| MinHeight | Integer | Minimum height |
| MaxHeight | Integer | Maximum height |
Container Attributes
| Attribute | Values | Meaning |
| ResponsiveMode | Auto, Manual | Automatic breakpoint handling |
| Breakpoints | „w1,w2,…“ | Breakpoint widths |
See also