Bläddra i källkod

Merge pull request #3615 from tig/v2_3499-Finish-DimAuto

Fixes #3499. Finishes `Dim.Auto` implementation
Tig 1 år sedan
förälder
incheckning
0583d4526d
76 ändrade filer med 3420 tillägg och 3364 borttagningar
  1. 6 6
      .github/workflows/api-docs.yml
  2. 1 1
      .github/workflows/publish.yml
  3. 5 6
      GitVersion.yml
  4. 10 2
      Terminal.Gui/Application/Application.cs
  5. 2 1
      Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
  6. 2 2
      Terminal.Gui/Drawing/Glyphs.cs
  7. 4 2
      Terminal.Gui/Drawing/Thickness.cs
  8. 430 342
      Terminal.Gui/Text/TextFormatter.cs
  9. 1 1
      Terminal.Gui/View/Adornment/Adornment.cs
  10. 4 3
      Terminal.Gui/View/Adornment/Border.cs
  11. 22 7
      Terminal.Gui/View/Adornment/Margin.cs
  12. 13 2
      Terminal.Gui/View/Adornment/ShadowView.cs
  13. 27 6
      Terminal.Gui/View/Layout/Dim.cs
  14. 332 195
      Terminal.Gui/View/Layout/DimAuto.cs
  15. 4 0
      Terminal.Gui/View/Layout/DimAutoStyle.cs
  16. 3 22
      Terminal.Gui/View/Layout/DimCombine.cs
  17. 2 8
      Terminal.Gui/View/Layout/Pos.cs
  18. 2 1
      Terminal.Gui/View/Layout/PosCenter.cs
  19. 366 312
      Terminal.Gui/View/Layout/ViewLayout.cs
  20. 1 1
      Terminal.Gui/View/View.cs
  21. 73 66
      Terminal.Gui/View/ViewText.cs
  22. 1 3
      Terminal.Gui/Views/Bar.cs
  23. 1 0
      Terminal.Gui/Views/Button.cs
  24. 1 10
      Terminal.Gui/Views/CheckBox.cs
  25. 23 0
      Terminal.Gui/Views/CheckState.cs
  26. 0 3
      Terminal.Gui/Views/DatePicker.cs
  27. 4 4
      Terminal.Gui/Views/Dialog.cs
  28. 3 0
      Terminal.Gui/Views/FileDialog.cs
  29. 1 1
      Terminal.Gui/Views/Menu/ContextMenu.cs
  30. 2 1
      Terminal.Gui/Views/Menu/Menu.cs
  31. 1 1
      Terminal.Gui/Views/Menu/MenuBar.cs
  32. 24 35
      Terminal.Gui/Views/MessageBox.cs
  33. 1 1
      Terminal.Gui/Views/ProgressBar.cs
  34. 0 1
      Terminal.Gui/Views/ScrollView.cs
  35. 3 3
      Terminal.Gui/Views/Shortcut.cs
  36. 3 3
      UICatalog/KeyBindingsDialog.cs
  37. 0 4
      UICatalog/Scenarios/AdornmentsEditor.cs
  38. 0 6
      UICatalog/Scenarios/Bars.cs
  39. 1 2
      UICatalog/Scenarios/BorderEditor.cs
  40. 53 2
      UICatalog/Scenarios/ComputedLayout.cs
  41. 15 6
      UICatalog/Scenarios/Dialogs.cs
  42. 36 22
      UICatalog/Scenarios/DimAutoDemo.cs
  43. 2 5
      UICatalog/Scenarios/ExpanderButton.cs
  44. 1 1
      UICatalog/Scenarios/ListColumns.cs
  45. 1 3
      UICatalog/Scenarios/MarginEditor.cs
  46. 8 4
      UICatalog/Scenarios/MessageBoxes.cs
  47. 9 5
      UICatalog/Scenarios/TableEditor.cs
  48. 1 35
      UICatalog/Scenarios/TextAlignmentAndDirection.cs
  49. 2 5
      UICatalog/Scenarios/ViewExperiments.cs
  50. 55 39
      UICatalog/UICatalog.cs
  51. 104 513
      UnitTests/Dialogs/MessageBoxTests.cs
  52. 7 0
      UnitTests/TestHelpers.cs
  53. 292 636
      UnitTests/Text/TextFormatterTests.cs
  54. 6 6
      UnitTests/View/Adornment/ShadowStyletests.cs
  55. 5 6
      UnitTests/View/DrawTests.cs
  56. 226 0
      UnitTests/View/Layout/Dim.AutoTests.DimTypes.cs
  57. 195 0
      UnitTests/View/Layout/Dim.AutoTests.MinMax.cs
  58. 616 0
      UnitTests/View/Layout/Dim.AutoTests.PosTypes.cs
  59. 234 650
      UnitTests/View/Layout/Dim.AutoTests.cs
  60. 2 2
      UnitTests/View/Layout/Dim.PercentTests.cs
  61. 1 1
      UnitTests/View/Layout/Pos.AnchorEndTests.cs
  62. 23 4
      UnitTests/View/Layout/Pos.CenterTests.cs
  63. 16 2
      UnitTests/View/Layout/Pos.PercentTests.cs
  64. 0 2
      UnitTests/View/Layout/Pos.Tests.cs
  65. 7 13
      UnitTests/View/Layout/ViewportTests.cs
  66. 49 146
      UnitTests/View/TextTests.cs
  67. 1 36
      UnitTests/View/TitleTests.cs
  68. 9 7
      UnitTests/View/ViewTests.cs
  69. 7 9
      UnitTests/Views/ButtonTests.cs
  70. 7 7
      UnitTests/Views/CheckBoxTests.cs
  71. 11 113
      UnitTests/Views/LabelTests.cs
  72. 11 9
      UnitTests/Views/ScrollViewTests.cs
  73. 3 2
      UnitTests/Views/ShortcutTests.cs
  74. 1 1
      UnitTests/Views/TextViewTests.cs
  75. 2 2
      UnitTests/Views/WindowTests.cs
  76. 23 6
      docfx/docs/dimauto.md

+ 6 - 6
.github/workflows/api-docs.yml

@@ -2,7 +2,7 @@ name: Build and publish API docs
 
 
 on:
 on:
   push:
   push:
-    branches: [main, v2_develop]
+    branches: [v1_release, v2_develop]
 
 
 permissions:
 permissions:
   id-token: write 
   id-token: write 
@@ -17,11 +17,11 @@ jobs:
     runs-on: windows-latest
     runs-on: windows-latest
     steps:
     steps:
     - name: Checkout
     - name: Checkout
-      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
+      if: github.ref_name == 'v1_release' ||  github.ref_name == 'v1_develop'
       uses: actions/checkout@v4
       uses: actions/checkout@v4
 
 
     - name: DocFX Build
     - name: DocFX Build
-      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
+      if: github.ref_name == 'v1_release' ||  github.ref_name == 'v1_develop'
       working-directory: docfx
       working-directory: docfx
       run: |
       run: |
         dotnet tool install -g docfx
         dotnet tool install -g docfx
@@ -31,17 +31,17 @@ jobs:
       continue-on-error: false
       continue-on-error: false
 
 
     - name: Setup Pages
     - name: Setup Pages
-      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
+      if: github.ref_name == 'v1_release' ||  github.ref_name == 'v1_develop'
       uses: actions/configure-pages@v5
       uses: actions/configure-pages@v5
       
       
     - name: Upload artifact
     - name: Upload artifact
-      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
+      if: github.ref_name == 'v1_release' ||  github.ref_name == 'v1_develop'
       uses: actions/upload-pages-artifact@v3
       uses: actions/upload-pages-artifact@v3
       with:
       with:
         path: docfx/_site
         path: docfx/_site
        
        
     - name: Deploy to GitHub Pages
     - name: Deploy to GitHub Pages
-      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
+      if: github.ref_name == 'v1_release' ||  github.ref_name == 'v1_develop'
       id: deployment
       id: deployment
       uses: actions/deploy-pages@v4
       uses: actions/deploy-pages@v4
       with:
       with:

+ 1 - 1
.github/workflows/publish.yml

@@ -2,7 +2,7 @@ name: Publish Terminal.Gui
 
 
 on:
 on:
   push:
   push:
-    branches: [ main, develop, v2_release, v2_develop ]
+    branches: [ v1_release, v1_develop, v2_release, v2_develop ]
     tags:
     tags:
       - v*
       - v*
     paths-ignore:
     paths-ignore:

+ 5 - 6
GitVersion.yml

@@ -2,12 +2,12 @@ mode: ContinuousDeployment
 tag-prefix: '[vV]'
 tag-prefix: '[vV]'
 continuous-delivery-fallback-tag: dev
 continuous-delivery-fallback-tag: dev
 branches:
 branches:
-  develop:
+  v1_develop:
     mode: ContinuousDeployment
     mode: ContinuousDeployment
     tag: dev
     tag: dev
-    regex: develop
+    regex: v1_develop
     source-branches:
     source-branches:
-    - main
+    - v1_release
     pre-release-weight: 100
     pre-release-weight: 100
 
 
   v2_develop:
   v2_develop:
@@ -32,9 +32,8 @@ branches:
     tag-number-pattern: '[/-](?<number>\d+)'
     tag-number-pattern: '[/-](?<number>\d+)'
     regex: ^(pull|pull\-requests|pr)[/-]
     regex: ^(pull|pull\-requests|pr)[/-]
     source-branches:
     source-branches:
-    - develop
-    - main
-    - release
+    - v1_develop
+    - v1_release
     - v2_develop
     - v2_develop
     - v2_release
     - v2_release
     - feature
     - feature

+ 10 - 2
Terminal.Gui/Application/Application.cs

@@ -68,6 +68,14 @@ public static partial class Application
                       .ToList ();
                       .ToList ();
     }
     }
 
 
+    /// <summary>
+    ///     Gets the size of the screen. This is the size of the screen as reported by the <see cref="ConsoleDriver"/>.
+    /// </summary>
+    /// <remarks>
+    ///     If the <see cref="ConsoleDriver"/> has not been initialized, this will return a default size of 2048x2048; useful for unit tests.
+    /// </remarks>
+    public static Rectangle Screen => Driver?.Screen ?? new (0, 0, 2048, 2048);
+
     // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`.
     // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`.
     // This variable is set in `End` in this case so that `Begin` correctly sets `Top`.
     // This variable is set in `End` in this case so that `Begin` correctly sets `Top`.
     private static Toplevel _cachedRunStateToplevel;
     private static Toplevel _cachedRunStateToplevel;
@@ -538,7 +546,7 @@ public static partial class Application
             MoveCurrent (Current);
             MoveCurrent (Current);
         }
         }
 
 
-        toplevel.SetRelativeLayout (Driver.Screen.Size);
+        toplevel.SetRelativeLayout (Screen.Size);
 
 
         toplevel.LayoutSubviews ();
         toplevel.LayoutSubviews ();
         toplevel.PositionToplevels ();
         toplevel.PositionToplevels ();
@@ -607,7 +615,7 @@ public static partial class Application
 
 
         // If the view is not visible within it's superview, don't position the cursor
         // If the view is not visible within it's superview, don't position the cursor
         Rectangle mostFocusedViewport = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = Point.Empty });
         Rectangle mostFocusedViewport = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = Point.Empty });
-        Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Driver.Screen;
+        Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Application.Screen;
 
 
         if (!superViewViewport.IntersectsWith (mostFocusedViewport))
         if (!superViewViewport.IntersectsWith (mostFocusedViewport))
         {
         {

+ 2 - 1
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -20,7 +20,7 @@ public abstract class ConsoleDriver
 
 
     // QUESTION: When non-full screen apps are supported, will this represent the app size, or will that be in Application?
     // QUESTION: When non-full screen apps are supported, will this represent the app size, or will that be in Application?
     /// <summary>Gets the location and size of the terminal screen.</summary>
     /// <summary>Gets the location and size of the terminal screen.</summary>
-    public Rectangle Screen => new (0, 0, Cols, Rows);
+    internal Rectangle Screen => new (0, 0, Cols, Rows);
 
 
     private Rectangle _clip;
     private Rectangle _clip;
 
 
@@ -426,6 +426,7 @@ public abstract class ConsoleDriver
     /// <param name="row">Row to move to.</param>
     /// <param name="row">Row to move to.</param>
     public virtual void Move (int col, int row)
     public virtual void Move (int col, int row)
     {
     {
+        //Debug.Assert (col >= 0 && row >= 0 && col < Contents.GetLength(1) && row < Contents.GetLength(0));
         Col = col;
         Col = col;
         Row = row;
         Row = row;
     }
     }

+ 2 - 2
Terminal.Gui/Drawing/Glyphs.cs

@@ -442,13 +442,13 @@ public class GlyphDefinitions
 
 
 
 
     /// <summary>Shadow - Vertical Start - Left Half Block - ▌ U+0258c</summary>
     /// <summary>Shadow - Vertical Start - Left Half Block - ▌ U+0258c</summary>
-    public Rune ShadowVerticalStart { get; set; } =  (Rune)''; // Half: '\u2596'  ▖;
+    public Rune ShadowVerticalStart { get; set; } =  (Rune)''; // Half: '\u2596'  ▖;
 
 
     /// <summary>Shadow - Vertical - Left Half Block - ▌ U+0258c</summary>
     /// <summary>Shadow - Vertical - Left Half Block - ▌ U+0258c</summary>
     public Rune ShadowVertical { get; set; } = (Rune)'▌';
     public Rune ShadowVertical { get; set; } = (Rune)'▌';
 
 
     /// <summary>Shadow - Horizontal Start - Upper Half Block - ▀ U+02580</summary>
     /// <summary>Shadow - Horizontal Start - Upper Half Block - ▀ U+02580</summary>
-    public Rune ShadowHorizontalStart { get; set; } = (Rune)''; // Half: ▝ U+0259d;
+    public Rune ShadowHorizontalStart { get; set; } = (Rune)''; // Half: ▝ U+0259d;
 
 
     /// <summary>Shadow - Horizontal - Upper Half Block - ▀ U+02580</summary>
     /// <summary>Shadow - Horizontal - Upper Half Block - ▀ U+02580</summary>
     public Rune ShadowHorizontal { get; set; } = (Rune)'▀';
     public Rune ShadowHorizontal { get; set; } = (Rune)'▀';

+ 4 - 2
Terminal.Gui/Drawing/Thickness.cs

@@ -190,12 +190,14 @@ public record struct Thickness
         if (View.Diagnostics.HasFlag (ViewDiagnosticFlags.Padding))
         if (View.Diagnostics.HasFlag (ViewDiagnosticFlags.Padding))
         {
         {
             // Draw the diagnostics label on the bottom
             // Draw the diagnostics label on the bottom
+            string text = label is null ? string.Empty : $"{label} {this}";
             var tf = new TextFormatter
             var tf = new TextFormatter
             {
             {
-                Text = label is null ? string.Empty : $"{label} {this}",
+                Text = text,
                 Alignment = Alignment.Center,
                 Alignment = Alignment.Center,
                 VerticalAlignment = Alignment.End,
                 VerticalAlignment = Alignment.End,
-                AutoSize = true
+                ConstrainToWidth = text.GetColumns (),
+                ConstrainToHeight = 1
             };
             };
             tf.Draw (rect, Application.Driver.CurrentAttribute, Application.Driver.CurrentAttribute, rect);
             tf.Draw (rect, Application.Driver.CurrentAttribute, Application.Driver.CurrentAttribute, rect);
         }
         }

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 430 - 342
Terminal.Gui/Text/TextFormatter.cs


+ 1 - 1
Terminal.Gui/View/Adornment/Adornment.cs

@@ -165,7 +165,7 @@ public class Adornment : View
         {
         {
             if (TextFormatter is { })
             if (TextFormatter is { })
             {
             {
-                TextFormatter.Size = Frame.Size;
+                TextFormatter.ConstrainToSize = Frame.Size;
                 TextFormatter.NeedsFormat = true;
                 TextFormatter.NeedsFormat = true;
             }
             }
         }
         }

+ 4 - 3
Terminal.Gui/View/Adornment/Border.cs

@@ -149,8 +149,9 @@ public class Border : Adornment
         }
         }
     }
     }
 
 
-    private Rectangle GetBorderRectangle (Rectangle screenRect)
+    internal Rectangle GetBorderRectangle ()
     {
     {
+        Rectangle screenRect = ViewportToScreen (Viewport);
         return new (
         return new (
                     screenRect.X + Math.Max (0, Thickness.Left - 1),
                     screenRect.X + Math.Max (0, Thickness.Left - 1),
                     screenRect.Y + Math.Max (0, Thickness.Top - 1),
                     screenRect.Y + Math.Max (0, Thickness.Top - 1),
@@ -407,7 +408,7 @@ public class Border : Adornment
         // ...thickness extends outward (border/title is always as far in as possible)
         // ...thickness extends outward (border/title is always as far in as possible)
         // PERF: How about a call to Rectangle.Offset?
         // PERF: How about a call to Rectangle.Offset?
 
 
-        Rectangle borderBounds = GetBorderRectangle (screenBounds);
+        Rectangle borderBounds = GetBorderRectangle ();
         int topTitleLineY = borderBounds.Y;
         int topTitleLineY = borderBounds.Y;
         int titleY = borderBounds.Y;
         int titleY = borderBounds.Y;
         var titleBarsLength = 0; // the little vertical thingies
         var titleBarsLength = 0; // the little vertical thingies
@@ -420,7 +421,7 @@ public class Border : Adornment
                                                )
                                                )
                                      );
                                      );
 
 
-        Parent.TitleTextFormatter.Size = new (maxTitleWidth, 1);
+        Parent.TitleTextFormatter.ConstrainToSize = new (maxTitleWidth, 1);
 
 
         int sideLineLength = borderBounds.Height;
         int sideLineLength = borderBounds.Height;
         bool canDrawBorder = borderBounds is { Width: > 0, Height: > 0 };
         bool canDrawBorder = borderBounds is { Width: > 0, Height: > 0 };

+ 22 - 7
Terminal.Gui/View/Adornment/Margin.cs

@@ -44,7 +44,7 @@ public class Margin : Adornment
         ShadowStyle = base.ShadowStyle;
         ShadowStyle = base.ShadowStyle;
 
 
         Add (
         Add (
-             _rightShadow = new()
+             _rightShadow = new ()
              {
              {
                  X = Pos.AnchorEnd (1),
                  X = Pos.AnchorEnd (1),
                  Y = 0,
                  Y = 0,
@@ -53,7 +53,7 @@ public class Margin : Adornment
                  ShadowStyle = ShadowStyle,
                  ShadowStyle = ShadowStyle,
                  Orientation = Orientation.Vertical
                  Orientation = Orientation.Vertical
              },
              },
-             _bottomShadow = new()
+             _bottomShadow = new ()
              {
              {
                  X = 0,
                  X = 0,
                  Y = Pos.AnchorEnd (1),
                  Y = Pos.AnchorEnd (1),
@@ -220,12 +220,27 @@ public class Margin : Adornment
     private void Margin_LayoutStarted (object? sender, LayoutEventArgs e)
     private void Margin_LayoutStarted (object? sender, LayoutEventArgs e)
     {
     {
         // Adjust the shadow such that it is drawn aligned with the Border
         // Adjust the shadow such that it is drawn aligned with the Border
-        if (ShadowStyle != ShadowStyle.None && _rightShadow is { } && _bottomShadow is { })
+        if (_rightShadow is { } && _bottomShadow is { })
         {
         {
-            _rightShadow.Y = Parent.Border.Thickness.Top > 0
-                                 ? Parent.Border.Thickness.Top - (Parent.Border.Thickness.Top > 2 && Parent.Border.Settings.FastHasFlags (BorderSettings.Title) ? 1 : 0)
-                                 : 1;
-            _bottomShadow.X = Parent.Border.Thickness.Left > 0 ? Parent.Border.Thickness.Left : 1;
+            switch (ShadowStyle)
+            {
+                case ShadowStyle.Transparent:
+                    // BUGBUG: This doesn't work right for all Border.Top sizes - Need an API on Border that gives top-right location of line corner.
+                    _rightShadow.Y = Parent.Border.Thickness.Top > 0 ? ScreenToViewport (Parent.Border.GetBorderRectangle ().Location).Y + 1 : 0;
+                    break;
+
+                case ShadowStyle.Opaque:
+                    // BUGBUG: This doesn't work right for all Border.Top sizes - Need an API on Border that gives top-right location of line corner.
+                    _rightShadow.Y = Parent.Border.Thickness.Top > 0 ? ScreenToViewport (Parent.Border.GetBorderRectangle ().Location).Y + 1 : 0;
+                    _bottomShadow.X = Parent.Border.Thickness.Left > 0 ? ScreenToViewport (Parent.Border.GetBorderRectangle ().Location).X + 1 : 0;
+                    break;
+
+                case ShadowStyle.None:
+                default:
+                    _rightShadow.Y = 0;
+                    _bottomShadow.X = 0;
+                    break;
+            }
         }
         }
     }
     }
 }
 }

+ 13 - 2
Terminal.Gui/View/Adornment/ShadowView.cs

@@ -1,4 +1,7 @@
 #nullable enable
 #nullable enable
+using Microsoft.VisualBasic;
+using System.Diagnostics;
+
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
 /// <summary>
 /// <summary>
@@ -109,7 +112,11 @@ internal class ShadowView : View
         for (int i = screen.X; i < screen.X + screen.Width - 1; i++)
         for (int i = screen.X; i < screen.X + screen.Width - 1; i++)
         {
         {
             Driver.Move (i, screen.Y);
             Driver.Move (i, screen.Y);
-            Driver.AddRune (Driver.Contents [screen.Y, i].Rune);
+
+            if (i < Driver.Contents.GetLength (1) && screen.Y < Driver.Contents.GetLength (0))
+            {
+                Driver.AddRune (Driver.Contents [screen.Y, i].Rune);
+            }
         }
         }
     }
     }
 
 
@@ -133,7 +140,11 @@ internal class ShadowView : View
         for (int i = screen.Y; i < screen.Y + viewport.Height; i++)
         for (int i = screen.Y; i < screen.Y + viewport.Height; i++)
         {
         {
             Driver.Move (screen.X, i);
             Driver.Move (screen.X, i);
-            Driver.AddRune (Driver.Contents [i, screen.X].Rune);
+
+            if (screen.X < Driver.Contents.GetLength (1) && i < Driver.Contents.GetLength (0))
+            {
+                Driver.AddRune (Driver.Contents [i, screen.X].Rune);
+            }
         }
         }
     }
     }
 }
 }

+ 27 - 6
Terminal.Gui/View/Layout/Dim.cs

@@ -160,10 +160,7 @@ public abstract class Dim
     /// </example>
     /// </example>
     public static Dim? Percent (int percent, DimPercentMode mode = DimPercentMode.ContentSize)
     public static Dim? Percent (int percent, DimPercentMode mode = DimPercentMode.ContentSize)
     {
     {
-        if (percent is < 0 /*or > 100*/)
-        {
-            throw new ArgumentException ("Percent value must be positive.");
-        }
+        ArgumentOutOfRangeException.ThrowIfNegative (percent, nameof (percent));
 
 
         return new DimPercent (percent, mode);
         return new DimPercent (percent, mode);
     }
     }
@@ -175,6 +172,30 @@ public abstract class Dim
 
 
     #endregion static Dim creation methods
     #endregion static Dim creation methods
 
 
