====== TUI Controls ======
Implementierungsrichtlinien für Controls/Widgets im TUI-Target.
Dieses Pattern erweitert das bestehende "Model + Renderer" Konzept um TUI-spezifische Anforderungen.
===== Architektur =====
==== Model + Renderer Trennung ====
Model (Target-neutral) Renderer (Target-spezifisch)
───────────────────── ─────────────────────────────
TWvdS* Pascal-Klasse TUI: CellBuffer via RenderSurface
- Properties, State GUI: Canvas/GDI
- Events, Commands Web: DOM/HTML
- Keine I/O-Abhängigkeit
==== Deliverables pro Control ====
| Komponente | Inhalt |
^ Model Unit | Properties, Events, State (target-neutral) |
^ TUI Renderer Unit | Paint, Focus, Input Handling |
^ Pack Manifest | PXAML Tag → Units Mapping |
===== Model Unit (Target-neutral) =====
==== Enthält ====
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;
==== Enthält NICHT ====
* Terminal I/O oder ANSI-Sequenzen
* DOM/Web APIs
* Plattform-spezifische Aufrufe
===== 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-Implementierung ====
PFLICHT für jeden TUI Renderer:
- Deterministisches Placeholder-Rendering (vor Feature-Vollständigkeit)
- Focus-Indikator Darstellung
- Disabled-State Darstellung
- Tab-Navigation funktioniert End-to-End
- Optional: Mouse Handling (wenn TerminalCaps.SupportsMouse)
===== Visual States =====
==== State-Hierarchie ====
Pflicht-States:
├─ Base (* Default-Darstellung *)
├─ Focus (* Hat Tastatur-Fokus *)
├─ Disabled (* Nicht interaktiv *)
└─ Error/Invalid (* Validierungsfehler *)
Optional-States:
├─ Hover (* Maus darüber - wenn Mouse supported *)
└─ Pressed (* Aktiv gedrückt *)
==== Rendering pro State ====
procedure TWvdSButtonTUIRenderer.Paint(AControl: TWvdSControl;
ASurface: TRenderSurface);
var
Btn: TWvdSButton;
Style: TStyle;
begin
Btn := TWvdSButton(AControl);
(* State-basierte Style-Auswahl *)
if not Btn.Enabled then
Style := Theme.ButtonDisabled
else if Btn.Focused then
Style := Theme.ButtonFocused
else
Style := Theme.ButtonBase;
(* Border + Caption rendern *)
ASurface.DrawBorder(Btn.Bounds, bsSingle);
ASurface.DrawText(Btn.Bounds.Left + 1, Btn.Bounds.Top,
Btn.Caption, Style);
end;
===== Accessibility (TUI-Äquivalent) =====
PFLICHT:
- Focus Ring / Highlight (* Klar erkennbar *)
- Hotkey/Accelerator Hint (* Optional: [A]bbrechen *)
- Error State Indicator (* Validierungsfehler sichtbar *)
===== Input Semantics =====
==== Focus Navigation ====
PFLICHT für jedes fokussierbare Control:
- Tab konsumieren (FocusManager entscheidet Bewegung)
- Enter/Space korrekt verarbeiten
- Text Input über normalisierte Events (nicht 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 konsumiert *)
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);
(* Minimale vernünftige Größe *)
Result.Width := Length(Btn.Caption) + 4; (* Padding + Border *)
Result.Height := 3; (* Border oben/unten + Text *)
(* Constraints vom Parent respektieren *)
if Result.Width > AAvailable.Width then
Result.Width := AAvailable.Width;
end;
==== Paint-Regeln ====
STRENG:
- NUR innerhalb des zugewiesenen Rect zeichnen
- Clipping MUSS aktiv sein
- Keine Out-of-Bounds Schreiboperationen
===== Virtualisierung =====
Für Controls mit großen Datenmengen (Tables, Lists, Trees, Logs):
PFLICHT:
- Nur sichtbare Rows/Items rendern
- Keine Per-Row Buffer-Allokation pro Frame
- Scroll-Position korrekt verwalten
==== Beispiel: Virtualisierte Liste ====
procedure TWvdSListTUIRenderer.Paint(AControl: TWvdSControl;
ASurface: TRenderSurface);
var
List: TWvdSList;
VisibleStart, VisibleEnd: Integer;
I, Y: Integer;
begin
List := TWvdSList(AControl);
(* Nur sichtbaren Bereich berechnen *)
VisibleStart := List.ScrollOffset;
VisibleEnd := VisibleStart + List.VisibleRowCount;
if VisibleEnd > List.ItemCount then
VisibleEnd := List.ItemCount;
(* Nur sichtbare Items rendern *)
Y := 0;
for I := VisibleStart to VisibleEnd - 1 do
begin
ASurface.DrawText(0, Y, List.Items[I], GetItemStyle(I));
Inc(Y);
end;
end;
===== Control Checkliste =====
==== A) Visual States ====
[ ] Base State rendert korrekt
[ ] Focus State klar erkennbar
[ ] Disabled State unterscheidbar
[ ] Error/Invalid State sichtbar
==== B) Input ====
[ ] Tab-Navigation funktioniert
[ ] Enter/Space löst Aktion aus (bei Buttons)
[ ] Text Input normalisiert (bei TextEdit)
[ ] Mouse optional unterstützt
==== C) Layout ====
[ ] Measure gibt sinnvolle Größe zurück
[ ] Paint respektiert zugewiesenes Rect
[ ] Kein Rendering außerhalb Bounds
[ ] Resize wird korrekt behandelt
==== D) Performance ====
[ ] Große Listen virtualisiert
[ ] Kein O(N) Repaint für Offscreen
[ ] Keine unnötigen Allokationen pro Frame
===== Dokumentation pro Control =====
Jedes Control dokumentieren:
WHY: Warum existiert dieses Control (Use Cases)
WHEN: Wann verwenden vs. einfachere Alternativen
TUI Notes:
- Capability Requirements (Mouse, Images, TrueColor)
- Resize Behavior (Anchoring/Responsive)
- Known Limitations
===== Siehe auch =====
* [[.:tui-entwicklung|TUI-Entwicklung Übersicht]]
* [[.:tui-engine|TUI Engine]]
* [[.:tui-layout|TUI Layout]]