====== 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 =====
* [[.:tui-entwicklung|TUI Development Overview]]
* [[.:tui-engine|TUI Engine]]
* [[.:tui-layout|TUI Layout]]