====== 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]]