diff --git a/Terminal.Gui/Windows/Dialog.cs b/Terminal.Gui/Windows/Dialog.cs index b51e5a8ae..5696adbff 100644 --- a/Terminal.Gui/Windows/Dialog.cs +++ b/Terminal.Gui/Windows/Dialog.cs @@ -109,24 +109,115 @@ namespace Terminal.Gui { LayoutSubviews (); } + // Get the width of all buttons, not including any spacing internal int GetButtonsWidth () { if (buttons.Count == 0) { return 0; } - return buttons.Select (b => b.Bounds.Width).Sum () + buttons.Count - 1; + return buttons.Select (b => b.Bounds.Width).Sum (); } + /// + /// Determines the horizontal alignment of the Dialog buttons. + /// + public enum ButtonAlignments { + /// + /// Center-aligns the buttons (the default). + /// + Center = 0, + + /// + /// Justifies the buttons + /// + Justify, + + /// + /// Left-aligns the buttons + /// + Left, + + /// + /// Right-aligns the buttons + /// + Right + } + + private ButtonAlignments buttonAlignment = Dialog.ButtonAlignments.Center; + + /// + /// Determines how the s are aligned along the + /// bottom of the dialog. + /// + public ButtonAlignments ButtonAlignment { get => buttonAlignment; set => buttonAlignment = value; } void LayoutStartedHandler () { - int buttonsWidth = GetButtonsWidth (); + if (buttons.Count == 0) return; - int shiftLeft = Math.Max ((Bounds.Width - buttonsWidth) / 2 - 2, 0); - for (int i = buttons.Count - 1; i >= 0; i--) { - Button button = buttons [i]; - shiftLeft += button.Frame.Width + 1; - button.X = Pos.AnchorEnd (shiftLeft); - button.Y = Pos.AnchorEnd (1); + int shiftLeft = 0; + + int buttonsWidth = GetButtonsWidth (); + switch (ButtonAlignment) { + case ButtonAlignments.Center: + // Center Buttons + shiftLeft = Math.Max ((Bounds.Width - buttonsWidth - buttons.Count - 2) / 2 + 1, 0); + for (int i = buttons.Count - 1; i >= 0; i--) { + Button button = buttons [i]; + shiftLeft += button.Frame.Width + (i == buttons.Count - 1 ? 0 : 1); + button.X = Pos.AnchorEnd (shiftLeft); + button.Y = Pos.AnchorEnd (1); + } + break; + + case ButtonAlignments.Justify: + // Justify Buttons + // leftmost and rightmost buttons are hard against edges. The rest are evenly spaced. + + var spacing = (int)Math.Ceiling ((double)(Bounds.Width - buttonsWidth - 2) / (buttons.Count - 1)); + for (int i = buttons.Count - 1; i >= 0; i--) { + Button button = buttons [i]; + if (i == buttons.Count - 1) { + shiftLeft += button.Frame.Width; + button.X = Pos.AnchorEnd (shiftLeft); + } else { + if (i == 0) { + // first (leftmost) button - always hard flush left + var left = Bounds.Width - 2; + button.X = Pos.AnchorEnd (left); + } else { + shiftLeft += button.Frame.Width + (spacing); + button.X = Pos.AnchorEnd (shiftLeft); + } + } + button.Y = Pos.AnchorEnd (1); + } + break; + + case ButtonAlignments.Left: + // Left Align Buttons + var prevButton = buttons [0]; + prevButton.X = 0; + prevButton.Y = Pos.AnchorEnd (1); + for (int i = 1; i < buttons.Count; i++) { + Button button = buttons [i]; + button.X = Pos.Right (prevButton) + 1; + button.Y = Pos.AnchorEnd (1); + prevButton = button; + } + break; + + case ButtonAlignments.Right: + // Right align buttons + shiftLeft = buttons [buttons.Count - 1].Frame.Width; + buttons [buttons.Count - 1].X = Pos.AnchorEnd (shiftLeft); + buttons [buttons.Count - 1].Y = Pos.AnchorEnd (1); + for (int i = buttons.Count - 2; i >= 0; i--) { + Button button = buttons [i]; + shiftLeft += button.Frame.Width + 1; + button.X = Pos.AnchorEnd (shiftLeft); + button.Y = Pos.AnchorEnd (1); + } + break; } } @@ -140,5 +231,6 @@ namespace Terminal.Gui { } return base.ProcessKey (kb); } + } } diff --git a/UICatalog/Scenarios/Dialogs.cs b/UICatalog/Scenarios/Dialogs.cs index 3da4ae548..6d43fd7ec 100644 --- a/UICatalog/Scenarios/Dialogs.cs +++ b/UICatalog/Scenarios/Dialogs.cs @@ -9,13 +9,13 @@ namespace UICatalog.Scenarios { [ScenarioMetadata (Name: "Dialogs", Description: "Demonstrates how to the Dialog class")] [ScenarioCategory ("Dialogs")] public class Dialogs : Scenario { + static int CODE_POINT = '你'; // We know this is a wide char public override void Setup () { var frame = new FrameView ("Dialog Options") { X = Pos.Center (), - Y = 1, - Width = Dim.Percent (75), - Height = 10 + Y = 0, + Width = Dim.Percent (75) }; Win.Add (frame); @@ -92,10 +92,31 @@ namespace UICatalog.Scenarios { }; frame.Add (numButtonsEdit); + var glyphsNotWords = new CheckBox ($"Add {Char.ConvertFromUtf32(CODE_POINT)} to button text to stress wide char support", false) { + X = Pos.Left (numButtonsEdit), + Y = Pos.Bottom (label), + TextAlignment = Terminal.Gui.TextAlignment.Right, + }; + frame.Add (glyphsNotWords); + + + label = new Label ("Button Style:") { + X = 0, + Y = Pos.Bottom (glyphsNotWords), + AutoSize = true, + TextAlignment = Terminal.Gui.TextAlignment.Right, + }; + frame.Add (label); + var styleRadioGroup = new RadioGroup (new ustring [] { "Center", "Justify", "Left", "Right" }) { + X = Pos.Right (label) + 1, + Y = Pos.Top (label), + }; + frame.Add (styleRadioGroup); + void Top_Loaded () { frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit) - + Dim.Height (numButtonsEdit) + 2; + + Dim.Height (numButtonsEdit) + Dim.Height (styleRadioGroup) + Dim.Height(glyphsNotWords) + 2; Top.Loaded -= Top_Loaded; } Top.Loaded += Top_Loaded; @@ -112,10 +133,14 @@ namespace UICatalog.Scenarios { Y = Pos.Bottom (frame) + 5, Width = 25, Height = 1, + ColorScheme = Colors.Error, }; + // glyphsNotWords + // false:var btnText = new [] { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine" }; + // true: var btnText = new [] { "0", "\u2780", "➁", "\u2783", "\u2784", "\u2785", "\u2786", "\u2787", "\u2788", "\u2789" }; + // \u2781 is ➁ dingbats \ufb70 is - //var btnText = new [] { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine" }; var showDialogButton = new Button ("Show Dialog") { X = Pos.Center (), Y = Pos.Bottom (frame) + 2, @@ -123,18 +148,26 @@ namespace UICatalog.Scenarios { }; showDialogButton.Clicked += () => { try { - int width = int.Parse (widthEdit.Text.ToString ()); - int height = int.Parse (heightEdit.Text.ToString ()); - int numButtons = int.Parse (numButtonsEdit.Text.ToString ()); + int width = 0; + int.TryParse (widthEdit.Text.ToString (), out width); + int height = 0; + int.TryParse (heightEdit.Text.ToString (), out height); + int numButtons = 3; + int.TryParse (numButtonsEdit.Text.ToString (), out numButtons); var buttons = new List