Tig пре 1 година
родитељ
комит
1bb90abb52

+ 5 - 0
Directory.Build.targets

@@ -0,0 +1,5 @@
+<Project>
+  <PropertyGroup>
+    <DefineConstants>$(DefineConstants);DIMAUTO</DefineConstants>
+  </PropertyGroup>
+</Project>

+ 0 - 1
Terminal.Gui/Directory.Build.props

@@ -7,5 +7,4 @@
     -->
     <Authors>Miguel de Icaza, Charlie Kindel (@tig), @BDisp</Authors>
   </PropertyGroup>
-
 </Project>

+ 190 - 152
Terminal.Gui/View/Layout/PosDim.cs

@@ -1,4 +1,4 @@
-namespace Terminal.Gui;
+namespace Terminal.Gui;
 
 /// <summary>
 ///     Describes the position of a <see cref="View"/> which can be an absolute value, a percentage, centered, or
@@ -43,7 +43,7 @@
 ///             </item>
 ///             <item>
 ///                 <term>
-///                     <see cref="Pos.Anchor(int)"/>
+///                     <see cref="Pos.AnchorEnd(int)"/>
 ///                 </term>
 ///                 <description>
 ///                     Creates a <see cref="Pos"/> object that is anchored to the end (right side or bottom) of
@@ -132,8 +132,7 @@ public class Pos
     /// <param name="offset">The view will be shifted left or up by the amount specified.</param>
     /// <example>
     ///     This sample shows how align a <see cref="Button"/> to the bottom-right of a <see cref="View"/>.
-    ///     <code>
-    /// // See Issue #502 
+    /// <code>
     /// anchorButton.X = Pos.AnchorEnd () - (Pos.Right (anchorButton) - Pos.Left (anchorButton));
     /// anchorButton.Y = Pos.AnchorEnd (1);
     /// </code>
@@ -159,19 +158,19 @@ public class Pos
     /// </summary>
     /// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
     /// <param name="view">The <see cref="View"/>  that will be tracked.</param>
-    public static Pos Bottom (View view) { return new PosView (view, 3); }
+    public static Pos Bottom (View view) { return new PosView (view, Side.Bottom); }
 
     /// <summary>Creates a <see cref="Pos"/> object that can be used to center the <see cref="View"/>.</summary>
     /// <returns>The center Pos.</returns>
     /// <example>
-    ///     This creates a <see cref="TextField"/>that is centered horizontally, is 50% of the way down, is 30% the height, and
+    ///     This creates a <see cref="TextView"/> centered horizontally, is 50% of the way down, is 30% the height, and
     ///     is 80% the width of the <see cref="View"/> it added to.
-    ///     <code>
+    ///  <code>
     ///  var textView = new TextView () {
-    /// 	X = Pos.Center (),
-    /// 	Y = Pos.Percent (50),
-    /// 	Width = Dim.Percent (80),
-    ///  	Height = Dim.Percent (30),
+    ///     X = Pos.Center (),
+    ///     Y = Pos.Percent (50),
+    ///     Width = Dim.Percent (80),
+    ///     Height = Dim.Percent (30),
     ///  };
     ///  </code>
     /// </example>
@@ -200,7 +199,7 @@ public class Pos
     /// <summary>Creates a <see cref="Pos"/> object that tracks the Left (X) position of the specified <see cref="View"/>.</summary>
     /// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
     /// <param name="view">The <see cref="View"/>  that will be tracked.</param>
-    public static Pos Left (View view) { return new PosView (view, 0); }
+    public static Pos Left (View view) { return new PosView (view, Side.X); }
 
     /// <summary>Adds a <see cref="Terminal.Gui.Pos"/> to a <see cref="Terminal.Gui.Pos"/>, yielding a new <see cref="Pos"/>.</summary>
     /// <param name="left">The first <see cref="Terminal.Gui.Pos"/> to add.</param>
@@ -246,27 +245,27 @@ public class Pos
 
     /// <summary>Creates a percentage <see cref="Pos"/> object</summary>
     /// <returns>The percent <see cref="Pos"/> object.</returns>
-    /// <param name="n">A value between 0 and 100 representing the percentage.</param>
+    /// <param name="percent">A value between 0 and 100 representing the percentage.</param>
     /// <example>
-    ///     This creates a <see cref="TextField"/>that is centered horizontally, is 50% of the way down, is 30% the height, and
+    ///     This creates a <see cref="TextField"/> centered horizontally, is 50% of the way down, is 30% the height, and
     ///     is 80% the width of the <see cref="View"/> it added to.
-    ///     <code>
-    ///  var textView = new TextView () {
-    /// 	X = Pos.Center (),
-    /// 	Y = Pos.Percent (50),
-    /// 	Width = Dim.Percent (80),
-    ///  	Height = Dim.Percent (30),
+    ///  <code>
+    ///  var textView = new TextField {
+    ///      X = Pos.Center (),
+    ///      Y = Pos.Percent (50),
+    ///      Width = Dim.Percent (80),
+    ///      Height = Dim.Percent (30),
     ///  };
     ///  </code>
     /// </example>
-    public static Pos Percent (float n)
+    public static Pos Percent (float percent)
     {
-        if (n is < 0 or > 100)
+        if (percent is < 0 or > 100)
         {
-            throw new ArgumentException ("Percent value must be between 0 and 100");
+            throw new ArgumentException ("Percent value must be between 0 and 100.");
         }
 
-        return new PosFactor (n / 100);
+        return new PosFactor (percent / 100);
     }
 
     /// <summary>
@@ -275,49 +274,46 @@ public class Pos
     /// </summary>
     /// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
     /// <param name="view">The <see cref="View"/>  that will be tracked.</param>
-    public static Pos Right (View view) { return new PosView (view, 2); }
+    public static Pos Right (View view) { return new PosView (view, Side.Right); }
 
     /// <summary>Creates a <see cref="Pos"/> object that tracks the Top (Y) position of the specified <see cref="View"/>.</summary>
     /// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
     /// <param name="view">The <see cref="View"/>  that will be tracked.</param>
-    public static Pos Top (View view) { return new PosView (view, 1); }
+    public static Pos Top (View view) { return new PosView (view, Side.Y); }
 
     /// <summary>Creates a <see cref="Pos"/> object that tracks the Left (X) position of the specified <see cref="View"/>.</summary>
     /// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
     /// <param name="view">The <see cref="View"/>  that will be tracked.</param>
-    public static Pos X (View view) { return new PosView (view, 0); }
+    public static Pos X (View view) { return new PosView (view, Side.X); }
 
     /// <summary>Creates a <see cref="Pos"/> object that tracks the Top (Y) position of the specified <see cref="View"/>.</summary>
     /// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
     /// <param name="view">The <see cref="View"/>  that will be tracked.</param>
-    public static Pos Y (View view) { return new PosView (view, 1); }
+    public static Pos Y (View view) { return new PosView (view, Side.Y); }
 
     internal virtual int Anchor (int width) { return 0; }
 
+    // BUGBUG: newPos is never used
     private static void SetPosCombine (Pos left, PosCombine newPos)
     {
-        var view = left as PosView;
-
-        if (view is { })
+        if (left is PosView view)
         {
             view.Target.SetNeedsLayout ();
         }
     }
 
-    internal class PosAbsolute : Pos
+    internal class PosAbsolute (int n) : Pos
     {
-        private readonly int _n;
-        public PosAbsolute (int n) { _n = n; }
+        private readonly int _n = n;
         public override bool Equals (object other) { return other is PosAbsolute abs && abs._n == _n; }
         public override int GetHashCode () { return _n.GetHashCode (); }
         public override string ToString () { return $"Absolute({_n})"; }
         internal override int Anchor (int width) { return _n; }
     }
 
-    internal class PosAnchorEnd : Pos
+    internal class PosAnchorEnd (int offset) : Pos
     {
-        private readonly int _offset;
-        public PosAnchorEnd (int offset) { _offset = offset; }
+        private readonly int _offset = offset;
         public override bool Equals (object other) { return other is PosAnchorEnd anchorEnd && anchorEnd._offset == _offset; }
         public override int GetHashCode () { return _offset.GetHashCode (); }
         public override string ToString () { return $"AnchorEnd({_offset})"; }
@@ -330,17 +326,10 @@ public class Pos
         internal override int Anchor (int width) { return width / 2; }
     }
 
-    internal class PosCombine : Pos
+    internal class PosCombine (bool add, Pos left, Pos right) : Pos
     {
-        internal bool _add;
-        internal Pos _left, _right;
-
-        public PosCombine (bool add, Pos left, Pos right)
-        {
-            _left = left;
-            _right = right;
-            _add = add;
-        }
+        internal bool _add = add;
+        internal Pos _left = left, _right = right;
 
         public override string ToString () { return $"Combine({_left}{(_add ? '+' : '-')}{_right})"; }
 
@@ -358,10 +347,9 @@ public class Pos
         }
     }
 
-    internal class PosFactor : Pos
+    internal class PosFactor (float factor) : Pos
     {
-        private readonly float _factor;
-        public PosFactor (float n) { _factor = n; }
+        private readonly float _factor = factor;
         public override bool Equals (object other) { return other is PosFactor f && f._factor == _factor; }
         public override int GetHashCode () { return _factor.GetHashCode (); }
         public override string ToString () { return $"Factor({_factor})"; }
@@ -369,75 +357,57 @@ public class Pos
     }
 
     // Helper class to provide dynamic value by the execution of a function that returns an integer.
-    internal class PosFunc : Pos
+    internal class PosFunc (Func<int> n) : Pos
     {
-        private readonly Func<int> _function;
-        public PosFunc (Func<int> n) { _function = n; }
+        private readonly Func<int> _function = n;
         public override bool Equals (object other) { return other is PosFunc f && f._function () == _function (); }
         public override int GetHashCode () { return _function.GetHashCode (); }
         public override string ToString () { return $"PosFunc({_function ()})"; }
         internal override int Anchor (int width) { return _function (); }
     }
 
-    internal class PosView : Pos
+    internal enum Side
     {
-        public readonly View Target;
-
-        private readonly int side;
+        X = 0,
+        Y = 1,
+        Right = 2,
+        Bottom = 3,
+    }
 
