Working on Centered

This commit is contained in:
Tig
2024-04-19 12:57:07 -06:00
parent bb16808021
commit 48cf0db291
3 changed files with 142 additions and 83 deletions

View File

@@ -16,7 +16,7 @@ public enum Justification
Right,
/// <summary>
/// The items will be centered.
/// The items will be arranged such that there is no more than 1 space between them. The group will be centered in the container.
/// </summary>
Centered,
@@ -24,9 +24,33 @@ public enum Justification
/// 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.
/// </summary>
/// <example>
/// <c>
/// 111 2222 33333
/// </c>
/// </example>
Justified,
/// <summary>
/// The items will be left-justified. The first item will be at the start and the last item will be at the end.
/// Those in between will be tight against the right item.
/// </summary>
/// <example>
/// <c>
/// 111 2222 33333
/// </c>
/// </example>
RightJustified,
/// <summary>
/// The items will be left-justified. The first item will be at the start and the last item will be at the end.
/// Those in between will be tight against the right item.
/// </summary>
/// <example>
/// <c>
/// 111 2222 33333
/// </c>
/// </example>
LeftJustified
}
@@ -85,22 +109,53 @@ public class Justifier
}
break;
case Justification.Centered:
currentPosition = (totalSize - totalItemsSize) / 2;
for (var i = 0; i < sizes.Length; i++)
case Justification.Centered:
if (sizes.Length > 1)
{
if (sizes [i] < 0)
totalItemsSize = sizes.Sum (); // total size of items
int totalGaps = sizes.Length - 1; // total gaps (0 or 1 space)
int totalItemsAndSpaces = totalItemsSize + totalGaps; // total size of items and spaces
int spaces = totalGaps;
if (totalItemsSize >= totalSize)
{
throw new ArgumentException ("The size of an item cannot be negative.");
spaces = 0;
}
else if (totalItemsAndSpaces > totalSize)
{
spaces = totalItemsAndSpaces - totalSize;
}
positions [i] = currentPosition;
currentPosition += sizes [i];
}
int remainingSpace = Math.Max(0, totalSize - totalItemsSize - spaces); // remaining space to be distributed before and after the items
int spaceBefore = remainingSpace / 2; // space before the items
positions [0] = spaceBefore; // first item position
for (var i = 1; i < sizes.Length; i++)
{
int aSpace = 0;
if (spaces > 0)
{
spaces--;
aSpace = 1;
}
// subsequent items are placed one space after the previous item
positions [i] = positions [i - 1] + sizes [i - 1] + aSpace;
}
// Adjust the last position if there is an extra space
if (positions [sizes.Length - 1] + sizes [sizes.Length - 1] > totalSize)
{
positions [sizes.Length - 1]--;
}
}
else if (sizes.Length == 1)
{
positions [0] = (totalSize - sizes [0]) / 2; // single item is centered
}
break;
case Justification.Justified:
int spaceBetween = sizes.Length > 1 ? (totalSize - totalItemsSize) / (sizes.Length - 1) : 0;
int remainder = sizes.Length > 1 ? (totalSize - totalItemsSize) % (sizes.Length - 1) : 0;

View File

