diff --git a/Terminal.Gui/Drawing/Aligner.cs b/Terminal.Gui/Drawing/Aligner.cs index b230d1352..df880bbfb 100644 --- a/Terminal.Gui/Drawing/Aligner.cs +++ b/Terminal.Gui/Drawing/Aligner.cs @@ -12,6 +12,11 @@ public class Aligner : INotifyPropertyChanged /// /// Gets or sets how the aligns items within a container. /// + /// + /// + /// provides additional options for aligning items in a container. + /// + /// public Alignment Alignment { get => _alignment; @@ -22,6 +27,21 @@ public class Aligner : INotifyPropertyChanged } } + private AlignmentModes _alignmentMode = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems; + + /// + /// Gets or sets the modes controlling . + /// + public AlignmentModes AlignmentMode + { + get => _alignmentMode; + set + { + _alignmentMode = value; + PropertyChanged?.Invoke (this, new (nameof (AlignmentMode))); + } + } + private int _containerSize; /// @@ -37,70 +57,39 @@ public class Aligner : INotifyPropertyChanged } } - private bool _spaceBetweenItems; - - /// - /// Gets or sets whether adds at least one space between items. Default is - /// . - /// - /// - /// - /// If the total size of the items is greater than the container size, the space between items will be ignored - /// starting from the right or bottom. - /// - /// - public bool SpaceBetweenItems - { - get => _spaceBetweenItems; - set - { - _spaceBetweenItems = value; - PropertyChanged?.Invoke (this, new (nameof (SpaceBetweenItems))); - } - } - /// public event PropertyChangedEventHandler PropertyChanged; /// /// Takes a list of item sizes and returns a list of the positions of those items when aligned within - /// using the and settings. + /// using the and settings. /// /// The sizes of the items to align. /// The locations of the items, from left/top to right/bottom. - public int [] Align (int [] sizes) { return Align (Alignment, SpaceBetweenItems, ContainerSize, sizes); } + public int [] Align (int [] sizes) { return Align (Alignment, AlignmentMode, ContainerSize, sizes); } /// /// Takes a list of item sizes and returns a list of the positions of those items when aligned within /// using specified parameters. /// - /// The sizes of the items to align. /// Specifies how the items will be aligned. - /// - /// - /// Indicates whether at least one space should be added between items. - /// - /// - /// If the total size of the items is greater than the container size, the space between items will be ignored - /// starting from the right or bottom. - /// - /// + /// /// The size of the container. + /// The sizes of the items to align. /// The positions of the items, from left/top to right/bottom. - public static int [] Align (Alignment alignment, bool spaceBetweenItems, int containerSize, int [] sizes) + public static int [] Align (in Alignment alignment, in AlignmentModes alignmentMode, int containerSize, int [] sizes) { if (sizes.Length == 0) { return new int [] { }; } - int maxSpaceBetweenItems = spaceBetweenItems ? 1 : 0; + int maxSpaceBetweenItems = alignmentMode.HasFlag (AlignmentModes.AddSpaceBetweenItems) ? 1 : 0; var positions = new int [sizes.Length]; // positions of the items. the return value. int totalItemsSize = sizes.Sum (); int totalGaps = sizes.Length - 1; // total gaps between items 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) @@ -112,159 +101,62 @@ public class Aligner : INotifyPropertyChanged spaces = containerSize - totalItemsSize; } + var currentPosition = 0; + switch (alignment) { case Alignment.Start: - var currentPosition = 0; - - for (var i = 0; i < sizes.Length; i++) + switch (alignmentMode & ~AlignmentModes.AddSpaceBetweenItems) { - CheckSizeCannotBeNegative (i, sizes); + case AlignmentModes.StartToEnd: + Start (sizes, positions, ref spaces, maxSpaceBetweenItems); - if (i == 0) - { - positions [0] = 0; // first item position + break; - continue; - } + case AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast: + IgnoreLast (sizes, containerSize, positions, maxSpaceBetweenItems, totalItemsSize, spaces, currentPosition); - int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0; + break; - // subsequent items are placed one space after the previous item - positions [i] = positions [i - 1] + sizes [i - 1] + spaceBefore; + case AlignmentModes.EndToStart: + case AlignmentModes.EndToStart | AlignmentModes.IgnoreFirstOrLast: + throw new NotImplementedException ("EndToStart is not implemented."); + + break; } break; case Alignment.End: - currentPosition = containerSize - totalItemsSize - spaces; - - for (var i = 0; i < sizes.Length; i++) + switch (alignmentMode & ~AlignmentModes.AddSpaceBetweenItems) { - CheckSizeCannotBeNegative (i, sizes); - int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0; + case AlignmentModes.StartToEnd: + End (containerSize, sizes, totalItemsSize, spaces, maxSpaceBetweenItems, positions); + + break; + + case AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast: + IgnoreFirst (sizes, containerSize, positions, maxSpaceBetweenItems, totalItemsSize, spaces, currentPosition); + + break; + + case AlignmentModes.EndToStart: + case AlignmentModes.EndToStart | AlignmentModes.IgnoreFirstOrLast: + throw new NotImplementedException ("EndToStart is not implemented."); + + break; - positions [i] = currentPosition; - currentPosition += sizes [i] + spaceBefore; } break; case Alignment.Center: - 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++) - { - CheckSizeCannotBeNegative (i, sizes); - - 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) - { - CheckSizeCannotBeNegative (0, sizes); - positions [0] = (containerSize - sizes [0]) / 2; // single item is centered - } + Center (containerSize, sizes, totalItemsSize, spaces, positions, maxSpaceBetweenItems); break; case Alignment.Fill: - 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++) - { - CheckSizeCannotBeNegative (i, sizes); - positions [i] = currentPosition; - int extraSpace = i < remainder ? 1 : 0; - currentPosition += sizes [i] + spaceBetween + extraSpace; - } - - break; - - // 111 2222 33333 - case Alignment.LastEndRestStart: - if (sizes.Length > 1) - { - if (totalItemsSize > containerSize) - { - currentPosition = containerSize - totalItemsSize - spaces; - } - else - { - currentPosition = 0; - } - - for (var i = 0; i < sizes.Length; i++) - { - CheckSizeCannotBeNegative (i, sizes); - - if (i < sizes.Length - 1) - { - int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0; - - positions [i] = currentPosition; - currentPosition += sizes [i] + spaceBefore; - } - } - - positions [sizes.Length - 1] = containerSize - sizes [^1]; - } - else if (sizes.Length == 1) - { - CheckSizeCannotBeNegative (0, sizes); - - positions [0] = containerSize - sizes [0]; // single item is flush right - } - - break; - - // 111 2222 33333 - case Alignment.FirstStartRestEnd: - if (sizes.Length > 1) - { - currentPosition = 0; - positions [0] = currentPosition; // first item is flush left - - for (int i = sizes.Length - 1; i >= 0; i--) - { - CheckSizeCannotBeNegative (i, sizes); - - if (i == sizes.Length - 1) - { - // start at right - currentPosition = Math.Max (totalItemsSize, 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) - { - CheckSizeCannotBeNegative (0, sizes); - positions [0] = 0; // single item is flush left - } + Fill (containerSize, sizes, totalItemsSize, positions); break; @@ -275,6 +167,158 @@ public class Aligner : INotifyPropertyChanged return positions; } + private static void Start (int [] sizes, int [] positions, ref int spaces, int maxSpaceBetweenItems) + { + for (var i = 0; i < sizes.Length; i++) + { + CheckSizeCannotBeNegative (i, sizes); + + 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; + } + } + + private static void IgnoreFirst (int [] sizes, int containerSize, int [] positions, int maxSpaceBetweenItems, int totalItemsSize, int spaces, int currentPosition) + { + if (sizes.Length > 1) + { + currentPosition = 0; + positions [0] = currentPosition; // first item is flush left + + for (int i = sizes.Length - 1; i >= 0; i--) + { + CheckSizeCannotBeNegative (i, sizes); + + if (i == sizes.Length - 1) + { + // start at right + currentPosition = Math.Max (totalItemsSize, 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) + { + CheckSizeCannotBeNegative (0, sizes); + positions [0] = 0; // single item is flush left + } + } + + private static void IgnoreLast (int [] sizes, int containerSize, int [] positions, int maxSpaceBetweenItems, int totalItemsSize, int spaces, int currentPosition) + { + if (sizes.Length > 1) + { + if (totalItemsSize > containerSize) + { + currentPosition = containerSize - totalItemsSize - spaces; + } + else + { + currentPosition = 0; + } + + for (var i = 0; i < sizes.Length; i++) + { + CheckSizeCannotBeNegative (i, sizes); + + if (i < sizes.Length - 1) + { + int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0; + + positions [i] = currentPosition; + currentPosition += sizes [i] + spaceBefore; + } + } + + positions [sizes.Length - 1] = containerSize - sizes [^1]; + } + else if (sizes.Length == 1) + { + CheckSizeCannotBeNegative (0, sizes); + + positions [0] = containerSize - sizes [0]; // single item is flush right + } + } + + private static void Fill (int containerSize, int [] sizes, int totalItemsSize, int [] positions) + { + int currentPosition; + 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++) + { + CheckSizeCannotBeNegative (i, sizes); + positions [i] = currentPosition; + int extraSpace = i < remainder ? 1 : 0; + currentPosition += sizes [i] + spaceBetween + extraSpace; + } + } + + private static void Center (int containerSize, int [] sizes, int totalItemsSize, int spaces, int [] positions, int maxSpaceBetweenItems) + { + 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++) + { + CheckSizeCannotBeNegative (i, sizes); + + 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) + { + CheckSizeCannotBeNegative (0, sizes); + positions [0] = (containerSize - sizes [0]) / 2; // single item is centered + } + } + + private static void End (int containerSize, int [] sizes, int totalItemsSize, int spaces, int maxSpaceBetweenItems, int [] positions) + { + int currentPosition; + currentPosition = containerSize - totalItemsSize - spaces; + + for (var i = 0; i < sizes.Length; i++) + { + CheckSizeCannotBeNegative (i, sizes); + int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0; + + positions [i] = currentPosition; + currentPosition += sizes [i] + spaceBefore; + } + } + private static void CheckSizeCannotBeNegative (int i, int [] sizes) { if (sizes [i] < 0) diff --git a/Terminal.Gui/Drawing/Alignment.cs b/Terminal.Gui/Drawing/Alignment.cs index ba38eb907..5a32cb491 100644 --- a/Terminal.Gui/Drawing/Alignment.cs +++ b/Terminal.Gui/Drawing/Alignment.cs @@ -13,6 +13,9 @@ public enum Alignment /// If the container is smaller than the total size of the items, the end items will be clipped (their locations /// will be greater than the container size). /// + /// + /// The enumeration provides additional options for aligning items in a container. + /// /// /// /// @@ -29,6 +32,9 @@ public enum Alignment /// If the container is smaller than the total size of the items, the start items will be clipped (their locations /// will be negative). /// + /// + /// The enumeration provides additional options for aligning items in a container. + /// /// /// /// @@ -69,36 +75,4 @@ public enum Alignment /// /// Fill, - - /// - /// The first item will be aligned to the start and the remaining will aligned to the end. - /// - /// - /// - /// If the container is smaller than the total size of the items, the end items will be clipped (their locations - /// will be greater than the container size). - /// - /// - /// - /// - /// |111 2222 33333| - /// - /// - FirstStartRestEnd, - - /// - /// The last item will be aligned to the end and the remaining will aligned to the start. - /// - /// - /// - /// If the container is smaller than the total size of the items, the start items will be clipped (their locations - /// will be negative). - /// - /// - /// - /// - /// |111 2222 33333| - /// - /// - LastEndRestStart } \ No newline at end of file diff --git a/Terminal.Gui/Drawing/AlignmentModes.cs b/Terminal.Gui/Drawing/AlignmentModes.cs new file mode 100644 index 000000000..abd88a397 --- /dev/null +++ b/Terminal.Gui/Drawing/AlignmentModes.cs @@ -0,0 +1,49 @@ +namespace Terminal.Gui; + +/// +/// Determines alignment modes for . +/// +[Flags] +public enum AlignmentModes +{ + /// + /// The items will be arranged from start (left/top) to end (right/bottom). + /// + StartToEnd = 0, + + /// + /// The items will be arranged from end (right/bottom) to start (left/top). + /// + /// + /// Not implemented. + /// + EndToStart = 1, + + /// + /// At least one space will be added between items. Useful for justifying text where at least one space is needed. + /// + /// + /// + /// If the total size of the items is greater than the container size, the space between items will be ignored + /// starting from the end. + /// + /// + AddSpaceBetweenItems = 2, + + /// + /// When aligning via or , the item opposite to the alignment (the first or last item) will be ignored. + /// + /// + /// + /// If the container is smaller than the total size of the items, the end items will be clipped (their locations + /// will be greater than the container size). + /// + /// + /// + /// + /// Start: |111 2222 33333| + /// End: |111 2222 33333| + /// + /// + IgnoreFirstOrLast = 4, +} \ No newline at end of file diff --git a/Terminal.Gui/Drawing/FlowModes.cs b/Terminal.Gui/Drawing/FlowModes.cs deleted file mode 100644 index d2c354505..000000000 --- a/Terminal.Gui/Drawing/FlowModes.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Terminal.Gui; - -/// -/// Determines how items will be arranged in a container when alignment is or , -/// -[Flags] -public enum FlowModes -{ - /// - /// The items will be arranged from start (left/top) to end (right/bottom). - /// - StartToEnd = 0, - - /// - /// The items will be arranged from end (right/bottom) to start (left/top). - /// - /// - /// Not implemented. - /// - EndToStart = 1, - - /// - /// When aligning via or , the first item will be aligned at the opposite end. - /// - IgnoreFirst = 2, - - /// - /// When aligning via or , the last item will be aligned at the opposite end. - /// - IgnoreLast = 4, -} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/Pos.cs b/Terminal.Gui/View/Layout/Pos.cs index 3c9f41864..2e630e812 100644 --- a/Terminal.Gui/View/Layout/Pos.cs +++ b/Terminal.Gui/View/Layout/Pos.cs @@ -144,13 +144,17 @@ public abstract class Pos /// /// Creates a object that aligns a set of views according to the specified alignment setting. /// - /// + /// The alignment. + /// The optional alignment modes. /// /// The optional, unique identifier for the set of views to align according to /// . /// /// - public static Pos Align (Alignment alignment, int groupId = 0) { return new PosAlign (alignment, groupId); } + public static Pos Align (Alignment alignment, AlignmentModes mode = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems, int groupId = 0) + { + return new PosAlign (alignment, mode, groupId); + } /// /// Creates a object that is anchored to the end (right side or diff --git a/Terminal.Gui/View/Layout/PosAlign.cs b/Terminal.Gui/View/Layout/PosAlign.cs index 9ca4a203b..fd6275fc0 100644 --- a/Terminal.Gui/View/Layout/PosAlign.cs +++ b/Terminal.Gui/View/Layout/PosAlign.cs @@ -108,11 +108,12 @@ public class PosAlign : Pos /// Enables alignment of a set of views. /// /// + /// /// The unique identifier for the set of views to align according to . - public PosAlign (Alignment alignment, int groupId = 0) + public PosAlign (Alignment alignment, AlignmentModes mode = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems, int groupId = 0) { - Aligner.SpaceBetweenItems = true; Aligner.Alignment = alignment; + Aligner.AlignmentMode = mode; _groupId = groupId; Aligner.PropertyChanged += Aligner_PropertyChanged; } diff --git a/Terminal.Gui/Views/Wizard/Wizard.cs b/Terminal.Gui/Views/Wizard/Wizard.cs index 53a84ad8e..e29a7f5df 100644 --- a/Terminal.Gui/Views/Wizard/Wizard.cs +++ b/Terminal.Gui/Views/Wizard/Wizard.cs @@ -66,8 +66,8 @@ public class Wizard : Dialog /// public Wizard () { - // TODO: LastRightRestLeft will enable a "Quit" button to always appear at the far left - ButtonAlignment = Alignment.LastEndRestStart; + // TODO: LastEndRestStart will enable a "Quit" button to always appear at the far left + // ButtonAlignment = Alignment.LastEndRestStart; BorderStyle = LineStyle.Double; //// Add a horiz separator diff --git a/Terminal.sln.DotSettings b/Terminal.sln.DotSettings index 2bb065af1..8ca3af1c0 100644 --- a/Terminal.sln.DotSettings +++ b/Terminal.sln.DotSettings @@ -391,6 +391,7 @@ <Policy><Descriptor Staticness="Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Instance fields (not private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy> <Policy><Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static fields (not private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy> <Policy><Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy> + PushToShowHints True True True diff --git a/UICatalog/Scenarios/Buttons.cs b/UICatalog/Scenarios/Buttons.cs index ccce3bc2f..d8e612ae5 100644 --- a/UICatalog/Scenarios/Buttons.cs +++ b/UICatalog/Scenarios/Buttons.cs @@ -218,7 +218,7 @@ public class Buttons : Scenario X = 4, Y = Pos.Bottom (label) + 1, SelectedItem = 2, - RadioLabels = new [] { "Left", "Right", "Centered", "Justified" } + RadioLabels = new [] { "Start", "End", "Center", "Fill" } }; main.Add (radioGroup); diff --git a/UICatalog/Scenarios/Dialogs.cs b/UICatalog/Scenarios/Dialogs.cs index 54ce3bba3..5270d3766 100644 --- a/UICatalog/Scenarios/Dialogs.cs +++ b/UICatalog/Scenarios/Dialogs.cs @@ -146,7 +146,7 @@ public class Dialogs : Scenario }; frame.Add (label); - var labels = new [] { "Left", "Centered", "Right", "Justified", "FirstLeftRestRight", "LastRightRestLeft" }; + var labels = new [] { "Start", "End", "Center", "Fill", "FirstStartRestEnd", "LastEndRestStart" }; var alignmentGroup = new RadioGroup { X = Pos.Right (label) + 1, diff --git a/UICatalog/Scenarios/PosAlignDemo.cs b/UICatalog/Scenarios/PosAlignDemo.cs index 1b75dc343..bce4ea010 100644 --- a/UICatalog/Scenarios/PosAlignDemo.cs +++ b/UICatalog/Scenarios/PosAlignDemo.cs @@ -25,11 +25,11 @@ public sealed class PosAlignDemo : Scenario Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()} - {GetDescription ()}" }; - SetupHorizontalControls (appWindow); + SetupControls (appWindow, Dimension.Width, Colors.ColorSchemes ["Toplevel"]); - SetupVerticalControls (appWindow); + SetupControls (appWindow, Dimension.Height, Colors.ColorSchemes ["Error"]); - Setup3by3Grid (appWindow); + //Setup3by3Grid (appWindow); // Run - Start the application. Application.Run (appWindow); @@ -39,82 +39,154 @@ public sealed class PosAlignDemo : Scenario Application.Shutdown (); } - private void SetupHorizontalControls (Window appWindow) + private void SetupControls (Window appWindow, Dimension dimension, ColorScheme colorScheme) { - ColorScheme colorScheme = Colors.ColorSchemes ["Toplevel"]; - RadioGroup alignRadioGroup = new () { - X = Pos.Align (_horizAligner.Alignment), - Y = Pos.Center (), - RadioLabels = new [] { "Start", "End", "Center", "Fill", "FirstLeftRestRight", "LastRightRestLeft" }, + RadioLabels = Enum.GetNames (), ColorScheme = colorScheme }; - alignRadioGroup.SelectedItemChanged += (s, e) => - { - _horizAligner.Alignment = - (Alignment)Enum.Parse (typeof (Alignment), alignRadioGroup.RadioLabels [alignRadioGroup.SelectedItem]); + if (dimension == Dimension.Width) + { + alignRadioGroup.X = Pos.Align (_horizAligner.Alignment); + alignRadioGroup.Y = Pos.Center (); + } + else + { + alignRadioGroup.X = Pos.Center (); + alignRadioGroup.Y = Pos.Align (_vertAligner.Alignment); + } - foreach (View view in appWindow.Subviews.Where (v => v.X is PosAlign)) - { - if (view.X is PosAlign j) - { - var newJust = new PosAlign (_horizAligner.Alignment) - { - Aligner = - { - SpaceBetweenItems = _horizAligner.SpaceBetweenItems - } - }; - view.X = newJust; - } - } - }; + alignRadioGroup.SelectedItemChanged += (s, e) => + { + if (dimension == Dimension.Width) + { + _horizAligner.Alignment = + (Alignment)Enum.Parse (typeof (Alignment), alignRadioGroup.RadioLabels [alignRadioGroup.SelectedItem]); + UpdatePosAlignObjects (appWindow, dimension, _horizAligner); + } + else + { + _vertAligner.Alignment = + (Alignment)Enum.Parse (typeof (Alignment), alignRadioGroup.RadioLabels [alignRadioGroup.SelectedItem]); + UpdatePosAlignObjects (appWindow, dimension, _vertAligner); + } + + }; appWindow.Add (alignRadioGroup); - CheckBox putSpaces = new () + + CheckBox ignoreFirstOrLast = new () { - X = Pos.Align (_horizAligner.Alignment), - Y = Pos.Top (alignRadioGroup), ColorScheme = colorScheme, - Text = "Spaces", - Checked = true + Text = "IgnoreFirstOrLast", }; - putSpaces.Toggled += (s, e) => - { - _horizAligner.SpaceBetweenItems = e.NewValue is { } && e.NewValue.Value; + if (dimension == Dimension.Width) + { + ignoreFirstOrLast.Checked = _horizAligner.AlignmentMode.HasFlag (AlignmentModes.IgnoreFirstOrLast); + ignoreFirstOrLast.X = Pos.Align (_horizAligner.Alignment); + ignoreFirstOrLast.Y = Pos.Top (alignRadioGroup); + } + else + { + ignoreFirstOrLast.Checked = _vertAligner.AlignmentMode.HasFlag (AlignmentModes.IgnoreFirstOrLast); + ignoreFirstOrLast.X = Pos.Left (alignRadioGroup); + ignoreFirstOrLast.Y = Pos.Align (_vertAligner.Alignment); + } - foreach (View view in appWindow.Subviews.Where (v => v.X is PosAlign)) + ignoreFirstOrLast.Toggled += (s, e) => + { + if (dimension == Dimension.Width) + { + _horizAligner.AlignmentMode = e.NewValue is { } && + e.NewValue.Value ? + _horizAligner.AlignmentMode | AlignmentModes.IgnoreFirstOrLast : + _horizAligner.AlignmentMode & ~AlignmentModes.IgnoreFirstOrLast; + UpdatePosAlignObjects (appWindow, dimension, _horizAligner); + } + else + { + _vertAligner.AlignmentMode = e.NewValue is { } && + e.NewValue.Value ? + _vertAligner.AlignmentMode | AlignmentModes.IgnoreFirstOrLast : + _vertAligner.AlignmentMode & ~AlignmentModes.IgnoreFirstOrLast; + UpdatePosAlignObjects (appWindow, dimension, _vertAligner); + } + }; + appWindow.Add (ignoreFirstOrLast); + + CheckBox addSpacesBetweenItems = new () + { + ColorScheme = colorScheme, + Text = "AddSpaceBetweenItems", + }; + + if (dimension == Dimension.Width) + { + addSpacesBetweenItems.Checked = _horizAligner.AlignmentMode.HasFlag (AlignmentModes.AddSpaceBetweenItems); + addSpacesBetweenItems.X = Pos.Align (_horizAligner.Alignment); + addSpacesBetweenItems.Y = Pos.Top (alignRadioGroup); + } + else + { + addSpacesBetweenItems.Checked = _vertAligner.AlignmentMode.HasFlag (AlignmentModes.AddSpaceBetweenItems); + addSpacesBetweenItems.X = Pos.Left (alignRadioGroup); + addSpacesBetweenItems.Y = Pos.Align (_vertAligner.Alignment); + } + + addSpacesBetweenItems.Toggled += (s, e) => + { + if (dimension == Dimension.Width) { - if (view.X is PosAlign j) - { - j.Aligner.SpaceBetweenItems = _horizAligner.SpaceBetweenItems; - } + _horizAligner.AlignmentMode = e.NewValue is { } && + e.NewValue.Value ? + _horizAligner.AlignmentMode | AlignmentModes.AddSpaceBetweenItems : + _horizAligner.AlignmentMode & ~AlignmentModes.AddSpaceBetweenItems; + UpdatePosAlignObjects (appWindow, dimension, _horizAligner); } + else + { + _vertAligner.AlignmentMode = e.NewValue is { } && + e.NewValue.Value ? + _vertAligner.AlignmentMode | AlignmentModes.AddSpaceBetweenItems : + _vertAligner.AlignmentMode & ~AlignmentModes.AddSpaceBetweenItems; + UpdatePosAlignObjects (appWindow, dimension, _vertAligner); + } + }; - appWindow.Add (putSpaces); + + appWindow.Add (addSpacesBetweenItems); CheckBox margin = new () { - X = Pos.Left (putSpaces), - Y = Pos.Bottom (putSpaces), ColorScheme = colorScheme, Text = "Margin" }; + if (dimension == Dimension.Width) + { + margin.X = Pos.Align (_horizAligner.Alignment); + margin.Y = Pos.Top (alignRadioGroup); + } + else + { + margin.X = Pos.Left (addSpacesBetweenItems); + margin.Y = Pos.Align (_vertAligner.Alignment); + } + margin.Toggled += (s, e) => { - _leftMargin = e.NewValue is { } && e.NewValue.Value ? 1 : 0; - - foreach (View view in appWindow.Subviews.Where (v => v.X is PosAlign)) + if (dimension == Dimension.Width) { - // Skip the justification radio group - if (view != alignRadioGroup) - { - view.Margin.Thickness = new (_leftMargin, 0, 0, 0); - } + _leftMargin = e.NewValue is { } && e.NewValue.Value ? 1 : 0; + UpdatePosAlignObjects (appWindow, dimension, _horizAligner); + } + else + { + _topMargin = e.NewValue is { } && e.NewValue.Value ? 1 : 0; + UpdatePosAlignObjects (appWindow, dimension, _vertAligner); } }; appWindow.Add (margin); @@ -122,24 +194,34 @@ public sealed class PosAlignDemo : Scenario List