-        public PosView (View view, int side)
-        {
-            Target = view;
-            this.side = side;
-        }
+    internal class PosView (View view, Side side) : Pos
+    {
+        public readonly View Target = view;
 
         public override bool Equals (object other) { return other is PosView abs && abs.Target == Target; }
         public override int GetHashCode () { return Target.GetHashCode (); }
 
         public override string ToString ()
         {
-            string tside;
-
-            switch (side)
-            {
-                case 0:
-                    tside = "x";
-
-                    break;
-                case 1:
-                    tside = "y";
-
-                    break;
-                case 2:
-                    tside = "right";
-
-                    break;
-                case 3:
-                    tside = "bottom";
-
-                    break;
-                default:
-                    tside = "unknown";
-
-                    break;
-            }
+            string side1 = side switch
+                           {
+                               Side.X => "x",
+                               Side.Y => "y",
+                               Side.Right => "right",
+                               Side.Bottom => "bottom",
+                               _ => "unknown"
+                           };
 
             if (Target is null)
             {
                 throw new NullReferenceException (nameof (Target));
             }
 
-            return $"View(side={tside},target={Target})";
+            return $"View(side={side1},target={Target})";
         }
 
         internal override int Anchor (int width)
         {
             switch (side)
             {
-                case 0: return Target.Frame.X;
-                case 1: return Target.Frame.Y;
-                case 2: return Target.Frame.Right;
-                case 3: return Target.Frame.Bottom;
+                case Side.X: return Target.Frame.X;
+                case Side.Y: return Target.Frame.Y;
+                case Side.Right: return Target.Frame.Right;
+                case Side.Bottom: return Target.Frame.Bottom;
                 default:
                     return 0;
             }
@@ -465,6 +435,15 @@ public class Pos
 ///             </listheader>
 ///             <item>
 ///                 <term>
+///                     <see cref="Dim.Auto"/>
+///                 </term>
+///                 <description>
+///                     Creates a <see cref="Dim"/> object that automatically sizes the view to fit
+///                     the view's SubViews.
+///                 </description>
+///             </item>
+///             <item>
+///                 <term>
 ///                     <see cref="Dim.Function(Func{int})"/>
 ///                 </term>
 ///                 <description>
@@ -486,8 +465,8 @@ public class Pos
 ///                     <see cref="Dim.Fill(int)"/>
 ///                 </term>
 ///                 <description>
-///                     Creates a <see cref="Dim"/> object that fills the dimension, leaving the specified number
-///                     of columns for a margin.
+///                     Creates a <see cref="Dim"/> object that fills the dimension from the View's X position
+///                     to the end of the super view's width, leaving the specified number of columns for a margin.
 ///                 </description>
 ///             </item>
 ///             <item>
@@ -514,6 +493,64 @@ public class Pos
 /// </remarks>
 public class Dim
 {
+    /// <summary>
+    ///     Specifies how <see cref="DimAuto"/> will compute the dimension.
+    /// </summary>
+    public enum DimAutoStyle
+    {
+        /// <summary>
+        ///     The dimension will be computed using both the view's <see cref="View.Text"/> and
+        ///     <see cref="View.Subviews"/>.
+        ///     The larger of the corresponding text dimension or Subview in <see cref="View.Subviews"/>
+        ///     with the largest corresponding position plus dimension will determine the dimension.
+        /// </summary>
+        Auto,
+
+        /// <summary>
+        ///     The Subview in <see cref="View.Subviews"/> with the largest corresponding position plus dimension
+        ///     will determine the dimension.
+        ///     The corresponding dimension of the view's <see cref="View.Text"/> will be ignored.
+        /// </summary>
+        Subviews,
+
+        /// <summary>
+        ///     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.
+        ///     The corresponding dimensions of the <see cref="View.Subviews"/> will be ignored.
+        /// </summary>
+        Text
+    }
+
+    /// <summary>
+    ///     Creates a <see cref="Dim"/> object that automatically sizes the view to fit all of the view's SubViews and/or Text.
+    /// </summary>
+    /// <example>
+    ///     This initializes a <see cref="View"/> with two SubViews. The view will be automatically sized to fit the two
+    ///     SubViews.
+    /// <code>
+    /// var button = new Button () { Text = "Click Me!", X = 1, Y = 1, Width = 10, Height = 1 };
+    /// var textField = new TextField { Text = "Type here", X = 1, Y = 2, Width = 20, Height = 1 };
+    /// var view = new Window () { Title = "MyWindow", X = 0, Y = 0, Width = Dim.AutoSize (), Height = Dim.AutoSize () };
+    /// view.Add (button, textField);
+    /// </code>
+    /// </example>
+    /// <returns>The AutoSize <see cref="Dim"/> object.</returns>
+    /// <param name="style">
+    ///     Specifies how <see cref="DimAuto"/> will compute the dimension. The default is <see cref="DimAutoStyle.Auto"/>.
+    /// </param>
+    /// <param name="min">Specifies the minimum dimension that view will be automatically sized to.</param>
+    /// <param name="max">Specifies the maximum dimension that view will be automatically sized to. NOT CURRENTLY SUPPORTED.</param>
+    public static Dim Auto (DimAutoStyle style = DimAutoStyle.Auto, Dim min = null, Dim max = null)
+    {
+        if (max != null)
+        {
+            throw new NotImplementedException (@"max is not implemented");
+        }
+
+        return new DimAuto (style, min, max);
+    }
+
     /// <summary>Determines whether the specified object is equal to the current object.</summary>
     /// <param name="other">The object to compare with the current object. </param>
     /// <returns>
@@ -545,11 +582,11 @@ public class Dim
     /// <summary>Creates a <see cref="Dim"/> object that tracks the Height of the specified <see cref="View"/>.</summary>
     /// <returns>The height <see cref="Dim"/> of the other <see cref="View"/>.</returns>
     /// <param name="view">The view that will be tracked.</param>
-    public static Dim Height (View view) { return new DimView (view, 0); }
+    public static Dim Height (View view) { return new DimView (view, Side.Height); }
 
-    /// <summary>Adds a <see cref="Terminal.Gui.Dim"/> to a <see cref="Terminal.Gui.Dim"/>, yielding a new <see cref="Dim"/>.</summary>
-    /// <param name="left">The first <see cref="Terminal.Gui.Dim"/> to add.</param>
-    /// <param name="right">The second <see cref="Terminal.Gui.Dim"/> to add.</param>
+    /// <summary>Adds a <see cref="Dim"/> to a <see cref="Dim"/>, yielding a new <see cref="Dim"/>.</summary>
+    /// <param name="left">The first <see cref="Dim"/> to add.</param>
+    /// <param name="right">The second <see cref="Dim"/> to add.</param>
     /// <returns>The <see cref="Dim"/> that is the sum of the values of <c>left</c> and <c>right</c>.</returns>
     public static Dim operator + (Dim left, Dim right)
     {
@@ -570,11 +607,11 @@ public class Dim
     public static implicit operator Dim (int n) { return new DimAbsolute (n); }
 
     /// <summary>
-    ///     Subtracts a <see cref="Terminal.Gui.Dim"/> from a <see cref="Terminal.Gui.Dim"/>, yielding a new
+    ///     Subtracts a <see cref="Dim"/> from a <see cref="Dim"/>, yielding a new
     ///     <see cref="Dim"/>.
     /// </summary>
-    /// <param name="left">The <see cref="Terminal.Gui.Dim"/> to subtract from (the minuend).</param>
-    /// <param name="right">The <see cref="Terminal.Gui.Dim"/> to subtract (the subtrahend).</param>
+    /// <param name="left">The <see cref="Dim"/> to subtract from (the minuend).</param>
+    /// <param name="right">The <see cref="Dim"/> to subtract (the subtrahend).</param>
     /// <returns>The <see cref="Dim"/> that is the <c>left</c> minus <c>right</c>.</returns>
     public static Dim operator - (Dim left, Dim right)
     {
@@ -591,31 +628,31 @@ public class Dim
 
     /// <summary>Creates a percentage <see cref="Dim"/> object that is a percentage of the width or height of the SuperView.</summary>
     /// <returns>The percent <see cref="Dim"/> object.</returns>
-    /// <param name="n">A value between 0 and 100 representing the percentage.</param>
-    /// <param name="r">
-    ///     If <c>true</c> the Percent is computed based on the remaining space after the X/Y anchor positions. If
-    ///     <c>false</c> is computed based on the whole original space.
+    /// <param name="percent">A value between 0 and 100 representing 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.Bounds"/>.
     /// </param>
     /// <example>
-    ///     This initializes a <see cref="TextField"/>that is centered horizontally, is 50% of the way down, is 30% the height,
-    ///     and is 80% the width of the <see cref="View"/> it added to.
-    ///     <code>
-    ///  var textView = new TextView () {
-    /// 	X = Pos.Center (),
-    /// 	Y = Pos.Percent (50),
-    /// 	Width = Dim.Percent (80),
-    ///  	Height = Dim.Percent (30),
+    ///     This initializes a <see cref="TextField"/> that will be centered horizontally, is 50% of the way down, is 30% the height,
+    ///     and is 80% the width of the SuperView.
+    ///  <code>
+    ///  var textView = new TextField {
+    ///     X = Pos.Center (),
+    ///     Y = Pos.Percent (50),
+    ///     Width = Dim.Percent (80),
+    ///     Height = Dim.Percent (30),
     ///  };
     ///  </code>
     /// </example>
-    public static Dim Percent (float n, bool r = false)
+    public static Dim Percent (float percent, bool usePosition = false)
     {
-        if (n is < 0 or > 100)
+        if (percent is < 0 or > 100)
         {
             throw new ArgumentException ("Percent value must be between 0 and 100");
         }
 
-        return new DimFactor (n / 100, r);
+        return new DimFactor (percent / 100, usePosition);
     }
 
     /// <summary>Creates an Absolute <see cref="Dim"/> from the specified integer value.</summary>
@@ -626,34 +663,37 @@ public class Dim
     /// <summary>Creates a <see cref="Dim"/> object that tracks the Width of the specified <see cref="View"/>.</summary>
     /// <returns>The width <see cref="Dim"/> of the other <see cref="View"/>.</returns>
     /// <param name="view">The view that will be tracked.</param>
-    public static Dim Width (View view) { return new DimView (view, 1); }
+    public static Dim Width (View view) { return new DimView (view, Side.Width); }
 
     internal virtual int Anchor (int width) { return 0; }
 
     // BUGBUG: newPos is never used.
     private static void SetDimCombine (Dim left, DimCombine newPos) { (left as DimView)?.Target.SetNeedsLayout (); }
 
-    internal class DimAbsolute : Dim
+    internal class DimAbsolute (int n) : Dim
     {
-        private readonly int _n;
-        public DimAbsolute (int n) { _n = n; }
+        private readonly int _n = n;
         public override bool Equals (object other) { return other is DimAbsolute abs && abs._n == _n; }
         public override int GetHashCode () { return _n.GetHashCode (); }
         public override string ToString () { return $"Absolute({_n})"; }
         internal override int Anchor (int width) { return _n; }
     }
 
-    internal class DimCombine : Dim
+    internal class DimAuto (DimAutoStyle style, Dim min, Dim max) : Dim
     {
-        internal bool _add;
-        internal Dim _left, _right;
+        internal readonly Dim _max = max;
+        internal readonly Dim _min = min;
+        internal readonly DimAutoStyle _style = style;
 
-        public DimCombine (bool add, Dim left, Dim right)
-        {
-            _left = left;
-            _right = right;
-            _add = add;
-        }
+        public override bool Equals (object other) { return other is DimAuto auto && auto._min == _min && auto._max == _max && auto._style == _style; }
+        public override int GetHashCode () { return HashCode.Combine (base.GetHashCode (), _min, _max, _style); }
+        public override string ToString () { return $"Auto({_style},{_min},{_max})"; }
+    }
+
+    internal class DimCombine (bool add, Dim left, Dim right) : Dim
+    {
+        internal bool _add = add;
+        internal Dim _left = left, _right = right;
 
         public override string ToString () { return $"Combine({_left}{(_add ? '+' : '-')}{_right})"; }
 
@@ -671,16 +711,10 @@ public class Dim
         }
     }
 
-    internal class DimFactor : Dim
+    internal class DimFactor (float n, bool usePosition = false) : Dim
     {
-        private readonly float _factor;
-        private readonly bool _remaining;
-
-        public DimFactor (float n, bool r = false)
-        {
-            _factor = n;
-            _remaining = r;
-        }
+        private readonly float _factor = n;
+        private readonly bool _remaining = usePosition;
 
         public override bool Equals (object other) { return other is DimFactor f && f._factor == _factor && f._remaining == _remaining; }
         public override int GetHashCode () { return _factor.GetHashCode (); }
@@ -689,10 +723,9 @@ public class Dim
         internal override int Anchor (int width) { return (int)(width * _factor); }
     }
 
-    internal class DimFill : Dim
+    internal class DimFill (int margin) : Dim
     {
-        private readonly int _margin;
-        public DimFill (int margin) { _margin = margin; }
+        private readonly int _margin = margin;
         public override bool Equals (object other) { return other is DimFill fill && fill._margin == _margin; }
         public override int GetHashCode () { return _margin.GetHashCode (); }
         public override string ToString () { return $"Fill({_margin})"; }
@@ -700,21 +733,26 @@ public class Dim
     }
 
     // Helper class to provide dynamic value by the execution of a function that returns an integer.
-    internal class DimFunc : Dim
+    internal class DimFunc (Func<int> n) : Dim
     {
-        private readonly Func<int> _function;
-        public DimFunc (Func<int> n) { _function = n; }
+        private readonly Func<int> _function = n;
         public override bool Equals (object other) { return other is DimFunc f && f._function () == _function (); }
         public override int GetHashCode () { return _function.GetHashCode (); }
         public override string ToString () { return $"DimFunc({_function ()})"; }
         internal override int Anchor (int width) { return _function (); }
     }
 
+    internal enum Side
+    {
+        Height = 0,
+        Width = 1
+    }
+
     internal class DimView : Dim
     {
-        private readonly int _side;
+        private readonly Side _side;
 
-        public DimView (View view, int side)
+        internal DimView (View view, Side side)
         {
             Target = view;
             _side = side;
@@ -731,22 +769,22 @@ public class Dim
                 throw new NullReferenceException ();
             }
 
-            string tside = _side switch
+            string side = _side switch
                            {
-                               0 => "Height",
-                               1 => "Width",
+                               Side.Height => "Height",
+                               Side.Width => "Width",
                                _ => "unknown"
                            };
 
-            return $"View({tside},{Target})";
+            return $"View({side},{Target})";
         }
 
         internal override int Anchor (int width)
         {
             return _side switch
                    {
-                       0 => Target.Frame.Height,
-                       1 => Target.Frame.Width,
+                       Side.Height => Target.Frame.Height,
+                       Side.Width => Target.Frame.Width,
                        _ => 0
                    };
         }

+ 287 - 164
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -26,9 +26,12 @@ public enum LayoutStyle
 
     /// <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.
+    ///     <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
 }
@@ -102,7 +105,7 @@ public partial class View
             }
 
             Point boundsOffset = super.GetBoundsOffset ();
-            boundsOffset.Offset(super.Frame.X, super.Frame.Y);
+            boundsOffset.Offset (super.Frame.X, super.Frame.Y);
             ret.X += boundsOffset.X;
             ret.Y += boundsOffset.Y;
             super = super.SuperView;
@@ -440,6 +443,7 @@ public partial class View
         }
     }
 
+
     /// <summary>If <paramref name="autoSize"/> is true, resizes the view.</summary>
     /// <param name="autoSize"></param>
     /// <returns></returns>
@@ -451,7 +455,7 @@ public partial class View
         }
 
         var boundsChanged = true;
-        Size newFrameSize = GetAutoSize ();
+        Size newFrameSize = GetTextAutoSize ();
 
         if (IsInitialized && newFrameSize != Frame.Size)
         {
@@ -469,141 +473,6 @@ public partial class View
 
         return boundsChanged;
     }
-
-    /// <summary>Determines if the View's <see cref="Height"/> can be set to a new value.</summary>
-    /// <remarks>TrySetHeight can only be called when AutoSize is true (or being set to true).</remarks>
-    /// <param name="desiredHeight"></param>
-    /// <param name="resultHeight">
-    ///     Contains the width that would result if <see cref="Height"/> were set to
-    ///     <paramref name="desiredHeight"/>"/>
-    /// </param>
-    /// <returns>
-    ///     <see langword="true"/> if the View's <see cref="Height"/> can be changed to the specified value. False
-    ///     otherwise.
-    /// </returns>
-    internal bool TrySetHeight (int desiredHeight, out int resultHeight)
-    {
-        int h = desiredHeight;
-        bool canSetHeight;
-
-        switch (Height)
-        {
-            case Dim.DimCombine _:
-            case Dim.DimView _:
-            case Dim.DimFill _:
-                // It's a Dim.DimCombine and so can't be assigned. Let it have it's height anchored.
-                h = Height.Anchor (h);
-                canSetHeight = !ValidatePosDim;
-
-                break;
-            case Dim.DimFactor factor:
-                // Tries to get the SuperView height otherwise the view height.
-                int sh = SuperView is { } ? SuperView.Frame.Height : h;
-
-                if (factor.IsFromRemaining ())
-                {
-                    sh -= Frame.Y;
-                }
-
-                h = Height.Anchor (sh);
-                canSetHeight = !ValidatePosDim;
-
-                break;
-            default:
-                canSetHeight = true;
-
-                break;
-        }
-
-        resultHeight = h;
-
-        return canSetHeight;
-    }
-
-    /// <summary>Determines if the View's <see cref="Width"/> can be set to a new value.</summary>
-    /// <remarks>TrySetWidth can only be called when AutoSize is true (or being set to true).</remarks>
-    /// <param name="desiredWidth"></param>
-    /// <param name="resultWidth">
-    ///     Contains the width that would result if <see cref="Width"/> were set to
-    ///     <paramref name="desiredWidth"/>"/>
-    /// </param>
-    /// <returns>
-    ///     <see langword="true"/> if the View's <see cref="Width"/> can be changed to the specified value. False
-    ///     otherwise.
-    /// </returns>
-    internal bool TrySetWidth (int desiredWidth, out int resultWidth)
-    {
-        int w = desiredWidth;
-        bool canSetWidth;
-
-        switch (Width)
-        {
-            case Dim.DimCombine _:
-            case Dim.DimView _:
-            case Dim.DimFill _:
-                // It's a Dim.DimCombine and so can't be assigned. Let it have it's Width anchored.
-                w = Width.Anchor (w);
-                canSetWidth = !ValidatePosDim;
-
-                break;
-            case Dim.DimFactor factor:
-                // Tries to get the SuperView Width otherwise the view Width.
-                int sw = SuperView is { } ? SuperView.Frame.Width : w;
-
-                if (factor.IsFromRemaining ())
-                {
-                    sw -= Frame.X;
-                }
-
-                w = Width.Anchor (sw);
-                canSetWidth = !ValidatePosDim;
-
-                break;
-            default:
-                canSetWidth = true;
-
-                break;
-        }
-
-        resultWidth = w;
-
-        return canSetWidth;
-    }
-
-    /// <summary>Resizes the View to fit the specified size. Factors in the HotKey.</summary>
-    /// <remarks>ResizeBoundsToFit can only be called when AutoSize is true (or being set to true).</remarks>
-    /// <param name="size"></param>
-    /// <returns>whether the Bounds was changed or not</returns>
-    private bool ResizeBoundsToFit (Size size)
-    {
-        //if (AutoSize == false) {
-        //	throw new InvalidOperationException ("ResizeBoundsToFit can only be called when AutoSize is true");
-        //}
-
-        var boundsChanged = false;
-        bool canSizeW = TrySetWidth (size.Width - GetHotKeySpecifierLength (), out int rW);
-        bool canSizeH = TrySetHeight (size.Height - GetHotKeySpecifierLength (false), out int rH);
-
-        if (canSizeW)
-        {
-            boundsChanged = true;
-            _width = rW;
-        }
-
-        if (canSizeH)
-        {
-            boundsChanged = true;
-            _height = rH;
-        }
-
-        if (boundsChanged)
-        {
-            Bounds = new (Bounds.X, Bounds.Y, canSizeW ? rW : Bounds.Width, canSizeH ? rH : Bounds.Height);
-        }
-
-        return boundsChanged;
-    }
-
     #endregion AutoSize
 
     #region Layout Engine
@@ -886,8 +755,8 @@ public partial class View
     public event EventHandler<LayoutEventArgs> LayoutStarted;
 
     /// <summary>
-    ///     Invoked when a view starts executing or when the dimensions of the view have changed, for example in response
-    ///     to the container view or terminal resizing.
+    ///     Invoked when a view starts executing or when the dimensions of the view have changed, for example in response to
+    ///     the container view or terminal resizing.
     /// </summary>
     /// <remarks>
     ///     <para>
@@ -900,9 +769,7 @@ public partial class View
     {
         if (!IsInitialized)
         {
-            Debug.WriteLine (
-                             $"WARNING: LayoutSubviews called before view has been initialized. This is likely a bug in {this}"
-                            );
+            Debug.WriteLine ($"WARNING: LayoutSubviews called before view has been initialized. This is likely a bug in {this}");
         }
 
         if (!LayoutNeeded)
@@ -910,6 +777,8 @@ public partial class View
             return;
         }
 
+        CheckDimAuto ();
+
         LayoutAdornments ();
 
         Rectangle oldBounds = Bounds;
@@ -925,7 +794,24 @@ public partial class View
 
         foreach (View v in ordered)
         {
-            LayoutSubview (v, new (GetBoundsOffset (), Bounds.Size));
+            if (v.Width is Dim.DimAuto || v.Height is Dim.DimAuto)
+            {
+                // If the view is auto-sized...
+                Rectangle f = v.Frame;
+                v._frame = new (v.Frame.X, v.Frame.Y, 0, 0);
+                LayoutSubview (v, new (GetBoundsOffset (), Bounds.Size));
+
+                if (v.Frame != f)
+                {
+                    // The subviews changed; do it again
+                    v.LayoutNeeded = true;
+                    LayoutSubview (v, new (GetBoundsOffset (), Bounds.Size));
+                }
+            }
+            else
+            {
+                LayoutSubview (v, new (GetBoundsOffset (), Bounds.Size));
+            }
         }
 
         // If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
@@ -1032,6 +918,8 @@ public partial class View
         Debug.Assert (_width is { });
         Debug.Assert (_height is { });
 
+        CheckDimAuto ();
+
         int newX, newW, newY, newH;
         var autosize = Size.Empty;
 
@@ -1039,7 +927,7 @@ public partial class View
         {
             // Note this is global to this function and used as such within the local functions defined
             // below. In v2 AutoSize will be re-factored to not need to be dealt with in this function.
-            autosize = GetAutoSize ();
+            autosize = GetTextAutoSize ();
         }
 
         // TODO: Since GetNewLocationAndDimension does not depend on View, it can be moved into PosDim.cs
@@ -1094,6 +982,41 @@ public partial class View
 
                         break;
 
