Răsfoiți Sursa

Dialog/MessageBox use new Justifier

Tig 1 an în urmă
părinte
comite
cd104e9163

+ 46 - 3
Terminal.Gui/Drawing/Justification.cs

@@ -13,6 +13,11 @@ public enum Justification
     ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
     ///     each item.
     /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         If the container is smaller than the total size of the items, the right items will be clipped (their locations will be greater than the container size).
+    ///     </para>
+    /// </remarks>
     /// <example>
     ///     <c>
     ///         111 2222 33333
@@ -32,6 +37,11 @@ public enum Justification
     ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
     ///     each item.
     /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         If the container is smaller than the total size of the items, the left items will be clipped (their locations will be negative).
+    ///     </para>
+    /// </remarks>
     /// <example>
     ///     <c>
     ///         111 2222 33333
@@ -52,6 +62,11 @@ public enum Justification
     ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
     ///     each item.
     /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Extra space will be distributed between the items, biased towards the left.
+    ///     </para>
+    /// </remarks>
     /// <example>
     ///     <c>
     ///         111 2222 33333
@@ -65,6 +80,11 @@ public enum Justification
     ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
     ///     each item.
     /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Extra space will be distributed between the items, biased towards the left.
+    ///     </para>
+    /// </remarks>
     /// <example>
     ///     <c>
     ///         111    2222     33333
@@ -77,6 +97,11 @@ public enum Justification
     ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
     ///     each item.
     /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         If the container is smaller than the total size of the items, the right items will be clipped (their locations will be greater than the container size).
+    ///     </para>
+    /// </remarks>
     /// <example>
     ///     <c>
     ///         111        2222 33333
@@ -96,6 +121,11 @@ public enum Justification
     ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
     ///     each item.
     /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         If the container is smaller than the total size of the items, the left items will be clipped (their locations will be negative).
+    ///     </para>
+    /// </remarks>
     /// <example>
     ///     <c>
     ///         111 2222        33333
@@ -153,6 +183,12 @@ public class Justifier : INotifyPropertyChanged
     ///     <see langword="false"/>. If <see langword="true"/>, a space will be
     ///     placed between each item, which is useful for justifying text.
     /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///        If the total size of the items is greater than the container size, the space between items will be ignored starting
