From ff4e7a71e03156e8cd1be752432ce71a2748eb9e Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Tue, 22 Sep 2026 16:13:34 +0200 Subject: [PATCH] Trasforma la barra di navigazione in una floatbar e uniforma i bottoni Avanti/Indietro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La barra Avanti/Indietro era un footer bianco a tutta larghezza con una linea di separazione da 1px. Ora è una card bianca staccata su tutti e 4 i lati dalla finestra (UiStile.FloatBar, angoli arrotondati, bordo sottile), riusata anche in PrtMancantiForm per Chiudi/Apri cartella raw. Avanti e Indietro avevano dimensioni diverse (testi di lunghezza diversa, più il grassetto di Primario che richiede più altezza del testo normale) ed erano visivamente disomogenei (bordo sottile quasi invisibile su sfondo bianco per Indietro contro il blu pieno di Avanti). Aggiunti UiStile.SecondarioPieno (variante piena, senza bordo, stessa costruzione di Primario ma grigio chiaro) e UiStile.LarghezzaUguale (stessa larghezza e altezza tra due bottoni, chiamata PRIMA di arrotondare gli angoli: arrotondare e poi ridimensionare lasciava un bordo residuo della Region vecchia). Doc aggiornati nello stesso commit: docs/architettura.md. Co-Authored-By: Claude Sonnet 5 --- PrepStep/Form1.cs | 39 ++++++++------------- PrepStep/PrtMancantiForm.cs | 14 +++----- PrepStep/UiStile.cs | 67 +++++++++++++++++++++++++++++++++++++ docs/architettura.md | 19 +++++++++-- 4 files changed, 101 insertions(+), 38 deletions(-) diff --git a/PrepStep/Form1.cs b/PrepStep/Form1.cs index 807588c..5c9b5d7 100644 --- a/PrepStep/Form1.cs +++ b/PrepStep/Form1.cs @@ -95,38 +95,27 @@ public partial class Form1 : Form _lblFase.Font = new Font(Font, FontStyle.Bold); headerPanel.Controls.Add(_lblFase); - // Barra di navigazione come footer separato dal contenuto: linea sottile in cima e - // sfondo bianco, invece dei bottoni appoggiati direttamente sul contenuto/sulla barra - // di stato senza alcuna divisione visiva. - // Padding destro = 16, lo stesso usato dai pannelli di ogni fase (Padding(16)): prima - // era 12, quindi "Avanti" sporgeva 4px oltre il margine destro del contenuto sopra. - var navContainer = new Panel { Dock = DockStyle.Bottom, Height = 64, BackColor = Color.White }; - var navSeparatore = new Panel - { - Dock = DockStyle.Top, - Height = 1, - BackColor = Color.FromArgb(220, 220, 220), - }; - var navPanel = new FlowLayoutPanel - { - Dock = DockStyle.Fill, - FlowDirection = FlowDirection.RightToLeft, - Padding = new Padding(16, 14, 16, 14), - }; + // Floatbar di navigazione: card staccata dai bordi della finestra invece di un footer + // a tutta larghezza appoggiato direttamente sul contenuto/sulla barra di stato. + var (navContainer, navPanel) = UiStile.FloatBar(); _btnAvanti.Text = "Avanti ›"; UiStile.Primario(_btnAvanti); - UiStile.Arrotonda(_btnAvanti); - _btnAvanti.Click += (_, _) => VaiAllaFase(_faseAttuale + 1); - navPanel.Controls.Add(_btnAvanti); _btnIndietro.Text = "‹ Indietro"; _btnIndietro.Margin = new Padding(8, 0, 0, 0); - UiStile.Secondario(_btnIndietro); - UiStile.Arrotonda(_btnIndietro); + UiStile.SecondarioPieno(_btnIndietro); + + // Dimensioni uguali decise PRIMA di arrotondare: se si arrotonda un bottone e solo dopo + // lo si ridimensiona, la Region calcolata sulla dimensione vecchia lascia un bordo + // "fantasma" finché non arriva un repaint completo della finestra. + UiStile.LarghezzaUguale(_btnAvanti, _btnIndietro); + UiStile.Arrotonda(_btnAvanti, 10); + UiStile.Arrotonda(_btnIndietro, 10); + + _btnAvanti.Click += (_, _) => VaiAllaFase(_faseAttuale + 1); + navPanel.Controls.Add(_btnAvanti); _btnIndietro.Click += (_, _) => VaiAllaFase(_faseAttuale - 1); navPanel.Controls.Add(_btnIndietro); - navContainer.Controls.Add(navPanel); - navContainer.Controls.Add(navSeparatore); var statusPanel = new Panel { Dock = DockStyle.Bottom, Height = 28, BackColor = SystemColors.ControlLight }; _lblStatus.Dock = DockStyle.Fill; diff --git a/PrepStep/PrtMancantiForm.cs b/PrepStep/PrtMancantiForm.cs index 29890ed..733c245 100644 --- a/PrepStep/PrtMancantiForm.cs +++ b/PrepStep/PrtMancantiForm.cs @@ -64,21 +64,17 @@ public class PrtMancantiForm : Form grid.Rows[i].DefaultCellStyle.ForeColor = Color.DarkRed; } - var pannelloAzioni = new Panel { Dock = DockStyle.Bottom, Height = 50 }; - var flowAzioni = new FlowLayoutPanel - { - Dock = DockStyle.Fill, - FlowDirection = FlowDirection.RightToLeft, - Padding = new Padding(12, 8, 12, 8), - }; + var (pannelloAzioni, flowAzioni) = UiStile.FloatBar(); var btnChiudi = new Button { Text = "Chiudi" }; UiStile.Primario(btnChiudi); + UiStile.Arrotonda(btnChiudi, 10); btnChiudi.Click += (_, _) => Close(); flowAzioni.Controls.Add(btnChiudi); var btnApriCartella = new Button { Text = "Apri cartella raw", Margin = new Padding(8, 0, 0, 0) }; - UiStile.Secondario(btnApriCartella); + UiStile.SecondarioPieno(btnApriCartella); + UiStile.Arrotonda(btnApriCartella, 10); btnApriCartella.Click += (_, _) => { try { Process.Start("explorer.exe", cartellaRaw); } @@ -90,8 +86,6 @@ public class PrtMancantiForm : Form }; flowAzioni.Controls.Add(btnApriCartella); - pannelloAzioni.Controls.Add(flowAzioni); - Controls.Add(grid); Controls.Add(lblInfo); Controls.Add(pannelloAzioni); diff --git a/PrepStep/UiStile.cs b/PrepStep/UiStile.cs index 1bc4314..af6387f 100644 --- a/PrepStep/UiStile.cs +++ b/PrepStep/UiStile.cs @@ -54,6 +54,21 @@ internal static class UiStile b.Cursor = Cursors.Hand; } + /// Come Secondario, ma pieno invece che a bordo: sulle card bianche delle floatbar + /// (vedi FloatBar) il bordo sottile di Secondario è quasi invisibile su sfondo bianco, e il + /// bottone risulterebbe visivamente diverso dal Primario pieno accanto — stessa costruzione + /// (nessun bordo, riempimento pieno), solo grigio chiaro invece che blu. + public static void SecondarioPieno(Button b) + { + DimensionamentoAutomatico(b); + b.FlatStyle = FlatStyle.Flat; + b.FlatAppearance.BorderSize = 0; + b.FlatAppearance.MouseOverBackColor = Color.FromArgb(230, 233, 237); + b.FlatAppearance.MouseDownBackColor = Color.FromArgb(213, 217, 222); + b.BackColor = Color.FromArgb(241, 243, 245); + b.Cursor = Cursors.Hand; + } + /// Arrotonda gli angoli del controllo (bottone o card). Si aggancia a SizeChanged /// invece di calcolare la Region una volta sola: con AutoSize la dimensione finale si /// conosce solo a layout avvenuto (dopo Text/Padding), non subito dopo la creazione del @@ -105,4 +120,56 @@ internal static class UiStile return card; } + /// Barra di bottoni "flottante" (Avanti/Indietro, Apri cartella raw/Chiudi, ecc.): + /// una card bianca staccata su tutti e 4 i lati dal bordo della finestra — non un footer a + /// tutta larghezza — con angoli arrotondati e bordo sottile, sospesa sopra lo sfondo grigio + /// della pagina invece che ancorata al bordo. Lo sfondo del contenitore esterno deve + /// combaciare con quello di default della Form (nessun BackColor impostato altrove: + /// SystemColors.Control) perché il "distacco" si veda solo nel margine attorno alla card, + /// non in una fascia di colore diverso. + public static (Panel Contenitore, FlowLayoutPanel Bottoni) FloatBar() + { + // Altezza minima per non tagliare il contenuto: bottone (MinimumSize.Height = 32) + + // padding verticale della riga bottoni (12+12) + padding verticale del contenitore + // esterno (10+16) = 82, con un po' di margine in più. + var contenitore = new Panel + { + Dock = DockStyle.Bottom, + Height = 88, + BackColor = SystemColors.Control, + Padding = new Padding(16, 10, 16, 16), + }; + + var card = new Panel { Dock = DockStyle.Fill, BackColor = Color.White }; + card.Paint += (_, e) => + { + using var penna = new Pen(ColoreBordoCard); + e.Graphics.DrawRectangle(penna, 0, 0, card.Width - 1, card.Height - 1); + }; + Arrotonda(card, 14); + + var bottoni = new FlowLayoutPanel + { + Dock = DockStyle.Fill, + FlowDirection = FlowDirection.RightToLeft, + Padding = new Padding(16, 12, 16, 12), + }; + + card.Controls.Add(bottoni); + contenitore.Controls.Add(card); + return (contenitore, bottoni); + } + + /// Forza le stesse dimensioni per due bottoni della stessa barra (es. Avanti/ + /// Indietro): AutoSize li dimensiona in base al proprio testo, e con testi di lunghezza + /// diversa (o solo uno dei due in grassetto, come Primario/Secondario) risulterebbero + /// disallineati sia in larghezza che in altezza — un dettaglio che un designer non + /// lascerebbe passare. Va chiamato dopo aver impostato Text/Font su entrambi. + public static void LarghezzaUguale(params Button[] bottoni) + { + int larghezza = bottoni.Max(b => b.PreferredSize.Width); + int altezza = bottoni.Max(b => b.PreferredSize.Height); + foreach (var b in bottoni) + b.MinimumSize = new Size(larghezza, altezza); + } } diff --git a/docs/architettura.md b/docs/architettura.md index 14ce54e..13159ba 100644 --- a/docs/architettura.md +++ b/docs/architettura.md @@ -211,9 +211,22 @@ completi". per i secondari, blu pieno per l'azione principale di ogni fase), entrambi con `AutoSize`+`Padding`+`MinimumSize` invece di una `Size` fissa in pixel indovinata a mano (altrimenti il testo va a capo e si taglia in verticale se non ci sta nella - larghezza scelta). `Arrotonda` applica angoli arrotondati via `Region` calcolata su - `SizeChanged` (non una volta sola: con `AutoSize` la dimensione finale del bottone si - conosce solo a layout avvenuto), usata sui bottoni "Avanti"/"Indietro" del wizard. + larghezza scelta). `SecondarioPieno` è la variante senza bordo (sfondo grigio chiaro + pieno) per i bottoni secondari sopra le card bianche di `Card`/`FloatBar`, dove il + bordo sottile di `Secondario` è troppo poco visibile su sfondo bianco. `Arrotonda` + applica angoli arrotondati a un `Control` qualsiasi (bottone o card) via `Region` + calcolata su `SizeChanged`, non una volta sola: con `AutoSize` la dimensione finale si + conosce solo a layout avvenuto — va chiamata dopo aver fissato le dimensioni finali del + controllo (es. dopo `LarghezzaUguale`), altrimenti la `Region` vecchia resta visibile + come bordo residuo finché non arriva un repaint completo. `Card` costruisce una card di + stato (sfondo/bordo distinti, angoli arrotondati), usata in fase 1 per il riepilogo + Database. `FloatBar` costruisce la barra di navigazione "flottante" in fondo alle + finestre (card bianca staccata su tutti e 4 i lati, non un footer a tutta larghezza): + usata per Avanti/Indietro nel wizard e per Chiudi/Apri cartella raw in + `PrtMancantiForm`. `LarghezzaUguale` forza la stessa larghezza e altezza tra due + bottoni della stessa barra (es. Avanti/Indietro, che altrimenti avrebbero dimensioni + diverse: testi di lunghezza diversa, e il font in grassetto di `Primario` richiede più + altezza di quello normale di `Secondario`/`SecondarioPieno`). - **app.ico** — icona dell'app, referenziata da `` nel csproj (icona dell'exe in Esplora risorse/taskbar) e riletta esplicitamente in `Form1.BuildUi()` con `Icon.ExtractAssociatedIcon(Application.ExecutablePath)` per la titlebar, senza