+    /// <summary>
+    ///     Indicates whether the specified type is in the hierarchy of this Dim object.
+    /// </summary>
+    /// <param name="type"></param>
+    /// <param name="dim"></param>
+    /// <returns></returns>
+    public bool Has (Type type, out Dim dim)
+    {
+        dim = this;
+        if (type == GetType ())
+        {
+            return true;
+        }
+
+        // If we are a PosCombine, we have to check the left and right
+        // to see if they are of the type we are looking for.
+        if (this is DimCombine { } combine && (combine.Left.Has (type, out dim) || combine.Right.Has (type, out dim)))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
     #region virtual methods
     #region virtual methods
 
 
     /// <summary>
     /// <summary>
@@ -224,7 +245,7 @@ public abstract class Dim
     /// <param name="left">The first <see cref="Dim"/> to add.</param>
     /// <param name="left">The first <see cref="Dim"/> to add.</param>
     /// <param name="right">The second <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>
     /// <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)
+    public static Dim operator + (Dim left, Dim right)
     {
     {
         if (left is DimAbsolute && right is DimAbsolute)
         if (left is DimAbsolute && right is DimAbsolute)
         {
         {
@@ -249,7 +270,7 @@ public abstract class Dim
     /// <param name="left">The <see cref="Dim"/> to subtract from (the minuend).</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>
     /// <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>
     /// <returns>The <see cref="Dim"/> that is the <c>left</c> minus <c>right</c>.</returns>
-    public static Dim operator - (Dim? left, Dim? right)
+    public static Dim operator - (Dim left, Dim right)
     {
     {
         if (left is DimAbsolute && right is DimAbsolute)
         if (left is DimAbsolute && right is DimAbsolute)
         {
         {

+ 332 - 195
Terminal.Gui/View/Layout/DimAuto.cs

@@ -1,5 +1,5 @@
 #nullable enable
 #nullable enable
-using System.Drawing;
+using System.Diagnostics;
 
 
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
@@ -15,13 +15,32 @@ namespace Terminal.Gui;
 ///         methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
 ///         methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
 ///     </para>
 ///     </para>
 /// </remarks>
 /// </remarks>
-public class DimAuto () : Dim
+public class DimAuto : Dim
 {
 {
     private readonly Dim? _maximumContentDim;
     private readonly Dim? _maximumContentDim;
 
 
+    private readonly Dim? _minimumContentDim;
+
+    private readonly DimAutoStyle _style;
+
+    /// <inheritdoc/>
+    public override bool Equals (object? other)
+    {
+        if (other is not DimAuto auto)
+        {
+            return false;
+        }
+
+        return auto.MinimumContentDim == MinimumContentDim && auto.MaximumContentDim == MaximumContentDim && auto.Style == Style;
+    }
+
+    /// <inheritdoc/>
+    public override int GetHashCode () { return HashCode.Combine (MinimumContentDim, MaximumContentDim, Style); }
+
     /// <summary>
     /// <summary>
     ///     Gets the maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED.
     ///     Gets the maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED.
     /// </summary>
     /// </summary>
+
     // ReSharper disable once ConvertToAutoProperty
     // ReSharper disable once ConvertToAutoProperty
     public required Dim? MaximumContentDim
     public required Dim? MaximumContentDim
     {
     {
@@ -29,11 +48,10 @@ public class DimAuto () : Dim
         init => _maximumContentDim = value;
         init => _maximumContentDim = value;
     }
     }
 
 
-    private readonly Dim? _minimumContentDim;
-
     /// <summary>
     /// <summary>
     ///     Gets the minimum dimension the View's ContentSize will be constrained to.
     ///     Gets the minimum dimension the View's ContentSize will be constrained to.
     /// </summary>
     /// </summary>
+
     // ReSharper disable once ConvertToAutoProperty
     // ReSharper disable once ConvertToAutoProperty
     public required Dim? MinimumContentDim
     public required Dim? MinimumContentDim
     {
     {
@@ -41,11 +59,10 @@ public class DimAuto () : Dim
         init => _minimumContentDim = value;
         init => _minimumContentDim = value;
     }
     }
 
 
-    private readonly DimAutoStyle _style;
-
     /// <summary>
     /// <summary>
     ///     Gets the style of the DimAuto.
     ///     Gets the style of the DimAuto.
     /// </summary>
     /// </summary>
+
     // ReSharper disable once ConvertToAutoProperty
     // ReSharper disable once ConvertToAutoProperty
     public required DimAutoStyle Style
     public required DimAutoStyle Style
     {
     {
@@ -59,242 +76,386 @@ public class DimAuto () : Dim
     internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
     internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
     {
     {
         var textSize = 0;
         var textSize = 0;
-        var subviewsSize = 0;
+        var maxCalculatedSize = 0;
 
 
         int autoMin = MinimumContentDim?.GetAnchor (superviewContentSize) ?? 0;
         int autoMin = MinimumContentDim?.GetAnchor (superviewContentSize) ?? 0;
-        int autoMax = MaximumContentDim?.GetAnchor (superviewContentSize) ?? int.MaxValue;
+        int screenX4 = dimension == Dimension.Width ? Application.Screen.Width * 4 : Application.Screen.Height * 4;
+        int autoMax = MaximumContentDim?.GetAnchor (superviewContentSize) ?? screenX4;
+
+        Debug.Assert (autoMin <= autoMax, "MinimumContentDim must be less than or equal to MaximumContentDim.");
 
 
         if (Style.FastHasFlags (DimAutoStyle.Text))
         if (Style.FastHasFlags (DimAutoStyle.Text))
         {
         {
-            textSize = int.Max (autoMin, dimension == Dimension.Width ? us.TextFormatter.Size.Width : us.TextFormatter.Size.Height);
+            if (dimension == Dimension.Width)
+            {
+                if (us.TextFormatter.ConstrainToWidth is null)
+                {
+                    // Set BOTH width and height (by setting Size). We do this because we will be called again, next
+                    // for Dimension.Height. We need to know the width to calculate the height.
+                    us.TextFormatter.ConstrainToSize = us.TextFormatter.FormatAndGetSize (new (int.Min (autoMax, screenX4), screenX4));
+                }
+
+                textSize = us.TextFormatter.ConstrainToWidth!.Value;
+            }
+            else
+            {
+                if (us.TextFormatter.ConstrainToHeight is null)
+                {
+                    // Set just the height. It is assumed that the width has already been set.
+                    // TODO: There may be cases where the width is not set. We may need to set it here.
+                    textSize = us.TextFormatter.FormatAndGetSize (new (us.TextFormatter.ConstrainToWidth ?? screenX4, int.Min (autoMax, screenX4))).Height;
+                    us.TextFormatter.ConstrainToHeight = textSize;
+                }
+                else
+                {
+                    textSize = us.TextFormatter.ConstrainToHeight.Value;
+                }
+            }
         }
         }
 
 
+        List<View> viewsNeedingLayout = new ();
+
         if (Style.FastHasFlags (DimAutoStyle.Content))
         if (Style.FastHasFlags (DimAutoStyle.Content))
         {
         {
             if (!us.ContentSizeTracksViewport)
             if (!us.ContentSizeTracksViewport)
             {
             {
-                // ContentSize was explicitly set. Ignore subviews.
-                subviewsSize = dimension == Dimension.Width ? us.GetContentSize ().Width : us.GetContentSize ().Height;
+                // ContentSize was explicitly set. Use `us.ContentSize` to determine size.
+                maxCalculatedSize = dimension == Dimension.Width ? us.GetContentSize ().Width : us.GetContentSize ().Height;
             }
             }
             else
             else
             {
             {
-                // ContentSize was NOT explicitly set. Use subviews to determine size.
-
-                // TODO: This whole body of code is a WIP (for https://github.com/gui-cs/Terminal.Gui/pull/3451).
-                subviewsSize = 0;
-
-                List<View> includedSubviews = us.Subviews.ToList ();//.Where (v => !v.ExcludeFromLayout).ToList ();
-                List<View> subviews;
-
-                #region Not Anchored and Are Not Dependent
-                // Start with subviews that are not anchored to the end, aligned, or dependent on content size
-                // [x] PosAnchorEnd
-                // [x] PosAlign
-                // [ ] PosCenter
-                // [ ] PosPercent
-                // [ ] PosView
-                // [ ] PosFunc
-                // [x] DimFill
-                // [ ] DimPercent
-                // [ ] DimFunc
-                // [ ] DimView
+                maxCalculatedSize = textSize;
+
+                // TOOD: All the below is a naive implementation. It may be possible to optimize this.
+
+                List<View> includedSubviews = us.Subviews.ToList ();
+
+                // If [x] it can cause `us.ContentSize` to change.
+                // If [ ] it doesn't need special processing for us to determine `us.ContentSize`.
+
+                // -------------------- Pos types that are dependent on `us.Subviews`
+                // [ ] PosAlign     - Position is dependent on other views with `GroupId` AND `us.ContentSize`
+                // [x] PosView      - Position is dependent on `subview.Target` - it can cause a change in `us.ContentSize`
+                // [x] PosCombine   - Position is dependent if `Pos.Has [one of the above]` - it can cause a change in `us.ContentSize`
+
+                // -------------------- Pos types that are dependent on `us.ContentSize`
+                // [ ] PosAlign     - Position is dependent on other views with `GroupId` AND `us.ContentSize`
+                // [x] PosAnchorEnd - Position is dependent on `us.ContentSize` AND `subview.Frame` - it can cause a change in `us.ContentSize`
+                // [ ] PosCenter    - Position is dependent `us.ContentSize` AND `subview.Frame` - 
+                // [ ] PosPercent   - Position is dependent `us.ContentSize` - Will always be 0 if there is no other content that makes the superview have a size.
+                // [x] PosCombine   - Position is dependent if `Pos.Has [one of the above]` - it can cause a change in `us.ContentSize`
+
+                // -------------------- Pos types that are not dependent on either `us.Subviews` or `us.ContentSize`
+                // [ ] PosAbsolute  - Position is fixed.
+                // [ ] PosFunc      - Position is internally calculated.
+
+                // -------------------- Dim types that are dependent on `us.Subviews`
+                // [x] DimView      - Dimension is dependent on `subview.Target`
+                // [x] DimCombine   - Dimension is dependent if `Dim.Has [one of the above]` - it can cause a change in `us.ContentSize`
+
+                // -------------------- Dim types that are dependent on `us.ContentSize`
+                // [ ] DimFill      - Dimension is dependent on `us.ContentSize` - Will always be 0 if there is no other content that makes the superview have a size.
+                // [ ] DimPercent   - Dimension is dependent on `us.ContentSize` - Will always be 0 if there is no other content that makes the superview have a size.
+                // [ ] DimCombine   - Dimension is dependent if `Dim.Has [one of the above]`
+
+                // -------------------- Dim types that are not dependent on either `us.Subviews` or `us.ContentSize`
+                // [ ] DimAuto      - Dimension is internally calculated
+                // [ ] DimAbsolute  - Dimension is fixed
+                // [ ] DimFunc      - Dimension is internally calculated
+
+                // ======================================================
+                // Do the easy stuff first - subviews whose position and size are not dependent on other views or content size
+                // ======================================================
+                // [ ] PosAbsolute  - Position is fixed.
+                // [ ] PosFunc      - Position is internally calculated
+                // [ ] DimAuto      - Dimension is internally calculated
+                // [ ] DimAbsolute  - Dimension is fixed
+                // [ ] DimFunc      - Dimension is internally calculated
+                List<View> notDependentSubViews;
+
                 if (dimension == Dimension.Width)
                 if (dimension == Dimension.Width)
                 {
                 {
-                    subviews = includedSubviews.Where (v => v.X is not PosAnchorEnd
-                                                           && v.X is not PosAlign
-                                                            // && v.X is not PosCenter
-                                                            && v.Width is not DimAuto
-                                                           && v.Width is not DimFill).ToList ();
+                    notDependentSubViews = includedSubviews.Where (
+                                                                   v => v.Width is { }
+                                                                        && (v.X is PosAbsolute or PosFunc || v.Width is DimAuto or DimAbsolute or DimFunc) // BUGBUG: We should use v.X.Has and v.Width.Has?
+                                                                        && !v.X.Has (typeof (PosAnchorEnd), out _)
+                                                                        && !v.X.Has (typeof (PosAlign), out _)
+                                                                        && !v.X.Has (typeof (PosCenter), out _)
+                                                                        && !v.Width.Has (typeof (DimFill), out _)
+                                                                        && !v.Width.Has (typeof (DimPercent), out _)
+                                                                  )
+                                                           .ToList ();
                 }
                 }
                 else
                 else
                 {
                 {
-                    subviews = includedSubviews.Where (v => v.Y is not PosAnchorEnd
-                                                           && v.Y is not PosAlign
-                                                            // && v.Y is not PosCenter
-                                                            && v.Height is not DimAuto
-                                                           && v.Height is not DimFill).ToList ();
+                    notDependentSubViews = includedSubviews.Where (
+                                                                   v => v.Height is { }
+                                                                        && (v.Y is PosAbsolute or PosFunc || v.Height is DimAuto or DimAbsolute or DimFunc) // BUGBUG: We should use v.Y.Has and v.Height.Has?
+                                                                        && !v.Y.Has (typeof (PosAnchorEnd), out _)
+                                                                        && !v.Y.Has (typeof (PosAlign), out _)
+                                                                        && !v.Y.Has (typeof (PosCenter), out _)
+                                                                        && !v.Height.Has (typeof (DimFill), out _)
+                                                                        && !v.Height.Has (typeof (DimPercent), out _)
+                                                                  )
+                                                           .ToList ();
                 }
                 }
 
 
-                for (var i = 0; i < subviews.Count; i++)
+                for (var i = 0; i < notDependentSubViews.Count; i++)
                 {
                 {
-                    View v = subviews [i];
+                    View v = notDependentSubViews [i];
 
 
-                    int size = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
+                    var size = 0;
 
 
-                    if (size > subviewsSize)
+                    if (dimension == Dimension.Width)
                     {
                     {
-                        // BUGBUG: Should we break here? Or choose min/max?
-                        subviewsSize = size;
+                        int width = v.Width!.Calculate (0, superviewContentSize, v, dimension);
+                        size = v.X.GetAnchor (0) + width;
+                    }
+                    else
+                    {
+                        int height = v.Height!.Calculate (0, superviewContentSize, v, dimension);
+                        size = v.Y!.GetAnchor (0) + height;
+                    }
+
+                    if (size > maxCalculatedSize)
+                    {
+                        maxCalculatedSize = size;
                     }
                     }
                 }
                 }
-                #endregion Not Anchored and Are Not Dependent
 
 
-                #region Anchored
-                // Now, handle subviews that are anchored to the end
-                // [x] PosAnchorEnd
+                // ************** We now have some idea of `us.ContentSize` ***************
+
+                #region Centered
+
+                // [ ] PosCenter    - Position is dependent `us.ContentSize` AND `subview.Frame`
+                List<View> centeredSubViews;
+
                 if (dimension == Dimension.Width)
                 if (dimension == Dimension.Width)
                 {
                 {
-                    subviews = includedSubviews.Where (v => v.X is PosAnchorEnd).ToList ();
+                    centeredSubViews = us.Subviews.Where (v => v.X.Has (typeof (PosCenter), out _)).ToList ();
                 }
                 }
                 else
                 else
                 {
                 {
-                    subviews = includedSubviews.Where (v => v.Y is PosAnchorEnd).ToList ();
+                    centeredSubViews = us.Subviews.Where (v => v.Y.Has (typeof (PosCenter), out _)).ToList ();
                 }
                 }
 
 
-                int maxAnchorEnd = 0;
-                for (var i = 0; i < subviews.Count; i++)
+                viewsNeedingLayout.AddRange (centeredSubViews);
+
+                var maxCentered = 0;
+
+                for (var i = 0; i < centeredSubViews.Count; i++)
                 {
                 {
-                    View v = subviews [i];
-                    maxAnchorEnd = dimension == Dimension.Width ? v.Frame.Width : v.Frame.Height;
+                    View v = centeredSubViews [i];
+
+                    if (dimension == Dimension.Width)
+                    {
+                        int width = v.Width!.Calculate (0, screenX4, v, dimension);
+                        maxCentered = v.X.GetAnchor (0) + width;
+                    }
+                    else
+                    {
+                        int height = v.Height!.Calculate (0, screenX4, v, dimension);
+                        maxCentered = v.Y.GetAnchor (0) + height;
+                    }
                 }
                 }
 
 
-                subviewsSize += maxAnchorEnd;
-                #endregion Anchored
+                maxCalculatedSize = int.Max (maxCalculatedSize, maxCentered);
+
+                #endregion Centered
+
+                #region Percent
+
+                // [ ] DimPercent   - Dimension is dependent on `us.ContentSize`
+                // No need to do anything.
+
+                #endregion Percent
+
+                #region Aligned
+
+                // [ ] PosAlign     - Position is dependent on other views with `GroupId` AND `us.ContentSize`
+                var maxAlign = 0;
+
+                // Use Linq to get a list of distinct GroupIds from the subviews
+                List<int> groupIds = includedSubviews.Select (
+                                                              v =>
+                                                              {
+                                                                  if (dimension == Dimension.Width)
+                                                                  {
+                                                                      if (v.X.Has (typeof (PosAlign), out Pos posAlign))
+                                                                      {
+                                                                          return ((PosAlign)posAlign).GroupId;
+                                                                      }
+                                                                  }
+                                                                  else
+                                                                  {
+                                                                      if (v.Y.Has (typeof (PosAlign), out Pos posAlign))
+                                                                      {
+                                                                          return ((PosAlign)posAlign).GroupId;
+                                                                      }
+                                                                  }
+
+                                                                  return -1;
+                                                              })
+                                                     .Distinct ()
+                                                     .ToList ();
+
+                foreach (int groupId in groupIds.Where (g => g != -1))
+                {
+                    // PERF: If this proves a perf issue, consider caching a ref to this list in each item
+                    List<PosAlign?> posAlignsInGroup = includedSubviews.Where (
+                                                                               v =>
+                                                                               {
+                                                                                   return dimension switch
+                                                                                   {
+                                                                                       Dimension.Width when v.X is PosAlign alignX => alignX.GroupId
+                                                                                           == groupId,
+                                                                                       Dimension.Height when v.Y is PosAlign alignY => alignY.GroupId
+                                                                                           == groupId,
+                                                                                       _ => false
+                                                                                   };
+                                                                               })
+                                                                       .Select (v => dimension == Dimension.Width ? v.X as PosAlign : v.Y as PosAlign)
+                                                                       .ToList ();
+
+                    if (posAlignsInGroup.Count == 0)
+                    {
+                        continue;
+                    }
+
+                    maxAlign = PosAlign.CalculateMinDimension (groupId, includedSubviews, dimension);
+                }
+
+                maxCalculatedSize = int.Max (maxCalculatedSize, maxAlign);
+
+                #endregion Aligned
+
+                #region Anchored
 
 
-                //#region Aligned
-
-                //// Now, handle subviews that are anchored to the end
-                //// [x] PosAnchorEnd
-                //int maxAlign = 0;
-                //if (dimension == Dimension.Width)
-                //{
-                //    // Use Linq to get a list of distinct GroupIds from the subviews
-                //    List<int> groupIds = includedSubviews.Select (v => v.X is PosAlign posAlign ? posAlign.GroupId : -1).Distinct ().ToList ();
-
-                //    foreach (var groupId in groupIds)
-                //    {
-                //        List<int> dimensionsList = new ();
-
-                //        // PERF: If this proves a perf issue, consider caching a ref to this list in each item
-                //        List<PosAlign?> posAlignsInGroup = includedSubviews.Where (
-                //            v =>
-                //            {
-                //                return dimension switch
-                //                {
-                //                    Dimension.Width when v.X is PosAlign alignX => alignX.GroupId == groupId,
-                //                    Dimension.Height when v.Y is PosAlign alignY => alignY.GroupId == groupId,
-                //                    _ => false
-                //                };
-                //            })
-                //            .Select (v => dimension == Dimension.Width ? v.X as PosAlign : v.Y as PosAlign)
-                //            .ToList ();
-
-                //        if (posAlignsInGroup.Count == 0)
-                //        {
-                //            continue;
-                //        }
-
-                //        maxAlign = PosAlign.CalculateMinDimension (groupId, includedSubviews, dimension);
-                //    }
-                //}
-                //else
-                //{
-                //    subviews = includedSubviews.Where (v => v.Y is PosAlign).ToList ();
-                //}
-
-                //subviewsSize = int.Max (subviewsSize, maxAlign);
-                //#endregion Aligned
-
-
-                #region Auto
+                // [x] PosAnchorEnd - Position is dependent on `us.ContentSize` AND `subview.Frame` 
+                List<View> anchoredSubViews;
 
 
                 if (dimension == Dimension.Width)
                 if (dimension == Dimension.Width)
                 {
                 {
-                    subviews = includedSubviews.Where (v => v.Width is DimAuto).ToList ();
+                    anchoredSubViews = includedSubviews.Where (v => v.X.Has (typeof (PosAnchorEnd), out _)).ToList ();
                 }
                 }
                 else
                 else
                 {
                 {
-                    subviews = includedSubviews.Where (v => v.Height is DimAuto).ToList ();
+                    anchoredSubViews = includedSubviews.Where (v => v.Y.Has (typeof (PosAnchorEnd), out _)).ToList ();
                 }
                 }
 
 
-                int maxAuto = 0;
-                for (var i = 0; i < subviews.Count; i++)
+                viewsNeedingLayout.AddRange (anchoredSubViews);
+
+                var maxAnchorEnd = 0;
+
+                for (var i = 0; i < anchoredSubViews.Count; i++)
                 {
                 {
-                    View v = subviews [i];
-
-                    //if (dimension == Dimension.Width)
-                    //{
-                    //    v.SetRelativeLayout (new Size (autoMax - subviewsSize, 0));
-                    //}
-                    //else
-                    //{
-                    //    v.SetRelativeLayout (new Size (0, autoMax - subviewsSize));
-                    //}
-                    maxAuto = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
-
-                    if (maxAuto > subviewsSize)
+                    View v = anchoredSubViews [i];
+
+                    // Need to set the relative layout for PosAnchorEnd subviews to calculate the size
+                    // TODO: Figure out a way to not have Calculate change the state of subviews (calling SRL).
+                    if (dimension == Dimension.Width)
                     {
                     {
-                        // BUGBUG: Should we break here? Or choose min/max?
-                        subviewsSize = maxAuto;
+                        v.SetRelativeLayout (new (maxCalculatedSize, screenX4));
                     }
                     }
+                    else
+                    {
+                        v.SetRelativeLayout (new (screenX4, maxCalculatedSize));
+                    }
+
+                    maxAnchorEnd = dimension == Dimension.Width
+                                       ? v.X.GetAnchor (maxCalculatedSize + v.Frame.Width)
+                                       : v.Y.GetAnchor (maxCalculatedSize + v.Frame.Height);
                 }
                 }
 
 
-//                subviewsSize += maxAuto;
-
-                #endregion Auto
-
-                //#region Center
-                //// Now, handle subviews that are Centered
-                //if (dimension == Dimension.Width)
-                //{
-                //    subviews = us.Subviews.Where (v => v.X is PosCenter).ToList ();
-                //}
-                //else
-                //{
-                //    subviews = us.Subviews.Where (v => v.Y is PosCenter).ToList ();
-                //}
-
-                //int maxCenter = 0;
-                //for (var i = 0; i < subviews.Count; i++)
-                //{
-                //    View v = subviews [i];
-                //    maxCenter = dimension == Dimension.Width ? v.Frame.Width : v.Frame.Height;
-                //}
-
-                //subviewsSize += maxCenter;
-                //#endregion Center
-
-                #region Are Dependent
-                // Now, go back to those that are dependent on content size
-                // [x] DimFill
-                // [ ] DimPercent
+                maxCalculatedSize = Math.Max (maxCalculatedSize, maxAnchorEnd);
+
+                #endregion Anchored
+
+                #region PosView
+
+                // [x] PosView      - Position is dependent on `subview.Target` - it can cause a change in `us.ContentSize`
+                List<View> posViewSubViews;
+
                 if (dimension == Dimension.Width)
                 if (dimension == Dimension.Width)
                 {
                 {
-                    subviews = includedSubviews.Where (v => v.Width is DimFill).ToList ();
+                    posViewSubViews = includedSubviews.Where (v => v.X.Has (typeof (PosView), out _)).ToList ();
                 }
                 }
                 else
                 else
                 {
                 {
-                    subviews = includedSubviews.Where (v => v.Height is DimFill).ToList ();
+                    posViewSubViews = includedSubviews.Where (v => v.Y.Has (typeof (PosView), out _)).ToList ();
                 }
                 }
 
 
-                int maxFill = 0;
-                for (var i = 0; i < subviews.Count; i++)
+                for (var i = 0; i < posViewSubViews.Count; i++)
                 {
                 {
-                    View v = subviews [i];
+                    View v = posViewSubViews [i];
 
 
-                    if (autoMax == int.MaxValue)
+                    // BUGBUG: The order may not be correct. May need to call TopologicalSort?
+                    // TODO: Figure out a way to not have Calculate change the state of subviews (calling SRL).
+                    if (dimension == Dimension.Width)
                     {
                     {
-                        autoMax = superviewContentSize;
+                        v.SetRelativeLayout (new (maxCalculatedSize, 0));
                     }
                     }
+                    else
+                    {
+                        v.SetRelativeLayout (new (0, maxCalculatedSize));
+                    }
+
+                    int maxPosView = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
+
+                    if (maxPosView > maxCalculatedSize)
+                    {
+                        maxCalculatedSize = maxPosView;
+                    }
+                }
+
+                #endregion PosView
+
+                // [x] PosCombine   - Position is dependent if `Pos.Has ([one of the above]` - it can cause a change in `us.ContentSize`
+
+                #region DimView
+
+                // [x] DimView      - Dimension is dependent on `subview.Target` - it can cause a change in `us.ContentSize`
+                List<View> dimViewSubViews;
+
+                if (dimension == Dimension.Width)
+                {
+                    dimViewSubViews = includedSubviews.Where (v => v.Width is { } && v.Width.Has (typeof (DimView), out _)).ToList ();
+                }
+                else
+                {
+                    dimViewSubViews = includedSubviews.Where (v => v.Height is { } && v.Height.Has (typeof (DimView), out _)).ToList ();
+                }
+
+                for (var i = 0; i < dimViewSubViews.Count; i++)
+                {
+                    View v = dimViewSubViews [i];
+
+                    // BUGBUG: The order may not be correct. May need to call TopologicalSort?
+                    // TODO: Figure out a way to not have Calculate change the state of subviews (calling SRL).
                     if (dimension == Dimension.Width)
                     if (dimension == Dimension.Width)
                     {
                     {
-                        v.SetRelativeLayout (new Size (autoMax - subviewsSize, 0));
+                        v.SetRelativeLayout (new (maxCalculatedSize, 0));
                     }
                     }
                     else
                     else
                     {
                     {
-                        v.SetRelativeLayout (new Size (0, autoMax - subviewsSize));
+                        v.SetRelativeLayout (new (0, maxCalculatedSize));
+                    }
+
+                    int maxDimView = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
+
+                    if (maxDimView > maxCalculatedSize)
+                    {
+                        maxCalculatedSize = maxDimView;
                     }
                     }
-                    maxFill = dimension == Dimension.Width ? v.Frame.Width : v.Frame.Height;
                 }
                 }
 
 
-                subviewsSize += maxFill;
-                #endregion Are Dependent
+                #endregion DimView
             }
             }
         }
         }
 
 
         // All sizes here are content-relative; ignoring adornments.
         // All sizes here are content-relative; ignoring adornments.
         // We take the largest of text and content.
         // We take the largest of text and content.
-        int max = int.Max (textSize, subviewsSize);
+        int max = int.Max (textSize, maxCalculatedSize);
 
 
         // And, if min: is set, it wins if larger
         // And, if min: is set, it wins if larger
         max = int.Max (max, autoMin);
         max = int.Max (max, autoMin);
@@ -302,9 +463,9 @@ public class DimAuto () : Dim
         // And, if max: is set, it wins if smaller
         // And, if max: is set, it wins if smaller
         max = int.Min (max, autoMax);
         max = int.Min (max, autoMax);
 
 
-        // Factor in adornments
         Thickness thickness = us.GetAdornmentsThickness ();
         Thickness thickness = us.GetAdornmentsThickness ();
-        max += dimension switch
+
+        int adornmentThickness = dimension switch
         {
         {
             Dimension.Width => thickness.Horizontal,
             Dimension.Width => thickness.Horizontal,
             Dimension.Height => thickness.Vertical,
             Dimension.Height => thickness.Vertical,
@@ -312,32 +473,8 @@ public class DimAuto () : Dim
             _ => throw new ArgumentOutOfRangeException (nameof (dimension), dimension, null)
             _ => throw new ArgumentOutOfRangeException (nameof (dimension), dimension, null)
         };
         };
 
 
-        return max;
-    }
-
-    internal override bool ReferencesOtherViews ()
-    {
-        // BUGBUG: This is not correct. _contentSize may be null.
-        return false; //_style.HasFlag (DimAutoStyle.Content);
-    }
+        max += adornmentThickness;
 
 
-    /// <inheritdoc/>
-    public override bool Equals (object? other)
-    {
-        if (other is not DimAuto auto)
-        {
-            return false;
-        }
-
-        return auto.MinimumContentDim == MinimumContentDim &&
-               auto.MaximumContentDim == MaximumContentDim &&
-               auto.Style == Style;
-    }
-
-    /// <inheritdoc/>
-    public override int GetHashCode ()
-    {
-        return HashCode.Combine (MinimumContentDim, MaximumContentDim, Style);
+        return max;
     }
     }
-
-}
+}

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

@@ -33,6 +33,10 @@ public enum DimAutoStyle
     ///     <para>
     ///     <para>
     ///         The corresponding dimensions of <see cref="View.GetContentSize ()"/> and/or <see cref="View.Subviews"/> will be ignored.
     ///         The corresponding dimensions of <see cref="View.GetContentSize ()"/> and/or <see cref="View.Subviews"/> will be ignored.
     ///     </para>
     ///     </para>
+    ///     <para>
+    ///         If <see cref="DimAuto.MaximumContentDim"/> is set, the dimension will be the maximum of the formatted text and the
+    ///         demension provided by <see cref="DimAuto.MaximumContentDim"/>. Otherwise, the dimension will be that of the formatted text.
+    ///     </para>
     /// </summary>
     /// </summary>
     Text = 2,
     Text = 2,
 
 

+ 3 - 22
Terminal.Gui/View/Layout/DimCombine.cs

@@ -13,7 +13,7 @@ namespace Terminal.Gui;
 /// </remarks>
 /// </remarks>
 /// <param name="left">The left dimension.</param>
 /// <param name="left">The left dimension.</param>
 /// <param name="right">The right dimension.</param>
 /// <param name="right">The right dimension.</param>
-public class DimCombine (AddOrSubtract add, Dim? left, Dim? right) : Dim
+public class DimCombine (AddOrSubtract add, Dim left, Dim right) : Dim
 {
 {
     /// <summary>
     /// <summary>
     ///     Gets whether the two dimensions are added or subtracted.
     ///     Gets whether the two dimensions are added or subtracted.
@@ -23,12 +23,12 @@ public class DimCombine (AddOrSubtract add, Dim? left, Dim? right) : Dim
     /// <summary>
     /// <summary>
     ///     Gets the left dimension.
     ///     Gets the left dimension.
     /// </summary>
     /// </summary>
-    public Dim? Left { get; } = left;
+    public Dim Left { get; } = left;
 
 
     /// <summary>
     /// <summary>
     ///     Gets the right dimension.
     ///     Gets the right dimension.
     /// </summary>
     /// </summary>
-    public Dim? Right { get; } = right;
+    public Dim Right { get; } = right;
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
     public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; }
     public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; }
@@ -61,23 +61,4 @@ public class DimCombine (AddOrSubtract add, Dim? left, Dim? right) : Dim
 
 
         return newDimension;
         return newDimension;
     }
     }
-
-    /// <summary>
-    ///     Diagnostics API to determine if this Dim object references other views.
-    /// </summary>
-    /// <returns></returns>
-    internal override bool ReferencesOtherViews ()
-    {
-        if (Left!.ReferencesOtherViews ())
-        {
-            return true;
-        }
-
-        if (Right!.ReferencesOtherViews ())
-        {
-            return true;
-        }
-
-        return false;
-    }
 }
 }

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

@@ -197,10 +197,7 @@ public abstract class Pos
     /// </example>
     /// </example>
     public static Pos AnchorEnd (int offset)
     public static Pos AnchorEnd (int offset)
     {
     {
-        if (offset < 0)
-        {
-            throw new ArgumentException (@"Must be positive", nameof (offset));
-        }
+        ArgumentOutOfRangeException.ThrowIfNegative (offset, nameof (offset));
 
 
         return new PosAnchorEnd (offset);
         return new PosAnchorEnd (offset);
     }
     }
@@ -246,10 +243,7 @@ public abstract class Pos
     /// </example>
     /// </example>
     public static Pos Percent (int percent)
     public static Pos Percent (int percent)
     {
     {
-        if (percent is < 0)
-        {
-            throw new ArgumentException ("Percent value must be positive.");
-        }
+        ArgumentOutOfRangeException.ThrowIfNegative (percent, nameof (percent));
 
 
         return new PosPercent (percent);
         return new PosPercent (percent);
     }
     }

+ 2 - 1
Terminal.Gui/View/Layout/PosCenter.cs

@@ -13,8 +13,9 @@ public class PosCenter : Pos
 
 
     internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
     internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
     {
     {
+        // Protect against negative dimensions
         int newDimension = Math.Max (dim.Calculate (0, superviewDimension, us, dimension), 0);
         int newDimension = Math.Max (dim.Calculate (0, superviewDimension, us, dimension), 0);
 
 
-        return GetAnchor (superviewDimension - newDimension);
+        return (superviewDimension - newDimension) / 2;
     }
     }
 }
 }

+ 366 - 312
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -5,6 +5,242 @@ namespace Terminal.Gui;
 
 
 public partial class View
 public partial class View
 {
 {
+    /// <summary>
+    ///     Indicates whether the specified SuperView-relative coordinates are within the View's <see cref="Frame"/>.
+    /// </summary>
+    /// <param name="location">SuperView-relative coordinate</param>
+    /// <returns><see langword="true"/> if the specified SuperView-relative coordinates are within the View.</returns>
+    public virtual bool Contains (in Point location) { return Frame.Contains (location); }
+
+    /// <summary>Finds the first Subview of <paramref name="start"/> that is visible at the provided location.</summary>
+    /// <remarks>
+    ///     <para>
+    ///         Used to determine what view the mouse is over.
+    ///     </para>
+    /// </remarks>
+    /// <param name="start">The view to scope the search by.</param>
+    /// <param name="location"><paramref name="start"/>.SuperView-relative coordinate.</param>
+    /// <returns>
+    ///     The view that was found at the <paramref name="location"/> coordinate.
+    ///     <see langword="null"/> if no view was found.
+    /// </returns>
+
+    // CONCURRENCY: This method is not thread-safe. Undefined behavior and likely program crashes are exposed by unsynchronized access to InternalSubviews.
+    internal static View? FindDeepestView (View? start, in Point location)
+    {
+        Point currentLocation = location;
+
+        while (start is { Visible: true } && start.Contains (currentLocation))
+        {
+            Adornment? found = null;
+
+            if (start.Margin.Contains (currentLocation))
+            {
+                found = start.Margin;
+            }
+            else if (start.Border.Contains (currentLocation))
+            {
+                found = start.Border;
+            }
+            else if (start.Padding.Contains (currentLocation))
+            {
+                found = start.Padding;
+            }
+
+            Point viewportOffset = start.GetViewportOffsetFromFrame ();
+
+            if (found is { })
+            {
+                start = found;
+                viewportOffset = found.Parent.Frame.Location;
+            }
+
+            int startOffsetX = currentLocation.X - (start.Frame.X + viewportOffset.X);
+            int startOffsetY = currentLocation.Y - (start.Frame.Y + viewportOffset.Y);
+
+            View? subview = null;
+
+            for (int i = start.InternalSubviews.Count - 1; i >= 0; i--)
+            {
+                if (start.InternalSubviews [i].Visible
+                    && start.InternalSubviews [i].Contains (new (startOffsetX + start.Viewport.X, startOffsetY + start.Viewport.Y)))
+                {
+                    subview = start.InternalSubviews [i];
+                    currentLocation.X = startOffsetX + start.Viewport.X;
+                    currentLocation.Y = startOffsetY + start.Viewport.Y;
+
+                    // start is the deepest subview under the mouse; stop searching the subviews
+                    break;
+                }
+            }
+
+            if (subview is null)
+            {
+                // No subview was found that's under the mouse, so we're done
+                return start;
+            }
+
+            // We found a subview of start that's under the mouse, continue...
+            start = subview;
+        }
+
+        return null;
+    }
+
+    // BUGBUG: This method interferes with Dialog/MessageBox default min/max size.
+
+    /// <summary>
+    ///     Gets a new location of the <see cref="View"/> that is within the Viewport of the <paramref name="viewToMove"/>'s
+    ///     <see cref="View.SuperView"/> (e.g. for dragging a Window). The `out` parameters are the new X and Y coordinates.
+    /// </summary>
+    /// <remarks>
+    ///     If <paramref name="viewToMove"/> does not have a <see cref="View.SuperView"/> or it's SuperView is not
+    ///     <see cref="Application.Top"/> the position will be bound by the <see cref="ConsoleDriver.Cols"/> and
+    ///     <see cref="ConsoleDriver.Rows"/>.
+    /// </remarks>
+    /// <param name="viewToMove">The View that is to be moved.</param>
+    /// <param name="targetX">The target x location.</param>
+    /// <param name="targetY">The target y location.</param>
+    /// <param name="nx">The new x location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
+    /// <param name="ny">The new y location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
+    /// <param name="statusBar">The new top most statusBar</param>
+    /// <returns>
+    ///     Either <see cref="Application.Top"/> (if <paramref name="viewToMove"/> does not have a Super View) or
+    ///     <paramref name="viewToMove"/>'s SuperView. This can be used to ensure LayoutSubviews is called on the correct View.
+    /// </returns>
+    internal static View GetLocationEnsuringFullVisibility (
+        View viewToMove,
+        int targetX,
+        int targetY,
+        out int nx,
+        out int ny,
+        out StatusBar statusBar
+    )
+    {
+        int maxDimension;
+        View superView;
+        statusBar = null!;
+
+        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
+        {
+            maxDimension = Driver.Cols;
+            superView = Application.Top;
+        }
+        else
+        {
+            // Use the SuperView's Viewport, not Frame
+            maxDimension = viewToMove!.SuperView.Viewport.Width;
+            superView = viewToMove.SuperView;
+        }
+
+        if (superView?.Margin is { } && superView == viewToMove!.SuperView)
+        {
+            maxDimension -= superView.GetAdornmentsThickness ().Left + superView.GetAdornmentsThickness ().Right;
+        }
+
+        if (viewToMove!.Frame.Width <= maxDimension)
+        {
+            nx = Math.Max (targetX, 0);
+            nx = nx + viewToMove.Frame.Width > maxDimension ? Math.Max (maxDimension - viewToMove.Frame.Width, 0) : nx;
+
+            if (nx > viewToMove.Frame.X + viewToMove.Frame.Width)
+            {
+                nx = Math.Max (viewToMove.Frame.Right, 0);
+            }
+        }
+        else
+        {
+            nx = targetX;
+        }
+
+        //System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
+        var menuVisible = false;
+        var statusVisible = false;
+
+        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
+        {
+            menuVisible = Application.Top?.MenuBar?.Visible == true;
+        }
+        else
+        {
+            View t = viewToMove!.SuperView;
+
+            while (t is { } and not Toplevel)
+            {
+                t = t.SuperView;
+            }
+
+            if (t is Toplevel topLevel)
+            {
+                menuVisible = topLevel.MenuBar?.Visible == true;
+            }
+        }
+
+        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
+        {
+            maxDimension = menuVisible ? 1 : 0;
+        }
+        else
+        {
+            maxDimension = 0;
+        }
+
+        ny = Math.Max (targetY, maxDimension);
+
+        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
+        {
+            statusVisible = Application.Top?.StatusBar?.Visible == true;
+            statusBar = Application.Top?.StatusBar!;
+        }
+        else
+        {
+            View t = viewToMove!.SuperView;
+
+            while (t is { } and not Toplevel)
+            {
+                t = t.SuperView;
+            }
+
+            if (t is Toplevel topLevel)
+            {
+                statusVisible = topLevel.StatusBar?.Visible == true;
+                statusBar = topLevel.StatusBar!;
+            }
+        }
+
+        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
+        {
+            maxDimension = statusVisible ? Driver.Rows - 1 : Driver.Rows;
+        }
+        else
+        {
+            maxDimension = statusVisible ? viewToMove!.SuperView.Viewport.Height - 1 : viewToMove!.SuperView.Viewport.Height;
+        }
+
+        if (superView?.Margin is { } && superView == viewToMove?.SuperView)
+        {
+            maxDimension -= superView.GetAdornmentsThickness ().Top + superView.GetAdornmentsThickness ().Bottom;
+        }
+
+        ny = Math.Min (ny, maxDimension);
+
+        if (viewToMove?.Frame.Height <= maxDimension)
+        {
+            ny = ny + viewToMove.Frame.Height > maxDimension
+                     ? Math.Max (maxDimension - viewToMove.Frame.Height, menuVisible ? 1 : 0)
+                     : ny;
+
+            if (ny > viewToMove.Frame.Y + viewToMove.Frame.Height)
+            {
+                ny = Math.Max (viewToMove.Frame.Bottom, 0);
+            }
+        }
+
+        //System.Diagnostics.Debug.WriteLine ($"ny:{ny}, rHeight:{rHeight}");
+
+        return superView!;
+    }
+
     #region Frame
     #region Frame
 
 
     private Rectangle _frame;
     private Rectangle _frame;
@@ -15,7 +251,10 @@ public partial class View
     ///     <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.
     ///     <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.
     /// </value>
     /// </value>
     /// <remarks>
     /// <remarks>
-    ///     <para>Frame is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.</para>
+    ///     <para>
+    ///         Frame is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>
+    ///         .
+    ///     </para>
     ///     <para>
     ///     <para>
     ///         Setting Frame will set <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> to the
     ///         Setting Frame will set <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> to the
     ///         values of the corresponding properties of the <paramref name="value"/> parameter.
     ///         values of the corresponding properties of the <paramref name="value"/> parameter.
@@ -45,7 +284,6 @@ public partial class View
             _width = _frame.Width;
             _width = _frame.Width;
             _height = _frame.Height;
             _height = _frame.Height;
 
 
-            // TODO: Figure out if the below can be optimized.
             if (IsInitialized)
             if (IsInitialized)
             {
             {
                 OnResizeNeeded ();
                 OnResizeNeeded ();
@@ -65,8 +303,6 @@ public partial class View
         // This is the only place where _frame should be set directly. Use Frame = or SetFrame instead.
         // This is the only place where _frame should be set directly. Use Frame = or SetFrame instead.
         _frame = frame;
         _frame = frame;
 
 
-        SetTextFormatterSize ();
-
         OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport));
         OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport));
     }
     }
 
 
@@ -133,7 +369,8 @@ public partial class View
     /// <value>The <see cref="Pos"/> object representing the X position.</value>
     /// <value>The <see cref="Pos"/> object representing the X position.</value>
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
-    ///         The position is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.
+    ///         The position is relative to the <see cref="SuperView"/>'s Content, which is bound by
+    ///         <see cref="GetContentSize ()"/>.
     ///     </para>
     ///     </para>
     ///     <para>
     ///     <para>
     ///         If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
     ///         If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
@@ -171,7 +408,8 @@ public partial class View
     /// <value>The <see cref="Pos"/> object representing the Y position.</value>
     /// <value>The <see cref="Pos"/> object representing the Y position.</value>
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
-    ///         The position is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.
+    ///         The position is relative to the <see cref="SuperView"/>'s Content, which is bound by
+    ///         <see cref="GetContentSize ()"/>.
     ///     </para>
     ///     </para>
     ///     <para>
     ///     <para>
     ///         If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
     ///         If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
@@ -208,7 +446,8 @@ public partial class View
     /// <value>The <see cref="Dim"/> object representing the height of the view (the number of rows).</value>
     /// <value>The <see cref="Dim"/> object representing the height of the view (the number of rows).</value>
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
-    ///         The dimension is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>
+    ///         The dimension is relative to the <see cref="SuperView"/>'s Content, which is bound by
+    ///         <see cref="GetContentSize ()"/>
     ///         .
     ///         .
     ///     </para>
     ///     </para>
     ///     <para>
     ///     <para>
@@ -235,7 +474,7 @@ public partial class View
                 return;
                 return;
             }
             }
 
 
-            if (_height is DimAuto)
+            if (_height is { } && _height.Has (typeof (DimAuto), out _))
             {
             {
                 // Reset ContentSize to Viewport
                 // Reset ContentSize to Viewport
                 _contentSize = null;
                 _contentSize = null;
@@ -243,6 +482,9 @@ public partial class View
 
 
             _height = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Height)} cannot be null");
             _height = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Height)} cannot be null");
 
 