+    ///        from the right.
+    ///     </para>
+    /// </remarks>
     public bool PutSpaceBetweenItems
     {
         get => _putSpaceBetweenItems;
@@ -234,7 +270,7 @@ public class Justifier : INotifyPropertyChanged
 
                 break;
             case Justification.Right:
-                currentPosition = Math.Max (0, containerSize - totalItemsSize - spaces);
+                currentPosition = containerSize - totalItemsSize - spaces;
 
                 for (var i = 0; i < sizes.Length; i++)
                 {
@@ -297,7 +333,14 @@ public class Justifier : INotifyPropertyChanged
             case Justification.LastRightRestLeft:
                 if (sizes.Length > 1)
                 {
-                    currentPosition = 0;
+                    if (totalItemsSize > containerSize)
+                    {
+                        currentPosition = containerSize - totalItemsSize - spaces;
+                    }
+                    else
+                    {
+                        currentPosition = 0;
+                    }
 
                     for (var i = 0; i < sizes.Length; i++)
                     {
@@ -337,7 +380,7 @@ public class Justifier : INotifyPropertyChanged
                         if (i == sizes.Length - 1)
                         {
                             // start at right
-                            currentPosition = containerSize - sizes [i];
+                            currentPosition = Math.Max (totalItemsSize, containerSize) - sizes [i];
                             positions [i] = currentPosition;
                         }
 

+ 3 - 0
Terminal.Gui/View/Layout/PosDim.cs

@@ -204,6 +204,7 @@ public class Pos
     /// <returns>The <see cref="Pos"/> returned from the function.</returns>
     public static Pos Function (Func<int> function) { return new PosFunc (function); }
 
+
     /// <summary>
     ///      Creates a <see cref="Pos"/> object that justifies a set of views according to the specified justification.
     /// </summary>
@@ -493,6 +494,7 @@ public class Pos
         internal override int Anchor (int width) { return (int)(width * _factor); }
     }
 
+
     /// <summary>
     /// Enables justification of a set of views.
     /// </summary>
@@ -604,6 +606,7 @@ public class Pos
         /// <param name="groupId">The unique identifier for the set of views to justify according to <paramref name="justification"/>.</param>
         public PosJustify (Justification justification, int groupId = 0)
         {
+            Justifier.PutSpaceBetweenItems = true;
             Justifier.Justification = justification;
             _groupId = groupId;
             Justifier.PropertyChanged += Justifier_PropertyChanged;

+ 2 - 4
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -1,5 +1,4 @@
 using System.Diagnostics;
-using static Terminal.Gui.Pos;
 
 namespace Terminal.Gui;
 
@@ -37,7 +36,6 @@ public enum LayoutStyle
     Computed
 }
 
-
 public partial class View
 {
     #region Frame
@@ -200,7 +198,7 @@ public partial class View
         get => VerifyIsInitialized (_x, nameof (X));
         set
         {
-            if (_x.Equals (value))
+            if (Equals (_x, value))
             {
                 return;
             }
@@ -239,7 +237,7 @@ public partial class View
         get => VerifyIsInitialized (_y, nameof (Y));
         set
         {
-            if (_y.Equals (value))
+            if (Equals (_y, value))
             {
                 return;
             }

+ 1 - 1
Terminal.Gui/Views/CheckBox.cs

@@ -20,7 +20,7 @@ public class CheckBox : View
         _charChecked = Glyphs.Checked;
         _charUnChecked = Glyphs.UnChecked;
 
-        Height = Dim.Auto (Dim.DimAutoStyle.Text);
+        Height = 1;
         Width = Dim.Auto (Dim.DimAutoStyle.Text);
 
         CanFocus = true;

+ 12 - 25
Terminal.Gui/Views/RadioGroup.cs

@@ -80,11 +80,6 @@ public class RadioGroup : View
         HighlightStyle = Gui.HighlightStyle.PressedOutside | Gui.HighlightStyle.Pressed;
 
         MouseClick += RadioGroup_MouseClick;
-
-        // TOOD: Hack - using Text when we should use SubViews
-        Add (_dummyView);
-        Width = Dim.Auto (Dim.DimAutoStyle.Content);
-        Height = Dim.Auto (Dim.DimAutoStyle.Content);
     }
 
     // TODO: Fix InvertColorsOnPress - only highlight the selected item
@@ -177,7 +172,7 @@ public class RadioGroup : View
                 }
             }
 
-            if (prevCount != _radioLabels.Count)
+            if (IsInitialized && prevCount != _radioLabels.Count)
             {
                 SetWidthHeight (_radioLabels);
             }
@@ -444,25 +439,21 @@ public class RadioGroup : View
         }
     }
 
-    private void RadioGroup_LayoutStarted (object sender, EventArgs e) { /*SetWidthHeight (_radioLabels);*/ }
+    private void RadioGroup_LayoutStarted (object sender, EventArgs e) { SetWidthHeight (_radioLabels); }
     private void SelectItem () { SelectedItem = _cursor; }
 
-    private View _dummyView = new View () {};
     private void SetWidthHeight (List<string> radioLabels)
     {
         switch (_orientation)
         {
             case Orientation.Vertical:
                 Rectangle r = MakeRect (0, 0, radioLabels);
-                // TODO: Hack
-                _dummyView.X = r.Width + +GetAdornmentsThickness ().Horizontal;
-                _dummyView.Y = radioLabels.Count + GetAdornmentsThickness ().Vertical;
 
-                //if (IsInitialized)
-                //{
-                //    Width = r.Width + GetAdornmentsThickness ().Horizontal;
-                //    Height = radioLabels.Count + GetAdornmentsThickness ().Vertical;
-                //}
+                if (IsInitialized)
+                {
+                    Width = r.Width + GetAdornmentsThickness ().Horizontal;
+                    Height = radioLabels.Count + GetAdornmentsThickness ().Vertical;
+                }
 
                 break;
 
@@ -475,15 +466,11 @@ public class RadioGroup : View
                     length += item.length;
                 }
 
-                // TODO: Hack
-                _dummyView.X = length + GetAdornmentsThickness ().Horizontal;
-                _dummyView.Y = 1 + GetAdornmentsThickness ().Vertical;
-
-                //if (IsInitialized)
-                //{
-                //    Width = length + GetAdornmentsThickness ().Vertical;
-                //    Height = 1 + GetAdornmentsThickness ().Horizontal;
-                //}
+                if (IsInitialized)
+                {
+                    Width = length + GetAdornmentsThickness ().Vertical;
+                    Height = 1 + GetAdornmentsThickness ().Horizontal;
+                }
 
                 break;
         }

+ 14 - 13
UnitTests/Dialogs/DialogTests.cs

@@ -39,7 +39,7 @@ public class DialogTests
         // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..)
         dlg.Border.Thickness = new (1, 0, 1, 0);
         runstate = Begin (dlg);
-        var buttonRow = $"{CM.Glyphs.VLine}     {btn1}    {CM.Glyphs.VLine}";
+        var buttonRow = $"{CM.Glyphs.VLine}    {btn1}     {CM.Glyphs.VLine}";
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
 
         // Now add a second button
@@ -64,7 +64,7 @@ public class DialogTests
         // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..)
         dlg.Border.Thickness = new (1, 0, 1, 0);
         runstate = Begin (dlg);
-        buttonRow = $"{CM.Glyphs.VLine}         {btn1}{CM.Glyphs.VLine}";
+        buttonRow = $"{CM.Glyphs.VLine}{btn1}         {CM.Glyphs.VLine}";
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
 
         // Now add a second button
@@ -166,7 +166,7 @@ public class DialogTests
         dlg.Dispose ();
 
         // Justify
-        buttonRow = $"{CM.Glyphs.VLine}{btn1} {btn2}  {btn3}  {btn4}{CM.Glyphs.VLine}";
+        buttonRow = $"{CM.Glyphs.VLine}{btn1}  {btn2}  {btn3} {btn4}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
         (runstate, dlg) = RunButtonTestDialog (
@@ -243,7 +243,7 @@ public class DialogTests
 
         // Default - Center
         buttonRow =
-            $"{CM.Glyphs.VLine}es {CM.Glyphs.RightBracket} {btn2} {btn3} {CM.Glyphs.LeftBracket} neve{CM.Glyphs.VLine}";
+            $"{CM.Glyphs.VLine}{CM.Glyphs.LeftBracket} yes {CM.Glyphs.RightBracket}{btn2}{btn3}{CM.Glyphs.LeftBracket} neve{CM.Glyphs.VLine}";
 
         (runstate, Dialog dlg) = RunButtonTestDialog (
                                                       title,
@@ -277,7 +277,8 @@ public class DialogTests
         dlg.Dispose ();
 
         // Right
-        buttonRow = $"{CM.Glyphs.VLine}{CM.Glyphs.RightBracket} {btn2} {btn3} {btn4}{CM.Glyphs.VLine}";
+        buttonRow = $"{CM.Glyphs.VLine}es {CM.Glyphs.RightBracket}{btn2}{btn3}{btn4}{CM.Glyphs.VLine}";
+        Assert.Equal (width, buttonRow.Length);
 
         (runstate, dlg) = RunButtonTestDialog (
                                                     title,
@@ -293,7 +294,7 @@ public class DialogTests
         dlg.Dispose ();
 
         // Left
-        buttonRow = $"{CM.Glyphs.VLine}{btn1} {btn2} {btn3} {CM.Glyphs.LeftBracket} n{CM.Glyphs.VLine}";
+        buttonRow = $"{CM.Glyphs.VLine}{btn1}{btn2}{btn3}{CM.Glyphs.LeftBracket} neve{CM.Glyphs.VLine}";
 
         (runstate, dlg) = RunButtonTestDialog (
                                                     title,
@@ -527,7 +528,7 @@ public class DialogTests
 
         // Justify 
         buttonRow =
-            $"{CM.Glyphs.VLine}    {CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}{CM.Glyphs.VLine}";
+            $"{CM.Glyphs.VLine}{CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}    {CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
         (runstate, dlg) = RunButtonTestDialog (
@@ -589,7 +590,7 @@ public class DialogTests
 
         // Justify
         buttonRow =
-            $"{CM.Glyphs.VLine}      {CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}{CM.Glyphs.VLine}";
+            $"{CM.Glyphs.VLine}{CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}      {CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
         (runstate, dlg) = RunButtonTestDialog (
@@ -915,7 +916,7 @@ public class DialogTests
                     @"
 ┌┌───────────────┐─┐
 ││               │ │
-││     ⟦ Ok ⟧    │ │
+││    ⟦ Ok ⟧     │ │
 │└───────────────┘ │
 └──────────────────┘"
                 )]
@@ -925,7 +926,7 @@ public class DialogTests
 ┌┌───────────────┐─┐
 ││               │ │
 ││               │ │
-││     ⟦ Ok ⟧    │ │
+││    ⟦ Ok ⟧     │ │
 │└───────────────┘ │
 └──────────────────┘"
                 )]
@@ -936,7 +937,7 @@ public class DialogTests
 │┌───────────────┐ │
 ││               │ │
 ││               │ │
-││     ⟦ Ok ⟧    │ │
+││    ⟦ Ok ⟧     │ │
 │└───────────────┘ │
 └──────────────────┘"
                 )]
@@ -948,7 +949,7 @@ public class DialogTests
 ││               │ │
 ││               │ │
 ││               │ │
-││     ⟦ Ok ⟧    │ │
+││    ⟦ Ok ⟧     │ │
 │└───────────────┘ │
 └──────────────────┘"
                 )]
