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