diff --git a/Terminal.Gui/Drawing/Justification.cs b/Terminal.Gui/Drawing/Justification.cs new file mode 100644 index 000000000..e9a9bdbf9 --- /dev/null +++ b/Terminal.Gui/Drawing/Justification.cs @@ -0,0 +1,323 @@ +namespace Terminal.Gui; + +/// +/// Controls how the justifies items within a container. +/// +public enum Justification +{ + /// + /// The items will be aligned to the left. + /// Set to to ensure at least one space between + /// each item. + /// + /// + /// + /// 111 2222 33333 + /// + /// + Left, + + /// + /// The items will be aligned to the right. + /// Set to to ensure at least one space between + /// each item. + /// + /// + /// + /// 111 2222 33333 + /// + /// + Right, + + /// + /// The group will be centered in the container. + /// If centering is not possible, the group will be left-justified. + /// Set to to ensure at least one space between + /// each item. + /// + /// + /// + /// 111 2222 33333 + /// + /// + Centered, + + /// + /// The items will be justified. Space will be added between the items such that the first item + /// is at the start and the right side of the last item against the end. + /// Set to to ensure at least one space between + /// each item. + /// + /// + /// + /// 111 2222 33333 + /// + /// + Justified, + + /// + /// The first item will be aligned to the left and the remaining will aligned to the right. + /// Set to to ensure at least one space between + /// each item. + /// + /// + /// + /// 111 2222 33333 + /// + /// + FirstLeftRestRight, + + /// + /// The last item will be aligned to the right and the remaining will aligned to the left. + /// Set to to ensure at least one space between + /// each item. + /// + /// + /// + /// 111 2222 33333 + /// + /// + LastRightRestLeft +} + +/// +/// Justifies items within a container based on the specified . +/// +public class Justifier +{ + private int _maxSpaceBetweenItems; + + /// + /// Gets or sets whether puts a space is placed between items. Default is . If , a space will be + /// placed between each item, which is useful for + /// justifying text. + /// + public bool PutSpaceBetweenItems + { + get => _maxSpaceBetweenItems == 1; + set => _maxSpaceBetweenItems = value ? 1 : 0; + } + + /// + /// Takes a list of items and returns their positions when justified within a container wide based on the specified + /// . + /// + /// The sizes of the items to justify. + /// The justification style. + /// The width of the container. + /// The locations of the items, from left to right. + public int [] Justify (int [] sizes, Justification justification, int containerSize) + { + if (sizes.Length == 0) + { + return new int [] { }; + } + + int totalItemsSize = sizes.Sum (); + + if (totalItemsSize > containerSize) + { + // throw new ArgumentException ("The sum of the sizes is greater than the total size."); + } + + var positions = new int [sizes.Length]; + totalItemsSize = sizes.Sum (); // total size of items + int totalGaps = sizes.Length - 1; // total gaps (MinimumSpaceBetweenItems) + int totalItemsAndSpaces = totalItemsSize + totalGaps * _maxSpaceBetweenItems; // total size of items and spaces if we had enough room + int spaces = totalGaps * _maxSpaceBetweenItems; // We'll decrement this below to place one space between each item until we run out + + if (totalItemsSize >= containerSize) + { + spaces = 0; + } + else if (totalItemsAndSpaces > containerSize) + { + spaces = containerSize - totalItemsSize; + } + + switch (justification) + { + case Justification.Left: + var currentPosition = 0; + + for (var i = 0; i < sizes.Length; i++) + { + if (sizes [i] < 0) + { + throw new ArgumentException ("The size of an item cannot be negative."); + } + + if (i == 0) + { + positions [0] = 0; // first item position + + continue; + } + + int spaceBefore = spaces-- > 0 ? _maxSpaceBetweenItems : 0; + + // subsequent items are placed one space after the previous item + positions [i] = positions [i - 1] + sizes [i - 1] + spaceBefore; + } + + break; + case Justification.Right: + currentPosition = Math.Max (0, containerSize - totalItemsSize - spaces); + + for (var i = 0; i < sizes.Length; i++) + { + if (sizes [i] < 0) + { + throw new ArgumentException ("The size of an item cannot be negative."); + } + + int spaceBefore = spaces-- > 0 ? _maxSpaceBetweenItems : 0; + + positions [i] = currentPosition; + currentPosition += sizes [i] + spaceBefore; + } + + break; + + case Justification.Centered: + if (sizes.Length > 1) + { + // remaining space to be distributed before first and after the items + int remainingSpace = Math.Max (0, containerSize - totalItemsSize - spaces); + + for (var i = 0; i < sizes.Length; i++) + { + if (sizes [i] < 0) + { + throw new ArgumentException ("The size of an item cannot be negative."); + } + + if (i == 0) + { + positions [i] = remainingSpace / 2; // first item position + + continue; + } + + int spaceBefore = spaces-- > 0 ? _maxSpaceBetweenItems : 0; + + // subsequent items are placed one space after the previous item + positions [i] = positions [i - 1] + sizes [i - 1] + spaceBefore; + } + } + else if (sizes.Length == 1) + { + if (sizes [0] < 0) + { + throw new ArgumentException ("The size of an item cannot be negative."); + } + + positions [0] = (containerSize - sizes [0]) / 2; // single item is centered + } + + break; + + case Justification.Justified: + int spaceBetween = sizes.Length > 1 ? (containerSize - totalItemsSize) / (sizes.Length - 1) : 0; + int remainder = sizes.Length > 1 ? (containerSize - totalItemsSize) % (sizes.Length - 1) : 0; + currentPosition = 0; + + for (var i = 0; i < sizes.Length; i++) + { + if (sizes [i] < 0) + { + throw new ArgumentException ("The size of an item cannot be negative."); + } + + positions [i] = currentPosition; + int extraSpace = i < remainder ? 1 : 0; + currentPosition += sizes [i] + spaceBetween + extraSpace; + } + + break; + + // 111 2222 33333 + case Justification.LastRightRestLeft: + if (sizes.Length > 1) + { + currentPosition = 0; + + for (var i = 0; i < sizes.Length; i++) + { + if (sizes [i] < 0) + { + throw new ArgumentException ("The size of an item cannot be negative."); + } + + if (i < sizes.Length - 1) + { + int spaceBefore = spaces-- > 0 ? _maxSpaceBetweenItems : 0; + + positions [i] = currentPosition; + currentPosition += sizes [i] + spaceBefore; + } + } + + positions [sizes.Length - 1] = containerSize - sizes [sizes.Length - 1]; + } + else if (sizes.Length == 1) + { + if (sizes [0] < 0) + { + throw new ArgumentException ("The size of an item cannot be negative."); + } + + positions [0] = containerSize - sizes [0]; // single item is flush right + } + + break; + + // 111 2222 33333 + case Justification.FirstLeftRestRight: + if (sizes.Length > 1) + { + currentPosition = 0; + positions [0] = currentPosition; // first item is flush left + + for (int i = sizes.Length - 1; i >= 0; i--) + { + if (sizes [i] < 0) + { + throw new ArgumentException ("The size of an item cannot be negative."); + } + + if (i == sizes.Length - 1) + { + // start at right + currentPosition = containerSize - sizes [i]; + positions [i] = currentPosition; + } + + if (i < sizes.Length - 1 && i > 0) + { + int spaceBefore = spaces-- > 0 ? _maxSpaceBetweenItems : 0; + + positions [i] = currentPosition - sizes [i] - spaceBefore; + currentPosition = positions [i]; + } + } + } + else if (sizes.Length == 1) + { + if (sizes [0] < 0) + { + throw new ArgumentException ("The size of an item cannot be negative."); + } + + positions [0] = 0; // single item is flush left + } + + break; + + default: + throw new ArgumentOutOfRangeException (nameof (justification), justification, null); + } + + return positions; + } +} diff --git a/Terminal.Gui/Resources/config.json b/Terminal.Gui/Resources/config.json index 368ccd8bf..4f82e43d6 100644 --- a/Terminal.Gui/Resources/config.json +++ b/Terminal.Gui/Resources/config.json @@ -24,7 +24,7 @@ "Themes": [ { "Default": { - "Dialog.DefaultButtonAlignment": "Center", + "Dialog.DefaultButtonAlignment": "Centered", "FrameView.DefaultBorderStyle": "Single", "Window.DefaultBorderStyle": "Single", "ColorSchemes": [ diff --git a/Terminal.Gui/View/Layout/PosDim.cs b/Terminal.Gui/View/Layout/PosDim.cs index 9941546f7..5e1b2a58b 100644 --- a/Terminal.Gui/View/Layout/PosDim.cs +++ b/Terminal.Gui/View/Layout/PosDim.cs @@ -1,7 +1,4 @@ using System.Diagnostics; -using static System.Net.Mime.MediaTypeNames; -using static Terminal.Gui.Dialog; -using static Terminal.Gui.Dim; namespace Terminal.Gui; @@ -206,6 +203,14 @@ public class Pos /// The returned from the function. public static Pos Function (Func function) { return new PosFunc (function); } + /// + /// Creates a object that justifies a set of views according to the specified justification. + /// + /// + /// + /// + public static Pos Justify ( Justification justification) { return new PosJustify (justification); } + /// Serves as the default hash function. /// A hash code for the current object. public override int GetHashCode () { return Anchor (0).GetHashCode (); } @@ -349,7 +354,7 @@ public class Pos /// that /// is used. /// - internal virtual int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) + internal virtual int Calculate (int superviewDimension, Dim dim, View us, Dim.Dimension dimension) { return Anchor (superviewDimension); } @@ -388,7 +393,7 @@ public class Pos return width - _offset; } - internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) + internal override int Calculate (int superviewDimension, Dim dim, View us, Dim.Dimension dimension) { int newLocation = Anchor (superviewDimension); @@ -406,7 +411,7 @@ public class Pos public override string ToString () { return "Center"; } internal override int Anchor (int width) { return width / 2; } - internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) + internal override int Calculate (int superviewDimension, Dim dim, View us, Dim.Dimension dimension) { int newDimension = Math.Max (dim.Calculate (0, superviewDimension, us, dimension), 0); @@ -434,7 +439,7 @@ public class Pos return la - ra; } - internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) + internal override int Calculate (int superviewDimension, Dim dim, View us, Dim.Dimension dimension) { int newDimension = dim.Calculate (0, superviewDimension, us, dimension); int left = _left.Calculate (superviewDimension, dim, us, dimension); @@ -458,6 +463,99 @@ public class Pos internal override int Anchor (int width) { return (int)(width * _factor); } } + + /// + /// Enables justification of a set of views. + /// + public class PosJustify : Pos + { + private readonly Justification _justification; + + /// + /// Enables justification of a set of views. + /// + /// The set of views to justify according to . + /// + public PosJustify (Justification justification) + { + _justification = justification; + } + + public override bool Equals (object other) + { + return other is PosJustify justify && justify._justification == _justification; + } + + public override int GetHashCode () { return _justification.GetHashCode (); } + + + public override string ToString () + { + return $"Justify(alignment={_justification})"; + } + + internal override int Anchor (int width) + { + return width; + } + + internal override int Calculate (int superviewDimension, Dim dim, View us, Dim.Dimension dimension) + { + if (us.SuperView is null) + { + return 0; + } + // Find all the views that are being justified - they have the same justification and opposite position as us + // Then, pass the array of views to the Justify method + int [] dimensions; + int [] positions; + + int ourIndex = 0; + if (dimension == Dim.Dimension.Width) + { + List dimensionsList = new List (); + for (int i = 0; i < us.SuperView.Subviews.Count; i++) + { + var v = us.SuperView.Subviews [i]; + var j = v.X as PosJustify; + if (j?._justification == _justification && v.Frame.Y == us.Frame.Y) + { + dimensionsList.Add (v.Frame.Width); + + if (v == us) + { + ourIndex = dimensionsList.Count - 1; + } + } + } + dimensions = dimensionsList.ToArray (); + positions = new Justifier () { PutSpaceBetweenItems = true }.Justify (dimensions, _justification, superviewDimension); + } + else + { + List dimensionsList = new List (); + for (int i = 0; i < us.SuperView.Subviews.Count; i++) + { + var v = us.SuperView.Subviews [i]; + var j = v.Y as PosJustify; + if (j?._justification == _justification && v.Frame.X == us.Frame.X) + { + dimensionsList.Add (v.Frame.Height); + + if (v == us) + { + ourIndex = dimensionsList.Count - 1; + } + } + } + dimensions = dimensionsList.ToArray (); + positions = new Justifier () { PutSpaceBetweenItems = false }.Justify (dimensions, _justification, superviewDimension); + } + + return positions [ourIndex]; + } + + } // Helper class to provide dynamic value by the execution of a function that returns an integer. internal class PosFunc (Func n) : Pos { diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs index 24b680fa0..e112100bc 100644 --- a/Terminal.Gui/View/Layout/ViewLayout.cs +++ b/Terminal.Gui/View/Layout/ViewLayout.cs @@ -36,6 +36,7 @@ public enum LayoutStyle Computed } + public partial class View { #region Frame diff --git a/Terminal.Gui/Views/Dialog.cs b/Terminal.Gui/Views/Dialog.cs index ea3ac13d2..8c64478df 100644 --- a/Terminal.Gui/Views/Dialog.cs +++ b/Terminal.Gui/Views/Dialog.cs @@ -15,21 +15,6 @@ namespace Terminal.Gui; /// public class Dialog : Window { - /// 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 - } // TODO: Reenable once border/borderframe design is settled /// @@ -108,7 +93,7 @@ public class Dialog : Window } /// Determines how the s are aligned along the bottom of the dialog. - public ButtonAlignments ButtonAlignment { get; set; } + public Justification ButtonAlignment { get; set; } /// Optional buttons to lay out at the bottom of the dialog. public Button [] Buttons @@ -128,11 +113,11 @@ public class Dialog : Window } } - /// The default for . + /// The default for . /// This property can be set in a Theme. [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] [JsonConverter (typeof (JsonStringEnumConverter))] - public static ButtonAlignments DefaultButtonAlignment { get; set; } = ButtonAlignments.Center; + public static Justification DefaultButtonAlignment { get; set; } = Justification.Centered; /// /// Adds a to the , its layout will be controlled by the @@ -159,18 +144,18 @@ public class Dialog : Window } /// - public override void LayoutSubviews () - { - if (_inLayout) - { - return; - } + //public override void LayoutSubviews () + //{ + // if (_inLayout) + // { + // return; + // } - _inLayout = true; - LayoutButtons (); - base.LayoutSubviews (); - _inLayout = false; - } + // _inLayout = true; + // //LayoutButtons (); + // base.LayoutSubviews (); + // _inLayout = false; + //} // Get the width of all buttons, not including any Margin. internal int GetButtonsWidth () @@ -199,7 +184,7 @@ public class Dialog : Window switch (ButtonAlignment) { - case ButtonAlignments.Center: + case Justification.Centered: // Center Buttons shiftLeft = (Viewport.Width - buttonsWidth - _buttons.Count - 1) / 2 + 1; @@ -222,7 +207,7 @@ public class Dialog : Window break; - case ButtonAlignments.Justify: + case Justification.Justified: // Justify Buttons // leftmost and rightmost buttons are hard against edges. The rest are evenly spaced. @@ -257,7 +242,7 @@ public class Dialog : Window break; - case ButtonAlignments.Left: + case Justification.Left: // Left Align Buttons Button prevButton = _buttons [0]; prevButton.X = 0; @@ -273,7 +258,7 @@ public class Dialog : Window break; - case ButtonAlignments.Right: + case Justification.Right: // Right align buttons shiftLeft = _buttons [_buttons.Count - 1].Frame.Width; _buttons [_buttons.Count - 1].X = Pos.AnchorEnd (shiftLeft); diff --git a/Terminal.Gui/Views/MessageBox.cs b/Terminal.Gui/Views/MessageBox.cs index ef7a33d10..d758d62f6 100644 --- a/Terminal.Gui/Views/MessageBox.cs +++ b/Terminal.Gui/Views/MessageBox.cs @@ -325,7 +325,7 @@ public static class MessageBox foreach (string s in buttons) { - var b = new Button { Text = s }; + var b = new Button { Text = s, Y = Pos.AnchorEnd (), X = Pos.Justify (Justification.Centered) }; if (count == defaultButton) { diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs index a20b4cbbc..12cdc5961 100644 --- a/Terminal.Gui/Views/TextView.cs +++ b/Terminal.Gui/Views/TextView.cs @@ -4180,7 +4180,10 @@ public class TextView : View } else { - PositionCursor (); + if (IsInitialized) + { + PositionCursor (); + } } OnUnwrappedCursorPosition (); diff --git a/Terminal.Gui/Views/Wizard/Wizard.cs b/Terminal.Gui/Views/Wizard/Wizard.cs index c3691b3e1..e77d4cfe5 100644 --- a/Terminal.Gui/Views/Wizard/Wizard.cs +++ b/Terminal.Gui/Views/Wizard/Wizard.cs @@ -85,7 +85,7 @@ public class Wizard : Dialog { // Using Justify causes the Back and Next buttons to be hard justified against // the left and right edge - ButtonAlignment = ButtonAlignments.Justify; + ButtonAlignment = Justification.Justified; BorderStyle = LineStyle.Double; //// Add a horiz separator diff --git a/Terminal.sln.DotSettings b/Terminal.sln.DotSettings index 3bc1fab5d..cdfa4823d 100644 --- a/Terminal.sln.DotSettings +++ b/Terminal.sln.DotSettings @@ -438,5 +438,6 @@ Concurrency Issue (?<=\W|^)(?<TAG>CONCURRENCY:)(\W|$)(.*) Warning + True True diff --git a/UICatalog/Scenarios/ComputedLayout.cs b/UICatalog/Scenarios/ComputedLayout.cs index c8013c46a..cd8f36ee4 100644 --- a/UICatalog/Scenarios/ComputedLayout.cs +++ b/UICatalog/Scenarios/ComputedLayout.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Terminal.Gui; +using static Terminal.Gui.Dialog; namespace UICatalog.Scenarios; @@ -332,13 +333,13 @@ public class ComputedLayout : Scenario // This is intentionally convoluted to illustrate potential bugs. var anchorEndLabel1 = new Label { - Text = "This Label should be the 2nd to last line (AnchorEnd (2)).", + Text = "This Label should be the 3rd to last line (AnchorEnd (3)).", TextAlignment = TextAlignment.Centered, ColorScheme = Colors.ColorSchemes ["Menu"], AutoSize = false, Width = Dim.Fill (5), X = 5, - Y = Pos.AnchorEnd (2) + Y = Pos.AnchorEnd (3) }; app.Add (anchorEndLabel1); @@ -347,20 +348,19 @@ public class ComputedLayout : Scenario var anchorEndLabel2 = new TextField { Text = - "This TextField should be the 3rd to last line (AnchorEnd (2) - 1).", + "This TextField should be the 4th to last line (AnchorEnd (3) - 1).", TextAlignment = TextAlignment.Left, ColorScheme = Colors.ColorSchemes ["Menu"], AutoSize = false, Width = Dim.Fill (5), X = 5, - Y = Pos.AnchorEnd (2) - 1 // Pos.Combine + Y = Pos.AnchorEnd (3) - 1 // Pos.Combine }; app.Add (anchorEndLabel2); - // Show positioning vertically using Pos.AnchorEnd via Pos.Combine var leftButton = new Button { - Text = "Left", Y = Pos.AnchorEnd (0) - 1 // Pos.Combine + Text = "Left", Y = Pos.AnchorEnd () - 1 }; leftButton.Accept += (s, e) => @@ -376,7 +376,7 @@ public class ComputedLayout : Scenario // show positioning vertically using Pos.AnchorEnd var centerButton = new Button { - Text = "Center", X = Pos.Center (), Y = Pos.AnchorEnd (1) // Pos.AnchorEnd(1) + Text = "Center", Y = Pos.AnchorEnd (2) // Pos.AnchorEnd(1) }; centerButton.Accept += (s, e) => @@ -402,14 +402,17 @@ public class ComputedLayout : Scenario app.LayoutSubviews (); }; - // Center three buttons with 5 spaces between them - leftButton.X = Pos.Left (centerButton) - (Pos.Right (leftButton) - Pos.Left (leftButton)) - 5; - rightButton.X = Pos.Right (centerButton) + 5; - + View [] buttons = { leftButton, centerButton, rightButton }; app.Add (leftButton); app.Add (centerButton); app.Add (rightButton); + + // Center three buttons with + leftButton.X = Pos.Justify (Justification.Centered); + centerButton.X = Pos.Justify (Justification.Centered); + rightButton.X = Pos.Justify (Justification.Centered); + Application.Run (app); app.Dispose (); } diff --git a/UICatalog/Scenarios/Dialogs.cs b/UICatalog/Scenarios/Dialogs.cs index fa8cacd21..802591aad 100644 --- a/UICatalog/Scenarios/Dialogs.cs +++ b/UICatalog/Scenarios/Dialogs.cs @@ -137,7 +137,7 @@ public class Dialogs : Scenario { X = Pos.Right (label) + 1, Y = Pos.Top (label), - RadioLabels = new [] { "_Center", "_Justify", "_Left", "_Right" } + RadioLabels = new [] { "_Centered", "_Justified", "_Left", "_Right" } }; frame.Add (styleRadioGroup); @@ -265,7 +265,7 @@ public class Dialogs : Scenario dialog = new Dialog { Title = titleEdit.Text, - ButtonAlignment = (Dialog.ButtonAlignments)styleRadioGroup.SelectedItem, + ButtonAlignment = (Justification)styleRadioGroup.SelectedItem, Buttons = buttons.ToArray () }; diff --git a/UICatalog/Scenarios/Generic.cs b/UICatalog/Scenarios/Generic.cs index 38e1086d7..ca5ee4d35 100644 --- a/UICatalog/Scenarios/Generic.cs +++ b/UICatalog/Scenarios/Generic.cs @@ -17,10 +17,81 @@ public sealed class MyScenario : Scenario Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" }; - var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" }; + int leftMargin = 0; + var just = Justification.Justified; + + var button = new Button { X = Pos.Justify(just), Y = Pos.Center (), Text = "Press me!" }; button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed the button!", "Ok"); appWindow.Add (button); + button = new Button { X = Pos.Justify (just), Y = Pos.Center (), Text = "Two" }; + button.Margin.Thickness = new Thickness (leftMargin, 0, 0, 0); + button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Two!", "Ok"); + appWindow.Add (button); + + button = new Button { X = Pos.Justify (just), Y = Pos.Center (), Text = "Three" }; + button.Margin.Thickness = new Thickness (leftMargin, 0, 0, 0); + button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (button); + + button = new Button { X = Pos.Justify (just), Y = Pos.Center (), Text = "Four" }; + button.Margin.Thickness = new Thickness (leftMargin, 0, 0, 0); + button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (button); + + button = new Button { X = Pos.Justify (just), Y = Pos.Center (), Text = "Five" }; + button.Margin.Thickness = new Thickness (leftMargin, 0, 0, 0); + button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (button); + + button = new Button { X = Pos.Justify (just), Y = Pos.Center (), Text = "Six" }; + button.Margin.Thickness = new Thickness (leftMargin, 0, 0, 0); + button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (button); + + button = new Button { X = Pos.Justify (just), Y = Pos.Center (), Text = "Seven" }; + button.Margin.Thickness = new Thickness (leftMargin, 0, 0, 0); + button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (button); + + button = new Button { X = Pos.Justify (just), Y = Pos.Center (), Text = "Eight" }; + button.Margin.Thickness = new Thickness (leftMargin, 0, 0, 0); + button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (button); + + just = Justification.FirstLeftRestRight; + var checkbox = new CheckBox { X = 5, Y = Pos.Justify (just), Text = "Check boxes!" }; + checkbox.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed the checkbox!", "Ok"); + appWindow.Add (checkbox); + + checkbox = new CheckBox { X = 5, Y = Pos.Justify (just), Text = "CheckTwo" }; + checkbox.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Two!", "Ok"); + appWindow.Add (checkbox); + + checkbox = new CheckBox { X = 5, Y = Pos.Justify (just), Text = "CheckThree" }; + checkbox.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (checkbox); + + checkbox = new CheckBox { X = 5, Y = Pos.Justify (just), Text = "CheckFour" }; + checkbox.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (checkbox); + + checkbox = new CheckBox { X = 5, Y = Pos.Justify (just), Text = "CheckFive" }; + checkbox.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (checkbox); + + checkbox = new CheckBox { X = 5, Y = Pos.Justify (just), Text = "CheckSix" }; + checkbox.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (checkbox); + + checkbox = new CheckBox { X = 5, Y = Pos.Justify (just), Text = "CheckSeven" }; + checkbox.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (checkbox); + + checkbox = new CheckBox { X = 5, Y = Pos.Justify (just), Text = "CheckEight" }; + checkbox.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed Three!", "Ok"); + appWindow.Add (checkbox); + // Run - Start the application. Application.Run (appWindow); appWindow.Dispose (); diff --git a/UnitTests/Configuration/ThemeScopeTests.cs b/UnitTests/Configuration/ThemeScopeTests.cs index 3da7f881a..0eecd05b7 100644 --- a/UnitTests/Configuration/ThemeScopeTests.cs +++ b/UnitTests/Configuration/ThemeScopeTests.cs @@ -29,12 +29,12 @@ public class ThemeScopeTests { Reset (); Assert.NotEmpty (Themes); - Assert.Equal (Dialog.ButtonAlignments.Center, Dialog.DefaultButtonAlignment); + Assert.Equal (Justification.Centered, Dialog.DefaultButtonAlignment); - Themes ["Default"] ["Dialog.DefaultButtonAlignment"].PropertyValue = Dialog.ButtonAlignments.Right; + Themes ["Default"] ["Dialog.DefaultButtonAlignment"].PropertyValue = Justification.Right; ThemeManager.Themes! [ThemeManager.SelectedTheme]!.Apply (); - Assert.Equal (Dialog.ButtonAlignments.Right, Dialog.DefaultButtonAlignment); + Assert.Equal (Justification.Right, Dialog.DefaultButtonAlignment); Reset (); } diff --git a/UnitTests/Configuration/ThemeTests.cs b/UnitTests/Configuration/ThemeTests.cs index f7d8c732f..5ecee6bbe 100644 --- a/UnitTests/Configuration/ThemeTests.cs +++ b/UnitTests/Configuration/ThemeTests.cs @@ -77,15 +77,15 @@ public class ThemeTests public void TestSerialize_RoundTrip () { var theme = new ThemeScope (); - theme ["Dialog.DefaultButtonAlignment"].PropertyValue = Dialog.ButtonAlignments.Right; + theme ["Dialog.DefaultButtonAlignment"].PropertyValue = Justification.Right; string json = JsonSerializer.Serialize (theme, _jsonOptions); var deserialized = JsonSerializer.Deserialize (json, _jsonOptions); Assert.Equal ( - Dialog.ButtonAlignments.Right, - (Dialog.ButtonAlignments)deserialized ["Dialog.DefaultButtonAlignment"].PropertyValue + Justification.Right, + (Justification)deserialized ["Dialog.DefaultButtonAlignment"].PropertyValue ); Reset (); } diff --git a/UnitTests/Dialogs/DialogTests.cs b/UnitTests/Dialogs/DialogTests.cs index dc4793c86..3ee034ee8 100644 --- a/UnitTests/Dialogs/DialogTests.cs +++ b/UnitTests/Dialogs/DialogTests.cs @@ -32,8 +32,8 @@ public class DialogTests Title = title, Width = width, Height = 1, - ButtonAlignment = Dialog.ButtonAlignments.Center, - Buttons = [new () { Text = btn1Text }] + ButtonAlignment = Justification.Centered, + Buttons = [new Button { Text = btn1Text }] }; // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..) @@ -57,8 +57,8 @@ public class DialogTests Title = title, Width = width, Height = 1, - ButtonAlignment = Dialog.ButtonAlignments.Justify, - Buttons = [new () { Text = btn1Text }] + ButtonAlignment = Justification.Justified, + Buttons = [new Button { Text = btn1Text }] }; // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..) @@ -82,8 +82,8 @@ public class DialogTests Title = title, Width = width, Height = 1, - ButtonAlignment = Dialog.ButtonAlignments.Right, - Buttons = [new () { Text = btn1Text }] + ButtonAlignment = Justification.Right, + Buttons = [new Button { Text = btn1Text }] }; // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..) @@ -107,8 +107,8 @@ public class DialogTests Title = title, Width = width, Height = 1, - ButtonAlignment = Dialog.ButtonAlignments.Left, - Buttons = [new () { Text = btn1Text }] + ButtonAlignment = Justification.Left, + Buttons = [new Button { Text = btn1Text }] }; // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..) @@ -153,14 +153,14 @@ public class DialogTests // Default - Center (runstate, Dialog dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Centered, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -170,14 +170,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Justify, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Justified, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -187,14 +187,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Right, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Right, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -204,14 +204,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Left, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Left, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -248,7 +248,7 @@ public class DialogTests (runstate, Dialog dlg) = RunButtonTestDialog ( title, width, - Dialog.ButtonAlignments.Center, + Justification.Centered, new Button { Text = btn1Text }, new Button { Text = btn2Text }, new Button { Text = btn3Text }, @@ -264,14 +264,14 @@ public class DialogTests $"{CM.Glyphs.VLine}{CM.Glyphs.LeftBracket} yes {CM.Glyphs.LeftBracket} no {CM.Glyphs.LeftBracket} maybe {CM.Glyphs.LeftBracket} never {CM.Glyphs.RightBracket}{CM.Glyphs.VLine}"; (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Justify, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Justified, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -280,14 +280,14 @@ public class DialogTests buttonRow = $"{CM.Glyphs.VLine}{CM.Glyphs.RightBracket} {btn2} {btn3} {btn4}{CM.Glyphs.VLine}"; (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Right, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Right, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -296,14 +296,14 @@ public class DialogTests buttonRow = $"{CM.Glyphs.VLine}{btn1} {btn2} {btn3} {CM.Glyphs.LeftBracket} n{CM.Glyphs.VLine}"; (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Left, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Left, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -337,14 +337,14 @@ public class DialogTests // Default - Center (runstate, Dialog dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Centered, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -354,14 +354,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Justify, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Justified, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -371,14 +371,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Right, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Right, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -388,14 +388,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Left, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Left, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -431,14 +431,14 @@ public class DialogTests // Default - Center (runstate, Dialog dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Centered, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -448,14 +448,14 @@ public class DialogTests Assert.Equal (width, buttonRow.GetColumns ()); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Justify, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Justified, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -465,14 +465,14 @@ public class DialogTests Assert.Equal (width, buttonRow.GetColumns ()); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Right, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Right, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -482,14 +482,14 @@ public class DialogTests Assert.Equal (width, buttonRow.GetColumns ()); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Left, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Justification.Left, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -514,11 +514,11 @@ public class DialogTests d.SetBufferSize (width, 1); (runstate, Dialog dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Center, - new Button { Text = btnText } - ); + title, + width, + Justification.Centered, + new Button { Text = btnText } + ); // Center TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); @@ -531,11 +531,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Justify, - new Button { Text = btnText } - ); + title, + width, + Justification.Justified, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -546,11 +546,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Right, - new Button { Text = btnText } - ); + title, + width, + Justification.Right, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -561,11 +561,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Left, - new Button { Text = btnText } - ); + title, + width, + Justification.Left, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -578,11 +578,11 @@ public class DialogTests d.SetBufferSize (width, 1); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Center, - new Button { Text = btnText } - ); + title, + width, + Justification.Centered, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -593,11 +593,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Justify, - new Button { Text = btnText } - ); + title, + width, + Justification.Justified, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -608,11 +608,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Right, - new Button { Text = btnText } - ); + title, + width, + Justification.Right, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -623,11 +623,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Left, - new Button { Text = btnText } - ); + title, + width, + Justification.Left, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -657,13 +657,13 @@ public class DialogTests d.SetBufferSize (buttonRow.Length, 3); (runstate, Dialog dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text } - ); + title, + width, + Justification.Centered, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -673,13 +673,13 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Justify, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text } - ); + title, + width, + Justification.Justified, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -689,13 +689,13 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Right, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text } - ); + title, + width, + Justification.Right, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -705,13 +705,13 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Left, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text } - ); + title, + width, + Justification.Left, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -739,12 +739,12 @@ public class DialogTests d.SetBufferSize (buttonRow.Length, 3); (runstate, Dialog dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text } - ); + title, + width, + Justification.Centered, + new Button { Text = btn1Text }, + new Button { Text = btn2Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -754,12 +754,12 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Justify, - new Button { Text = btn1Text }, - new Button { Text = btn2Text } - ); + title, + width, + Justification.Justified, + new Button { Text = btn1Text }, + new Button { Text = btn2Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -769,12 +769,12 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Right, - new Button { Text = btn1Text }, - new Button { Text = btn2Text } - ); + title, + width, + Justification.Right, + new Button { Text = btn1Text }, + new Button { Text = btn2Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -784,12 +784,12 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = RunButtonTestDialog ( - title, - width, - Dialog.ButtonAlignments.Left, - new Button { Text = btn1Text }, - new Button { Text = btn2Text } - ); + title, + width, + Justification.Left, + new Button { Text = btn1Text }, + new Button { Text = btn2Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -821,9 +821,9 @@ public class DialogTests Button button1, button2; // Default (Center) - button1 = new () { Text = btn1Text }; - button2 = new () { Text = btn2Text }; - (runstate, dlg) = RunButtonTestDialog (title, width, Dialog.ButtonAlignments.Center, button1, button2); + button1 = new Button { Text = btn1Text }; + button2 = new Button { Text = btn2Text }; + (runstate, dlg) = RunButtonTestDialog (title, width, Justification.Centered, button1, button2); button1.Visible = false; RunIteration (ref runstate, ref firstIteration); buttonRow = $@"{CM.Glyphs.VLine} {btn2} {CM.Glyphs.VLine}"; @@ -833,9 +833,9 @@ public class DialogTests // Justify Assert.Equal (width, buttonRow.Length); - button1 = new () { Text = btn1Text }; - button2 = new () { Text = btn2Text }; - (runstate, dlg) = RunButtonTestDialog (title, width, Dialog.ButtonAlignments.Justify, button1, button2); + button1 = new Button { Text = btn1Text }; + button2 = new Button { Text = btn2Text }; + (runstate, dlg) = RunButtonTestDialog (title, width, Justification.Justified, button1, button2); button1.Visible = false; RunIteration (ref runstate, ref firstIteration); buttonRow = $@"{CM.Glyphs.VLine} {btn2}{CM.Glyphs.VLine}"; @@ -845,9 +845,9 @@ public class DialogTests // Right Assert.Equal (width, buttonRow.Length); - button1 = new () { Text = btn1Text }; - button2 = new () { Text = btn2Text }; - (runstate, dlg) = RunButtonTestDialog (title, width, Dialog.ButtonAlignments.Right, button1, button2); + button1 = new Button { Text = btn1Text }; + button2 = new Button { Text = btn2Text }; + (runstate, dlg) = RunButtonTestDialog (title, width, Justification.Right, button1, button2); button1.Visible = false; RunIteration (ref runstate, ref firstIteration); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); @@ -856,9 +856,9 @@ public class DialogTests // Left Assert.Equal (width, buttonRow.Length); - button1 = new () { Text = btn1Text }; - button2 = new () { Text = btn2Text }; - (runstate, dlg) = RunButtonTestDialog (title, width, Dialog.ButtonAlignments.Left, button1, button2); + button1 = new Button { Text = btn1Text }; + button2 = new Button { Text = btn2Text }; + (runstate, dlg) = RunButtonTestDialog (title, width, Justification.Left, button1, button2); button1.Visible = false; RunIteration (ref runstate, ref firstIteration); buttonRow = $@"{CM.Glyphs.VLine} {btn2} {CM.Glyphs.VLine}"; @@ -1281,7 +1281,7 @@ public class DialogTests (runstate, Dialog _) = RunButtonTestDialog ( title, width, - Dialog.ButtonAlignments.Center, + Justification.Centered, new Button { Text = btnText } ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); @@ -1334,7 +1334,7 @@ public class DialogTests int width = buttonRow.Length; d.SetBufferSize (buttonRow.Length, 3); - (runstate, Dialog dlg) = RunButtonTestDialog (title, width, Dialog.ButtonAlignments.Center, null); + (runstate, Dialog dlg) = RunButtonTestDialog (title, width, Justification.Centered, null); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); @@ -1344,7 +1344,7 @@ public class DialogTests private (RunState, Dialog) RunButtonTestDialog ( string title, int width, - Dialog.ButtonAlignments align, + Justification align, params Button [] btns ) { diff --git a/UnitTests/Drawing/JustifierTests.cs b/UnitTests/Drawing/JustifierTests.cs new file mode 100644 index 000000000..3f0a08188 --- /dev/null +++ b/UnitTests/Drawing/JustifierTests.cs @@ -0,0 +1,414 @@ +using System.Text; +using Xunit.Abstractions; + +namespace Terminal.Gui.DrawingTests; + +public class JustifierTests (ITestOutputHelper output) +{ + private readonly ITestOutputHelper _output = output; + + public static IEnumerable JustificationEnumValues () + { + foreach (object number in Enum.GetValues (typeof (Justification))) + { + yield return new [] { number }; + } + } + + [Theory] + [MemberData (nameof (JustificationEnumValues))] + public void NoItems_Works (Justification justification) + { + int [] sizes = { }; + int [] positions = new Justifier ().Justify (sizes, justification, 100); + Assert.Equal (new int [] { }, positions); + } + + //[Theory] + //[MemberData (nameof (JustificationEnumValues))] + //public void Items_Width_Cannot_Exceed_TotalSize (Justification justification) + //{ + // int [] sizes = { 1000, 2000, 3000 }; + // Assert.Throws (() => new Justifier ().Justify (sizes, justification, 100)); + //} + + [Theory] + [MemberData (nameof (JustificationEnumValues))] + public void Negative_Widths_Not_Allowed (Justification justification) + { + Assert.Throws (() => new Justifier ().Justify (new [] { -10, 20, 30 }, justification, 100)); + Assert.Throws (() => new Justifier ().Justify (new [] { 10, -20, 30 }, justification, 100)); + Assert.Throws (() => new Justifier ().Justify (new [] { 10, 20, -30 }, justification, 100)); + } + + [Theory] + [InlineData (Justification.Left, new [] { 0 }, 1, new [] { 0 })] + [InlineData (Justification.Left, new [] { 0, 0 }, 1, new [] { 0, 1 })] + [InlineData (Justification.Left, new [] { 0, 0, 0 }, 1, new [] { 0, 1, 1 })] + [InlineData (Justification.Left, new [] { 1 }, 1, new [] { 0 })] + [InlineData (Justification.Left, new [] { 1 }, 2, new [] { 0 })] + [InlineData (Justification.Left, new [] { 1 }, 3, new [] { 0 })] + [InlineData (Justification.Left, new [] { 1, 1 }, 2, new [] { 0, 1 })] + [InlineData (Justification.Left, new [] { 1, 1 }, 3, new [] { 0, 2 })] + [InlineData (Justification.Left, new [] { 1, 1 }, 4, new [] { 0, 2 })] + [InlineData (Justification.Left, new [] { 1, 1, 1 }, 3, new [] { 0, 1, 2 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 7, new [] { 0, 2, 4 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 10, new [] { 0, 2, 5 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 11, new [] { 0, 2, 5 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 12, new [] { 0, 2, 5 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 13, new [] { 0, 2, 5 })] + [InlineData (Justification.Left, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.Left, new [] { 1, 2, 3, 4 }, 11, new [] { 0, 2, 4, 7 })] + [InlineData (Justification.Left, new [] { 33, 33, 33 }, 100, new [] { 0, 34, 67 })] + [InlineData (Justification.Left, new [] { 10 }, 101, new [] { 0 })] + [InlineData (Justification.Left, new [] { 10, 20 }, 101, new [] { 0, 11 })] + [InlineData (Justification.Left, new [] { 10, 20, 30 }, 100, new [] { 0, 11, 32 })] + [InlineData (Justification.Left, new [] { 10, 20, 30 }, 101, new [] { 0, 11, 32 })] + [InlineData (Justification.Left, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 11, 31, 61 })] + [InlineData (Justification.Left, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 11, 31, 61, 101 })] + [InlineData (Justification.Right, new [] { 0 }, 1, new [] { 1 })] + [InlineData (Justification.Right, new [] { 0, 0 }, 1, new [] { 0, 1 })] + [InlineData (Justification.Right, new [] { 0, 0, 0 }, 1, new [] { 0, 1, 1 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 7, new [] { 0, 2, 4 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 10, new [] { 2, 4, 7 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 11, new [] { 3, 5, 8 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 12, new [] { 4, 6, 9 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 13, new [] { 5, 7, 10 })] + [InlineData (Justification.Right, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.Right, new [] { 1, 2, 3, 4 }, 11, new [] { 0, 2, 4, 7 })] + [InlineData (Justification.Right, new [] { 10, 20, 30 }, 100, new [] { 38, 49, 70 })] + [InlineData (Justification.Right, new [] { 33, 33, 33 }, 100, new [] { 0, 34, 67 })] + [InlineData (Justification.Right, new [] { 10 }, 101, new [] { 91 })] + [InlineData (Justification.Right, new [] { 10, 20 }, 101, new [] { 70, 81 })] + [InlineData (Justification.Right, new [] { 10, 20, 30 }, 101, new [] { 39, 50, 71 })] + [InlineData (Justification.Right, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 11, 31, 61 })] + [InlineData (Justification.Right, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 11, 31, 61, 101 })] + [InlineData (Justification.Centered, new [] { 0 }, 1, new [] { 0 })] + [InlineData (Justification.Centered, new [] { 0, 0 }, 1, new [] { 0, 1 })] + [InlineData (Justification.Centered, new [] { 0, 0, 0 }, 1, new [] { 0, 1, 1 })] + [InlineData (Justification.Centered, new [] { 1 }, 1, new [] { 0 })] + [InlineData (Justification.Centered, new [] { 1 }, 2, new [] { 0 })] + [InlineData (Justification.Centered, new [] { 1 }, 3, new [] { 1 })] + [InlineData (Justification.Centered, new [] { 1, 1 }, 2, new [] { 0, 1 })] + [InlineData (Justification.Centered, new [] { 1, 1 }, 3, new [] { 0, 2 })] + [InlineData (Justification.Centered, new [] { 1, 1 }, 4, new [] { 0, 2 })] + [InlineData (Justification.Centered, new [] { 1, 1, 1 }, 3, new [] { 0, 1, 2 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3 }, 7, new [] { 0, 2, 4 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3 }, 10, new [] { 1, 3, 6 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3 }, 11, new [] { 1, 3, 6 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3, 4 }, 11, new [] { 0, 2, 4, 7 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 9, new [] { 0, 3, 6 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 10, new [] { 0, 4, 7 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 11, new [] { 0, 4, 8 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 12, new [] { 0, 4, 8 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 13, new [] { 1, 5, 9 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 100, new [] { 0, 34, 67 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 101, new [] { 0, 34, 68 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 102, new [] { 0, 34, 68 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 103, new [] { 1, 35, 69 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 104, new [] { 1, 35, 69 })] + [InlineData (Justification.Centered, new [] { 10 }, 101, new [] { 45 })] + [InlineData (Justification.Centered, new [] { 10, 20 }, 101, new [] { 35, 46 })] + [InlineData (Justification.Centered, new [] { 10, 20, 30 }, 100, new [] { 19, 30, 51 })] + [InlineData (Justification.Centered, new [] { 10, 20, 30 }, 101, new [] { 19, 30, 51 })] + [InlineData (Justification.Centered, new [] { 10, 20, 30, 40 }, 100, new [] { 0, 10, 30, 60 })] + [InlineData (Justification.Centered, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 11, 31, 61 })] + [InlineData (Justification.Centered, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 11, 31, 61, 101 })] + [InlineData (Justification.Centered, new [] { 3, 4, 5, 6 }, 25, new [] { 2, 6, 11, 17 })] + [InlineData (Justification.Justified, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 11, 31, 61, 101 })] + [InlineData (Justification.Justified, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 11, 31, 61 })] + [InlineData (Justification.Justified, new [] { 10, 20, 30 }, 100, new [] { 0, 30, 70 })] + [InlineData (Justification.Justified, new [] { 10, 20, 30 }, 101, new [] { 0, 31, 71 })] + [InlineData (Justification.Justified, new [] { 33, 33, 33 }, 100, new [] { 0, 34, 67 })] + [InlineData (Justification.Justified, new [] { 11, 17, 23 }, 100, new [] { 0, 36, 77 })] + [InlineData (Justification.Justified, new [] { 1, 2, 3 }, 11, new [] { 0, 4, 8 })] + [InlineData (Justification.Justified, new [] { 10, 20 }, 101, new [] { 0, 81 })] + [InlineData (Justification.Justified, new [] { 10 }, 101, new [] { 0 })] + [InlineData (Justification.Justified, new [] { 3, 3, 3 }, 21, new [] { 0, 9, 18 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5 }, 21, new [] { 0, 8, 16 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5, 6 }, 18, new [] { 0, 3, 7, 12 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5, 6 }, 19, new [] { 0, 4, 8, 13 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5, 6 }, 20, new [] { 0, 4, 9, 14 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5, 6 }, 21, new [] { 0, 4, 9, 15 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 22, new [] { 0, 8, 14, 19 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 23, new [] { 0, 8, 15, 20 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 24, new [] { 0, 8, 15, 21 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 25, new [] { 0, 9, 16, 22 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 26, new [] { 0, 9, 17, 23 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 31, new [] { 0, 11, 20, 28 })] + [InlineData (Justification.LastRightRestLeft, new [] { 0 }, 1, new [] { 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 0, 0 }, 1, new [] { 0, 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 0, 0, 0 }, 1, new [] { 0, 1, 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1 }, 1, new [] { 0 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1 }, 2, new [] { 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1 }, 3, new [] { 2 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 1 }, 2, new [] { 0, 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 1 }, 3, new [] { 0, 2 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 1 }, 4, new [] { 0, 3 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 1, 1 }, 3, new [] { 0, 1, 2 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 7, new [] { 0, 2, 4 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 8, new [] { 0, 2, 5 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 9, new [] { 0, 2, 6 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 10, new [] { 0, 2, 7 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 11, new [] { 0, 2, 8 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3, 4 }, 11, new [] { 0, 2, 4, 7 })] + [InlineData (Justification.LastRightRestLeft, new [] { 3, 3, 3 }, 21, new [] { 0, 4, 18 })] + [InlineData (Justification.LastRightRestLeft, new [] { 3, 4, 5 }, 21, new [] { 0, 4, 16 })] + [InlineData (Justification.LastRightRestLeft, new [] { 33, 33, 33 }, 100, new [] { 0, 34, 67 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10 }, 101, new [] { 91 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20 }, 101, new [] { 0, 81 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20, 30 }, 100, new [] { 0, 11, 70 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20, 30 }, 101, new [] { 0, 11, 71 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 11, 31, 61 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 11, 31, 61, 101 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 0 }, 1, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 0, 0 }, 1, new [] { 0, 1 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 0, 0, 0 }, 1, new [] { 0, 0, 1 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1 }, 1, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1 }, 2, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1 }, 3, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 1 }, 2, new [] { 0, 1 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 1 }, 3, new [] { 0, 2 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 1 }, 4, new [] { 0, 3 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 1, 1 }, 3, new [] { 0, 1, 2 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 7, new [] { 0, 1, 4 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 8, new [] { 0, 2, 5 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 9, new [] { 0, 3, 6 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 10, new [] { 0, 4, 7 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 11, new [] { 0, 5, 8 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3, 4 }, 11, new [] { 0, 1, 3, 7 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3, 4 }, 12, new [] { 0, 1, 4, 8 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 3, 3, 3 }, 21, new [] { 0, 14, 18 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 3, 4, 5 }, 21, new [] { 0, 11, 16 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 33, 33, 33 }, 100, new [] { 0, 33, 67 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10 }, 101, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20 }, 101, new [] { 0, 81 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20, 30 }, 100, new [] { 0, 49, 70 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20, 30 }, 101, new [] { 0, 50, 71 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 10, 30, 61 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 10, 30, 60, 101 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 3, 3, 3 }, 21, new [] { 0, 14, 18 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 3, 4, 5 }, 21, new [] { 0, 11, 16 })] + public void TestJustifications_PutSpaceBetweenItems (Justification justification, int [] sizes, int totalSize, int [] expected) + { + int [] positions = new Justifier { PutSpaceBetweenItems = true }.Justify (sizes, justification, totalSize); + AssertJustification (justification, sizes, totalSize, positions, expected); + } + + [Theory] + [InlineData (Justification.Left, new [] { 0 }, 1, new [] { 0 })] + [InlineData (Justification.Left, new [] { 0, 0 }, 1, new [] { 0, 0 })] + [InlineData (Justification.Left, new [] { 0, 0, 0 }, 1, new [] { 0, 0, 0 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 7, new [] { 0, 1, 3 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 10, new [] { 0, 1, 3 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 11, new [] { 0, 1, 3 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 12, new [] { 0, 1, 3 })] + [InlineData (Justification.Left, new [] { 1, 2, 3 }, 13, new [] { 0, 1, 3 })] + [InlineData (Justification.Left, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.Left, new [] { 1, 2, 3, 4 }, 11, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.Left, new [] { 10, 20, 30 }, 100, new [] { 0, 10, 30 })] + [InlineData (Justification.Left, new [] { 33, 33, 33 }, 100, new [] { 0, 33, 66 })] + [InlineData (Justification.Left, new [] { 10 }, 101, new [] { 0 })] + [InlineData (Justification.Left, new [] { 10, 20 }, 101, new [] { 0, 10 })] + [InlineData (Justification.Left, new [] { 10, 20, 30 }, 101, new [] { 0, 10, 30 })] + [InlineData (Justification.Left, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 10, 30, 60 })] + [InlineData (Justification.Left, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 10, 30, 60, 100 })] + [InlineData (Justification.Right, new [] { 0 }, 1, new [] { 1 })] + [InlineData (Justification.Right, new [] { 0, 0 }, 1, new [] { 1, 1 })] + [InlineData (Justification.Right, new [] { 0, 0, 0 }, 1, new [] { 1, 1, 1 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 7, new [] { 1, 2, 4 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 10, new [] { 4, 5, 7 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 11, new [] { 5, 6, 8 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 12, new [] { 6, 7, 9 })] + [InlineData (Justification.Right, new [] { 1, 2, 3 }, 13, new [] { 7, 8, 10 })] + [InlineData (Justification.Right, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.Right, new [] { 1, 2, 3, 4 }, 11, new [] { 1, 2, 4, 7 })] + [InlineData (Justification.Right, new [] { 10, 20, 30 }, 100, new [] { 40, 50, 70 })] + [InlineData (Justification.Right, new [] { 33, 33, 33 }, 100, new [] { 1, 34, 67 })] + [InlineData (Justification.Right, new [] { 10 }, 101, new [] { 91 })] + [InlineData (Justification.Right, new [] { 10, 20 }, 101, new [] { 71, 81 })] + [InlineData (Justification.Right, new [] { 10, 20, 30 }, 101, new [] { 41, 51, 71 })] + [InlineData (Justification.Right, new [] { 10, 20, 30, 40 }, 101, new [] { 1, 11, 31, 61 })] + [InlineData (Justification.Right, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 1, 11, 31, 61, 101 })] + [InlineData (Justification.Centered, new [] { 1 }, 1, new [] { 0 })] + [InlineData (Justification.Centered, new [] { 1 }, 2, new [] { 0 })] + [InlineData (Justification.Centered, new [] { 1 }, 3, new [] { 1 })] + [InlineData (Justification.Centered, new [] { 1, 1 }, 2, new [] { 0, 1 })] + [InlineData (Justification.Centered, new [] { 1, 1 }, 3, new [] { 0, 1 })] + [InlineData (Justification.Centered, new [] { 1, 1 }, 4, new [] { 1, 2 })] + [InlineData (Justification.Centered, new [] { 1, 1, 1 }, 3, new [] { 0, 1, 2 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3 }, 7, new [] { 0, 1, 3 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3 }, 10, new [] { 2, 3, 5 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3 }, 11, new [] { 2, 3, 5 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.Centered, new [] { 1, 2, 3, 4 }, 11, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 9, new [] { 0, 3, 6 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 10, new [] { 0, 3, 6 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 11, new [] { 1, 4, 7 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 12, new [] { 1, 4, 7 })] + [InlineData (Justification.Centered, new [] { 3, 3, 3 }, 13, new [] { 2, 5, 8 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 100, new [] { 0, 33, 66 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 101, new [] { 1, 34, 67 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 102, new [] { 1, 34, 67 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 103, new [] { 2, 35, 68 })] + [InlineData (Justification.Centered, new [] { 33, 33, 33 }, 104, new [] { 2, 35, 68 })] + [InlineData (Justification.Centered, new [] { 3, 4, 5, 6 }, 25, new [] { 3, 6, 10, 15 })] + [InlineData (Justification.Justified, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 11, 31, 61, 101 })] + [InlineData (Justification.Justified, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 11, 31, 61 })] + [InlineData (Justification.Justified, new [] { 10, 20, 30 }, 100, new [] { 0, 30, 70 })] + [InlineData (Justification.Justified, new [] { 10, 20, 30 }, 101, new [] { 0, 31, 71 })] + [InlineData (Justification.Justified, new [] { 33, 33, 33 }, 100, new [] { 0, 34, 67 })] + [InlineData (Justification.Justified, new [] { 11, 17, 23 }, 100, new [] { 0, 36, 77 })] + [InlineData (Justification.Justified, new [] { 1, 2, 3 }, 11, new [] { 0, 4, 8 })] + [InlineData (Justification.Justified, new [] { 10, 20 }, 101, new [] { 0, 81 })] + [InlineData (Justification.Justified, new [] { 10 }, 101, new [] { 0 })] + [InlineData (Justification.Justified, new [] { 3, 3, 3 }, 21, new [] { 0, 9, 18 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5 }, 21, new [] { 0, 8, 16 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5, 6 }, 18, new [] { 0, 3, 7, 12 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5, 6 }, 19, new [] { 0, 4, 8, 13 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5, 6 }, 20, new [] { 0, 4, 9, 14 })] + [InlineData (Justification.Justified, new [] { 3, 4, 5, 6 }, 21, new [] { 0, 4, 9, 15 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 22, new [] { 0, 8, 14, 19 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 23, new [] { 0, 8, 15, 20 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 24, new [] { 0, 8, 15, 21 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 25, new [] { 0, 9, 16, 22 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 26, new [] { 0, 9, 17, 23 })] + [InlineData (Justification.Justified, new [] { 6, 5, 4, 3 }, 31, new [] { 0, 11, 20, 28 })] + [InlineData (Justification.LastRightRestLeft, new [] { 0 }, 1, new [] { 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 0, 0 }, 1, new [] { 0, 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 0, 0, 0 }, 1, new [] { 0, 0, 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1 }, 1, new [] { 0 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1 }, 2, new [] { 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1 }, 3, new [] { 2 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 1 }, 2, new [] { 0, 1 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 1 }, 3, new [] { 0, 2 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 1 }, 4, new [] { 0, 3 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 1, 1 }, 3, new [] { 0, 1, 2 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 7, new [] { 0, 1, 4 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 8, new [] { 0, 1, 5 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 9, new [] { 0, 1, 6 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 10, new [] { 0, 1, 7 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3 }, 11, new [] { 0, 1, 8 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3, 4 }, 11, new [] { 0, 1, 3, 7 })] + [InlineData (Justification.LastRightRestLeft, new [] { 1, 2, 3, 4 }, 12, new [] { 0, 1, 3, 8 })] + [InlineData (Justification.LastRightRestLeft, new [] { 3, 3, 3 }, 21, new [] { 0, 3, 18 })] + [InlineData (Justification.LastRightRestLeft, new [] { 3, 4, 5 }, 21, new [] { 0, 3, 16 })] + [InlineData (Justification.LastRightRestLeft, new [] { 33, 33, 33 }, 100, new [] { 0, 33, 67 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10 }, 101, new [] { 91 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20 }, 101, new [] { 0, 81 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20, 30 }, 100, new [] { 0, 10, 70 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20, 30 }, 101, new [] { 0, 10, 71 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 10, 30, 61 })] + [InlineData (Justification.LastRightRestLeft, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 10, 30, 60, 101 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 0 }, 1, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 0, 0 }, 1, new [] { 0, 1 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 0, 0, 0 }, 1, new [] { 0, 1, 1 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1 }, 1, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1 }, 2, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1 }, 3, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 1 }, 2, new [] { 0, 1 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 1 }, 3, new [] { 0, 2 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 1 }, 4, new [] { 0, 3 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 1, 1 }, 3, new [] { 0, 1, 2 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 6, new [] { 0, 1, 3 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 7, new [] { 0, 2, 4 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 8, new [] { 0, 3, 5 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 9, new [] { 0, 4, 6 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 10, new [] { 0, 5, 7 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3 }, 11, new [] { 0, 6, 8 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3, 4 }, 10, new [] { 0, 1, 3, 6 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3, 4 }, 11, new [] { 0, 2, 4, 7 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 1, 2, 3, 4 }, 12, new [] { 0, 3, 5, 8 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 3, 3, 3 }, 21, new [] { 0, 15, 18 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 3, 4, 5 }, 21, new [] { 0, 12, 16 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 33, 33, 33 }, 100, new [] { 0, 34, 67 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10 }, 101, new [] { 0 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20 }, 101, new [] { 0, 81 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20, 30 }, 100, new [] { 0, 50, 70 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20, 30 }, 101, new [] { 0, 51, 71 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20, 30, 40 }, 101, new [] { 0, 11, 31, 61 })] + [InlineData (Justification.FirstLeftRestRight, new [] { 10, 20, 30, 40, 50 }, 151, new [] { 0, 11, 31, 61, 101 })] + public void TestJustifications_NoSpaceBetweenItems (Justification justification, int [] sizes, int totalSize, int [] expected) + { + int [] positions = new Justifier { PutSpaceBetweenItems = false }.Justify (sizes, justification, totalSize); + AssertJustification (justification, sizes, totalSize, positions, expected); + } + + public void AssertJustification (Justification justification, int [] sizes, int totalSize, int [] positions, int [] expected) + { + try + { + _output.WriteLine ($"Testing: {RenderJustification (justification, sizes, totalSize, expected)}"); + } + catch (Exception e) + { + _output.WriteLine ($"Exception rendering expected: {e.Message}"); + _output.WriteLine ($"Actual: {RenderJustification (justification, sizes, totalSize, positions)}"); + } + + if (!expected.SequenceEqual (positions)) + { + _output.WriteLine ($"Expected: {RenderJustification (justification, sizes, totalSize, expected)}"); + _output.WriteLine ($"Actual: {RenderJustification (justification, sizes, totalSize, positions)}"); + Assert.Fail (" Expected and actual do not match"); + } + } + + public string RenderJustification (Justification justification, int [] sizes, int totalSize, int [] positions) + { + var output = new StringBuilder (); + output.AppendLine ($"Justification: {justification}, Positions: {string.Join (", ", positions)}, TotalSize: {totalSize}"); + + for (var i = 0; i <= totalSize / 10; i++) + { + output.Append (i.ToString ().PadRight (9) + " "); + } + + output.AppendLine (); + + for (var i = 0; i < totalSize; i++) + { + output.Append (i % 10); + } + + output.AppendLine (); + + var items = new char [totalSize]; + + for (var position = 0; position < positions.Length; position++) + { + // try + { + for (var j = 0; j < sizes [position] && positions [position] + j < totalSize; j++) + { + items [positions [position] + j] = (position + 1).ToString () [0]; + } + } + + //catch (Exception e) + //{ + // output.AppendLine ($"{e.Message} - position = {position}, positions[{position}]: {positions [position]}, sizes[{position}]: {sizes [position]}, totalSize: {totalSize}"); + // output.Append (new string (items).Replace ('\0', ' ')); + + // Assert.Fail (e.Message + output.ToString ()); + //} + } + + output.Append (new string (items).Replace ('\0', ' ')); + + return output.ToString (); + } +}