2
0
Tig 1 жил өмнө
parent
commit
18f2ee3a77

+ 1 - 539
Terminal.Gui/View/Layout/Dim.cs

@@ -3,69 +3,6 @@ using System.Diagnostics;
 
 namespace Terminal.Gui;
 
-/// <summary>
-///     Specifies how <see cref="Dim.Auto"/> will compute the dimension.
-/// </summary>
-[Flags]
-public enum DimAutoStyle
-{
-    /// <summary>
-    ///     The dimension will be computed using both the view's <see cref="View.Text"/> and
-    ///     <see cref="View.Subviews"/> (whichever is larger).
-    /// </summary>
-    Auto = Content | Text,
-
-    /// <summary>
-    ///     The dimensions will be computed based on the View's non-Text content.
-    ///     <para>
-    ///         If <see cref="View.ContentSize"/> is explicitly set (is not <see langword="null"/>) then
-    ///         <see cref="View.ContentSize"/>
-    ///         will be used to determine the dimension.
-    ///     </para>
-    ///     <para>
-    ///         Otherwise, the Subview in <see cref="View.Subviews"/> with the largest corresponding position plus dimension
-    ///         will determine the dimension.
-    ///     </para>
-    ///     <para>
-    ///         The corresponding dimension of the view's <see cref="View.Text"/> will be ignored.
-    ///     </para>
-    /// </summary>
-    Content = 0,
-
-    /// <summary>
-    ///     <para>
-    ///         The corresponding dimension of the view's <see cref="View.Text"/>, formatted using the
-    ///         <see cref="View.TextFormatter"/> settings,
-    ///         will be used to determine the dimension.
-    ///     </para>
-    ///     <para>
-    ///         The corresponding dimensions of the <see cref="View.Subviews"/> will be ignored.
-    ///     </para>
-    /// </summary>
-    Text = 1
-}
-
-/// <summary>
-///     Indicates the dimension for <see cref="Dim"/> operations.
-/// </summary>
-public enum Dimension
-{
-    /// <summary>
-    ///     No dimension specified.
-    /// </summary>
-    None = 0,
-
-    /// <summary>
-    ///     The height dimension.
-    /// </summary>
-    Height = 1,
-
-    /// <summary>
-    ///     The width dimension.
-    /// </summary>
-    Width = 2
-}
-
 /// <summary>
 ///     <para>
 ///         A Dim object describes the dimensions of a <see cref="View"/>. Dim is the type of the
@@ -337,479 +274,4 @@ public abstract class Dim
 
     #endregion operators
 