@@ -961,7 +962,7 @@ public class DialogTests
 ││               │ │
 ││               │ │
 ││               │ │
-││     ⟦ Ok ⟧    │ │
+││    ⟦ Ok ⟧     │ │
 │└───────────────┘ │
 └──────────────────┘"
                 )]

+ 6 - 6
UnitTests/Dialogs/MessageBoxTests.cs

@@ -278,7 +278,7 @@ public class MessageBoxTests
 │ffffffffffffffffff│
 │  ffffffffffffff  │
 │                  │
-│     {btn}    │
+│    {btn} 
 └──────────────────┘",
                                                                                        _output
                                                                                       );
@@ -302,7 +302,7 @@ public class MessageBoxTests
 │ffffffffffffffffff│
 │ffffffffffffffffff│
 │ffffffffffffffffff│
-│     {btn}    │",
+│    {btn}     │",
                                                                                        _output
                                                                                       );
                                          Application.RequestStop ();
@@ -377,7 +377,7 @@ ff ff ff ff ff ff ff
 ────────────────────
 ffffffffffffffffffff
                     
-      ⟦► btn ◄⟧     
+     ⟦► btn ◄⟧      
 ────────────────────
 ",
                                                                                        _output
@@ -459,7 +459,7 @@ ffffffffffffffffffff
 │ffffffffffffffffff│
 │ffffffffffffffffff│
 │ffffffffffffffffff│