+            // Reset TextFormatter - Will be recalculated in SetTextFormatterSize
+            TextFormatter.ConstrainToHeight = null;
+
             OnResizeNeeded ();
             OnResizeNeeded ();
         }
         }
     }
     }
@@ -253,7 +495,8 @@ public partial class View
     /// <value>The <see cref="Dim"/> object representing the width of the view (the number of columns).</value>
     /// <value>The <see cref="Dim"/> object representing the width of the view (the number of columns).</value>
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
-    ///         The dimension is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>
+    ///         The dimension is relative to the <see cref="SuperView"/>'s Content, which is bound by
+    ///         <see cref="GetContentSize ()"/>
     ///         .
     ///         .
     ///     </para>
     ///     </para>
     ///     <para>
     ///     <para>
@@ -280,7 +523,7 @@ public partial class View
                 return;
                 return;
             }
             }
 
 
-            if (_width is DimAuto)
+            if (_width is { } && _width.Has (typeof (DimAuto), out _))
             {
             {
                 // Reset ContentSize to Viewport
                 // Reset ContentSize to Viewport
                 _contentSize = null;
                 _contentSize = null;
@@ -288,6 +531,9 @@ public partial class View
 
 
             _width = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Width)} cannot be null");
             _width = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Width)} cannot be null");
 
 
+            // Reset TextFormatter - Will be recalculated in SetTextFormatterSize
+            TextFormatter.ConstrainToWidth = null;
+
             OnResizeNeeded ();
             OnResizeNeeded ();
         }
         }
     }
     }
@@ -296,258 +542,127 @@ public partial class View
 
 
     #region Layout Engine
     #region Layout Engine
 
 
-    #endregion Layout Engine
-
-    /// <summary>
-    ///     Indicates whether the specified SuperView-relative coordinates are within the View's <see cref="Frame"/>.
-    /// </summary>
-    /// <param name="location">SuperView-relative coordinate</param>
-    /// <returns><see langword="true"/> if the specified SuperView-relative coordinates are within the View.</returns>
-    public virtual bool Contains (in Point location) { return Frame.Contains (location); }
-
-    /// <summary>Finds the first Subview of <paramref name="start"/> that is visible at the provided location.</summary>
+    /// <summary>Fired after the View's <see cref="LayoutSubviews"/> method has completed.</summary>
     /// <remarks>
     /// <remarks>
-    ///     <para>
-    ///         Used to determine what view the mouse is over.
-    ///     </para>
+    ///     Subscribe to this event to perform tasks when the <see cref="View"/> has been resized or the layout has
+    ///     otherwise changed.
     /// </remarks>
     /// </remarks>
-    /// <param name="start">The view to scope the search by.</param>
-    /// <param name="location"><paramref name="start"/>.SuperView-relative coordinate.</param>
-    /// <returns>
-    ///     The view that was found at the <paramref name="location"/> coordinate.
-    ///     <see langword="null"/> if no view was found.
-    /// </returns>
-
-    // CONCURRENCY: This method is not thread-safe. Undefined behavior and likely program crashes are exposed by unsynchronized access to InternalSubviews.
-    internal static View? FindDeepestView (View? start, in Point location)
-    {
-        Point currentLocation = location;
-        while (start is { Visible: true } && start.Contains (currentLocation))
-        {
-            Adornment? found = null;
-
-            if (start.Margin.Contains (currentLocation))
-            {
-                found = start.Margin;
-            }
-            else if (start.Border.Contains (currentLocation))
-            {
-                found = start.Border;
-            }
-            else if (start.Padding.Contains (currentLocation))
-            {
-                found = start.Padding;
-            }
-
-            Point viewportOffset = start.GetViewportOffsetFromFrame ();
-
-            if (found is { })
-            {
-                start = found;
-                viewportOffset = found.Parent.Frame.Location;
-            }
-
-            int startOffsetX = currentLocation.X - (start.Frame.X + viewportOffset.X);
-            int startOffsetY = currentLocation.Y - (start.Frame.Y + viewportOffset.Y);
-
-            View? subview = null;
-
-            for (int i = start.InternalSubviews.Count - 1; i >= 0; i--)
-            {
-                if (start.InternalSubviews [i].Visible
-                    && start.InternalSubviews [i].Contains (new (startOffsetX + start.Viewport.X, startOffsetY + start.Viewport.Y)))
-                {
-                    subview = start.InternalSubviews [i];
-                    currentLocation.X = startOffsetX + start.Viewport.X;
-                    currentLocation.Y = startOffsetY + start.Viewport.Y;
-
-                    // start is the deepest subview under the mouse; stop searching the subviews
-                    break;
-                }
-            }
-
-            if (subview is null)
-            {
-                // No subview was found that's under the mouse, so we're done
-                return start;
-            }
-
-            // We found a subview of start that's under the mouse, continue...
-            start = subview;
-        }
+    public event EventHandler<LayoutEventArgs> LayoutComplete;
 
 
-        return null;
-    }
+    /// <summary>Fired after the View's <see cref="LayoutSubviews"/> method has completed.</summary>
+    /// <remarks>
+    ///     Subscribe to this event to perform tasks when the <see cref="View"/> has been resized or the layout has
+    ///     otherwise changed.
+    /// </remarks>
+    public event EventHandler<LayoutEventArgs> LayoutStarted;
 
 
     /// <summary>
     /// <summary>
-    ///     Gets a new location of the <see cref="View"/> that is within the Viewport of the <paramref name="viewToMove"/>'s
-    ///     <see cref="View.SuperView"/> (e.g. for dragging a Window). The `out` parameters are the new X and Y coordinates.
+    ///     Adjusts <see cref="Frame"/> given the SuperView's ContentSize (nominally the same as
+    ///     <c>this.SuperView.GetContentSize ()</c>)
+    ///     and the position (<see cref="X"/>, <see cref="Y"/>) and dimension (<see cref="Width"/>, and
+    ///     <see cref="Height"/>).
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
-    ///     If <paramref name="viewToMove"/> does not have a <see cref="View.SuperView"/> or it's SuperView is not
-    ///     <see cref="Application.Top"/> the position will be bound by the <see cref="ConsoleDriver.Cols"/> and
-    ///     <see cref="ConsoleDriver.Rows"/>.
+    ///     <para>
+    ///         If <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, or <see cref="Height"/> are
+    ///         absolute, they will be updated to reflect the new size and position of the view. Otherwise, they
+    ///         are left unchanged.
+    ///     </para>
+    ///     <para>
+    ///         If any of the view's subviews have a position or dimension dependent on either <see cref="GetContentSize"/> or
+    ///         other subviews, <see cref="LayoutSubview"/> on
+    ///         will be called for that subview.
+    ///     </para>
     /// </remarks>
     /// </remarks>
-    /// <param name="viewToMove">The View that is to be moved.</param>
-    /// <param name="targetX">The target x location.</param>
-    /// <param name="targetY">The target y location.</param>
-    /// <param name="nx">The new x location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
-    /// <param name="ny">The new y location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
-    /// <param name="statusBar">The new top most statusBar</param>
-    /// <returns>
-    ///     Either <see cref="Application.Top"/> (if <paramref name="viewToMove"/> does not have a Super View) or
-    ///     <paramref name="viewToMove"/>'s SuperView. This can be used to ensure LayoutSubviews is called on the correct View.
-    /// </returns>
-    internal static View GetLocationEnsuringFullVisibility (
-        View viewToMove,
-        int targetX,
-        int targetY,
-        out int nx,
-        out int ny,
-        out StatusBar statusBar
-    )
+    /// <param name="superviewContentSize">
+    ///     The size of the SuperView's content (nominally the same as <c>this.SuperView.GetContentSize ()</c>).
+    /// </param>
+    internal void SetRelativeLayout (Size superviewContentSize)
     {
     {
-        int maxDimension;
-        View superView;
-        statusBar = null!;
+        Debug.Assert (_x is { });
+        Debug.Assert (_y is { });
+        Debug.Assert (_width is { });
+        Debug.Assert (_height is { });
 
 
-        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
+        CheckDimAuto ();
+        SetTextFormatterSize ();
+
+        int newX, newW, newY, newH;
+
+        // Calculate the new X, Y, Width, and Height
+        // If the Width or Height is Dim.Auto, calculate the Width or Height first. Otherwise, calculate the X or Y first.
+        if (_width is DimAuto)
         {
         {
-            maxDimension = Driver.Cols;
-            superView = Application.Top;
+            newW = _width.Calculate (0, superviewContentSize.Width, this, Dimension.Width);
+            newX = _x.Calculate (superviewContentSize.Width, newW, this, Dimension.Width);
         }
         }
         else
         else
         {
         {
-            // Use the SuperView's Viewport, not Frame
-            maxDimension = viewToMove!.SuperView.Viewport.Width;
-            superView = viewToMove.SuperView;
-        }
-
-        if (superView?.Margin is { } && superView == viewToMove!.SuperView)
-        {
-            maxDimension -= superView.GetAdornmentsThickness ().Left + superView.GetAdornmentsThickness ().Right;
+            newX = _x.Calculate (superviewContentSize.Width, _width, this, Dimension.Width);
+            newW = _width.Calculate (newX, superviewContentSize.Width, this, Dimension.Width);
         }
         }
 
 
-        if (viewToMove!.Frame.Width <= maxDimension)
+        if (_height is DimAuto)
         {
         {
-            nx = Math.Max (targetX, 0);
-            nx = nx + viewToMove.Frame.Width > maxDimension ? Math.Max (maxDimension - viewToMove.Frame.Width, 0) : nx;
-
-            if (nx > viewToMove.Frame.X + viewToMove.Frame.Width)
-            {
-                nx = Math.Max (viewToMove.Frame.Right, 0);
-            }
+            newH = _height.Calculate (0, superviewContentSize.Height, this, Dimension.Height);
+            newY = _y.Calculate (superviewContentSize.Height, newH, this, Dimension.Height);
         }
         }
         else
         else
         {
         {
-            nx = targetX;
+            newY = _y.Calculate (superviewContentSize.Height, _height, this, Dimension.Height);
+            newH = _height.Calculate (newY, superviewContentSize.Height, this, Dimension.Height);
         }
         }
 
 
-        //System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
-        var menuVisible = false;
-        var statusVisible = false;
+        Rectangle newFrame = new (newX, newY, newW, newH);
 
 
-        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
-        {
-            menuVisible = Application.Top?.MenuBar?.Visible == true;
-        }
-        else
+        if (Frame != newFrame)
         {
         {
-            View t = viewToMove!.SuperView;
+            // Set the frame. Do NOT use `Frame` as it overwrites X, Y, Width, and Height
+            SetFrame (newFrame);
 
 
-            while (t is { } and not Toplevel)
+            if (_x is PosAbsolute)
             {
             {
-                t = t.SuperView;
+                _x = Frame.X;
             }
             }
 
 
-            if (t is Toplevel topLevel)
+            if (_y is PosAbsolute)
             {
             {
-                menuVisible = topLevel.MenuBar?.Visible == true;
+                _y = Frame.Y;
             }
             }
-        }
-
-        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
-        {
-            maxDimension = menuVisible ? 1 : 0;
-        }
-        else
-        {
-            maxDimension = 0;
-        }
-
-        ny = Math.Max (targetY, maxDimension);
 
 
-        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
-        {
-            statusVisible = Application.Top?.StatusBar?.Visible == true;
-            statusBar = Application.Top?.StatusBar!;
-        }
-        else
-        {
-            View t = viewToMove!.SuperView;
+            if (_width is DimAbsolute)
+            {
+                _width = Frame.Width;
+            }
 
 
-            while (t is { } and not Toplevel)
+            if (_height is DimAbsolute)
             {
             {
-                t = t.SuperView;
+                _height = Frame.Height;
             }
             }
 
 
-            if (t is Toplevel topLevel)
+            if (!string.IsNullOrEmpty (Title))
             {
             {
-                statusVisible = topLevel.StatusBar?.Visible == true;
-                statusBar = topLevel.StatusBar!;
+                SetTitleTextFormatterSize ();
             }
             }
-        }
 
 
-        if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
-        {
-            maxDimension = statusVisible ? Driver.Rows - 1 : Driver.Rows;
-        }
-        else
-        {
-            maxDimension = statusVisible ? viewToMove!.SuperView.Viewport.Height - 1 : viewToMove!.SuperView.Viewport.Height;
+            SetNeedsLayout ();
+            SetNeedsDisplay ();
         }
         }
 
 
-        if (superView?.Margin is { } && superView == viewToMove?.SuperView)
+        if (TextFormatter.ConstrainToWidth is null)
         {
         {
-            maxDimension -= superView.GetAdornmentsThickness ().Top + superView.GetAdornmentsThickness ().Bottom;
+            TextFormatter.ConstrainToWidth = GetContentSize ().Width;
         }
         }
 
 
-        ny = Math.Min (ny, maxDimension);
-
-        if (viewToMove?.Frame.Height <= maxDimension)
+        if (TextFormatter.ConstrainToHeight is null)
         {
         {
-            ny = ny + viewToMove.Frame.Height > maxDimension
-                     ? Math.Max (maxDimension - viewToMove.Frame.Height, menuVisible ? 1 : 0)
-                     : ny;
-
-            if (ny > viewToMove.Frame.Y + viewToMove.Frame.Height)
-            {
-                ny = Math.Max (viewToMove.Frame.Bottom, 0);
-            }
+            TextFormatter.ConstrainToHeight = GetContentSize ().Height;
         }
         }
-
-        //System.Diagnostics.Debug.WriteLine ($"ny:{ny}, rHeight:{rHeight}");
-
-        return superView!;
     }
     }
 
 
-    /// <summary>Fired after the View's <see cref="LayoutSubviews"/> method has completed.</summary>
-    /// <remarks>
-    ///     Subscribe to this event to perform tasks when the <see cref="View"/> has been resized or the layout has
-    ///     otherwise changed.
-    /// </remarks>
-    public event EventHandler<LayoutEventArgs> LayoutComplete;
-
-    /// <summary>Fired after the View's <see cref="LayoutSubviews"/> method has completed.</summary>
-    /// <remarks>
-    ///     Subscribe to this event to perform tasks when the <see cref="View"/> has been resized or the layout has
-    ///     otherwise changed.
-    /// </remarks>
-    public event EventHandler<LayoutEventArgs> LayoutStarted;
-
     /// <summary>
     /// <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 the dimensions of the view have changed, for example in response to the container view or terminal
+    ///     resizing.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
@@ -570,13 +685,11 @@ public partial class View
 
 
         CheckDimAuto ();
         CheckDimAuto ();
 
 
-        var contentSize = GetContentSize ();
+        Size contentSize = GetContentSize ();
         OnLayoutStarted (new (contentSize));
         OnLayoutStarted (new (contentSize));
 
 
         LayoutAdornments ();
         LayoutAdornments ();
 
 
-        SetTextFormatterSize ();
-
         // Sort out the dependencies of the X, Y, Width, Height properties
         // Sort out the dependencies of the X, Y, Width, Height properties
         HashSet<View> nodes = new ();
         HashSet<View> nodes = new ();
         HashSet<(View, View)> edges = new ();
         HashSet<(View, View)> edges = new ();
@@ -605,7 +718,7 @@ public partial class View
 
 
     private void LayoutSubview (View v, Size contentSize)
     private void LayoutSubview (View v, Size contentSize)
     {
     {
-        // BUGBUG: Calling SetRelativeLayout before LayoutSubviews is problematic. Need to resolve.
+        // Note, SetRelativeLayout calls SetTextFormatterSize
         v.SetRelativeLayout (contentSize);
         v.SetRelativeLayout (contentSize);
         v.LayoutSubviews ();
         v.LayoutSubviews ();
         v.LayoutNeeded = false;
         v.LayoutNeeded = false;
@@ -620,9 +733,6 @@ public partial class View
     /// </summary>
     /// </summary>
     internal virtual void OnLayoutComplete (LayoutEventArgs args) { LayoutComplete?.Invoke (this, args); }
     internal virtual void OnLayoutComplete (LayoutEventArgs args) { LayoutComplete?.Invoke (this, args); }
 
 
-    // BUGBUG: We need an API/event that is called from SetRelativeLayout instead of/in addition to 
-    // BUGBUG: OnLayoutStarted which is called from LayoutSubviews.
-
     /// <summary>
     /// <summary>
     ///     Raises the <see cref="LayoutStarted"/> event. Called from  <see cref="LayoutSubviews"/> before any subviews
     ///     Raises the <see cref="LayoutStarted"/> event. Called from  <see cref="LayoutSubviews"/> before any subviews
     ///     have been laid out.
     ///     have been laid out.
@@ -646,12 +756,10 @@ public partial class View
 
 
         // Determine our container's ContentSize -
         // Determine our container's ContentSize -
         //  First try SuperView.Viewport, then Application.Top, then Driver.Viewport.
         //  First try SuperView.Viewport, then Application.Top, then Driver.Viewport.
-        //  Finally, if none of those are valid, use int.MaxValue (for Unit tests).
+        //  Finally, if none of those are valid, use 2048 (for Unit tests).
         Size superViewContentSize = SuperView is { IsInitialized: true } ? SuperView.GetContentSize () :
         Size superViewContentSize = SuperView is { IsInitialized: true } ? SuperView.GetContentSize () :
-                           Application.Top is { } && Application.Top != this && Application.Top.IsInitialized ? Application.Top.GetContentSize () :
-                           Application.Driver?.Screen.Size ?? new (int.MaxValue, int.MaxValue);
-
-        SetTextFormatterSize ();
+                                    Application.Top is { } && Application.Top != this && Application.Top.IsInitialized ? Application.Top.GetContentSize () :
+                                    Application.Screen.Size;
 
 
         SetRelativeLayout (superViewContentSize);
         SetRelativeLayout (superViewContentSize);
 
 
@@ -689,90 +797,15 @@ public partial class View
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Adjusts <see cref="Frame"/> given the SuperView's ContentSize (nominally the same as
-    ///     <c>this.SuperView.GetContentSize ()</c>)
-    ///     and the position (<see cref="X"/>, <see cref="Y"/>) and dimension (<see cref="Width"/>, and
-    ///     <see cref="Height"/>).
+    ///     Collects all views and their dependencies from a given starting view for layout purposes. Used by
+    ///     <see cref="TopologicalSort"/> to create an ordered list of views to layout.
     /// </summary>
     /// </summary>
-    /// <remarks>
-    ///     <para>
-    ///         If <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, or <see cref="Height"/> are
-    ///         absolute, they will be updated to reflect the new size and position of the view. Otherwise, they
-    ///         are left unchanged.
-    ///     </para>
-    /// </remarks>
-    /// <param name="superviewContentSize">
-    ///     The size of the SuperView's content (nominally the same as <c>this.SuperView.GetContentSize ()</c>).
+    /// <param name="from">The starting view from which to collect dependencies.</param>
+    /// <param name="nNodes">A reference to a set of views representing nodes in the layout graph.</param>
+    /// <param name="nEdges">
+    ///     A reference to a set of tuples representing edges in the layout graph, where each tuple consists of a pair of views
+    ///     indicating a dependency.
     /// </param>
     /// </param>
-    internal void SetRelativeLayout (Size superviewContentSize)
-    {
-        Debug.Assert (_x is { });
-        Debug.Assert (_y is { });
-        Debug.Assert (_width is { });
-        Debug.Assert (_height is { });
-
-        CheckDimAuto ();
-        int newX, newW, newY, newH;
-
-        if (_width is DimAuto)
-        {
-            newW = _width.Calculate (0, superviewContentSize.Width, this, Dimension.Width);
-            newX = _x.Calculate (superviewContentSize.Width, newW, this, Dimension.Width);
-        }
-        else
-        {
-            newX = _x.Calculate (superviewContentSize.Width, _width, this, Dimension.Width);
-            newW = _width.Calculate (newX, superviewContentSize.Width, this, Dimension.Width);
-        }
-
-        if (_height is DimAuto)
-        {
-            newH = _height.Calculate (0, superviewContentSize.Height, this, Dimension.Height);
-            newY = _y.Calculate (superviewContentSize.Height, newH, this, Dimension.Height);
-        }
-        else
-        {
-            newY = _y.Calculate (superviewContentSize.Height, _height, this, Dimension.Height);
-            newH = _height.Calculate (newY, superviewContentSize.Height, this, Dimension.Height);
-        }
-
-        Rectangle newFrame = new (newX, newY, newW, newH);
-
-        if (Frame != newFrame)
-        {
-            // Set the frame. Do NOT use `Frame` as it overwrites X, Y, Width, and Height
-            SetFrame (newFrame);
-
-            if (_x is PosAbsolute)
-            {
-                _x = Frame.X;
-            }
-
-            if (_y is PosAbsolute)
-            {
-                _y = Frame.Y;
-            }
-
-            if (_width is DimAbsolute)
-            {
-                _width = Frame.Width;
-            }
-
-            if (_height is DimAbsolute)
-            {
-                _height = Frame.Height;
-            }
-
-            if (!string.IsNullOrEmpty (Title))
-            {
-                SetTitleTextFormatterSize ();
-            }
-
-            SetNeedsLayout ();
-            SetNeedsDisplay ();
-        }
-    }
-
     internal void CollectAll (View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
     internal void CollectAll (View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
     {
     {
         foreach (View? v in from.InternalSubviews)
         foreach (View? v in from.InternalSubviews)
@@ -785,6 +818,16 @@ public partial class View
         }
         }
     }
     }
 
 
+    /// <summary>
+    ///     Collects dimension (where Width or Height is `DimView`) dependencies for a given view.
+    /// </summary>
+    /// <param name="dim">The dimension (width or height) to collect dependencies for.</param>
+    /// <param name="from">The view for which to collect dimension dependencies.</param>
+    /// <param name="nNodes">A reference to a set of views representing nodes in the layout graph.</param>
+    /// <param name="nEdges">
+    ///     A reference to a set of tuples representing edges in the layout graph, where each tuple consists of a pair of views
+    ///     indicating a dependency.
+    /// </param>
     internal void CollectDim (Dim? dim, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
     internal void CollectDim (Dim? dim, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
     {
     {
         switch (dim)
         switch (dim)
@@ -808,6 +851,16 @@ public partial class View
         }
         }
     }
     }
 
 
+    /// <summary>
+    ///     Collects position (where X or Y is `PosView`) dependencies for a given view.
+    /// </summary>
+    /// <param name="pos">The position (X or Y) to collect dependencies for.</param>
+    /// <param name="from">The view for which to collect position dependencies.</param>
+    /// <param name="nNodes">A reference to a set of views representing nodes in the layout graph.</param>
+    /// <param name="nEdges">
+    ///     A reference to a set of tuples representing edges in the layout graph, where each tuple consists of a pair of views
+    ///     indicating a dependency.
+    /// </param>
     internal void CollectPos (Pos pos, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
     internal void CollectPos (Pos pos, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
     {
     {
         switch (pos)
         switch (pos)
@@ -966,7 +1019,6 @@ public partial class View
     /// </remarks>
     /// </remarks>
     public bool ValidatePosDim { get; set; }
     public bool ValidatePosDim { get; set; }
 
 
-
     // TODO: Move this logic into the Pos/Dim classes
     // TODO: Move this logic into the Pos/Dim classes
     /// <summary>
     /// <summary>
     ///     Throws an <see cref="InvalidOperationException"/> if any SubViews are using Dim objects that depend on this
     ///     Throws an <see cref="InvalidOperationException"/> if any SubViews are using Dim objects that depend on this
@@ -980,8 +1032,8 @@ public partial class View
             return;
             return;
         }
         }
 
 
-        DimAuto? widthAuto = Width as DimAuto;
-        DimAuto? heightAuto = Height as DimAuto;
+        var widthAuto = Width as DimAuto;
+        var heightAuto = Height as DimAuto;
 
 
         // Verify none of the subviews are using Dim objects that depend on the SuperView's dimensions.
         // Verify none of the subviews are using Dim objects that depend on the SuperView's dimensions.
         foreach (View view in Subviews)
         foreach (View view in Subviews)
@@ -1046,8 +1098,10 @@ public partial class View
                 throw new InvalidOperationException (
                 throw new InvalidOperationException (
                                                      $"{view.GetType ().Name}.{name} = {bad.GetType ().Name} "
                                                      $"{view.GetType ().Name}.{name} = {bad.GetType ().Name} "
                                                      + $"which depends on the SuperView's dimensions and the SuperView uses Dim.Auto."
                                                      + $"which depends on the SuperView's dimensions and the SuperView uses Dim.Auto."
-                                                     );
+                                                    );
             }
             }
         }
         }
     }
     }
+
+    #endregion Layout Engine
 }
 }

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

@@ -479,7 +479,7 @@ public partial class View : Responder, ISupportInitializeNotification
 
 
     private void SetTitleTextFormatterSize ()
     private void SetTitleTextFormatterSize ()
     {
     {
-        TitleTextFormatter.Size = new (
+        TitleTextFormatter.ConstrainToSize = new (
                                        TextFormatter.GetWidestLineLength (TitleTextFormatter.Text)
                                        TextFormatter.GetWidestLineLength (TitleTextFormatter.Text)
                                        - (TitleTextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
                                        - (TitleTextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
                                               ? Math.Max (HotKeySpecifier.GetColumns (), 0)
                                               ? Math.Max (HotKeySpecifier.GetColumns (), 0)

+ 73 - 66
Terminal.Gui/View/ViewText.cs

@@ -4,17 +4,14 @@ namespace Terminal.Gui;
 
 
 public partial class View
 public partial class View
 {
 {
+    private string _text;
+
     /// <summary>
     /// <summary>
-    ///    Initializes the Text of the View. Called by the constructor.
+    ///     Called when the <see cref="Text"/> has changed. Fires the <see cref="TextChanged"/> event.
     /// </summary>
     /// </summary>
-    private void SetupText ()
-    {
-        Text = string.Empty;
-        TextDirection = TextDirection.LeftRight_TopBottom;
-    }
-
-    private string _text;
+    public void OnTextChanged () { TextChanged?.Invoke (this, EventArgs.Empty); }
 
 
+    // TODO: Make this non-virtual. Nobody overrides it.
     /// <summary>
     /// <summary>
     ///     Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved
     ///     Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved
     ///     or not when <see cref="TextFormatter.WordWrap"/> is enabled.
     ///     or not when <see cref="TextFormatter.WordWrap"/> is enabled.
@@ -46,11 +43,14 @@ public partial class View
     ///         to <see cref="TextAlignment"/> and <see cref="TextDirection"/>.
     ///         to <see cref="TextAlignment"/> and <see cref="TextDirection"/>.
     ///     </para>
     ///     </para>
     ///     <para>
     ///     <para>
-    ///         The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="GetContentSize ()"/>'s height
+    ///         The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="GetContentSize ()"/>
+    ///         's height
     ///         is 1, the text will be clipped.
     ///         is 1, the text will be clipped.
     ///     </para>
     ///     </para>
-    ///     <para>If <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="DimAutoStyle.Text"/>,
-    ///     the <see cref="GetContentSize ()"/> will be adjusted to fit the text.</para>
+    ///     <para>
+    ///         If <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="DimAutoStyle.Text"/>,
+    ///         the <see cref="GetContentSize ()"/> will be adjusted to fit the text.
+    ///     </para>
     ///     <para>When the text changes, the <see cref="TextChanged"/> is fired.</para>
     ///     <para>When the text changes, the <see cref="TextChanged"/> is fired.</para>
     /// </remarks>
     /// </remarks>
     public virtual string Text
     public virtual string Text
@@ -73,25 +73,16 @@ public partial class View
         }
         }
     }
     }
 
 
-    /// <summary>
-    /// Called when the <see cref="Text"/> has changed. Fires the <see cref="TextChanged"/> event.
-    /// </summary>
-    public void OnTextChanged ()
-    {
-        TextChanged?.Invoke (this, EventArgs.Empty);
-    }
-
-    /// <summary>
-    ///     Text changed event, raised when the text has changed.
-    /// </summary>
-    public event EventHandler? TextChanged;
-
+    // TODO: Make this non-virtual. Nobody overrides it.
     /// <summary>
     /// <summary>
     ///     Gets or sets how the View's <see cref="Text"/> is aligned horizontally when drawn. Changing this property will
     ///     Gets or sets how the View's <see cref="Text"/> is aligned horizontally when drawn. Changing this property will
     ///     redisplay the <see cref="View"/>.
     ///     redisplay the <see cref="View"/>.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
-    ///     <para> <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="DimAutoStyle.Text"/>, the <see cref="GetContentSize ()"/> will be adjusted to fit the text.</para>
+    ///     <para>
+    ///         <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="DimAutoStyle.Text"/>, the
+    ///         <see cref="GetContentSize ()"/> will be adjusted to fit the text.
+    ///     </para>
     /// </remarks>
     /// </remarks>
     /// <value>The text alignment.</value>
     /// <value>The text alignment.</value>
     public virtual Alignment TextAlignment
     public virtual Alignment TextAlignment
@@ -105,36 +96,45 @@ public partial class View
         }
         }
     }
     }
 
 
+    /// <summary>
+    ///     Text changed event, raised when the text has changed.
+    /// </summary>
+    public event EventHandler? TextChanged;
+
+    // TODO: Make this non-virtual. Nobody overrides it.
     /// <summary>
     /// <summary>
     ///     Gets or sets the direction of the View's <see cref="Text"/>. Changing this property will redisplay the
     ///     Gets or sets the direction of the View's <see cref="Text"/>. Changing this property will redisplay the
     ///     <see cref="View"/>.
     ///     <see cref="View"/>.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
-    ///     <para> <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="DimAutoStyle.Text"/>, the <see cref="GetContentSize ()"/> will be adjusted to fit the text.</para>
+    ///     <para>
+    ///         <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="DimAutoStyle.Text"/>, the
+    ///         <see cref="GetContentSize ()"/> will be adjusted to fit the text.
+    ///     </para>
     /// </remarks>
     /// </remarks>
     /// <value>The text direction.</value>
     /// <value>The text direction.</value>
     public virtual TextDirection TextDirection
     public virtual TextDirection TextDirection
     {
     {
         get => TextFormatter.Direction;
         get => TextFormatter.Direction;
-        set
-        {
-            UpdateTextDirection (value);
-            TextFormatter.Direction = value;
-        }
+        set => UpdateTextDirection (value);
     }
     }
 
 
     /// <summary>
     /// <summary>
     ///     Gets or sets the <see cref="Gui.TextFormatter"/> used to format <see cref="Text"/>.
     ///     Gets or sets the <see cref="Gui.TextFormatter"/> used to format <see cref="Text"/>.
     /// </summary>
     /// </summary>