-}
-
-/// <summary>
-///     Represents a dimension that is a fixed size.
-/// </summary>
-/// <remarks>
-///     <para>
-///         This is a low-level API that is typically used internally by the layout system. Use the various static
-///         methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
-///     </para>
-/// </remarks>
-/// <param name="size"></param>
-public class DimAbsolute (int size) : Dim
-{
-    /// <inheritdoc/>
-    public override bool Equals (object? other) { return other is DimAbsolute abs && abs.Size == Size; }
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Size.GetHashCode (); }
-
-    /// <summary>
-    ///     Gets the size of the dimension.
-    /// </summary>
-    public int Size { get; } = size;
-
-    /// <inheritdoc/>
-    public override string ToString () { return $"Absolute({Size})"; }
-
-    internal override int GetAnchor (int size) { return Size; }
-
-    internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
-    {
-        return Math.Max (GetAnchor (0), 0);
-    }
-}
-
-/// <summary>
-///     Represents a dimension that automatically sizes the view to fit all the view's Content, SubViews, and/or Text.
-/// </summary>
-/// <remarks>
-///     <para>
-///         See <see cref="DimAutoStyle"/>.
-///     </para>
-///     <para>
-///         This is a low-level API that is typically used internally by the layout system. Use the various static
-///         methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
-///     </para>
-/// </remarks>
-public class DimAuto () : Dim
-{
-    private readonly Dim? _maximumContentDim;
-
-    /// <summary>
-    ///     Gets the maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED.
-    /// </summary>
-    // ReSharper disable once ConvertToAutoProperty
-    public required Dim? MaximumContentDim
-    {
-        get => _maximumContentDim;
-        init => _maximumContentDim = value;
-    }
-
-    private readonly Dim? _minimumContentDim;
-
-    /// <summary>
-    ///     Gets the minimum dimension the View's ContentSize will be constrained to.
-    /// </summary>
-    // ReSharper disable once ConvertToAutoProperty
-    public required Dim? MinimumContentDim
-    {
-        get => _minimumContentDim;
-        init => _minimumContentDim = value;
-    }
-
-    private readonly DimAutoStyle _style;
-
-    /// <summary>
-    ///     Gets the style of the DimAuto.
-    /// </summary>
-    // ReSharper disable once ConvertToAutoProperty
-    public required DimAutoStyle Style
-    {
-        get => _style;
-        init => _style = value;
-    }
-
-    /// <inheritdoc/>
-    public override string ToString () { return $"Auto({Style},{MinimumContentDim},{MaximumContentDim})"; }
-
-    internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
-    {
-        var textSize = 0;
-        var subviewsSize = 0;
-
-        int autoMin = MinimumContentDim?.GetAnchor (superviewContentSize) ?? 0;
-
-        if (Style.HasFlag (DimAutoStyle.Text))
-        {
-            textSize = int.Max (autoMin, dimension == Dimension.Width ? us.TextFormatter.Size.Width : us.TextFormatter.Size.Height);
-        }
-
-        if (Style.HasFlag (DimAutoStyle.Content))
-        {
-            if (us._contentSize is { })
-            {
-                subviewsSize = dimension == Dimension.Width ? us.ContentSize.Width : us.ContentSize.Height;
-            }
-            else
-            {
-                // TODO: This whole body of code is a WIP (for https://github.com/gui-cs/Terminal.Gui/pull/3451).
-                subviewsSize = 0;
-
-                List<View> subviews;
-
-                if (dimension == Dimension.Width)
-                {
-                    subviews = us.Subviews.Where (v => v.X is not PosAnchorEnd && v.Width is not DimFill).ToList ();
-                }
-                else
-                {
-                    subviews = us.Subviews.Where (v => v.Y is not PosAnchorEnd && v.Height is not DimFill).ToList ();
-                }
-
-                for (var i = 0; i < subviews.Count; i++)
-                {
-                    View v = subviews [i];
-
-                    int size = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
-
-                    if (size > subviewsSize)
-                    {
-                        subviewsSize = size;
-                    }
-                }
-
-                if (dimension == Dimension.Width)
-                {
-                    subviews = us.Subviews.Where (v => v.X is PosAnchorEnd).ToList ();
-                }
-                else
-                {
-                    subviews = us.Subviews.Where (v => v.Y is PosAnchorEnd).ToList ();
-                }
-
-                int maxAnchorEnd = 0;
-                for (var i = 0; i < subviews.Count; i++)
-                {
-                    View v = subviews [i];
-                    maxAnchorEnd = dimension == Dimension.Width ? v.Frame.Width : v.Frame.Height;
-                }
-
-                subviewsSize += maxAnchorEnd;
-
-
-                if (dimension == Dimension.Width)
-                {
-                    subviews = us.Subviews.Where (v => v.Width is DimFill).ToList ();
-                }
-                else
-                {
-                    subviews = us.Subviews.Where (v => v.Height is DimFill).ToList ();
-                }
-
-                for (var i = 0; i < subviews.Count; i++)
-                {
-                    View v = subviews [i];
-
-                    if (dimension == Dimension.Width)
-                    {
-                        v.SetRelativeLayout (new Size (autoMin - subviewsSize, 0));
-                    }
-                    else
-                    {
-                        v.SetRelativeLayout (new Size (0, autoMin - subviewsSize));
-                    }
-                }
-
-            }
-        }
-
-        // All sizes here are content-relative; ignoring adornments.
-        // We take the largest of text and content.
-        int max = int.Max (textSize, subviewsSize);
-
-        // And, if min: is set, it wins if larger
-        max = int.Max (max, autoMin);
-
-        // Factor in adornments
-        Thickness thickness = us.GetAdornmentsThickness ();
-
-        max += dimension switch
-               {
-                   Dimension.Width => thickness.Horizontal,
-                   Dimension.Height => thickness.Vertical,
-                   Dimension.None => 0,
-                   _ => throw new ArgumentOutOfRangeException (nameof (dimension), dimension, null)
-               };
-
-        return int.Min (max, MaximumContentDim?.GetAnchor (superviewContentSize) ?? max);
-    }
-
-    internal override bool ReferencesOtherViews ()
-    {
-        // BUGBUG: This is not correct. _contentSize may be null.
-        return false; //_style.HasFlag (DimAutoStyle.Content);
-    }
-
-    /// <inheritdoc/>
-    public override bool Equals (object? other)
-    {
-        if (other is not DimAuto auto)
-        {
-            return false;
-        }
-
-        return auto.MinimumContentDim == MinimumContentDim &&
-               auto.MaximumContentDim == MaximumContentDim &&
-               auto.Style == Style;
-    }
-
-    /// <inheritdoc/>
-    public override int GetHashCode ()
-    {
-        return HashCode.Combine (MinimumContentDim, MaximumContentDim, Style);
-    }
-
-}
-
-/// <summary>
-///     Represents a dimension that is a combination of two other dimensions.
-/// </summary>
-/// <param name="add">
-///     Indicates whether the two dimensions are added or subtracted. 
-/// </param>
-/// <remarks>
-///     This is a low-level API that is typically used internally by the layout system. Use the various static
-///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
-/// </remarks>
-/// <param name="left">The left dimension.</param>
-/// <param name="right">The right dimension.</param>
-public class DimCombine (AddOrSubtract add, Dim? left, Dim? right) : Dim
-{
-    /// <summary>
-    ///     Gets whether the two dimensions are added or subtracted.
-    /// </summary>
-    public AddOrSubtract Add { get; } = add;
-
-    /// <summary>
-    ///     Gets the left dimension.
-    /// </summary>
-    public Dim? Left { get; } = left;
-
-    /// <summary>
-    ///     Gets the right dimension.
-    /// </summary>
-    public Dim? Right { get; } = right;
-
-    /// <inheritdoc/>
-    public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; }
-
-    internal override int GetAnchor (int size)
-    {
-        int la = Left!.GetAnchor (size);
-        int ra = Right!.GetAnchor (size);
-
-        if (Add == AddOrSubtract.Add)
-        {
-            return la + ra;
-        }
-
-        return la - ra;
-    }
-
-    internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
-    {
-        int leftNewDim = Left!.Calculate (location, superviewContentSize, us, dimension);
-        int rightNewDim = Right!.Calculate (location, superviewContentSize, us, dimension);
-
-        int newDimension;
-
-        if (Add == AddOrSubtract.Add)
-        {
-            newDimension = leftNewDim + rightNewDim;
-        }
-        else
-        {
-            newDimension = Math.Max (0, leftNewDim - rightNewDim);
-        }
-
-        return newDimension;
-    }
-
-    /// <summary>
-    ///     Diagnostics API to determine if this Dim object references other views.
-    /// </summary>
-    /// <returns></returns>
-    internal override bool ReferencesOtherViews ()
-    {
-        if (Left!.ReferencesOtherViews ())
-        {
-            return true;
-        }
-
-        if (Right!.ReferencesOtherViews ())
-        {
-            return true;
-        }
-
-        return false;
-    }
-}
-
-/// <summary>
-///     Represents a dimension that is a percentage of the width or height of the SuperView.
-/// </summary>
-/// <remarks>
-///     This is a low-level API that is typically used internally by the layout system. Use the various static
-///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
-/// </remarks>
-/// <param name="percent">The percentage.</param>
-/// <param name="usePosition">
-///     If <see langword="true"/> the dimension is computed using the View's position (<see cref="View.X"/> or
-///     <see cref="View.Y"/>).
-///     If <see langword="false"/> the dimension is computed using the View's <see cref="View.ContentSize"/>.
-/// </param>
-public class DimPercent (float percent, bool usePosition = false) : Dim
-{
-    /// <inheritdoc/>
-    public override bool Equals (object? other) { return other is DimPercent f && f.Percent == Percent && f.UsePosition == UsePosition; }
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Percent.GetHashCode (); }
-
-    /// <summary>
-    ///     Gets the percentage.
-    /// </summary>
-    public new float Percent { get; } = percent;
-
-    /// <summary>
-    /// </summary>
-    /// <returns></returns>
-    public override string ToString () { return $"Percent({Percent},{UsePosition})"; }
-
-    /// <summary>
-    ///     Gets whether the dimension is computed using the View's position or ContentSize.
-    /// </summary>
-    public bool UsePosition { get; } = usePosition;
-
-    internal override int GetAnchor (int size) { return (int)(size * Percent); }
-
-    internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
-    {
-        return UsePosition ? Math.Max (GetAnchor (superviewContentSize - location), 0) : GetAnchor (superviewContentSize);
-    }
-}
-
-/// <summary>
-///     Represents a dimension that fills the dimension, leaving the specified margin.
-/// </summary>
-/// <remarks>
-///     This is a low-level API that is typically used internally by the layout system. Use the various static
-///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
-/// </remarks>
-/// <param name="margin">The margin to not fill.</param>
-public class DimFill (int margin) : Dim
-{
-    /// <inheritdoc/>
-    public override bool Equals (object? other) { return other is DimFill fill && fill.Margin == Margin; }
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Margin.GetHashCode (); }
-
-    /// <summary>
-    ///     Gets the margin to not fill.
-    /// </summary>
-    public int Margin { get; } = margin;
-
-    /// <inheritdoc/>
-    public override string ToString () { return $"Fill({Margin})"; }
-
-    internal override int GetAnchor (int size) { return size - Margin; }
-}
-
-/// <summary>
-///     Represents a function <see cref="Dim"/> object that computes the dimension by executing the provided function.
-/// </summary>
-/// <remarks>
-///     This is a low-level API that is typically used internally by the layout system. Use the various static
-///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
-/// </remarks>
-/// <param name="dim"></param>
-public class DimFunc (Func<int> dim) : Dim
-{
-    /// <inheritdoc/>
-    public override bool Equals (object? other) { return other is DimFunc f && f.Func () == Func (); }
-
-    /// <summary>
-    ///     Gets the function that computes the dimension.
-    /// </summary>
-    public new Func<int> Func { get; } = dim;
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Func.GetHashCode (); }
-
-    /// <inheritdoc/>
-    public override string ToString () { return $"DimFunc({Func ()})"; }
-
-    internal override int GetAnchor (int size) { return Func (); }
-}
-
-/// <summary>
-///     Represents a dimension that tracks the Height or Width of the specified View.
-/// </summary>
-/// <remarks>
-///     This is a low-level API that is typically used internally by the layout system. Use the various static
-///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
-/// </remarks>
-public class DimView : Dim
-{
-    /// <summary>
-    ///     Initializes a new instance of the <see cref="DimView"/> class.
-    /// </summary>
-    /// <param name="view">The view the dimension is anchored to.</param>
-    /// <param name="dimension">Indicates which dimension is tracked.</param>
-    public DimView (View view, Dimension dimension)
-    {
-        Target = view;
-        Dimension = dimension;
-    }
-
-    /// <summary>
-    ///     Gets the indicated dimension of the View.
-    /// </summary>
-    public Dimension Dimension { get; }
-
-    /// <inheritdoc/>
-    public override bool Equals (object? other) { return other is DimView abs && abs.Target == Target && abs.Dimension == Dimension; }
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Target.GetHashCode (); }
-
-    /// <summary>
-    ///     Gets the View the dimension is anchored to.
-    /// </summary>
-    public View Target { get; init; }
-
-    /// <inheritdoc/>
-    public override string ToString ()
-    {
-        if (Target == null)
-        {
-            throw new NullReferenceException ();
-        }
-
-        string dimString = Dimension switch
-        {
-            Dimension.Height => "Height",
-            Dimension.Width => "Width",
-            _ => "unknown"
-        };
-
-        return $"View({dimString},{Target})";
-    }
-
-    internal override int GetAnchor (int size)
-    {
-        return Dimension switch
-        {
-            Dimension.Height => Target.Frame.Height,
-            Dimension.Width => Target.Frame.Width,
-            _ => 0
-        };
-    }
-
-    internal override bool ReferencesOtherViews () { return true; }
-}
+}

