====== TUI Engine ======
Architettura e requisiti di qualità del TUI Rendering Engine.
Questi requisiti sono **non negoziabili** - definiscono lo standard minimo per qualità TUI simile alla GUI.
===== Requisiti di qualità =====
==== 1. Rendering flicker-free ====
OBBLIGATORIO:
- Double buffering con flush basato su diff
- Ottimizzazione dirty-rect o run-length
- Nessun loop di redraw full-screen
**Perché:** Il flicker distrugge l'esperienza utente e rende la TUI inutilizzabile per applicazioni professionali.
==== 2. Layout deterministico + clipping ====
OBBLIGATORIO:
- Implementare ciclo di vita Measure/Arrange/Paint
- Clippare il disegno ai rettangoli assegnati
- Nessuna operazione di scrittura out-of-bounds
==== 3. Correttezza Unicode ====
OBBLIGATORIO:
- Gestire correttamente wide character (East Asian Width)
- Gestire correttamente combining mark
- Calcolare correttamente larghezza emoji
- Posizionamento cursore deve essere grapheme-aware
**Problema:** "Drifting Caret" - il cursore deriva con i wide char.
**Soluzione:** Usare grapheme cluster per il calcolo del cursore.
==== 4. Theme + State Layering ====
OBBLIGATORIO:
- Supportare token di stile
- Implementare stati stratificati:
Base → Hover (se mouse) → Focus → Pressed → Disabled → Error/Validation
- Indicatori focus consistenti su tutti i controlli
==== 5. Input + Focus come first-class ====
OBBLIGATORIO:
- Navigazione focus (Tab/Shift+Tab)
- Ordinamento focus deterministico
- Modello eventi input normalizzato:
Tasti, input testo, resize, mouse opzionale
==== 6. Performance e scalabilita ====
OBBLIGATORIO:
- Virtualizzazione per surface grandi (tabelle/log/alberi)
- Evitare repaint O(N) di righe/colonne offscreen
- Uso memoria efficiente
==== 7. Supporto immagini (SCADA/MES) ====
OBBLIGATORIO:
- Implementare rilevamento capability
- Catena fallback:
1. Kitty Graphics (preferito)
2. Sixel
3. Placeholder (frame + caption + "image unavailable")
===== Componenti engine =====
==== A) Layer Terminal Capability ====
TTerminalCaps = record
SupportsAnsi: Boolean;
SupportsAltScreen: Boolean;
SupportsTrueColor: Boolean;
Supports256Color: Boolean;
SupportsMouse: Boolean;
SupportsKittyGraphics: Boolean;
SupportsSixel: Boolean;
SupportsUnicodeWidth: Boolean;
end;
TTerminalIO = class
procedure EnterAltScreen;
procedure ExitAltScreen;
procedure ShowCursor;
procedure HideCursor;
procedure WriteEscapeSequence(const ASeq: string);
procedure WriteTextRun(const AText: string);
procedure MoveCursor(AX, AY: Integer);
procedure SetStyle(AStyle: TStyle);
procedure BatchFlush;
end;
==== B) Modello render: CellBuffer + DiffEngine ====
TCell = record
Grapheme: string; (* Unicode Grapheme Cluster *)
Fg: TColor; (* Foreground Color *)
Bg: TColor; (* Background Color *)
Attrs: TAttributes; (* Bold, Italic, Underline, ecc. *)
Link: string; (* Opzionale: Hyperlink *)
ImageRef: Integer; (* Opzionale: Riferimento immagine *)
end;
TCellBuffer = class
private
FCells: array of array of TCell;
FWidth, FHeight: Integer;
public
procedure SetCell(AX, AY: Integer; const ACell: TCell);
function GetCell(AX, AY: Integer): TCell;
procedure Clear;
procedure Resize(AWidth, AHeight: Integer);
end;
**DiffEngine:**
TDiffEngine = class
private
FBackBuffer: TCellBuffer; (* Frame target *)
FFrontBuffer: TCellBuffer; (* Ultimo frame flushato *)
public
procedure ComputeDiff(out ADirtyRects: TRectArray);
procedure Flush(ATerminal: TTerminalIO);
end;
**Requisiti per DiffEngine:**
* Movimenti cursore minimi
* Cambi stile minimi
* Stabile con resize veloce
==== C) Render Surface (API disegno) ====
TRenderSurface = class
private
FBuffer: TCellBuffer;
FClipStack: TRectStack;
public
procedure FillRect(ARect: TRect; AChar: Char; AStyle: TStyle);
procedure DrawText(AX, AY: Integer; const AText: string; AStyle: TStyle);
procedure DrawBorder(ARect: TRect; ABorderStyle: TBorderStyle);
procedure DrawImage(ARect: TRect; AImageRef: Integer);
procedure ClipPush(ARect: TRect);
procedure ClipPop;
end;
**Importante:** Surface scrive solo in BackBuffer, non direttamente in TerminalIO.
==== D) Layout Engine ====
I controlli vengono disposti in rect.
Container minimi:
- Stack (verticale/orizzontale)
- Dock (Left, Top, Right, Bottom, Fill)
- Grid (successivo)
- Overlay (per popup/modali)
==== E) Contratto rendering Widget/Control ====
IWvdSTUIRenderer = interface
function Measure(AControl: TWvdSControl; AAvailable: TSize): TSize;
procedure Arrange(AControl: TWvdSControl; ARect: TRect);
procedure Paint(AControl: TWvdSControl; ASurface: TRenderSurface);
function HandleInput(AControl: TWvdSControl; AEvent: TInputEvent): Boolean;
end;
===== Testing =====
==== Test snapshot ====
OBBLIGATORIO:
- Dump BackBuffer in rappresentazione testuale stabile
- Confronto con output atteso
==== Fixture Unicode ====
OBBLIGATORIO:
- Test con wide character (cinese, giapponese)
- Test con combining mark (e = e + accento)
- Test con emoji
==== Test fallback immagini ====
OBBLIGATORIO:
- Testare fallback Kitty → Sixel → Placeholder
- Verificare rilevamento capability
===== Checklist verifica =====
Verifica TUI Engine:
Rendering:
- [ ] Nessun flicker al repaint ripetuto
- [ ] Resize produce layout stabile
- [ ] Nessun cursore bloccato
- [ ] Nessun clipping rotto
Unicode:
- [ ] Wide character posizionati correttamente
- [ ] Combining mark visualizzati correttamente
- [ ] Larghezza emoji corretta
Performance:
- [ ] Table/List renderizza 10k righe con scroll
- [ ] Nessun repaint O(N) per offscreen
Immagini:
- [ ] Kitty Graphics funziona (se supportato)
- [ ] Fallback Sixel funziona
- [ ] Placeholder se non supportato
===== Vedi anche =====
* [[.:tui-entwicklung|Panoramica sviluppo TUI]]
* [[.:tui-controls|Controlli TUI]]
* [[.:tui-layout|Layout TUI]]