Layout TUI

Layout responsive anchoring-first per applicazioni TUI.

L'anchoring e la modalita default - ogni controllo si comporta correttamente al resize del terminale senza container speciali.

Principio fondamentale

Anchoring-First significa:
- Il resize del terminale non deve rompere layout, focus e rendering
- I controlli mantengono relazioni spaziali stabili
- Regole prevedibili di espansione/contrazione

Semantica anchor

Anchor disponibili

Anchor Significato
Left Distanza dal bordo sinistro rimane costante
Top Distanza dal bordo superiore rimane costante
Right Distanza dal bordo destro rimane costante
Bottom Distanza dal bordo inferiore rimane costante

Combinazioni

Default: Left + Top
→ Posizione rimane stabile, dimensione costante

Left + Right:
→ Larghezza si espande/contrae con larghezza parent

Top + Bottom:
→ Altezza si espande/contrae con altezza parent

Tutti e quattro (Left + Top + Right + Bottom):
→ Rect si espande in entrambe le direzioni

Nessun anchor:
→ Trattare come Left + Top (nessuna ambiguita "floating")

Esempi PXAML

<!-- Posizione fissa in alto a sinistra -->
<Button Anchors="Left,Top" Text="OK" />
 
<!-- Larghezza piena, altezza fissa -->
<TextEdit Anchors="Left,Top,Right" Height="3" />
 
<!-- Riempie l'intera area disponibile -->
<ListView Anchors="Left,Top,Right,Bottom" />
 
<!-- Barra di stato in basso -->
<StatusBar Anchors="Left,Right,Bottom" Height="1" />

Comportamento resize

Flusso al resize

1. Evento resize ricevuto
   └─ Aggiornare rect disponibile root

2. Invalidare layout
   └─ Eseguire passaggio Measure/Arrange

3. Mantenere focus
   └─ Stesso controllo logico mantiene il focus

4. Re-renderizzare
   └─ Paint → DiffFlush

Deterministico

OBBLIGATORIO:
- Stesso input → stesso layout
- Nessun flicker con resize veloce
- Nessuna corruzione cursore
- Focus rimane sul controllo logico

Breakpoint

Soglie di resize opzionali ma raccomandate:

Breakpoint standard

Breakpoint Larghezza Layout tipico
Narrow < 80 Colonna singola, impilato
Medium 80-119 Sidebar collassata in tab
Wide >= 120 Sidebar + contenuto affiancati

Configurazione PXAML

<Panel ResponsiveMode="Auto" Breakpoints="80,120">
  <!-- Reflow automatico al superamento breakpoint -->
</Panel>

Regole breakpoint

OBBLIGATORIO:
- I breakpoint NON sono "magici" - definire in PXAML o config tema
- Documentare i breakpoint
- Definire chiaramente il comportamento per ogni breakpoint

Container layout

Stack

Orientamento: Verticale o orizzontale
I figli vengono disposti in sequenza
<Stack Orientation="Vertical">
  <Label Text="Nome:" />
  <TextEdit />
  <Label Text="Email:" />
  <TextEdit />
</Stack>

Dock

Posizioni: Left, Top, Right, Bottom, Fill
I figli si agganciano ai lati, il resto riempie il centro
<Dock>
  <MenuBar Dock="Top" />
  <StatusBar Dock="Bottom" />
  <Sidebar Dock="Left" Width="20" />
  <Content Dock="Fill" />
</Dock>

Overlay

Per popup, modali, tooltip
Si sovrappone ad altri controlli
Deve rimanere entro i bounds dello schermo (clamped)
<Overlay>
  <Dialog X="10" Y="5" Width="40" Height="10">
    <!-- Contenuto modale -->
  </Dialog>
</Overlay>

Grid (futuro)

Definire righe e colonne
Posizionare controlli nelle celle

Precedenza anchoring

Ordine di calcolo del layout:

1. Layout container (se esplicito)
   └─ Stack/Grid/Dock/Overlay calcola rect figli

2. Applicare anchor
   └─ Raffinare all'interno del rect container
   └─ Rispettare Min/Max
   └─ Preservare margin/padding

3. Clipping per ultimo
   └─ Ritagliare bounds finali

Scroll e viewport

Quando il contenuto e piu grande dell'area

PREFERITO:
- Usare container ScrollViewer
- Rendere il contenuto scrollabile

NON come default:
- Testo "shrink to fit"

OBBLIGATORIO:
- I controlli possono renderizzare in rect piu piccolo (clip + ellipsis)
- Lo stato non deve andare perso

Esempio ScrollViewer

<ScrollViewer Anchors="Left,Top,Right,Bottom">
  <Stack Orientation="Vertical">
    <!-- Lista lunga di controlli -->
  </Stack>
</ScrollViewer>

Focus durante reflow

OBBLIGATORIO:
- Il focus viene tracciato tramite identita del controllo (non posizione schermo)
- Dopo il reflow:
  - Se il controllo focalizzato e ancora focalizzabile e visibile → mantenere
  - Altrimenti: fallback al prossimo sibling focalizzabile nell'ordine focus

Stabilita focus

procedure TLayoutEngine.ApplyReflow;
var
  PreviousFocus: TWvdSControl;
begin
  (* Memorizzare focus *)
  PreviousFocus := FocusManager.FocusedControl;
 
  (* Ricalcolare layout *)
  MeasureAndArrange(RootControl);
 
  (* Ripristinare focus *)
  if (PreviousFocus <> nil) and
     PreviousFocus.CanFocus and
     PreviousFocus.IsVisible then
    FocusManager.SetFocus(PreviousFocus)
  else
    FocusManager.FocusNextAvailable;
end;

Verifica

Test resize

[ ] Narrow ↔ Wide ripetuto: nessun flicker
[ ] Cursore non corrotto dopo resize
[ ] Focus rimane sullo stesso controllo
[ ] Controlli anchored stretch non si sovrappongono
[ ] Popup/overlay rimangono nei bounds schermo

Test breakpoint

[ ] Layout cambia correttamente al superamento breakpoint
[ ] Nessun flicker al cambio breakpoint
[ ] Tutti i breakpoint documentati

Test container

[ ] Stack dispone i figli correttamente
[ ] Dock riempie correttamente (Left, Top, Right, Bottom, Fill)
[ ] Overlay rimane nei bounds
[ ] Container annidati funzionano

Riferimento PXAML

Attributi controllo

Attributo Valori Significato
Anchors Left,Top,Right,Bottom Combinazioni anchor
Margin „l,t,r,b“ o „all“ Distanza esterna
Padding „l,t,r,b“ o „all“ Distanza interna
MinWidth Integer Larghezza minima
MaxWidth Integer Larghezza massima
MinHeight Integer Altezza minima
MaxHeight Integer Altezza massima

Attributi container

Attributo Valori Significato
ResponsiveMode Auto, Manual Gestione automatica breakpoint
Breakpoints „w1,w2,…“ Larghezze breakpoint

Vedi anche

Zuletzt geändert: il 29/01/2026 alle 22:41