+ 36 - 0
Terminal.Gui/View/Layout/DimAbsolute.cs

@@ -0,0 +1,36 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a dimension that is a fixed size.
+/// </summary>
+/// <remarks>
+///     <para>
+///         This is a low-level API that is typically used internally by the layout system. Use the various static
+///         methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
+///     </para>
+/// </remarks>
+/// <param name="size"></param>
+public class DimAbsolute (int size) : Dim
+{
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is DimAbsolute abs && abs.Size == Size; }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Size.GetHashCode (); }
+
+    /// <summary>
+    ///     Gets the size of the dimension.
+    /// </summary>
+    public int Size { get; } = size;
+
+    /// <inheritdoc/>
+    public override string ToString () { return $"Absolute({Size})"; }
+
+    internal override int GetAnchor (int size) { return Size; }
+
+    internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
+    {
+        return Math.Max (GetAnchor (0), 0);
+    }
+}

+ 194 - 0
Terminal.Gui/View/Layout/DimAuto.cs

@@ -0,0 +1,194 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a dimension that automatically sizes the view to fit all the view's Content, SubViews, and/or Text.
+/// </summary>
+/// <remarks>
+///     <para>
+///         See <see cref="DimAutoStyle"/>.
+///     </para>
+///     <para>
+///         This is a low-level API that is typically used internally by the layout system. Use the various static
+///         methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
+///     </para>
+/// </remarks>
+public class DimAuto () : Dim
+{
+    private readonly Dim? _maximumContentDim;
+
+    /// <summary>
+    ///     Gets the maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED.
+    /// </summary>
+    // ReSharper disable once ConvertToAutoProperty
+    public required Dim? MaximumContentDim
+    {
+        get => _maximumContentDim;
+        init => _maximumContentDim = value;
+    }
+
+    private readonly Dim? _minimumContentDim;
+
+    /// <summary>
+    ///     Gets the minimum dimension the View's ContentSize will be constrained to.
+    /// </summary>
+    // ReSharper disable once ConvertToAutoProperty
+    public required Dim? MinimumContentDim
+    {
+        get => _minimumContentDim;
+        init => _minimumContentDim = value;
+    }
+
+    private readonly DimAutoStyle _style;
+
+    /// <summary>
+    ///     Gets the style of the DimAuto.
+    /// </summary>
+    // ReSharper disable once ConvertToAutoProperty
+    public required DimAutoStyle Style
+    {
+        get => _style;
+        init => _style = value;
+    }
+
+    /// <inheritdoc/>
+    public override string ToString () { return $"Auto({Style},{MinimumContentDim},{MaximumContentDim})"; }
+
+    internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
+    {
+        var textSize = 0;
+        var subviewsSize = 0;
+
+        int autoMin = MinimumContentDim?.GetAnchor (superviewContentSize) ?? 0;
+
+        if (Style.HasFlag (DimAutoStyle.Text))
+        {
+            textSize = int.Max (autoMin, dimension == Dimension.Width ? us.TextFormatter.Size.Width : us.TextFormatter.Size.Height);
+        }
+
+        if (Style.HasFlag (DimAutoStyle.Content))
+        {
+            if (us._contentSize is { })
+            {
+                subviewsSize = dimension == Dimension.Width ? us.ContentSize.Width : us.ContentSize.Height;
+            }
+            else
+            {
+                // TODO: This whole body of code is a WIP (for https://github.com/gui-cs/Terminal.Gui/pull/3451).
+                subviewsSize = 0;
+
+                List<View> subviews;
+
+                if (dimension == Dimension.Width)
+                {
+                    subviews = us.Subviews.Where (v => v.X is not PosAnchorEnd && v.Width is not DimFill).ToList ();
+                }
+                else
+                {
+                    subviews = us.Subviews.Where (v => v.Y is not PosAnchorEnd && v.Height is not DimFill).ToList ();
+                }
+
+                for (var i = 0; i < subviews.Count; i++)
+                {
+                    View v = subviews [i];
+
+                    int size = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
+
+                    if (size > subviewsSize)
+                    {
+                        subviewsSize = size;
+                    }
+                }
+
+                if (dimension == Dimension.Width)
+                {
+                    subviews = us.Subviews.Where (v => v.X is PosAnchorEnd).ToList ();
+                }
+                else
+                {
+                    subviews = us.Subviews.Where (v => v.Y is PosAnchorEnd).ToList ();
+                }
+
+                int maxAnchorEnd = 0;
+                for (var i = 0; i < subviews.Count; i++)
+                {
+                    View v = subviews [i];
+                    maxAnchorEnd = dimension == Dimension.Width ? v.Frame.Width : v.Frame.Height;
+                }
+
+                subviewsSize += maxAnchorEnd;
+
+
+                if (dimension == Dimension.Width)
+                {
+                    subviews = us.Subviews.Where (v => v.Width is DimFill).ToList ();
+                }
+                else
+                {
+                    subviews = us.Subviews.Where (v => v.Height is DimFill).ToList ();
+                }
+
+                for (var i = 0; i < subviews.Count; i++)
+                {
+                    View v = subviews [i];
+
+                    if (dimension == Dimension.Width)
+                    {
+                        v.SetRelativeLayout (new Size (autoMin - subviewsSize, 0));
+                    }
+                    else
+                    {
+                        v.SetRelativeLayout (new Size (0, autoMin - subviewsSize));
+                    }
+                }
+
+            }
+        }
+
+        // All sizes here are content-relative; ignoring adornments.
+        // We take the largest of text and content.
+        int max = int.Max (textSize, subviewsSize);
+
+        // And, if min: is set, it wins if larger
+        max = int.Max (max, autoMin);
+
+        // Factor in adornments
+        Thickness thickness = us.GetAdornmentsThickness ();
+
+        max += dimension switch
+               {
+                   Dimension.Width => thickness.Horizontal,
+                   Dimension.Height => thickness.Vertical,
+                   Dimension.None => 0,
+                   _ => throw new ArgumentOutOfRangeException (nameof (dimension), dimension, null)
+               };
+
+        return int.Min (max, MaximumContentDim?.GetAnchor (superviewContentSize) ?? max);
+    }
+
+    internal override bool ReferencesOtherViews ()
+    {
+        // BUGBUG: This is not correct. _contentSize may be null.
+        return false; //_style.HasFlag (DimAutoStyle.Content);
+    }
+
+    /// <inheritdoc/>
+    public override bool Equals (object? other)
+    {
+        if (other is not DimAuto auto)
+        {
+            return false;
+        }
+
+        return auto.MinimumContentDim == MinimumContentDim &&
+               auto.MaximumContentDim == MaximumContentDim &&
+               auto.Style == Style;
+    }
+
+    /// <inheritdoc/>
+    public override int GetHashCode ()
+    {
+        return HashCode.Combine (MinimumContentDim, MaximumContentDim, Style);
+    }
+
+}

