TUI Controls

Smjernice implementacije za Controls/Widgets u TUI-Targetu.

Ovaj pattern proširuje postojeći „Model + Renderer“ koncept s TUI-specifičnim zahtjevima.

Arhitektura

Model + Renderer Razdvajanje

Model (Target-neutralan)          Renderer (Target-specifičan)
─────────────────────          ─────────────────────────────
TWvdS* Pascal-klasa            TUI: CellBuffer via RenderSurface
- Properties, State            GUI: Canvas/GDI
- Events, Commands             Web: DOM/HTML
- Bez I/O-ovisnosti

Deliverables po Controlu

Komponenta Sadržaj
Model Unit Properties, Events, State (target-neutralno)
TUI Renderer Unit Paint, Focus, Input Handling
Pack Manifest PXAML Tag → Units Mapping

Model Unit (Target-neutralno)

Sadrži

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 sadrži

  • Terminal I/O ili ANSI-sekvence
  • DOM/Web APIs
  • Platformno-specifične pozive

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;

Minimalna implementacija

OBAVEZNO za svaki TUI Renderer:
- Deterministički Placeholder-rendering (prije Feature-potpunosti)
- Prikaz Focus-Indikatora
- Prikaz Disabled-Statea
- Tab-Navigacija funkcionira End-to-End
- Opcionalno: Mouse Handling (ako TerminalCaps.SupportsMouse)

Visual States

State-Hijerarhija

Obavezni States:
├─ Base         (* Default-prikaz *)
├─ Focus        (* Ima tipkovnički fokus *)
├─ Disabled     (* Nije interaktivan *)
└─ Error/Invalid (* Validacijska greška *)

Opcionalni States:
├─ Hover        (* Miš iznad - ako Mouse podržan *)
└─ Pressed      (* Aktivno pritisnut *)

Rendering po Stateu

procedure TWvdSButtonTUIRenderer.Paint(AControl: TWvdSControl;
  ASurface: TRenderSurface);
var
  Btn: TWvdSButton;
  Style: TStyle;
begin
  Btn := TWvdSButton(AControl);
 
  (* State-bazirani odabir Stylea *)
  if not Btn.Enabled then
    Style := Theme.ButtonDisabled
  else if Btn.Focused then
    Style := Theme.ButtonFocused
  else
    Style := Theme.ButtonBase;
 
  (* Renderiranje Bordera + Captiona *)
  ASurface.DrawBorder(Btn.Bounds, bsSingle);
  ASurface.DrawText(Btn.Bounds.Left + 1, Btn.Bounds.Top,
    Btn.Caption, Style);
end;

Accessibility (TUI-Ekvivalent)

OBAVEZNO:
- Focus Ring / Highlight    (* Jasno prepoznatljivo *)
- Hotkey/Accelerator Hint   (* Opcionalno: [O]dustani *)
- Error State Indicator     (* Validacijska greška vidljiva *)

Input Semantics

Focus Navigation

OBAVEZNO za svaki fokusirajući Control:
- Tab konzumirati (FocusManager odlučuje o pomicanju)
- Enter/Space ispravno obraditi
- Text Input preko normaliziranih Eventa (ne 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 konzumiran *)
      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);
 
  (* Minimalna razumna veličina *)
  Result.Width := Length(Btn.Caption) + 4;  (* Padding + Border *)
  Result.Height := 3;  (* Border gore/dolje + Text *)
 
  (* Poštivanje Constrainta od Parenta *)
  if Result.Width > AAvailable.Width then
    Result.Width := AAvailable.Width;
end;

Paint-Pravila

STRIKTNO:
- Crtati SAMO unutar dodijeljenog Recta
- Clipping MORA biti aktivan
- Nikakve Out-of-Bounds pisanja

Virtualizacija

Za Controls s velikim količinama podataka (Tables, Lists, Trees, Logs):

OBAVEZNO:
- Renderirati samo vidljive Rows/Items
- Nikakve Per-Row Buffer-alokacije po Frameu
- Ispravno upravljati Scroll-pozicijom

Primjer: Virtualizirana Lista

procedure TWvdSListTUIRenderer.Paint(AControl: TWvdSControl;
  ASurface: TRenderSurface);
var
  List: TWvdSList;
  VisibleStart, VisibleEnd: Integer;
  I, Y: Integer;
begin
  List := TWvdSList(AControl);
 
  (* Izračunati samo vidljivo područje *)
  VisibleStart := List.ScrollOffset;
  VisibleEnd := VisibleStart + List.VisibleRowCount;
 
  if VisibleEnd > List.ItemCount then
    VisibleEnd := List.ItemCount;
 
  (* Renderirati samo vidljive iteme *)
  Y := 0;
  for I := VisibleStart to VisibleEnd - 1 do
  begin
    ASurface.DrawText(0, Y, List.Items[I], GetItemStyle(I));
    Inc(Y);
  end;
end;

Control Checklista

A) Visual States

[ ] Base State renderira ispravno
[ ] Focus State jasno prepoznatljiv
[ ] Disabled State razlikuje se
[ ] Error/Invalid State vidljiv

B) Input

[ ] Tab-Navigacija funkcionira
[ ] Enter/Space pokreće akciju (kod Buttona)
[ ] Text Input normaliziran (kod TextEdita)
[ ] Mouse opcionalno podržan

C) Layout

[ ] Measure vraća razumnu veličinu
[ ] Paint poštuje dodijeljeni Rect
[ ] Nema renderiranja izvan Boundsa
[ ] Resize se ispravno obrađuje

D) Performanse

[ ] Velike liste virtualizirane
[ ] Nema O(N) Repainta za Offscreen
[ ] Nema nepotrebnih alokacija po Frameu

Dokumentacija po Controlu

Svaki Control dokumentirati:

WHY:   Zašto ovaj Control postoji (Use Cases)
WHEN:  Kada koristiti vs. jednostavnije alternative

TUI Notes:
- Capability Requirements (Mouse, Images, TrueColor)
- Resize Behavior (Anchoring/Responsive)
- Known Limitations

Vidi također

Zuletzt geändert: 29.01.2026. u 22:40