Inhaltsverzeichnis
TUI Controls
Implementation guidelines for controls/widgets in the TUI target.
This pattern extends the existing „Model + Renderer“ concept with TUI-specific requirements.
Architecture
Model + Renderer Separation
Model (Target-neutral) Renderer (Target-specific) ───────────────────── ───────────────────────────── TWvdS* Pascal class TUI: CellBuffer via RenderSurface - Properties, State GUI: Canvas/GDI - Events, Commands Web: DOM/HTML - No I/O dependency
Deliverables per Control
| Component | Content |
| Model Unit | Properties, events, state (target-neutral) |
|---|---|
| TUI Renderer Unit | Paint, focus, input handling |
| Pack Manifest | PXAML tag → units mapping |
Model Unit (Target-neutral)
Contains
TWvdSButton = class(TWvdSControl) private FCaption: string; FEnabled: Boolean; FFocused: Boolean; FPressed: Boolean; FOnClick: TNotifyEvent; public property Caption: string read FCaption write SetCaption; property Enabled: Boolean read FEnabled write SetEnabled; property Focused: Boolean read FFocused write SetFocused; property OnClick: TNotifyEvent read FOnClick write FOnClick; end;
Does NOT Contain
- Terminal I/O or ANSI sequences
- DOM/Web APIs
- Platform-specific calls
TUI Renderer Unit
Interface
IWvdSTUIRenderer = interface (* Layout *) function Measure(AControl: TWvdSControl; AAvailable: TSize): TSize; procedure Arrange(AControl: TWvdSControl; ARect: TRect); (* Rendering *) procedure Paint(AControl: TWvdSControl; ASurface: TRenderSurface); (* Input *) function HandleInput(AControl: TWvdSControl; AEvent: TInputEvent): Boolean; end;
Minimum Implementation
REQUIRED for every TUI Renderer: - Deterministic placeholder rendering (before feature completion) - Focus indicator display - Disabled state display - Tab navigation works end-to-end - Optional: Mouse handling (if TerminalCaps.SupportsMouse)
Visual States
State Hierarchy
Required States: ├─ Base (* Default display *) ├─ Focus (* Has keyboard focus *) ├─ Disabled (* Not interactive *) └─ Error/Invalid (* Validation error *) Optional States: ├─ Hover (* Mouse over - if mouse supported *) └─ Pressed (* Actively pressed *)
Rendering per State
procedure TWvdSButtonTUIRenderer.Paint(AControl: TWvdSControl; ASurface: TRenderSurface); var Btn: TWvdSButton; Style: TStyle; begin Btn := TWvdSButton(AControl); (* State-based style selection *) if not Btn.Enabled then Style := Theme.ButtonDisabled else if Btn.Focused then Style := Theme.ButtonFocused else Style := Theme.ButtonBase; (* Render border + caption *) ASurface.DrawBorder(Btn.Bounds, bsSingle); ASurface.DrawText(Btn.Bounds.Left + 1, Btn.Bounds.Top, Btn.Caption, Style); end;
Accessibility (TUI Equivalent)
REQUIRED: - Focus Ring / Highlight (* Clearly visible *) - Hotkey/Accelerator Hint (* Optional: [C]ancel *) - Error State Indicator (* Validation errors visible *)
Input Semantics
Focus Navigation
REQUIRED for every focusable control: - Consume Tab (FocusManager decides movement) - Process Enter/Space correctly - Text input via normalized events (not raw keycodes)
Input Handler Pattern
function TWvdSButtonTUIRenderer.HandleInput(AControl: TWvdSControl; AEvent: TInputEvent): Boolean; var Btn: TWvdSButton; begin Result := False; Btn := TWvdSButton(AControl); if not Btn.Enabled then Exit; if not Btn.Focused then Exit; case AEvent.Kind of iekKey: if AEvent.Key in [vkReturn, vkSpace] then begin if Assigned(Btn.OnClick) then Btn.OnClick(Btn); Result := True; (* Event consumed *) end; iekMouse: if (AEvent.MouseButton = mbLeft) and (AEvent.MouseAction = maClick) then begin if Assigned(Btn.OnClick) then Btn.OnClick(Btn); Result := True; end; end; end;
Layout Semantics
Measure
function TWvdSButtonTUIRenderer.Measure(AControl: TWvdSControl; AAvailable: TSize): TSize; var Btn: TWvdSButton; begin Btn := TWvdSButton(AControl); (* Minimum reasonable size *) Result.Width := Length(Btn.Caption) + 4; (* Padding + Border *) Result.Height := 3; (* Border top/bottom + text *) (* Respect constraints from parent *) if Result.Width > AAvailable.Width then Result.Width := AAvailable.Width; end;
Paint Rules
STRICT: - Draw ONLY within assigned rect - Clipping MUST be active - No out-of-bounds write operations
Virtualization
For controls with large data sets (tables, lists, trees, logs):
REQUIRED: - Render only visible rows/items - No per-row buffer allocation per frame - Manage scroll position correctly
Example: Virtualized List
procedure TWvdSListTUIRenderer.Paint(AControl: TWvdSControl; ASurface: TRenderSurface); var List: TWvdSList; VisibleStart, VisibleEnd: Integer; I, Y: Integer; begin List := TWvdSList(AControl); (* Calculate only visible range *) VisibleStart := List.ScrollOffset; VisibleEnd := VisibleStart + List.VisibleRowCount; if VisibleEnd > List.ItemCount then VisibleEnd := List.ItemCount; (* Render only visible items *) Y := 0; for I := VisibleStart to VisibleEnd - 1 do begin ASurface.DrawText(0, Y, List.Items[I], GetItemStyle(I)); Inc(Y); end; end;
Control Checklist
A) Visual States
[ ] Base state renders correctly [ ] Focus state clearly visible [ ] Disabled state distinguishable [ ] Error/Invalid state visible
B) Input
[ ] Tab navigation works [ ] Enter/Space triggers action (for buttons) [ ] Text input normalized (for TextEdit) [ ] Mouse optionally supported
C) Layout
[ ] Measure returns reasonable size [ ] Paint respects assigned rect [ ] No rendering outside bounds [ ] Resize handled correctly
D) Performance
[ ] Large lists virtualized [ ] No O(N) repaint for offscreen [ ] No unnecessary allocations per frame
Documentation per Control
Document every control: WHY: Why does this control exist (use cases) WHEN: When to use vs. simpler alternatives TUI Notes: - Capability requirements (mouse, images, TrueColor) - Resize behavior (anchoring/responsive) - Known limitations
See also
Zuletzt geändert: on 2026/01/29 at 10:28 PM