+ 43 - 0
Terminal.Gui/View/Layout/DimAutoStyle.cs

@@ -0,0 +1,43 @@
+namespace Terminal.Gui;
+
+/// <summary>
+///     Specifies how <see cref="Dim.Auto"/> will compute the dimension.
+/// </summary>
+[Flags]
+public enum DimAutoStyle
+{
+    /// <summary>
+    ///     The dimension will be computed using both the view's <see cref="View.Text"/> and
+    ///     <see cref="View.Subviews"/> (whichever is larger).
+    /// </summary>
+    Auto = Content | Text,
+
+    /// <summary>
+    ///     The dimensions will be computed based on the View's non-Text content.
+    ///     <para>
+    ///         If <see cref="View.ContentSize"/> is explicitly set (is not <see langword="null"/>) then
+    ///         <see cref="View.ContentSize"/>
+    ///         will be used to determine the dimension.
+    ///     </para>
+    ///     <para>
+    ///         Otherwise, the Subview in <see cref="View.Subviews"/> with the largest corresponding position plus dimension
+    ///         will determine the dimension.
+    ///     </para>
+    ///     <para>
+    ///         The corresponding dimension of the view's <see cref="View.Text"/> will be ignored.
+    ///     </para>
+    /// </summary>
+    Content = 0,
+
+    /// <summary>
+    ///     <para>
+    ///         The corresponding dimension of the view's <see cref="View.Text"/>, formatted using the
+    ///         <see cref="View.TextFormatter"/> settings,
+    ///         will be used to determine the dimension.
+    ///     </para>
+    ///     <para>
+    ///         The corresponding dimensions of the <see cref="View.Subviews"/> will be ignored.
+    ///     </para>
+    /// </summary>
+    Text = 1
+}

+ 86 - 0
Terminal.Gui/View/Layout/DimCombine.cs

@@ -0,0 +1,86 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a dimension that is a combination of two other dimensions.
+/// </summary>
+/// <param name="add">
+///     Indicates whether the two dimensions are added or subtracted. 
+/// </param>
+/// <remarks>
+///     This is a low-level API that is typically used internally by the layout system. Use the various static
+///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
+/// </remarks>
+/// <param name="left">The left dimension.</param>
+/// <param name="right">The right dimension.</param>
+public class DimCombine (AddOrSubtract add, Dim? left, Dim? right) : Dim
+{
+    /// <summary>
+    ///     Gets whether the two dimensions are added or subtracted.
+    /// </summary>
+    public AddOrSubtract Add { get; } = add;
+
+    /// <summary>
+    ///     Gets the left dimension.
+    /// </summary>
+    public Dim? Left { get; } = left;
+
+    /// <summary>
+    ///     Gets the right dimension.
+    /// </summary>
+    public Dim? Right { get; } = right;
+
+    /// <inheritdoc/>
+    public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; }
+
+    internal override int GetAnchor (int size)
+    {
+        int la = Left!.GetAnchor (size);
+        int ra = Right!.GetAnchor (size);
+
+        if (Add == AddOrSubtract.Add)
+        {
+            return la + ra;
+        }
+
+        return la - ra;
+    }
+
+    internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
+    {
+        int leftNewDim = Left!.Calculate (location, superviewContentSize, us, dimension);
+        int rightNewDim = Right!.Calculate (location, superviewContentSize, us, dimension);
+
+        int newDimension;
+
+        if (Add == AddOrSubtract.Add)
+        {
+            newDimension = leftNewDim + rightNewDim;
+        }
+        else
+        {
+            newDimension = Math.Max (0, leftNewDim - rightNewDim);
+        }
+
+        return newDimension;
+    }
+
+    /// <summary>
+    ///     Diagnostics API to determine if this Dim object references other views.
+    /// </summary>
+    /// <returns></returns>
+    internal override bool ReferencesOtherViews ()
+    {
+        if (Left!.ReferencesOtherViews ())
+        {
+            return true;
+        }
+
+        if (Right!.ReferencesOtherViews ())
+        {
+            return true;
+        }
+
+        return false;
+    }
+}

+ 29 - 0
Terminal.Gui/View/Layout/DimFill.cs