+                    case Dim.DimAuto auto:
+                        Thickness thickness = GetAdornmentsThickness ();
+                        var text = 0;
+                        var subviews = 0;
+
+                        int superviewSize = width ? superviewBounds.Width : superviewBounds.Height;
+                        int autoMin = auto._min?.Anchor (superviewSize) ?? 0;
+
+                        if (superviewSize < autoMin)
+                        {
+                            Debug.WriteLine ($"WARNING: DimAuto specifies a min size ({autoMin}), but the SuperView's bounds are smaller ({superviewSize}).");
+                        }
+
+                        if (auto._style is Dim.DimAutoStyle.Text or Dim.DimAutoStyle.Auto)
+                        {
+                            text = int.Max (width ? TextFormatter.Size.Width : TextFormatter.Size.Height, autoMin);
+                        }
+
+                        if (auto._style is Dim.DimAutoStyle.Subviews or Dim.DimAutoStyle.Auto)
+                        {
+                            subviews = Subviews.Count == 0
+                                           ? 0
+                                           : Subviews
+                                             .Where (v => width ? v.X is not Pos.PosAnchorEnd : v.Y is not Pos.PosAnchorEnd)
+                                             .Max (v => width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height);
+                        }
+
+                        int max = int.Max (text, subviews);
+
+                        newDimension = int.Max (width ? max + thickness.Left + thickness.Right : max + thickness.Top + thickness.Bottom, autoMin);
+                        // If _max is set, use it. Otherwise, use superview;'s size to constrain
+                        newDimension = int.Min (newDimension, auto._max?.Anchor (superviewSize) ?? superviewSize);
+
+                        break;
+
                     case Dim.DimAbsolute:
                         // DimAbsolute.Anchor (int width) ignores width and returns n
                         newDimension = Math.Max (d.Anchor (0), 0);
@@ -1104,6 +1027,12 @@ public partial class View
                         break;
 
                     case Dim.DimFill:
+                        // Fills the remaining space. 
+                        newDimension = Math.Max (d.Anchor (dimension - location), 0 /* width ? superviewBounds.Width : superviewBounds.Height*/);
+                        newDimension = AutoSize && autosize > newDimension ? autosize : newDimension;
+
+                        break;
+
                     default:
                         newDimension = Math.Max (d.Anchor (dimension - location), 0);
                         newDimension = AutoSize && autosize > newDimension ? autosize : newDimension;
@@ -1413,6 +1342,174 @@ public partial class View
         return result;
     } // TopologicalSort
 
+    /// <summary>Determines if the View's <see cref="Height"/> can be set to a new value.</summary>
+    /// <remarks>TrySetHeight can only be called when AutoSize is true (or being set to true).</remarks>
+    /// <param name="desiredHeight"></param>
+    /// <param name="resultHeight">
+    ///     Contains the width that would result if <see cref="Height"/> were set to
+    ///     <paramref name="desiredHeight"/>"/>
+    /// </param>
+    /// <returns>
+    ///     <see langword="true"/> if the View's <see cref="Height"/> can be changed to the specified value. False
+    ///     otherwise.
+    /// </returns>
+    internal bool TrySetHeight (int desiredHeight, out int resultHeight)
+    {
+        int h = desiredHeight;
+        bool canSetHeight;
+
+        switch (Height)
+        {
+            case Dim.DimCombine _:
+            case Dim.DimView _:
+            case Dim.DimFill _:
+                // It's a Dim.DimCombine and so can't be assigned. Let it have it's height anchored.
+                h = Height.Anchor (h);
+                canSetHeight = !ValidatePosDim;
+
+                break;
+            case Dim.DimFactor factor:
+                // Tries to get the SuperView height otherwise the view height.
+                int sh = SuperView != null ? SuperView.Frame.Height : h;
+
+                if (factor.IsFromRemaining ())
+                {
+                    sh -= Frame.Y;
+                }
+
+                h = Height.Anchor (sh);
+                canSetHeight = !ValidatePosDim;
+
+                break;
+            default:
+                canSetHeight = true;
+
+                break;
+        }
+
+        resultHeight = h;
+
+        return canSetHeight;
+    }
+
+    /// <summary>Determines if the View's <see cref="Width"/> can be set to a new value.</summary>
+    /// <remarks>TrySetWidth can only be called when AutoSize is true (or being set to true).</remarks>
+    /// <param name="desiredWidth"></param>
+    /// <param name="resultWidth">
+    ///     Contains the width that would result if <see cref="Width"/> were set to
+    ///     <paramref name="desiredWidth"/>"/>
+    /// </param>
+    /// <returns>
+    ///     <see langword="true"/> if the View's <see cref="Width"/> can be changed to the specified value. False
+    ///     otherwise.
+    /// </returns>
+    internal bool TrySetWidth (int desiredWidth, out int resultWidth)
+    {
+        int w = desiredWidth;
+        bool canSetWidth;
+
+        switch (Width)
+        {
+            case Dim.DimCombine _:
+            case Dim.DimView _:
+            case Dim.DimFill _:
+                // It's a Dim.DimCombine and so can't be assigned. Let it have it's Width anchored.
+                w = Width.Anchor (w);
+                canSetWidth = !ValidatePosDim;
+
+                break;
+            case Dim.DimFactor factor:
+                // Tries to get the SuperView Width otherwise the view Width.
+                int sw = SuperView != null ? SuperView.Frame.Width : w;
+
+                if (factor.IsFromRemaining ())
+                {
+                    sw -= Frame.X;
+                }
+
+                w = Width.Anchor (sw);
+                canSetWidth = !ValidatePosDim;
+
+                break;
+            default:
+                canSetWidth = true;
+
+                break;
+        }
+
+        resultWidth = w;
+
+        return canSetWidth;
+    }
+
+    /// <summary>
+    ///     Throws an <see cref="InvalidOperationException"/> if any SubViews are using Dim objects that depend on this
+    ///     Views dimensions.
+    /// </summary>
+    /// <exception cref="InvalidOperationException"></exception>
+    private void CheckDimAuto ()
+    {
+        if (!ValidatePosDim || !IsInitialized || (Width is not Dim.DimAuto && Height is not Dim.DimAuto))
+        {
+            return;
+        }
+
+        void ThrowInvalid (View view, object checkPosDim, string name)
+        {
+            // TODO: Figure out how to make CheckDimAuto deal with PosCombine
+            object bad = null;
+
+            switch (checkPosDim)
+            {
+                case Pos pos and not Pos.PosAbsolute and not Pos.PosView and not Pos.PosCombine:
+                    bad = pos;
+
+                    break;
+
+                case Pos pos and Pos.PosCombine:
+                    // Recursively check for not Absolute or not View
+                    ThrowInvalid (view, (pos as Pos.PosCombine)._left, name);
+                    ThrowInvalid (view, (pos as Pos.PosCombine)._right, name);
+
+                    break;
+
+                case Dim dim and not Dim.DimAbsolute and not Dim.DimView and not Dim.DimCombine:
+                    bad = dim;
+
+                    break;
+
+                case Dim dim and Dim.DimCombine:
+                    // Recursively check for not Absolute or not View
+                    ThrowInvalid (view, (dim as Dim.DimCombine)._left, name);
+                    ThrowInvalid (view, (dim as Dim.DimCombine)._right, name);
+
+                    break;
+            }
+
+            if (bad != null)
+            {
+                throw new InvalidOperationException (
+                                                     @$"{view.GetType ().Name}.{name} = {bad.GetType ().Name} which depends on the SuperView's dimensions and the SuperView uses Dim.Auto.");
+            }
+        }
+
+        // Verify none of the subviews are using Dim objects that depend on the SuperView's dimensions.
+        foreach (View view in Subviews)
+        {
+            if (Width is Dim.DimAuto { _min: null })
+            {
+                ThrowInvalid (view, view.Width, nameof (view.Width));
+                ThrowInvalid (view, view.X, nameof (view.X));
+            }
+
+            if (Height is Dim.DimAuto { _min: null })
+            {
+                ThrowInvalid (view, view.Height, nameof (view.Height));
+                ThrowInvalid (view, view.Y, nameof (view.Y));
+            }
+        }
+    }
+
     private void LayoutSubview (View v, Rectangle contentArea)
     {
         //if (v.LayoutStyle == LayoutStyle.Computed) {
@@ -1424,36 +1521,64 @@ public partial class View
         v.LayoutNeeded = false;
     }
 
-    #region Diagnostics
-
-    // Diagnostics to highlight when Width or Height is read before the view has been initialized
-    private Dim VerifyIsInitialized (Dim dim, string member)
+    /// <summary>Resizes the View to fit the specified size. Factors in the HotKey.</summary>
+    /// <remarks>ResizeBoundsToFit can only be called when AutoSize is true (or being set to true).</remarks>
+    /// <param name="size"></param>
+    /// <returns>whether the Bounds was changed or not</returns>
+    private bool ResizeBoundsToFit (Size size)
     {
-#if DEBUG
-        if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
+        //if (AutoSize == false) {
+        //	throw new InvalidOperationException ("ResizeBoundsToFit can only be called when AutoSize is true");
+        //}
+
+        var boundsChanged = false;
+        bool canSizeW = TrySetWidth (size.Width - GetHotKeySpecifierLength (), out int rW);
+        bool canSizeH = TrySetHeight (size.Height - GetHotKeySpecifierLength (false), out int rH);
+
+        if (canSizeW)
         {
-            Debug.WriteLine (
-                             $"WARNING: \"{this}\" has not been initialized; {member} is indeterminate: {dim}. This is potentially a bug."
-                            );
+            boundsChanged = true;
+            _width = rW;
         }
-#endif // DEBUG		
-        return dim;
+
+        if (canSizeH)
+        {
+            boundsChanged = true;
+            _height = rH;
+        }
+
+        if (boundsChanged)
+        {
+            Bounds = new (Bounds.X, Bounds.Y, canSizeW ? rW : Bounds.Width, canSizeH ? rH : Bounds.Height);
+        }
+
+        return boundsChanged;
     }
 
     // Diagnostics to highlight when X or Y is read before the view has been initialized
     private Pos VerifyIsInitialized (Pos pos, string member)
     {
 #if DEBUG
-        if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
+        if (pos is not Pos.PosAbsolute && LayoutStyle == LayoutStyle.Computed && !IsInitialized)
         {
-            Debug.WriteLine (
-                             $"WARNING: \"{this}\" has not been initialized; {member} is indeterminate {pos}. This is potentially a bug."
-                            );
+            Debug.WriteLine ($"WARNING: \"{this}\" has not been initialized; {member} is indeterminate ({pos}). This is potentially a bug.");
         }
 #endif // DEBUG
         return pos;
     }
 
+    // Diagnostics to highlight when Width or Height is read before the view has been initialized
+    private Dim VerifyIsInitialized (Dim dim, string member)
+    {
+#if DEBUG
+        if (dim is not Dim.DimAbsolute && LayoutStyle == LayoutStyle.Computed && !IsInitialized)
+        {
+            Debug.WriteLine ($"WARNING: \"{this}\" has not been initialized; {member} is indeterminate: ({dim}). This is potentially a bug.");
+        }
+#endif // DEBUG
+        return dim;
+    }
+
     /// <summary>Gets or sets whether validation of <see cref="Pos"/> and <see cref="Dim"/> occurs.</summary>
     /// <remarks>
     ///     Setting this to <see langword="true"/> will enable validation of <see cref="X"/>, <see cref="Y"/>,
@@ -1462,6 +1587,4 @@ public partial class View
     ///     thus should only be used for debugging.
     /// </remarks>
     public bool ValidatePosDim { get; set; }
-
-    #endregion
 }

+ 1 - 0
Terminal.Gui/View/ViewSubViews.cs

@@ -85,6 +85,7 @@ public partial class View
             view.EndInit ();
         }
 
+        CheckDimAuto ();
         SetNeedsLayout ();
         SetNeedsDisplay ();
     }

+ 143 - 100
Terminal.Gui/View/ViewText.cs

@@ -1,13 +1,14 @@
-namespace Terminal.Gui;
+namespace Terminal.Gui;
 
 public partial class View
 {
     private string _text;
 
     /// <summary>
-    ///     Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved or not when
-    ///     <see cref="TextFormatter.WordWrap"/> is enabled. If <see langword="true"/> trailing spaces at the end of wrapped
-    ///     lines will be removed when <see cref="Text"/> is formatted for display. The default is <see langword="false"/>.
+    ///     Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved
+    ///     or not when <see cref="TextFormatter.WordWrap"/> is enabled.
+    ///     If <see langword="true"/> trailing spaces at the end of wrapped lines will be removed when
+    ///     <see cref="Text"/> is formatted for display. The default is <see langword="false"/>.
     /// </summary>
     public virtual bool PreserveTrailingSpaces
     {
@@ -22,19 +23,29 @@ public partial class View
         }
     }
 
-    /// <summary>The text displayed by the <see cref="View"/>.</summary>
+    /// <summary>
+    ///     The text displayed by the <see cref="View"/>.
+    /// </summary>
     /// <remarks>
-    ///     <para>The text will be drawn before any subviews are drawn.</para>
     ///     <para>
-    ///         The text will be drawn starting at the view origin (0, 0) and will be formatted according to
-    ///         <see cref="TextAlignment"/> and <see cref="TextDirection"/>.
+    ///         The text will be drawn before any subviews are drawn.
+    ///     </para>
+    ///     <para>
+    ///         The text will be drawn starting at the view origin (0, 0) and will be formatted according
+    ///         to <see cref="TextAlignment"/> and <see cref="TextDirection"/>.
     ///     </para>
     ///     <para>
     ///         The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="Bounds"/>'s height
     ///         is 1, the text will be clipped.
     ///     </para>
-    ///     <para>If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Bounds"/> will be adjusted to fit the text.</para>
-    ///     <para>When the text changes, the <see cref="TextChanged"/> is fired.</para>
+    ///     <para>
+    ///         Set the <see cref="HotKeySpecifier"/> to enable hotkey support. To disable hotkey support set
+    ///         <see cref="HotKeySpecifier"/> to
+    ///         <c>(Rune)0xffff</c>.
+    ///     </para>
+    ///     <para>
+    ///         If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Bounds"/> will be adjusted to fit the text.
+    ///     </para>
     /// </remarks>
     public virtual string Text
     {
@@ -80,7 +91,9 @@ public partial class View
     ///     redisplay the <see cref="View"/>.
     /// </summary>
     /// <remarks>
-    ///     <para>If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Bounds"/> will be adjusted to fit the text.</para>
+    ///     <para>
+    ///         If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Bounds"/> will be adjusted to fit the text.
+    ///     </para>
     /// </remarks>
     /// <value>The text alignment.</value>
     public virtual TextAlignment TextAlignment
@@ -99,7 +112,9 @@ public partial class View
     ///     <see cref="View"/>.
     /// </summary>
     /// <remarks>
-    ///     <para>If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Bounds"/> will be adjusted to fit the text.</para>
+    ///     <para>
+    ///         If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Bounds"/> will be adjusted to fit the text.
+    ///     </para>
     /// </remarks>
     /// <value>The text alignment.</value>
     public virtual TextDirection TextDirection
@@ -112,15 +127,20 @@ public partial class View
         }
     }
 
-    /// <summary>Gets the <see cref="Gui.TextFormatter"/> used to format <see cref="Text"/>.</summary>
+    /// <summary>
+    ///     Gets or sets the <see cref="Gui.TextFormatter"/> used to format <see cref="Text"/>.
+    /// </summary>
     public TextFormatter TextFormatter { get; init; } = new ();
 
     /// <summary>
     ///     Gets or sets how the View's <see cref="Text"/> is aligned vertically when drawn. Changing this property will
-    ///     redisplay the <see cref="View"/>.
+    ///     redisplay
+    ///     the <see cref="View"/>.
     /// </summary>
     /// <remarks>
-    ///     <para>If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Bounds"/> will be adjusted to fit the text.</para>
+    ///     <para>
+    ///         If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Bounds"/> will be adjusted to fit the text.
+    ///     </para>
     /// </remarks>
     /// <value>The text alignment.</value>
     public virtual VerticalTextAlignment VerticalTextAlignment
@@ -134,12 +154,47 @@ public partial class View
     }
 
     /// <summary>
-    ///     Gets the Frame dimensions required to fit <see cref="Text"/> within <see cref="Bounds"/> using the text
-    ///     <see cref="NavigationDirection"/> specified by the <see cref="TextFormatter"/> property and accounting for any
-    ///     <see cref="HotKeySpecifier"/> characters.
+    ///     Gets the width or height of the <see cref="TextFormatter.HotKeySpecifier"/> characters
+    ///     in the <see cref="Text"/> property.
     /// </summary>
