====== TUI Engine ======
Architecture and quality requirements for the TUI rendering engine.
These requirements are **non-negotiable** - they define the minimum standard for GUI-like TUI quality.
===== Quality Requirements =====
==== 1. Flicker-free Rendering ====
REQUIRED:
- Double-buffering with diff-based flush
- Dirty-rect or run-length optimization
- No full-screen redraw loops
**Why:** Flicker destroys user experience and makes TUI unusable for professional applications.
==== 2. Deterministic Layout + Clipping ====
REQUIRED:
- Implement Measure/Arrange/Paint lifecycle
- Clip drawing to assigned rectangles
- No out-of-bounds write operations
==== 3. Unicode Correctness ====
REQUIRED:
- Handle wide characters (East Asian Width) correctly
- Handle combining marks correctly
- Calculate emoji width correctly
- Cursor positioning must be grapheme-aware
**Problem:** "Drifting caret" - cursor wanders with wide chars.
**Solution:** Use grapheme clusters for cursor calculation.
==== 4. Theme + State Layering ====
REQUIRED:
- Support style tokens
- Implement layered states:
Base → Hover (if mouse) → Focus → Pressed → Disabled → Error/Validation
- Consistent focus indicators across all controls
==== 5. Input + Focus as First-Class ====
REQUIRED:
- Focus navigation (Tab/Shift+Tab)
- Deterministic focus ordering
- Normalized input event model:
Keys, text input, resize, optional mouse
==== 6. Performance and Scaling ====
REQUIRED:
- Virtualization for large surfaces (tables/logs/trees)
- Avoid O(N) repaint of offscreen rows/columns
- Efficient memory usage
==== 7. Image Support (SCADA/MES) ====
REQUIRED:
- Implement capability detection
- Fallback chain:
1. Kitty Graphics (preferred)
2. Sixel
3. Placeholder (frame + caption + "image unavailable")
===== Engine Building Blocks =====
==== A) Terminal Capability Layer ====
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) Render Model: CellBuffer + DiffEngine ====
TCell = record
Grapheme: string; (* Unicode Grapheme Cluster *)
Fg: TColor; (* Foreground Color *)
Bg: TColor; (* Background Color *)
Attrs: TAttributes; (* Bold, Italic, Underline, etc. *)
Link: string; (* Optional: Hyperlink *)
ImageRef: Integer; (* Optional: Image Reference *)
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; (* Target frame *)
FFrontBuffer: TCellBuffer; (* Last flushed frame *)
public
procedure ComputeDiff(out ADirtyRects: TRectArray);
procedure Flush(ATerminal: TTerminalIO);
end;
**DiffEngine Requirements:**
* Minimal cursor movements
* Minimal style switches
* Stable during rapid resize
==== C) Render Surface (Drawing API) ====
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;
**Important:** Surface writes only to BackBuffer, not directly to TerminalIO.
==== D) Layout Engine ====
Controls are arranged into rects.
Minimum Containers:
- Stack (vertical/horizontal)
- Dock (Left, Top, Right, Bottom, Fill)
- Grid (later)
- Overlay (for popups/modals)
==== E) Widget/Control Rendering Contract ====
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 =====
==== Snapshot Tests ====
REQUIRED:
- Dump BackBuffer to stable text representation
- Compare with expected output
==== Unicode Fixtures ====
REQUIRED:
- Tests with wide characters (Chinese, Japanese)
- Tests with combining marks (e + accent)
- Tests with emoji
==== Image Fallback Tests ====
REQUIRED:
- Test Kitty → Sixel → Placeholder fallback
- Verify capability detection
===== Verification Checklist =====
TUI Engine Verification:
Rendering:
- [ ] No flicker during repeated repaint
- [ ] Resize produces stable layout
- [ ] No stuck cursor
- [ ] No broken clipping
Unicode:
- [ ] Wide characters positioned correctly
- [ ] Combining marks displayed correctly
- [ ] Emoji width correct
Performance:
- [ ] Table/List renders 10k rows with scroll
- [ ] No O(N) repaint for offscreen
Images:
- [ ] Kitty Graphics works (if supported)
- [ ] Sixel fallback works
- [ ] Placeholder when no support
===== See also =====
* [[.:tui-entwicklung|TUI Development Overview]]
* [[.:tui-controls|TUI Controls]]
* [[.:tui-layout|TUI Layout]]