@@ -0,0 +1,29 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a dimension that fills the dimension, leaving the specified margin.
+/// </summary>
+/// <remarks>
+///     This is a low-level API that is typically used internally by the layout system. Use the various static
+///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
+/// </remarks>
+/// <param name="margin">The margin to not fill.</param>
+public class DimFill (int margin) : Dim
+{
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is DimFill fill && fill.Margin == Margin; }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Margin.GetHashCode (); }
+
+    /// <summary>
+    ///     Gets the margin to not fill.
+    /// </summary>
+    public int Margin { get; } = margin;
+
+    /// <inheritdoc/>
+    public override string ToString () { return $"Fill({Margin})"; }
+
+    internal override int GetAnchor (int size) { return size - Margin; }
+}

+ 29 - 0
Terminal.Gui/View/Layout/DimFunc.cs

@@ -0,0 +1,29 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a function <see cref="Dim"/> object that computes the dimension by executing the provided function.
+/// </summary>
+/// <remarks>
+///     This is a low-level API that is typically used internally by the layout system. Use the various static
+///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
+/// </remarks>
+/// <param name="dim"></param>
+public class DimFunc (Func<int> dim) : Dim
+{
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is DimFunc f && f.Func () == Func (); }
+
+    /// <summary>
+    ///     Gets the function that computes the dimension.
+    /// </summary>
+    public new Func<int> Func { get; } = dim;
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Func.GetHashCode (); }
+
+    /// <inheritdoc/>
+    public override string ToString () { return $"DimFunc({Func ()})"; }
+
+    internal override int GetAnchor (int size) { return Func (); }
+}

+ 46 - 0
Terminal.Gui/View/Layout/DimPercent.cs

@@ -0,0 +1,46 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a dimension that is a percentage of the width or height of the SuperView.
+/// </summary>
+/// <remarks>
+///     This is a low-level API that is typically used internally by the layout system. Use the various static
+///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
+/// </remarks>
+/// <param name="percent">The percentage.</param>
+/// <param name="usePosition">
+///     If <see langword="true"/> the dimension is computed using the View's position (<see cref="View.X"/> or
+///     <see cref="View.Y"/>).
+///     If <see langword="false"/> the dimension is computed using the View's <see cref="View.ContentSize"/>.
+/// </param>
+public class DimPercent (float percent, bool usePosition = false) : Dim
+{
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is DimPercent f && f.Percent == Percent && f.UsePosition == UsePosition; }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Percent.GetHashCode (); }
+
+    /// <summary>
+    ///     Gets the percentage.
+    /// </summary>
+    public new float Percent { get; } = percent;
+
+    /// <summary>
+    /// </summary>
+    /// <returns></returns>
+    public override string ToString () { return $"Percent({Percent},{UsePosition})"; }
+
+    /// <summary>
+    ///     Gets whether the dimension is computed using the View's position or ContentSize.
+    /// </summary>
+    public bool UsePosition { get; } = usePosition;
+
+    internal override int GetAnchor (int size) { return (int)(size * Percent); }
+
+    internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
+    {
+        return UsePosition ? Math.Max (GetAnchor (superviewContentSize - location), 0) : GetAnchor (superviewContentSize);
+    }
+}

+ 69 - 0
Terminal.Gui/View/Layout/DimView.cs

@@ -0,0 +1,69 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a dimension that tracks the Height or Width of the specified View.
+/// </summary>
+/// <remarks>
+///     This is a low-level API that is typically used internally by the layout system. Use the various static
+///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
+/// </remarks>
+public class DimView : Dim
+{
+    /// <summary>
+    ///     Initializes a new instance of the <see cref="DimView"/> class.
+    /// </summary>
+    /// <param name="view">The view the dimension is anchored to.</param>
+    /// <param name="dimension">Indicates which dimension is tracked.</param>
+    public DimView (View view, Dimension dimension)
+    {
+        Target = view;
+        Dimension = dimension;
+    }
+
+    /// <summary>
+    ///     Gets the indicated dimension of the View.
+    /// </summary>
+    public Dimension Dimension { get; }
+
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is DimView abs && abs.Target == Target && abs.Dimension == Dimension; }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Target.GetHashCode (); }
+
+    /// <summary>
+    ///     Gets the View the dimension is anchored to.
+    /// </summary>
+    public View Target { get; init; }
+
+    /// <inheritdoc/>
+    public override string ToString ()
+    {
+        if (Target == null)
+        {
+            throw new NullReferenceException ();
+        }
+
+        string dimString = Dimension switch
+                           {
+                               Dimension.Height => "Height",
+                               Dimension.Width => "Width",
+                               _ => "unknown"
+                           };
+
+        return $"View({dimString},{Target})";
+    }
+
+    internal override int GetAnchor (int size)
+    {
+        return Dimension switch
+               {
+                   Dimension.Height => Target.Frame.Height,
+                   Dimension.Width => Target.Frame.Width,
+                   _ => 0
+               };
+    }
+
+    internal override bool ReferencesOtherViews () { return true; }
+}

+ 22 - 0
Terminal.Gui/View/Layout/Dimension.cs

@@ -0,0 +1,22 @@
+namespace Terminal.Gui;
+
+/// <summary>
+///     Indicates the dimension for <see cref="Dim"/> operations.
+/// </summary>
+public enum Dimension
+{
+    /// <summary>
+    ///     No dimension specified.
+    /// </summary>
+    None = 0,
+
+    /// <summary>
+    ///     The height dimension.
+    /// </summary>
+    Height = 1,
+
+    /// <summary>
+    ///     The width dimension.
+    /// </summary>
+    Width = 2
+}

+ 35 - 0
Terminal.Gui/View/Layout/LayoutStyle.cs

@@ -0,0 +1,35 @@
+namespace Terminal.Gui;
+
+/// <summary>
+///     <para>Indicates the LayoutStyle for the <see cref="View"/>.</para>
+///     <para>
+///         If Absolute, the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, and
+///         <see cref="View.Height"/> objects are all absolute values and are not relative. The position and size of the
+///         view is described by <see cref="View.Frame"/>.
+///     </para>
+///     <para>
+///         If Computed, one or more of the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, or
+///         <see cref="View.Height"/> objects are relative to the <see cref="View.SuperView"/> and are computed at layout
+///         time.
+///     </para>
+/// </summary>
+public enum LayoutStyle
+{
+    /// <summary>
+    ///     Indicates the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, and
+    ///     <see cref="View.Height"/> objects are all absolute values and are not relative. The position and size of the view
+    ///     is described by <see cref="View.Frame"/>.
+    /// </summary>
+    Absolute,
+
+    /// <summary>
+    ///     Indicates one or more of the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, or
+    ///     <see cref="View.Height"/>
+    ///     objects are relative to the <see cref="View.SuperView"/> and are computed at layout time.  The position and size of
+    ///     the
+    ///     view
+    ///     will be computed based on these objects at layout time. <see cref="View.Frame"/> will provide the absolute computed
+    ///     values.
+    /// </summary>
+    Computed
+}

+ 2 - 338
Terminal.Gui/View/Layout/Pos.cs

@@ -1,31 +1,6 @@
+#nullable enable
 namespace Terminal.Gui;
 