-    /// <returns>The <see cref="Size"/> the <see cref="Frame"/> needs to be set to fit the text.</returns>
-    public Size GetAutoSize ()
+    /// <remarks>
+    ///     Only the first HotKey specifier found in <see cref="Text"/> is supported.
+    /// </remarks>
+    /// <param name="isWidth">
+    ///     If <see langword="true"/> (the default) the width required for the HotKey specifier is returned. Otherwise the
+    ///     height
+    ///     is returned.
+    /// </param>
+    /// <returns>
+    ///     The number of characters required for the <see cref="TextFormatter.HotKeySpecifier"/>. If the text
+    ///     direction specified
+    ///     by <see cref="TextDirection"/> does not match the <paramref name="isWidth"/> parameter, <c>0</c> is returned.
+    /// </returns>
+    public int GetHotKeySpecifierLength (bool isWidth = true)
+    {
+        if (isWidth)
+        {
+            return TextFormatter.IsHorizontalDirection (TextDirection) && TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
+                       ? Math.Max (HotKeySpecifier.GetColumns (), 0)
+                       : 0;
+        }
+
+        return TextFormatter.IsVerticalDirection (TextDirection) && TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
+                   ? Math.Max (HotKeySpecifier.GetColumns (), 0)
+                   : 0;
+    }
+
+    // TODO: Refactor this to return the Bounds size, not Frame. Move code that accounts for
+    // TODO: Thickness out to callers.
+    /// <summary>
+    ///     Gets the size of the <see cref="Frame"/> required to fit <see cref="Text"/> within <see cref="Bounds"/> using the
+    ///     text
+    ///     formatting settings of <see cref="View.TextFormatter"/> and accounting for <see cref="HotKeySpecifier"/>.
+    /// </summary>
+    /// <remarks>
+    /// </remarks>
+    /// <returns>The <see cref="Size"/> of the <see cref="Frame"/> required to fit the formatted text.</returns>
+    public Size GetTextAutoSize ()
     {
         var x = 0;
         var y = 0;
@@ -154,58 +209,19 @@ public partial class View
 
         int newWidth = rect.Size.Width
                        - GetHotKeySpecifierLength ()
-                       + (Margin == null
-                              ? 0
-                              : Margin.Thickness.Horizontal
-                                + Border.Thickness.Horizontal
-                                + Padding.Thickness.Horizontal);
+                       + (Margin == null ? 0 : Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal);
 
         int newHeight = rect.Size.Height
                         - GetHotKeySpecifierLength (false)
-                        + (Margin == null
-                               ? 0
-                               : Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical);
+                        + (Margin == null ? 0 : Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical);
 
         return new (newWidth, newHeight);
     }
 
     /// <summary>
-    ///     Gets the width or height of the <see cref="TextFormatter.HotKeySpecifier"/> characters in the
-    ///     <see cref="Text"/> property.
+    ///     Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has
+    ///     different format than the default.
     /// </summary>
-    /// <remarks>
-    ///     <para>
-    ///         This is for <see cref="Text"/>, not <see cref="Title"/>. For <see cref="Text"/> to show the hotkey,
-    ///         set <c>View.</c><see cref="TextFormatter.HotKeySpecifier"/> to the desired character.
-    ///     </para>
-    ///     <para>
-    ///         Only the first HotKey specifier found in <see cref="Text"/> is supported.
-    ///     </para>
-    /// </remarks>
-    /// <param name="isWidth">
-    ///     If <see langword="true"/> (the default) the width required for the HotKey specifier is returned.
-    ///     Otherwise the height is returned.
-    /// </param>
-    /// <returns>
-    ///     The number of characters required for the <see cref="TextFormatter.HotKeySpecifier"/>. If the text direction
-    ///     specified by <see cref="TextDirection"/> does not match the <paramref name="isWidth"/> parameter, <c>0</c> is
-    ///     returned.
-    /// </returns>
-    public int GetHotKeySpecifierLength (bool isWidth = true)
-    {
-        if (isWidth)
-        {
-            return TextFormatter.IsHorizontalDirection (TextDirection) && TextFormatter.Text?.Contains ((char)TextFormatter.HotKeySpecifier.Value) == true
-                       ? Math.Max (TextFormatter.HotKeySpecifier.GetColumns (), 0)
-                       : 0;
-        }
-
-        return TextFormatter.IsVerticalDirection (TextDirection) && TextFormatter.Text?.Contains ((char)TextFormatter.HotKeySpecifier.Value) == true
-                   ? Math.Max (TextFormatter.HotKeySpecifier.GetColumns (), 0)
-                   : 0;
-    }
-
-    /// <summary>Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has different format than the default.</summary>
     protected virtual void UpdateTextFormatterText ()
     {
         if (TextFormatter is { })
@@ -214,23 +230,25 @@ public partial class View
         }
     }
 
-    /// <summary>Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="TextFormatter.HotKeySpecifier"/>.</summary>
+    /// <summary>
+    ///     Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="TextFormatter.HotKeySpecifier"/>.
+    /// </summary>
     /// <returns></returns>
     internal Size GetSizeNeededForTextWithoutHotKey ()
     {
-        return new (
-                    TextFormatter.Size.Width - GetHotKeySpecifierLength (),
-                    TextFormatter.Size.Height - GetHotKeySpecifierLength (false)
-                   );
+        return new Size (
+                         TextFormatter.Size.Width - GetHotKeySpecifierLength (),
+                         TextFormatter.Size.Height - GetHotKeySpecifierLength (false));
     }
 
     /// <summary>
-    ///     Internal API. Sets <see cref="TextFormatter"/>.Size to the current <see cref="Bounds"/> size, adjusted for
+    ///     Sets <see cref="TextFormatter"/>.Size to the current <see cref="Bounds"/> size, adjusted for
     ///     <see cref="TextFormatter.HotKeySpecifier"/>.
     /// </summary>
     /// <remarks>
-    ///     Use this API to set <see cref="TextFormatter.Size"/> when the view has changed such that the size required to
-    ///     fit the text has changed. changes.
+    ///     Use this API to set <see cref="TextFormatter.Size"/> when the view has changed such that the
+    ///     size required to fit the text has changed.
+    ///     changes.
     /// </remarks>
     /// <returns></returns>
     internal void SetTextFormatterSize ()
@@ -249,20 +267,45 @@ public partial class View
             return;
         }
 
-        TextFormatter.Size = new (
-                                  Bounds.Size.Width + GetHotKeySpecifierLength (),
-                                  Bounds.Size.Height + GetHotKeySpecifierLength (false)
-                                 );
+        int w = Bounds.Size.Width + GetHotKeySpecifierLength ();
+
+        if (Width is Dim.DimAuto widthAuto && widthAuto._style != Dim.DimAutoStyle.Subviews)
+        {
+            if (Height is Dim.DimAuto)
+            {
+                // Both are auto. 
+                TextFormatter.Size = new Size (SuperView?.Bounds.Width ?? 0, SuperView?.Bounds.Height ?? 0);
+            }
+            else
+            {
+                TextFormatter.Size = new Size (SuperView?.Bounds.Width ?? 0, Bounds.Size.Height + GetHotKeySpecifierLength ());
+            }
+
+            w = TextFormatter.FormatAndGetSize ().Width;
+        }
+        else
+        {
+            TextFormatter.Size = new Size (w, SuperView?.Bounds.Height ?? 0);
+        }
+
+        int h = Bounds.Size.Height + GetHotKeySpecifierLength ();
+
+        if (Height is Dim.DimAuto heightAuto && heightAuto._style != Dim.DimAutoStyle.Subviews)
+        {
+            TextFormatter.NeedsFormat = true;
+            h = TextFormatter.FormatAndGetSize ().Height;
+        }
+
+        TextFormatter.Size = new Size (w, h);
     }
 
     private bool IsValidAutoSize (out Size autoSize)
     {
         Rectangle rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
 
-        autoSize = new (
-                        rect.Size.Width - GetHotKeySpecifierLength (),
-                        rect.Size.Height - GetHotKeySpecifierLength (false)
-                       );
+        autoSize = new Size (
+                             rect.Size.Width - GetHotKeySpecifierLength (),
+                             rect.Size.Height - GetHotKeySpecifierLength (false));
 
         return !((ValidatePosDim && (!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute)))
                  || _frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength ()
@@ -274,8 +317,7 @@ public partial class View
         Rectangle rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
         int dimValue = height.Anchor (0);
 
-        return !((ValidatePosDim && !(height is Dim.DimAbsolute))
-                 || dimValue != rect.Size.Height - GetHotKeySpecifierLength (false));
+        return !((ValidatePosDim && !(height is Dim.DimAbsolute)) || dimValue != rect.Size.Height - GetHotKeySpecifierLength (false));
     }
 
     private bool IsValidAutoSizeWidth (Dim width)
@@ -283,27 +325,24 @@ public partial class View
         Rectangle rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
         int dimValue = width.Anchor (0);
 
-        return !((ValidatePosDim && !(width is Dim.DimAbsolute))
-                 || dimValue != rect.Size.Width - GetHotKeySpecifierLength ());
+        return !((ValidatePosDim && !(width is Dim.DimAbsolute)) || dimValue != rect.Size.Width - GetHotKeySpecifierLength ());
     }
 
-    /// <summary>Sets the size of the View to the minimum width or height required to fit <see cref="Text"/>.</summary>
+    /// <summary>
+    ///     Sets the size of the View to the minimum width or height required to fit <see cref="Text"/>.
+    /// </summary>
     /// <returns>
     ///     <see langword="true"/> if the size was changed; <see langword="false"/> if <see cref="AutoSize"/> ==
-    ///     <see langword="true"/> or <see cref="Text"/> will not fit.
+    ///     <see langword="true"/> or
+    ///     <see cref="Text"/> will not fit.
     /// </returns>
     /// <remarks>
-    ///     Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or if
-    ///     <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero. Does not take into
-    ///     account word wrapping.
+    ///     Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or
+    ///     if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
+    ///     Does not take into account word wrapping.
     /// </remarks>
     private bool SetFrameToFitText ()
     {
-        if (AutoSize == false)
-        {
-            throw new InvalidOperationException ("SetFrameToFitText can only be called when AutoSize is true");
-        }
-
         // BUGBUG: This API is broken - should not assume Frame.Height == Bounds.Height
         // <summary>
         // Gets the minimum dimensions required to fit the View's <see cref="Text"/>, factoring in <see cref="TextDirection"/>.
@@ -334,7 +373,7 @@ public partial class View
             switch (TextFormatter.IsVerticalDirection (TextDirection))
             {
                 case true:
-                    int colWidth = TextFormatter.GetWidestLineLength (new List<string> { TextFormatter.Text }, 0, 1);
+                    int colWidth = TextFormatter.GetSumMaxCharWidth (TextFormatter.Text, 0, 1);
 
                     // TODO: v2 - This uses frame.Width; it should only use Bounds
                     if (_frame.Width < colWidth
@@ -374,25 +413,29 @@ public partial class View
         return false;
     }
 
-    // only called from EndInit
     private void UpdateTextDirection (TextDirection newDirection)
     {
-        bool directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction)
-                                != TextFormatter.IsHorizontalDirection (newDirection);
+        bool directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction) != TextFormatter.IsHorizontalDirection (newDirection);
         TextFormatter.Direction = newDirection;
 
         bool isValidOldAutoSize = AutoSize && IsValidAutoSize (out Size _);
 
         UpdateTextFormatterText ();
 
-        if ((!ValidatePosDim && directionChanged && AutoSize)
-            || (ValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize))
+        if ((!ValidatePosDim && directionChanged && AutoSize) || (ValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize))
         {
             OnResizeNeeded ();
         }
-        else if (AutoSize && directionChanged && IsAdded)
+        else if (directionChanged && IsAdded)
         {
             ResizeBoundsToFit (Bounds.Size);
+
+            // BUGBUG: I think this call is redundant.
+            SetFrameToFitText ();
+        }
+        else
+        {
+            SetFrameToFitText ();
         }
 
         SetTextFormatterSize ();

+ 7 - 3
Terminal.Gui/Views/Dialog.cs

@@ -60,9 +60,13 @@ public class Dialog : Window
         Y = Pos.Center ();
         ValidatePosDim = true;
 
-        Width = Dim.Percent (85); // Dim.Auto (min: Dim.Percent (10));
-        Height = Dim.Percent (85); //Dim.Auto (min: Dim.Percent (50));
-
+#if DIMAUTO
+        Width = Dim.Auto (min: Dim.Percent (10));
+        Height = Dim.Auto (min: Dim.Percent (50));
+#else
+        Width = Dim.Percent (85); 
+        Height = Dim.Percent (85);
+#endif
         ColorScheme = Colors.ColorSchemes ["Dialog"];
 
         Modal = true;

+ 197 - 0
UICatalog/Scenarios/DimAutoDemo.cs

@@ -0,0 +1,197 @@
+using System;
+using Terminal.Gui;
+using static Terminal.Gui.Dim;
+
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("DimAuto", "Demonstrates Dim.Auto")]
+[ScenarioCategory ("Layout")]
+public class DimAutoDemo : Scenario
+{
+    public override void Main ()
+    {
+        Application.Init ();
+        // Setup - Create a top-level application window and configure it.
+        Window appWindow = new ()
+        {
+            Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}"
+        };
+
+        var view = new FrameView
+        {
+            Title = "Type to make View grow",
+            X = 1,
+            Y = 1,
+            Width = Auto (DimAutoStyle.Subviews, 40),
+            Height = Auto (DimAutoStyle.Subviews, 10)
+        };
+        view.ValidatePosDim = true;
+
+        var textEdit = new TextView { Text = "", X = 1, Y = 0, Width = 20, Height = 4 };
+        view.Add (textEdit);
+
+        var hlabel = new Label
+        {
+            Text = textEdit.Text,
+            X = Pos.Left (textEdit) + 1,
+            Y = Pos.Bottom (textEdit),
+            AutoSize = false,
+            Width = Auto (DimAutoStyle.Text, 20),
+            Height = 1,
+            ColorScheme = Colors.ColorSchemes ["Error"]
+        };
+        view.Add (hlabel);
+
+        var vlabel = new Label
+        {
+            Text = textEdit.Text,
+            X = Pos.Left (textEdit),
+            Y = Pos.Bottom (textEdit) + 1,
+            AutoSize = false,
+            Width = 1,
+            Height = Auto (DimAutoStyle.Text, 8),
+            ColorScheme = Colors.ColorSchemes ["Error"]
+
+            //TextDirection = TextDirection.TopBottom_LeftRight
+        };
+        vlabel.Id = "vlabel";
+        view.Add (vlabel);
+
+        var heightAuto = new View
+        {
+            X = Pos.Right (vlabel) + 1,
+            Y = Pos.Bottom (hlabel) + 1,
+            Width = 20,
+            Height = Auto (),
+            ColorScheme = Colors.ColorSchemes ["Error"],
+            Title = "W: 20, H: Auto",
+            BorderStyle = LineStyle.Rounded
+        };
+        heightAuto.Id = "heightAuto";
+        view.Add (heightAuto);
+
+        var widthAuto = new View
+        {
+            X = Pos.Right (heightAuto) + 1,
+            Y = Pos.Bottom (hlabel) + 1,
+            Width = Auto (),
+            Height = 5,
+            ColorScheme = Colors.ColorSchemes ["Error"],
+            Title = "W: Auto, H: 5",
+            BorderStyle = LineStyle.Rounded
+        };
+        widthAuto.Id = "widthAuto";
+        view.Add (widthAuto);
+
+        var bothAuto = new View
+        {
+            X = Pos.Right (widthAuto) + 1,
+            Y = Pos.Bottom (hlabel) + 1,
+            Width = Auto (),
+            Height = Auto (),
+            ColorScheme = Colors.ColorSchemes ["Error"],
+            Title = "W: Auto, H: Auto",
+            BorderStyle = LineStyle.Rounded
+        };
+        bothAuto.Id = "bothAuto";
+        view.Add (bothAuto);
+
+        textEdit.ContentsChanged += (s, e) =>
+                                    {
+                                        hlabel.Text = textEdit.Text;
+                                        vlabel.Text = textEdit.Text;
+                                        heightAuto.Text = textEdit.Text;
+                                        widthAuto.Text = textEdit.Text;
+                                        bothAuto.Text = textEdit.Text;
+                                    };
+
+        var movingButton = new Button
+        {
+            Text = "_Move down",
+            X = Pos.Right (vlabel),
+            Y = Pos.Bottom (vlabel),
+        };
+        movingButton.Accept += (s, e) => { movingButton.Y = movingButton.Frame.Y + 1; };
+        view.Add (movingButton);
+
+        var resetButton = new Button
+        {
+            Text = "_Reset Button",
+            X = Pos.Right (movingButton),
+            Y = Pos.Top (movingButton)
+        };
+
+        resetButton.Accept += (s, e) => { movingButton.Y = Pos.Bottom (hlabel); };
+        view.Add (resetButton);
+
+        var dlgButton = new Button
+        {
+            Text = "Open Test _Dialog",
+            X = Pos.Right (view),
+            Y = Pos.Top (view)
+        };
+        dlgButton.Accept += DlgButton_Clicked;
+
+        appWindow.Add (view, dlgButton);
+
+        // Run - Start the application.
+        Application.Run (appWindow);
+        appWindow.Dispose ();
+
+        // Shutdown - Calling Application.Shutdown is required.
+        Application.Shutdown ();
+
+    }
+
+    private void DlgButton_Clicked (object sender, EventArgs e)
+    {
+        var dlg = new Dialog
+        {
+            Title = "Test Dialog"
+        };
+
+        //var ok = new Button ("Bye") { IsDefault = true };
+        //ok.Clicked += (s, _) => Application.RequestStop (dlg);
+        //dlg.AddButton (ok);
+
+        //var cancel = new Button ("Abort") { };
+        //cancel.Clicked += (s, _) => Application.RequestStop (dlg);
+        //dlg.AddButton (cancel);
+
+        var label = new Label
+        {
+            ValidatePosDim = true,
+            Text = "This is a label (AutoSize = false; Dim.Auto(3/20). Press Esc to close. Even more text.",
+            AutoSize = false,
+            X = Pos.Center (),
+            Y = 0,
+            Height = Auto (min: 3),
+            Width = Auto (min: 20),
+            ColorScheme = Colors.ColorSchemes ["Menu"]
+        };
+
+        var text = new TextField
+        {
+            ValidatePosDim = true,
+            Text = "TextField: X=1; Y=Pos.Bottom (label)+1, Width=Dim.Fill (0); Height=1",
+            TextFormatter = new TextFormatter { WordWrap = true },
+            X = 0,
+            Y = Pos.Bottom (label) + 1,
+            Width = Fill (10),
+            Height = 1
+        };
+
+        //var btn = new Button
+        //{
+        //    Text = "AnchorEnd", Y = Pos.AnchorEnd (1)
+        //};
+
+        //// TODO: We should really fix AnchorEnd to do this automatically. 
+        //btn.X = Pos.AnchorEnd () - (Pos.Right (btn) - Pos.Left (btn));
+        dlg.Add (label);
+        dlg.Add (text);
+        //dlg.Add (btn);
+        Application.Run (dlg);
+        dlg.Dispose ();
+    }
+}