-    public TextFormatter TextFormatter { get; init; } = new () { };
+    public TextFormatter TextFormatter { get; init; } = new ();
 
 
+    // TODO: Make this non-virtual. Nobody overrides it.
     /// <summary>
     /// <summary>
     ///     Gets or sets how the View's <see cref="Text"/> is aligned vertically when drawn. Changing this property will
     ///     Gets or sets how the View's <see cref="Text"/> is aligned vertically when drawn. Changing this property will
     ///     redisplay
     ///     redisplay
     ///     the <see cref="View"/>.
     ///     the <see cref="View"/>.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
-    ///     <para> <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="DimAutoStyle.Text"/>, the <see cref="GetContentSize ()"/> will be adjusted to fit the text.</para>
+    ///     <para>
+    ///         <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="DimAutoStyle.Text"/>, the
+    ///         <see cref="GetContentSize ()"/> will be adjusted to fit the text.
+    ///     </para>
     /// </remarks>
     /// </remarks>
     /// <value>The vertical text alignment.</value>
     /// <value>The vertical text alignment.</value>
     public virtual Alignment VerticalTextAlignment
     public virtual Alignment VerticalTextAlignment
@@ -147,35 +147,26 @@ public partial class View
         }
         }
     }
     }
 
 
+    // TODO: Add a OnUpdateTextFormatterText method that invokes UpdateTextFormatterText so that overrides don't have to call base.
     /// <summary>
     /// <summary>
-    ///     Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has
+    ///     Can be overridden if the <see cref="TextFormatter.Text"/> has
     ///     different format than the default.
     ///     different format than the default.
     /// </summary>
     /// </summary>
+    /// <remarks>
+    ///     Overrides must call <c>base.UpdateTextFormatterText</c> before updating <see cref="TextFormatter.Text"/>.
+    /// </remarks>
     protected virtual void UpdateTextFormatterText ()
     protected virtual void UpdateTextFormatterText ()
     {
     {
-        if (TextFormatter is { })
-        {
-            TextFormatter.Text = _text;
-        }
-    }
-
-    /// <summary>
-    ///     Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="TextFormatter.HotKeySpecifier"/>.
-    /// </summary>
-    /// <returns></returns>
-    internal Size GetSizeNeededForTextWithoutHotKey ()
-    {
-        return new Size (
-                         TextFormatter.Size.Width - TextFormatter.GetHotKeySpecifierLength (),
-                         TextFormatter.Size.Height - TextFormatter.GetHotKeySpecifierLength (false));
+        TextFormatter.Text = _text;
+        TextFormatter.ConstrainToWidth = null;
+        TextFormatter.ConstrainToHeight = null;
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Internal API. Sets <see cref="TextFormatter"/>.Size to the current <see cref="Viewport"/> size, adjusted for
-    ///     <see cref="TextFormatter.HotKeySpecifier"/>.
+    ///     Internal API. Sets <see cref="TextFormatter"/>.Width/Height.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
-    ///     Use this API to set <see cref="TextFormatter.Size"/> when the view has changed such that the
+    ///     Use this API to set <see cref="Gui.TextFormatter.ConstrainToWidth"/>/Height when the view has changed such that the
     ///     size required to fit the text has changed.
     ///     size required to fit the text has changed.
     ///     changes.
     ///     changes.
     /// </remarks>
     /// </remarks>
@@ -187,29 +178,44 @@ public partial class View
         UpdateTextFormatterText ();
         UpdateTextFormatterText ();
 
 
         // Default is to use GetContentSize ().
         // Default is to use GetContentSize ().
-        var size = GetContentSize ();
+        Size? size = _contentSize;
 
 
-        // TODO: This is a hack. Figure out how to move this into DimDimAuto
         // Use _width & _height instead of Width & Height to avoid debug spew
         // Use _width & _height instead of Width & Height to avoid debug spew
-        DimAuto? widthAuto = _width as DimAuto;
-        DimAuto? heightAuto = _height as DimAuto;
-        if ((widthAuto is { } && widthAuto.Style.FastHasFlags (DimAutoStyle.Text))
-            || (heightAuto is { } && heightAuto.Style.FastHasFlags (DimAutoStyle.Text)))
-        {
-            size = TextFormatter.GetAutoSize ();
+        var widthAuto = _width as DimAuto;
+        var heightAuto = _height as DimAuto;
 
 
-            if (widthAuto is null || !widthAuto.Style.FastHasFlags (DimAutoStyle.Text))
+        if (widthAuto is { } && widthAuto.Style.FastHasFlags (DimAutoStyle.Text))
+        {
+            TextFormatter.ConstrainToWidth = null;
+        }
+        else
+        {
+            if (size is { })
             {
             {
-                size.Width = GetContentSize ().Width;
+                TextFormatter.ConstrainToWidth = size?.Width;
             }
             }
+        }
 
 
-            if (heightAuto is null || !heightAuto.Style.FastHasFlags (DimAutoStyle.Text))
+        if (heightAuto is { } && heightAuto.Style.FastHasFlags (DimAutoStyle.Text))
+        {
+            TextFormatter.ConstrainToHeight = null;
+        }
+        else
+        {
+            if (size is { })
             {
             {
-                size.Height = GetContentSize ().Height;
+                TextFormatter.ConstrainToHeight = size?.Height;
             }
             }
         }
         }
+    }
 
 
-        TextFormatter.Size = size;
+    /// <summary>
+    ///     Initializes the Text of the View. Called by the constructor.
+    /// </summary>
+    private void SetupText ()
+    {
+        Text = string.Empty;
+        TextDirection = TextDirection.LeftRight_TopBottom;
     }
     }
 
 
     private void UpdateTextDirection (TextDirection newDirection)
     private void UpdateTextDirection (TextDirection newDirection)
@@ -221,10 +227,11 @@ public partial class View
 
 
         if (directionChanged)
         if (directionChanged)
         {
         {
+            TextFormatter.ConstrainToWidth = null;
+            TextFormatter.ConstrainToHeight = null;
             OnResizeNeeded ();
             OnResizeNeeded ();
         }
         }
 
 
-        SetTextFormatterSize ();
         SetNeedsDisplay ();
         SetNeedsDisplay ();
     }
     }
 }
 }

+ 1 - 3
Terminal.Gui/Views/Bar.cs

@@ -153,11 +153,9 @@ public class Bar : View
                     barItem.ColorScheme = ColorScheme;
                     barItem.ColorScheme = ColorScheme;
                     barItem.X = Pos.Align (Alignment.Start, AlignmentModes);
                     barItem.X = Pos.Align (Alignment.Start, AlignmentModes);
                     barItem.Y = 0; //Pos.Center ();
                     barItem.Y = 0; //Pos.Center ();
-
                     // HACK: This should not be needed
                     // HACK: This should not be needed
                     barItem.SetRelativeLayout (GetContentSize ());
                     barItem.SetRelativeLayout (GetContentSize ());
                 }
                 }
-
                 break;
                 break;
 
 
             case Orientation.Vertical:
             case Orientation.Vertical:
@@ -168,7 +166,7 @@ public class Bar : View
                 List<Shortcut> shortcuts = Subviews.Where (s => s is Shortcut && s.Visible).Cast<Shortcut> ().ToList ();
                 List<Shortcut> shortcuts = Subviews.Where (s => s is Shortcut && s.Visible).Cast<Shortcut> ().ToList ();
                 foreach (Shortcut shortcut in shortcuts)
                 foreach (Shortcut shortcut in shortcuts)
                 {
                 {
-                    // Let AutoSize do its thing to get the minimum width of each CommandView and HelpView
+                    // Let DimAuto do its thing to get the minimum width of each CommandView and HelpView
                     //shortcut.CommandView.SetRelativeLayout (new Size (int.MaxValue, int.MaxValue));
                     //shortcut.CommandView.SetRelativeLayout (new Size (int.MaxValue, int.MaxValue));
                     minKeyWidth = int.Max (minKeyWidth, shortcut.KeyView.Text.GetColumns ());
                     minKeyWidth = int.Max (minKeyWidth, shortcut.KeyView.Text.GetColumns ());
                 }
                 }

+ 1 - 0
Terminal.Gui/Views/Button.cs

