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