+ 1 - 1
UICatalog/UICatalog.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <TargetFramework>net8.0</TargetFramework>

Разлика између датотеке није приказан због своје велике величине
+ 291 - 311
UnitTests/Dialogs/DialogTests.cs


+ 545 - 0
UnitTests/View/Layout/DimAutoTests.cs

@@ -0,0 +1,545 @@
+using System.Globalization;
+using System.Text;
+using Xunit.Abstractions;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui.ViewTests;
+
+public class DimAutoTests
+{
+    private readonly ITestOutputHelper _output;
+
+    public DimAutoTests (ITestOutputHelper output)
+    {
+        _output = output;
+        Console.OutputEncoding = Encoding.Default;
+
+        // Change current culture
+        var culture = CultureInfo.CreateSpecificCulture ("en-US");
+        Thread.CurrentThread.CurrentCulture = culture;
+        Thread.CurrentThread.CurrentUICulture = culture;
+    }
+
+    // Test min - ensure that if min is specified in the DimAuto constructor it is honored
+    [Fact]
+    public void DimAuto_Min ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (min: 10),
+            Height = Dim.Auto (min: 10),
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 5
+        };
+
+        superView.Add (subView);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        superView.LayoutSubviews (); // no throw
+
+        Assert.Equal (10, superView.Frame.Width);
+        Assert.Equal (10, superView.Frame.Height);
+    }
+
+    // what happens if DimAuto (min: 10) and the subview moves to a negative coord?
+    [Fact]
+    public void DimAuto_Min_Resets_If_Subview_Moves_Negative ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (min: 10),
+            Height = Dim.Auto (min: 10),
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 5
+        };
+
+        superView.Add (subView);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        superView.LayoutSubviews (); // no throw
+
+        Assert.Equal (10, superView.Frame.Width);
+        Assert.Equal (10, superView.Frame.Height);
+
+        subView.X = -1;
+        subView.Y = -1;
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        superView.LayoutSubviews (); // no throw
+
+        Assert.Equal (5, subView.Frame.Width);
+        Assert.Equal (5, subView.Frame.Height);
+
+        Assert.Equal (10, superView.Frame.Width);
+        Assert.Equal (10, superView.Frame.Height);
+    }
+
+    [Fact]
+    public void DimAuto_Min_Resets_If_Subview_Shrinks ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (min: 10),
+            Height = Dim.Auto (min: 10),
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 5
+        };
+
+        superView.Add (subView);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        superView.LayoutSubviews (); // no throw
+
+        Assert.Equal (10, superView.Frame.Width);
+        Assert.Equal (10, superView.Frame.Height);
+
+        subView.Width = 3;
+        subView.Height = 3;
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        superView.LayoutSubviews (); // no throw
+
+        Assert.Equal (3, subView.Frame.Width);
+        Assert.Equal (3, subView.Frame.Height);
+
+        Assert.Equal (10, superView.Frame.Width);
+        Assert.Equal (10, superView.Frame.Height);
+    }
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0)]
+    [InlineData (0, 0, 5, 0, 0)]
+    [InlineData (0, 0, 0, 5, 5)]
+    [InlineData (0, 0, 5, 5, 5)]
+    [InlineData (1, 0, 5, 0, 0)]
+    [InlineData (1, 0, 0, 5, 5)]
+    [InlineData (1, 0, 5, 5, 5)]
+    [InlineData (1, 1, 5, 5, 6)]
+    [InlineData (-1, 0, 5, 0, 0)]
+    [InlineData (-1, 0, 0, 5, 5)]
+    [InlineData (-1, 0, 5, 5, 5)]
+    [InlineData (-1, -1, 5, 5, 4)]
+    public void Height_Auto_Width_NotChanged (int subX, int subY, int subWidth, int subHeight, int expectedHeight)
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = 10,
+            Height = Dim.Auto (),
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = subX,
+            Y = subY,
+            Width = subWidth,
+            Height = subHeight,
+            ValidatePosDim = true
+        };
+
+        superView.Add (subView);
+
+        superView.BeginInit ();
+        superView.EndInit ();
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        Assert.Equal (new Rectangle (0, 0, 10, expectedHeight), superView.Frame);
+    }
+
+    [Fact]
+    public void NoSubViews_Does_Nothing ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+            ValidatePosDim = true
+        };
+
+        superView.BeginInit ();
+        superView.EndInit ();
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        Assert.Equal (new Rectangle (0, 0, 0, 0), superView.Frame);
+
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        Assert.Equal (new Rectangle (0, 0, 0, 0), superView.Frame);
+
+        superView.SetRelativeLayout (new Rectangle (10, 10, 10, 10));
+        Assert.Equal (new Rectangle (0, 0, 0, 0), superView.Frame);
+    }
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 0, 5, 0, 5, 0)]
+    [InlineData (0, 0, 0, 5, 0, 5)]
+    [InlineData (0, 0, 5, 5, 5, 5)]
+    [InlineData (1, 0, 5, 0, 6, 0)]
+    [InlineData (1, 0, 0, 5, 1, 5)]
+    [InlineData (1, 0, 5, 5, 6, 5)]
+    [InlineData (1, 1, 5, 5, 6, 6)]
+    [InlineData (-1, 0, 5, 0, 4, 0)]
+    [InlineData (-1, 0, 0, 5, 0, 5)]
+    [InlineData (-1, 0, 5, 5, 4, 5)]
+    [InlineData (-1, -1, 5, 5, 4, 4)]
+    public void SubView_ChangesSuperViewSize (int subX, int subY, int subWidth, int subHeight, int expectedWidth, int expectedHeight)
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = subX,
+            Y = subY,
+            Width = subWidth,
+            Height = subHeight,
+            ValidatePosDim = true
+        };
+
+        superView.Add (subView);
+
+        superView.BeginInit ();
+        superView.EndInit ();
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        Assert.Equal (new Rectangle (0, 0, expectedWidth, expectedHeight), superView.Frame);
+    }
+
+    // Test validation
+    [Fact]
+    public void ValidatePosDim_True_Throws_When_SubView_Uses_SuperView_Dims ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Fill (),
+            Height = 10,
+            ValidatePosDim = true
+        };
+
+        superView.BeginInit ();
+        superView.EndInit ();
+        Assert.Throws<InvalidOperationException> (() => superView.Add (subView));
+
+        subView.Width = 10;
+        superView.Add (subView);
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        superView.LayoutSubviews (); // no throw
+
+        subView.Width = Dim.Fill ();
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.Width = 10;
+
+        subView.Height = Dim.Fill ();
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.Height = 10;
+
+        subView.Height = Dim.Percent (50);
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.Height = 10;
+
+        subView.X = Pos.Center ();
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.X = 0;
+
+        subView.Y = Pos.Center ();
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.Y = 0;
+
+        subView.Width = 10;
+        subView.Height = 10;
+        subView.X = 0;
+        subView.Y = 0;
+        superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0));
+        superView.LayoutSubviews ();
+    }
+
+    // Test validation
+    [Fact]
+    public void ValidatePosDim_True_Throws_When_SubView_Uses_SuperView_Dims_Combine ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = 10,
+            Height = 10
+        };
+
+        var subView2 = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = 10,
+            Height = 10
+        };
+
+        superView.Add (subView, subView2);
+        superView.BeginInit ();
+        superView.EndInit ();
+        superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0));
+        superView.LayoutSubviews (); // no throw
+
+        subView.Height = Dim.Fill () + 3;
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.Height = 0;
+
+        subView.Height = 3 + Dim.Fill ();
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.Height = 0;
+
+        subView.Height = 3 + 5 + Dim.Fill ();
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.Height = 0;
+
+        subView.Height = 3 + 5 + Dim.Percent (10);
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.Height = 0;
+
+        // Tests nested Combine
+        subView.Height = 5 + new Dim.DimCombine (true, 3, new Dim.DimCombine (true, Dim.Percent (10), 9));
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+    }
+
+    [Fact]
+    public void ValidatePosDim_True_Throws_When_SubView_Uses_SuperView_Pos_Combine ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = 10,
+            Height = 10
+        };
+
+        var subView2 = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = 10,
+            Height = 10
+        };
+
+        superView.Add (subView, subView2);
+        superView.BeginInit ();
+        superView.EndInit ();
+        superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0));
+        superView.LayoutSubviews (); // no throw
+
+        subView.X = Pos.Right (subView2);
+        superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0));
+        superView.LayoutSubviews (); // no throw
+
+        subView.X = Pos.Right (subView2) + 3;
+        superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)); // no throw
+        superView.LayoutSubviews (); // no throw
+
+        subView.X = new Pos.PosCombine (true, Pos.Right (subView2), new Pos.PosCombine (true, 7, 9));
+        superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)); // no throw
+
+        subView.X = Pos.Center () + 3;
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.X = 0;
+
+        subView.X = 3 + Pos.Center ();
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.X = 0;
+
+        subView.X = 3 + 5 + Pos.Center ();
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.X = 0;
+
+        subView.X = 3 + 5 + Pos.Percent (10);
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.X = 0;
+
+        subView.X = Pos.Percent (10) + Pos.Center ();
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.X = 0;
+
+        // Tests nested Combine
+        subView.X = 5 + new Pos.PosCombine (true, Pos.Right (subView2), new Pos.PosCombine (true, Pos.Center (), 9));
+        Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new Rectangle (0, 0, 0, 0)));
+        subView.X = 0;
+    }
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0)]
+    [InlineData (0, 0, 5, 0, 5)]
+    [InlineData (0, 0, 0, 5, 0)]
+    [InlineData (0, 0, 5, 5, 5)]
+    [InlineData (1, 0, 5, 0, 6)]
+    [InlineData (1, 0, 0, 5, 1)]
+    [InlineData (1, 0, 5, 5, 6)]
+    [InlineData (1, 1, 5, 5, 6)]
+    [InlineData (-1, 0, 5, 0, 4)]
+    [InlineData (-1, 0, 0, 5, 0)]
+    [InlineData (-1, 0, 5, 5, 4)]
+    [InlineData (-1, -1, 5, 5, 4)]
+    public void Width_Auto_Height_NotChanged (int subX, int subY, int subWidth, int subHeight, int expectedWidth)
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (),
+            Height = 10,
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = subX,
+            Y = subY,
+            Width = subWidth,
+            Height = subHeight,
+            ValidatePosDim = true
+        };
+
+        superView.Add (subView);
+
+        superView.BeginInit ();
+        superView.EndInit ();
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 10));
+        Assert.Equal (new Rectangle (0, 0, expectedWidth, 10), superView.Frame);
+    }
+
+    // Test that when a view has Width set to DimAuto (min: x) the width is never < x even if SetRelativeLayout is called with smaller bounds
+    [Theory]
+    [InlineData (0, 0)]
+    [InlineData (1, 1)]
+    [InlineData (3, 3)]
+    [InlineData (4, 4)]
+    [InlineData (5, 4)] // This is clearly invalid, but we choose to not throw but log a debug message
+    public void Width_Auto_Min (int min, int expectedWidth)
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (min: min),
+            Height = 1,
+            ValidatePosDim = true
+        };
+        
+        superView.BeginInit ();
+        superView.EndInit ();
+        superView.SetRelativeLayout (new Rectangle (0, 0, 4, 1));
+        Assert.Equal (expectedWidth, superView.Frame.Width);
+    }
+
+    // Test Dim.Fill - Fill should not impact width of the DimAuto superview
+    [Theory]
+    [InlineData (0, 0, 0, 10, 10)]
+    [InlineData (0, 1, 0, 10, 10)]
+    [InlineData (0, 11, 0, 10, 10)]
+    [InlineData (0, 10, 0, 10, 10)]
+    [InlineData (0, 5, 0, 10, 10)]
+    [InlineData (1, 5, 0, 10, 9)]
+    [InlineData (1, 10, 0, 10, 9)]
+    [InlineData (0, 0, 1, 10, 9)]
+    [InlineData (0, 10, 1, 10, 9)]
+    [InlineData (0, 5, 1, 10, 9)]
+    [InlineData (1, 5, 1, 10, 8)]
+    [InlineData (1, 10, 1, 10, 8)]
+    public void Width_Fill_Fills (int subX, int superMinWidth, int fill, int expectedSuperWidth, int expectedSubWidth)
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (min:superMinWidth),
+            Height = 1,
+            ValidatePosDim = true
+        };
+
+        var subView = new View
+        {
+            X = subX,
+            Y = 0,
+            Width = Dim.Fill (fill),
+            Height = 1,
+            ValidatePosDim = true
+        };
+
+        superView.Add (subView);
+
+        superView.BeginInit ();
+        superView.EndInit ();
+        superView.SetRelativeLayout (new Rectangle (0, 0, 10, 1));
+        Assert.Equal (expectedSuperWidth, superView.Frame.Width);
+        superView.LayoutSubviews ();
+        Assert.Equal (expectedSubWidth, subView.Frame.Width);
+        Assert.Equal (expectedSuperWidth, superView.Frame.Width);
+    }
+
+    // Test variations of Frame
+}

+ 408 - 285
UnitTests/View/Layout/DimTests.cs

@@ -1,9 +1,7 @@
 using System.Globalization;
 using System.Text;
 using Xunit.Abstractions;
-
-// Alias Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.FakeConsole;
+using static Terminal.Gui.Dim;
 
 namespace Terminal.Gui.ViewTests;
 
@@ -26,7 +24,7 @@ public class DimTests
     // A new test that does not depend on Application is needed.
     [Fact]
     [AutoInitShutdown]