-│     {btn}    │",
+│    {btn}     │",
                                                                                        _output
                                                                                       );
                                          Application.RequestStop ();
@@ -509,7 +509,7 @@ ffffffffffffffffffff
 ────────────────────
 ffffffffffffffffffff
                     
-      ⟦► btn ◄⟧     
+     ⟦► btn ◄⟧      
 ────────────────────
 ",
                                                                                        _output
@@ -529,7 +529,7 @@ ffffffffffffffffffff
 ────────────────────
 ffffffffffffffffffff
                     
-      ⟦► btn ◄⟧     
+     ⟦► btn ◄⟧      
 ────────────────────
 ",
                                                                                        _output

+ 18 - 1
UnitTests/Drawing/JustifierTests.cs

@@ -62,6 +62,7 @@ public class JustifierTests (ITestOutputHelper output)
     [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 }, 5, new [] { 0, 1, 3 })] // 5 is too small to fit the items. The first item is at 0, the items to the right are clipped.
     [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 })]
@@ -80,6 +81,9 @@ public class JustifierTests (ITestOutputHelper output)
     [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 }, 5, new [] { -1, 0, 2 })] // 5 is too small to fit the items. The first item is at -1.
+
     [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 })]
@@ -103,6 +107,7 @@ public class JustifierTests (ITestOutputHelper output)
     [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 }, 5, new [] { 0, 1, 3 })] // 5 is too small to fit the items. The first item is at 0, the items to the right are clipped.
     [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 })]
@@ -160,6 +165,7 @@ public class JustifierTests (ITestOutputHelper output)
     [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 }, 5, new [] { -1, 0, 2 })] // 5 is too small to fit the items. The first item is at -1.})]
     [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 })]
@@ -187,6 +193,7 @@ public class JustifierTests (ITestOutputHelper output)
     [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 }, 5, new [] { 0, 1, 3 })]
     [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 })]
@@ -224,6 +231,8 @@ public class JustifierTests (ITestOutputHelper output)
     [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 [] { 1, 2, 3 }, 5, new [] { 0, 1, 3 })] // 5 is too small to fit the items. The first item is at 0, the items to the right are clipped.
+
     [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 })]
@@ -240,6 +249,9 @@ public class JustifierTests (ITestOutputHelper output)
     [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 }, 5, new [] { -1, 0, 2 })] // 5 is too small to fit the items. The first item is at -1.
+
     [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 })]
@@ -267,6 +279,8 @@ public class JustifierTests (ITestOutputHelper output)
     [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 [] { 1, 2, 3 }, 5, new [] { 0, 1, 3 })] // 5 is too small to fit the items. The first item is at 0, the items to the right are clipped.
+
     [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 })]
@@ -408,7 +422,10 @@ public class JustifierTests (ITestOutputHelper output)
             {
                 for (var j = 0; j < sizes [position] && positions [position] + j < totalSize; j++)
                 {
-                    items [positions [position] + j] = (position + 1).ToString () [0];
+                    if (positions [position] + j >= 0)
+                    {
+                        items [positions [position] + j] = (position + 1).ToString () [0];
+                    }
                 }
             }