|
@@ -3,7 +3,8 @@ using System.ComponentModel;
|
|
|
namespace Terminal.Gui;
|
|
|
|
|
|
/// <summary>
|
|
|
-/// Aligns items within a container based on the specified <see cref="Gui.Alignment"/>. Both horizontal and vertical alignments are supported.
|
|
|
+/// Aligns items within a container based on the specified <see cref="Gui.Alignment"/>. Both horizontal and vertical
|
|
|
+/// alignments are supported.
|
|
|
/// </summary>
|
|
|
public class Aligner : INotifyPropertyChanged
|
|
|
{
|
|
@@ -61,7 +62,8 @@ public class Aligner : INotifyPropertyChanged
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Takes a list of item sizes and returns a list of the positions of those items when aligned within <see name="ContainerSize"/>
|
|
|
+ /// Takes a list of item sizes and returns a list of the positions of those items when aligned within
|
|
|
+ /// <see name="ContainerSize"/>
|
|
|
/// using the <see cref="Alignment"/> and <see cref="AlignmentModes"/> settings.
|
|
|
/// </summary>
|
|
|
/// <param name="sizes">The sizes of the items to align.</param>
|
|
@@ -69,7 +71,8 @@ public class Aligner : INotifyPropertyChanged
|
|
|
public int [] Align (int [] sizes) { return Align (Alignment, AlignmentModes, ContainerSize, sizes); }
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Takes a list of item sizes and returns a list of the positions of those items when aligned within <paramref name="containerSize"/>
|
|
|
+ /// Takes a list of item sizes and returns a list of the positions of those items when aligned within
|
|
|
+ /// <paramref name="containerSize"/>
|
|
|
/// using specified parameters.
|
|
|
/// </summary>
|
|
|
/// <param name="alignment">Specifies how the items will be aligned.</param>
|
|
@@ -77,52 +80,43 @@ public class Aligner : INotifyPropertyChanged
|
|
|
/// <param name="containerSize">The size of the container.</param>
|
|
|
/// <param name="sizes">The sizes of the items to align.</param>
|
|
|
/// <returns>The positions of the items, from left/top to right/bottom.</returns>
|
|
|
- public static int [] Align (in Alignment alignment, in AlignmentModes alignmentMode, int containerSize, int [] sizes)
|
|
|
+ public static int [] Align (in Alignment alignment, in AlignmentModes alignmentMode, in int containerSize, in int [] sizes)
|
|
|
{
|
|
|
+ if (alignmentMode.HasFlag (AlignmentModes.EndToStart))
|
|
|
+ {
|
|
|
+ throw new NotImplementedException ("EndToStart is not implemented.");
|
|
|
+ }
|
|
|
+
|
|
|
if (sizes.Length == 0)
|
|
|
{
|
|
|
- return new int [] { };
|
|
|
+ return [];
|
|
|
}
|
|
|
|
|
|
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
|
|
|
+ int totalItemsAndSpaces = totalItemsSize + totalGaps * maxSpaceBetweenItems; // total size of items and spacesToGive if we had enough room
|
|
|
+ int spacesToGive = totalGaps * maxSpaceBetweenItems; // We'll decrement this below to place one space between each item until we run out
|
|
|
|
|
|
if (totalItemsSize >= containerSize)
|
|
|
{
|
|
|
- spaces = 0;
|
|
|
+ spacesToGive = 0;
|
|
|
}
|
|
|
else if (totalItemsAndSpaces > containerSize)
|
|
|
{
|
|
|
- spaces = containerSize - totalItemsSize;
|
|
|
+ spacesToGive = containerSize - totalItemsSize;
|
|
|
}
|
|
|
|
|
|
- var currentPosition = 0;
|
|
|
-
|
|
|
switch (alignment)
|
|
|
{
|
|
|
case Alignment.Start:
|
|
|
switch (alignmentMode & ~AlignmentModes.AddSpaceBetweenItems)
|
|
|
{
|
|
|
case AlignmentModes.StartToEnd:
|
|
|
- Start (sizes, positions, ref spaces, maxSpaceBetweenItems);
|
|
|
-
|
|
|
- break;
|
|
|
+ return Start (in sizes, maxSpaceBetweenItems, spacesToGive);
|
|
|
|
|
|
case AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast:
|
|
|
- IgnoreLast (sizes, containerSize, positions, maxSpaceBetweenItems, totalItemsSize, spaces, currentPosition);
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case AlignmentModes.EndToStart:
|
|
|
- case AlignmentModes.EndToStart | AlignmentModes.IgnoreFirstOrLast:
|
|
|
- throw new NotImplementedException ("EndToStart is not implemented.");
|
|
|
-
|
|
|
- break;
|
|
|
+ return IgnoreLast (in sizes, containerSize, totalItemsSize, maxSpaceBetweenItems, spacesToGive);
|
|
|
}
|
|
|
|
|
|
break;
|
|
@@ -131,44 +125,31 @@ public class Aligner : INotifyPropertyChanged
|
|
|
switch (alignmentMode & ~AlignmentModes.AddSpaceBetweenItems)
|
|
|
{
|
|
|
case AlignmentModes.StartToEnd:
|
|
|
- End (containerSize, sizes, totalItemsSize, spaces, maxSpaceBetweenItems, positions);
|
|
|
-
|
|
|
- break;
|
|
|
+ return End (in sizes, containerSize, totalItemsSize, maxSpaceBetweenItems, spacesToGive);
|
|
|
|
|
|
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;
|
|
|
-
|
|
|
+ return IgnoreFirst (in sizes, containerSize, totalItemsSize, maxSpaceBetweenItems, spacesToGive);
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case Alignment.Center:
|
|
|
- Center (containerSize, sizes, totalItemsSize, spaces, positions, maxSpaceBetweenItems);
|
|
|
-
|
|
|
- break;
|
|
|
+ return Center (in sizes, containerSize, totalItemsSize, maxSpaceBetweenItems, spacesToGive);
|
|
|
|
|
|
case Alignment.Fill:
|
|
|
- Fill (containerSize, sizes, totalItemsSize, positions);
|
|
|
-
|
|
|
- break;
|
|
|
+ return Fill (in sizes, containerSize, totalItemsSize);
|
|
|
|
|
|
default:
|
|
|
throw new ArgumentOutOfRangeException (nameof (alignment), alignment, null);
|
|
|
}
|
|
|
|
|
|
- return positions;
|
|
|
+ return [];
|
|
|
}
|
|
|
|
|
|
- private static void Start (int [] sizes, int [] positions, ref int spaces, int maxSpaceBetweenItems)
|
|
|
+ private static int [] Start (ref readonly int [] sizes, int maxSpaceBetweenItems, int spacesToGive)
|
|
|
{
|
|
|
+ var positions = new int [sizes.Length]; // positions of the items. the return value.
|
|
|
+
|
|
|
for (var i = 0; i < sizes.Length; i++)
|
|
|
{
|
|
|
CheckSizeCannotBeNegative (i, sizes);
|
|
@@ -180,18 +161,28 @@ public class Aligner : INotifyPropertyChanged
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
+ int spaceBefore = spacesToGive-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
|
|
|
// subsequent items are placed one space after the previous item
|
|
|
positions [i] = positions [i - 1] + sizes [i - 1] + spaceBefore;
|
|
|
}
|
|
|
+
|
|
|
+ return positions;
|
|
|
}
|
|
|
|
|
|
- private static void IgnoreFirst (int [] sizes, int containerSize, int [] positions, int maxSpaceBetweenItems, int totalItemsSize, int spaces, int currentPosition)
|
|
|
+ private static int [] IgnoreFirst (
|
|
|
+ ref readonly int [] sizes,
|
|
|
+ int containerSize,
|
|
|
+ int totalItemsSize,
|
|
|
+ int maxSpaceBetweenItems,
|
|
|
+ int spacesToGive
|
|
|
+ )
|
|
|
{
|
|
|
+ var positions = new int [sizes.Length]; // positions of the items. the return value.
|
|
|
+
|
|
|
if (sizes.Length > 1)
|
|
|
{
|
|
|
- currentPosition = 0;
|
|
|
+ var currentPosition = 0;
|
|
|
positions [0] = currentPosition; // first item is flush left
|
|
|
|
|
|
for (int i = sizes.Length - 1; i >= 0; i--)
|
|
@@ -207,7 +198,7 @@ public class Aligner : INotifyPropertyChanged
|
|
|
|
|
|
if (i < sizes.Length - 1 && i > 0)
|
|
|
{
|
|
|
- int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
+ int spaceBefore = spacesToGive-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
|
|
|
positions [i] = currentPosition - sizes [i] - spaceBefore;
|
|
|
currentPosition = positions [i];
|
|
@@ -219,19 +210,26 @@ public class Aligner : INotifyPropertyChanged
|
|
|
CheckSizeCannotBeNegative (0, sizes);
|
|
|
positions [0] = 0; // single item is flush left
|
|
|
}
|
|
|
+
|
|
|
+ return positions;
|
|
|
}
|
|
|
|
|
|
- private static void IgnoreLast (int [] sizes, int containerSize, int [] positions, int maxSpaceBetweenItems, int totalItemsSize, int spaces, int currentPosition)
|
|
|
+ private static int [] IgnoreLast (
|
|
|
+ ref readonly int [] sizes,
|
|
|
+ int containerSize,
|
|
|
+ int totalItemsSize,
|
|
|
+ int maxSpaceBetweenItems,
|
|
|
+ int spacesToGive
|
|
|
+ )
|
|
|
{
|
|
|
+ var positions = new int [sizes.Length]; // positions of the items. the return value.
|
|
|
+
|
|
|
if (sizes.Length > 1)
|
|
|
{
|
|
|
+ var currentPosition = 0;
|
|
|
if (totalItemsSize > containerSize)
|
|
|
{
|
|
|
- currentPosition = containerSize - totalItemsSize - spaces;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- currentPosition = 0;
|
|
|
+ currentPosition = containerSize - totalItemsSize - spacesToGive;
|
|
|
}
|
|
|
|
|
|
for (var i = 0; i < sizes.Length; i++)
|
|
@@ -240,7 +238,7 @@ public class Aligner : INotifyPropertyChanged
|
|
|
|
|
|
if (i < sizes.Length - 1)
|
|
|
{
|
|
|
- int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
+ int spaceBefore = spacesToGive-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
|
|
|
positions [i] = currentPosition;
|
|
|
currentPosition += sizes [i] + spaceBefore;
|
|
@@ -255,14 +253,17 @@ public class Aligner : INotifyPropertyChanged
|
|
|
|
|
|
positions [0] = containerSize - sizes [0]; // single item is flush right
|
|
|
}
|
|
|
+
|
|
|
+ return positions;
|
|
|
}
|
|
|
|
|
|
- private static void Fill (int containerSize, int [] sizes, int totalItemsSize, int [] positions)
|
|
|
+ private static int [] Fill (ref readonly int [] sizes, int containerSize, int totalItemsSize)
|
|
|
{
|
|
|
- int currentPosition;
|
|
|
+ var positions = new int [sizes.Length]; // positions of the items. the return value.
|
|
|
+
|
|
|
int spaceBetween = sizes.Length > 1 ? (containerSize - totalItemsSize) / (sizes.Length - 1) : 0;
|
|
|
int remainder = sizes.Length > 1 ? (containerSize - totalItemsSize) % (sizes.Length - 1) : 0;
|
|
|
- currentPosition = 0;
|
|
|
+ var currentPosition = 0;
|
|
|
|
|
|
for (var i = 0; i < sizes.Length; i++)
|
|
|
{
|
|
@@ -271,14 +272,18 @@ public class Aligner : INotifyPropertyChanged
|
|
|
int extraSpace = i < remainder ? 1 : 0;
|
|
|
currentPosition += sizes [i] + spaceBetween + extraSpace;
|
|
|
}
|
|
|
+
|
|
|
+ return positions;
|
|
|
}
|
|
|
|
|
|
- private static void Center (int containerSize, int [] sizes, int totalItemsSize, int spaces, int [] positions, int maxSpaceBetweenItems)
|
|
|
+ private static int [] Center (ref readonly int [] sizes, int containerSize, int totalItemsSize, int maxSpaceBetweenItems, int spacesToGive)
|
|
|
{
|
|
|
+ var positions = new int [sizes.Length]; // positions of the items. the return value.
|
|
|
+
|
|
|
if (sizes.Length > 1)
|
|
|
{
|
|
|
// remaining space to be distributed before first and after the items
|
|
|
- int remainingSpace = Math.Max (0, containerSize - totalItemsSize - spaces);
|
|
|
+ int remainingSpace = Math.Max (0, containerSize - totalItemsSize - spacesToGive);
|
|
|
|
|
|
for (var i = 0; i < sizes.Length; i++)
|
|
|
{
|
|
@@ -291,7 +296,7 @@ public class Aligner : INotifyPropertyChanged
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
+ int spaceBefore = spacesToGive-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
|
|
|
// subsequent items are placed one space after the previous item
|
|
|
positions [i] = positions [i - 1] + sizes [i - 1] + spaceBefore;
|
|
@@ -302,24 +307,28 @@ public class Aligner : INotifyPropertyChanged
|
|
|
CheckSizeCannotBeNegative (0, sizes);
|
|
|
positions [0] = (containerSize - sizes [0]) / 2; // single item is centered
|
|
|
}
|
|
|
+
|
|
|
+ return positions;
|
|
|
}
|
|
|
|
|
|
- private static void End (int containerSize, int [] sizes, int totalItemsSize, int spaces, int maxSpaceBetweenItems, int [] positions)
|
|
|
+ private static int [] End (ref readonly int [] sizes, int containerSize, int totalItemsSize, int maxSpaceBetweenItems, int spacesToGive)
|
|
|
{
|
|
|
- int currentPosition;
|
|
|
- currentPosition = containerSize - totalItemsSize - spaces;
|
|
|
+ var positions = new int [sizes.Length]; // positions of the items. the return value.
|
|
|
+ int currentPosition = containerSize - totalItemsSize - spacesToGive;
|
|
|
|
|
|
for (var i = 0; i < sizes.Length; i++)
|
|
|
{
|
|
|
CheckSizeCannotBeNegative (i, sizes);
|
|
|
- int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
+ int spaceBefore = spacesToGive-- > 0 ? maxSpaceBetweenItems : 0;
|
|
|
|
|
|
positions [i] = currentPosition;
|
|
|
currentPosition += sizes [i] + spaceBefore;
|
|
|
}
|
|
|
+
|
|
|
+ return positions;
|
|
|
}
|
|
|
|
|
|
- private static void CheckSizeCannotBeNegative (int i, int [] sizes)
|
|
|
+ private static void CheckSizeCannotBeNegative (int i, IReadOnlyList<int> sizes)
|
|
|
{
|
|
|
if (sizes [i] < 0)
|
|
|
{
|