Przeglądaj źródła

Working on Centered

Tig 1 rok temu
rodzic
commit
48cf0db291

+ 64 - 9
Terminal.Gui/Drawing/Justification.cs

@@ -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;

+ 19 - 19
Terminal.Gui/View/Layout/PosDim.cs

@@ -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
             };
         }

+ 64 - 60
UnitTests/Drawing/JustifierTests.cs

@@ -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.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.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.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.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.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.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.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 })]
 
     public void TestJustifications (Justification justification, int [] sizes, int totalSize, int [] expected)
     {