@@ -170,6 +170,7 @@ public class Button : View, IDesignable
     /// <inheritdoc/>
     /// <inheritdoc/>
     protected override void UpdateTextFormatterText ()
     protected override void UpdateTextFormatterText ()
     {
     {
+        base.UpdateTextFormatterText();
         if (NoDecorations)
         if (NoDecorations)
         {
         {
             TextFormatter.Text = Text;
             TextFormatter.Text = Text;

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

@@ -1,16 +1,6 @@
 #nullable enable
 #nullable enable
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
-/// <summary>
-///     Represents the state of a <see cref="CheckBox"/>.
-/// </summary>
-public enum CheckState
-{
-    None,
-    Checked,
-    UnChecked
-}
-
 /// <summary>Shows a check box that can be toggled.</summary>
 /// <summary>Shows a check box that can be toggled.</summary>
 public class CheckBox : View
 public class CheckBox : View
 {
 {
@@ -182,6 +172,7 @@ public class CheckBox : View
     /// <inheritdoc/>
     /// <inheritdoc/>
     protected override void UpdateTextFormatterText ()
     protected override void UpdateTextFormatterText ()
     {
     {
+        base.UpdateTextFormatterText();
         switch (TextAlignment)
         switch (TextAlignment)
         {
         {
             case Alignment.Start:
             case Alignment.Start:

+ 23 - 0
Terminal.Gui/Views/CheckState.cs

@@ -0,0 +1,23 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Represents the state of a <see cref="CheckBox"/>.
+/// </summary>
+public enum CheckState
+{
+    /// <summary>
+    ///     Neither checked nor unchecked.
+    /// </summary>
+    None,
+
+    /// <summary>
+    ///     Checked.
+    /// </summary>
+    Checked,
+
+    /// <summary>
+    ///     Not checked.
+    /// </summary>
+    UnChecked
+}

+ 0 - 3
Terminal.Gui/Views/DatePicker.cs

@@ -276,9 +276,6 @@ public class DatePicker : View
         Width = Dim.Auto (DimAutoStyle.Content);
         Width = Dim.Auto (DimAutoStyle.Content);
         Height = Dim.Auto (DimAutoStyle.Content);
         Height = Dim.Auto (DimAutoStyle.Content);
 
 
-        // BUGBUG: Remove when Dim.Auto(subviews) fully works
-        SetContentSize (new (_calendar.Style.ColumnStyles.Sum (c => c.Value.MinWidth) + 7, _calendar.Frame.Height + 1));
-
         _dateField.DateChanged += DateField_DateChanged;
         _dateField.DateChanged += DateField_DateChanged;
 
 
         Add (_dateLabel, _dateField, _calendar, _previousMonthButton, _nextMonthButton);
         Add (_dateLabel, _dateField, _calendar, _previousMonthButton, _nextMonthButton);

+ 4 - 4
Terminal.Gui/Views/Dialog.cs

@@ -33,14 +33,14 @@ public class Dialog : Window
     ///     <see cref="ConfigurationManager"/>.
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static int DefaultMinimumWidth { get; set; } = 25;
+    public static int DefaultMinimumWidth { get; set; } = 80;
 
 
     /// <summary>
     /// <summary>
     ///     Defines the default minimum Dialog height, as a percentage of the container width. Can be configured via
     ///     Defines the default minimum Dialog height, as a percentage of the container width. Can be configured via
     ///     <see cref="ConfigurationManager"/>.
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static int DefaultMinimumHeight { get; set; } = 25;
+    public static int DefaultMinimumHeight { get; set; } = 80;
 
 
 
 
     /// <summary>
     /// <summary>
@@ -78,9 +78,9 @@ public class Dialog : Window
 
 
         X = Pos.Center ();
         X = Pos.Center ();
         Y = Pos.Center ();
         Y = Pos.Center ();
+        Width = Dim.Auto (DimAutoStyle.Auto, Dim.Percent (DefaultMinimumWidth), Dim.Percent (90));
+        Height = Dim.Auto (DimAutoStyle.Auto, Dim.Percent (DefaultMinimumHeight), Dim.Percent (90));
 
 
-        Width = Dim.Auto (DimAutoStyle.Content, Dim.Percent (DefaultMinimumWidth), Dim.Percent (90));
-        Height = Dim.Auto (DimAutoStyle.Content, Dim.Percent (DefaultMinimumHeight), Dim.Percent (90));
         ColorScheme = Colors.ColorSchemes ["Dialog"];
         ColorScheme = Colors.ColorSchemes ["Dialog"];
 
 
         Modal = true;
         Modal = true;

+ 3 - 0
Terminal.Gui/Views/FileDialog.cs

@@ -60,6 +60,9 @@ public class FileDialog : Dialog
     /// <remarks>This overload is mainly useful for testing.</remarks>
     /// <remarks>This overload is mainly useful for testing.</remarks>
     internal FileDialog (IFileSystem fileSystem)
     internal FileDialog (IFileSystem fileSystem)
     {
     {
+        Height = Dim.Percent (80);
+        Width = Dim.Percent (80);
+
         // Assume canceled
         // Assume canceled
         Canceled = true;
         Canceled = true;
 
 

+ 1 - 1
Terminal.Gui/Views/Menu/ContextMenu.cs

@@ -144,7 +144,7 @@ public sealed class ContextMenu : IDisposable
         _container = Application.Current;
         _container = Application.Current;
         _container.Closing += Container_Closing;
         _container.Closing += Container_Closing;
         _container.Deactivate += Container_Deactivate;
         _container.Deactivate += Container_Deactivate;
-        Rectangle frame = Application.Driver.Screen;
+        Rectangle frame = Application.Screen;
         Point position = Position;
         Point position = Position;
 
 
         if (Host is { })
         if (Host is { })

+ 2 - 1
Terminal.Gui/Views/Menu/Menu.cs

@@ -489,7 +489,8 @@ internal sealed class Menu : View
                 {
                 {
                     var tf = new TextFormatter
                     var tf = new TextFormatter
                     {
                     {
-                        AutoSize = true,
+                        ConstrainToWidth = Frame.Width - 3,
+                        ConstrainToHeight = 1,
                         Alignment = Alignment.Center, HotKeySpecifier = MenuBar.HotKeySpecifier, Text = textToDraw
                         Alignment = Alignment.Center, HotKeySpecifier = MenuBar.HotKeySpecifier, Text = textToDraw
                     };
                     };
 
 

+ 1 - 1
Terminal.Gui/Views/Menu/MenuBar.cs

@@ -619,7 +619,7 @@ public class MenuBar : View, IDesignable
             return Point.Empty;
             return Point.Empty;
         }
         }
 
 
-        Rectangle superViewFrame = SuperView is null ? Driver.Screen : SuperView.Frame;
+        Rectangle superViewFrame = SuperView is null ? Application.Screen : SuperView.Frame;
         View sv = SuperView is null ? Application.Current : SuperView;
         View sv = SuperView is null ? Application.Current : SuperView;
 
 
         if (sv is null)
         if (sv is null)

+ 24 - 35
Terminal.Gui/Views/MessageBox.cs

@@ -1,4 +1,5 @@
-using System.Text.Json.Serialization;
+using System.Diagnostics;
+using System.Text.Json.Serialization;
 
 
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
@@ -35,18 +36,18 @@ public static class MessageBox
     public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
     public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
 
 
     /// <summary>
     /// <summary>
-    ///     Defines the default minimum MessageBox width, as a percentage of the container width. Can be configured via
+    ///     Defines the default minimum MessageBox width, as a percentage of the screen width. Can be configured via
     ///     <see cref="ConfigurationManager"/>.
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static int DefaultMinimumWidth { get; set; } = 60;
+    public static int DefaultMinimumWidth { get; set; } = 0;
 
 
     /// <summary>
     /// <summary>
-    ///     Defines the default minimum Dialog height, as a percentage of the container width. Can be configured via
+    ///     Defines the default minimum Dialog height, as a percentage of the screen width. Can be configured via
     ///     <see cref="ConfigurationManager"/>.
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static int DefaultMinimumHeight { get; set; } = 5;
+    public static int DefaultMinimumHeight { get; set; } = 0;
     /// <summary>
     /// <summary>
     ///     The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox. This is useful for web
     ///     The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox. This is useful for web
     ///     based console where there is no SynchronizationContext or TaskScheduler.
     ///     based console where there is no SynchronizationContext or TaskScheduler.
@@ -368,10 +369,17 @@ public static class MessageBox
             ButtonAlignment = Alignment.Center,
             ButtonAlignment = Alignment.Center,
             ButtonAlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems,
             ButtonAlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems,
             BorderStyle = MessageBox.DefaultBorderStyle,
             BorderStyle = MessageBox.DefaultBorderStyle,
-            Width = Dim.Auto (DimAutoStyle.Content, minimumContentDim: 1, Dim.Percent (90)),
-            Height = Dim.Auto (DimAutoStyle.Content, minimumContentDim: 1, Dim.Percent (90)),
         };
         };
 
 
+        d.Width = Dim.Auto (DimAutoStyle.Auto,
+                            minimumContentDim: Dim.Func (() => (int)((Application.Screen.Width - d.GetAdornmentsThickness ().Horizontal) * (DefaultMinimumWidth / 100f) )),
+                            maximumContentDim: Dim.Func (() => (int)((Application.Screen.Width - d.GetAdornmentsThickness ().Horizontal) * 0.9f)));
+
+        d.Height = Dim.Auto (DimAutoStyle.Auto,
+                             minimumContentDim: Dim.Func (() => (int)((Application.Screen.Height - d.GetAdornmentsThickness ().Vertical) * (DefaultMinimumHeight / 100f))),
+                             maximumContentDim: Dim.Func (() => (int)((Application.Screen.Height - d.GetAdornmentsThickness ().Vertical) * 0.9f)));
+
+
         if (width != 0)
         if (width != 0)
         {
         {
             d.Width = width;
             d.Width = width;
@@ -384,36 +392,17 @@ public static class MessageBox
 
 
         d.ColorScheme = useErrorColors ? Colors.ColorSchemes ["Error"] : Colors.ColorSchemes ["Dialog"];
         d.ColorScheme = useErrorColors ? Colors.ColorSchemes ["Error"] : Colors.ColorSchemes ["Dialog"];
 
 
-        var messageLabel = new Label
-        {
-            HotKeySpecifier = new Rune ('\xFFFF'),
-            Width = Dim.Auto (DimAutoStyle.Text),
-            Height = Dim.Auto (DimAutoStyle.Text),
-            Text = message,
-            TextAlignment = Alignment.Center,
-            X = Pos.Center (),
-            Y = 0,
-            //ColorScheme = Colors.ColorSchemes ["Error"],
-        };
-
-        messageLabel.TextFormatter.WordWrap = wrapMessage;
-        messageLabel.TextFormatter.MultiLine = !wrapMessage;
+        d.HotKeySpecifier = new Rune ('\xFFFF');
+        d.Text = message;
+        d.TextAlignment = Alignment.Center;
+        d.VerticalTextAlignment = Alignment.Start;
+        d.TextFormatter.WordWrap = wrapMessage;
+        d.TextFormatter.MultiLine = !wrapMessage;
 
 
-        if (wrapMessage)
+        d.ColorScheme = new ColorScheme (d.ColorScheme)
         {
         {
-            int buttonHeight = buttonList.Count > 0 ? buttonList [0].Frame.Height : 0;
-
-            messageLabel.Width = Dim.Fill ();
-            messageLabel.Height = Dim.Func (() => GetWrapSize ().Height);
-            Size GetWrapSize ()
-            {
-                // A bit of a hack to get the height of the wrapped text.
-                messageLabel.TextFormatter.Size = d.GetContentSize () with { Height = 1000 };
-                return messageLabel.TextFormatter.FormatAndGetSize ();
-            }
-        }
-
-        d.Add (messageLabel);
+            Focus = d.ColorScheme.Normal
+        };
 
 
         // Setup actions
         // Setup actions
         Clicked = -1;
         Clicked = -1;

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

@@ -175,7 +175,7 @@ public class ProgressBar : View, IDesignable
 
 
         if (ProgressBarFormat != ProgressBarFormat.Simple && !_isActivity)
         if (ProgressBarFormat != ProgressBarFormat.Simple && !_isActivity)
         {
         {
-            var tf = new TextFormatter { Alignment = Alignment.Center, Text = Text, AutoSize = true };
+            var tf = new TextFormatter { Alignment = Alignment.Center, Text = Text };
             var attr = new Attribute (ColorScheme.HotNormal.Foreground, ColorScheme.HotNormal.Background);
             var attr = new Attribute (ColorScheme.HotNormal.Foreground, ColorScheme.HotNormal.Background);
 
 
             if (_fraction > .5)
             if (_fraction > .5)

+ 0 - 1
Terminal.Gui/Views/ScrollView.cs

@@ -623,7 +623,6 @@ public class ScrollView : View
         {
         {
             _horizontal.Position = Math.Max (0, -_contentOffset.X);
             _horizontal.Position = Math.Max (0, -_contentOffset.X);
         }
         }
-
         SetNeedsDisplay ();
         SetNeedsDisplay ();
     }
     }
 
 

+ 3 - 3
Terminal.Gui/Views/Shortcut.cs

@@ -71,7 +71,7 @@ public class Shortcut : View
         CommandView = new ()
         CommandView = new ()
         {
         {
             Width = Dim.Auto (),
             Width = Dim.Auto (),
-            Height = Dim.Auto ()
+            Height = Dim.Auto (DimAutoStyle.Auto, minimumContentDim: 1)
         };
         };
 
 
         HelpView.Id = "_helpView";
         HelpView.Id = "_helpView";
@@ -484,7 +484,7 @@ public override string Text
     get => HelpView?.Text;
     get => HelpView?.Text;
     set
     set
     {
     {
-        if (HelpView != null)
+        if (HelpView is {})
         {
         {
             HelpView.Text = value;
             HelpView.Text = value;
             ShowHide ();
             ShowHide ();
@@ -500,7 +500,7 @@ public string HelpText
     get => HelpView?.Text;
     get => HelpView?.Text;
     set
     set
     {
     {
-        if (HelpView != null)
+        if (HelpView is {})
         {
         {
             HelpView.Text = value;
             HelpView.Text = value;
             ShowHide ();
             ShowHide ();

+ 3 - 3
UICatalog/KeyBindingsDialog.cs

@@ -19,8 +19,8 @@ internal class KeyBindingsDialog : Dialog
     {
     {
         Title = "Keybindings";
         Title = "Keybindings";
 
 
-        //Height = 50;
-        //Width = 10;
+        Height = Dim.Percent(80);
+        Width = Dim.Percent(80);
         if (ViewTracker.Instance == null)
         if (ViewTracker.Instance == null)
         {
         {
             ViewTracker.Initialize ();
             ViewTracker.Initialize ();
@@ -32,7 +32,7 @@ internal class KeyBindingsDialog : Dialog
         _commandsListView = new ListView
         _commandsListView = new ListView
         {
         {
             Width = Dim.Percent (50),
             Width = Dim.Percent (50),
-            Height = Dim.Percent (100) - 1,
+            Height = Dim.Fill () - 1,
             Source = new ListWrapper<Command> (_commands),
             Source = new ListWrapper<Command> (_commands),
             SelectedItem = 0
             SelectedItem = 0
         };
         };

+ 0 - 4
UICatalog/Scenarios/AdornmentsEditor.cs

@@ -124,10 +124,6 @@ public class AdornmentsEditor : View
 
 
         Add (_diagRulerCheckBox);
         Add (_diagRulerCheckBox);
         _diagRulerCheckBox.Y = Pos.Bottom (_diagPaddingCheckBox);
         _diagRulerCheckBox.Y = Pos.Bottom (_diagPaddingCheckBox);
-
-        // BUGBUG: This should not be needed. There's some bug in the layout system that doesn't update the layout.
-        SuperView.LayoutSubviews();
-
     }
     }
 
 
     private void Application_MouseEvent (object sender, MouseEvent e)
     private void Application_MouseEvent (object sender, MouseEvent e)

+ 0 - 6
UICatalog/Scenarios/Bars.cs

@@ -341,12 +341,6 @@ public class Bars : Scenario
     //    Application.MouseEvent -= Application_MouseEvent;
     //    Application.MouseEvent -= Application_MouseEvent;
     //}
     //}
 
 
-    private void Menu_Initialized (object sender, EventArgs e)
-    {
-        // BUGBUG: this should not be needed    
-
-        ((View)(sender)).LayoutSubviews ();
-    }
 
 
     private void ConfigMenuBar (Bar bar)
     private void ConfigMenuBar (Bar bar)
     {
     {

+ 1 - 2
UICatalog/Scenarios/BorderEditor.cs

@@ -33,9 +33,8 @@ public class BorderEditor : AdornmentEditor
         {
         {
             X = 0,
             X = 0,
 
 
-            // BUGBUG: Hack until dimauto is working properly
             Y = Pos.Bottom (Subviews [^1]),
             Y = Pos.Bottom (Subviews [^1]),
-            Width = Dim.Width (Subviews [^2]) + Dim.Width (Subviews [^1]) - 1,
+            Width = Dim.Fill (),
             SelectedItem = (int)(((Border)AdornmentToEdit)?.LineStyle ?? LineStyle.None),
             SelectedItem = (int)(((Border)AdornmentToEdit)?.LineStyle ?? LineStyle.None),
             BorderStyle = LineStyle.Single,
             BorderStyle = LineStyle.Single,
             Title = "Border St_yle",
             Title = "Border St_yle",

+ 53 - 2
UICatalog/Scenarios/ComputedLayout.cs

@@ -7,8 +7,7 @@ using static Terminal.Gui.Dialog;
 namespace UICatalog.Scenarios;
 namespace UICatalog.Scenarios;
 
 
 /// <summary>
 /// <summary>
-///     This Scenario demonstrates how to use Termina.gui's Dim and Pos Layout System. [x] - Using Dim.Fill to fill a
-///     window [x] - Using Dim.Fill and Dim.Pos to automatically align controls based on an initial control [ ] - ...
+///     This Scenario demonstrates how to use Terminal.Gui's Dim and Pos Layout System. 
 /// </summary>
 /// </summary>
 [ScenarioMetadata ("Computed Layout", "Demonstrates the Computed (Dim and Pos) Layout System.")]
 [ScenarioMetadata ("Computed Layout", "Demonstrates the Computed (Dim and Pos) Layout System.")]
 [ScenarioCategory ("Layout")]
 [ScenarioCategory ("Layout")]
@@ -216,6 +215,58 @@ public class ComputedLayout : Scenario
                                      fv.Title =
                                      fv.Title =
                                          $"{frameView.GetType ().Name} {{X={fv.X},Y={fv.Y},Width={fv.Width},Height={fv.Height}}}";
                                          $"{frameView.GetType ().Name} {{X={fv.X},Y={fv.Y},Width={fv.Width},Height={fv.Height}}}";
                                  };
                                  };
+
+        labelList = new List<Label> ();
+        labelList.Add (new Label { Text = "The lines below show different alignment" });
+
+        labelList.Add (
+                       new Label
+                       {
+                           TextAlignment = Alignment.Start,
+                           Width = Dim.Fill (),
+                           X = 0,
+                           Y = Pos.Bottom (labelList.LastOrDefault ()),
+                           ColorScheme = Colors.ColorSchemes ["Dialog"],
+                           Text = $"{i++}-{txt}"
+                       }
+                      );
+
+        labelList.Add (
+                       new Label
+                       {
+                           TextAlignment = Alignment.End,
+                           Width = Dim.Fill (),
+                           X = 0,
+                           Y = Pos.Bottom (labelList.LastOrDefault ()),
+                           ColorScheme = Colors.ColorSchemes ["Dialog"],
+                           Text = $"{i++}-{txt}"
+                       }
+                      );
+
+        labelList.Add (
+                       new Label
+                       {
+                           TextAlignment = Alignment.Center,
+                           Width = Dim.Fill (),
+                           X = 0,
+                           Y = Pos.Bottom (labelList.LastOrDefault ()),
+                           ColorScheme = Colors.ColorSchemes ["Dialog"],
+                           Text = $"{i++}-{txt}"
+                       }
+                      );
+
+        labelList.Add (
+                       new Label
+                       {
+                           TextAlignment = Alignment.Fill,
+                           Width = Dim.Fill (),
+                           X = 0,
+                           Y = Pos.Bottom (labelList.LastOrDefault ()),
+                           ColorScheme = Colors.ColorSchemes ["Dialog"],
+                           Text = $"{i++}-{txt}"
+                       }
+                      );
+        frameView.Add (labelList.ToArray ());
         app.Add (frameView);
         app.Add (frameView);
 
 
         // Demonstrate Dim & Pos using percentages - a TextField that is 30% height and 80% wide
         // Demonstrate Dim & Pos using percentages - a TextField that is 30% height and 80% wide

+ 15 - 6
UICatalog/Scenarios/Dialogs.cs

@@ -79,7 +79,12 @@ public class Dialogs : Scenario
         frame.Add (heightEdit);
         frame.Add (heightEdit);
 
 
         frame.Add (
         frame.Add (
-                   new Label { X = Pos.Right (widthEdit) + 2, Y = Pos.Top (widthEdit), Text = "If height & width are both 0," }
+                   new Label
+                   {
+                       X = Pos.Right (widthEdit) + 2,
+                       Y = Pos.Top (widthEdit),
+                       Text = $"If width is 0, the dimension will be greater than {Dialog.DefaultMinimumWidth}%."
+                   }
                   );
                   );
 
 
         frame.Add (
         frame.Add (
@@ -87,7 +92,7 @@ public class Dialogs : Scenario
                    {
                    {
                        X = Pos.Right (heightEdit) + 2,
                        X = Pos.Right (heightEdit) + 2,
                        Y = Pos.Top (heightEdit),
                        Y = Pos.Top (heightEdit),
-                       Text = "the Dialog will size to 80% of container."
+                       Text = $"If height is 0, the dimension will be greater {Dialog.DefaultMinimumHeight}%."
                    }
                    }
                   );
                   );
 
 
@@ -263,16 +268,19 @@ public class Dialogs : Scenario
                 Buttons = buttons.ToArray ()
                 Buttons = buttons.ToArray ()
             };
             };
 
 
-            if (height != 0 || width != 0)
+            if (width != 0)
             {
             {
-                dialog.Height = height;
                 dialog.Width = width;
                 dialog.Width = width;
             }
             }
+            if (height != 0)
+            {
+                dialog.Height = height;
+            }
 
 
             var add = new Button
             var add = new Button
             {
             {
                 X = Pos.Center (),
                 X = Pos.Center (),
-                Y = Pos.Center (),
+                Y = Pos.Center () - 1,
                 Text = "_Add a button"
                 Text = "_Add a button"
             };
             };
 
 
@@ -325,8 +333,9 @@ public class Dialogs : Scenario
 
 
                                   dialog.LayoutSubviews ();
                                   dialog.LayoutSubviews ();
                               };
                               };
-            dialog.Closed += (s, e) => { buttonPressedLabel.Text = $"{clicked}"; };
             dialog.Add (addChar);
             dialog.Add (addChar);
+
+            dialog.Closed += (s, e) => { buttonPressedLabel.Text = $"{clicked}"; };
         }
         }
         catch (FormatException)
         catch (FormatException)
         {
         {

+ 36 - 22
UICatalog/Scenarios/DimAutoDemo.cs

@@ -23,21 +23,21 @@ public class DimAutoDemo : Scenario
 
 
         FrameView dimAutoFrameView = CreateDimAutoContentFrameView ();
         FrameView dimAutoFrameView = CreateDimAutoContentFrameView ();
 
 
-        FrameView sliderFrameView = CreateSliderFrameView ();
-        sliderFrameView.X = Pos.Right(dimAutoFrameView) + 1;
-        sliderFrameView.Width = Dim.Fill ();
-        sliderFrameView.Height = Dim.Fill ();
+        //FrameView sliderFrameView = CreateSliderFrameView ();
+        //sliderFrameView.X = Pos.Right(dimAutoFrameView) + 1;
+        //sliderFrameView.Width = Dim.Fill ();
+        //sliderFrameView.Height = Dim.Fill ();
 
 
 
 
-        //var dlgButton = new Button
-        //{
-        //    Text = "Open Test _Dialog",
-        //    X = Pos.Right (dimAutoFrameView),
-        //    Y = Pos.Top (dimAutoFrameView)
-        //};
-        //dlgButton.Accept += DlgButton_Clicked;
+        ////var dlgButton = new Button
+        ////{
+        ////    Text = "Open Test _Dialog",
+        ////    X = Pos.Right (dimAutoFrameView),
+        ////    Y = Pos.Top (dimAutoFrameView)
+        ////};
+        ////dlgButton.Accept += DlgButton_Clicked;
 
 
-        appWindow.Add (dimAutoFrameView, sliderFrameView /*dlgButton*/);
+        appWindow.Add (dimAutoFrameView/*, sliderFrameView dlgButton*/);
 
 
         // Run - Start the application.
         // Run - Start the application.
         Application.Run (appWindow);
         Application.Run (appWindow);
@@ -140,25 +140,39 @@ public class DimAutoDemo : Scenario
                                         bothAuto.Text = textEdit.Text;
                                         bothAuto.Text = textEdit.Text;
                                     };
                                     };
 
 
-        var movingButton = new Button
-        {
-            Text = "_Click\nTo Move\nDown",
-            X = Pos.Right (vlabel),
-            Y = Pos.Bottom (vlabel)
-        };
-        movingButton.Accept += (s, e) => { movingButton.Y = movingButton.Frame.Y + 1; };
-        dimAutoFrameView.Add (movingButton);
+        //var movingButton = new Button
+        //{
+        //    Text = "_Click\nTo Move\nDown",
+        //    X = Pos.Right (vlabel),
+        //    Y = Pos.Bottom (vlabel)
+        //};
+        //movingButton.Accept += (s, e) => { movingButton.Y = movingButton.Frame.Y + 1; };
+        //dimAutoFrameView.Add (movingButton);
 
 
         var resetButton = new Button
         var resetButton = new Button
         {
         {
             Text = "_Reset Button (AnchorEnd)",
             Text = "_Reset Button (AnchorEnd)",
             X = Pos.AnchorEnd (),
             X = Pos.AnchorEnd (),
-            Y = Pos.AnchorEnd (1)
+            Y = Pos.AnchorEnd ()
         };
         };
 
 
-        resetButton.Accept += (s, e) => { movingButton.Y = Pos.Bottom (hlabel); };
+        resetButton.Accept += (s, e) =>
+        {
+            //movingButton.Y = Pos.Bottom (hlabel);
+            //movingButton.X = 0;
+        };
         dimAutoFrameView.Add (resetButton);
         dimAutoFrameView.Add (resetButton);
 
 
+
+        var radioGroup = new RadioGroup ()
+        {
+            RadioLabels = ["One", "Two", "Three"],
+            X = 0,
+            Y = Pos.AnchorEnd (),
+            Title = "Radios",
+            BorderStyle = LineStyle.Dotted
+        };
+        dimAutoFrameView.Add (radioGroup);
         return dimAutoFrameView;
         return dimAutoFrameView;
     }
     }
 
 

+ 2 - 5
UICatalog/Scenarios/ExpanderButton.cs

@@ -96,8 +96,6 @@ public class ExpanderButton : Button
                 ExpandedGlyph = new ('\u21d2'); // ⇒
                 ExpandedGlyph = new ('\u21d2'); // ⇒
             }
             }
 
 
-            Text = $"{(Collapsed ? CollapsedGlyph : ExpandedGlyph)}";
-
             ExpandOrCollapse (Collapsed);
             ExpandOrCollapse (Collapsed);
         }
         }
 
 
@@ -157,9 +155,6 @@ public class ExpanderButton : Button
                 subview.Visible = !Collapsed;
                 subview.Visible = !Collapsed;
                 subview.Enabled = !Collapsed;
                 subview.Enabled = !Collapsed;
             }
             }
-
-            // BUGBUG: This should not be needed. There's some bug in the layout system that doesn't update the layout.
-            superView.SuperView?.LayoutSubviews ();
         }
         }
 
 
         return args.Cancel;
         return args.Cancel;
@@ -186,6 +181,8 @@ public class ExpanderButton : Button
 
 
     private void ExpandOrCollapse (bool collapse)
     private void ExpandOrCollapse (bool collapse)
     {
     {
+        Text = $"{(Collapsed ? CollapsedGlyph : ExpandedGlyph)}";
+
         View superView = SuperView;
         View superView = SuperView;
         if (superView is Adornment adornment)
         if (superView is Adornment adornment)
         {
         {

+ 1 - 1
UICatalog/Scenarios/ListColumns.cs

@@ -284,7 +284,7 @@ public class ListColumns : Scenario
         cancel.Accept += (s, e) => { Application.RequestStop (); };
         cancel.Accept += (s, e) => { Application.RequestStop (); };
         var d = new Dialog { Title = prompt, Buttons = [ok, cancel] };
         var d = new Dialog { Title = prompt, Buttons = [ok, cancel] };
 
 
-        var tf = new TextField { Text = getter (_listColView).ToString (), X = 0, Y = 1, Width = Dim.Fill () };
+        var tf = new TextField { Text = getter (_listColView).ToString (), X = 0, Y = 0, Width = Dim.Fill () };
 
 
         d.Add (tf);
         d.Add (tf);
         tf.SetFocus ();
         tf.SetFocus ();

+ 1 - 3
UICatalog/Scenarios/MarginEditor.cs

@@ -28,9 +28,7 @@ public class MarginEditor : AdornmentEditor
         _rgShadow = new RadioGroup
         _rgShadow = new RadioGroup
         {
         {
             X = 0,
             X = 0,
-            //Y = Pos.AnchorEnd(),
-            // BUGBUG: Hack until dimauto is working properly
-            Y = Pos.Bottom (Subviews [^1]),
+            Y = Pos.AnchorEnd (),
 
 
             SuperViewRendersLineCanvas = true,
             SuperViewRendersLineCanvas = true,
             Title = "_Shadow",
             Title = "_Shadow",

+ 8 - 4
UICatalog/Scenarios/MessageBoxes.cs

@@ -15,7 +15,7 @@ public class MessageBoxes : Scenario
 
 
         Window app = new ()
         Window app = new ()
         {
         {
-            Title = GetQuitKeyAndName ()
+            Title = GetQuitKeyAndName (),
         };
         };
 
 
         var frame = new FrameView
         var frame = new FrameView
@@ -47,7 +47,6 @@ public class MessageBoxes : Scenario
         {
         {
             X = 0,
             X = 0,
             Y = Pos.Bottom (label),
             Y = Pos.Bottom (label),
-
             Width = Dim.Width (label),
             Width = Dim.Width (label),
             Height = 1,
             Height = 1,
             TextAlignment = Alignment.End,
             TextAlignment = Alignment.End,
@@ -66,7 +65,12 @@ public class MessageBoxes : Scenario
         frame.Add (heightEdit);
         frame.Add (heightEdit);
 
 
         frame.Add (
         frame.Add (
-                   new Label { X = Pos.Right (widthEdit) + 2, Y = Pos.Top (widthEdit), Text = "If height & width are both 0," }
+                   new Label
+                   {
+                       X = Pos.Right (widthEdit) + 2,
+                       Y = Pos.Top (widthEdit),
+                       Text = $"If width is 0, the dimension will be greater than {MessageBox.DefaultMinimumWidth}%."
+                   }
                   );
                   );
 
 
         frame.Add (
         frame.Add (
@@ -74,7 +78,7 @@ public class MessageBoxes : Scenario
                    {
                    {
                        X = Pos.Right (heightEdit) + 2,
                        X = Pos.Right (heightEdit) + 2,
                        Y = Pos.Top (heightEdit),
                        Y = Pos.Top (heightEdit),
-                       Text = "the MessageBox will be sized automatically."
+                       Text = $"If height is 0, the dimension will be greater than {MessageBox.DefaultMinimumHeight}%."
                    }
                    }
                   );
                   );
 
 

+ 9 - 5
UICatalog/Scenarios/TableEditor.cs

@@ -1083,13 +1083,16 @@ public class TableEditor : Scenario
                      };
                      };
         var cancel = new Button { Text = "Cancel" };
         var cancel = new Button { Text = "Cancel" };
         cancel.Accept += (s, e) => { Application.RequestStop (); };
         cancel.Accept += (s, e) => { Application.RequestStop (); };
-        var d = new Dialog { Title = prompt, Buttons = [ok, cancel] };
+        var d = new Dialog
+        {
+            Title = prompt,
+            Buttons = [ok, cancel]
+        };
 
 
         ColumnStyle style = _tableView.Style.GetOrCreateColumnStyle (col.Value);
         ColumnStyle style = _tableView.Style.GetOrCreateColumnStyle (col.Value);
 
 
-        var lbl = new Label { X = 0, Y = 1, Text = _tableView.Table.ColumnNames [col.Value] };
-
-        var tf = new TextField { Text = getter (style).ToString (), X = 0, Y = 2, Width = Dim.Fill () };
+        var lbl = new Label { X = 0, Y = 0, Text = $"{_tableView.Table.ColumnNames [col.Value]}: " };
+        var tf = new TextField { Text = getter (style).ToString (), X = Pos.Right (lbl), Y = 0, Width = 20 };
 
 
         d.Add (lbl, tf);
         d.Add (lbl, tf);
         tf.SetFocus ();
         tf.SetFocus ();
@@ -1461,7 +1464,8 @@ public class TableEditor : Scenario
                                                                              treeSource,
                                                                              treeSource,
                                                                              _checkedFileSystemInfos.Contains,
                                                                              _checkedFileSystemInfos.Contains,
                                                                              CheckOrUncheckFile
                                                                              CheckOrUncheckFile
-                                                                            ) { UseRadioButtons = radio };
+                                                                            )
+            { UseRadioButtons = radio };
         }
         }
         else
         else
         {
         {

+ 1 - 35
UICatalog/Scenarios/TextAlignmentAndDirection.cs

@@ -522,46 +522,12 @@ public class TextAlignmentAndDirection : Scenario
 
 
         app.Add (wrapCheckbox);
         app.Add (wrapCheckbox);
 
 
-        // AUTOSIZE CHECKBOX
-
-        var autoSizeCheckbox = new CheckBox
-        {
-            X = Pos.Right (container) + 1,
-            Y = Pos.Y (wrapCheckbox) + 1,
-            Width = Dim.Fill (10),
-            Height = 1,
-            Text = "AutoSize"
-        };
-        autoSizeCheckbox.State = autoSizeCheckbox.TextFormatter.AutoSize ? CheckState.Checked : CheckState.UnChecked;
-
-        autoSizeCheckbox.Toggle += (s, e) =>
-                                    {
-                                        if (e.CurrentValue == CheckState.Checked)
-                                        {
-                                            foreach (Label t in multiLineLabels)
-                                            {
-                                                t.TextFormatter.AutoSize = false;
-                                            }
-                                        }
-                                        else
-                                        {
-                                            foreach (Label t in multiLineLabels)
-                                            {
-                                                t.TextFormatter.AutoSize = true;
-                                            }
-                                        }
-                                    };
-
-        app.Add (autoSizeCheckbox);
-
-        // Direction Options
-
         List<TextDirection> directionsEnum = Enum.GetValues (typeof (TextDirection)).Cast<TextDirection> ().ToList ();
         List<TextDirection> directionsEnum = Enum.GetValues (typeof (TextDirection)).Cast<TextDirection> ().ToList ();
 
 
         var directionOptions = new RadioGroup
         var directionOptions = new RadioGroup
         {
         {
             X = Pos.Right (container) + 1,
             X = Pos.Right (container) + 1,
-            Y = Pos.Bottom (autoSizeCheckbox) + 1,
+            Y = Pos.Bottom (wrapCheckbox) + 1,
             Width = Dim.Fill (10),
             Width = Dim.Fill (10),
             Height = Dim.Fill (1),
             Height = Dim.Fill (1),
             HotKeySpecifier = (Rune)'\xffff',
             HotKeySpecifier = (Rune)'\xffff',

+ 2 - 5
UICatalog/Scenarios/ViewExperiments.cs

@@ -151,13 +151,10 @@ public class ViewExperiments : Scenario
 
 
         view.Add (view5);
         view.Add (view5);
 
 
-        var label = new Label { Text = "AutoSize true; 1;1:", X = 1, Y = 1 };
-        view.Add (label);
-
         var edit = new TextField
         var edit = new TextField
         {
         {
-            Text = "Right (label)",
-            X = Pos.Right (label),
+            Text = "Right (view5)",
+            X = Pos.Right (view5),
             Y = 1,
             Y = 1,
             Width = 15,
             Width = 15,
             Height = 1
             Height = 1

+ 55 - 39
UICatalog/UICatalog.cs

@@ -1,4 +1,4 @@
-global using Attribute = Terminal.Gui.Attribute;
+global using Attribute = Terminal.Gui.Attribute;
 global using CM = Terminal.Gui.ConfigurationManager;
 global using CM = Terminal.Gui.ConfigurationManager;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -45,9 +45,8 @@ namespace UICatalog;
 ///         (https://github.com/gui-cs/Terminal.Gui/tree/master/UICatalog/README.md).
 ///         (https://github.com/gui-cs/Terminal.Gui/tree/master/UICatalog/README.md).
 ///     </para>
 ///     </para>
 /// </remarks>
 /// </remarks>
-internal class UICatalogApp
+public class UICatalogApp
 {
 {
-    private static StringBuilder? _aboutMessage;
     private static int _cachedCategoryIndex;
     private static int _cachedCategoryIndex;
 
 
     // When a scenario is run, the main app is killed. These items
     // When a scenario is run, the main app is killed. These items
@@ -74,6 +73,34 @@ internal class UICatalogApp
     [JsonPropertyName ("UICatalog.StatusBar")]
     [JsonPropertyName ("UICatalog.StatusBar")]
     public static bool ShowStatusBar { get; set; } = true;
     public static bool ShowStatusBar { get; set; } = true;
 
 
+    /// <summary>
+    /// Gets the message displayed in the About Box. `public` so it can be used from Unit tests.
+    /// </summary>
+    /// <returns></returns>
+    public static string GetAboutBoxMessage ()
+    {
+        // NOTE: Do not use multiline verbatim strings here.
+        // WSL gets all confused.
+        StringBuilder msg = new ();
+        msg.AppendLine ("UI Catalog: A comprehensive sample library for");
+        msg.AppendLine ();
+
+        msg.AppendLine ("""
+                         _______                  _             _   _____       _ 
+                        |__   __|                (_)           | | / ____|     (_)
+                           | | ___ _ __ _ __ ___  _ _ __   __ _| || |  __ _   _ _ 
+                           | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | || | |_ | | | | |
+                           | |  __/ |  | | | | | | | | | | (_| | || |__| | |_| | |
+                           |_|\___|_|  |_| |_| |_|_|_| |_|\__,_|_(_)_____|\__,_|_|
+                        """);
+        msg.AppendLine ();
+        msg.AppendLine ("v2 - Pre-Alpha");
+        msg.AppendLine ();
+        msg.AppendLine ("https://github.com/gui-cs/Terminal.Gui");
+
+        return msg.ToString ();
+    }
+
     private static void ConfigFileChanged (object sender, FileSystemEventArgs e)
     private static void ConfigFileChanged (object sender, FileSystemEventArgs e)
     {
     {
         if (Application.Top == null)
         if (Application.Top == null)
@@ -295,6 +322,7 @@ internal class UICatalogApp
             _selectedScenario.Main ();
             _selectedScenario.Main ();
             _selectedScenario.Dispose ();
             _selectedScenario.Dispose ();
             _selectedScenario = null;
             _selectedScenario = null;
+
             // TODO: Throw if shutdown was not called already
             // TODO: Throw if shutdown was not called already
             Application.Shutdown ();
             Application.Shutdown ();
             VerifyObjectsWereDisposed ();
             VerifyObjectsWereDisposed ();
@@ -302,20 +330,6 @@ internal class UICatalogApp
             return;
             return;
         }
         }
 
 
-        _aboutMessage = new ();
-        _aboutMessage.AppendLine (@"A comprehensive sample library for");
-        _aboutMessage.AppendLine (@"");
-        _aboutMessage.AppendLine (@"  _______                  _             _   _____       _  ");
-        _aboutMessage.AppendLine (@" |__   __|                (_)           | | / ____|     (_) ");
-        _aboutMessage.AppendLine (@"    | | ___ _ __ _ __ ___  _ _ __   __ _| || |  __ _   _ _  ");
-        _aboutMessage.AppendLine (@"    | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | || | |_ | | | | | ");
-        _aboutMessage.AppendLine (@"    | |  __/ |  | | | | | | | | | | (_| | || |__| | |_| | | ");
-        _aboutMessage.AppendLine (@"    |_|\___|_|  |_| |_| |_|_|_| |_|\__,_|_(_)_____|\__,_|_| ");
-        _aboutMessage.AppendLine (@"");
-        _aboutMessage.AppendLine (@"v2 - Work in Progress");
-        _aboutMessage.AppendLine (@"");
-        _aboutMessage.AppendLine (@"https://github.com/gui-cs/Terminal.Gui");
-
         while (RunUICatalogTopLevel () is { } scenario)
         while (RunUICatalogTopLevel () is { } scenario)
         {
         {
             VerifyObjectsWereDisposed ();
             VerifyObjectsWereDisposed ();
@@ -374,7 +388,9 @@ internal class UICatalogApp
         public MenuItem? MiIsMenuBorderDisabled;
         public MenuItem? MiIsMenuBorderDisabled;
         public MenuItem? MiIsMouseDisabled;
         public MenuItem? MiIsMouseDisabled;
         public MenuItem? MiUseSubMenusSingleFrame;
         public MenuItem? MiUseSubMenusSingleFrame;
+
         public Shortcut? ShForce16Colors;
         public Shortcut? ShForce16Colors;
+
         //public Shortcut? ShDiagnostics;
         //public Shortcut? ShDiagnostics;
         public Shortcut? ShVersion;
         public Shortcut? ShVersion;
 
 
@@ -387,7 +403,7 @@ internal class UICatalogApp
 
 
         public UICatalogTopLevel ()
         public UICatalogTopLevel ()
         {
         {
-            _diagnosticFlags = View.Diagnostics;
+            _diagnosticFlags = Diagnostics;
 
 
             _themeMenuItems = CreateThemeMenuItems ();
             _themeMenuItems = CreateThemeMenuItems ();
             _themeMenuBarItem = new ("_Themes", _themeMenuItems);
             _themeMenuBarItem = new ("_Themes", _themeMenuItems);
@@ -433,11 +449,10 @@ internal class UICatalogApp
                                   "_About...",
                                   "_About...",
                                   "About UI Catalog",
                                   "About UI Catalog",
                                   () => MessageBox.Query (
                                   () => MessageBox.Query (
-                                                          "About UI Catalog",
-                                                          _aboutMessage!.ToString (),
-                                                          0,
-                                                          false,
-                                                          "_Ok"
+                                                          title: "",
+                                                          message: GetAboutBoxMessage (),
+                                                          wrapMessage: false,
+                                                          buttons: "_Ok"
                                                          ),
                                                          ),
                                   null,
                                   null,
                                   null,
                                   null,
@@ -459,35 +474,34 @@ internal class UICatalogApp
                 ShVersion = new ()
                 ShVersion = new ()
                 {
                 {
                     Title = "Version Info",
                     Title = "Version Info",
-                    CanFocus = false,
-
+                    CanFocus = false
                 };
                 };
 
 
-                Shortcut statusBarShortcut = new Shortcut ()
+                var statusBarShortcut = new Shortcut
                 {
                 {
                     Key = Key.F10,
                     Key = Key.F10,
-                    Title = "Show/Hide Status Bar",
+                    Title = "Show/Hide Status Bar"
                 };
                 };
                 statusBarShortcut.Accept += (sender, args) => { StatusBar.Visible = !StatusBar.Visible; };
                 statusBarShortcut.Accept += (sender, args) => { StatusBar.Visible = !StatusBar.Visible; };
 
 
-                ShForce16Colors = new Shortcut ()
+                ShForce16Colors = new ()
                 {
                 {
-                    CommandView = new CheckBox ()
+                    CommandView = new CheckBox
                     {
                     {
                         Title = "16 color mode",
                         Title = "16 color mode",
                         State = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
                         State = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
-                        CanFocus = false,
+                        CanFocus = false
                     },
                     },
                     HelpText = "",
                     HelpText = "",
-                    Key = Key.F6,
+                    Key = Key.F6
                 };
                 };
 
 
                 ((CheckBox)ShForce16Colors.CommandView).Toggle += (sender, args) =>
                 ((CheckBox)ShForce16Colors.CommandView).Toggle += (sender, args) =>
-                                          {
-                                              Application.Force16Colors = args.NewValue == CheckState.Checked;
-                                              MiForce16Colors!.Checked = Application.Force16Colors;
-                                              Application.Refresh ();
-                                          };
+                                                                  {
+                                                                      Application.Force16Colors = args.NewValue == CheckState.Checked;
+                                                                      MiForce16Colors!.Checked = Application.Force16Colors;
+                                                                      Application.Refresh ();
+                                                                  };
 
 
                 //ShDiagnostics = new Shortcut ()
                 //ShDiagnostics = new Shortcut ()
                 //{
                 //{
@@ -502,10 +516,10 @@ internal class UICatalogApp
                 //};
                 //};
 
 
                 StatusBar.Add (
                 StatusBar.Add (
-                               new Shortcut ()
+                               new Shortcut
                                {
                                {
                                    Title = "Quit",
                                    Title = "Quit",
-                                   Key = Application.QuitKey,
+                                   Key = Application.QuitKey
                                },
                                },
                                statusBarShortcut,
                                statusBarShortcut,
                                ShForce16Colors,
                                ShForce16Colors,
@@ -1006,7 +1020,9 @@ internal class UICatalogApp
             MiForce16Colors.Action += () =>
             MiForce16Colors.Action += () =>
                                       {
                                       {
                                           MiForce16Colors.Checked = Application.Force16Colors = (bool)!MiForce16Colors.Checked!;
                                           MiForce16Colors.Checked = Application.Force16Colors = (bool)!MiForce16Colors.Checked!;
-                                          ((CheckBox)ShForce16Colors!.CommandView!).State = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
+
+                                          ((CheckBox)ShForce16Colors!.CommandView!).State =
+                                              Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
                                           Application.Refresh ();
                                           Application.Refresh ();
                                       };
                                       };
             menuItems.Add (MiForce16Colors);
             menuItems.Add (MiForce16Colors);

+ 104 - 513
UnitTests/Dialogs/MessageBoxTests.cs

@@ -1,4 +1,5 @@
 using System.Text;
 using System.Text;
+using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
 namespace Terminal.Gui.DialogTests;
 namespace Terminal.Gui.DialogTests;
@@ -120,58 +121,25 @@ public class MessageBoxTests
         Assert.Equal (1, result);
         Assert.Equal (1, result);
     }
     }
 
 
-    [Fact (Skip = "Pos.Align WIP")]
+    [Theory]
+    [InlineData (@"", false, false, 6, 6, 2, 2)]
+    [InlineData (@"", false, true, 3, 6, 9, 3)]
+    [InlineData (@"01234\n-----\n01234", false, false, 1, 6, 13, 3)]
+    [InlineData (@"01234\n-----\n01234", true, false, 1, 5, 13, 4)]
+    [InlineData (@"0123456789", false, false, 1, 6, 12, 3)]
+    [InlineData (@"0123456789", false, true, 1, 5, 12, 4)]
+    [InlineData (@"01234567890123456789", false, true, 1, 5, 13, 4)]
+    [InlineData (@"01234567890123456789", true, true, 1, 5, 13, 5)]
+    [InlineData (@"01234567890123456789\n01234567890123456789", false, true, 1, 5, 13, 4)]
+    [InlineData (@"01234567890123456789\n01234567890123456789", true, true, 1, 4, 13, 7)]
     [AutoInitShutdown]
     [AutoInitShutdown]
-    public void Location_Default ()
+    public void Location_And_Size_Correct (string message, bool wrapMessage, bool hasButton, int expectedX, int expectedY, int expectedW, int expectedH)
     {
     {
         int iterations = -1;
         int iterations = -1;
-        ((FakeDriver)Application.Driver).SetBufferSize (100, 100);
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     iterations++;
-
-                                     if (iterations == 0)
-                                     {
-                                         MessageBox.Query (string.Empty, string.Empty, null);
 
 
-                                         Application.RequestStop ();
-                                     }
-                                     else if (iterations == 1)
-                                     {
-                                         Application.Refresh ();
+        ((FakeDriver)Application.Driver).SetBufferSize (15, 15); // 15 x 15 gives us enough room for a button with one char (9x1)
 
 
-                                         Assert.IsType<Dialog> (Application.Current);
-
-                                         // Default location is centered, so
-                                         // X = (100 / 2) - (60 / 2) = 20
-                                         // Y = (100 / 2) - (5 / 2) = 47
-                                         Assert.Equal (new Point (20, 47), (Point)Application.Current.Frame.Location);
-
-                                         Application.RequestStop ();
-                                     }
-                                 };
-
-        Application.Run ().Dispose ();
-    }
-
-    [Theory (Skip = "Pos.Align WIP")]
-    [AutoInitShutdown]
-    [InlineData (" ", true, 1)]
-    [InlineData (" ", false, 1)]
-    [InlineData ("", true, 1)]
-    [InlineData ("", false, 1)]
-    [InlineData ("\n", true, 1)]
-    [InlineData ("\n", false, 1)]
-    [InlineData (" \n", true, 1)]
-    [InlineData (" \n", false, 2)]
-    public void Message_Empty_Or_A_NewLline_WrapMessagge_True_Or_False (
-        string message,
-        bool wrapMessage,
-        int linesLength
-    )
-    {
-        int iterations = -1;
+        Rectangle mbFrame = Rectangle.Empty;
 
 
         Application.Iteration += (s, a) =>
         Application.Iteration += (s, a) =>
                                  {
                                  {
@@ -179,140 +147,22 @@ public class MessageBoxTests
 
 
                                      if (iterations == 0)
                                      if (iterations == 0)
                                      {
                                      {
-                                         MessageBox.Query (string.Empty, message, 0, wrapMessage, "ok");
-
+                                         MessageBox.Query (string.Empty, message, 0, wrapMessage, hasButton ? ["0"] : []);
                                          Application.RequestStop ();
                                          Application.RequestStop ();
                                      }
                                      }
                                      else if (iterations == 1)
                                      else if (iterations == 1)
                                      {
                                      {
-                                         Application.Refresh ();
-
-                                         if (linesLength == 1)
-                                         {
-                                             TestHelpers.AssertDriverContentsWithFrameAre (
-                                                                                           @$"
-                ┌──────────────────────────────────────────────┐
-                │                                              │
-                │                                              │
-                │                   {
-                    CM.Glyphs.LeftBracket
-                }{
-                    CM.Glyphs.LeftDefaultIndicator
-                } ok {
-                    CM.Glyphs.RightDefaultIndicator
-                }{
-                    CM.Glyphs.RightBracket
-                }                   │
-                └──────────────────────────────────────────────┘",
-                                                                                           _output
-                                                                                          );
-                                         }
-                                         else
-                                         {
-                                             TestHelpers.AssertDriverContentsWithFrameAre (
-                                                                                           @$"
-                ┌──────────────────────────────────────────────┐
-                │                                              │
-                │                                              │
-                │                                              │
-                │                   {
-                    CM.Glyphs.LeftBracket
-                }{
-                    CM.Glyphs.LeftDefaultIndicator
-                } ok {
-                    CM.Glyphs.RightDefaultIndicator
-                }{
-                    CM.Glyphs.RightBracket
-                }                   │
-                └──────────────────────────────────────────────┘",
-                                                                                           _output
-                                                                                          );
-                                         }
-
+                                         mbFrame = Application.Current.Frame;
                                          Application.RequestStop ();
                                          Application.RequestStop ();
                                      }
                                      }
                                  };
                                  };
 
 
         Application.Run ().Dispose ();
         Application.Run ().Dispose ();
-    }
-
-    [Fact (Skip = "Pos.Align WIP")]
-    [AutoInitShutdown]
-    public void Message_Long_Without_Spaces_WrapMessage_True ()
-    {
-        int iterations = -1;
-        var top = new Toplevel ();
-        top.BorderStyle = LineStyle.None;
-        ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
-
-        var btn =
-            $"{
-                CM.Glyphs.LeftBracket
-            }{
-                CM.Glyphs.LeftDefaultIndicator
-            } btn {
-                CM.Glyphs.RightDefaultIndicator
-            }{
-                CM.Glyphs.RightBracket
-            }";
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     iterations++;
-
-                                     if (iterations == 0)
-                                     {
-                                         // 50 characters should make the height of the wrapped text 7
-                                         MessageBox.Query (string.Empty, new string ('f', 50), 0, true, "btn");
-
-                                         Application.RequestStop ();
-                                     }
-                                     else if (iterations == 1)
-                                     {
-                                         Application.Refresh ();
-
-                                         TestHelpers.AssertDriverContentsWithFrameAre (
-                                                                                       @$"
-┌──────────────────┐
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│  ffffffffffffff  │
-│                  │
-│    {btn}     │
-└──────────────────┘",
-                                                                                       _output
-                                                                                      );
-                                         Application.RequestStop ();
-
-                                         // Really long text
-                                         MessageBox.Query (string.Empty, new string ('f', 500), 0, true, "btn");
-                                     }
-                                     else if (iterations == 2)
-                                     {
-                                         Application.Refresh ();
-
-                                         TestHelpers.AssertDriverContentsWithFrameAre (
-                                                                                       @$"
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│    {btn}     │",
-                                                                                       _output
-                                                                                      );
-                                         Application.RequestStop ();
-                                     }
-                                 };
 
 
-        Application.Run (top);
+        Assert.Equal (new (expectedX, expectedY, expectedW, expectedH), mbFrame);
     }
     }
 
 
-    [Fact (Skip = "Pos.Align WIP")]
+    [Fact]
     [AutoInitShutdown]
     [AutoInitShutdown]
     public void Message_With_Spaces_WrapMessage_False ()
     public void Message_With_Spaces_WrapMessage_False ()
     {
     {
@@ -322,15 +172,7 @@ public class MessageBoxTests
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
 
         var btn =
         var btn =
-            $"{
-                CM.Glyphs.LeftBracket
-            }{
-                CM.Glyphs.LeftDefaultIndicator
-            } btn {
-                CM.Glyphs.RightDefaultIndicator
-            }{
-                CM.Glyphs.RightBracket
-            }";
+            $"{CM.Glyphs.LeftBracket}{CM.Glyphs.LeftDefaultIndicator} btn {CM.Glyphs.RightDefaultIndicator}{CM.Glyphs.RightBracket}";
 
 
         Application.Iteration += (s, a) =>
         Application.Iteration += (s, a) =>
                                  {
                                  {
@@ -355,12 +197,10 @@ public class MessageBoxTests
 
 
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @"
                                                                                        @"
-────────────────────
-ff ff ff ff ff ff ff
-                    
-      ⟦► btn ◄⟧     
-────────────────────
-",
+ ╔════════════════╗
+ ║ ff ff ff ff ff ║
+ ║       ⟦► btn ◄⟧║
+ ╚════════════════╝",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
                                          Application.RequestStop ();
                                          Application.RequestStop ();
@@ -374,12 +214,10 @@ ff ff ff ff ff ff ff
 
 
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @"
                                                                                        @"
-────────────────────
-ffffffffffffffffffff
-                    
-     ⟦► btn ◄⟧      
-────────────────────
-",
+ ╔════════════════╗
+ ║ffffffffffffffff║
+ ║       ⟦► btn ◄⟧║
+ ╚════════════════╝",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
                                          Application.RequestStop ();
                                          Application.RequestStop ();
@@ -389,25 +227,17 @@ ffffffffffffffffffff
         Application.Run (top);
         Application.Run (top);
     }
     }
 
 
-    [Fact (Skip = "Pos.Align WIP")]
+    [Fact]
     [AutoInitShutdown]
     [AutoInitShutdown]
     public void Message_With_Spaces_WrapMessage_True ()
     public void Message_With_Spaces_WrapMessage_True ()
     {
     {
         int iterations = -1;
         int iterations = -1;
-        var top = new Toplevel();
+        var top = new Toplevel ();
         top.BorderStyle = LineStyle.None;
         top.BorderStyle = LineStyle.None;
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
 
         var btn =
         var btn =
-            $"{
-                CM.Glyphs.LeftBracket
-            }{
-                CM.Glyphs.LeftDefaultIndicator
-            } btn {
-                CM.Glyphs.RightDefaultIndicator
-            }{
-                CM.Glyphs.RightBracket
-            }";
+            $"{CM.Glyphs.LeftBracket}{CM.Glyphs.LeftDefaultIndicator} btn {CM.Glyphs.RightDefaultIndicator}{CM.Glyphs.RightBracket}";
 
 
         Application.Iteration += (s, a) =>
         Application.Iteration += (s, a) =>
                                  {
                                  {
@@ -430,254 +260,39 @@ ffffffffffffffffffff
                                      {
                                      {
                                          Application.Refresh ();
                                          Application.Refresh ();
 
 
-                                         TestHelpers.AssertDriverContentsWithFrameAre (@$"
-┌─────────────────┐
-│ff ff ff ff ff ff│
-│ff ff ff ff ff ff│
-│ ff ff ff ff ff  │
-│                 │
-│    {btn}    │
-└─────────────────┘",
-                                                                                       _output
-                                                                                      );
-                                         Application.RequestStop ();
-
-                                         // Really long text
-                                         MessageBox.Query (string.Empty, new string ('f', 500), 0, true, "btn");
-                                     }
-                                     else if (iterations == 2)
-                                     {
-                                         Application.Refresh ();
-
-                                         TestHelpers.AssertDriverContentsWithFrameAre (@$"
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│ffffffffffffffffff│
-│    {btn}     │",
-                                                                                       _output
-                                                                                      );
-                                         Application.RequestStop ();
-                                     }
-                                 };
-
-        Application.Run (top);
-        top.Dispose ();
-    }
-
-    [Fact (Skip = "Pos.Align WIP")]
-    [AutoInitShutdown]
-    public void Message_Without_Spaces_WrapMessage_False ()
-    {
-        int iterations = -1;
-        var top = new Toplevel();
-        top.BorderStyle = LineStyle.None;
-        ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
-
-        var btn =
-            $"{
-                CM.Glyphs.LeftBracket
-            }{
-                CM.Glyphs.LeftDefaultIndicator
-            } btn {
-                CM.Glyphs.RightDefaultIndicator
-            }{
-                CM.Glyphs.RightBracket
-            }";
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     iterations++;
-
-                                     if (iterations == 0)
-                                     {
-                                         MessageBox.Query (string.Empty, new string ('f', 50), 0, false, "btn");
-
-                                         Application.RequestStop ();
-                                     }
-                                     else if (iterations == 1)
-                                     {
-                                         Application.Refresh ();
-
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @"
                                                                                        @"
-────────────────────
-ffffffffffffffffffff
-                    
-     ⟦► btn ◄⟧      
-────────────────────
-",
+  ╔══════════════╗
+  ║ff ff ff ff ff║
+  ║ff ff ff ff ff║
+  ║ff ff ff ff ff║
+  ║    ff ff     ║
+  ║     ⟦► btn ◄⟧║
+  ╚══════════════╝",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
-
                                          Application.RequestStop ();
                                          Application.RequestStop ();
 
 
                                          // Really long text
                                          // Really long text
-                                         MessageBox.Query (string.Empty, new string ('f', 500), 0, false, "btn");
+                                         MessageBox.Query (string.Empty, new string ('f', 500), 0, true, "btn");
                                      }
                                      }
                                      else if (iterations == 2)
                                      else if (iterations == 2)
                                      {
                                      {
                                          Application.Refresh ();
                                          Application.Refresh ();
 
 
-                                         TestHelpers.AssertDriverContentsWithFrameAre (
-                                                                                       @"
-────────────────────
-ffffffffffffffffffff
-                    
-     ⟦► btn ◄⟧      
-────────────────────
-",
-                                                                                       _output
-                                                                                      );
-
-                                         Application.RequestStop ();
-                                     }
-                                 };
-
-        Application.Run (top);
-    }
-
-    [Fact (Skip = "Pos.Align WIP")]
-    [AutoInitShutdown]
-    public void Size_Default ()
-    {
-        int iterations = -1;
-        ((FakeDriver)Application.Driver).SetBufferSize (100, 100);
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     iterations++;
-
-                                     if (iterations == 0)
-                                     {
-                                         MessageBox.Query (string.Empty, string.Empty, null);
-
-                                         Application.RequestStop ();
-                                     }
-                                     else if (iterations == 1)
-                                     {
-                                         Application.Refresh ();
-
-                                         Assert.IsType<Dialog> (Application.Current);
-
-                                         // Default size is Percent(60)
-                                         Assert.Equal (new ((int)(100 * .60), 5), Application.Current.Frame.Size);
-
-                                         Application.RequestStop ();
-                                     }
-                                 };
-
-        Application.Run ().Dispose ();
-    }
-
-    [Fact (Skip = "Pos.Align WIP")]
-    [AutoInitShutdown]
-    public void Size_JustBigEnough_Fixed_Size ()
-    {
-        int iterations = -1;
-
-        var btn =
-            $"{
-                CM.Glyphs.LeftBracket
-            }{
-                CM.Glyphs.LeftDefaultIndicator
-            } Ok {
-                CM.Glyphs.RightDefaultIndicator
-            }{
-                CM.Glyphs.RightBracket
-            }";
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     iterations++;
-
-                                     if (iterations == 0)
-                                     {
-                                         MessageBox.Query (11, 5, string.Empty, "Message", "_Ok");
-
-                                         Application.RequestStop ();
-                                     }
-                                     else if (iterations == 1)
-                                     {
-                                         Application.Refresh ();
-
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @$"
                                                                                        @$"
-                                  ┌─────────┐
-                                  │ Message │
-                                  │         │
-                                  │{
-                                      btn
-                                  } │
-                                  └─────────┘
-",
+ ╔════════════════╗
+ ║ffffffffffffffff║
+ ║ffffffffffffffff║
+ ║ffffffffffffffff║
+ ║ffffffffffffffff║
+ ║ffffffffffffffff║
+ ║ffffffffffffffff║
+ ║fffffff⟦► btn ◄⟧║
+ ╚════════════════╝",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
-
-                                         Application.RequestStop ();
-                                     }
-                                 };
-
-        Application.Run ().Dispose ();
-    }
-
-    [Fact (Skip = "Pos.Align WIP")]
-    [AutoInitShutdown]
-    public void Size_No_With_Button ()
-    {
-        var top = new Toplevel ();
-        top.BorderStyle = LineStyle.None;
-        int iterations = -1;
-
-        var aboutMessage = new StringBuilder ();
-        aboutMessage.AppendLine (@"0123456789012345678901234567890123456789");
-        aboutMessage.AppendLine (@"https://github.com/gui-cs/Terminal.Gui");
-        var message = aboutMessage.ToString ();
-
-        var btn =
-            $"{
-                CM.Glyphs.LeftBracket
-            }{
-                CM.Glyphs.LeftDefaultIndicator
-            } Ok {
-                CM.Glyphs.RightDefaultIndicator
-            }{
-                CM.Glyphs.RightBracket
-            }";
-
-        ((FakeDriver)Application.Driver).SetBufferSize (40 + 4, 8);
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     iterations++;
-
-                                     if (iterations == 0)
-                                     {
-                                         MessageBox.Query (string.Empty, message, "_Ok");
-
-                                         Application.RequestStop ();
-                                     }
-                                     else if (iterations == 1)
-                                     {
-                                         Application.Refresh ();
-
-                                         TestHelpers.AssertDriverContentsWithFrameAre (
-                                                                                       @$"
- ┌────────────────────────────────────────┐
- │0123456789012345678901234567890123456789│
- │ https://github.com/gui-cs/Terminal.Gui │
- │                                        │
- │                {btn}                │
- └────────────────────────────────────────┘
-",
-                                                                                       _output
-                                                                                      );
-
                                          Application.RequestStop ();
                                          Application.RequestStop ();
                                      }
                                      }
                                  };
                                  };
@@ -686,44 +301,6 @@ ffffffffffffffffffff
         top.Dispose ();
         top.Dispose ();
     }
     }
 
 
-    [Fact (Skip = "Pos.Align WIP")]
-    [AutoInitShutdown]
-    public void Size_None_No_Buttons ()
-    {
-        int iterations = -1;
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     iterations++;
-
-                                     if (iterations == 0)
-                                     {
-                                         MessageBox.Query ("Title", "Message");
-
-                                         Application.RequestStop ();
-                                     }
-                                     else if (iterations == 1)
-                                     {
-                                         Application.Refresh ();
-
-                                         TestHelpers.AssertDriverContentsWithFrameAre (
-                                                                                       @"
-                ┌┤Title├───────────────────────────────────────┐
-                │                   Message                    │
-                │                                              │
-                │                                              │
-                └──────────────────────────────────────────────┘
-",
-                                                                                       _output
-                                                                                      );
-
-                                         Application.RequestStop ();
-                                     }
-                                 };
-
-        Application.Run ().Dispose ();
-    }
-
     [Theory]
     [Theory]
     [InlineData (0, 0, "1")]
     [InlineData (0, 0, "1")]
     [InlineData (1, 1, "1")]
     [InlineData (1, 1, "1")]
@@ -831,46 +408,60 @@ ffffffffffffffffffff
                                  };
                                  };
     }
     }
 
 
-    // TODO: Reimplement once messagebox ues Dim.Auto
-//    [Fact]
-//    [AutoInitShutdown]
-//    public void Size_Tiny_Fixed_Size ()
-//    {
-//        int iterations = -1;
-
-//        Application.Iteration += (s, a) =>
-//                                 {
-//                                     iterations++;
-
-//                                     if (iterations == 0)
-//                                     {
-//                                         MessageBox.Query (7, 5, string.Empty, "Message", "_Ok");
-
-//                                         Application.RequestStop ();
-//                                     }
-//                                     else if (iterations == 1)
-//                                     {
-//                                         Application.Refresh ();
-
-//                                         Assert.Equal (new (7, 5), Application.Current.Frame.Size);
-
-//                                         TestHelpers.AssertDriverContentsWithFrameAre (
-//                                                                                       @$"
-//                                    ┌─────┐
-//                                    │Messa│
-//                                    │ ge  │
-//                                    │ Ok {
-//                                        CM.Glyphs.RightDefaultIndicator
-//                                    }│
-//                                    └─────┘
-//",
-//                                                                                       _output
-//                                                                                      );
-
-//                                         Application.RequestStop ();
-//                                     }
-//                                 };
-
-//        Application.Run ().Dispose ();
-//    }
+    [Fact]
+    [AutoInitShutdown]
+    public void UICatalog_AboutBox ()
+    {
+        int iterations = -1;
+        ((FakeDriver)Application.Driver).SetBufferSize (70, 15);
+
+        Application.Iteration += (s, a) =>
+                                 {
+                                     iterations++;
+
+                                     if (iterations == 0)
+                                     {
+                                         MessageBox.Query (
+                                                           title: "",
+                                                           message: UICatalog.UICatalogApp.GetAboutBoxMessage (),
+                                                           wrapMessage: false,
+                                                           buttons: "_Ok"
+                                                          );
+
+                                         Application.RequestStop ();
+                                     }
+                                     else if (iterations == 1)
+                                     {
+                                         Application.Refresh ();
+
+                                         string expectedText = """
+                                                               ┌────────────────────────────────────────────────────────────────────┐
+                                                               │    ╔══════════════════════════════════════════════════════════╗    │
+                                                               │    ║      UI Catalog: A comprehensive sample library for      ║    │
+                                                               │    ║                                                          ║    │
+                                                               │    ║ _______                  _             _   _____       _ ║    │
+                                                               │    ║|__   __|                (_)           | | / ____|     (_)║    │
+                                                               │    ║   | | ___ _ __ _ __ ___  _ _ __   __ _| || |  __ _   _ _ ║    │
+                                                               │    ║   | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | || | |_ | | | | |║    │
+                                                               │    ║   | |  __/ |  | | | | | | | | | | (_| | || |__| | |_| | |║    │
+                                                               │    ║   |_|\___|_|  |_| |_| |_|_|_| |_|\__,_|_(_)_____|\__,_|_|║    │
+                                                               │    ║                                                          ║    │
+                                                               │    ║                      v2 - Pre-Alpha                      ║    │
+                                                               │    ║                                                  ⟦► Ok ◄⟧║    │
+                                                               │    ╚══════════════════════════════════════════════════════════╝    │
+                                                               └────────────────────────────────────────────────────────────────────┘
+                                                               """;
+
+                                         TestHelpers.AssertDriverContentsAre (expectedText, _output);
+
+                                         Application.RequestStop ();
+                                     }
+                                 };
+
+        var top = new Toplevel ();
+        top.BorderStyle = LineStyle.Single;
+        Application.Run (top);
+
+    }
 }
 }
+

+ 7 - 0
UnitTests/TestHelpers.cs

@@ -448,6 +448,13 @@ internal partial class TestHelpers
             expectedLook = expectedLook [..^Environment.NewLine.Length];
             expectedLook = expectedLook [..^Environment.NewLine.Length];
         }
         }
 
 
+        // If test is about to fail show user what things looked like
+        if (!string.Equals (expectedLook, actualLook))
+        {
+            output?.WriteLine ("Expected:" + Environment.NewLine + expectedLook);
+            output?.WriteLine (" But Was:" + Environment.NewLine + actualLook);
+        }
+
         Assert.Equal (expectedLook, actualLook);
         Assert.Equal (expectedLook, actualLook);
 
 
         return new (x > -1 ? x : 0, y > -1 ? y : 0, w > -1 ? w : 0, h > -1 ? h : 0);
         return new (x > -1 ? x : 0, y > -1 ? y : 0, w > -1 ? w : 0, h > -1 ? h : 0);

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 292 - 636
UnitTests/Text/TextFormatterTests.cs


+ 6 - 6
UnitTests/View/Adornment/ShadowStyletests.cs

@@ -99,15 +99,15 @@ public class ShadowStyleTests (ITestOutputHelper _output)
     [InlineData (
     [InlineData (
                     ShadowStyle.Transparent,
                     ShadowStyle.Transparent,
                     """
                     """
-                    011
-                    131
+                    031
+                    331
                     111
                     111
                     """)]
                     """)]
     [InlineData (
     [InlineData (
                     ShadowStyle.Opaque,
                     ShadowStyle.Opaque,
                     """
                     """
-                    011
-                    121
+                    021
+                    221
                     111
                     111
                     """)]
                     """)]
     [SetupFakeDriver]
     [SetupFakeDriver]
@@ -182,9 +182,9 @@ public class ShadowStyleTests (ITestOutputHelper _output)
     [InlineData (
     [InlineData (
                     ShadowStyle.Opaque,
                     ShadowStyle.Opaque,
                     """
                     """
-                    01#$
+                    01$
                     AB▌$
                     AB▌$
-                    !▀▘$
+                    ▀▘$
                     !@#$
                     !@#$
                     """)]
                     """)]
     [InlineData (
     [InlineData (

+ 5 - 6
UnitTests/View/DrawTests.cs

@@ -293,7 +293,6 @@ public class DrawTests (ITestOutputHelper _output)
         var top = new Toplevel ();
         var top = new Toplevel ();
         top.Add (win);
         top.Add (win);
 
 
-        // Don't use Label. It sets AutoSize = true which is not what we're testing here.
         var view = new View { Text = "ワイドルーン。", Height = Dim.Fill (), Width = Dim.Fill () };
         var view = new View { Text = "ワイドルーン。", Height = Dim.Fill (), Width = Dim.Fill () };
 
 
         // Don't have unit tests use things that aren't absolutely critical for the test, like Dialog
         // Don't have unit tests use things that aren't absolutely critical for the test, like Dialog
@@ -394,7 +393,7 @@ public class DrawTests (ITestOutputHelper _output)
         var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
         var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Screen.Size);
+        view.SetRelativeLayout (Application.Screen.Size);
 
 
         Assert.Equal (new (0, 0, 2, 2), view.Frame);
         Assert.Equal (new (0, 0, 2, 2), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);
@@ -419,7 +418,7 @@ public class DrawTests (ITestOutputHelper _output)
         view.Border.Thickness = new Thickness (1, 1, 1, 0);
         view.Border.Thickness = new Thickness (1, 1, 1, 0);
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Screen.Size);
+        view.SetRelativeLayout (Application.Screen.Size);
 
 
         Assert.Equal (new (0, 0, 2, 1), view.Frame);
         Assert.Equal (new (0, 0, 2, 1), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);
@@ -437,7 +436,7 @@ public class DrawTests (ITestOutputHelper _output)
         view.Border.Thickness = new Thickness (0, 1, 1, 1);
         view.Border.Thickness = new Thickness (0, 1, 1, 1);
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Screen.Size);
+        view.SetRelativeLayout (Application.Screen.Size);
 
 
         Assert.Equal (new (0, 0, 1, 2), view.Frame);
         Assert.Equal (new (0, 0, 1, 2), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);
@@ -462,7 +461,7 @@ public class DrawTests (ITestOutputHelper _output)
         view.Border.Thickness = new Thickness (1, 1, 0, 1);
         view.Border.Thickness = new Thickness (1, 1, 0, 1);
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Screen.Size);
+        view.SetRelativeLayout (Application.Screen.Size);
 
 
         Assert.Equal (new (0, 0, 1, 2), view.Frame);
         Assert.Equal (new (0, 0, 1, 2), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);
@@ -488,7 +487,7 @@ public class DrawTests (ITestOutputHelper _output)
 
 
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Screen.Size);
+        view.SetRelativeLayout (Application.Screen.Size);
 
 
         Assert.Equal (new (0, 0, 2, 1), view.Frame);
         Assert.Equal (new (0, 0, 2, 1), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);

+ 226 - 0
UnitTests/View/Layout/Dim.AutoTests.DimTypes.cs

@@ -0,0 +1,226 @@
+namespace Terminal.Gui.LayoutTests;
+
+public partial class DimAutoTests
+{
+    // Tests all the Dim Types in Subview scenarios to ensure DimAutoStyle.Content is calculated correctly
+
+    #region DimAbsolute
+
+    [Theory]
+    [InlineData (0, 15, 15)]
+    [InlineData (1, 15, 16)]
+    [InlineData (-1, 15, 14)]
+    public void With_Subview_Using_DimAbsolute (int subViewOffset, int dimAbsoluteSize, int expectedSize)
+    {
+        var view = new View ();
+
+        var subview = new View
+        {
+            X = subViewOffset,
+            Y = subViewOffset,
+            Width = Dim.Absolute (dimAbsoluteSize),
+            Height = Dim.Absolute (dimAbsoluteSize)
+        };
+        view.Add (subview);
+
+        Dim dim = Dim.Auto (DimAutoStyle.Content);
+
+        int calculatedWidth = dim.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = dim.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedSize, calculatedWidth);
+        Assert.Equal (expectedSize, calculatedHeight);
+    }
+
+    #endregion DimAbsolute
+
+    #region DimPercent
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 50, 0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 0, 100, 100, 100, 100, 100, 100)]
+    [InlineData (0, 50, 100, 100, 100, 100, 100, 100)]
+    public void With_Subview_Using_DimPercent (
+        int subViewOffset,
+        int percent,
+        int minWidth,
+        int maxWidth,
+        int minHeight,
+        int maxHeight,
+        int expectedWidth,
+        int expectedHeight
+    )
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var subview = new View
+        {
+            X = subViewOffset,
+            Y = subViewOffset,
+            Width = Dim.Percent (percent),
+            Height = Dim.Percent (percent)
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth); // subview's width
+        Assert.Equal (expectedHeight, calculatedHeight); // subview's height
+        Assert.Equal (subViewOffset, calculatedX);
+        Assert.Equal (subViewOffset, calculatedY);
+
+        view.SetRelativeLayout (new (100, 100));
+        view.LayoutSubviews ();
+
+        Assert.Equal (expectedWidth * (percent / 100f), subview.Viewport.Width);
+        Assert.Equal (expectedHeight * (percent / 100f), subview.Viewport.Height);
+    }
+    #endregion DimPercent
+
+    #region DimFill
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 0, 0)]
+    [InlineData (0, 20, 0, 10, 0, 0)]
+    [InlineData (0, 21, 0, 11, 0, 0)]
+    [InlineData (1, 21, 1, 11, 1, 1)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    public void With_Subview_Using_DimFill (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var subview = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Fill (),
+            Height = Dim.Fill ()
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+    }
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 2, 4)]
+    [InlineData (0, 20, 0, 10, 2, 4)]
+    [InlineData (0, 21, 0, 11, 2, 4)]
+    [InlineData (1, 21, 1, 11, 2, 4)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    public void With_Subview_Using_DimFill_And_Another_Subview (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var absView = new View
+        {
+            X = 1,
+            Y = 2,
+            Width = 1,
+            Height = 2
+        };
+        view.Add (absView);
+
+        var subview = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Fill (),
+            Height = Dim.Fill ()
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+    }
+
+    #endregion
+
+    #region DimFunc
+
+    [Fact]
+    public void With_Subview_Using_DimFunc ()
+    {
+        var view = new View ();
+        var subview = new View { Width = Dim.Func (() => 20), Height = Dim.Func (() => 25) };
+        view.Add (subview);
+
+        subview.SetRelativeLayout (new (100, 100));
+
+        Dim dim = Dim.Auto (DimAutoStyle.Content);
+
+        int calculatedWidth = dim.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = dim.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (20, calculatedWidth);
+        Assert.Equal (25, calculatedHeight);
+    }
+
+    #endregion DimFunc
+
+    #region DimView
+
+    [Fact]
+    public void With_Subview_Using_DimView ()
+    {
+        var view = new View ();
+        var subview = new View { Width = 30, Height = 40 };
+        var subSubview = new View { Width = Dim.Width (subview), Height = Dim.Height (subview) };
+        view.Add (subview);
+        view.Add (subSubview);
+
+        subview.SetRelativeLayout (new (100, 100));
+
+        Dim dim = Dim.Auto (DimAutoStyle.Content);
+
+        int calculatedWidth = dim.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = dim.Calculate (0, 100, view, Dimension.Height);
+
+        // Expecting the size to match the subview, which is the largest
+        Assert.Equal (30, calculatedWidth);
+        Assert.Equal (40, calculatedHeight);
+    }
+
+    #endregion DimView
+
+    #region DimCombine
+    // TODO: Need DimCombine tests
+    #endregion DimCombine
+}

+ 195 - 0
UnitTests/View/Layout/Dim.AutoTests.MinMax.cs

@@ -0,0 +1,195 @@
+namespace Terminal.Gui.LayoutTests;
+
+public partial class DimAutoTests
+{
+    #region minimumContentDim Tests
+
+    [Fact]
+    public void Min_Is_Honored ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (minimumContentDim: 10),
+            Height = Dim.Auto (minimumContentDim: 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 (10, 10));
+        superView.LayoutSubviews (); // no throw
+
+        Assert.Equal (10, superView.Frame.Width);
+        Assert.Equal (10, superView.Frame.Height);
+    }
+
+    [Theory]
+    [InlineData (0, 2, 4)]
+    [InlineData (1, 2, 4)]
+    [InlineData (2, 2, 4)]
+    [InlineData (3, 2, 5)]
+    [InlineData (1, 0, 3)]
+    public void Min_Absolute_Is_Content_Relative (int contentSize, int minAbsolute, int expected)
+    {
+        var view = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (minimumContentDim: minAbsolute),
+            BorderStyle = LineStyle.Single, // a 1 thick adornment
+            ValidatePosDim = true
+        };
+
+        view.SetContentSize (new (contentSize, 0));
+
+        Assert.Equal (expected, view.Frame.Width);
+    }
+
+    [Theory]
+    [InlineData (1, 100, 100)]
+    [InlineData (1, 50, 50)]
+    public void Min_Percent (int contentSize, int minPercent, int expected)
+    {
+        var view = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (minimumContentDim: Dim.Percent (minPercent)),
+            ValidatePosDim = true
+        };
+
+        view.SetContentSize (new (contentSize, 0));
+        view.SetRelativeLayout (new (100, 100));
+
+        Assert.Equal (expected, view.Frame.Width);
+    }
+
+    [Theory]
+    [InlineData (1, 100, 102)]
+    [InlineData (1, 50, 52)] // 50% of 100 is 50, but the border adds 2
+    [InlineData (1, 30, 32)] // 30% of 100 is 30, but the border adds 2
+    [InlineData (2, 30, 32)] // 30% of 100 is 30, but the border adds 2
+    public void Min_Percent_Is_Content_Relative (int contentSize, int minPercent, int expected)
+    {
+        var view = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (minimumContentDim: Dim.Percent (minPercent)),
+            BorderStyle = LineStyle.Single, // a 1 thick adornment
+            ValidatePosDim = true
+        };
+
+        view.SetContentSize (new (contentSize, 0));
+        view.SetRelativeLayout (new (100, 100));
+
+        Assert.Equal (expected, view.Frame.Width);
+    }
+
+    [Fact]
+    public void Min_Resets_If_Subview_Moves_Negative ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (minimumContentDim: 10),
+            Height = Dim.Auto (minimumContentDim: 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 (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 (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 Min_Resets_If_Subview_Shrinks ()
+    {
+        var superView = new View
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Auto (minimumContentDim: 10),
+            Height = Dim.Auto (minimumContentDim: 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 (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 (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);
+    }
+
+    #endregion minimumContentDim Tests
+
+    // Test min - ensure that if min is specified in the DimAuto constructor it is honored
+
+    // what happens if DimAuto (min: 10) and the subview moves to a negative coord?
+
+    #region maximumContentDim Tests
+    // TODO: Add tests
+
+    #endregion maximumContentDim Tests
+}

+ 616 - 0
UnitTests/View/Layout/Dim.AutoTests.PosTypes.cs

@@ -0,0 +1,616 @@
+namespace Terminal.Gui.LayoutTests;
+
+public partial class DimAutoTests
+{
+    // Tests all the Pos Types in Subview scenarios to ensure DimAutoStyle.Content is calculated correctly
+
+    #region PosAbsolute
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 21, 11)]
+    [InlineData (1, 21, 1, 11, 21, 11)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    public void With_Subview_Using_PosAbsolute (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var subview = new View
+        {
+            X = Pos.Absolute (10),
+            Y = Pos.Absolute (5),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+    }
+
+    #endregion PosAbsolute
+
+    #region PosPercent
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 20, 10)]
+    [InlineData (1, 21, 1, 11, 20, 10)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    public void With_Subview_Using_PosPercent (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var subview = new View
+        {
+            X = Pos.Percent (50),
+            Y = Pos.Percent (50),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // subview should be at 50% in the parent view
+        Assert.Equal ((int)(view.Viewport.Width * .50), subview.Frame.X);
+        Assert.Equal ((int)(view.Viewport.Height * .50), subview.Frame.Y);
+    }
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 21, 11)]
+    [InlineData (1, 21, 1, 11, 21, 11)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    public void With_Subview_Using_PosPercent_Combine (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var subview = new View
+        {
+            X = Pos.Percent (50) + 1,
+            Y = 1 + Pos.Percent (50),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // subview should be at 50% in the parent view
+        Assert.Equal ((int)(view.Viewport.Width * .50) + 1, subview.Frame.X);
+        Assert.Equal ((int)(view.Viewport.Height * .50) + 1, subview.Frame.Y);
+    }
+
+    #endregion PosPercent
+
+    #region PosCenter
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 20, 10)]
+    [InlineData (1, 21, 1, 11, 20, 10)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    public void With_Subview_Using_PosCenter (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var subview = new View
+        {
+            X = Pos.Center (),
+            Y = Pos.Center (),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // subview should be centered in the parent view + 1
+        Assert.Equal ((view.Viewport.Width - subview.Frame.Width) / 2, subview.Frame.X);
+        Assert.Equal ((view.Viewport.Height - subview.Frame.Height) / 2, subview.Frame.Y);
+    }
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 18, 0, 8, 18, 8)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 21, 11)]
+    [InlineData (1, 21, 1, 11, 21, 11)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    public void With_Subview_Using_PosCenter_Combine (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var subview = new View
+        {
+            X = Pos.Center () + 1,
+            Y = 1 + Pos.Center (),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // subview should be centered in the parent view + 1
+        Assert.Equal ((view.Viewport.Width - subview.Frame.Width) / 2 + 1, subview.Frame.X);
+        Assert.Equal ((view.Viewport.Height - subview.Frame.Height) / 2 + 1, subview.Frame.Y);
+    }
+
+    #endregion PosCenter
+
+    #region PosView
+
+    // TODO: Need PosView tests
+
+    [Fact]
+    public void With_Subview_Using_PosView ()
+    {
+        var view = new View ()
+        {
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+        };
+        var subview1 = new View { X = 1, Y = 2, Width = 1, Height = 2 };
+        var subview2 = new View { X = Pos.Top (subview1), Y = Pos.Bottom (subview1), Width = 1, Height = 2 };
+        view.Add (subview1, subview2);
+
+        view.SetRelativeLayout (new (100, 100));
+
+        // subview1.X + subview1.Width + subview2.Width
+        Assert.Equal (1 + 1 + 1, view.Frame.Width);
+        // subview1.Y + subview1.Height + subview2.Height
+        Assert.Equal (2 + 2 + 2, view.Frame.Height);
+    }
+
+    #endregion PosView
+
+    #region PosAnchorEnd
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 18, 0, 8, 18, 8)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 20, 10)]
+    [InlineData (1, 21, 1, 11, 20, 10)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    public void With_Subview_Using_PosAnchorEnd (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var subview = new View
+        {
+            X = Pos.AnchorEnd (),
+            Y = Pos.AnchorEnd (),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // subview should be at the end of the view
+        Assert.Equal (view.Viewport.Width - subview.Frame.Width, subview.Frame.X);
+        Assert.Equal (view.Viewport.Height - subview.Frame.Height, subview.Frame.Y);
+    }
+
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 18, 0, 8, 18, 8)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 21, 11)]
+    [InlineData (1, 21, 1, 11, 21, 11)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    [InlineData (0, 30, 0, 20, 25, 15)]
+    public void With_Subview_And_Subview_Using_PosAnchorEnd (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var otherView = new View
+        {
+            Width = 5,
+            Height = 5
+        };
+        view.Add (otherView);
+
+        var subview = new View
+        {
+            X = Pos.AnchorEnd (),
+            Y = Pos.AnchorEnd (),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // subview should be at the end of the view
+        Assert.Equal (view.Viewport.Width - subview.Frame.Width, subview.Frame.X);
+        Assert.Equal (view.Viewport.Height - subview.Frame.Height, subview.Frame.Y);
+    }
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 18, 0, 8, 18, 8)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 21, 11)]
+    [InlineData (1, 21, 1, 11, 21, 11)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    [InlineData (0, 30, 0, 20, 25, 15)]
+    public void With_DimAutoSubview_And_Subview_Using_PosAnchorEnd (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var otherView = new View
+        {
+            Text = "01234\n01234\n01234\n01234\n01234",
+            Width = Dim.Auto(),
+            Height = Dim.Auto ()
+        };
+        view.Add (otherView);
+
+        var subview = new View
+        {
+            X = Pos.AnchorEnd (),
+            Y = Pos.AnchorEnd (),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // subview should be at the end of the view
+        Assert.Equal (view.Viewport.Width - subview.Frame.Width, subview.Frame.X);
+        Assert.Equal (view.Viewport.Height - subview.Frame.Height, subview.Frame.Y);
+    }
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 18, 0, 8, 18, 8)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 21, 11)]
+    [InlineData (1, 21, 1, 11, 21, 11)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    [InlineData (0, 30, 0, 20, 26, 16)]
+    public void With_PosViewSubview_And_Subview_Using_PosAnchorEnd (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var otherView = new View
+        {
+            Width = 1,
+            Height = 1,
+        };
+        view.Add (otherView);
+
+        var posViewView = new View
+        {
+            X = Pos.Bottom(otherView),
+            Y = Pos.Right(otherView),
+            Width = 5,
+            Height = 5,
+        };
+        view.Add (posViewView);
+
+        var subview = new View
+        {
+            X = Pos.AnchorEnd (),
+            Y = Pos.AnchorEnd (),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // subview should be at the end of the view
+        Assert.Equal (view.Viewport.Width - subview.Frame.Width, subview.Frame.X);
+        Assert.Equal (view.Viewport.Height - subview.Frame.Height, subview.Frame.Y);
+    }
+
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0)]
+    [InlineData (0, 19, 0, 9, 19, 9)]
+    [InlineData (0, 18, 0, 8, 18, 8)]
+    [InlineData (0, 20, 0, 10, 20, 10)]
+    [InlineData (0, 21, 0, 11, 21, 11)]
+    [InlineData (1, 21, 1, 11, 21, 11)]
+    [InlineData (21, 21, 11, 11, 21, 11)]
+    [InlineData (0, 30, 0, 20, 22, 12)]
+    public void With_DimViewSubview_And_Subview_Using_PosAnchorEnd (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
+            Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
+        };
+
+        var otherView = new View
+        {
+            Width = 1,
+            Height = 1,
+        };
+        view.Add (otherView);
+
+        var dimViewView = new View
+        {
+            Id = "dimViewView",
+            X = 1,
+            Y = 1,
+            Width = Dim.Width (otherView),
+            Height = Dim.Height (otherView),
+        };
+        view.Add (dimViewView);
+
+        var subview = new View
+        {
+            X = Pos.AnchorEnd (),
+            Y = Pos.AnchorEnd (),
+            Width = 20,
+            Height = 10
+        };
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // subview should be at the end of the view
+        Assert.Equal (view.Viewport.Width - subview.Frame.Width, subview.Frame.X);
+        Assert.Equal (view.Viewport.Height - subview.Frame.Height, subview.Frame.Y);
+    }
+    [Theory]
+    [InlineData (0, 10, 0, 10, 10, 2)]
+    [InlineData (0, 5, 0, 5, 5, 3)] // max width of 5 should cause wordwrap at 5 giving a height of 2 + 1
+    [InlineData (0, 19, 0, 9, 11, 2)]
+    //[InlineData (0, 20, 0, 10, 20, 10)]
+    //[InlineData (0, 21, 0, 11, 21, 11)]
+    //[InlineData (1, 21, 1, 11, 21, 11)]
+    //[InlineData (21, 21, 11, 11, 21, 11)]
+    public void With_Text_And_Subview_Using_PosAnchorEnd (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
+    {
+        var view = new View
+        {
+            Text = "01234ABCDE",
+            Width = Dim.Auto (),
+            Height = Dim.Auto ()
+        };
+
+        // Without a subview, width should be 10
+        // Without a subview, height should be 1
+        view.SetRelativeLayout (Application.Screen.Size);
+        Assert.Equal (10, view.Frame.Width);
+        Assert.Equal (1, view.Frame.Height);
+
+        view.Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth);
+        view.Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight);
+
+        var subview = new View
+        {
+            X = Pos.AnchorEnd (),
+            Y = Pos.AnchorEnd (),
+            Width = 1,
+            Height = 1
+        };
+
+        view.Add (subview);
+
+        // Assuming the calculation is done after layout
+        int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
+        int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
+        int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
+        int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
+
+        Assert.Equal (expectedWidth, calculatedWidth);
+        Assert.Equal (expectedHeight, calculatedHeight);
+
+        Assert.Equal (0, calculatedX);
+        Assert.Equal (0, calculatedY);
+    }
+
+    #endregion PosAnchorEnd
+
+    #region PosFunc
+
+    [Fact]
+    public void With_Subview_Using_PosFunc ()
+    {
+        var view = new View ()
+        {
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+        };
+        var subview = new View { X = Pos.Func (() => 20), Y = Pos.Func (() => 25) };
+        view.Add (subview);
+
+        view.SetRelativeLayout (new (100, 100));
+
+        Assert.Equal (20, view.Frame.Width);
+        Assert.Equal (25, view.Frame.Height);
+    }
+
+    #endregion PosFunc
+
+    #region PosCombine
+
+    // TODO: Need more PosCombine tests
+
+    #endregion PosCombine
+}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 234 - 650
UnitTests/View/Layout/Dim.AutoTests.cs