-    public void Dim_Add_Operator ()
+    public void Add_Operator ()
     {
         Toplevel top = new ();
 
@@ -76,176 +74,7 @@ public class DimTests
     // TODO: A new test that calls SetRelativeLayout directly is needed.
     [Fact]
     [TestRespondersDisposed]
-    public void Dim_Referencing_SuperView_Does_Not_Throw ()
-    {
-        var super = new View { Width = 10, Height = 10, Text = "super" };
-
-        var view = new View
-        {
-            Width = Dim.Width (super), // this is allowed
-            Height = Dim.Height (super), // this is allowed
-            Text = "view"
-        };
-
-        super.Add (view);
-        super.BeginInit ();
-        super.EndInit ();
-
-        Exception exception = Record.Exception (super.LayoutSubviews);
-        Assert.Null (exception);
-        super.Dispose ();
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    [AutoInitShutdown]
-    public void Dim_Subtract_Operator ()
-    {
-        Toplevel top = new ();
-
-        var view = new View { X = 0, Y = 0, Width = 20, Height = 0 };
-        var field = new TextField { X = 0, Y = Pos.Bottom (view), Width = 20 };
-        var count = 20;
-        List<Label> listLabels = new ();
-
-        for (var i = 0; i < count; i++)
-        {
-            field.Text = $"Label {i}";
-            var label = new Label { X = 0, Y = view.Bounds.Height, /*Width = 20,*/ Text = field.Text };
-            view.Add (label);
-            Assert.Equal ($"Label {i}", label.Text);
-            Assert.Equal ($"Absolute({i})", label.Y.ToString ());
-            listLabels.Add (label);
-
-            Assert.Equal ($"Absolute({i})", view.Height.ToString ());
-            view.Height += 1;
-            Assert.Equal ($"Absolute({i + 1})", view.Height.ToString ());
-        }
-
-        field.KeyDown += (s, k) =>
-                         {
-                             if (k.KeyCode == KeyCode.Enter)
-                             {
-                                 Assert.Equal ($"Label {count - 1}", listLabels [count - 1].Text);
-                                 view.Remove (listLabels [count - 1]);
-                                 listLabels [count - 1].Dispose ();
-
-                                 Assert.Equal ($"Absolute({count})", view.Height.ToString ());
-                                 view.Height -= 1;
-                                 count--;
-                                 Assert.Equal ($"Absolute({count})", view.Height.ToString ());
-                             }
-                         };
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     while (count > 0)
-                                     {
-                                         field.NewKeyDownEvent (Key.Enter);
-                                     }
-
-                                     Application.RequestStop ();
-                                 };
-
-        var win = new Window ();
-        win.Add (view);
-        win.Add (field);
-
-        top.Add (win);
-
-        Application.Run (top);
-
-        Assert.Equal (0, count);
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    [TestRespondersDisposed]
-    public void Dim_SyperView_Referencing_SubView_Throws ()
-    {
-        var super = new View { Width = 10, Height = 10, Text = "super" };
-        var view2 = new View { Width = 10, Height = 10, Text = "view2" };
-
-        var view = new View
-        {
-            Width = Dim.Width (view2), // this is not allowed
-            Height = Dim.Height (view2), // this is not allowed
-            Text = "view"
-        };
-
-        view.Add (view2);
-        super.Add (view);
-        super.BeginInit ();
-        super.EndInit ();
-
-        Assert.Throws<InvalidOperationException> (super.LayoutSubviews);
-        super.Dispose ();
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    [TestRespondersDisposed]
-    public void
-        Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
-    {
-        var t = new View { Width = 80, Height = 25, Text = "top" };
-
-        var w = new Window { Width = Dim.Fill (), Height = Dim.Sized (10) };
-        var v = new View { Width = Dim.Width (w) - 2, Height = Dim.Percent (10), Text = "v" };
-
-        w.Add (v);
-        t.Add (w);
-
-        Assert.Equal (LayoutStyle.Absolute, t.LayoutStyle);
-        Assert.Equal (LayoutStyle.Computed, w.LayoutStyle);
-        Assert.Equal (LayoutStyle.Computed, v.LayoutStyle);
-
-        t.LayoutSubviews ();
-        Assert.Equal (2, v.Width = 2);
-        Assert.Equal (2, v.Height = 2);
-
-        // Force v to be LayoutStyle.Absolute;
-        v.Frame = new Rectangle (0, 1, 3, 4);
-        Assert.Equal (LayoutStyle.Absolute, v.LayoutStyle);
-        t.LayoutSubviews ();
-
-        Assert.Equal (2, v.Width = 2);
-        Assert.Equal (2, v.Height = 2);
-        t.Dispose ();
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    [TestRespondersDisposed]
-    public void Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Null ()
-    {
-        var t = new View { Width = 80, Height = 25, Text = "top" };
-
-        var w = new Window
-        {
-            X = 1,
-            Y = 2,
-            Width = 4,
-            Height = 5,
-            Title = "w"
-        };
-        t.Add (w);
-        t.LayoutSubviews ();
-
-        Assert.Equal (3, w.Width = 3);
-        Assert.Equal (4, w.Height = 4);
-        t.Dispose ();
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    [TestRespondersDisposed]
-    public void DimCombine_ObtuseScenario_Does_Not_Throw_If_Two_SubViews_Refs_The_Same_SuperView ()
+    public void Combine_ObtuseScenario_Does_Not_Throw_If_Two_SubViews_Refs_The_Same_SuperView ()
     {
         var t = new View { Width = 80, Height = 25, Text = "top" };
 
@@ -318,7 +147,7 @@ public class DimTests
     /// <summary>This is an intentionally obtuse test. See https://github.com/gui-cs/Terminal.Gui/issues/2461</summary>
     [Fact]
     [TestRespondersDisposed]
-    public void DimCombine_ObtuseScenario_Throw_If_SuperView_Refs_SubView ()
+    public void Combine_ObtuseScenario_Throw_If_SuperView_Refs_SubView ()
     {
         var t = new View { Width = 80, Height = 25 };
 
@@ -366,55 +195,159 @@ public class DimTests
 
     // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
     // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    [TestRespondersDisposed]
+    public void Combine_View_Not_Added_Throws ()
+    {
+        var t = new View { Width = 80, Height = 50 };
+
+        var super = new View { Width = Dim.Width (t) - 2, Height = Dim.Height (t) - 2 };
+        t.Add (super);
+
+        var sub = new View ();
+        super.Add (sub);
+
+        var v1 = new View { Width = Dim.Width (super) - 2, Height = Dim.Height (super) - 2 };
+        var v2 = new View { Width = Dim.Width (v1) - 2, Height = Dim.Height (v1) - 2 };
+        sub.Add (v1);
+
+        // v2 not added to sub; should cause exception on Layout since it's referenced by sub.
+        sub.Width = Dim.Fill () - Dim.Width (v2);
+        sub.Height = Dim.Fill () - Dim.Height (v2);
+
+        t.BeginInit ();
+        t.EndInit ();
+
+        Assert.Throws<InvalidOperationException> (() => t.LayoutSubviews ());
+        t.Dispose ();
+        v2.Dispose ();
+    }
+
+    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
+    // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    [TestRespondersDisposed]
+    public void
+        Dim_Validation_Does_Not_Throw_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
+    {
+        var t = new View { Width = 80, Height = 25, Text = "top" };
+
+        var w = new Window { Width = Dim.Fill (), Height = Dim.Sized (10) };
+        var v = new View { Width = Dim.Width (w) - 2, Height = Dim.Percent (10), Text = "v" };
+
+        w.Add (v);
+        t.Add (w);
+
+        Assert.Equal (LayoutStyle.Absolute, t.LayoutStyle);
+        Assert.Equal (LayoutStyle.Computed, w.LayoutStyle);
+        Assert.Equal (LayoutStyle.Computed, v.LayoutStyle);
+
+        t.LayoutSubviews ();
+        Assert.Equal (2, v.Width = 2);
+        Assert.Equal (2, v.Height = 2);
+
+        // Force v to be LayoutStyle.Absolute;
+        v.Frame = new Rectangle (0, 1, 3, 4);
+        Assert.Equal (LayoutStyle.Absolute, v.LayoutStyle);
+        t.LayoutSubviews ();
+
+        Assert.Equal (2, v.Width = 2);
+        Assert.Equal (2, v.Height = 2);
+        t.Dispose ();
+    }
+
+    [Fact]
+    public void Fill_Equal ()
+    {
+        var margin1 = 0;
+        var margin2 = 0;
+        Dim dim1 = Dim.Fill (margin1);
+        Dim dim2 = Dim.Fill (margin2);
+        Assert.Equal (dim1, dim2);
+    }
+
+    // Tests that Dim.Fill honors the margin parameter correctly
     [Theory]
-    [AutoInitShutdown]
-    [InlineData (0, true)]
-    [InlineData (0, false)]
-    [InlineData (50, true)]
-    [InlineData (50, false)]
-    public void DimPercentPlusOne (int startingDistance, bool testHorizontal)
+    [InlineData (0, true, 25)]
+    [InlineData (0, false, 25)]
+    [InlineData (1, true, 24)]
+    [InlineData (1, false, 24)]
+    [InlineData (2, true, 23)]
+    [InlineData (2, false, 23)]
+    [InlineData (-2, true, 27)]
+    [InlineData (-2, false, 27)]
+    public void Fill_Margin (int margin, bool width, int expected)
     {
-        var container = new View { Width = 100, Height = 100 };
+        var super = new View { Width = 25, Height = 25 };
 
-        var label = new Label
+        var view = new View
         {
-            AutoSize = false,
-            X = testHorizontal ? startingDistance : 0,
-            Y = testHorizontal ? 0 : startingDistance,
-            Width = testHorizontal ? Dim.Percent (50) + 1 : 1,
-            Height = testHorizontal ? 1 : Dim.Percent (50) + 1
+            X = 0,
+            Y = 0,
+            Width = width ? Dim.Fill (margin) : 1,
+            Height = width ? 1 : Dim.Fill (margin)
         };
 
-        container.Add (label);
-        var top = new Toplevel ();
-        top.Add (container);
-        top.BeginInit ();
-        top.EndInit ();
-        top.LayoutSubviews ();
+        super.Add (view);
+        super.BeginInit ();
+        super.EndInit ();
+        super.LayoutSubviews ();
 
-        Assert.Equal (100, container.Frame.Width);
-        Assert.Equal (100, container.Frame.Height);
+        Assert.Equal (25, super.Frame.Width);
+        Assert.Equal (25, super.Frame.Height);
 
-        if (testHorizontal)
+        if (width)
         {
-            Assert.Equal (51, label.Frame.Width);
-            Assert.Equal (1, label.Frame.Height);
+            Assert.Equal (expected, view.Frame.Width);
+            Assert.Equal (1, view.Frame.Height);
         }
         else
         {
-            Assert.Equal (1, label.Frame.Width);
-            Assert.Equal (51, label.Frame.Height);
+            Assert.Equal (1, view.Frame.Width);
+            Assert.Equal (expected, view.Frame.Height);
         }
     }
 
-    [Fact]
-    public void Fill_Equal ()
+    // Tests that Dim.Fill fills the dimension REMAINING from the View's X position to the end of the super view's width
+    [Theory]
+    [InlineData (0, true, 25)]
+    [InlineData (0, false, 25)]
+    [InlineData (1, true, 24)]
+    [InlineData (1, false, 24)]
+    [InlineData (2, true, 23)]
+    [InlineData (2, false, 23)]
+    [InlineData (-2, true, 27)]
+    [InlineData (-2, false, 27)]
+    public void Fill_Offset (int offset, bool width, int expected)
     {
-        var margin1 = 0;
-        var margin2 = 0;
-        Dim dim1 = Dim.Fill (margin1);
-        Dim dim2 = Dim.Fill (margin2);
-        Assert.Equal (dim1, dim2);
+        var super = new View { Width = 25, Height = 25 };
+
+        var view = new View
+        {
+            X = width ? offset : 0,
+            Y = width ? 0 : offset,
+            Width = width ? Dim.Fill () : 1,
+            Height = width ? 1 : Dim.Fill ()
+        };
+
+        super.Add (view);
+        super.BeginInit ();
+        super.EndInit ();
+        super.LayoutSubviews ();
+
+        Assert.Equal (25, super.Frame.Width);
+        Assert.Equal (25, super.Frame.Height);
+
+        if (width)
+        {
+            Assert.Equal (expected, view.Frame.Width);
+            Assert.Equal (1, view.Frame.Height);
+        }
+        else
+        {
+            Assert.Equal (1, view.Frame.Width);
+            Assert.Equal (expected, view.Frame.Height);
+        }
     }
 
     // TODO: Other Dim.Height tests (e.g. Equal?)
@@ -507,9 +440,9 @@ public class DimTests
         Assert.Equal (20, dimCombine.Anchor (100));
 
         var view = new View { Frame = new Rectangle (20, 10, 20, 1) };
-        var dimViewHeight = new Dim.DimView (view, 0);
+        var dimViewHeight = new Dim.DimView (view, Side.Height);
         Assert.Equal (1, dimViewHeight.Anchor (0));
-        var dimViewWidth = new Dim.DimView (view, 1);
+        var dimViewWidth = new Dim.DimView (view, Side.Width);
         Assert.Equal (20, dimViewWidth.Anchor (0));
 
         view.Dispose ();
@@ -616,45 +549,45 @@ public class DimTests
 
         t.Ready += (s, e) =>
                    {
-                                            Assert.Equal ("Absolute(100)", w.Width.ToString ());
-                                            Assert.Equal ("Absolute(100)", w.Height.ToString ());
-                                            Assert.Equal (100, w.Frame.Width);
-                                            Assert.Equal (100, w.Frame.Height);
-
-                                            Assert.Equal ("Factor(0.5,False)", f1.Width.ToString ());
-                                            Assert.Equal ("Absolute(5)", f1.Height.ToString ());
-                                            Assert.Equal (49, f1.Frame.Width); // 50-1=49
-                                            Assert.Equal (5, f1.Frame.Height);
-
-                                            Assert.Equal ("Fill(0)", f2.Width.ToString ());
-                                            Assert.Equal ("Absolute(5)", f2.Height.ToString ());
-                                            Assert.Equal (49, f2.Frame.Width); // 50-1=49
-                                            Assert.Equal (5, f2.Frame.Height);
-
-                    #if DEBUG
+                       Assert.Equal ("Absolute(100)", w.Width.ToString ());
+                       Assert.Equal ("Absolute(100)", w.Height.ToString ());
+                       Assert.Equal (100, w.Frame.Width);
+                       Assert.Equal (100, w.Frame.Height);
+
+                       Assert.Equal ("Factor(0.5,False)", f1.Width.ToString ());
+                       Assert.Equal ("Absolute(5)", f1.Height.ToString ());
+                       Assert.Equal (49, f1.Frame.Width); // 50-1=49
+                       Assert.Equal (5, f1.Frame.Height);
+
+                       Assert.Equal ("Fill(0)", f2.Width.ToString ());
+                       Assert.Equal ("Absolute(5)", f2.Height.ToString ());
+                       Assert.Equal (49, f2.Frame.Width); // 50-1=49
+                       Assert.Equal (5, f2.Frame.Height);
+
+#if DEBUG
                        Assert.Equal ($"Combine(View(Width,FrameView(f1){f1.Border.Frame})-Absolute(2))", v1.Width.ToString ());
-                    #else
+#else
                        Assert.Equal ($"Combine(View(Width,FrameView(){f1.Border.Frame})-Absolute(2))", v1.Width.ToString ());
-                    #endif
+#endif
                        Assert.Equal ("Combine(Fill(0)-Absolute(2))", v1.Height.ToString ());
                        Assert.Equal (47, v1.Frame.Width); // 49-2=47
                        Assert.Equal (89, v1.Frame.Height); // 98-5-2-2=89
 
-                   #if DEBUG
+#if DEBUG
                        Assert.Equal (
                                      $"Combine(View(Width,FrameView(f2){f2.Frame})-Absolute(2))",
                                      v2.Width.ToString ()
-                   #else
+#else
                        Assert.Equal (
                                      $"Combine(View(Width,FrameView(){f2.Frame})-Absolute(2))",
                                      v2.Width.ToString ()
-                   #endif
+#endif
                                     );
-                   #if DEBUG
+#if DEBUG
                        Assert.Equal ("Combine(Fill(0)-Absolute(2))", v2.Height.ToString ());
-                   #else
+#else
                        Assert.Equal ("Combine(Fill(0)-Absolute(2))", v2.Height.ToString ());
-                   #endif
+#endif
                        Assert.Equal (47, v2.Frame.Width); // 49-2=47
                        Assert.Equal (89, v2.Frame.Height); // 98-5-2-2=89
 
@@ -667,11 +600,11 @@ public class DimTests
                        Assert.Equal ("Absolute(50)", v4.Height.ToString ());
                        Assert.Equal (50, v4.Frame.Width);
                        Assert.Equal (50, v4.Frame.Height);
-                   #if DEBUG
+#if DEBUG
                        Assert.Equal ($"Combine(View(Width,Button(v1){v1.Frame})-View(Width,Button(v3){v3.Bounds}))", v5.Width.ToString ());
-                    #else
+#else
                        Assert.Equal ($"Combine(View(Height,Button(){v1.Frame})-View(Height,Button(){v3.Bounds}))", v5.Height.ToString ( ));
-                   #endif
+#endif
                        Assert.Equal (38, v5.Frame.Width);  // 47-9=38
                        Assert.Equal (80, v5.Frame.Height); // 89-9=80
 
@@ -703,22 +636,22 @@ public class DimTests
                        Assert.Equal (5, f2.Frame.Height);
 
                        v1.Text = "Button1";
-                   #if DEBUG
+#if DEBUG
                        Assert.Equal ($"Combine(View(Width,FrameView(f1){f1.Frame})-Absolute(2))", v1.Width.ToString ());
-                   #else
+#else
                        Assert.Equal ($"Combine(View(Width,FrameView(){f1.Frame})-Absolute(2))", v1.Width.ToString ());
-                   #endif
+#endif
                        Assert.Equal ("Combine(Fill(0)-Absolute(2))", v1.Height.ToString ());
                        Assert.Equal (97, v1.Frame.Width);   // 99-2=97
                        Assert.Equal (189, v1.Frame.Height); // 198-2-7=189
 
                        v2.Text = "Button2";
 
-                   #if DEBUG
-                   Assert.Equal ( $"Combine(View(Width,FrameView(f2){f2.Frame})-Absolute(2))", v2.Width.ToString ());
-                   #else
+#if DEBUG
+                       Assert.Equal ($"Combine(View(Width,FrameView(f2){f2.Frame})-Absolute(2))", v2.Width.ToString ());
+#else
                        Assert.Equal ($"Combine(View(Width,FrameView(){f2.Frame})-Absolute(2))", v2.Width.ToString ());
-                   #endif
+#endif
                        Assert.Equal ("Combine(Fill(0)-Absolute(2))", v2.Height.ToString ());
                        Assert.Equal (97, v2.Frame.Width);   // 99-2=97
                        Assert.Equal (189, v2.Frame.Height); // 198-2-7=189
@@ -728,7 +661,7 @@ public class DimTests
                        Assert.Equal ("Factor(0.1,False)", v3.Height.ToString ());
 
                        // 198*10%=19 * Percent is related to the super-view if it isn't null otherwise the view width
-                       Assert.Equal (19, v3.Frame.Width );
+                       Assert.Equal (19, v3.Frame.Width);
                        // 199*10%=19
                        Assert.Equal (19, v3.Frame.Height);
 
@@ -746,13 +679,13 @@ public class DimTests
 
                        v5.Text = "Button5";
 
-                   #if DEBUG
+#if DEBUG
                        Assert.Equal ($"Combine(View(Width,Button(v1){v1.Frame})-View(Width,Button(v3){v3.Frame}))", v5.Width.ToString ());
                        Assert.Equal ($"Combine(View(Height,Button(v1){v1.Frame})-View(Height,Button(v3){v3.Frame}))", v5.Height.ToString ());
-                   #else
+#else
                        Assert.Equal ($"Combine(View(Width,Button(){v1.Frame})-View(Width,Button(){v3.Frame}))", v5.Width.ToString ());
                        Assert.Equal ($"Combine(View(Height,Button(){v1.Frame})-View(Height,Button(){v3.Frame}))", v5.Height.ToString ());
-                   #endif
+#endif
 
                        Assert.Equal (78, v5.Frame.Width);   // 97-9=78
                        Assert.Equal (170, v5.Frame.Height); // 189-19=170
@@ -826,6 +759,89 @@ public class DimTests
         Assert.Throws<ArgumentException> (() => dim = Dim.Percent (1000001));
     }
 
+    [Theory]
+    [InlineData (0, false, true, 12)]
+    [InlineData (0, false, false, 12)]
+    [InlineData (1, false, true, 12)]
+    [InlineData (1, false, false, 12)]
+    [InlineData (2, false, true, 12)]
+    [InlineData (2, false, false, 12)]
+
+    [InlineData (0, true, true, 12)]
+    [InlineData (0, true, false, 12)]
+    [InlineData (1, true, true, 12)]
+    [InlineData (1, true, false, 12)]
+    [InlineData (2, true, true, 11)]
+    [InlineData (2, true, false, 11)]
+    public void Percent_Position (int position, bool usePosition, bool width, int expected)
+    {
+        var super = new View { Width = 25, Height = 25 };
+
+        var view = new View
+        {
+            X = width ? position : 0,
+            Y = width ? 0 : position,
+            Width = width ? Dim.Percent (50, usePosition) : 1,
+            Height = width ? 1 : Dim.Percent (50, usePosition)
+        };
+
+        super.Add (view);
+        super.BeginInit ();
+        super.EndInit ();
+        super.LayoutSubviews ();
+
+        Assert.Equal (25, super.Frame.Width);
+        Assert.Equal (25, super.Frame.Height);
+
+        if (width)
+        {
+            Assert.Equal (expected, view.Frame.Width);
+            Assert.Equal (1, view.Frame.Height);
+        }
+        else
+        {
+            Assert.Equal (1, view.Frame.Width);
+            Assert.Equal (expected, view.Frame.Height);
+        }
+    }
+
+    [Theory]
+    [InlineData (0, true)]
+    [InlineData (0, false)]
+    [InlineData (50, true)]
+    [InlineData (50, false)]
+    public void Percent_PlusOne (int startingDistance, bool testHorizontal)
+    {
+        var super = new View { Width = 100, Height = 100 };
+
+        var view = new View
+        {
+            X = testHorizontal ? startingDistance : 0,
+            Y = testHorizontal ? 0 : startingDistance,
+            Width = testHorizontal ? Dim.Percent (50) + 1 : 1,
+            Height = testHorizontal ? 1 : Dim.Percent (50) + 1
+        };
+
+        super.Add (view);
+        super.BeginInit ();
+        super.EndInit ();
+        super.LayoutSubviews ();
+
+        Assert.Equal (100, super.Frame.Width);
+        Assert.Equal (100, super.Frame.Height);
+
+        if (testHorizontal)
+        {
+            Assert.Equal (51, view.Frame.Width);
+            Assert.Equal (1, view.Frame.Height);
+        }
+        else
+        {
+            Assert.Equal (1, view.Frame.Width);
+            Assert.Equal (51, view.Frame.Height);
+        }
+    }
+
     [Fact]
     public void Percent_SetsValue ()
     {
@@ -844,47 +860,24 @@ public class DimTests
     // TODO: A new test that calls SetRelativeLayout directly is needed.
     [Fact]
     [TestRespondersDisposed]
-    public void PosCombine_View_Not_Added_Throws ()
+    public void Referencing_SuperView_Does_Not_Throw ()
     {
-        var t = new View { Width = 80, Height = 50 };
-
-        var super = new View { Width = Dim.Width (t) - 2, Height = Dim.Height (t) - 2 };
-        t.Add (super);
-
-        var sub = new View ();
-        super.Add (sub);
-
-        var v1 = new View { Width = Dim.Width (super) - 2, Height = Dim.Height (super) - 2 };
-        var v2 = new View { Width = Dim.Width (v1) - 2, Height = Dim.Height (v1) - 2 };
-        sub.Add (v1);
-
-        // v2 not added to sub; should cause exception on Layout since it's referenced by sub.
-        sub.Width = Dim.Fill () - Dim.Width (v2);
-        sub.Height = Dim.Fill () - Dim.Height (v2);
-
-        t.BeginInit ();
-        t.EndInit ();
+        var super = new View { Width = 10, Height = 10, Text = "super" };
 
-        Assert.Throws<InvalidOperationException> (() => t.LayoutSubviews ());
-        t.Dispose ();
-        v2.Dispose ();
-    }
+        var view = new View
+        {
+            Width = Dim.Width (super), // this is allowed
+            Height = Dim.Height (super), // this is allowed
+            Text = "view"
+        };
 
-    [Fact]
-    [TestRespondersDisposed]
-    public void SetsValue ()
-    {
-        var testVal = Rectangle.Empty;
-        var testValView = new View { Frame = testVal };
-        Dim dim = Dim.Width (testValView);
-        Assert.Equal ($"View(Width,View(){testVal})", dim.ToString ());
-        testValView.Dispose ();
+        super.Add (view);
+        super.BeginInit ();
+        super.EndInit ();
 
-        testVal = new Rectangle (1, 2, 3, 4);
-        testValView = new View { Frame = testVal };
-        dim = Dim.Width (testValView);
-        Assert.Equal ($"View(Width,View(){testVal})", dim.ToString ());
-        testValView.Dispose ();
+        Exception exception = Record.Exception (super.LayoutSubviews);
+        Assert.Null (exception);
+        super.Dispose ();
     }
 
     [Fact]
@@ -928,6 +921,119 @@ public class DimTests
         Assert.Equal ($"Absolute({testVal})", dim.ToString ());
     }
 
+    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
+    // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    [AutoInitShutdown]
+    public void Subtract_Operator ()
+    {
+        Toplevel top = new Toplevel ();
+
+        var view = new View { X = 0, Y = 0, Width = 20, Height = 0 };
+        var field = new TextField { X = 0, Y = Pos.Bottom (view), Width = 20 };
+        var count = 20;
+        List<Label> listLabels = new ();
+
+        for (var i = 0; i < count; i++)
+        {
+            field.Text = $"Label {i}";
+            var label = new Label { X = 0, Y = view.Bounds.Height, /*Width = 20,*/ Text = field.Text };
+            view.Add (label);
+            Assert.Equal ($"Label {i}", label.Text);
+            Assert.Equal ($"Absolute({i})", label.Y.ToString ());
+            listLabels.Add (label);
+
+            Assert.Equal ($"Absolute({i})", view.Height.ToString ());
+            view.Height += 1;
+            Assert.Equal ($"Absolute({i + 1})", view.Height.ToString ());
+        }
+
+        field.KeyDown += (s, k) =>
+                         {
+                             if (k.KeyCode == KeyCode.Enter)
+                             {
+                                 Assert.Equal ($"Label {count - 1}", listLabels [count - 1].Text);
+                                 view.Remove (listLabels [count - 1]);
+                                 listLabels [count - 1].Dispose ();
+
+                                 Assert.Equal ($"Absolute({count})", view.Height.ToString ());
+                                 view.Height -= 1;
+                                 count--;
+                                 Assert.Equal ($"Absolute({count})", view.Height.ToString ());
+                             }
+                         };
+
+        Application.Iteration += (s, a) =>
+                                 {
+                                     while (count > 0)
+                                     {
+                                         field.NewKeyDownEvent (new Key (KeyCode.Enter));
+                                     }
+
+                                     Application.RequestStop ();
+                                 };
+
+        var win = new Window ();
+        win.Add (view);
+        win.Add (field);
+
+        top.Add (win);
+
+        Application.Run (top);
+        top.Dispose ();
+
+        Assert.Equal (0, count);
+    }
+
+    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
+    // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    [TestRespondersDisposed]
+    public void SyperView_Referencing_SubView_Throws ()
+    {
+        var super = new View { Width = 10, Height = 10, Text = "super" };
+        var view2 = new View { Width = 10, Height = 10, Text = "view2" };
+
+        var view = new View
+        {
+            Width = Dim.Width (view2), // this is not allowed
+            Height = Dim.Height (view2), // this is not allowed
+            Text = "view"
+        };
+
+        view.Add (view2);
+        super.Add (view);
+        super.BeginInit ();
+        super.EndInit ();
+
+        Assert.Throws<InvalidOperationException> (super.LayoutSubviews);
+        super.Dispose ();
+    }
+
+    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
+    // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    [TestRespondersDisposed]
+    public void Validation_Does_Not_Throw_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Null ()
+    {
+        var t = new View { Width = 80, Height = 25, Text = "top" };
+
+        var w = new Window
+        {
+            X = 1,
+            Y = 2,
+            Width = 4,
+            Height = 5,
+            Title = "w"
+        };
+        t.Add (w);
+        t.LayoutSubviews ();
+
+        Assert.Equal (3, w.Width = 3);
+        Assert.Equal (4, w.Height = 4);
+        t.Dispose ();
+    }
+
     [Fact]
     [TestRespondersDisposed]
     public void Width_Equals ()
@@ -985,4 +1091,21 @@ public class DimTests
         Dim dim = Dim.Width (null);
         Assert.Throws<NullReferenceException> (() => dim.ToString ());
     }
+
+    [Fact]
+    [TestRespondersDisposed]
+    public void Width_SetsValue ()
+    {
+        var testVal = Rectangle.Empty;
+        var testValView = new View { Frame = testVal };
+        Dim dim = Dim.Width (testValView);
+        Assert.Equal ($"View(Width,View(){testVal})", dim.ToString ());
+        testValView.Dispose ();
+
+        testVal = new Rectangle (1, 2, 3, 4);
+        testValView = new View { Frame = testVal };
+        dim = Dim.Width (testValView);
+        Assert.Equal ($"View(Width,View(){testVal})", dim.ToString ());
+        testValView.Dispose ();
+    }
 }

+ 236 - 243
UnitTests/View/Layout/PosTests.cs

@@ -1,13 +1,65 @@
 using Xunit.Abstractions;
-
-// Alias Console to MockConsole so we don't accidentally use Console
+using static Terminal.Gui.Pos;
 
 namespace Terminal.Gui.ViewTests;
 
-public class PosTests
+public class PosTests (ITestOutputHelper output)
 {
-    private readonly ITestOutputHelper _output;
-    public PosTests (ITestOutputHelper output) { _output = output; }
+    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
+    // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    [TestRespondersDisposed]
+    public void Add_Operator ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Toplevel top = new Toplevel();
+
+        var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
+        var field = new TextField { X = 0, Y = 0, Width = 20 };
+        var count = 0;
+
+        field.KeyDown += (s, k) =>
+                         {
+                             if (k.KeyCode == KeyCode.Enter)
+                             {
+                                 field.Text = $"View {count}";
+                                 var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
+                                 view.Add (view2);
+                                 Assert.Equal ($"View {count}", view2.Text);
+                                 Assert.Equal ($"Absolute({count})", view2.Y.ToString ());
+
+                                 Assert.Equal ($"Absolute({count})", field.Y.ToString ());
+                                 field.Y += 1;
+                                 count++;
+                                 Assert.Equal ($"Absolute({count})", field.Y.ToString ());
+                             }
+                         };
+
+        Application.Iteration += (s, a) =>
+                                 {
+                                     while (count < 20)
+                                     {
+                                         field.NewKeyDownEvent (new Key (KeyCode.Enter));
+                                     }
+
+                                     Application.RequestStop ();
+                                 };
+
+        var win = new Window ();
+        win.Add (view);
+        win.Add (field);
+
+        top.Add (win);
+
+        Application.Run (top);
+        top.Dispose ();
+
+        Assert.Equal (20, count);
+
+        // Shutdown must be called to safely clean up Application if Init has been called
+        Application.Shutdown ();
+    }
 
     [Fact]
     public void AnchorEnd_Equal ()
@@ -154,12 +206,10 @@ public class PosTests
 
         var expected = $@"
 ┌────────────────┐
-│012345678 {
-    b
-}│
+│012345678 {b}│
 └────────────────┘
 ";
-        _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+        _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
     }
 
     [Fact]
@@ -193,8 +243,60 @@ public class PosTests
         Assert.Equal ("Center", pos.ToString ());
     }
 
+    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
+    // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    public void Combine_Referencing_Same_View ()
+    {
+        var super = new View { Width = 10, Height = 10, Text = "super" };
+        var view1 = new View { Width = 2, Height = 2, Text = "view1" };
+        var view2 = new View { Width = 2, Height = 2, Text = "view2" };
+        view2.X = Pos.AnchorEnd () - (Pos.Right (view2) - Pos.Left (view2));
+
+        super.Add (view1, view2);
+        super.BeginInit ();
+        super.EndInit ();
+
+        Exception exception = Record.Exception (super.LayoutSubviews);
+        Assert.Null (exception);
+        Assert.Equal (new Rectangle (0, 0, 10, 10), super.Frame);
+        Assert.Equal (new Rectangle (0, 0, 2, 2), view1.Frame);
+        Assert.Equal (new Rectangle (8, 0, 2, 2), view2.Frame);
+
+        super.Dispose ();
+    }
+
+    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
+    // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    [TestRespondersDisposed]
+    public void Combine_WHY_Throws ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Toplevel t = new Toplevel();
+
+        var w = new Window { X = Pos.Left (t) + 2, Y = Pos.Top (t) + 2 };
+        var f = new FrameView ();
+        var v1 = new View { X = Pos.Left (w) + 2, Y = Pos.Top (w) + 2 };
+        var v2 = new View { X = Pos.Left (v1) + 2, Y = Pos.Top (v1) + 2 };
+
+        f.Add (v1); // v2 not added
+        w.Add (f);
+        t.Add (w);
+
+        f.X = Pos.X (v2) - Pos.X (v1);
+        f.Y = Pos.Y (v2) - Pos.Y (v1);
+
+        Assert.Throws<InvalidOperationException> (() => Application.Run (t));
+        t.Dispose ();
+        Application.Shutdown ();
+
+        v2.Dispose ();
+    }
+
     [Fact]
-    public void DoNotReturnPosCombine ()
+    public void DoesNotReturnPosCombine ()
     {
         var v = new View { Id = "V" };
 
@@ -297,13 +399,13 @@ public class PosTests
         Assert.Equal (20, posCombine.Anchor (100));
 
         var view = new View { Frame = new Rectangle (20, 10, 20, 1) };
-        var posViewX = new Pos.PosView (view, 0);
+        var posViewX = new Pos.PosView (view, Pos.Side.X);
         Assert.Equal (20, posViewX.Anchor (0));
-        var posViewY = new Pos.PosView (view, 1);
+        var posViewY = new Pos.PosView (view, Pos.Side.Y);
         Assert.Equal (10, posViewY.Anchor (0));
-        var posRight = new Pos.PosView (view, 2);
+        var posRight = new Pos.PosView (view, Pos.Side.Right);
         Assert.Equal (40, posRight.Anchor (0));
-        var posViewBottom = new Pos.PosView (view, 3);
+        var posViewBottom = new Pos.PosView (view, Side.Bottom);
         Assert.Equal (11, posViewBottom.Anchor (0));
 
         view.Dispose ();
@@ -437,239 +539,13 @@ public class PosTests
         Assert.NotEqual (pos1, pos2);
     }
 
-    [Fact]
-    public void Percent_SetsValue ()
-    {
-        float f = 0;
-        Pos pos = Pos.Percent (f);
-        Assert.Equal ($"Factor({f / 100:0.###})", pos.ToString ());
-        f = 0.5F;
-        pos = Pos.Percent (f);
-        Assert.Equal ($"Factor({f / 100:0.###})", pos.ToString ());
-        f = 100;
-        pos = Pos.Percent (f);
-        Assert.Equal ($"Factor({f / 100:0.###})", pos.ToString ());
-    }
-
-    [Fact]
-    public void Percent_ThrowsOnIvalid ()
-    {
-        Pos pos = Pos.Percent (0);
-        Assert.Throws<ArgumentException> (() => pos = Pos.Percent (-1));
-        Assert.Throws<ArgumentException> (() => pos = Pos.Percent (101));
-        Assert.Throws<ArgumentException> (() => pos = Pos.Percent (100.0001F));
-        Assert.Throws<ArgumentException> (() => pos = Pos.Percent (1000001));
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    [TestRespondersDisposed]
-    public void Pos_Add_Operator ()
-    {
-        Application.Init (new FakeDriver ());
-
-        Toplevel top = new ();
-
-        var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
-        var field = new TextField { X = 0, Y = 0, Width = 20 };
-        var count = 0;
-
-        field.KeyDown += (s, k) =>
-                         {
-                             if (k.KeyCode == KeyCode.Enter)
-                             {
-                                 field.Text = $"View {count}";
-                                 var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
-                                 view.Add (view2);
-                                 Assert.Equal ($"View {count}", view2.Text);
-                                 Assert.Equal ($"Absolute({count})", view2.Y.ToString ());
-
-                                 Assert.Equal ($"Absolute({count})", field.Y.ToString ());
-                                 field.Y += 1;
-                                 count++;
-                                 Assert.Equal ($"Absolute({count})", field.Y.ToString ());
-                             }
-                         };
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     while (count < 20)
-                                     {
-                                         field.NewKeyDownEvent (Key.Enter);
-                                     }
-
-                                     Application.RequestStop ();
-                                 };
-
-        var win = new Window ();
-        win.Add (view);
-        win.Add (field);
-
-        top.Add (win);
-
-        Application.Run (top);
-
-        Assert.Equal (20, count);
-
-        top.Dispose ();
-        // Shutdown must be called to safely clean up Application if Init has been called
-        Application.Shutdown ();
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    [TestRespondersDisposed]
-    public void Pos_Subtract_Operator ()
-    {
-        Application.Init (new FakeDriver ());
-
-        Toplevel top = new ();
-
-        var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
-        var field = new TextField { X = 0, Y = 0, Width = 20 };
-        var count = 20;
-        List<View> listViews = new ();
-
-        for (var i = 0; i < count; i++)
-        {
-            field.Text = $"View {i}";
-            var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
-            view.Add (view2);
-            Assert.Equal ($"View {i}", view2.Text);
-            Assert.Equal ($"Absolute({i})", field.Y.ToString ());
-            listViews.Add (view2);
-
-            Assert.Equal ($"Absolute({i})", field.Y.ToString ());
-            field.Y += 1;
-            Assert.Equal ($"Absolute({i + 1})", field.Y.ToString ());
-        }
-
-        field.KeyDown += (s, k) =>
-                         {
-                             if (k.KeyCode == KeyCode.Enter)
-                             {
-                                 Assert.Equal ($"View {count - 1}", listViews [count - 1].Text);
-                                 view.Remove (listViews [count - 1]);
-                                 listViews [count - 1].Dispose ();
-
-                                 Assert.Equal ($"Absolute({count})", field.Y.ToString ());
-                                 field.Y -= 1;
-                                 count--;
-                                 Assert.Equal ($"Absolute({count})", field.Y.ToString ());
-                             }
-                         };
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     while (count > 0)
-                                     {
-                                         field.NewKeyDownEvent (Key.Enter);
-                                     }
-
-                                     Application.RequestStop ();
-                                 };
-
-        var win = new Window ();
-        win.Add (view);
-        win.Add (field);
-
-        top.Add (win);
-
-        Application.Run (top);
-
-        Assert.Equal (0, count);
-
-        top.Dispose ();
-        // Shutdown must be called to safely clean up Application if Init has been called
-        Application.Shutdown ();
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
-    {
-        Application.Init (new FakeDriver ());
-
-        Toplevel t = new ();
-
-        var w = new Window { X = 1, Y = 2, Width = 3, Height = 5 };
-        t.Add (w);
-
-        t.Ready += (s, e) =>
-                   {
-                       Assert.Equal (2, w.X = 2);
-                       Assert.Equal (2, w.Y = 2);
-                   };
-
-        Application.Iteration += (s, a) => Application.RequestStop ();
-
-        Application.Run (t);
-        t.Dispose ();
-        Application.Shutdown ();
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    public void PosCombine_Referencing_Same_View ()
-    {
-        var super = new View { Width = 10, Height = 10, Text = "super" };
-        var view1 = new View { Width = 2, Height = 2, Text = "view1" };
-        var view2 = new View { Width = 2, Height = 2, Text = "view2" };
-        view2.X = Pos.AnchorEnd () - (Pos.Right (view2) - Pos.Left (view2));
-
-        super.Add (view1, view2);
-        super.BeginInit ();
-        super.EndInit ();
-
-        Exception exception = Record.Exception (super.LayoutSubviews);
-        Assert.Null (exception);
-        Assert.Equal (new Rectangle (0, 0, 10, 10), super.Frame);
-        Assert.Equal (new Rectangle (0, 0, 2, 2), view1.Frame);
-        Assert.Equal (new Rectangle (8, 0, 2, 2), view2.Frame);
-
-        super.Dispose ();
-    }
-
-    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
-    // TODO: A new test that calls SetRelativeLayout directly is needed.
-    [Fact]
-    [TestRespondersDisposed]
-    public void PosCombine_Will_Throws ()
-    {
-        Application.Init (new FakeDriver ());
-
-        Toplevel t = new ();
-
-        var w = new Window { X = Pos.Left (t) + 2, Y = Pos.Top (t) + 2 };
-        var f = new FrameView ();
-        var v1 = new View { X = Pos.Left (w) + 2, Y = Pos.Top (w) + 2 };
-        var v2 = new View { X = Pos.Left (v1) + 2, Y = Pos.Top (v1) + 2 };
-
-        f.Add (v1); // v2 not added
-        w.Add (f);
-        t.Add (w);
-
-        f.X = Pos.X (v2) - Pos.X (v1);
-        f.Y = Pos.Y (v2) - Pos.Y (v1);
-
-        Assert.Throws<InvalidOperationException> (() => Application.Run (t));
-        t.Dispose ();
-        Application.Shutdown ();
-
-        v2.Dispose ();
-    }
-
     // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
     // TODO: A new test that calls SetRelativeLayout directly is needed.
     [Theory]
     [AutoInitShutdown]
     [InlineData (true)]
     [InlineData (false)]
-    public void PosPercentPlusOne (bool testHorizontal)
+    public void Percent_PlusOne (bool testHorizontal)
     {
         var container = new View { Width = 100, Height = 100 };
 
@@ -701,12 +577,36 @@ public class PosTests
         }
     }
 
+    [Fact]
+    public void Percent_SetsValue ()
+    {
+        float f = 0;
+        Pos pos = Pos.Percent (f);
+        Assert.Equal ($"Factor({f / 100:0.###})", pos.ToString ());
+        f = 0.5F;
+        pos = Pos.Percent (f);
+        Assert.Equal ($"Factor({f / 100:0.###})", pos.ToString ());
+        f = 100;
+        pos = Pos.Percent (f);
+        Assert.Equal ($"Factor({f / 100:0.###})", pos.ToString ());
+    }
+
+    [Fact]
+    public void Percent_ThrowsOnIvalid ()
+    {
+        Pos pos = Pos.Percent (0);
+        Assert.Throws<ArgumentException> (() => pos = Pos.Percent (-1));
+        Assert.Throws<ArgumentException> (() => pos = Pos.Percent (101));
+        Assert.Throws<ArgumentException> (() => pos = Pos.Percent (100.0001F));
+        Assert.Throws<ArgumentException> (() => pos = Pos.Percent (1000001));
+    }
+
     // TODO: Test Left, Top, Right bottom Equal
 
     /// <summary>Tests Pos.Left, Pos.X, Pos.Top, Pos.Y, Pos.Right, and Pos.Bottom set operations</summary>
     [Fact]
     [TestRespondersDisposed]
-    public void PosSide_SetsValue ()
+    public void Side_SetsValue ()
     {
         string side; // used in format string
         var testRect = Rectangle.Empty;
@@ -931,7 +831,7 @@ public class PosTests
     }
 
     [Fact]
-    public void SetSide_Null_Throws ()
+    public void Side_SetToNull_Throws ()
     {
         Pos pos = Pos.Left (null);
         Assert.Throws<NullReferenceException> (() => pos.ToString ());
@@ -951,4 +851,97 @@ public class PosTests
         pos = Pos.Right (null);
         Assert.Throws<NullReferenceException> (() => pos.ToString ());
     }
+
+    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
+    // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    [TestRespondersDisposed]
+    public void Subtract_Operator ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Toplevel top = new Toplevel ();
+
+        var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
+        var field = new TextField { X = 0, Y = 0, Width = 20 };
+        var count = 20;
+        List<View> listViews = new ();
+
+        for (var i = 0; i < count; i++)
+        {
+            field.Text = $"View {i}";
+            var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
+            view.Add (view2);
+            Assert.Equal ($"View {i}", view2.Text);
+            Assert.Equal ($"Absolute({i})", field.Y.ToString ());
+            listViews.Add (view2);
+
+            Assert.Equal ($"Absolute({i})", field.Y.ToString ());
+            field.Y += 1;
+            Assert.Equal ($"Absolute({i + 1})", field.Y.ToString ());
+        }
+
+        field.KeyDown += (s, k) =>
+                         {
+                             if (k.KeyCode == KeyCode.Enter)
+                             {
+                                 Assert.Equal ($"View {count - 1}", listViews [count - 1].Text);
+                                 view.Remove (listViews [count - 1]);
+                                 listViews [count - 1].Dispose ();
+
+                                 Assert.Equal ($"Absolute({count})", field.Y.ToString ());
+                                 field.Y -= 1;
+                                 count--;
+                                 Assert.Equal ($"Absolute({count})", field.Y.ToString ());
+                             }
+                         };
+
+        Application.Iteration += (s, a) =>
+                                 {
+                                     while (count > 0)
+                                     {
+                                         field.NewKeyDownEvent (new Key (KeyCode.Enter));
+                                     }
+
+                                     Application.RequestStop ();
+                                 };
+
+        var win = new Window ();
+        win.Add (view);
+        win.Add (field);
+
+        top.Add (win);
+
+        Application.Run (top);
+        top.Dispose ();
+        Assert.Equal (0, count);
+
+        // Shutdown must be called to safely clean up Application if Init has been called
+        Application.Shutdown ();
+    }
+
+    // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
+    // TODO: A new test that calls SetRelativeLayout directly is needed.
+    [Fact]
+    public void Validation_Does_Not_Throw_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Toplevel t = new Toplevel ();
+
+        var w = new Window { X = 1, Y = 2, Width = 3, Height = 5 };
+        t.Add (w);
+
+        t.Ready += (s, e) =>
+                   {
+                       Assert.Equal (2, w.X = 2);
+                       Assert.Equal (2, w.Y = 2);
+                   };
+
+        Application.Iteration += (s, a) => Application.RequestStop ();
+
+        Application.Run (t);
+        t.Dispose ();
+        Application.Shutdown ();
+    }
 }

+ 70 - 70
UnitTests/View/Text/AutoSizeTrueTests.cs

@@ -930,31 +930,31 @@ public class AutoSizeTrueTests
         Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
 
-        Size size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length, 1), size);
+        Size size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length, 1), size);
 
         view.Text = $"{text}\n{text}";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length, 2), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length, 2), size);
 
         view.Text = $"{text}\n{text}\n{text}+";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length + 1, 3), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length + 1, 3), size);
 
         text = string.Empty;
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (Size.Empty, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (0, 0), size);
 
         text = "1";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (_size1x1, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (1, 1), size);
 
         text = "界";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (new (2, 1), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (2, 1), size);
     }
 
     [Fact]