@@ -307,22 +307,22 @@ public class Pos
/// <summary>Creates a <see cref="Pos"/> object that tracks the Top (Y) position of the specified <see cref="View"/>.</summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
public static Pos Top (View view) { return new PosView (view, Side.Y); }
public static Pos Top (View view) { return new PosView (view, Side.Top); }
/// <summary>Creates a <see cref="Pos"/> object that tracks the Top (Y) position of the specified <see cref="View"/>.</summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
public static Pos Y (View view) { return new PosView (view, Side.Y); }
public static Pos Y (View view) { return new PosView (view, Side.Top); }
/// <summary>Creates a <see cref="Pos"/> object that tracks the Left (X) position of the specified <see cref="View"/>.</summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
public static Pos Left (View view) { return new PosView (view, Side.X); }
public static Pos Left (View view) { return new PosView (view, Side.Left); }
/// <summary>Creates a <see cref="Pos"/> object that tracks the Left (X) position of the specified <see cref="View"/>.</summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
public static Pos X (View view) { return new PosView (view, Side.X); }
public static Pos X (View view) { return new PosView (view, Side.Left); }
/// <summary>
/// Creates a <see cref="Pos"/> object that tracks the Bottom (Y+Height) coordinate of the specified
@@ -486,8 +486,8 @@ public class Pos
public enum Side
{
X = 0,
Y = 1,
Left = 0,
Top = 1,
Right = 2,
Bottom = 3
}
@@ -503,8 +503,8 @@ public class Pos
{
string sideString = side switch
{
Side.X => "x",
Side.Y => "y",
Side.Left => "x",
Side.Top => "y",
Side.Right => "right",
Side.Bottom => "bottom",
_ => "unknown"
@@ -522,8 +522,8 @@ public class Pos
{
return side switch
{
Side.X => Target.Frame.X,
Side.Y => Target.Frame.Y,
Side.Left => Target.Frame.X,
Side.Top => Target.Frame.Y,
Side.Right => Target.Frame.Right,
Side.Bottom => Target.Frame.Bottom,
_ => 0
@@ -718,7 +718,7 @@ public class Dim
/// <summary>Creates a <see cref="Dim"/> object that tracks the Height of the specified <see cref="View"/>.</summary>
/// <returns>The height <see cref="Dim"/> of the other <see cref="View"/>.</returns>
/// <param name="view">The view that will be tracked.</param>
public static Dim Height (View view) { return new DimView (view, Side.Height); }
public static Dim Height (View view) { return new DimView (view, Dimension.Height); }
/// <summary>Adds a <see cref="Dim"/> to a <see cref="Dim"/>, yielding a new <see cref="Dim"/>.</summary>
/// <param name="left">The first <see cref="Dim"/> to add.</param>
@@ -801,7 +801,7 @@ public class Dim
/// <summary>Creates a <see cref="Dim"/> object that tracks the Width of the specified <see cref="View"/>.</summary>
/// <returns>The width <see cref="Dim"/> of the other <see cref="View"/>.</returns>
/// <param name="view">The view that will be tracked.</param>
public static Dim Width (View view) { return new DimView (view, Side.Width); }
public static Dim Width (View view) { return new DimView (view, Dimension.Width); }
/// <summary>
/// Gets a dimension that is anchored to a certain point in the layout.
@@ -932,7 +932,7 @@ public class Dim
internal override int Anchor (int width) { return _function (); }
}
public enum Side
public enum Dimension
{
Height = 0,
Width = 1
@@ -940,9 +940,9 @@ public class Dim
internal class DimView : Dim
{
private readonly Side _side;
private readonly Dimension _side;
internal DimView (View view, Side side)
internal DimView (View view, Dimension side)
{
Target = view;
_side = side;
@@ -961,8 +961,8 @@ public class Dim
string sideString = _side switch
{
Side.Height => "Height",
Side.Width => "Width",
Dimension.Height => "Height",
Dimension.Width => "Width",
_ => "unknown"
};
@@ -973,8 +973,8 @@ public class Dim
{
return _side switch
{
Side.Height => Target.Frame.Height,
Side.Width => Target.Frame.Width,
Dimension.Height => Target.Frame.Height,
Dimension.Width => Target.Frame.Width,
_ => 0
};
}

View File

@@ -81,24 +81,27 @@ public class JustifierTests (ITestOutputHelper output)
}
[Theory]
[InlineData (Justification.Left, new int [] { 10, 20, 30 }, 100, new int [] { 0, 10, 30 })]
[InlineData (Justification.Left, new int [] { 33, 33, 33 }, 100, new int [] { 0, 33, 66 })]
[InlineData (Justification.Left, new int [] { 10 }, 101, new int [] { 0 })]
[InlineData (Justification.Left, new int [] { 10, 20 }, 101, new int [] { 0, 10 })]
[InlineData (Justification.Left, new int [] { 10, 20, 30 }, 101, new int [] { 0, 10, 30 })]
[InlineData (Justification.Left, new int [] { 10, 20, 30, 40 }, 101, new int [] { 0, 10, 30, 60 })]
[InlineData (Justification.Left, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 0, 10, 30, 60, 100 })]
//[InlineData (Justification.Left, new int [] { 10, 20, 30 }, 100, new int [] { 0, 10, 30 })]
//[InlineData (Justification.Left, new int [] { 33, 33, 33 }, 100, new int [] { 0, 33, 66 })]
//[InlineData (Justification.Left, new int [] { 10 }, 101, new int [] { 0 })]
//[InlineData (Justification.Left, new int [] { 10, 20 }, 101, new int [] { 0, 10 })]
//[InlineData (Justification.Left, new int [] { 10, 20, 30 }, 101, new int [] { 0, 10, 30 })]
//[InlineData (Justification.Left, new int [] { 10, 20, 30, 40 }, 101, new int [] { 0, 10, 30, 60 })]
//[InlineData (Justification.Left, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 0, 10, 30, 60, 100 })]
[InlineData (Justification.Right, new int [] { 10, 20, 30 }, 100, new int [] { 40, 50, 70 })]
[InlineData (Justification.Right, new int [] { 33, 33, 33 }, 100, new int [] { 1, 34, 67 })]
[InlineData (Justification.Right, new int [] { 10 }, 101, new int [] { 91 })]
[InlineData (Justification.Right, new int [] { 10, 20 }, 101, new int [] { 71, 81 })]
[InlineData (Justification.Right, new int [] { 10, 20, 30 }, 101, new int [] { 41, 51, 71 })]
[InlineData (Justification.Right, new int [] { 10, 20, 30, 40 }, 101, new int [] { 1, 11, 31, 61 })]
[InlineData (Justification.Right, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 1, 11, 31, 61, 101 })]
//[InlineData (Justification.Right, new int [] { 10, 20, 30 }, 100, new int [] { 40, 50, 70 })]
//[InlineData (Justification.Right, new int [] { 33, 33, 33 }, 100, new int [] { 1, 34, 67 })]
//[InlineData (Justification.Right, new int [] { 10 }, 101, new int [] { 91 })]
//[InlineData (Justification.Right, new int [] { 10, 20 }, 101, new int [] { 71, 81 })]
//[InlineData (Justification.Right, new int [] { 10, 20, 30 }, 101, new int [] { 41, 51, 71 })]
//[InlineData (Justification.Right, new int [] { 10, 20, 30, 40 }, 101, new int [] { 1, 11, 31, 61 })]
//[InlineData (Justification.Right, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 1, 11, 31, 61, 101 })]
[InlineData (Justification.Centered, new int [] { 10, 20, 30 }, 100, new int [] { 20, 30, 50 })]
[InlineData (Justification.Centered, new int [] { 33, 33, 33 }, 99, new int [] { 0, 33, 66 })]
[InlineData (Justification.Centered, new int [] { 1, 2, 3 }, 10, new int [] { 1, 3, 6 })]
[InlineData (Justification.Centered, new int [] { 10, 20, 30 }, 100, new int [] { 19, 30, 51 })]
[InlineData (Justification.Centered, new int [] { 3, 3, 3 }, 9, new int [] { 0, 3, 6 })]
[InlineData (Justification.Centered, new int [] { 3, 3, 3 }, 10, new int [] { 0, 4, 7 })]
[InlineData (Justification.Centered, new int [] { 3, 3, 3 }, 11, new int [] { 0, 4, 8 })]
[InlineData (Justification.Centered, new int [] { 33, 33, 33 }, 100, new int [] { 0, 33, 66 })]
[InlineData (Justification.Centered, new int [] { 33, 33, 33 }, 101, new int [] { 1, 34, 67 })]
[InlineData (Justification.Centered, new int [] { 33, 33, 33 }, 102, new int [] { 1, 34, 67 })]
@@ -108,48 +111,49 @@ public class JustifierTests (ITestOutputHelper output)
[InlineData (Justification.Centered, new int [] { 10, 20, 30 }, 101, new int [] { 20, 30, 50 })]
[InlineData (Justification.Centered, new int [] { 10, 20, 30, 40 }, 101, new int [] { 0, 10, 30, 60 })]
[InlineData (Justification.Centered, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 0, 10, 30, 60, 100 })]
[InlineData (Justification.Centered, new int [] { 3, 4, 5, 6 }, 25, new int [] { 2, 6, 11, 17 })]
[InlineData (Justification.Justified, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 0, 11, 31, 61, 101 })]
[InlineData (Justification.Justified, new int [] { 10, 20, 30, 40 }, 101, new int [] { 0, 11, 31, 61 })]
[InlineData (Justification.Justified, new int [] { 10, 20, 30 }, 100, new int [] { 0, 30, 70 })]
[InlineData (Justification.Justified, new int [] { 10, 20, 30 }, 101, new int [] { 0, 31, 71 })]
[InlineData (Justification.Justified, new int [] { 33, 33, 33 }, 100, new int [] { 0, 34, 67 })]
[InlineData (Justification.Justified, new int [] { 11, 17, 23 }, 100, new int [] { 0, 36, 77 })]
[InlineData (Justification.Justified, new int [] { 1, 2, 3 }, 11, new int [] { 0, 4, 8 })]
[InlineData (Justification.Justified, new int [] { 10, 20 }, 101, new int [] { 0, 81 })]
[InlineData (Justification.Justified, new int [] { 10 }, 101, new int [] { 0 })]
[InlineData (Justification.Justified, new int [] { 3, 3, 3 }, 21, new int [] { 0, 9, 18 })]
[InlineData (Justification.Justified, new int [] { 3, 4, 5 }, 21, new int [] { 0, 8, 16 })]
[InlineData (Justification.Justified, new int [] { 3, 4, 5, 6 }, 18, new int [] { 0, 3, 7, 12 })]
[InlineData (Justification.Justified, new int [] { 3, 4, 5, 6 }, 19, new int [] { 0, 4, 8, 13 })]
[InlineData (Justification.Justified, new int [] { 3, 4, 5, 6 }, 20, new int [] { 0, 4, 9, 14 })]
[InlineData (Justification.Justified, new int [] { 3, 4, 5, 6 }, 21, new int [] { 0, 4, 9, 15 })]
[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 22, new int [] { 0, 8, 14, 19 })]
[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 23, new int [] { 0, 8, 15, 20, })]
[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 24, new int [] { 0, 8, 15, 21 })]
[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 25, new int [] { 0, 9, 16, 22 })]
[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 26, new int [] { 0, 9, 17, 23 })]
[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 31, new int [] { 0, 11, 20, 28 })]
//[InlineData (Justification.Justified, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 0, 11, 31, 61, 101 })]
//[InlineData (Justification.Justified, new int [] { 10, 20, 30, 40 }, 101, new int [] { 0, 11, 31, 61 })]
//[InlineData (Justification.Justified, new int [] { 10, 20, 30 }, 100, new int [] { 0, 30, 70 })]
//[InlineData (Justification.Justified, new int [] { 10, 20, 30 }, 101, new int [] { 0, 31, 71 })]
//[InlineData (Justification.Justified, new int [] { 33, 33, 33 }, 100, new int [] { 0, 34, 67 })]
//[InlineData (Justification.Justified, new int [] { 11, 17, 23 }, 100, new int [] { 0, 36, 77 })]
//[InlineData (Justification.Justified, new int [] { 1, 2, 3 }, 11, new int [] { 0, 4, 8 })]
//[InlineData (Justification.Justified, new int [] { 10, 20 }, 101, new int [] { 0, 81 })]
//[InlineData (Justification.Justified, new int [] { 10 }, 101, new int [] { 0 })]
//[InlineData (Justification.Justified, new int [] { 3, 3, 3 }, 21, new int [] { 0, 9, 18 })]
//[InlineData (Justification.Justified, new int [] { 3, 4, 5 }, 21, new int [] { 0, 8, 16 })]
//[InlineData (Justification.Justified, new int [] { 3, 4, 5, 6 }, 18, new int [] { 0, 3, 7, 12 })]
//[InlineData (Justification.Justified, new int [] { 3, 4, 5, 6 }, 19, new int [] { 0, 4, 8, 13 })]
//[InlineData (Justification.Justified, new int [] { 3, 4, 5, 6 }, 20, new int [] { 0, 4, 9, 14 })]
//[InlineData (Justification.Justified, new int [] { 3, 4, 5, 6 }, 21, new int [] { 0, 4, 9, 15 })]
//[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 22, new int [] { 0, 8, 14, 19 })]
//[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 23, new int [] { 0, 8, 15, 20, })]
//[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 24, new int [] { 0, 8, 15, 21 })]
//[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 25, new int [] { 0, 9, 16, 22 })]
//[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 26, new int [] { 0, 9, 17, 23 })]
//[InlineData (Justification.Justified, new int [] { 6, 5, 4, 3 }, 31, new int [] { 0, 11, 20, 28 })]
[InlineData (Justification.LeftJustified, new int [] { 10, 20, 30 }, 100, new int [] { 0, 11, 70 })]
[InlineData (Justification.LeftJustified, new int [] { 33, 33, 33 }, 100, new int [] { 0, 34, 67 })]
[InlineData (Justification.LeftJustified, new int [] { 10 }, 101, new int [] { 0 })]
[InlineData (Justification.LeftJustified, new int [] { 10, 20 }, 101, new int [] { 0, 81 })]
[InlineData (Justification.LeftJustified, new int [] { 10, 20, 30 }, 101, new int [] { 0, 11, 71 })]
[InlineData (Justification.LeftJustified, new int [] { 10, 20, 30, 40 }, 101, new int [] { 0, 11, 32, 61 })]
[InlineData (Justification.LeftJustified, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 0, 11, 32, 63, 101 })]
[InlineData (Justification.LeftJustified, new int [] { 3, 3, 3 }, 21, new int [] { 0, 4, 18 })]
[InlineData (Justification.LeftJustified, new int [] { 3, 4, 5 }, 21, new int [] { 0, 4, 16 })]
//[InlineData (Justification.LeftJustified, new int [] { 10, 20, 30 }, 100, new int [] { 0, 11, 70 })]
//[InlineData (Justification.LeftJustified, new int [] { 33, 33, 33 }, 100, new int [] { 0, 34, 67 })]
//[InlineData (Justification.LeftJustified, new int [] { 10 }, 101, new int [] { 0 })]
//[InlineData (Justification.LeftJustified, new int [] { 10, 20 }, 101, new int [] { 0, 81 })]
//[InlineData (Justification.LeftJustified, new int [] { 10, 20, 30 }, 101, new int [] { 0, 11, 71 })]
//[InlineData (Justification.LeftJustified, new int [] { 10, 20, 30, 40 }, 101, new int [] { 0, 11, 32, 61 })]
//[InlineData (Justification.LeftJustified, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 0, 11, 32, 63, 101 })]
//[InlineData (Justification.LeftJustified, new int [] { 3, 3, 3 }, 21, new int [] { 0, 4, 18 })]
//[InlineData (Justification.LeftJustified, new int [] { 3, 4, 5 }, 21, new int [] { 0, 4, 16 })]
[InlineData (Justification.RightJustified, new int [] { 10, 20, 30 }, 100, new int [] { 0, 49, 70 })]
[InlineData (Justification.RightJustified, new int [] { 33, 33, 33 }, 100, new int [] { 0, 33, 67 })]
[InlineData (Justification.RightJustified, new int [] { 10 }, 101, new int [] { 0 })]
[InlineData (Justification.RightJustified, new int [] { 10, 20 }, 101, new int [] { 0, 81 })]
[InlineData (Justification.RightJustified, new int [] { 10, 20, 30 }, 101, new int [] { 0, 50, 71 })]
[InlineData (Justification.RightJustified, new int [] { 10, 20, 30, 40 }, 101, new int [] { 0, 9, 30, 61 })]
[InlineData (Justification.RightJustified, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 0, 8, 29, 60, 101 })]
[InlineData (Justification.RightJustified, new int [] { 3, 3, 3 }, 21, new int [] { 0, 14, 18 })]
[InlineData (Justification.RightJustified, new int [] { 3, 4, 5 }, 21, new int [] { 0, 11, 16 })]
//[InlineData (Justification.RightJustified, new int [] { 10, 20, 30 }, 100, new int [] { 0, 49, 70 })]
//[InlineData (Justification.RightJustified, new int [] { 33, 33, 33 }, 100, new int [] { 0, 33, 67 })]
//[InlineData (Justification.RightJustified, new int [] { 10 }, 101, new int [] { 0 })]
//[InlineData (Justification.RightJustified, new int [] { 10, 20 }, 101, new int [] { 0, 81 })]
//[InlineData (Justification.RightJustified, new int [] { 10, 20, 30 }, 101, new int [] { 0, 50, 71 })]
//[InlineData (Justification.RightJustified, new int [] { 10, 20, 30, 40 }, 101, new int [] { 0, 9, 30, 61 })]
//[InlineData (Justification.RightJustified, new int [] { 10, 20, 30, 40, 50 }, 151, new int [] { 0, 8, 29, 60, 101 })]
//[InlineData (Justification.RightJustified, new int [] { 3, 3, 3 }, 21, new int [] { 0, 14, 18 })]
//[InlineData (Justification.RightJustified, new int [] { 3, 4, 5 }, 21, new int [] { 0, 11, 16 })]
public void TestJustifications (Justification justification, int [] sizes, int totalSize, int [] expected)
{