+ 2 - 2
UnitTests/View/Layout/Dim.PercentTests.cs

@@ -67,9 +67,9 @@ public class DimPercentTests
     public void DimPercent_Invalid_Throws ()
     public void DimPercent_Invalid_Throws ()
     {
     {
         Dim dim = Dim.Percent (0);
         Dim dim = Dim.Percent (0);
-        Assert.Throws<ArgumentException> (() => dim = Dim.Percent (-1));
+        Assert.Throws<ArgumentOutOfRangeException> (() => dim = Dim.Percent (-1));
         //Assert.Throws<ArgumentException> (() => dim = Dim.Percent (101));
         //Assert.Throws<ArgumentException> (() => dim = Dim.Percent (101));
-        Assert.Throws<ArgumentException> (() => dim = Dim.Percent (-1000001));
+        Assert.Throws<ArgumentOutOfRangeException> (() => dim = Dim.Percent (-1000001));
         //Assert.Throws<ArgumentException> (() => dim = Dim.Percent (1000001));
         //Assert.Throws<ArgumentException> (() => dim = Dim.Percent (1000001));
     }
     }
 
 

+ 1 - 1
UnitTests/View/Layout/Pos.AnchorEndTests.cs

@@ -67,7 +67,7 @@ public class PosAnchorEndTests (ITestOutputHelper output)
     {
     {
         Pos pos;
         Pos pos;
         int n = -1;
         int n = -1;
-        Assert.Throws<ArgumentException> (() => pos = Pos.AnchorEnd (n));
+        Assert.Throws<ArgumentOutOfRangeException> (() => pos = Pos.AnchorEnd (n));
     }
     }
 
 
     [Theory]
     [Theory]