-/// <summary>
-///     Indicates the side for <see cref="Pos"/> operations.
-/// </summary>
-public enum Side
-{
-    /// <summary>
-    ///     The left (X) side of the view.
-    /// </summary>
-    Left = 0,
-
-    /// <summary>
-    ///     The top (Y) side of the view.
-    /// </summary>
-    Top = 1,
-
-    /// <summary>
-    ///     The right (X + Width) side of the view.
-    /// </summary>
-    Right = 2,
-
-    /// <summary>
-    ///     The bottom (Y + Height) side of the view.
-    /// </summary>
-    Bottom = 3
-}
-
 /// <summary>
 ///     Describes the position of a <see cref="View"/> which can be an absolute value, a percentage, centered, or
 ///     relative to the ending dimension. Integer values are implicitly convertible to an absolute <see cref="Pos"/>. These
@@ -385,315 +360,4 @@ public abstract class Pos
 
     #endregion operators
 
-}
-
-/// <summary>
-///     Represents an absolute position in the layout. This is used to specify a fixed position in the layout.
-/// </summary>
-/// <remarks>
-///     <para>
-///         This is a low-level API that is typically used internally by the layout system. Use the various static
-///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
-///     </para>
-/// </remarks>
-/// <param name="position"></param>
-public class PosAbsolute (int position) : Pos
-{
-    /// <summary>
-    ///     The position of the <see cref="View"/> in the layout.
-    /// </summary>
-    public int Position { get; } = position;
-
-    /// <inheritdoc/>
-    public override bool Equals (object other) { return other is PosAbsolute abs && abs.Position == Position; }
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Position.GetHashCode (); }
-
-    /// <inheritdoc/>
-    public override string ToString () { return $"Absolute({Position})"; }
-
-    internal override int GetAnchor (int size) { return Position; }
-}
-
-/// <summary>
-///     Represents a position anchored to the end (right side or bottom).
-/// </summary>
-/// <remarks>
-///     <para>
-///         This is a low-level API that is typically used internally by the layout system. Use the various static
-///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
-///     </para>
-/// </remarks>
-public class PosAnchorEnd : Pos
-{
-    /// <summary>
-    ///     Gets the offset of the position from the right/bottom.
-    /// </summary>
-    public int Offset { get; }
-
-    /// <summary>
-    ///     Constructs a new position anchored to the end (right side or bottom) of the SuperView,
-    ///     minus the respective dimension of the View. This is equivalent to using <see cref="PosAnchorEnd(int)"/>,
-    ///     with an offset equivalent to the View's respective dimension.
-    /// </summary>
-    public PosAnchorEnd () { UseDimForOffset = true; }
-
-    /// <summary>
-    ///     Constructs a new position anchored to the end (right side or bottom) of the SuperView,
-    /// </summary>
-    /// <param name="offset"></param>
-    public PosAnchorEnd (int offset) { Offset = offset; }
-
-    /// <inheritdoc/>
-    public override bool Equals (object other) { return other is PosAnchorEnd anchorEnd && anchorEnd.Offset == Offset; }
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Offset.GetHashCode (); }
-
-    /// <summary>
-    ///     If true, the offset is the width of the view, if false, the offset is the offset value.
-    /// </summary>
-    public bool UseDimForOffset { get; }
-
-    /// <inheritdoc/>
-    public override string ToString () { return UseDimForOffset ? "AnchorEnd()" : $"AnchorEnd({Offset})"; }
-
-    internal override int GetAnchor (int size)
-    {
-        if (UseDimForOffset)
-        {
-            return size;
-        }
-
-        return size - Offset;
-    }
-
-    internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
-    {
-        int newLocation = GetAnchor (superviewDimension);
-
-        if (UseDimForOffset)
-        {
-            newLocation -= dim.GetAnchor (superviewDimension);
-        }
-
-        return newLocation;
-    }
-}
-
-/// <summary>
-///     Represents a position that is centered.
-/// </summary>
-public class PosCenter : Pos
-{
-    /// <inheritdoc/>
-    public override string ToString () { return "Center"; }
-
-    internal override int GetAnchor (int size) { return size / 2; }
-
-    internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
-    {
-        int newDimension = Math.Max (dim.Calculate (0, superviewDimension, us, dimension), 0);
-
-        return GetAnchor (superviewDimension - newDimension);
-    }
-}
-
-/// <summary>
-///     Represents a position that is a combination of two other positions.
-/// </summary>
-/// <remarks>
-///     <para>
-///         This is a low-level API that is typically used internally by the layout system. Use the various static
-///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
-///     </para>
-/// </remarks>
-/// <param name="add">
-///     Indicates whether the two positions are added or subtracted.
-/// </param>
-/// <param name="left">The left position.</param>
-/// <param name="right">The right position.</param>
-public class PosCombine (AddOrSubtract add, Pos left, Pos right) : Pos
-{
-    /// <summary>
-    ///     Gets whether the two positions are added or subtracted.
-    /// </summary>
-    public AddOrSubtract Add { get; } = add;
-
-    /// <summary>
-    ///     Gets the left position.
-    /// </summary>
-    public new Pos Left { get; } = left;
-
-    /// <summary>
-    ///     Gets the right position.
-    /// </summary>
-    public new Pos Right { get; } = right;
-
-    /// <inheritdoc/>
-    public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; }
-
-    internal override int GetAnchor (int size)
-    {
-        int la = Left.GetAnchor (size);
-        int ra = Right.GetAnchor (size);
-
-        if (Add == AddOrSubtract.Add)
-        {
-            return la + ra;
-        }
-
-        return la - ra;
-    }
-
-    internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
-    {
-        int left = Left.Calculate (superviewDimension, dim, us, dimension);
-        int right = Right.Calculate (superviewDimension, dim, us, dimension);
-
-        if (Add == AddOrSubtract.Add)
-        {
-            return left + right;
-        }
-
-        return left - right;
-    }
-
-    internal override bool ReferencesOtherViews ()
-    {
-        if (Left.ReferencesOtherViews ())
-        {
-            return true;
-        }
-
-        if (Right.ReferencesOtherViews ())
-        {
-            return true;
-        }
-
-        return false;
-    }
-}
-
-/// <summary>
-///     Represents a position that is a percentage of the width or height of the SuperView.
-/// </summary>
-/// <remarks>
-///     <para>
-///         This is a low-level API that is typically used internally by the layout system. Use the various static
-///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
-///     </para>
-/// </remarks>
-/// <param name="percent"></param>
-public class PosPercent (float percent) : Pos
-{
-    /// <summary>
-    ///     Gets the factor that represents the percentage of the width or height of the SuperView.
-    /// </summary>
-    public new float Percent { get; } = percent;
-
-    /// <inheritdoc/>
-    public override bool Equals (object other) { return other is PosPercent f && f.Percent == Percent; }
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Percent.GetHashCode (); }
-
-    /// <inheritdoc/>
-    public override string ToString () { return $"Percent({Percent})"; }
-
-    internal override int GetAnchor (int size) { return (int)(size * Percent); }
-}
-
-/// <summary>
-///     Represents a position that is computed by executing a function that returns an integer position.
-/// </summary>
-/// <remarks>
-///     <para>
-///         This is a low-level API that is typically used internally by the layout system. Use the various static
-///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
-///     </para>
-/// </remarks>
-/// <param name="pos">The position.</param>
-public class PosFunc (Func<int> pos) : Pos
-{
-    /// <summary>
-    ///     Gets the function that computes the position.
-    /// </summary>
-    public new Func<int> Func { get; } = pos;
-
-    /// <inheritdoc/>
-    public override bool Equals (object other) { return other is PosFunc f && f.Func () == Func (); }
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Func.GetHashCode (); }
-
-    /// <inheritdoc/>
-    public override string ToString () { return $"PosFunc({Func ()})"; }
-
-    internal override int GetAnchor (int size) { return Func (); }
-}
-
-/// <summary>
-///     Represents a position that is anchored to the side of another view.
-/// </summary>
-/// <remarks>
-///     <para>
-///         This is a low-level API that is typically used internally by the layout system. Use the various static
-///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
-///     </para>
-/// </remarks>
-/// <param name="view">The View the position is anchored to.</param>
-/// <param name="side">The side of the View the position is anchored to.</param>
-public class PosView (View view, Side side) : Pos
-{
-    /// <summary>
-    ///     Gets the View the position is anchored to.
-    /// </summary>
-    public View Target { get; } = view;
-
-    /// <summary>
-    ///     Gets the side of the View the position is anchored to.
-    /// </summary>
-    public Side Side { get; } = side;
-
-    /// <inheritdoc/>
-    public override bool Equals (object other) { return other is PosView abs && abs.Target == Target && abs.Side == Side; }
-
-    /// <inheritdoc/>
-    public override int GetHashCode () { return Target.GetHashCode (); }
-
-    /// <inheritdoc/>
-    public override string ToString ()
-    {
-        string sideString = Side switch
-                            {
-                                Side.Left => "left",
-                                Side.Top => "top",
-                                Side.Right => "right",
-                                Side.Bottom => "bottom",
-                                _ => "unknown"
-                            };
-
-        if (Target == null)
-        {
-            throw new NullReferenceException (nameof (Target));
-        }
-
-        return $"View(side={sideString},target={Target})";
-    }
-
-    internal override int GetAnchor (int size)
-    {
-        return Side switch
-               {
-                   Side.Left => Target.Frame.X,
-                   Side.Top => Target.Frame.Y,
-                   Side.Right => Target.Frame.Right,
-                   Side.Bottom => Target.Frame.Bottom,
-                   _ => 0
-               };
-    }
-
-    internal override bool ReferencesOtherViews () { return true; }
-}
+}

