namespace Terminal.Gui; /// /// Controls how items are justified within a container. Used by . /// public enum Justification { /// /// The items will be left-justified. /// Left, /// /// The items will be right-justified. /// Right, /// /// The items will be arranged such that there is no more than 1 space between them. The group will be centered in the container. /// Centered, /// /// 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. /// /// /// /// 111 2222 33333 /// /// Justified, /// /// 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. /// /// /// /// 111 2222 33333 /// /// RightJustified, /// /// 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. /// /// /// /// 111 2222 33333 /// /// LeftJustified } /// /// Justifies items within a container based on the specified . /// public class Justifier { /// /// Justifies the within a container wide based on the specified /// . /// /// /// /// /// public static int [] Justify (int [] sizes, Justification justification, int totalSize) { var positions = new int [sizes.Length]; int totalItemsSize = sizes.Sum (); if (totalItemsSize > totalSize) { throw new ArgumentException ("The sum of the sizes is greater than the total size."); } switch (justification) { case Justification.Left: var currentPosition = 0; for (var i = 0; i < sizes.Length; i++) { if (sizes [i] < 0) { throw new ArgumentException ("The size of an item cannot be negative."); } positions [i] = currentPosition; currentPosition += sizes [i]; } break; case Justification.Right: currentPosition = totalSize - totalItemsSize; for (var i = 0; i < sizes.Length; i++) { if (sizes [i] < 0) { throw new ArgumentException ("The size of an item cannot be negative."); } positions [i] = currentPosition; currentPosition += sizes [i]; } break; case Justification.Centered: if (sizes.Length > 1) { 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) { spaces = 0; } else if (totalItemsAndSpaces > totalSize) { spaces = totalItemsAndSpaces - totalSize; } 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; currentPosition = 0; for (var i = 0; i < sizes.Length; i++) { if (sizes [i] < 0) { throw new ArgumentException ("The size of an item cannot be negative."); } positions [i] = currentPosition; int extraSpace = i < remainder ? 1 : 0; currentPosition += sizes [i] + spaceBetween + extraSpace; } break; case Justification.LeftJustified: if (sizes.Length > 1) { int spaceBetweenLeft = totalSize - sizes.Sum () + 1; // +1 for the extra space currentPosition = 0; for (var i = 0; i < sizes.Length - 1; i++) { if (sizes [i] < 0) { throw new ArgumentException ("The size of an item cannot be negative."); } positions [i] = currentPosition; currentPosition += sizes [i] + 1; // +1 for the extra space } positions [sizes.Length - 1] = totalSize - sizes [sizes.Length - 1]; } else if (sizes.Length == 1) { positions [0] = 0; } break; case Justification.RightJustified: if (sizes.Length > 1) { totalItemsSize = sizes.Sum (); int totalSpaces = totalSize - totalItemsSize; int bigSpace = totalSpaces - (sizes.Length - 2); positions [0] = 0; // first item is flush left positions [1] = sizes [0] + bigSpace; // second item has the big space before it // remaining items have one space between them for (var i = 2; i < sizes.Length; i++) { positions [i] = positions [i - 1] + sizes [i - 1] + 1; } } else if (sizes.Length == 1) { positions [0] = 0; // single item is flush left } break; } return positions; } }