TUI Controls

Smernice za implementacijo kontrol/gradnikov v TUI cilju.

Ta vzorec razširja obstoječi koncept „Model + Renderer“ s TUI specifičnimi zahtevami.

Arhitektura

Ločitev modela in izrisovalnika

Model (Ciljno neodvisen)          Renderer (Ciljno specifičen)
─────────────────────          ─────────────────────────────
TWvdS* Pascal razred           TUI: CellBuffer preko RenderSurface
- Lastnosti, stanje           GUI: Canvas/GDI
- Dogodki, ukazi              Web: DOM/HTML
- Brez I/O odvisnosti

Izdelki za vsako kontrolo

Komponenta Vsebina
Model enota Lastnosti, dogodki, stanje (ciljno neodvisno)
TUI Renderer enota Paint, Focus, obravnava vnosa
Manifest paketa PXAML oznaka → preslikava enot

Model enota (ciljno neodvisna)

Vsebuje

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;

NE vsebuje

  • Terminal I/O ali ANSI zaporedij
  • DOM/Web API-jev
  • Platformno specifičnih klicev

TUI Renderer enota

Vmesnik

IWvdsTUIRenderer = interface
  (* Razporeditev *)
  function Measure(AControl: TWvdSControl; AAvailable: TSize): TSize;
  procedure Arrange(AControl: TWvdSControl; ARect: TRect);
 
  (* Izrisovanje *)
  procedure Paint(AControl: TWvdSControl; ASurface: TRenderSurface);
 
  (* Vnos *)
  function HandleInput(AControl: TWvdSControl; AEvent: TInputEvent): Boolean;
end;

Minimalna implementacija

OBVEZNO za vsak TUI Renderer:
- Deterministično izrisovanje nadomestka (pred popolnostjo funkcij)
- Prikaz indikatorja fokusa
- Prikaz stanja onemogočeno
- Navigacija s Tab deluje od konca do konca
- Opcijsko: obravnava miške (če TerminalCaps.SupportsMouse)

Vizualna stanja

Hierarhija stanj

Obvezna stanja:
├─ Base         (* Privzeti prikaz *)
├─ Focus        (* Ima tipkovnični fokus *)
├─ Disabled     (* Ni interaktivno *)
└─ Error/Invalid (* Napaka pri preverjanju *)

Opcijska stanja:
├─ Hover        (* Miška nad - če miška podprta *)
└─ Pressed      (* Aktivno pritisnjen *)

Izrisovanje glede na stanje

procedure TWvdSButtonTUIRenderer.Paint(AControl: TWvdSControl;
  ASurface: TRenderSurface);
var
  Btn: TWvdSButton;
  Style: TStyle;
begin
  Btn := TWvdSButton(AControl);
 
  (* Izbira sloga na podlagi stanja *)
  if not Btn.Enabled then
    Style := Theme.ButtonDisabled
  else if Btn.Focused then
    Style := Theme.ButtonFocused
  else
    Style := Theme.ButtonBase;
 
  (* Izriši rob + napis *)
  ASurface.DrawBorder(Btn.Bounds, bsSingle);
  ASurface.DrawText(Btn.Bounds.Left + 1, Btn.Bounds.Top,
    Btn.Caption, Style);
end;

Dostopnost (TUI ekvivalent)

OBVEZNO:
- Obroč fokusa / poudarek    (* Jasno prepoznaven *)
- Namig za bližnjico         (* Opcijsko: [P]rekliči *)
- Indikator stanja napake    (* Napaka pri preverjanju vidna *)

Semantika vnosa

OBVEZNO za vsako fokusabilno kontrolo:
- Tab porabi (FocusManager odloča o premiku)
- Enter/Space pravilno obdela
- Vnos besedila prek normaliziranih dogodkov (ne surovih kod tipk)

Vzorec obravnave vnosa

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;  (* Dogodek porabljen *)
      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;

Semantika razporeditve

Measure

function TWvdSButtonTUIRenderer.Measure(AControl: TWvdSControl;
  AAvailable: TSize): TSize;
var
  Btn: TWvdSButton;
begin
  Btn := TWvdSButton(AControl);
 
  (* Minimalna razumna velikost *)
  Result.Width := Length(Btn.Caption) + 4;  (* Odmik + rob *)
  Result.Height := 3;  (* Rob zgoraj/spodaj + besedilo *)
 
  (* Upoštevaj omejitve starša *)
  if Result.Width > AAvailable.Width then
    Result.Width := AAvailable.Width;
end;

Pravila za Paint

STROGO:
- SAMO znotraj dodeljenega Rect risati
- Obrezovanje MORA biti aktivno
- Brez pisanja izven meja

Virtualizacija

Za kontrole z velikimi količinami podatkov (tabele, seznami, drevesa, dnevniki):

OBVEZNO:
- Izrisuj samo vidne vrstice/elemente
- Brez dodeljevanja medpomnilnika za vsako vrstico v vsakem okvirju
- Pravilno upravljanje položaja drsenja

Primer: Virtualiziran seznam

procedure TWvdSListTUIRenderer.Paint(AControl: TWvdSControl;
  ASurface: TRenderSurface);
var
  List: TWvdSList;
  VisibleStart, VisibleEnd: Integer;
  I, Y: Integer;
begin
  List := TWvdSList(AControl);
 
  (* Izračunaj samo vidno območje *)
  VisibleStart := List.ScrollOffset;
  VisibleEnd := VisibleStart + List.VisibleRowCount;
 
  if VisibleEnd > List.ItemCount then
    VisibleEnd := List.ItemCount;
 
  (* Izriši samo vidne elemente *)
  Y := 0;
  for I := VisibleStart to VisibleEnd - 1 do
  begin
    ASurface.DrawText(0, Y, List.Items[I], GetItemStyle(I));
    Inc(Y);
  end;
end;

Kontrolni seznam za kontrole

A) Vizualna stanja

[ ] Osnovno stanje se pravilno izrisuje
[ ] Stanje fokusa jasno prepoznavno
[ ] Stanje onemogočeno razločljivo
[ ] Stanje napake/neveljavnosti vidno

B) Vnos

[ ] Navigacija s Tab deluje
[ ] Enter/Space sproži akcijo (pri gumbih)
[ ] Vnos besedila normaliziran (pri TextEdit)
[ ] Miška opcijsko podprta

C) Razporeditev

[ ] Measure vrne smiselno velikost
[ ] Paint upošteva dodeljen Rect
[ ] Brez izrisovanja izven meja
[ ] Sprememba velikosti pravilno obdelana

D) Zmogljivost

[ ] Veliki seznami virtualizirani
[ ] Brez O(N) ponovnega izrisovanja za izven zaslona
[ ] Brez nepotrebnih dodeljevanj na okvir

Dokumentacija za vsako kontrolo

Dokumentiraj vsako kontrolo:

WHY:   Zakaj ta kontrola obstaja (primeri uporabe)
WHEN:  Kdaj uporabiti vs. enostavnejše alternative

TUI opombe:
- Zahteve zmogljivosti (Mouse, Images, TrueColor)
- Obnašanje ob spremembi velikosti (Sidranje/Odzivnost)
- Znane omejitve

Glejte tudi

Zuletzt geändert: dne 29.01.2026 ob 22:25