+ 31 - 0
Terminal.Gui/View/Layout/PosAbsolute.cs

@@ -0,0 +1,31 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents an absolute position in the layout. This is used to specify a fixed position in the layout.
+/// </summary>
+/// <remarks>
+///     <para>
+///         This is a low-level API that is typically used internally by the layout system. Use the various static
+///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
+///     </para>
+/// </remarks>
+/// <param name="position"></param>
+public class PosAbsolute (int position) : Pos
+{
+    /// <summary>
+    ///     The position of the <see cref="View"/> in the layout.
+    /// </summary>
+    public int Position { get; } = position;
+
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is PosAbsolute abs && abs.Position == Position; }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Position.GetHashCode (); }
+
+    /// <inheritdoc/>
+    public override string ToString () { return $"Absolute({Position})"; }
+
+    internal override int GetAnchor (int size) { return Position; }
+}

+ 68 - 0
Terminal.Gui/View/Layout/PosAnchorEnd.cs

@@ -0,0 +1,68 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a position anchored to the end (right side or bottom).
+/// </summary>
+/// <remarks>
+///     <para>
+///         This is a low-level API that is typically used internally by the layout system. Use the various static
+///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
+///     </para>
+/// </remarks>
+public class PosAnchorEnd : Pos
+{
+    /// <summary>
+    ///     Gets the offset of the position from the right/bottom.
+    /// </summary>
+    public int Offset { get; }
+
+    /// <summary>
+    ///     Constructs a new position anchored to the end (right side or bottom) of the SuperView,
+    ///     minus the respective dimension of the View. This is equivalent to using <see cref="PosAnchorEnd(int)"/>,
+    ///     with an offset equivalent to the View's respective dimension.
+    /// </summary>
+    public PosAnchorEnd () { UseDimForOffset = true; }
+
+    /// <summary>
+    ///     Constructs a new position anchored to the end (right side or bottom) of the SuperView,
+    /// </summary>
+    /// <param name="offset"></param>
+    public PosAnchorEnd (int offset) { Offset = offset; }
+
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is PosAnchorEnd anchorEnd && anchorEnd.Offset == Offset; }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Offset.GetHashCode (); }
+
+    /// <summary>
+    ///     If true, the offset is the width of the view, if false, the offset is the offset value.
+    /// </summary>
+    public bool UseDimForOffset { get; }
+
+    /// <inheritdoc/>
+    public override string ToString () { return UseDimForOffset ? "AnchorEnd()" : $"AnchorEnd({Offset})"; }
+
+    internal override int GetAnchor (int size)
+    {
+        if (UseDimForOffset)
+        {
+            return size;
+        }
+
+        return size - Offset;
+    }
+
+    internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
+    {
+        int newLocation = GetAnchor (superviewDimension);
+
+        if (UseDimForOffset)
+        {
+            newLocation -= dim.GetAnchor (superviewDimension);
+        }
+
+        return newLocation;
+    }
+}

+ 20 - 0
Terminal.Gui/View/Layout/PosCenter.cs

@@ -0,0 +1,20 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a position that is centered.
+/// </summary>
+public class PosCenter : Pos
+{
+    /// <inheritdoc/>
+    public override string ToString () { return "Center"; }
+
+    internal override int GetAnchor (int size) { return size / 2; }
+
+    internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
+    {
+        int newDimension = Math.Max (dim.Calculate (0, superviewDimension, us, dimension), 0);
+
+        return GetAnchor (superviewDimension - newDimension);
+    }
+}

+ 78 - 0
Terminal.Gui/View/Layout/PosCombine.cs