+ 23 - 4
UnitTests/View/Layout/Pos.CenterTests.cs

@@ -51,12 +51,31 @@ public class PosCenterTests (ITestOutputHelper output)
         Assert.IsType<PosCenter> (pos);
         Assert.IsType<PosCenter> (pos);
     }
     }
 
 
-    [Fact]
-    public void PosCenter_Calculate_ReturnsExpectedValue ()
+    [Theory]
+    [InlineData (10, 2, 4)]
+    [InlineData (10, 10, 0)]
+    [InlineData (10, 11, 0)]
+    [InlineData (10, 12, -1)]
+    [InlineData (19, 20, 0)]
+    public void PosCenter_Calculate_ReturnsExpectedValue (int superviewDimension, int width, int expectedX)
     {
     {
         var posCenter = new PosCenter ();
         var posCenter = new PosCenter ();
-        int result = posCenter.Calculate (10, new DimAbsolute (2), null, Dimension.None);
-        Assert.Equal (4, result);
+        int result = posCenter.Calculate (superviewDimension, new DimAbsolute (width), null!, Dimension.Width);
+        Assert.Equal (expectedX, result);
+    }
+
+
+    [Fact]
+    public void PosCenter_Bigger_Than_SuperView ()
+    {
+        var superView = new View { Width = 10, Height = 10 };
+        var view = new View { X = Center (), Y = Center (), Width = 20, Height = 20 };
+        superView.Add (view);
+        superView.BeginInit();
+        superView.EndInit();
+
+        Assert.Equal (-5, view.Frame.Left);
+        Assert.Equal (-5, view.Frame.Top);
     }
     }
 
 
     [Theory]
     [Theory]

+ 16 - 2
UnitTests/View/Layout/Pos.PercentTests.cs

@@ -7,6 +7,20 @@ public class PosPercentTests (ITestOutputHelper output)
 {
 {
     private readonly ITestOutputHelper _output = output;
     private readonly ITestOutputHelper _output = output;
 
 
+    [Theory]
+    [InlineData (50, 10, 2, 5)]
+    [InlineData (50, 10, 10, 5)]
+    [InlineData (50, 10, 11, 5)]
+    [InlineData (50, 10, 12, 5)]
+    [InlineData (50, 19, 20, 9)]
+    public void PosPercent_Calculate_ReturnsExpectedValue (int percent, int superviewDimension, int width, int expectedX)
+    {
+        var posPercent = new PosPercent (percent);
+        int result = posPercent.Calculate (superviewDimension, new DimAbsolute (width), null!, Dimension.Width);
+        Assert.Equal (expectedX, result);
+    }
+
+
     // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
     // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
     // TODO: A new test that calls SetRelativeLayout directly is needed.
     // TODO: A new test that calls SetRelativeLayout directly is needed.
     [Theory]
     [Theory]
@@ -61,10 +75,10 @@ public class PosPercentTests (ITestOutputHelper output)
     }
     }
 
 
     [Fact]
     [Fact]
-    public void PosPercent_ThrowsOnIvalid ()
+    public void PosPercent_ThrowsOnInvalid ()
     {
     {
         Pos pos = Percent (0);
         Pos pos = Percent (0);
-        Assert.Throws<ArgumentException> (() => pos = Percent (-1));
+        Assert.Throws<ArgumentOutOfRangeException> (() => pos = Percent (-1));
 
 
         //Assert.Throws<ArgumentException> (() => pos = Pos.Percent (101));
         //Assert.Throws<ArgumentException> (() => pos = Pos.Percent (101));
         //Assert.Throws<ArgumentException> (() => pos = Pos.Percent (1000001));
         //Assert.Throws<ArgumentException> (() => pos = Pos.Percent (1000001));

+ 0 - 2
UnitTests/View/Layout/Pos.Tests.cs

@@ -6,8 +6,6 @@ namespace Terminal.Gui.LayoutTests;
 
 
 public class PosTests ()
 public class PosTests ()
 {
 {
-    // Was named AutoSize_Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
-    // but doesn't actually have anything to do with AutoSize.
     [Fact]
     [Fact]
     public void
     public void
         Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
         Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()

+ 7 - 13
UnitTests/View/Layout/ViewportTests.cs

@@ -12,11 +12,8 @@ public class ViewportTests (ITestOutputHelper output)
     private readonly ITestOutputHelper _output = output;
     private readonly ITestOutputHelper _output = output;
 
 
     [Theory]
     [Theory]
-    [InlineData (0, 10)]
-    [InlineData (1, 10)]
-    [InlineData (-1, 10)]
-    [InlineData (11, 10)]
-    public void Get_Viewport_NoSuperView_WithoutAdornments (int x, int expectedW)
+    [CombinatorialData]
+    public void Get_Viewport_NoSuperView_WithoutAdornments ([CombinatorialRange (-11, 11)] int x)
     {
     {
         // We test with only X because Y is equivalent. Height/Width are irrelevant.
         // We test with only X because Y is equivalent. Height/Width are irrelevant.
         // Arrange
         // Arrange
@@ -31,7 +28,7 @@ public class ViewportTests (ITestOutputHelper output)
         var bounds = view.Viewport;
         var bounds = view.Viewport;
 
 
         // Assert
         // Assert
-        Assert.Equal (expectedW, bounds.Width);
+        Assert.Equal (10, bounds.Width);
     }
     }
 
 
     [Theory]
     [Theory]
@@ -250,11 +247,8 @@ public class ViewportTests (ITestOutputHelper output)
     }
     }
 
 
     [Theory]
     [Theory]
-    [InlineData (0, 0, 10, 10, 10, 10)]
-    [InlineData (10, 0, 10, 10, 10, 10)]
-    [InlineData (0, 10, 10, 10, 10, 10)]
-    [InlineData (10, 10, 10, 10, 10, 10)]
-    public void Set_Viewport_ValidValue_UpdatesViewport_AllowLocationGreaterThanContentSize (int viewWidth, int viewHeight, int viewportX, int viewportY, int expectedX, int expectedY)
+    [CombinatorialData]
+    public void Set_Viewport_ValidValue_UpdatesViewport_AllowLocationGreaterThanContentSize ([CombinatorialRange (0, 5)] int viewWidth, [CombinatorialRange (0, 5)] int viewHeight)
     {
     {
         // Arrange
         // Arrange
         var view = new View ()
         var view = new View ()
@@ -263,13 +257,13 @@ public class ViewportTests (ITestOutputHelper output)
             Height = viewHeight,
             Height = viewHeight,
             ViewportSettings = ViewportSettings.AllowLocationGreaterThanContentSize
             ViewportSettings = ViewportSettings.AllowLocationGreaterThanContentSize
         };
         };
-        var newViewport = new Rectangle (viewportX, viewportY, viewWidth, viewHeight);
+        var newViewport = new Rectangle (10, 10, viewWidth, viewHeight);
 
 
         // Act
         // Act
         view.Viewport = newViewport;
         view.Viewport = newViewport;
 
 
         // Assert
         // Assert
-        Assert.Equal (new Rectangle (expectedX, expectedY, viewWidth, viewHeight), view.Viewport);
+        Assert.Equal (new Rectangle (10, 10, viewWidth, viewHeight), view.Viewport);
     }
     }
 
 
     [Fact]
     [Fact]

+ 49 - 146
UnitTests/View/TextTests.cs

@@ -5,8 +5,7 @@ using Xunit.Abstractions;
 namespace Terminal.Gui.ViewTests;
 namespace Terminal.Gui.ViewTests;
 
 
 /// <summary>
 /// <summary>
-///     Tests of the <see cref="View.Text"/> and <see cref="View.TextFormatter"/> properties (independent of
-///     AutoSize).
+///     Tests of the <see cref="View.Text"/> and <see cref="View.TextFormatter"/> properties.
 /// </summary>
 /// </summary>
 public class TextTests (ITestOutputHelper output)
 public class TextTests (ITestOutputHelper output)
 {
 {
@@ -19,7 +18,7 @@ public class TextTests (ITestOutputHelper output)
     {
     {
         var view = new View ();
         var view = new View ();
         view.Text = text;
         view.Text = text;
-        Assert.Equal (new (expectedW, expectedH), view.TextFormatter.Size);
+        Assert.Equal (new (expectedW, expectedH), view.TextFormatter.ConstrainToSize);
     }
     }
 
 
     // TextFormatter.Size should track ContentSize (without DimAuto)
     // TextFormatter.Size should track ContentSize (without DimAuto)
@@ -32,7 +31,7 @@ public class TextTests (ITestOutputHelper output)
         var view = new View ();
         var view = new View ();
         view.SetContentSize (new (1, 1));
         view.SetContentSize (new (1, 1));
         view.Text = text;
         view.Text = text;
-        Assert.Equal (new (expectedW, expectedH), view.TextFormatter.Size);
+        Assert.Equal (new (expectedW, expectedH), view.TextFormatter.ConstrainToSize);
     }
     }
 
 
     [Fact]
     [Fact]
@@ -277,9 +276,9 @@ Y
 
 
         view.Width = 12;
         view.Width = 12;
         view.Height = 1;
         view.Height = 1;
-        view.TextFormatter.Size = new (12, 1);
+        view.TextFormatter.ConstrainToSize = new (12, 1);
         win.LayoutSubviews ();
         win.LayoutSubviews ();
-        Assert.Equal (new (12, 1), view.TextFormatter.Size);
+        Assert.Equal (new (12, 1), view.TextFormatter.ConstrainToSize);
         Assert.Equal (new (0, 0, 12, 1), view.Frame);
         Assert.Equal (new (0, 0, 12, 1), view.Frame);
         top.Clear ();
         top.Clear ();
         view.Draw ();
         view.Draw ();
@@ -398,7 +397,7 @@ Y
 
 
     [Fact]
     [Fact]
     [AutoInitShutdown]
     [AutoInitShutdown]
-    public void AutoSize_True_View_IsEmpty_False_Minimum_Width ()
+    public void View_IsEmpty_False_Minimum_Width ()
     {
     {
         var text = "Views";
         var text = "Views";
 
 
@@ -421,7 +420,7 @@ Y
         Assert.Equal (5, text.Length);
         Assert.Equal (5, text.Length);
 
 
         Assert.Equal (new (0, 0, 1, 5), view.Frame);
         Assert.Equal (new (0, 0, 1, 5), view.Frame);
-        Assert.Equal (new (1, 5), view.TextFormatter.Size);
+        Assert.Equal (new (1, 5), view.TextFormatter.ConstrainToSize);
         Assert.Equal (new () { "Views" }, view.TextFormatter.GetLines ());
         Assert.Equal (new () { "Views" }, view.TextFormatter.GetLines ());
         Assert.Equal (new (0, 0, 4, 10), win.Frame);
         Assert.Equal (new (0, 0, 4, 10), win.Frame);
         Assert.Equal (new (0, 0, 4, 10), Application.Top.Frame);
         Assert.Equal (new (0, 0, 4, 10), Application.Top.Frame);
@@ -449,7 +448,7 @@ Y
         Application.Refresh ();
         Application.Refresh ();
 
 
         Assert.Equal (new (0, 0, 1, 5), view.Frame);
         Assert.Equal (new (0, 0, 1, 5), view.Frame);
-        Assert.Equal (new (1, 5), view.TextFormatter.Size);
+        Assert.Equal (new (1, 5), view.TextFormatter.ConstrainToSize);
         Exception exception = Record.Exception (() => Assert.Single (view.TextFormatter.GetLines ()));
         Exception exception = Record.Exception (() => Assert.Single (view.TextFormatter.GetLines ()));
         Assert.Null (exception);
         Assert.Null (exception);
 
 
@@ -472,8 +471,8 @@ Y
     }
     }
 
 
     [Fact]
     [Fact]
-    [AutoInitShutdown]
-    public void AutoSize_True_View_IsEmpty_False_Minimum_Width_Wide_Rune ()
+    [SetupFakeDriver]
+    public void DimAuto_Vertical_TextDirection_Wide_Rune ()
     {
     {
         var text = "界View";
         var text = "界View";
 
 
@@ -484,74 +483,31 @@ Y
             Width = Dim.Auto (),
             Width = Dim.Auto (),
             Height = Dim.Auto ()
             Height = Dim.Auto ()
         };
         };
-        var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
-        win.Add (view);
-        var top = new Toplevel ();
-        top.Add (win);
-        Application.Begin (top);
-        ((FakeDriver)Application.Driver).SetBufferSize (4, 10);
+
+        view.SetRelativeLayout (new Size (4, 10));
 
 
         Assert.Equal (5, text.Length);
         Assert.Equal (5, text.Length);
+
+        // Vertical text - 2 wide, 5 down
         Assert.Equal (new (0, 0, 2, 5), view.Frame);
         Assert.Equal (new (0, 0, 2, 5), view.Frame);
-        Assert.Equal (new (2, 5), view.TextFormatter.Size);
+        Assert.Equal (new (2, 5), view.TextFormatter.ConstrainToSize);
         Assert.Equal (new () { "界View" }, view.TextFormatter.GetLines ());
         Assert.Equal (new () { "界View" }, view.TextFormatter.GetLines ());
-        Assert.Equal (new (0, 0, 4, 10), win.Frame);
-        Assert.Equal (new (0, 0, 4, 10), Application.Top.Frame);
+
+        view.Draw ();
 
 
         var expected = @"
         var expected = @"
-┌──┐
-│界│
-│V │
-│i │
-│e │
-│w │
-│  │
-│  │
-│  │
-└──┘
-";
+界
+V 
+i 
+e 
+w ";
 
 
         Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-        Assert.Equal (new (0, 0, 4, 10), pos);
-
-        text = "0123456789";
-        Assert.Equal (10, text.Length);
-
-        //view.Height = Dim.Fill () - text.Length;
-        Application.Refresh ();
-
-        Assert.Equal (new (0, 0, 2, 5), view.Frame);
-        Assert.Equal (new (2, 5), view.TextFormatter.Size);
-
-        Exception exception = Record.Exception (
-                                                () => Assert.Equal (
-                                                                    new () { "界View" },
-                                                                    view.TextFormatter.GetLines ()
-                                                                   )
-                                               );
-        Assert.Null (exception);
-
-        expected = @"
-┌──┐
-│界│
-│V │
-│i │
-│e │
-│w │
-│  │
-│  │
-│  │
-└──┘
-";
-
-        pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-        Assert.Equal (new (0, 0, 4, 10), pos);
-        top.Dispose ();
     }
     }
 
 
     [Fact]
     [Fact]
     [AutoInitShutdown]
     [AutoInitShutdown]
-    public void AutoSize_True_Width_Height_SetMinWidthHeight_Narrow_Wide_Runes ()
+    public void Width_Height_SetMinWidthHeight_Narrow_Wide_Runes ()
     {
     {
         var text = $"0123456789{Environment.NewLine}01234567891";
         var text = $"0123456789{Environment.NewLine}01234567891";
 
 
@@ -648,7 +604,7 @@ Y
 
 
     [Fact]
     [Fact]
     [AutoInitShutdown]
     [AutoInitShutdown]
-    public void AutoSize_True_Width_Height_Stay_True_If_TextFormatter_Size_Fit ()
+    public void Width_Height_Stay_True_If_TextFormatter_Size_Fit ()
     {
     {
         var text = "Finish 終";
         var text = "Finish 終";
 
 
@@ -674,8 +630,8 @@ Y
         RunState rs = Application.Begin (top);
         RunState rs = Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (22, 22);
         ((FakeDriver)Application.Driver).SetBufferSize (22, 22);
 
 
-        Assert.Equal (new (text.GetColumns (), 1), horizontalView.TextFormatter.Size);
-        Assert.Equal (new (2, 8), verticalView.TextFormatter.Size);
+        Assert.Equal (new (text.GetColumns (), 1), horizontalView.TextFormatter.ConstrainToSize);
+        Assert.Equal (new (2, 8), verticalView.TextFormatter.ConstrainToSize);
 
 
         //Assert.Equal (new (0, 0, 10, 1), horizontalView.Frame);
         //Assert.Equal (new (0, 0, 10, 1), horizontalView.Frame);
         //Assert.Equal (new (0, 3, 10, 9), verticalView.Frame);
         //Assert.Equal (new (0, 3, 10, 9), verticalView.Frame);
@@ -778,56 +734,6 @@ Y
         Application.End (rs);
         Application.End (rs);
         top.Dispose ();
         top.Dispose ();
     }
     }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void GetTextFormatterBoundsSize_GetSizeNeededForText_HotKeySpecifier ()
-    {
-        var text = "Say Hello 你";
-
-        // Frame: 0, 0, 12, 1
-        var horizontalView = new View
-        {
-            Width = Dim.Auto (), Height = Dim.Auto ()
-        };
-        horizontalView.TextFormatter.HotKeySpecifier = (Rune)'_';
-        horizontalView.Text = text;
-
-        // Frame: 0, 0, 1, 12
-        var verticalView = new View
-        {
-            Width = Dim.Auto (), Height = Dim.Auto (), TextDirection = TextDirection.TopBottom_LeftRight
-        };
-        verticalView.Text = text;
-        verticalView.TextFormatter.HotKeySpecifier = (Rune)'_';
-
-        var top = new Toplevel ();
-        top.Add (horizontalView, verticalView);
-        Application.Begin (top);
-        ((FakeDriver)Application.Driver).SetBufferSize (50, 50);
-
-        Assert.Equal (new (0, 0, 12, 1), horizontalView.Frame);
-        Assert.Equal (new (12, 1), horizontalView.GetSizeNeededForTextWithoutHotKey ());
-        Assert.Equal (horizontalView.Frame.Size, horizontalView.GetSizeNeededForTextWithoutHotKey ());
-
-        Assert.Equal (new (0, 0, 2, 11), verticalView.Frame);
-        Assert.Equal (new (2, 11), verticalView.GetSizeNeededForTextWithoutHotKey ());
-        Assert.Equal (verticalView.Frame.Size, verticalView.GetSizeNeededForTextWithoutHotKey ());
-
-        text = "012345678你";
-        horizontalView.Text = text;
-        verticalView.Text = text;
-
-        Assert.Equal (new (0, 0, 11, 1), horizontalView.Frame);
-        Assert.Equal (new (11, 1), horizontalView.GetSizeNeededForTextWithoutHotKey ());
-        Assert.Equal (horizontalView.Frame.Size, horizontalView.GetSizeNeededForTextWithoutHotKey ());
-
-        Assert.Equal (new (0, 0, 2, 10), verticalView.Frame);
-        Assert.Equal (new (2, 10), verticalView.GetSizeNeededForTextWithoutHotKey ());
-        Assert.Equal (verticalView.Frame.Size, verticalView.GetSizeNeededForTextWithoutHotKey ());
-        top.Dispose ();
-    }
-
     [Theory]
     [Theory]
     [AutoInitShutdown]
     [AutoInitShutdown]
     [InlineData (true)]
     [InlineData (true)]
@@ -902,21 +808,23 @@ Y
         Application.Begin (top);
         Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (width + 2, 6);
         ((FakeDriver)Application.Driver).SetBufferSize (width + 2, 6);
 
 
+        // frame.Width is width + border wide (20 + 2) and 6 high
+
         if (autoSize)
         if (autoSize)
         {
         {
             Size expectedSize = new (11, 1);
             Size expectedSize = new (11, 1);
-            Assert.Equal (expectedSize, lblLeft.TextFormatter.Size);
-            Assert.Equal (expectedSize, lblCenter.TextFormatter.Size);
-            Assert.Equal (expectedSize, lblRight.TextFormatter.Size);
-            Assert.Equal (expectedSize, lblJust.TextFormatter.Size);
+            Assert.Equal (expectedSize, lblLeft.TextFormatter.ConstrainToSize);
+            Assert.Equal (expectedSize, lblCenter.TextFormatter.ConstrainToSize);
+            Assert.Equal (expectedSize, lblRight.TextFormatter.ConstrainToSize);
+            Assert.Equal (expectedSize, lblJust.TextFormatter.ConstrainToSize);
         }
         }
         else
         else
         {
         {
             Size expectedSize = new (width, 1);
             Size expectedSize = new (width, 1);
-            Assert.Equal (expectedSize, lblLeft.TextFormatter.Size);
-            Assert.Equal (expectedSize, lblCenter.TextFormatter.Size);
-            Assert.Equal (expectedSize, lblRight.TextFormatter.Size);
-            Assert.Equal (expectedSize, lblJust.TextFormatter.Size);
+            Assert.Equal (expectedSize, lblLeft.TextFormatter.ConstrainToSize);
+            Assert.Equal (expectedSize, lblCenter.TextFormatter.ConstrainToSize);
+            Assert.Equal (expectedSize, lblRight.TextFormatter.ConstrainToSize);
+            Assert.Equal (expectedSize, lblJust.TextFormatter.ConstrainToSize);
         }
         }
 
 
         Assert.Equal (new (0, 0, width + 2, 6), frame.Frame);
         Assert.Equal (new (0, 0, width + 2, 6), frame.Frame);
@@ -1032,18 +940,18 @@ Y
 
 
         if (autoSize)
         if (autoSize)
         {
         {
-            Assert.Equal (new (1, 11), lblLeft.TextFormatter.Size);
-            Assert.Equal (new (1, 11), lblCenter.TextFormatter.Size);
-            Assert.Equal (new (1, 11), lblRight.TextFormatter.Size);
-            Assert.Equal (new (1, 11), lblJust.TextFormatter.Size);
+            Assert.Equal (new (1, 11), lblLeft.TextFormatter.ConstrainToSize);
+            Assert.Equal (new (1, 11), lblCenter.TextFormatter.ConstrainToSize);
+            Assert.Equal (new (1, 11), lblRight.TextFormatter.ConstrainToSize);
+            Assert.Equal (new (1, 11), lblJust.TextFormatter.ConstrainToSize);
             Assert.Equal (new (0, 0, 9, height + 2), frame.Frame);
             Assert.Equal (new (0, 0, 9, height + 2), frame.Frame);
         }
         }
         else
         else
         {
         {
-            Assert.Equal (new (1, height), lblLeft.TextFormatter.Size);
-            Assert.Equal (new (1, height), lblCenter.TextFormatter.Size);
-            Assert.Equal (new (1, height), lblRight.TextFormatter.Size);
-            Assert.Equal (new (1, height), lblJust.TextFormatter.Size);
+            Assert.Equal (new (1, height), lblLeft.TextFormatter.ConstrainToSize);
+            Assert.Equal (new (1, height), lblCenter.TextFormatter.ConstrainToSize);
+            Assert.Equal (new (1, height), lblRight.TextFormatter.ConstrainToSize);
+            Assert.Equal (new (1, height), lblJust.TextFormatter.ConstrainToSize);
             Assert.Equal (new (0, 0, 9, height + 2), frame.Frame);
             Assert.Equal (new (0, 0, 9, height + 2), frame.Frame);
         }
         }
 
 
@@ -1117,7 +1025,7 @@ Y
         Assert.Equal ("Hello World ", view.TextFormatter.Text);
         Assert.Equal ("Hello World ", view.TextFormatter.Text);
 
 
         view.TextFormatter.WordWrap = true;
         view.TextFormatter.WordWrap = true;
-        view.TextFormatter.Size = new (5, 3);
+        view.TextFormatter.ConstrainToSize = new (5, 3);
 
 
         view.PreserveTrailingSpaces = false;
         view.PreserveTrailingSpaces = false;
         Assert.Equal ($"Hello{Environment.NewLine}World", view.TextFormatter.Format ());
         Assert.Equal ($"Hello{Environment.NewLine}World", view.TextFormatter.Format ());
@@ -1244,7 +1152,7 @@ Y
         Assert.Equal (new (0, 0, 10, 1), view.Frame);
         Assert.Equal (new (0, 0, 10, 1), view.Frame);
         Assert.Equal (new (0, 0, 10, 1), view.Viewport);
         Assert.Equal (new (0, 0, 10, 1), view.Viewport);
 
 
-        Assert.Equal (new (10, 1), view.TextFormatter.Size);
+        Assert.Equal (new (10, 1), view.TextFormatter.ConstrainToSize);
     }
     }
 
 
     [Fact]
     [Fact]
@@ -1279,7 +1187,7 @@ Y
         var horizontalView = new View { Width = 20, Height = 1, Text = text };
         var horizontalView = new View { Width = 20, Height = 1, Text = text };
 
 
         // Autosize is off, so we have to explicitly set TextFormatter.Size
         // Autosize is off, so we have to explicitly set TextFormatter.Size
-        horizontalView.TextFormatter.Size = new (20, 1);
+        horizontalView.TextFormatter.ConstrainToSize = new (20, 1);
 
 
         var verticalView = new View
         var verticalView = new View
         {
         {
@@ -1291,7 +1199,7 @@ Y
         };
         };
 
 
         // Autosize is off, so we have to explicitly set TextFormatter.Size
         // Autosize is off, so we have to explicitly set TextFormatter.Size
-        verticalView.TextFormatter.Size = new (1, 20);
+        verticalView.TextFormatter.ConstrainToSize = new (1, 20);
 
 
         var frame = new FrameView { Width = Dim.Fill (), Height = Dim.Fill (), Text = "Window" };
         var frame = new FrameView { Width = Dim.Fill (), Height = Dim.Fill (), Text = "Window" };
         frame.Add (horizontalView, verticalView);
         frame.Add (horizontalView, verticalView);
@@ -1347,7 +1255,7 @@ Y
         // Autosize is off, so we have to explicitly set TextFormatter.Size
         // Autosize is off, so we have to explicitly set TextFormatter.Size
         // We know these glpyhs are 2 cols wide, so we need to widen the view
         // We know these glpyhs are 2 cols wide, so we need to widen the view
         verticalView.Width = 2;
         verticalView.Width = 2;
-        verticalView.TextFormatter.Size = new (2, 20);
+        verticalView.TextFormatter.ConstrainToSize = new (2, 20);
         Assert.True (verticalView.TextFormatter.NeedsFormat);
         Assert.True (verticalView.TextFormatter.NeedsFormat);
 
 
         top.Draw ();
         top.Draw ();
@@ -1390,9 +1298,4 @@ Y
 
 
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
     }
     }
-
-    // Test behavior of AutoSize property. 
-    // - Default is false
-    // - Setting to true invalidates Height/Width
-    // - Setting to false invalidates Height/Width
 }
 }

+ 1 - 36
UnitTests/View/TitleTests.cs

@@ -5,42 +5,7 @@ namespace Terminal.Gui.ViewTests;
 
 
 public class TitleTests (ITestOutputHelper output)
 public class TitleTests (ITestOutputHelper output)
 {
 {
-    [SetupFakeDriver]
-    [Fact]
-    public void Change_View_Size_Update_Title_Size ()
-    {
-        var view = new View
-        {
-            Title = "_Hello World",
-            Width = Dim.Auto (),
-            Height = Dim.Auto (),
-            BorderStyle = LineStyle.Single
-        };
-        var top = new Toplevel ();
-        top.Add (view);
-        top.BeginInit ();
-        top.EndInit ();
-
-        Assert.Equal (string.Empty, view.Text);
-        Assert.Equal (new (2, 2), view.Frame.Size);
-        top.Draw ();
-
-        TestHelpers.AssertDriverContentsWithFrameAre (
-                                                      @"
-┌┐
-└┘",
-                                                      output);
-
-        var text = "This text will increment the view size and display the title.";
-        view.Text = text;
-        top.Draw ();
-        Assert.Equal (text, view.Text);
-
-        // SetupFakeDriver only create a screen with 25 cols and 25 rows
-        Assert.Equal (new (text.Length, 1), view.GetContentSize ());
-
-        top.Dispose ();
-    }
+    // Unit tests that verify look & feel of title are in BorderTests.cs
 
 
     [Fact]
     [Fact]
     public void Set_Title_Fires_TitleChanged ()
     public void Set_Title_Fires_TitleChanged ()

+ 9 - 7
UnitTests/View/ViewTests.cs

@@ -143,9 +143,13 @@ public class ViewTests (ITestOutputHelper output)
     {
     {
         var root = new View { Width = 20, Height = 10, ColorScheme = Colors.ColorSchemes ["Base"] };
         var root = new View { Width = 20, Height = 10, ColorScheme = Colors.ColorSchemes ["Base"] };
 
 
+        string text = new ('c', 100);
+
         View v = label
         View v = label
-                     ? new Label { Text = new ('c', 100) }
-                     : new TextView { Height = 1, Text = new ('c', 100), Width = Dim.Fill () };
+                     // Label has Width/Height == AutoSize, so Frame.Size will be (100, 1)
+                     ? new Label { Text = text }
+                     // TextView has Width/Height == (Dim.Fill, 1), so Frame.Size will be 20 (width of root), 1
+                     : new TextView { Width = Dim.Fill (), Height = 1, Text = text };
 
 
         root.Add (v);
         root.Add (v);
 
 
@@ -156,8 +160,7 @@ public class ViewTests (ITestOutputHelper output)
         if (label)
         if (label)
         {
         {
             Assert.False (v.CanFocus);
             Assert.False (v.CanFocus);
-
-            //Assert.Equal (new Rectangle (0, 0, 20, 1), v.Frame);
+            Assert.Equal (new  (0, 0, text.Length, 1), v.Frame);
         }
         }
         else
         else
         {
         {
@@ -833,10 +836,10 @@ At 0,0
             TextDirection = TextDirection.TopBottom_LeftRight,
             TextDirection = TextDirection.TopBottom_LeftRight,
             Width = Dim.Auto (),
             Width = Dim.Auto (),
             Height = Dim.Auto ()
             Height = Dim.Auto ()
-        }; // BUGBUG: AutoSize or Height need be set
+        };
+        r.TextFormatter.WordWrap = false;
         Assert.NotNull (r);
         Assert.NotNull (r);
 
 
-        // BUGBUG: IsInitialized must be true to process calculation
         r.BeginInit ();
         r.BeginInit ();
         r.EndInit ();
         r.EndInit ();
         Assert.False (r.CanFocus);
         Assert.False (r.CanFocus);
@@ -1003,7 +1006,6 @@ At 0,0
     {
     {
         var view = new View { Text = "Testing visibility." }; // use View, not Label to avoid AutoSize == true
         var view = new View { Text = "Testing visibility." }; // use View, not Label to avoid AutoSize == true
 
 
-        // BUGBUG: AutoSize is false and size wasn't provided so it's 0,0
         Assert.Equal (0, view.Frame.Width);
         Assert.Equal (0, view.Frame.Width);
         Assert.Equal (0, view.Height);
         Assert.Equal (0, view.Height);
         var win = new Window ();
         var win = new Window ();

+ 7 - 9
UnitTests/Views/ButtonTests.cs

@@ -62,7 +62,7 @@ public class ButtonTests (ITestOutputHelper output)
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.Frame.Size);
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.Frame.Size);
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.Viewport.Size);
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.Viewport.Size);
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.GetContentSize ());
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.GetContentSize ());
-        Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.TextFormatter.Size);
+        Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.TextFormatter.ConstrainToSize);
 
 
         btn1.Dispose ();
         btn1.Dispose ();
     }
     }
