Controlli TUI

Linee guida di implementazione per controlli/widget nel target TUI.

Questo pattern estende il concetto esistente „Model + Renderer“ con requisiti specifici TUI.

Architettura

Separazione Model + Renderer

Model (Target-neutral)          Renderer (Target-specifico)
─────────────────────          ─────────────────────────────
Classe Pascal TWvdS*           TUI: CellBuffer via RenderSurface
- Properties, stato            GUI: Canvas/GDI
- Eventi, comandi              Web: DOM/HTML
- Nessuna dipendenza I/O

Deliverable per controllo

Componente Contenuto
Unit Model Properties, eventi, stato (target-neutral)
Unit TUI Renderer Paint, focus, gestione input
Pack Manifest Mapping tag PXAML → unit

Unit Model (Target-neutral)

Contiene

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;

NON contiene

  • Terminal I/O o sequenze ANSI
  • API DOM/Web
  • Chiamate specifiche della piattaforma

Unit TUI Renderer

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;

Implementazione minima

OBBLIGATORIO per ogni TUI Renderer:
- Rendering placeholder deterministico (prima della completezza feature)
- Visualizzazione indicatore focus
- Visualizzazione stato disabled
- Navigazione Tab funzionante end-to-end
- Opzionale: Gestione mouse (se TerminalCaps.SupportsMouse)

Stati visuali

Gerarchia stati

Stati obbligatori:
├─ Base         (* Visualizzazione default *)
├─ Focus        (* Ha il focus tastiera *)
├─ Disabled     (* Non interattivo *)
└─ Error/Invalid (* Errore validazione *)

Stati opzionali:
├─ Hover        (* Mouse sopra - se mouse supportato *)
└─ Pressed      (* Premuto attivamente *)

Rendering per stato

procedure TWvdSButtonTUIRenderer.Paint(AControl: TWvdSControl;
  ASurface: TRenderSurface);
var
  Btn: TWvdSButton;
  Style: TStyle;
begin
  Btn := TWvdSButton(AControl);
 
  (* Selezione stile basata su stato *)
  if not Btn.Enabled then
    Style := Theme.ButtonDisabled
  else if Btn.Focused then
    Style := Theme.ButtonFocused
  else
    Style := Theme.ButtonBase;
 
  (* Renderizzare bordo + caption *)
  ASurface.DrawBorder(Btn.Bounds, bsSingle);
  ASurface.DrawText(Btn.Bounds.Left + 1, Btn.Bounds.Top,
    Btn.Caption, Style);
end;

Accessibilita (equivalente TUI)

OBBLIGATORIO:
- Focus Ring / Highlight    (* Chiaramente riconoscibile *)
- Hint Hotkey/Acceleratore  (* Opzionale: [A]nnulla *)
- Indicatore stato errore   (* Errori validazione visibili *)

Semantica input

OBBLIGATORIO per ogni controllo focalizzabile:
- Consumare Tab (FocusManager decide il movimento)
- Elaborare correttamente Enter/Space
- Input testo via eventi normalizzati (non raw keycode)

Pattern handler input

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;  (* Evento consumato *)
      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;

Semantica layout

Measure

function TWvdSButtonTUIRenderer.Measure(AControl: TWvdSControl;
  AAvailable: TSize): TSize;
var
  Btn: TWvdSButton;
begin
  Btn := TWvdSButton(AControl);
 
  (* Dimensione minima ragionevole *)
  Result.Width := Length(Btn.Caption) + 4;  (* Padding + bordo *)
  Result.Height := 3;  (* Bordo sopra/sotto + testo *)
 
  (* Rispettare constraint dal parent *)
  if Result.Width > AAvailable.Width then
    Result.Width := AAvailable.Width;
end;

Regole Paint

RIGOROSO:
- Disegnare SOLO all'interno del rect assegnato
- Clipping DEVE essere attivo
- Nessuna operazione di rendering fuori bounds

Virtualizzazione

Per controlli con grandi quantità di dati (tabelle, liste, alberi, log):

OBBLIGATORIO:
- Renderizzare solo righe/elementi visibili
- Nessuna allocazione buffer per riga per frame
- Gestire correttamente posizione scroll

Esempio: Lista virtualizzata

procedure TWvdSListTUIRenderer.Paint(AControl: TWvdSControl;
  ASurface: TRenderSurface);
var
  List: TWvdSList;
  VisibleStart, VisibleEnd: Integer;
  I, Y: Integer;
begin
  List := TWvdSList(AControl);
 
  (* Calcolare solo area visibile *)
  VisibleStart := List.ScrollOffset;
  VisibleEnd := VisibleStart + List.VisibleRowCount;
 
  if VisibleEnd > List.ItemCount then
    VisibleEnd := List.ItemCount;
 
  (* Renderizzare solo elementi visibili *)
  Y := 0;
  for I := VisibleStart to VisibleEnd - 1 do
  begin
    ASurface.DrawText(0, Y, List.Items[I], GetItemStyle(I));
    Inc(Y);
  end;
end;

Checklist controllo

A) Stati visuali

[ ] Stato base renderizza correttamente
[ ] Stato focus chiaramente riconoscibile
[ ] Stato disabled distinguibile
[ ] Stato errore/invalid visibile

B) Input

[ ] Navigazione Tab funziona
[ ] Enter/Space attiva azione (per button)
[ ] Input testo normalizzato (per TextEdit)
[ ] Mouse supportato opzionalmente

C) Layout

[ ] Measure restituisce dimensione sensata
[ ] Paint rispetta rect assegnato
[ ] Nessun rendering fuori bounds
[ ] Resize gestito correttamente

D) Performance

[ ] Liste grandi virtualizzate
[ ] Nessun repaint O(N) per offscreen
[ ] Nessuna allocazione inutile per frame

Documentazione per controllo

Documentare ogni controllo:

WHY:   Perché esiste questo controllo (casi d'uso)
WHEN:  Quando usarlo vs alternative più semplici

Note TUI:
- Requisiti capability (mouse, immagini, TrueColor)
- Comportamento resize (anchoring/responsive)
- Limitazioni note

Vedi anche

Zuletzt geändert: il 30/01/2026 alle 01:32