@@ -0,0 +1,78 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a position that is a combination of two other positions.
+/// </summary>
+/// <remarks>
+///     <para>
+///         This is a low-level API that is typically used internally by the layout system. Use the various static
+///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
+///     </para>
+/// </remarks>
+/// <param name="add">
+///     Indicates whether the two positions are added or subtracted.
+/// </param>
+/// <param name="left">The left position.</param>
+/// <param name="right">The right position.</param>
+public class PosCombine (AddOrSubtract add, Pos left, Pos right) : Pos
+{
+    /// <summary>
+    ///     Gets whether the two positions are added or subtracted.
+    /// </summary>
+    public AddOrSubtract Add { get; } = add;
+
+    /// <summary>
+    ///     Gets the left position.
+    /// </summary>
+    public new Pos Left { get; } = left;
+
+    /// <summary>
+    ///     Gets the right position.
+    /// </summary>
+    public new Pos Right { get; } = right;
+
+    /// <inheritdoc/>
+    public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; }
+
+    internal override int GetAnchor (int size)
+    {
+        int la = Left.GetAnchor (size);
+        int ra = Right.GetAnchor (size);
+
+        if (Add == AddOrSubtract.Add)
+        {
+            return la + ra;
+        }
+
+        return la - ra;
+    }
+
+    internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
+    {
+        int left = Left.Calculate (superviewDimension, dim, us, dimension);
+        int right = Right.Calculate (superviewDimension, dim, us, dimension);
+
+        if (Add == AddOrSubtract.Add)
+        {
+            return left + right;
+        }
+
+        return left - right;
+    }
+
+    internal override bool ReferencesOtherViews ()
+    {
+        if (Left.ReferencesOtherViews ())
+        {
+            return true;
+        }
+
+        if (Right.ReferencesOtherViews ())
+        {
+            return true;
+        }
+
+        return false;
+    }
+}

+ 31 - 0
Terminal.Gui/View/Layout/PosFunc.cs

@@ -0,0 +1,31 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a position that is computed by executing a function that returns an integer position.
+/// </summary>
+/// <remarks>
+///     <para>
+///         This is a low-level API that is typically used internally by the layout system. Use the various static
+///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
+///     </para>
+/// </remarks>
+/// <param name="pos">The position.</param>
+public class PosFunc (Func<int> pos) : Pos
+{
+    /// <summary>
+    ///     Gets the function that computes the position.
+    /// </summary>
+    public new Func<int> Func { get; } = pos;
+
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is PosFunc f && f.Func () == Func (); }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Func.GetHashCode (); }
+
+    /// <inheritdoc/>
+    public override string ToString () { return $"PosFunc({Func ()})"; }
+
+    internal override int GetAnchor (int size) { return Func (); }
+}

+ 31 - 0
Terminal.Gui/View/Layout/PosPercent.cs

@@ -0,0 +1,31 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a position that is a percentage of the width or height of the SuperView.
+/// </summary>
+/// <remarks>
+///     <para>
+///         This is a low-level API that is typically used internally by the layout system. Use the various static
+///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
+///     </para>
+/// </remarks>
+/// <param name="percent"></param>
+public class PosPercent (float percent) : Pos
+{
+    /// <summary>
+    ///     Gets the factor that represents the percentage of the width or height of the SuperView.
+    /// </summary>
+    public new float Percent { get; } = percent;
+
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is PosPercent f && f.Percent == Percent; }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Percent.GetHashCode (); }
+
+    /// <inheritdoc/>
+    public override string ToString () { return $"Percent({Percent})"; }
+
+    internal override int GetAnchor (int size) { return (int)(size * Percent); }
+}

+ 66 - 0
Terminal.Gui/View/Layout/PosView.cs

@@ -0,0 +1,66 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents a position that is anchored to the side of another view.
+/// </summary>
+/// <remarks>
+///     <para>
+///         This is a low-level API that is typically used internally by the layout system. Use the various static
+///         methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
+///     </para>
+/// </remarks>
+/// <param name="view">The View the position is anchored to.</param>
+/// <param name="side">The side of the View the position is anchored to.</param>
+public class PosView (View view, Side side) : Pos
+{
+    /// <summary>
+    ///     Gets the View the position is anchored to.
+    /// </summary>
+    public View Target { get; } = view;
+
+    /// <summary>
+    ///     Gets the side of the View the position is anchored to.
+    /// </summary>
+    public Side Side { get; } = side;
+
+    /// <inheritdoc/>
+    public override bool Equals (object? other) { return other is PosView abs && abs.Target == Target && abs.Side == Side; }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return Target.GetHashCode (); }
+
+    /// <inheritdoc/>
+    public override string ToString ()
+    {
+        string sideString = Side switch
+                            {
+                                Side.Left => "left",
+                                Side.Top => "top",
+                                Side.Right => "right",
+                                Side.Bottom => "bottom",
+                                _ => "unknown"
+                            };
+
+        if (Target == null)
+        {
+            throw new NullReferenceException (nameof (Target));
+        }
+
+        return $"View(side={sideString},target={Target})";
+    }
+
+    internal override int GetAnchor (int size)
+    {
+        return Side switch
+               {
+                   Side.Left => Target.Frame.X,
+                   Side.Top => Target.Frame.Y,
+                   Side.Right => Target.Frame.Right,
+                   Side.Bottom => Target.Frame.Bottom,
+                   _ => 0
+               };
+    }
+
+    internal override bool ReferencesOtherViews () { return true; }
+}

+ 27 - 0
Terminal.Gui/View/Layout/Side.cs

@@ -0,0 +1,27 @@
+namespace Terminal.Gui;
+
+/// <summary>
+///     Indicates the side for <see cref="Pos"/> operations.
+/// </summary>
+public enum Side
+{
+    /// <summary>
+    ///     The left (X) side of the view.
+    /// </summary>
+    Left = 0,
+
+    /// <summary>
+    ///     The top (Y) side of the view.
+    /// </summary>
+    Top = 1,
+
+    /// <summary>
+    ///     The right (X + Width) side of the view.
+    /// </summary>
+    Right = 2,
+
+    /// <summary>
+    ///     The bottom (Y + Height) side of the view.
+    /// </summary>
+    Bottom = 3
+}

+ 0 - 34
Terminal.Gui/View/Layout/ViewLayout.cs → Terminal.Gui/View/Layout/View.cs

@@ -4,40 +4,6 @@ using Microsoft.CodeAnalysis;
 
 namespace Terminal.Gui;
 
-/// <summary>
-///     <para>Indicates the LayoutStyle for the <see cref="View"/>.</para>
-///     <para>
-///         If Absolute, the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, and
-///         <see cref="View.Height"/> objects are all absolute values and are not relative. The position and size of the
-///         view is described by <see cref="View.Frame"/>.
-///     </para>
-///     <para>
-///         If Computed, one or more of the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, or
-///         <see cref="View.Height"/> objects are relative to the <see cref="View.SuperView"/> and are computed at layout
-///         time.
-///     </para>
-/// </summary>
-public enum LayoutStyle
-{
-    /// <summary>
-    ///     Indicates the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, and
-    ///     <see cref="View.Height"/> objects are all absolute values and are not relative. The position and size of the view
-    ///     is described by <see cref="View.Frame"/>.
-    /// </summary>
-    Absolute,
-
-    /// <summary>
-    ///     Indicates one or more of the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, or
-    ///     <see cref="View.Height"/>
-    ///     objects are relative to the <see cref="View.SuperView"/> and are computed at layout time.  The position and size of
-    ///     the
-    ///     view
-    ///     will be computed based on these objects at layout time. <see cref="View.Frame"/> will provide the absolute computed
-    ///     values.
-    /// </summary>
-    Computed
-}
-
 public partial class View
 {
     #region Frame