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