@@ -76,15 +76,13 @@ public class ButtonTests (ITestOutputHelper output)
     [InlineData (10, 3, 10, 3)]
     [InlineData (10, 3, 10, 3)]
     public void Button_AbsoluteSize_DefaultText (int width, int height, int expectedWidth, int expectedHeight)
     public void Button_AbsoluteSize_DefaultText (int width, int height, int expectedWidth, int expectedHeight)
     {
     {
-        var btn1 = new Button
-        {
-            Width = width,
-            Height = height,
-        };
+        var btn1 = new Button ();
+        btn1.Width = width;
+        btn1.Height = height;
 
 
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.Frame.Size);
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.Frame.Size);
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.Viewport.Size);
         Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.Viewport.Size);
-        Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.TextFormatter.Size);
+        Assert.Equal (new Size (expectedWidth, expectedHeight), btn1.TextFormatter.ConstrainToSize);
 
 
         btn1.Dispose ();
         btn1.Dispose ();
     }
     }
@@ -178,7 +176,7 @@ public class ButtonTests (ITestOutputHelper output)
         btn.Dispose ();
         btn.Dispose ();
 
 
         btn = new () { Text = "_Test", IsDefault = true };
         btn = new () { Text = "_Test", IsDefault = true };
-        Assert.Equal (new (10, 1), btn.TextFormatter.Size);
+        Assert.Equal (new (10, 1), btn.TextFormatter.ConstrainToSize);
 
 
 
 
 
 
@@ -201,7 +199,7 @@ public class ButtonTests (ITestOutputHelper output)
         // [* Test *]
         // [* Test *]
         Assert.Equal ('_', btn.HotKeySpecifier.Value);
         Assert.Equal ('_', btn.HotKeySpecifier.Value);
         Assert.Equal (10, btn.TextFormatter.Format ().Length);
         Assert.Equal (10, btn.TextFormatter.Format ().Length);
-        Assert.Equal (new (10, 1), btn.TextFormatter.Size);
+        Assert.Equal (new (10, 1), btn.TextFormatter.ConstrainToSize);
         Assert.Equal (new (10, 1), btn.GetContentSize ());
         Assert.Equal (new (10, 1), btn.GetContentSize ());
         Assert.Equal (new (0, 0, 10, 1), btn.Viewport);
         Assert.Equal (new (0, 0, 10, 1), btn.Viewport);
         Assert.Equal (new (0, 0, 10, 1), btn.Frame);
         Assert.Equal (new (0, 0, 10, 1), btn.Frame);

+ 7 - 7
UnitTests/Views/CheckBoxTests.cs

@@ -38,7 +38,7 @@ public class CheckBoxTests (ITestOutputHelper output)
 
 
         Assert.Equal (new (expectedWidth, expectedHeight), checkBox.Frame.Size);
         Assert.Equal (new (expectedWidth, expectedHeight), checkBox.Frame.Size);
         Assert.Equal (new (expectedWidth, expectedHeight), checkBox.Viewport.Size);
         Assert.Equal (new (expectedWidth, expectedHeight), checkBox.Viewport.Size);
-        Assert.Equal (new (expectedWidth, expectedHeight), checkBox.TextFormatter.Size);
+        Assert.Equal (new (expectedWidth, expectedHeight), checkBox.TextFormatter.ConstrainToSize);
 
 
         checkBox.Dispose ();
         checkBox.Dispose ();
     }
     }
@@ -62,7 +62,7 @@ public class CheckBoxTests (ITestOutputHelper output)
 
 
         Assert.Equal (new (expectedWidth, expectedHeight), checkBox.Frame.Size);
         Assert.Equal (new (expectedWidth, expectedHeight), checkBox.Frame.Size);
         Assert.Equal (new (expectedWidth, expectedHeight), checkBox.Viewport.Size);
         Assert.Equal (new (expectedWidth, expectedHeight), checkBox.Viewport.Size);
-        Assert.Equal (new (expectedWidth, expectedHeight), checkBox.TextFormatter.Size);
+        Assert.Equal (new (expectedWidth, expectedHeight), checkBox.TextFormatter.ConstrainToSize);
 
 
         checkBox.Dispose ();
         checkBox.Dispose ();
     }
     }
@@ -258,7 +258,7 @@ public class CheckBoxTests (ITestOutputHelper output)
 
 
         Assert.Equal (Alignment.Center, checkBox.TextAlignment);
         Assert.Equal (Alignment.Center, checkBox.TextAlignment);
         Assert.Equal (new (1, 1, 25, 1), checkBox.Frame);
         Assert.Equal (new (1, 1, 25, 1), checkBox.Frame);
-        Assert.Equal (_size25x1, checkBox.TextFormatter.Size);
+        Assert.Equal (_size25x1, checkBox.TextFormatter.ConstrainToSize);
 
 
         var expected = @$"
         var expected = @$"
 ┌┤Test Demo 你├──────────────┐
 ┌┤Test Demo 你├──────────────┐
@@ -335,10 +335,10 @@ public class CheckBoxTests (ITestOutputHelper output)
 
 
         checkBox1.State = CheckState.Checked;
         checkBox1.State = CheckState.Checked;
         Assert.Equal (new (1, 1, 25, 1), checkBox1.Frame);
         Assert.Equal (new (1, 1, 25, 1), checkBox1.Frame);
-        Assert.Equal (_size25x1, checkBox1.TextFormatter.Size);
+        Assert.Equal (_size25x1, checkBox1.TextFormatter.ConstrainToSize);
         checkBox2.State = CheckState.Checked;
         checkBox2.State = CheckState.Checked;
         Assert.Equal (new (1, 2, 25, 1), checkBox2.Frame);
         Assert.Equal (new (1, 2, 25, 1), checkBox2.Frame);
-        Assert.Equal (_size25x1, checkBox2.TextFormatter.Size);
+        Assert.Equal (_size25x1, checkBox2.TextFormatter.ConstrainToSize);
         Application.Refresh ();
         Application.Refresh ();
 
 
         expected = @$"
         expected = @$"
@@ -376,7 +376,7 @@ public class CheckBoxTests (ITestOutputHelper output)
 
 
         Assert.Equal (Alignment.Start, checkBox.TextAlignment);
         Assert.Equal (Alignment.Start, checkBox.TextAlignment);
         Assert.Equal (new (1, 1, 25, 1), checkBox.Frame);
         Assert.Equal (new (1, 1, 25, 1), checkBox.Frame);
-        Assert.Equal (_size25x1, checkBox.TextFormatter.Size);
+        Assert.Equal (_size25x1, checkBox.TextFormatter.ConstrainToSize);
 
 
         var expected = @$"
         var expected = @$"
 ┌┤Test Demo 你├──────────────┐
 ┌┤Test Demo 你├──────────────┐
@@ -427,7 +427,7 @@ public class CheckBoxTests (ITestOutputHelper output)
 
 
         Assert.Equal (Alignment.End, checkBox.TextAlignment);
         Assert.Equal (Alignment.End, checkBox.TextAlignment);
         Assert.Equal (new (1, 1, 25, 1), checkBox.Frame);
         Assert.Equal (new (1, 1, 25, 1), checkBox.Frame);
-        Assert.Equal (_size25x1, checkBox.TextFormatter.Size);
+        Assert.Equal (_size25x1, checkBox.TextFormatter.ConstrainToSize);
 
 
         var expected = @$"
         var expected = @$"
 ┌┤Test Demo 你├──────────────┐
 ┌┤Test Demo 你├──────────────┐

+ 11 - 113
UnitTests/Views/LabelTests.cs

@@ -86,7 +86,7 @@ public class LabelTests (ITestOutputHelper output)
 
 
     [Fact]
     [Fact]
     [AutoInitShutdown]
     [AutoInitShutdown]
-    public void AutoSize_Stays_True_AnchorEnd ()
+    public void Text_Set_With_AnchorEnd_Works ()
     {
     {
         var label = new Label { Y = Pos.Center (), Text = "Say Hello 你" };
         var label = new Label { Y = Pos.Center (), Text = "Say Hello 你" };
         label.X = Pos.AnchorEnd (0) - Pos.Func (() => label.TextFormatter.Text.GetColumns ());
         label.X = Pos.AnchorEnd (0) - Pos.Func (() => label.TextFormatter.Text.GetColumns ());
@@ -127,7 +127,7 @@ public class LabelTests (ITestOutputHelper output)
 
 
     [Fact]
     [Fact]
     [AutoInitShutdown]
     [AutoInitShutdown]
-    public void AutoSize_Stays_True_Center ()
+    public void Set_Text_With_Center ()
     {
     {
         var label = new Label { X = Pos.Center (), Y = Pos.Center (), Text = "Say Hello 你" };
         var label = new Label { X = Pos.Center (), Y = Pos.Center (), Text = "Say Hello 你" };
 
 
@@ -164,35 +164,7 @@ public class LabelTests (ITestOutputHelper output)
         TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         top.Dispose ();
         top.Dispose ();
     }
     }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void AutoSize_Stays_True_With_EmptyText ()
-    {
-        var label = new Label { X = Pos.Center (), Y = Pos.Center () };
-
-        var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
-        win.Add (label);
-        var top = new Toplevel ();
-        top.Add (win);
-
-        label.Text = "Say Hello 你";
-
-        Application.Begin (top);
-        ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
-
-        var expected = @"
-┌────────────────────────────┐
-│                            │
-│        Say Hello 你        │
-│                            │
-└────────────────────────────┘
-";
-
-        TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-        top.Dispose ();
-    }
-
+    
     [Fact]
     [Fact]
     public void Constructors_Defaults ()
     public void Constructors_Defaults ()
     {
     {
@@ -206,25 +178,22 @@ public class LabelTests (ITestOutputHelper output)
 
 
     [Fact]
     [Fact]
     [AutoInitShutdown]
     [AutoInitShutdown]
-    public void Label_Draw_Fill_Remaining_AutoSize_False ()
+    public void Label_Draw_Fill_Remaining ()
     {
     {
         var tfSize = new Size (80, 1);
         var tfSize = new Size (80, 1);
 
 
         var label = new Label { Text = "This label needs to be cleared before rewritten.", Width = tfSize.Width, Height = tfSize.Height };
         var label = new Label { Text = "This label needs to be cleared before rewritten.", Width = tfSize.Width, Height = tfSize.Height };
 
 
-        var tf1 = new TextFormatter { Direction = TextDirection.LeftRight_TopBottom, Size = tfSize };
+        var tf1 = new TextFormatter { Direction = TextDirection.LeftRight_TopBottom, ConstrainToSize = tfSize };
         tf1.Text = "This TextFormatter (tf1) without fill will not be cleared on rewritten.";
         tf1.Text = "This TextFormatter (tf1) without fill will not be cleared on rewritten.";
 
 
-        var tf2 = new TextFormatter { Direction = TextDirection.LeftRight_TopBottom, Size = tfSize, FillRemaining = true };
+        var tf2 = new TextFormatter { Direction = TextDirection.LeftRight_TopBottom, ConstrainToSize = tfSize, FillRemaining = true };
         tf2.Text = "This TextFormatter (tf2) with fill will be cleared on rewritten.";
         tf2.Text = "This TextFormatter (tf2) with fill will be cleared on rewritten.";
 
 
         var top = new Toplevel ();
         var top = new Toplevel ();
         top.Add (label);
         top.Add (label);
         Application.Begin (top);
         Application.Begin (top);
 
 
-        Assert.False (label.TextFormatter.AutoSize);
-        Assert.False (tf1.AutoSize);
-        Assert.False (tf2.AutoSize);
         Assert.False (label.TextFormatter.FillRemaining);
         Assert.False (label.TextFormatter.FillRemaining);
         Assert.False (tf1.FillRemaining);
         Assert.False (tf1.FillRemaining);
         Assert.True (tf2.FillRemaining);
         Assert.True (tf2.FillRemaining);
@@ -473,7 +442,7 @@ e
         var label = new Label { BorderStyle = LineStyle.Single, Text = "Test" };
         var label = new Label { BorderStyle = LineStyle.Single, Text = "Test" };
         label.BeginInit ();
         label.BeginInit ();
         label.EndInit ();
         label.EndInit ();
-        label.SetRelativeLayout (Application.Driver.Screen.Size);
+        label.SetRelativeLayout (Application.Screen.Size);
 
 
         Assert.Equal (new (0, 0, 4, 1), label.Viewport);
         Assert.Equal (new (0, 0, 4, 1), label.Viewport);
         Assert.Equal (new (0, 0, 6, 3), label.Frame);
         Assert.Equal (new (0, 0, 6, 3), label.Frame);
@@ -914,7 +883,6 @@ e
     {
     {
         var win = new Window ();
         var win = new Window ();
 
 
-        // Label is AutoSize == true
         var label = new Label
         var label = new Label
         {
         {
             Text = "This should be the last line.",
             Text = "This should be the last line.",
@@ -955,73 +923,6 @@ e
         top.Dispose ();
         top.Dispose ();
     }
     }
 
 
-#if V2_STATUSBAR
-    // TODO: This is a Label test. Move to label tests if there's not already a test for this.
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Bottom_Equal_Inside_Window_With_MenuBar_And_StatusBar_On_Toplevel ()
-    {
-        var win = new Window ();
-
-        // Label is AutoSize == true
-        var label = new Label
-        {
-            Text = "This should be the last line.",
-            ColorScheme = Colors.ColorSchemes ["Menu"],
-
-            //Width = Dim.Fill (),
-            X = 0,
-            Y = Pos.Bottom (win) - 4 // two lines top and bottom borders more two lines above border
-        };
-
-        win.Add (label);
-
-        var menu = new MenuBar { Menus = new MenuBarItem [] { new ("Menu", "", null) } };
-        var status = new StatusBar (new StatusItem [] { new (KeyCode.F1, "~F1~ Help", null) });
-        Toplevel top = new ();
-        top.Add (win, menu, status);
-        RunState rs = Application.Begin (top);
-
-        Assert.Equal (new (0, 0, 80, 25), top.Frame);
-        Assert.Equal (new (0, 0, 80, 1), menu.Frame);
-        Assert.Equal (new (0, 24, 80, 1), status.Frame);
-        Assert.Equal (new (0, 1, 80, 23), win.Frame);
-        Assert.Equal (new (0, 20, 29, 1), label.Frame);
-
-        var expected = @"
- Menu                                                                           
-┌──────────────────────────────────────────────────────────────────────────────┐
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│                                                                              │
-│This should be the last line.                                                 │
-└──────────────────────────────────────────────────────────────────────────────┘
- F1 Help                                                                        
-";
-
-        TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-        Application.End (rs);
-        top.Dispose ();
-    }
-#endif
     // TODO: This is a Dim test. Move to Dim tests.
     // TODO: This is a Dim test. Move to Dim tests.
 
 
     [Fact]
     [Fact]
@@ -1041,7 +942,6 @@ e
         var field = new TextField { X = 0, Y = Pos.Bottom (view), Width = 20 };
         var field = new TextField { X = 0, Y = Pos.Bottom (view), Width = 20 };
         var count = 20;
         var count = 20;
 
 
-        // Label is AutoSize == true
         List<Label> listLabels = new ();
         List<Label> listLabels = new ();
 
 
         for (var i = 0; i < count; i++)
         for (var i = 0; i < count; i++)
@@ -1216,7 +1116,6 @@ e
         var field = new TextField { X = 0, Y = Pos.Bottom (view), Width = 20 };
         var field = new TextField { X = 0, Y = Pos.Bottom (view), Width = 20 };
         var count = 0;
         var count = 0;
 
 
-        // Label is AutoSize == true
         List<Label> listLabels = new ();
         List<Label> listLabels = new ();
 
 
         field.KeyDown += (s, k) =>
         field.KeyDown += (s, k) =>
@@ -1231,7 +1130,6 @@ e
                                  {
                                  {
                                      field.Text = $"Label {count}";
                                      field.Text = $"Label {count}";
 
 
-                                     // Label is AutoSize = true
                                      var label = new Label { Text = field.Text, X = 0, Y = view.Viewport.Height /*, Width = 10*/ };
                                      var label = new Label { Text = field.Text, X = 0, Y = view.Viewport.Height /*, Width = 10*/ };
                                      view.Add (label);
                                      view.Add (label);
                                      Assert.Equal ($"Label {count}", label.Text);
                                      Assert.Equal ($"Label {count}", label.Text);
@@ -1303,7 +1201,7 @@ e
 
 
         Assert.Equal (5, text.Length);
         Assert.Equal (5, text.Length);
         Assert.Equal (new (0, 0, 5, 1), label.Frame);
         Assert.Equal (new (0, 0, 5, 1), label.Frame);
-        Assert.Equal (new (5, 1), label.TextFormatter.Size);
+        Assert.Equal (new (5, 1), label.TextFormatter.ConstrainToSize);
         Assert.Equal (["Label"], label.TextFormatter.GetLines ());
         Assert.Equal (["Label"], label.TextFormatter.GetLines ());
         Assert.Equal (new (0, 0, 10, 4), win.Frame);
         Assert.Equal (new (0, 0, 10, 4), win.Frame);
         Assert.Equal (new (0, 0, 10, 4), Application.Top.Frame);
         Assert.Equal (new (0, 0, 10, 4), Application.Top.Frame);
@@ -1325,7 +1223,7 @@ e
         Application.Refresh ();
         Application.Refresh ();
 
 
         Assert.Equal (new (0, 0, 5, 1), label.Frame);
         Assert.Equal (new (0, 0, 5, 1), label.Frame);
-        Assert.Equal (new (5, 1), label.TextFormatter.Size);
+        Assert.Equal (new (5, 1), label.TextFormatter.ConstrainToSize);
         Exception exception = Record.Exception (() => Assert.Single (label.TextFormatter.GetLines ()));
         Exception exception = Record.Exception (() => Assert.Single (label.TextFormatter.GetLines ()));
         Assert.Null (exception);
         Assert.Null (exception);
 
 
@@ -1362,7 +1260,7 @@ e
 
 
         Assert.Equal (5, text.Length);
         Assert.Equal (5, text.Length);
         Assert.Equal (new (0, 0, 5, 1), label.Frame);
         Assert.Equal (new (0, 0, 5, 1), label.Frame);
-        Assert.Equal (new (5, 1), label.TextFormatter.Size);
+        Assert.Equal (new (5, 1), label.TextFormatter.ConstrainToSize);
         Assert.Equal (["Label"], label.TextFormatter.GetLines ());
         Assert.Equal (["Label"], label.TextFormatter.GetLines ());
         Assert.Equal (new (0, 0, 10, 4), win.Frame);
         Assert.Equal (new (0, 0, 10, 4), win.Frame);
         Assert.Equal (new (0, 0, 10, 4), Application.Top.Frame);
         Assert.Equal (new (0, 0, 10, 4), Application.Top.Frame);
@@ -1384,7 +1282,7 @@ e
         Application.Refresh ();
         Application.Refresh ();
 
 
         Assert.Equal (new (0, 0, 5, 1), label.Frame);
         Assert.Equal (new (0, 0, 5, 1), label.Frame);
-        Assert.Equal (new (5, 1), label.TextFormatter.Size);
+        Assert.Equal (new (5, 1), label.TextFormatter.ConstrainToSize);
         Assert.Single (label.TextFormatter.GetLines ());
         Assert.Single (label.TextFormatter.GetLines ());
 
 
         expected = @"
         expected = @"

+ 11 - 9
UnitTests/Views/ScrollViewTests.cs

@@ -349,7 +349,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         Assert.True (sv.AutoHideScrollBars);
         Assert.True (sv.AutoHideScrollBars);
         Assert.True (sv.KeepContentAlwaysInViewport);
         Assert.True (sv.KeepContentAlwaysInViewport);
 
 
-        sv = new() { X = 1, Y = 2, Width = 20, Height = 10 };
+        sv = new () { X = 1, Y = 2, Width = 20, Height = 10 };
         Assert.True (sv.CanFocus);
         Assert.True (sv.CanFocus);
         Assert.Equal (new (1, 2, 20, 10), sv.Frame);
         Assert.Equal (new (1, 2, 20, 10), sv.Frame);
         Assert.Equal (Point.Empty, sv.ContentOffset);
         Assert.Equal (Point.Empty, sv.ContentOffset);
@@ -364,7 +364,7 @@ public class ScrollViewTests (ITestOutputHelper output)
     {
     {
         ((FakeDriver)Application.Driver).SetBufferSize (30, 30);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 30);
 
 
-        var top = new View { Width = 30, Height = 30, ColorScheme = new() { Normal = Attribute.Default } };
+        var top = new View { Width = 30, Height = 30, ColorScheme = new () { Normal = Attribute.Default } };
 
 
         Size size = new (20, 10);
         Size size = new (20, 10);
 
 
@@ -374,7 +374,7 @@ public class ScrollViewTests (ITestOutputHelper output)
             Y = 1,
             Y = 1,
             Width = 10,
             Width = 10,
             Height = 5,
             Height = 5,
-            ColorScheme = new() { Normal = new (Color.Red, Color.Green) }
+            ColorScheme = new () { Normal = new (Color.Red, Color.Green) }
         };
         };
         sv.SetContentSize (size);
         sv.SetContentSize (size);
         string text = null;
         string text = null;
@@ -391,7 +391,7 @@ public class ScrollViewTests (ITestOutputHelper output)
 
 
         var view = new View
         var view = new View
         {
         {
-            ColorScheme = new() { Normal = new (Color.Blue, Color.Yellow) },
+            ColorScheme = new () { Normal = new (Color.Blue, Color.Yellow) },
             Width = Dim.Auto (DimAutoStyle.Text),
             Width = Dim.Auto (DimAutoStyle.Text),
             Height = Dim.Auto (DimAutoStyle.Text),
             Height = Dim.Auto (DimAutoStyle.Text),
             Text = text
             Text = text
@@ -523,7 +523,9 @@ public class ScrollViewTests (ITestOutputHelper output)
         view.Add (
         view.Add (
                   new Label
                   new Label
                   {
                   {
-                      Width = Dim.Fill (), Height = 1, Text = rule.Repeat (size.Width / rule.Length)
+                      Width = Dim.Fill (),
+                      Height = 1,
+                      Text = rule.Repeat (size.Width / rule.Length)
                   }
                   }
                  );
                  );
 
 
@@ -856,8 +858,8 @@ public class ScrollViewTests (ITestOutputHelper output)
  └──────────────────┘
  └──────────────────┘
 ";
 ";
 
 
-        pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-        Assert.Equal (new (1, 1, 21, 14), pos);
+        TestHelpers.AssertDriverContentsAre (expected, output);
+        
         top.Dispose ();
         top.Dispose ();
     }
     }
 
 
@@ -1090,7 +1092,7 @@ public class ScrollViewTests (ITestOutputHelper output)
             Width = width;
             Width = width;
             Height = height;
             Height = height;
 
 
-            labelFill = new() { Width = Dim.Fill (), Height = Dim.Fill (), Visible = false };
+            labelFill = new () { Width = Dim.Fill (), Height = Dim.Fill (), Visible = false };
 
 
             labelFill.LayoutComplete += (s, e) =>
             labelFill.LayoutComplete += (s, e) =>
                                         {
                                         {
@@ -1112,7 +1114,7 @@ public class ScrollViewTests (ITestOutputHelper output)
                                             labelFill.Text = fillText.ToString ();
                                             labelFill.Text = fillText.ToString ();
                                         };
                                         };
 
 
-            labelText = new() { X = Pos.Center (), Y = Pos.Center (), Text = text };
+            labelText = new () { X = Pos.Center (), Y = Pos.Center (), Text = text };
             Add (labelFill, labelText);
             Add (labelFill, labelText);
             CanFocus = true;
             CanFocus = true;
         }
         }

+ 3 - 2
UnitTests/Views/ShortcutTests.cs

@@ -38,8 +38,9 @@ public class ShortcutTests
 
 
         Assert.IsType<DimAuto> (shortcut.Width);
         Assert.IsType<DimAuto> (shortcut.Width);
         Assert.IsType<DimAuto> (shortcut.Height);
         Assert.IsType<DimAuto> (shortcut.Height);
-
-        shortcut.LayoutSubviews ();
+        //shortcut.BeginInit();
+        //shortcut.EndInit ();
+       // shortcut.LayoutSubviews ();
         shortcut.SetRelativeLayout (new (100, 100));
         shortcut.SetRelativeLayout (new (100, 100));
 
 
         // |0123456789
         // |0123456789

+ 1 - 1
UnitTests/Views/TextViewTests.cs

@@ -6900,7 +6900,7 @@ This is the second line.
                                                      );
                                                      );
 
 
         ((FakeDriver)Application.Driver).SetBufferSize (6, 25);
         ((FakeDriver)Application.Driver).SetBufferSize (6, 25);
-        tv.SetRelativeLayout (Application.Driver.Screen.Size);
+        tv.SetRelativeLayout (Application.Screen.Size);
         tv.Draw ();
         tv.Draw ();
         Assert.Equal (new Point (4, 2), tv.CursorPosition);
         Assert.Equal (new Point (4, 2), tv.CursorPosition);
         Assert.Equal (new Point (12, 0), cp);
         Assert.Equal (new Point (12, 0), cp);

+ 2 - 2
UnitTests/Views/WindowTests.cs

@@ -130,8 +130,8 @@ public class WindowTests
         Assert.Equal ($"Window(){defaultWindow.Frame}", defaultWindow.ToString ());
         Assert.Equal ($"Window(){defaultWindow.Frame}", defaultWindow.ToString ());
         Assert.True (defaultWindow.CanFocus);
         Assert.True (defaultWindow.CanFocus);
         Assert.False (defaultWindow.HasFocus);
         Assert.False (defaultWindow.HasFocus);
-        Assert.Equal (new Rectangle (0, 0, 2147483645, 2147483645), defaultWindow.Viewport);
-        Assert.Equal (new Rectangle (0, 0, 2147483647, 2147483647), defaultWindow.Frame);
+        Assert.Equal (new Rectangle (0, 0, Application.Screen.Width - 2, Application.Screen.Height - 2), defaultWindow.Viewport);
+        Assert.Equal (new Rectangle (0, 0, Application.Screen.Width, Application.Screen.Height), defaultWindow.Frame);
         Assert.Null (defaultWindow.Focused);
         Assert.Null (defaultWindow.Focused);
         Assert.NotNull (defaultWindow.ColorScheme);
         Assert.NotNull (defaultWindow.ColorScheme);
         Assert.Equal (0, defaultWindow.X);
         Assert.Equal (0, defaultWindow.X);

+ 23 - 6
docfx/docs/dimauto.md

@@ -2,7 +2,7 @@
 
 
 The `Dim.Auto` type is a type of `Dim` that automatically sizes the view based on its content. This is useful when you want to size a view based on the content it contains. That content can either be the `Text`, the `SubViews`, or something else defined by the view.
 The `Dim.Auto` type is a type of `Dim` that automatically sizes the view based on its content. This is useful when you want to size a view based on the content it contains. That content can either be the `Text`, the `SubViews`, or something else defined by the view.
 
 
-Like all `Dim` types, `Dim.Auto` is used to set the `Width` or `Height` of a view. 
+Like all `Dim` types, `Dim.Auto` is used to set the `Width` or `Height` of a view and can be combined with other `Dim` types using addition or subtraction (see. `DimCombine`).
 
 
 The `DimAutoStyle` enum defines the different ways that `Dim.Auto` can be used to size a view. The `DimAutoStyle` enum has the following values:
 The `DimAutoStyle` enum defines the different ways that `Dim.Auto` can be used to size a view. The `DimAutoStyle` enum has the following values:
 
 
@@ -77,7 +77,7 @@ int GetDynamicMinSize ()
 
 
 ### Specifying a maximum size
 ### Specifying a maximum size
 
 
-> NOT YET IMPLEMENTED
+It is common to want to constrain how large a View can be sized. The `maximumContentDim` parameter to the `Dim.Auto ()` method enables this. Like `minimumContentDim` it is of type `Dim` and thus can represent a dynamic value. For example, by default `Dialog` specifies `maximumContentDim` as `Dim.Percent (90)` to ensure a Dialog box is never larger than 90% of the screen.
 
 
 ## Limitations
 ## Limitations
 
 
@@ -85,11 +85,28 @@ int GetDynamicMinSize ()
 
 
 `Dim.Auto` is also not always the most efficient way to size a view. If you know the size of the content ahead of time, you can set the `Width` and `Height` properties to `Dim.Absolute (n)` instead of using `Dim.Auto`.
 `Dim.Auto` is also not always the most efficient way to size a view. If you know the size of the content ahead of time, you can set the `Width` and `Height` properties to `Dim.Absolute (n)` instead of using `Dim.Auto`.
 
 
-> TODO: Verify accuracy of the following paragraphs
+## Behavior of other Pos/Dim Types when used within a Dim.Auto-sized View
+
+The table below descibes the behavior of the various Pos/Dim types when used by subviews of a View that uses `Dim.Auto` for it's `Width` or `Height`:
+
+| Type        | Impacts Dimension | Notes                                                                                             |
+|-------------|-------------------|---------------------------------------------------------------------------------------------------------|
+| PosAlign    | Yes               | The subviews with the same `GroupId` will be aligned at the maximimum dimension to enable them to not be clipped. This dimension plus the group's position will determine the minimum `Dim.Auto` dimension. |
+| PosView     | Yes               | The position plus the dimension of `subview.Target` will determine the minimum `Dim.Auto` dimension. |
+| PosCombine  | Yes               | <needs clarification> |
+| PosAnchorEnd| Yes               | The `Dim.Auto` dimension will be increased by the dimension of the subview. |
+| PosCenter   | No                |  |
+| PosPercent  | No                |  |
+| PosAbsolute | Yes               |  |
+| PosFunc     | Yes               |  |
+| DimView     | Yes               | The position plus the dimension of `subview.Target` will determine the minimum `Dim.Auto` dimension. |
+| DimCombine  | Yes               | <needs clarification>  |
+| DimFill     | No                |  |
+| DimPercent  | No                |  |
+| DimAuto     | Yes               |  |
+| DimAbsolute | Yes               |  |
+| DimFunc     | Yes               | <needs clarification> |
 
 
-Some `Pos` and `Dim` types are not compatible with `Dim.Auto`. For example, you cannot use `Dim.Auto (DimAutoStyle.Content)` with Subviews that use `Dim.Fill ()` or `Dim.Percent (n)` because the size of the Subview is not known until the layout is computed.
-
-`Pos` types that are relative to the size of the view, such as `Pos.Percent (n)` are not compatible with `Dim.Auto` because the size of the view is not known until the layout is computed. However, `Pos.Center ()` and `Pos.AnchorEnd ()` are compatible with `Dim.Auto` because they are relative to the size of the view's Superview.
 
 
 ## Building Dim.Auto friendly View
 ## Building Dim.Auto friendly View
 
 

Vissa filer visades inte eftersom för många filer har ändrats