@@ -970,31 +970,31 @@ public class AutoSizeTrueTests
         Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
 
-        Size size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length, 1), size);
+        Size size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length, 1), size);
 
         view.Text = $"{text}\n{text}";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length, 2), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length, 2), size);
 
         view.Text = $"{text}\n{text}\n{text}+";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length + 1, 3), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length + 1, 3), size);
 
         text = string.Empty;
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (Size.Empty, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (0, 0), size);
 
         text = "1";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (_size1x1, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (1, 1), size);
 
         text = "界";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (new (2, 1), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (2, 1), size);
     }
 
     [Fact]
@@ -1010,31 +1010,31 @@ public class AutoSizeTrueTests
         Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
 
-        Size size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length, 1), size);
+        Size size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length, 1), size);
 
         view.Text = $"{text}\n{text}";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length, 2), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length, 2), size);
 
         view.Text = $"{text}\n{text}\n{text}+";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length + 1, 3), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length + 1, 3), size);
 
         text = string.Empty;
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (Size.Empty, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (0, 0), size);
 
         text = "1";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (_size1x1, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (1, 1), size);
 
         text = "界";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (new (2, 1), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (2, 1), size);
     }
 
     [Fact]
@@ -1050,31 +1050,31 @@ public class AutoSizeTrueTests
         Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
 
