Inhaltsverzeichnis

TUI Layout

Anchoring-First Responsive Layout für TUI-Anwendungen.

Anchoring ist der Default-Modus - jedes Control verhält sich korrekt bei Terminal-Resize ohne spezielle Container.

Grundprinzip

Anchoring-First bedeutet:
- Terminal Resize darf Layout, Focus und Rendering nicht brechen
- Controls behalten stabile räumliche Beziehungen
- Vorhersagbare Expansion/Shrinking-Regeln

Anchor-Semantik

Verfügbare Anchors

Anchor Bedeutung
Left Abstand zum linken Rand bleibt konstant
Top Abstand zum oberen Rand bleibt konstant
Right Abstand zum rechten Rand bleibt konstant
Bottom Abstand zum unteren Rand bleibt konstant

Kombinationen

Default: Left + Top
→ Position bleibt stabil, Größe konstant

Left + Right:
→ Breite dehnt/schrumpft mit Parent-Breite

Top + Bottom:
→ Höhe dehnt/schrumpft mit Parent-Höhe

Alle vier (Left + Top + Right + Bottom):
→ Rect dehnt sich in beide Richtungen

Keine Anchors:
→ Behandeln wie Left + Top (keine "floating" Ambiguität)

PXAML Beispiele

<!-- Feste Position oben links -->
<Button Anchors="Left,Top" Text="OK" />
 
<!-- Volle Breite, feste Höhe -->
<TextEdit Anchors="Left,Top,Right" Height="3" />
 
<!-- Füllt gesamten verfügbaren Bereich -->
<ListView Anchors="Left,Top,Right,Bottom" />
 
<!-- Statusleiste unten -->
<StatusBar Anchors="Left,Right,Bottom" Height="1" />

Resize-Verhalten

Ablauf bei Resize

1. Resize Event empfangen
   └─ Root Available Rect aktualisieren

2. Layout invalidieren
   └─ Measure/Arrange Pass durchführen

3. Focus erhalten
   └─ Gleicher logischer Control behält Focus

4. Neu rendern
   └─ Paint → DiffFlush

Deterministisch

PFLICHT:
- Gleicher Input → Gleiches Layout
- Kein Flicker bei schnellem Resize
- Kein Cursor-Corruption
- Focus bleibt auf logischem Control

Breakpoints

Optionale aber empfohlene Resize-Schwellwerte:

Standard-Breakpoints

Breakpoint Breite Typisches Layout
Narrow < 80 Single-Column, gestapelt
Medium 80-119 Sidebar collapsed zu Tabs
Wide >= 120 Sidebar + Content nebeneinander

PXAML Konfiguration

<Panel ResponsiveMode="Auto" Breakpoints="80,120">
  <!-- Automatisches Reflow bei Breakpoint-Überschreitung -->
</Panel>

Breakpoint-Regeln

PFLICHT:
- Breakpoints NICHT "magic" - in PXAML oder Theme Config definieren
- Breakpoints dokumentieren
- Verhalten bei jedem Breakpoint klar definieren

Layout-Container

Stack

Orientierung: Vertikal oder Horizontal
Kinder werden nacheinander angeordnet
<Stack Orientation="Vertical">
  <Label Text="Name:" />
  <TextEdit />
  <Label Text="Email:" />
  <TextEdit />
</Stack>

Dock

Positionen: Left, Top, Right, Bottom, Fill
Kinder docken an Seiten, Rest füllt Mitte
<Dock>
  <MenuBar Dock="Top" />
  <StatusBar Dock="Bottom" />
  <Sidebar Dock="Left" Width="20" />
  <Content Dock="Fill" />
</Dock>

Overlay

Für Popups, Modals, Tooltips
Überlagert andere Controls
Muss innerhalb Screen Bounds bleiben (clamped)
<Overlay>
  <Dialog X="10" Y="5" Width="40" Height="10">
    <!-- Modal Content -->
  </Dialog>
</Overlay>

Grid (später)

Zeilen und Spalten definieren
Controls in Zellen platzieren

Anchoring-Precedence

Reihenfolge der Layout-Berechnung:

1. Container Layout (wenn explizit)
   └─ Stack/Grid/Dock/Overlay berechnet Child-Rects

2. Anchors anwenden
   └─ Innerhalb des Container-Rects verfeinern
   └─ Min/Max beachten
   └─ Margins/Padding erhalten

3. Clipping zuletzt
   └─ Finale Bounds beschneiden

Scroll und Viewport

Wenn Content größer als Bereich

BEVORZUGT:
- ScrollViewer Container verwenden
- Content scrollbar machen

NICHT als Default:
- Text "shrink to fit"

PFLICHT:
- Controls können in kleinerem Rect rendern (Clip + Ellipsis)
- State darf nicht verloren gehen

ScrollViewer Beispiel

<ScrollViewer Anchors="Left,Top,Right,Bottom">
  <Stack Orientation="Vertical">
    <!-- Lange Liste von Controls -->
  </Stack>
</ScrollViewer>

Focus unter Reflow

PFLICHT:
- Focus wird über Control-Identität getrackt (nicht Screen-Position)
- Nach Reflow:
  - Wenn fokussiertes Control noch fokussierbar und sichtbar → behalten
  - Sonst: Fallback auf nächstes fokussierbares Sibling in Focus-Order

Focus-Stabilität

procedure TLayoutEngine.ApplyReflow;
var
  PreviousFocus: TWvdSControl;
begin
  (* Focus merken *)
  PreviousFocus := FocusManager.FocusedControl;
 
  (* Layout neu berechnen *)
  MeasureAndArrange(RootControl);
 
  (* Focus wiederherstellen *)
  if (PreviousFocus <> nil) and
     PreviousFocus.CanFocus and
     PreviousFocus.IsVisible then
    FocusManager.SetFocus(PreviousFocus)
  else
    FocusManager.FocusNextAvailable;
end;

Verifikation

Resize-Tests

[ ] Narrow ↔ Wide wiederholt: kein Flicker
[ ] Cursor nicht korrupt nach Resize
[ ] Focus bleibt auf gleichem Control
[ ] Anchored Stretch Controls überlappen nicht
[ ] Popups/Overlays bleiben in Screen Bounds

Breakpoint-Tests

[ ] Layout wechselt korrekt bei Breakpoint-Überschreitung
[ ] Kein Flicker beim Breakpoint-Wechsel
[ ] Alle Breakpoints dokumentiert

Container-Tests

[ ] Stack ordnet Kinder korrekt an
[ ] Dock füllt korrekt (Left, Top, Right, Bottom, Fill)
[ ] Overlay bleibt in Bounds
[ ] Nested Containers funktionieren

PXAML Referenz

Control-Attribute

Attribut Werte Bedeutung
Anchors Left,Top,Right,Bottom Anchor-Kombinationen
Margin „l,t,r,b“ oder „all“ Äußerer Abstand
Padding „l,t,r,b“ oder „all“ Innerer Abstand
MinWidth Integer Minimale Breite
MaxWidth Integer Maximale Breite
MinHeight Integer Minimale Höhe
MaxHeight Integer Maximale Höhe

Container-Attribute

Attribut Werte Bedeutung
ResponsiveMode Auto, Manual Automatisches Breakpoint-Handling
Breakpoints „w1,w2,…“ Breakpoint-Breiten

Siehe auch