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

Scroll and Viewport

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 Example

<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

Zuletzt geändert: on 2026/01/29 at 10:29 PM