-        Size size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length, 1), size);
+        Size size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length, 1), size);
 
         view.Text = $"{text}\n{text}";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length, 2), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length, 2), size);
 
         view.Text = $"{text}\n{text}\n{text}+";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (text.Length + 1, 3), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (text.Length + 1, 3), size);
 
         text = string.Empty;
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (Size.Empty, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (0, 0), size);
 
         text = "1";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (_size1x1, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (1, 1), size);
 
         text = "界";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (new (2, 1), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (2, 1), size);
     }
 
     [Fact]
@@ -1090,31 +1090,31 @@ public class AutoSizeTrueTests
         Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
 
-        Size size = view.GetAutoSize ();
-        Assert.Equal (new (1, text.Length), size);
+        Size size = view.GetTextAutoSize();
+        Assert.Equal (new Size (1, text.Length), size);
 
         view.Text = $"{text}\n{text}";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (2, text.Length), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (2, text.Length), size);
 
         view.Text = $"{text}\n{text}\n{text}+";
-        size = view.GetAutoSize ();
-        Assert.Equal (new (3, text.Length + 1), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (3, text.Length + 1), size);
 
         text = string.Empty;
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (Size.Empty, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (0, 0), size);
 
         text = "1";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (_size1x1, size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (1, 1), size);
 
         text = "界";
         view.Text = text;
-        size = view.GetAutoSize ();
-        Assert.Equal (new (2, 1), size);
+        size = view.GetTextAutoSize();
+        Assert.Equal (new Size (2, 1), size);
     }
 
     [Fact]
@@ -2134,7 +2134,7 @@ Y
     [AutoInitShutdown]
     public void AutoSize_True_Width_Height_Stay_True_If_TextFormatter_Size_Fit ()
     {
-        var text = "Fi_nish 終";
+        var text = "Finish 終";
 
         var horizontalView = new View
         {
@@ -2159,18 +2159,17 @@ Y
         Assert.True (horizontalView.AutoSize);
         Assert.True (verticalView.AutoSize);
         Assert.Equal (new (text.GetColumns (), 1), horizontalView.TextFormatter.Size);
-        Assert.Equal (new (2, 9), verticalView.TextFormatter.Size);
-        Assert.Equal (new (0, 0, 10, 1), horizontalView.Frame);
-        Assert.Equal (new (0, 3, 10, 9), verticalView.Frame);
+        Assert.Equal (new (2, 8), verticalView.TextFormatter.Size);
+        //Assert.Equal (new (0, 0, 10, 1), horizontalView.Frame);
+        //Assert.Equal (new (0, 3, 10, 9), verticalView.Frame);
 
         var expected = @"
 ┌────────────────────┐
-│Fi_nish 終          │
+│Finish 終 
 │                    │
 │                    │
 │F                   │
 │i                   │
-│_                   │
 │n                   │
 │i                   │
 │s                   │
@@ -2185,27 +2184,27 @@ Y
 │                    │
 │                    │
 │                    │
+│                    │
 └────────────────────┘
 ";
 
         Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
 
-        verticalView.Text = "最初_の行二行目";
+        verticalView.Text = "最初の行二行目";
         Application.Top.Draw ();
         Assert.True (horizontalView.AutoSize);
         Assert.True (verticalView.AutoSize);
 
         // height was initialized with 8 and can only grow or keep initial value
-        Assert.Equal (new Rectangle (0, 3, 10, 9), verticalView.Frame);
+        Assert.Equal (new Rectangle (0, 3, 9, 8), verticalView.Frame);
 
         expected = @"
 ┌────────────────────┐
-│Fi_nish 終          │
+│Finish 終 
 │                    │
 │                    │
 │最                  │
 │初                  │
-│_                   │
 │の                  │
 │行                  │
 │二                  │
@@ -2220,6 +2219,7 @@ Y
 │                    │
 │                    │
 │                    │
+│                    │
 └────────────────────┘
 ";
 

Неке датотеке нису приказане због велике количине промена