소스 검색

Tons of Layout refactoring. LayoutSubviews is now internal.

Tig 9 달 전
부모
커밋
8c7982f9c0
47개의 변경된 파일928개의 추가작업 그리고 701개의 파일을 삭제
  1. 18 19
      Terminal.Gui/Application/Application.Run.cs
  2. 17 5
      Terminal.Gui/Application/Application.Screen.cs
  3. 3 6
      Terminal.Gui/View/Adornment/Adornment.cs
  4. 15 15
      Terminal.Gui/View/Adornment/Border.cs
  5. 2 6
      Terminal.Gui/View/Adornment/Margin.cs
  6. 1 1
      Terminal.Gui/View/Layout/PosAlign.cs
  7. 5 5
      Terminal.Gui/View/View.Adornments.cs
  8. 1 1
      Terminal.Gui/View/View.Content.cs
  9. 58 75
      Terminal.Gui/View/View.Layout.cs
  10. 5 3
      Terminal.Gui/View/View.cs
  11. 3 4
      Terminal.Gui/Views/ColorPicker.cs
  12. 3 2
      Terminal.Gui/Views/FileDialog.cs
  13. 3 1
      Terminal.Gui/Views/ScrollBarView.cs
  14. 29 18
      Terminal.Gui/Views/TabView.cs
  15. 27 47
      Terminal.Gui/Views/TileView.cs
  16. 10 20
      Terminal.Gui/Views/Toplevel.cs
  17. 0 3
      Terminal.Gui/Views/Wizard/Wizard.cs
  18. 3 3
      UICatalog/Scenarios/BorderEditor.cs
  19. 0 1
      UICatalog/Scenarios/ColorPicker.cs
  20. 0 10
      UICatalog/Scenarios/ComputedLayout.cs
  21. 0 2
      UICatalog/Scenarios/ConfigurationEditor.cs
  22. 0 1
      UICatalog/Scenarios/Dialogs.cs
  23. 0 3
      UICatalog/Scenarios/Editor.cs
  24. 3 4
      UICatalog/Scenarios/LineDrawing.cs
  25. 0 2
      UICatalog/Scenarios/PosAlignDemo.cs
  26. 0 2
      UICatalog/Scenarios/Progress.cs
  27. 1 3
      UICatalog/Scenarios/Scrolling.cs
  28. 0 8
      UICatalog/Scenarios/Sliders.cs
  29. 4 9
      UICatalog/Scenarios/TileViewNesting.cs
  30. 0 3
      UICatalog/Scenarios/Wizards.cs
  31. 1 1
      UnitTests/Application/ApplicationTests.cs
  32. 11 12
      UnitTests/Dialogs/DialogTests.cs
  33. 5 5
      UnitTests/Dialogs/WizardTests.cs
  34. 8 9
      UnitTests/View/Adornment/BorderTests.cs
  35. 237 76
      UnitTests/View/DrawTests.cs
  36. 0 236
      UnitTests/View/Layout/AbsoluteLayoutTests.cs
  37. 13 11
      UnitTests/View/Layout/Dim.AutoTests.cs
  38. 411 40
      UnitTests/View/Layout/LayoutTests.cs
  39. 2 2
      UnitTests/View/Layout/Pos.CenterTests.cs
  40. 2 1
      UnitTests/View/Layout/ToScreenTests.cs
  41. 4 1
      UnitTests/View/Mouse/MouseTests.cs
  42. 1 1
      UnitTests/View/ViewTests.cs
  43. 8 8
      UnitTests/Views/ContextMenuTests.cs
  44. 10 10
      UnitTests/Views/MenuBarTests.cs
  45. 1 2
      UnitTests/Views/TextFieldTests.cs
  46. 1 2
      UnitTests/Views/TextViewTests.cs
  47. 2 2
      UnitTests/Views/ToplevelTests.cs

+ 18 - 19
Terminal.Gui/Application/Application.Run.cs

@@ -183,12 +183,8 @@ public static partial class Application // Run (Begin, Run, End, Stop)
             toplevel.BeginInit ();
             toplevel.EndInit ();
 
-            if (toplevel.SetRelativeLayout (Driver!.Screen.Size))
-            {
-                toplevel.LayoutSubviews ();
-            }
-
-            // toplevel.SetLayoutNeeded();
+            // Force a layout - normally this is done each iteration of the main loop but we prime it here.
+            toplevel.Layout (Screen.Size);
         }
 
         // Try to set initial focus to any TabStop
@@ -197,6 +193,11 @@ public static partial class Application // Run (Begin, Run, End, Stop)
             toplevel.SetFocus ();
         }
 
+        // DEBATE: Should Begin call Refresh (or Draw) here? It previously did.
+        //   FOR: the screen has something on it after Begin is called.
+        //   AGAINST: the screen is cleared and then redrawn in RunLoop. We don't want to draw twice.
+        Refresh();
+
         toplevel.OnLoaded ();
 
         if (PositionCursor ())
@@ -227,11 +228,12 @@ public static partial class Application // Run (Begin, Run, End, Stop)
         // If the view is not visible or enabled, don't position the cursor
         if (mostFocused is null || !mostFocused.Visible || !mostFocused.Enabled)
         {
-            Driver!.GetCursorVisibility (out CursorVisibility current);
+            CursorVisibility current = CursorVisibility.Invisible;
+            Driver?.GetCursorVisibility (out  current);
 
             if (current != CursorVisibility.Invisible)
             {
-                Driver.SetCursorVisibility (CursorVisibility.Invisible);
+                Driver?.SetCursorVisibility (CursorVisibility.Invisible);
             }
 
             return false;
@@ -497,11 +499,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
             if (tl.IsLayoutNeeded ())
             {
                 clear = true;
-
-                if (tl.SetRelativeLayout (Screen.Size))
-                {
-                    tl.LayoutSubviews ();
-                }
+                tl.Layout (Screen.Size);
             }
         }
 
@@ -554,23 +552,23 @@ public static partial class Application // Run (Begin, Run, End, Stop)
                 return;
             }
 
-            RunIteration (ref state, ref firstIteration);
+            firstIteration = RunIteration (ref state, firstIteration);
         }
 
         MainLoop!.Running = false;
 
         // Run one last iteration to consume any outstanding input events from Driver
         // This is important for remaining OnKeyUp events.
-        RunIteration (ref state, ref firstIteration);
+        RunIteration (ref state, firstIteration);
     }
 
     /// <summary>Run one application iteration.</summary>
     /// <param name="state">The state returned by <see cref="Begin(Toplevel)"/>.</param>
     /// <param name="firstIteration">
-    ///     Set to <see langword="true"/> if this is the first run loop iteration. Upon return, it
-    ///     will be set to <see langword="false"/> if at least one iteration happened.
+    ///     Set to <see langword="true"/> if this is the first run loop iteration.
     /// </param>
-    public static void RunIteration (ref RunState state, ref bool firstIteration)
+    /// <returns><see langword="false"/> if at least one iteration happened.</returns>
+    public static bool RunIteration (ref RunState state, bool firstIteration = false)
     {
         if (MainLoop!.Running && MainLoop.EventsPending ())
         {
@@ -588,7 +586,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
 
         if (Top is null)
         {
-            return;
+            return firstIteration;
         }
 
         Refresh ();
@@ -598,6 +596,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
             Driver!.UpdateCursor ();
         }
 
+        return firstIteration;
     }
 
     /// <summary>Stops the provided <see cref="Toplevel"/>, causing or the <paramref name="top"/> if provided.</summary>

+ 17 - 5
Terminal.Gui/Application/Application.Screen.cs

@@ -3,13 +3,28 @@ namespace Terminal.Gui;
 
 public static partial class Application // Screen related stuff
 {
+    private static Size _screenSize = new (2048, 2048);
+
+    /// <summary>
+    ///     INTERNAL API for Unit Tests. Only works if there's no driver.
+    /// </summary>
+    /// <param name="size"></param>
+    internal static void SetScreenSize (Size size)
+    {
+        if (Driver is { })
+        {
+            throw new InvalidOperationException ("Cannot set the screen size when the ConsoleDriver is already initialized.");
+        }
+        _screenSize = size;
+    }
+
     /// <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);
+    public static Rectangle Screen => Driver?.Screen ?? new (new (0, 0), _screenSize);
 
     /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
     /// <remarks>
@@ -35,11 +50,8 @@ public static partial class Application // Screen related stuff
 
         foreach (Toplevel t in TopLevels)
         {
-            if (t.SetRelativeLayout (args.Size.Value))
-            {
-                t.LayoutSubviews ();
-            }
             t.OnSizeChanging (new (args.Size));
+            t.SetLayoutNeeded ();
         }
 
         Refresh ();

+ 3 - 6
Terminal.Gui/View/Adornment/Adornment.cs

@@ -152,18 +152,15 @@ public class Adornment : View
 
         Rectangle screen = ViewportToScreen (viewport);
         Attribute normalAttr = GetNormalColor ();
-        Driver.SetAttribute (normalAttr);
+        Driver?.SetAttribute (normalAttr);
 
         // This just draws/clears the thickness, not the insides.
         Thickness.Draw (screen, ToString ());
 
         if (!string.IsNullOrEmpty (TextFormatter.Text))
         {
-            if (TextFormatter is { })
-            {
-                TextFormatter.ConstrainToSize = Frame.Size;
-                TextFormatter.NeedsFormat = true;
-            }
+            TextFormatter.ConstrainToSize = Frame.Size;
+            TextFormatter.NeedsFormat = true;
         }
 
         TextFormatter?.Draw (screen, normalAttr, normalAttr, Rectangle.Empty);

+ 15 - 15
Terminal.Gui/View/Adornment/Border.cs

@@ -703,15 +703,15 @@ public class Border : Adornment
             bool drawBottom = Thickness.Bottom > 0 && Frame.Width > 1 && Frame.Height > 1;
             bool drawRight = Thickness.Right > 0 && (Frame.Height > 1 || Thickness.Top == 0);
 
-            Attribute prevAttr = Driver.GetAttribute ();
+            Attribute prevAttr = Driver?.GetAttribute () ?? Attribute.Default;
 
             if (ColorScheme is { })
             {
-                Driver.SetAttribute (GetNormalColor ());
+                Driver?.SetAttribute (GetNormalColor ());
             }
             else
             {
-                Driver.SetAttribute (Parent!.GetNormalColor ());
+                Driver?.SetAttribute (Parent!.GetNormalColor ());
             }
 
             if (drawTop)
@@ -726,7 +726,7 @@ public class Border : Adornment
                                  borderBounds.Width,
                                  Orientation.Horizontal,
                                  lineStyle,
-                                 Driver.GetAttribute ()
+                                 Driver?.GetAttribute ()
                                 );
                 }
                 else
@@ -741,7 +741,7 @@ public class Border : Adornment
                                      Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
                                      Orientation.Horizontal,
                                      lineStyle,
-                                     Driver.GetAttribute ()
+                                     Driver?.GetAttribute ()
                                     );
                     }
 
@@ -755,7 +755,7 @@ public class Border : Adornment
                                      Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
                                      Orientation.Horizontal,
                                      lineStyle,
-                                     Driver.GetAttribute ()
+                                     Driver?.GetAttribute ()
                                     );
 
                         lc?.AddLine (
@@ -763,7 +763,7 @@ public class Border : Adornment
                                      Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
                                      Orientation.Horizontal,
                                      lineStyle,
-                                     Driver.GetAttribute ()
+                                     Driver?.GetAttribute ()
                                     );
                     }
 
@@ -774,7 +774,7 @@ public class Border : Adornment
                                  2,
                                  Orientation.Horizontal,
                                  lineStyle,
-                                 Driver.GetAttribute ()
+                                 Driver?.GetAttribute ()
                                 );
 
                     // Add a vert line for ╔╡
@@ -783,7 +783,7 @@ public class Border : Adornment
                                  titleBarsLength,
                                  Orientation.Vertical,
                                  LineStyle.Single,
-                                 Driver.GetAttribute ()
+                                 Driver?.GetAttribute ()
                                 );
 
                     // Add a vert line for ╞
@@ -798,7 +798,7 @@ public class Border : Adornment
                                  titleBarsLength,
                                  Orientation.Vertical,
                                  LineStyle.Single,
-                                 Driver.GetAttribute ()
+                                 Driver?.GetAttribute ()
                                 );
 
                     // Add the right hand line for ╞═════╗
@@ -813,7 +813,7 @@ public class Border : Adornment
                                  borderBounds.Width - Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
                                  Orientation.Horizontal,
                                  lineStyle,
-                                 Driver.GetAttribute ()
+                                 Driver?.GetAttribute ()
                                 );
                 }
             }
@@ -827,7 +827,7 @@ public class Border : Adornment
                              sideLineLength,
                              Orientation.Vertical,
                              lineStyle,
-                             Driver.GetAttribute ()
+                             Driver?.GetAttribute ()
                             );
             }
 #endif
@@ -839,7 +839,7 @@ public class Border : Adornment
                              borderBounds.Width,
                              Orientation.Horizontal,
                              lineStyle,
-                             Driver.GetAttribute ()
+                             Driver?.GetAttribute ()
                             );
             }
 
@@ -850,11 +850,11 @@ public class Border : Adornment
                              sideLineLength,
                              Orientation.Vertical,
                              lineStyle,
-                             Driver.GetAttribute ()
+                             Driver?.GetAttribute ()
                             );
             }
 
-            Driver.SetAttribute (prevAttr);
+            Driver?.SetAttribute (prevAttr);
 
             // TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler
             if (Diagnostics.HasFlag (ViewDiagnosticFlags.Ruler))

+ 2 - 6
Terminal.Gui/View/Adornment/Margin.cs

@@ -117,16 +117,12 @@ public class Margin : Adornment
             {
                 IEnumerable<View> subviewsNeedingDraw = Subviews.Where (
                                                                         view => view.Visible
-                                                                                && (view.NeedsDisplay || view.SubViewNeedsDisplay || view.IsLayoutNeeded ())
+                                                                                && (view.NeedsDisplay || view.SubViewNeedsDisplay)
                                                                        );
 
                 foreach (View view in subviewsNeedingDraw)
                 {
-                    if (view.IsLayoutNeeded ())
-                    {
-                        view.LayoutSubviews ();
-                    }
-
+                    //view.Layout ();
                     view.Draw ();
                 }
             }

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

@@ -10,7 +10,7 @@ namespace Terminal.Gui;
 /// <remarks>
 ///     <para>
 ///         Updating the properties of <see cref="Aligner"/> is supported, but will not automatically cause re-layout to
-///         happen. <see cref="View.LayoutSubviews"/>
+///         happen. <see cref="View.Layout()"/>
 ///         must be called on the SuperView.
 ///     </para>
 ///     <para>

+ 5 - 5
Terminal.Gui/View/View.Adornments.cs

@@ -54,7 +54,7 @@ public partial class View // Adornments
     ///     </para>
     ///     <para>
     ///         Changing the size of an adornment (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
-    ///         change the size of <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout of the
+    ///         change the size of <see cref="Frame"/> which will call <see cref="SetLayoutNeeded"/> to update the layout of the
     ///         <see cref="SuperView"/> and its <see cref="Subviews"/>.
     ///     </para>
     /// </remarks>
@@ -109,8 +109,8 @@ public partial class View // Adornments
     ///         View's content and are not clipped by the View's Clip Area.
     ///     </para>
     ///     <para>
-    ///         Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
-    ///         change the size of the <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout of the
+    ///         Changing the size of an adornment (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
+    ///         change the size of <see cref="Frame"/> which will call <see cref="SetLayoutNeeded"/> to update the layout of the
     ///         <see cref="SuperView"/> and its <see cref="Subviews"/>.
     ///     </para>
     /// </remarks>
@@ -217,8 +217,8 @@ public partial class View // Adornments
     ///         View's content and are not clipped by the View's Clip Area.
     ///     </para>
     ///     <para>
-    ///         Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
-    ///         change the size of the <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout of the
+    ///         Changing the size of an adornment (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>) will
+    ///         change the size of <see cref="Frame"/> which will call <see cref="SetLayoutNeeded"/> to update the layout of the
     ///         <see cref="SuperView"/> and its <see cref="Subviews"/>.
     ///     </para>
     /// </remarks>

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

@@ -265,7 +265,7 @@ public partial class View
     ///     </para>
     ///     <para>
     ///         Altering the Viewport Size will eventually (when the view is next laid out) cause the
-    ///         <see cref="LayoutSubview(View, Size)"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
+    ///         <see cref="Layout"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
     ///     </para>
     /// </remarks>
     public virtual Rectangle Viewport

+ 58 - 75
Terminal.Gui/View/View.Layout.cs

@@ -190,7 +190,7 @@ public partial class View // Layout APIs
     ///     </para>
     ///     <para>
     ///         Altering the Frame will eventually (when the view hierarchy is next laid out via  see
-    ///         cref="LayoutSubviews"/>) cause <see cref="LayoutSubview(View, Size)"/> and
+    ///         cref="LayoutSubviews"/>) cause <see cref="Layout"/> and
     ///         <see cref="OnDrawContent(Rectangle)"/>
     ///         methods to be called.
     ///     </para>
@@ -207,21 +207,15 @@ public partial class View // Layout APIs
         }
         set
         {
-            if (_frame == value)
+            // This will set _frame, call SetsNeedsLayout, and raise OnViewportChanged/ViewportChanged
+            if (SetFrame (value with { Width = Math.Max (value.Width, 0), Height = Math.Max (value.Height, 0) }))
             {
-                return;
+                // If Frame gets set, set all Pos/Dim to Absolute values.
+                _x = _frame.X;
+                _y = _frame.Y;
+                _width = _frame.Width;
+                _height = _frame.Height;
             }
-
-            // This will set _frame, call SetsNeedsLayout, and raise OnViewportChanged/ViewportChanged
-            SetFrame (value with { Width = Math.Max (value.Width, 0), Height = Math.Max (value.Height, 0) });
-
-            // If Frame gets set, set all Pos/Dim to Absolute values.
-            _x = _frame.X;
-            _y = _frame.Y;
-            _width = _frame.Width;
-            _height = _frame.Height;
-
-            SetLayoutNeeded ();
         }
     }
 
@@ -229,11 +223,12 @@ public partial class View // Layout APIs
     ///     INTERNAL API - Sets _frame, calls SetsNeedsLayout, and raises OnViewportChanged/ViewportChanged
     /// </summary>
     /// <param name="frame"></param>
-    private void SetFrame (in Rectangle frame)
+    /// <returns><see langword="true"/> if the frame was changed.</returns>
+    private bool SetFrame (in Rectangle frame)
     {
         if (_frame == frame)
         {
-            return;
+            return false;
         }
 
         var oldViewport = Rectangle.Empty;
@@ -252,6 +247,8 @@ public partial class View // Layout APIs
 
         // BUGBUG: When SetFrame is called from Frame_set, this event gets raised BEFORE OnResizeNeeded. Is that OK?
         OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport));
+
+        return true;
     }
 
     /// <summary>Gets the <see cref="Frame"/> with a screen-relative location.</summary>
@@ -331,7 +328,7 @@ public partial class View // Layout APIs
     ///     </para>
     ///     <para>
     ///         Changing this property will eventually (when the view is next drawn) cause the
-    ///         <see cref="LayoutSubview(View, Size)"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
+    ///         <see cref="Layout"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
     ///     </para>
     ///     <para>
     ///         Changing this property will cause <see cref="Frame"/> to be updated.
@@ -350,12 +347,6 @@ public partial class View // Layout APIs
 
             _x = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (X)} cannot be null");
 
-            if (!IsInitialized)
-            {
-                // Supports Unit Tests that don't call Begin/EndInit
-                //SetRelativeLayout (GetBestGuessSuperViewContentSize ());
-            }
-
             SetLayoutNeeded ();
         }
     }
@@ -380,7 +371,7 @@ public partial class View // Layout APIs
     ///     </para>
     ///     <para>
     ///         Changing this property will eventually (when the view is next drawn) cause the
-    ///         <see cref="LayoutSubview(View, Size)"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
+    ///         <see cref="Layout"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
     ///     </para>
     ///     <para>
     ///         Changing this property will cause <see cref="Frame"/> to be updated.
@@ -399,12 +390,6 @@ public partial class View // Layout APIs
 
             _y = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Y)} cannot be null");
 
-            if (!IsInitialized)
-            {
-                // Supports Unit Tests that don't call Begin/EndInit
-                //SetRelativeLayout (GetBestGuessSuperViewContentSize ());
-            }
-
             SetLayoutNeeded ();
         }
     }
@@ -430,7 +415,7 @@ public partial class View // Layout APIs
     ///     </para>
     ///     <para>
     ///         Changing this property will eventually (when the view is next drawn) cause the
-    ///         <see cref="LayoutSubview(View, Size)"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
+    ///         <see cref="Layout"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
     ///     </para>
     ///     <para>
     ///         Changing this property will cause <see cref="Frame"/> to be updated.
@@ -458,12 +443,6 @@ public partial class View // Layout APIs
             // Reset TextFormatter - Will be recalculated in SetTextFormatterSize
             TextFormatter.ConstrainToHeight = null;
 
-            if (!IsInitialized)
-            {
-                // Supports Unit Tests that don't call Begin/EndInit
-                //SetRelativeLayout (GetBestGuessSuperViewContentSize ());
-            }
-
             SetLayoutNeeded ();
         }
     }
@@ -489,7 +468,7 @@ public partial class View // Layout APIs
     ///     </para>
     ///     <para>
     ///         Changing this property will eventually (when the view is next drawn) cause the
-    ///         <see cref="LayoutSubview(View, Size)"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
+    ///         <see cref="Layout"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
     ///     </para>
     ///     <para>
     ///         Changing this property will cause <see cref="Frame"/> to be updated.
@@ -517,12 +496,6 @@ public partial class View // Layout APIs
             // Reset TextFormatter - Will be recalculated in SetTextFormatterSize
             TextFormatter.ConstrainToWidth = null;
 
-            if (!IsInitialized)
-            {
-                // Supports Unit Tests that don't call Begin/EndInit
-                //SetRelativeLayout (GetBestGuessSuperViewContentSize ());
-            }
-
             SetLayoutNeeded ();
         }
     }
@@ -559,7 +532,7 @@ public partial class View // Layout APIs
     ///     </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
+    ///         other subviews, <see cref="Layout"/> on
     ///         will be called for that subview.
     ///     </para>
     ///     <para>
@@ -657,7 +630,6 @@ public partial class View // Layout APIs
                 SetTitleTextFormatterSize ();
             }
 
-            //SetNeedsDisplay ();
             SuperView?.SetNeedsDisplay ();
         }
 
@@ -674,10 +646,8 @@ public partial class View // Layout APIs
         return true;
     }
 
-    // TODO: remove virtual from this
     /// <summary>
-    ///     Invoked when the dimensions of the view have changed, for example in response to the container view or terminal
-    ///     resizing.
+    ///    INTERNAL API - Causes the view's subviews and adornments to be laid out within the view's content areas. Assumes the view's relative layout has been set via <see cref="SetRelativeLayout"/>.
     /// </summary>
     /// <remarks>
     ///     <para>
@@ -690,7 +660,7 @@ public partial class View // Layout APIs
     ///     </para>
     ///     <para>Raises the <see cref="LayoutComplete"/> event before it returns.</para>
     /// </remarks>
-    public virtual void LayoutSubviews ()
+    internal void LayoutSubviews ()
     {
         if (!IsInitialized)
         {
@@ -707,6 +677,7 @@ public partial class View // Layout APIs
         Size contentSize = GetContentSize ();
         OnLayoutStarted (new (contentSize));
 
+        // The Adornments already have their Frame's set by SetRelativeLayout so we call LayoutSubViews vs. Layout here.
         Margin?.LayoutSubviews ();
         Border?.LayoutSubviews ();
         Padding?.LayoutSubviews ();
@@ -720,7 +691,7 @@ public partial class View // Layout APIs
         List<View> redo = new ();
         foreach (View v in ordered)
         {
-            if (!LayoutSubview (v, contentSize))
+            if (!v.Layout (contentSize))
             {
                 redo.Add (v);
             }
@@ -729,7 +700,7 @@ public partial class View // Layout APIs
         bool layoutStillNeeded = false;
         foreach (View v in redo)
         {
-            if (!LayoutSubview (v, contentSize))
+            if (!v.Layout (contentSize))
             {
                 layoutStillNeeded = true;
             }
@@ -742,7 +713,7 @@ public partial class View // Layout APIs
             foreach ((View from, View to) in edges)
             {
                 Debug.Fail ("This is dead code?");
-                LayoutSubview (to, from.GetContentSize ());
+                to.Layout (from.GetContentSize ());
             }
         }
 
@@ -752,17 +723,16 @@ public partial class View // Layout APIs
     }
 
     /// <summary>
-    ///     Lays out <see cref="subView"/>. 
+    ///     Performs layout of the view and its subviews within the specified content size.
     /// </summary>
-    /// <param name="subView"></param>
     /// <param name="contentSize"></param>
     /// <returns><see langword="false"/>If the view could not be laid out (typically because a dependencies was not ready). </returns>
-    private bool LayoutSubview (View subView, Size contentSize)
+    public bool Layout (Size contentSize)
     {
         // Note, SetRelativeLayout calls SetTextFormatterSize
-        if (subView.SetRelativeLayout (contentSize))
+        if (SetRelativeLayout (contentSize))
         {
-            subView.LayoutSubviews ();
+            LayoutSubviews ();
 
             return true;
         }
@@ -770,6 +740,15 @@ public partial class View // Layout APIs
         return false;
     }
 
+    /// <summary>
+    ///     Performs layout of the view and its subviews using the content size of either the <see cref="SuperView"/> or <see cref="Application.Screen"/>.
+    /// </summary>
+    /// <returns><see langword="false"/>If the view could not be laid out (typically because a dependencies was not ready). </returns>
+    public bool Layout ()
+    {
+        return Layout (GetBestGuessSuperViewContentSize ());
+    }
+
     /// <summary>
     ///     Raises the <see cref="LayoutComplete"/> event. Called from  <see cref="LayoutSubviews"/> before all sub-views
     ///     have been laid out.
@@ -787,17 +766,26 @@ public partial class View // Layout APIs
     private bool _layoutNeeded = true;
 
     /// <summary>
-    ///     Indicates the View's Frame or the relative layout of the View's subviews (including Adornments) have
-    ///     changed since the last time the View was laid out. Used to prevent <see cref="LayoutSubviews"/> from needlessly computing
-    ///     layout.
+    ///     Indicates the View's Frame or the layout of the View's subviews (including Adornments) have
+    ///     changed since the last time the View was laid out. 
     /// </summary>
-    /// <returns></returns>
-    public bool IsLayoutNeeded () => _layoutNeeded;
+    /// <remarks>
+    /// <para>Used to prevent <see cref="Layout()"/> from needlessly computing
+    ///     layout.
+    /// </para>
+    /// </remarks>
+    /// <returns><see langword="true"/> if layout is needed.</returns>
+    public bool IsLayoutNeeded () { return _layoutNeeded; }
 
     /// <summary>
-    ///     INTERNAL API - Sets <see cref="_layoutNeeded"/> for this View and all of it's subviews and it's SuperView.
-    ///     The main loop will call SetRelativeLayout and LayoutSubviews for any view with <see cref="IsLayoutNeeded"/> set.
+    ///     Sets <see cref="IsLayoutNeeded"/> to return <see langword="true"/>, indicating this View and all of it's subviews (including adornments) need to be laid out in the next Application iteration.
     /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         The <see cref="MainLoop"/> will cause <see cref="Layout()"/> to be called on the next <see cref="Application.Iteration"/> so there is normally no reason to call see <see cref="Layout()"/>.
+    ///     </para>
+    /// </remarks>
+
     public void SetLayoutNeeded ()
     {
         if (IsLayoutNeeded ())
@@ -880,7 +868,7 @@ public partial class View // Layout APIs
     }
 
     /// <summary>
-    ///     Collects dimension (where Width or Height is `DimView`) dependencies for a given view.
+    ///      INTERNAL API - 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>
@@ -891,7 +879,7 @@ public partial class View // Layout APIs
     /// </param>
     internal void CollectDim (Dim? dim, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
     {
-        if (dim!.Has<DimView> (out var dv))
+        if (dim!.Has<DimView> (out DimView dv))
         {
             if (dv.Target != this)
             {
@@ -899,21 +887,15 @@ public partial class View // Layout APIs
             }
         }
 
-        if (dim!.Has<DimCombine> (out var dc))
+        if (dim!.Has<DimCombine> (out DimCombine dc))
         {
             CollectDim (dc.Left, from, ref nNodes, ref nEdges);
             CollectDim (dc.Right, from, ref nNodes, ref nEdges);
         }
-
-        if (dim!.Has<DimFunc> (out var df))
-        {
-
-        }
-
     }
 
     /// <summary>
-    ///     Collects position (where X or Y is `PosView`) dependencies for a given view.
+    ///     INTERNAL API - 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>
@@ -924,6 +906,7 @@ public partial class View // Layout APIs
     /// </param>
     internal void CollectPos (Pos pos, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
     {
+        // TODO: Use Pos.Has<T> instead.
         switch (pos)
         {
             case PosView pv:

+ 5 - 3
Terminal.Gui/View/View.cs

@@ -74,7 +74,9 @@ namespace Terminal.Gui;
 ///         To flag the entire view for redraw call <see cref="SetNeedsDisplay()"/>.
 ///     </para>
 ///     <para>
-///         The <see cref="LayoutSubviews"/> method is invoked when the size or layout of a view has changed.
+///         The <see cref="SetLayoutNeeded"/> method is called when the size or layout of a view has changed. The <see cref="MainLoop"/> will
+///         cause <see cref="Layout()"/> to be called on the next <see cref="Application.Iteration"/> so there is normally no reason to direclty call
+///         see <see cref="Layout()"/>.
 ///     </para>
 ///     <para>
 ///         Views have a <see cref="ColorScheme"/> property that defines the default colors that subviews should use for
@@ -243,8 +245,8 @@ public partial class View : Responder, ISupportInitializeNotification
             }
         }
 
-        // TOOD: Figure out how to move this out of here and just depend on IsLayoutNeeded in Mainloop
-        LayoutSubviews();
+        // TODO: Figure out how to move this out of here and just depend on IsLayoutNeeded in Mainloop
+        Layout ();
 
         Initialized?.Invoke (this, EventArgs.Empty);
     }

+ 3 - 4
Terminal.Gui/Views/ColorPicker.cs

@@ -90,10 +90,7 @@ public partial class ColorPicker : View
         CreateTextField ();
         SelectedColor = oldValue;
 
-        if (IsInitialized)
-        {
-            LayoutSubviews ();
-        }
+        SetLayoutNeeded ();
     }
 
     /// <summary>
@@ -275,6 +272,8 @@ public partial class ColorPicker : View
         {
             _tfHex.Text = colorHex;
         }
+
+        SetLayoutNeeded ();
     }
 
     private void UpdateSingleBarValueFromTextField (object? sender, HasFocusEventArgs e)

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

@@ -189,7 +189,7 @@ public class FileDialog : Dialog
                                                   bool newState = !tile.ContentView.Visible;
                                                   tile.ContentView.Visible = newState;
                                                   _btnToggleSplitterCollapse.Text = GetToggleSplitterText (newState);
-                                                  LayoutSubviews ();
+                                                  SetLayoutNeeded();
                                               };
 
         _tbFind = new TextField
@@ -493,7 +493,8 @@ public class FileDialog : Dialog
             _btnOk.X = Pos.Right (_btnCancel) + 1;
             MoveSubviewTowardsStart (_btnCancel);
         }
-        LayoutSubviews ();
+
+        SetLayoutNeeded();
     }
 
     /// <inheritdoc/>

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

@@ -5,6 +5,8 @@
 //   Miguel de Icaza ([email protected])
 //
 
+using System.Diagnostics;
+
 namespace Terminal.Gui;
 
 /// <summary>ScrollBarViews are views that display a 1-character scrollbar, either horizontal or vertical</summary>
@@ -259,7 +261,7 @@ public class ScrollBarView : View
             {
                 SetRelativeLayout (SuperView?.Frame.Size ?? Host.Frame.Size);
                 ShowHideScrollBars (false);
-                SetNeedsDisplay ();
+                SetLayoutNeeded ();
             }
         }
     }

+ 29 - 18
Terminal.Gui/Views/TabView.cs

@@ -147,12 +147,27 @@ public class TabView : View
 
                 OnSelectedTabChanged (old, value);
             }
+            SetLayoutNeeded ();
         }
     }
 
+    private TabStyle _style = new ();
+
     /// <summary>Render choices for how to display tabs.  After making changes, call <see cref="ApplyStyleChanges()"/>.</summary>
     /// <value></value>
-    public TabStyle Style { get; set; } = new ();
+    public TabStyle Style
+    {
+        get => _style;
+        set
+        {
+            if (_style == value)
+            {
+                return;
+            }
+            _style = value;
+            SetLayoutNeeded();
+        }
+    }
 
     /// <summary>All tabs currently hosted by the control.</summary>
     /// <value></value>
@@ -163,7 +178,11 @@ public class TabView : View
     public int TabScrollOffset
     {
         get => _tabScrollOffset;
-        set => _tabScrollOffset = EnsureValidScrollOffsets (value);
+        set
+        {
+            _tabScrollOffset = EnsureValidScrollOffsets (value);
+            SetLayoutNeeded ();
+        }
     }
 
     /// <summary>Adds the given <paramref name="tab"/> to <see cref="Tabs"/>.</summary>
@@ -188,7 +207,7 @@ public class TabView : View
             tab.View?.SetFocus ();
         }
 
-        SetNeedsDisplay ();
+        SetLayoutNeeded ();
     }
 
     /// <summary>
@@ -245,12 +264,7 @@ public class TabView : View
             // Should be able to just use 0 but switching between top/bottom tabs repeatedly breaks in ValidatePosDim if just using the absolute value 0
         }
 
-        if (IsInitialized)
-        {
-            LayoutSubviews ();
-        }
-
-        SetNeedsDisplay ();
+        SetLayoutNeeded();
     }
 
     /// <summary>Updates <see cref="TabScrollOffset"/> to ensure that <see cref="SelectedTab"/> is visible.</summary>
@@ -327,7 +341,7 @@ public class TabView : View
         }
 
         EnsureSelectedTabIsVisible ();
-        SetNeedsDisplay ();
+        SetLayoutNeeded ();
     }
 
     /// <summary>Event for when <see cref="SelectedTab"/> changes.</summary>
@@ -349,7 +363,6 @@ public class TabView : View
         if (Tabs.Count == 1 || SelectedTab is null)
         {
             SelectedTab = Tabs.ElementAt (0);
-            SetNeedsDisplay ();
 
             return SelectedTab is { };
         }
@@ -359,9 +372,7 @@ public class TabView : View
         // Currently selected tab has vanished!
         if (currentIdx == -1)
         {
-            SelectedTab = Tabs.ElementAt (0);
-            SetNeedsDisplay ();
-
+            SelectedTab = Tabs.ElementAt (0); 
             return true;
         }
 
@@ -373,7 +384,6 @@ public class TabView : View
         }
 
         SelectedTab = _tabs [newIdx];
-        SetNeedsDisplay ();
 
         EnsureSelectedTabIsVisible ();
 
@@ -611,7 +621,7 @@ public class TabView : View
                 {
                     _host.SwitchTabBy (scrollIndicatorHit);
 
-                    SetNeedsDisplay ();
+                    SetLayoutNeeded ();
 
                     return true;
                 }
@@ -619,7 +629,7 @@ public class TabView : View
                 if (hit is { })
                 {
                     _host.SelectedTab = hit;
-                    SetNeedsDisplay ();
+                    SetLayoutNeeded ();
 
                     return true;
                 }
@@ -1256,7 +1266,8 @@ public class TabView : View
 
                 tab.Text = toRender.TextToRender;
 
-                LayoutSubviews ();
+                // BUGBUG: Layout should only be called from Mainloop iteration!
+                Layout ();
 
                 tab.OnDrawAdornments ();
 

+ 27 - 47
Terminal.Gui/Views/TileView.cs

@@ -23,6 +23,23 @@ public class TileView : View
     {
         CanFocus = true;
         RebuildForTileCount (tiles);
+
+        LayoutStarted += (_, _) =>
+                         {
+                             Rectangle viewport = Viewport;
+
+                             if (HasBorder ())
+                             {
+                                 viewport = new (
+                                                 viewport.X + 1,
+                                                 viewport.Y + 1,
+                                                 Math.Max (0, viewport.Width - 2),
+                                                 Math.Max (0, viewport.Height - 2)
+                                                );
+                             }
+
+                             Setup (viewport);
+                         };
     }
 
     /// <summary>The line style to use when drawing the splitter lines.</summary>
@@ -34,12 +51,14 @@ public class TileView : View
         get => _orientation;
         set
         {
-            _orientation = value;
-
-            if (IsInitialized)
+            if (_orientation == value)
             {
-                LayoutSubviews ();
+                return;
             }
+
+            _orientation = value;
+
+            SetLayoutNeeded ();
         }
     }
 
@@ -131,13 +150,7 @@ public class TileView : View
             }
         }
 
-        SetNeedsDisplay ();
-
-        if (IsInitialized)
-        {
-            LayoutSubviews ();
-        }
-
+        SetLayoutNeeded ();
         return toReturn;
     }
 
@@ -155,31 +168,6 @@ public class TileView : View
     /// <returns></returns>
     public bool IsRootTileView () { return _parentTileView == null; }
 
-    // TODO: Use OnLayoutStarted instead
-    /// <inheritdoc/>
-    public override void LayoutSubviews ()
-    {
-        if (!IsInitialized)
-        {
-            return;
-        }
-
-        Rectangle viewport = Viewport;
-
-        if (HasBorder ())
-        {
-            viewport = new (
-                            viewport.X + 1,
-                            viewport.Y + 1,
-                            Math.Max (0, viewport.Width - 2),
-                            Math.Max (0, viewport.Height - 2)
-                           );
-        }
-
-        Setup (viewport);
-        base.LayoutSubviews ();
-    }
-
     // BUG: v2 fix this hack
     // QUESTION: Does this need to be fixed before events are refactored?
     /// <summary>Overridden so no Frames get drawn</summary>
@@ -364,12 +352,8 @@ public class TileView : View
             _tiles.Add (tile);
             tile.ContentView.Id = $"Tile.ContentView {i}";
             Add (tile.ContentView);
-            tile.TitleChanged += (s, e) => SetNeedsDisplay ();
-        }
-
-        if (IsInitialized)
-        {
-            LayoutSubviews ();
+            // BUGBUG: This should not be needed:
+            tile.TitleChanged += (s, e) => SetLayoutNeeded ();
         }
     }
 
@@ -407,9 +391,6 @@ public class TileView : View
             Add (_tiles [i].ContentView);
         }
 
-        SetNeedsDisplay ();
-        LayoutSubviews ();
-
         return removed;
     }
 
@@ -441,7 +422,6 @@ public class TileView : View
         }
 
         _splitterDistances [idx] = value;
-        GetRootTileView ().LayoutSubviews ();
         OnSplitterMoved (idx);
 
         return true;
@@ -957,7 +937,7 @@ public class TileView : View
                     moveRuneRenderLocation = new Point (0, Math.Max (1, Math.Min (Viewport.Height - 2, mouseEvent.Position.Y)));
                 }
 
-                Parent.SetNeedsDisplay ();
+                Parent.SetLayoutNeeded ();
 
                 return true;
             }

+ 10 - 20
Terminal.Gui/Views/Toplevel.cs

@@ -235,7 +235,7 @@ public partial class Toplevel : View
             return;
         }
 
-        var layoutSubviews = false;
+        //var layoutSubviews = false;
         var maxWidth = 0;
 
         if (superView.Margin is { } && superView == top.SuperView)
@@ -251,36 +251,26 @@ public partial class Toplevel : View
             if (top?.X is null or PosAbsolute && top?.Frame.X != nx)
             {
                 top!.X = nx;
-                layoutSubviews = true;
+                //layoutSubviews = true;
             }
 
             if (top?.Y is null or PosAbsolute && top?.Frame.Y != ny)
             {
                 top!.Y = ny;
-                layoutSubviews = true;
+                //layoutSubviews = true;
             }
         }
 
-        //// TODO: v2 - This is a hack to get the StatusBar to be positioned correctly.
-        //if (sb != null
-        //    && !top!.Subviews.Contains (sb)
-        //    && ny + top.Frame.Height != superView.Frame.Height - (sb.Visible ? 1 : 0)
-        //    && top.Height is DimFill
-        //    && -top.Height.GetAnchor (0) < 1)
+
+        //if (superView.IsLayoutNeeded () || layoutSubviews)
         //{
-        //    top.Height = Dim.Fill (sb.Visible ? 1 : 0);
-        //    layoutSubviews = true;
+        //    superView.LayoutSubviews ();
         //}
 
-        if (superView.IsLayoutNeeded () || layoutSubviews)
-        {
-            superView.LayoutSubviews ();
-        }
-
-        if (IsLayoutNeeded ())
-        {
-            LayoutSubviews ();
-        }
+        //if (IsLayoutNeeded ())
+        //{
+        //    LayoutSubviews ();
+        //}
     }
 
     /// <summary>Invoked when the terminal has been resized. The new <see cref="Size"/> of the terminal is provided.</summary>

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

@@ -546,9 +546,6 @@ public class Wizard : Dialog
         SizeStep (CurrentStep);
 
         SetLayoutNeeded ();
-        LayoutSubviews ();
-
-        //Draw ();
     }
 
     private void Wizard_Closing (object sender, ToplevelClosingEventArgs obj)

+ 3 - 3
UICatalog/Scenarios/BorderEditor.cs

@@ -29,7 +29,7 @@ public class BorderEditor : AdornmentEditor
     {
         List<LineStyle> borderStyleEnum = Enum.GetValues (typeof (LineStyle)).Cast<LineStyle> ().ToList ();
 
-        _rbBorderStyle = new()
+        _rbBorderStyle = new ()
         {
             X = 0,
 
@@ -46,7 +46,7 @@ public class BorderEditor : AdornmentEditor
 
         _rbBorderStyle.SelectedItemChanged += OnRbBorderStyleOnSelectedItemChanged;
 
-        _ckbTitle = new()
+        _ckbTitle = new ()
         {
             X = 0,
             Y = Pos.Bottom (_rbBorderStyle),
@@ -91,7 +91,7 @@ public class BorderEditor : AdornmentEditor
             }
 
             ((Border)AdornmentToEdit).SetNeedsDisplay ();
-            LayoutSubviews ();
+            SetLayoutNeeded ();
         }
 
         void OnCkbTitleOnToggle (object sender, CancelEventArgs<CheckState> args)

+ 0 - 1
UICatalog/Scenarios/ColorPicker.cs

@@ -218,7 +218,6 @@ public class ColorPickers : Scenario
         // Set default colors.
         foregroundColorPicker.SelectedColor = _demoView.SuperView.ColorScheme.Normal.Foreground.GetClosestNamedColor16 ();
         backgroundColorPicker.SelectedColor = _demoView.SuperView.ColorScheme.Normal.Background.GetClosestNamedColor16 ();
-        app.Initialized += (s, e) => app.LayoutSubviews ();
 
         Application.Run (app);
         app.Dispose ();

+ 0 - 10
UICatalog/Scenarios/ComputedLayout.cs

@@ -370,7 +370,6 @@ public class ComputedLayout : Scenario
                                     // The call to app.LayoutSubviews causes the Computed layout to
                                     // get updated. 
                                     anchorButton.Text += "!";
-                                    app.LayoutSubviews ();
                                 };
         app.Add (anchorButton);
 
@@ -415,10 +414,7 @@ public class ComputedLayout : Scenario
                               {
                                   // This demonstrates how to have a dynamically sized button
                                   // Each time the button is clicked the button's text gets longer
-                                  // The call to app.LayoutSubviews causes the Computed layout to
-                                  // get updated. 
                                   leftButton.Text += "!";
-                                  app.LayoutSubviews ();
                               };
 
         // show positioning vertically using Pos.AnchorEnd
@@ -433,10 +429,7 @@ public class ComputedLayout : Scenario
                                 {
                                     // This demonstrates how to have a dynamically sized button
                                     // Each time the button is clicked the button's text gets longer
-                                    // The call to app.LayoutSubviews causes the Computed layout to
-                                    // get updated. 
                                     centerButton.Text += "!";
-                                    app.LayoutSubviews ();
                                 };
 
         // show positioning vertically using another window and Pos.Bottom
@@ -451,10 +444,7 @@ public class ComputedLayout : Scenario
                                {
                                    // This demonstrates how to have a dynamically sized button
                                    // Each time the button is clicked the button's text gets longer
-                                   // The call to app.LayoutSubviews causes the Computed layout to
-                                   // get updated. 
                                    rightButton.Text += "!";
-                                   app.LayoutSubviews ();
                                };
 
         View [] buttons = { leftButton, centerButton, rightButton };

+ 0 - 2
UICatalog/Scenarios/ConfigurationEditor.cs

@@ -154,8 +154,6 @@ public class ConfigurationEditor : Scenario
         {
             _tileView.Tiles.ToArray () [1].ContentView.SetFocus ();
         }
-
-        Application.Top.LayoutSubviews ();
     }
 
     private void Quit ()

+ 0 - 1
UICatalog/Scenarios/Dialogs.cs

@@ -340,7 +340,6 @@ public class Dialogs : Scenario
                                       button.Text += char.ConvertFromUtf32 (CODE_POINT);
                                   }
 
-                                  dialog.LayoutSubviews ();
                                   e.Cancel = true;
                               };
             dialog.Add (addChar);

+ 0 - 3
UICatalog/Scenarios/Editor.cs

@@ -306,9 +306,6 @@ public class Editor : Scenario
                                          _scrollBar.OtherScrollBarView.Size = _textView.Maxlength;
                                          _scrollBar.OtherScrollBarView.Position = _textView.LeftColumn;
                                      }
-
-                                     _scrollBar.LayoutSubviews ();
-                                     _scrollBar.Refresh ();
                                  };
 
 

+ 3 - 4
UICatalog/Scenarios/LineDrawing.cs

@@ -253,12 +253,8 @@ public class ToolsView : Window
 
     private void ToolsView_Initialized (object sender, EventArgs e)
     {
-        LayoutSubviews ();
-
         Width = Math.Max (_colors.Frame.Width, _stylePicker.Frame.Width) + GetAdornmentsThickness ().Horizontal;
-
         Height = _colors.Frame.Height + _stylePicker.Frame.Height + _addLayerBtn.Frame.Height + GetAdornmentsThickness ().Vertical;
-        SuperView.LayoutSubviews ();
     }
 }
 
@@ -289,6 +285,9 @@ public class DrawingArea : View
                 }
             }
         }
+
+        // TODO: This is a hack to work around overlapped views not drawing correctly.
+        SuperView?.SetLayoutNeeded();
     }
 
     //// BUGBUG: Why is this not handled by a key binding???

+ 0 - 2
UICatalog/Scenarios/PosAlignDemo.cs

@@ -335,8 +335,6 @@ public sealed class PosAlignDemo : Scenario
                 }
             }
         }
-
-        superView.LayoutSubviews ();
     }
 
     /// <summary>

+ 0 - 2
UICatalog/Scenarios/Progress.cs

@@ -304,7 +304,6 @@ public class Progress : Scenario
                                 {
                                     Spinner.Visible = true;
                                     ActivityProgressBar.Width = Dim.Fill () - Spinner.Width;
-                                    LayoutSubviews ();
                                 }
                                );
         }
@@ -319,7 +318,6 @@ public class Progress : Scenario
                                 {
                                     Spinner.Visible = false;
                                     ActivityProgressBar.Width = Dim.Fill () - Spinner.Width;
-                                    LayoutSubviews ();
                                 }
                                );
         }

+ 1 - 3
UICatalog/Scenarios/Scrolling.cs

@@ -134,10 +134,8 @@ public class Scrolling : Scenario
                                {
                                    // This demonstrates how to have a dynamically sized button
                                    // Each time the button is clicked the button's text gets longer
-                                   // The call to Win.LayoutSubviews causes the Computed layout to
-                                   // get updated. 
                                    anchorButton.Text += "!";
-                                   app.LayoutSubviews ();
+
                                };
         scrollView.Add (anchorButton);
 

+ 0 - 8
UICatalog/Scenarios/Sliders.cs

@@ -219,11 +219,6 @@ public class Sliders : Scenario
                                              }
                                          }
                                      }
-
-                                     if (app.IsInitialized)
-                                     {
-                                         app.LayoutSubviews ();
-                                     }
                                  };
         optionsSlider.SetOption (0); // Legends
         optionsSlider.SetOption (1); // RangeAllowSingle
@@ -326,8 +321,6 @@ public class Sliders : Scenario
                                                                 }
                                                             }
                                                         }
-
-                                                        app.LayoutSubviews ();
                                                     };
 
         #endregion Slider Orientation Slider
@@ -384,7 +377,6 @@ public class Sliders : Scenario
                                                              }
                                                          }
 
-                                                         app.LayoutSubviews ();
                                                      };
 
         #endregion Legends Orientation Slider

+ 4 - 9
UICatalog/Scenarios/TileViewNesting.cs

@@ -35,16 +35,16 @@ public class TileViewNesting : Scenario
         _textField.TextChanged += (s, e) => SetupTileView ();
 
         _cbHorizontal = new() { X = Pos.Right (_textField) + 1, Text = "Horizontal" };
-        _cbHorizontal.CheckedStateChanging += (s, e) => SetupTileView ();
+        _cbHorizontal.CheckedStateChanged += (s, e) => SetupTileView ();
 
         _cbBorder = new() { X = Pos.Right (_cbHorizontal) + 1, Text = "Border" };
-        _cbBorder.CheckedStateChanging += (s, e) => SetupTileView ();
+        _cbBorder.CheckedStateChanged += (s, e) => SetupTileView ();
 
         _cbTitles = new() { X = Pos.Right (_cbBorder) + 1, Text = "Titles" };
-        _cbTitles.CheckedStateChanging += (s, e) => SetupTileView ();
+        _cbTitles.CheckedStateChanged += (s, e) => SetupTileView ();
 
         _cbUseLabels = new() { X = Pos.Right (_cbTitles) + 1, Text = "Use Labels" };
-        _cbUseLabels.CheckedStateChanging += (s, e) => SetupTileView ();
+        _cbUseLabels.CheckedStateChanged += (s, e) => SetupTileView ();
 
         _workArea = new() { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill () };
 
@@ -196,11 +196,6 @@ public class TileViewNesting : Scenario
             _viewsToCreate = numberOfViews;
             AddMoreViews (root);
         }
-
-        if (_loaded)
-        {
-            _workArea.LayoutSubviews ();
-        }
     }
 
     private void Split (TileView to, bool left)

+ 0 - 3
UICatalog/Scenarios/Wizards.cs

@@ -336,9 +336,6 @@ public class Wizards : Scenario
                                                                            scrollBar.OtherScrollBarView.Size = someText.Maxlength;
                                                                            scrollBar.OtherScrollBarView.Position = someText.LeftColumn;
                                                                        }
-
-                                                                       scrollBar.LayoutSubviews ();
-                                                                       scrollBar.Refresh ();
                                                                    };
                                            fourthStep.Add (scrollBar);
 

+ 1 - 1
UnitTests/Application/ApplicationTests.cs

@@ -546,7 +546,7 @@ public class ApplicationTests
         var actionCalled = 0;
         Application.Invoke (() => { actionCalled++; });
         Application.MainLoop.Running = true;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         Assert.Equal (1, actionCalled);
         top.Dispose ();
         Application.Shutdown ();

+ 11 - 12
UnitTests/Dialogs/DialogTests.cs

@@ -51,8 +51,8 @@ public class DialogTests
         // Now add a second button
         buttonRow = $"{CM.Glyphs.VLine} {btn1} {btn2} {CM.Glyphs.VLine}";
         dlg.AddButton (new () { Text = btn2Text });
-        var first = false;
-        RunIteration (ref runstate, ref first);
+        
+        RunIteration (ref runstate);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
         dlg.Dispose ();
@@ -76,8 +76,7 @@ public class DialogTests
         // Now add a second button
         buttonRow = $"{CM.Glyphs.VLine}{btn1}   {btn2}{CM.Glyphs.VLine}";
         dlg.AddButton (new () { Text = btn2Text });
-        first = false;
-        RunIteration (ref runstate, ref first);
+        RunIteration (ref runstate);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
         dlg.Dispose ();
@@ -101,8 +100,8 @@ public class DialogTests
         // Now add a second button
         buttonRow = $"{CM.Glyphs.VLine}  {btn1} {btn2}{CM.Glyphs.VLine}";
         dlg.AddButton (new () { Text = btn2Text });
-        first = false;
-        RunIteration (ref runstate, ref first);
+
+        RunIteration (ref runstate);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
         dlg.Dispose ();
@@ -126,8 +125,8 @@ public class DialogTests
         // Now add a second button
         buttonRow = $"{CM.Glyphs.VLine}{btn1} {btn2}  {CM.Glyphs.VLine}";
         dlg.AddButton (new () { Text = btn2Text });
-        first = false;
-        RunIteration (ref runstate, ref first);
+
+        RunIteration (ref runstate);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
         dlg.Dispose ();
@@ -849,7 +848,7 @@ public class DialogTests
         button2 = new Button { Text = btn2Text };
         (runstate, dlg) = RunButtonTestDialog (title, width, Alignment.Center, button1, button2);
         button1.Visible = false;
-        RunIteration (ref runstate, ref firstIteration);
+        RunIteration (ref runstate, firstIteration);
         buttonRow = $@"{CM.Glyphs.VLine}         {btn2} {CM.Glyphs.VLine}";
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
@@ -861,7 +860,7 @@ public class DialogTests
         button2 = new Button { Text = btn2Text };
         (runstate, dlg) = RunButtonTestDialog (title, width, Alignment.Fill, button1, button2);
         button1.Visible = false;
-        RunIteration (ref runstate, ref firstIteration);
+        RunIteration (ref runstate, firstIteration);
         buttonRow = $@"{CM.Glyphs.VLine}          {btn2}{CM.Glyphs.VLine}";
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
@@ -873,7 +872,7 @@ public class DialogTests
         button2 = new Button { Text = btn2Text };
         (runstate, dlg) = RunButtonTestDialog (title, width, Alignment.End, button1, button2);
         button1.Visible = false;
-        RunIteration (ref runstate, ref firstIteration);
+        RunIteration (ref runstate, firstIteration);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
         dlg.Dispose ();
@@ -884,7 +883,7 @@ public class DialogTests
         button2 = new Button { Text = btn2Text };
         (runstate, dlg) = RunButtonTestDialog (title, width, Alignment.Start, button1, button2);
         button1.Visible = false;
-        RunIteration (ref runstate, ref firstIteration);
+        RunIteration (ref runstate, firstIteration);
         buttonRow = $@"{CM.Glyphs.VLine}        {btn2}  {CM.Glyphs.VLine}";
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);

+ 5 - 5
UnitTests/Dialogs/WizardTests.cs

@@ -31,10 +31,10 @@ public class WizardTests ()
 
         RunState runstate = Application.Begin (wizard);
         var firstIteration = true;
-        Application.RunIteration (ref runstate, ref firstIteration);
+        Application.RunIteration (ref runstate, firstIteration);
 
         wizard.NextFinishButton.InvokeCommand (Command.Accept);
-        Application.RunIteration (ref runstate, ref firstIteration);
+        Application.RunIteration (ref runstate, firstIteration);
         Application.End (runstate);
         Assert.True (finishedFired);
         Assert.True (closedFired);
@@ -56,7 +56,7 @@ public class WizardTests ()
         wizard.Closed += (s, e) => { closedFired = true; };
 
         runstate = Application.Begin (wizard);
-        Application.RunIteration (ref runstate, ref firstIteration);
+        Application.RunIteration (ref runstate, firstIteration);
 
         Assert.Equal (step1.Title, wizard.CurrentStep.Title);
         wizard.NextFinishButton.InvokeCommand (Command.Accept);
@@ -90,7 +90,7 @@ public class WizardTests ()
         wizard.Closed += (s, e) => { closedFired = true; };
 
         runstate = Application.Begin (wizard);
-        Application.RunIteration (ref runstate, ref firstIteration);
+        Application.RunIteration (ref runstate, firstIteration);
 
         Assert.Equal (step2.Title, wizard.CurrentStep.Title);
         Assert.Equal (wizard.GetLastStep ().Title, wizard.CurrentStep.Title);
@@ -464,7 +464,7 @@ public class WizardTests ()
         //wizard.LayoutSubviews ();
         var firstIteration = false;
         RunState runstate = Application.Begin (wizard);
-        Application.RunIteration (ref runstate, ref firstIteration);
+        Application.RunIteration (ref runstate, firstIteration);
 
         // TODO: Disabled until Dim.Auto is used in Dialog
         //TestHelpers.AssertDriverContentsWithFrameAre (

+ 8 - 9
UnitTests/View/Adornment/BorderTests.cs

@@ -96,7 +96,7 @@ public class BorderTests (ITestOutputHelper output)
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (width, 5);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         var expected = string.Empty;
 
         switch (width)
@@ -227,10 +227,9 @@ public class BorderTests (ITestOutputHelper output)
         win.Border.Thickness = win.Border.Thickness with { Top = 3 };
 
         RunState rs = Application.Begin (win);
-        var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (width, 4);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, false);
         var expected = string.Empty;
 
         switch (width)
@@ -364,7 +363,7 @@ public class BorderTests (ITestOutputHelper output)
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (width, 4);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         var expected = string.Empty;
 
         switch (width)
@@ -487,7 +486,7 @@ public class BorderTests (ITestOutputHelper output)
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (20, height);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         var expected = string.Empty;
 
         switch (height)
@@ -549,7 +548,7 @@ public class BorderTests (ITestOutputHelper output)
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (width, 3);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         var expected = string.Empty;
 
         switch (width)
@@ -729,7 +728,7 @@ public class BorderTests (ITestOutputHelper output)
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (5, 5);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         var expected = @"
 ╔═══╗
@@ -757,7 +756,7 @@ public class BorderTests (ITestOutputHelper output)
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (10, 4);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         var expected = @"
 ╔════════╗
@@ -780,7 +779,7 @@ public class BorderTests (ITestOutputHelper output)
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (3, 3);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         var expected = @"
 ┌─┐

+ 237 - 76
UnitTests/View/DrawTests.cs

@@ -7,6 +7,139 @@ namespace Terminal.Gui.ViewTests;
 [Trait ("Category", "Output")]
 public class DrawTests (ITestOutputHelper _output)
 {
+    [Fact]
+    public void NeedsDisplay_True_After_Constructor ()
+    {
+        var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
+        Assert.True (view.NeedsDisplay);
+    }
+
+    [Fact]
+    public void NeedsDisplay_False_After_BeginInit ()
+    {
+        var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
+        Assert.True (view.NeedsDisplay);
+
+        view.BeginInit ();
+        Assert.True (view.NeedsDisplay);
+
+        view.NeedsDisplay = false;
+
+        view.BeginInit ();
+        Assert.False (view.NeedsDisplay);
+    }
+
+    [Fact]
+    public void NeedsDisplay_False_After_EndInit ()
+    {
+        var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
+        Assert.True (view.NeedsDisplay);
+
+        view.BeginInit ();
+        Assert.True (view.NeedsDisplay);
+
+        view.EndInit ();
+        Assert.True (view.NeedsDisplay);
+
+        view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
+        view.BeginInit ();
+        view.NeedsDisplay = false;
+        view.EndInit ();
+        Assert.False (view.NeedsDisplay);
+    }
+
+    [Fact]
+    public void NeedsDisplay_False_After_SetRelativeLayout ()
+    {
+        var view = new View { Width = 2, Height = 2 };
+        Assert.True (view.NeedsDisplay);
+
+        view.BeginInit ();
+        Assert.True (view.NeedsDisplay);
+
+        view.EndInit ();
+        Assert.True (view.NeedsDisplay);
+
+        view.SetRelativeLayout (Application.Screen.Size);
+        Assert.True (view.NeedsDisplay);
+
+        view.NeedsDisplay = false;
+        view.SetRelativeLayout (new (10, 10));
+        Assert.False (view.NeedsDisplay);
+
+        view = new View { Width = Dim.Percent(50), Height = Dim.Percent(50) };
+        View superView = new ()
+        {
+            Id = "superView",
+            Width = Dim.Fill(),
+            Height = Dim.Fill()
+        };
+        superView.Add (view);
+
+        superView.BeginInit ();
+        Assert.True (view.NeedsDisplay);
+        Assert.True (superView.NeedsDisplay);
+
+        superView.EndInit ();
+        Assert.True (view.NeedsDisplay);
+        Assert.True (superView.NeedsDisplay);
+
+        superView.SetRelativeLayout (Application.Screen.Size);
+        Assert.True (view.NeedsDisplay);
+        Assert.True (superView.NeedsDisplay);
+
+        superView.NeedsDisplay = false;
+        superView.SetRelativeLayout (new (10, 10));
+        Assert.False (superView.NeedsDisplay);
+        Assert.False (view.NeedsDisplay);
+
+        view.SetRelativeLayout (new (11, 11));
+        Assert.True (superView.NeedsDisplay);
+        Assert.True (view.NeedsDisplay);
+
+    }
+
+    [Fact]
+    public void NeedsDisplay_True_After_LayoutSubviews ()
+    {
+        var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
+        Assert.True (view.NeedsDisplay);
+
+        view.BeginInit ();
+        Assert.True (view.NeedsDisplay);
+
+        view.EndInit ();
+        Assert.True (view.NeedsDisplay);
+
+        view.SetRelativeLayout (Application.Screen.Size);
+        Assert.True (view.NeedsDisplay);
+
+        view.LayoutSubviews ();
+        Assert.True (view.NeedsDisplay);
+    }
+
+    [Fact]
+    public void NeedsDisplay_False_After_Draw ()
+    {
+        var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
+        Assert.True (view.NeedsDisplay);
+
+        view.BeginInit ();
+        Assert.True (view.NeedsDisplay);
+
+        view.EndInit ();
+        Assert.True (view.NeedsDisplay);
+
+        view.SetRelativeLayout (Application.Screen.Size);
+        Assert.True (view.NeedsDisplay);
+
+        view.LayoutSubviews ();
+        Assert.True (view.NeedsDisplay);
+
+        view.Draw ();
+        Assert.False (view.NeedsDisplay);
+    }
+
     [Fact]
     [SetupFakeDriver]
     public void Move_Is_Constrained_To_Viewport ()
@@ -17,18 +150,18 @@ public class DrawTests (ITestOutputHelper _output)
             Y = 1,
             Width = 3, Height = 3
         };
-        view.Margin.Thickness = new Thickness (1);
+        view.Margin.Thickness = new (1);
 
         // Only valid location w/in Viewport is 0, 0 (view) - 2, 2 (screen)
 
         view.Move (0, 0);
-        Assert.Equal (new Point (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
+        Assert.Equal (new (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
 
         view.Move (-1, -1);
-        Assert.Equal (new Point (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
+        Assert.Equal (new (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
 
         view.Move (1, 1);
-        Assert.Equal (new Point (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
+        Assert.Equal (new (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
     }
 
     [Fact]
@@ -41,7 +174,7 @@ public class DrawTests (ITestOutputHelper _output)
             Y = 1,
             Width = 3, Height = 3
         };
-        view.Margin.Thickness = new Thickness (1);
+        view.Margin.Thickness = new (1);
         View.Diagnostics = ViewDiagnosticFlags.Padding;
         view.BeginInit ();
         view.EndInit ();
@@ -84,6 +217,7 @@ public class DrawTests (ITestOutputHelper _output)
         superView.LayoutSubviews ();
 
         superView.Draw ();
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -93,6 +227,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         Rectangle toFill = new (x, y, width, height);
         view.FillRect (toFill);
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -103,6 +238,7 @@ public class DrawTests (ITestOutputHelper _output)
         // Now try to clear beyond Viewport (invalid; clipping should prevent)
         superView.SetNeedsDisplay ();
         superView.Draw ();
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -111,6 +247,7 @@ public class DrawTests (ITestOutputHelper _output)
                                                       _output);
         toFill = new (-width, -height, width, height);
         view.FillRect (toFill);
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -121,6 +258,7 @@ public class DrawTests (ITestOutputHelper _output)
         // Now try to clear beyond Viewport (valid)
         superView.SetNeedsDisplay ();
         superView.Draw ();
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -129,6 +267,7 @@ public class DrawTests (ITestOutputHelper _output)
                                                       _output);
         toFill = new (-1, -1, width + 1, height + 1);
         view.FillRect (toFill);
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -139,6 +278,7 @@ public class DrawTests (ITestOutputHelper _output)
         // Now clear too much size
         superView.SetNeedsDisplay ();
         superView.Draw ();
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -147,6 +287,7 @@ public class DrawTests (ITestOutputHelper _output)
                                                       _output);
         toFill = new (0, 0, width * 2, height * 2);
         view.FillRect (toFill);
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -174,6 +315,7 @@ public class DrawTests (ITestOutputHelper _output)
         superView.LayoutSubviews ();
 
         superView.Draw ();
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -182,6 +324,7 @@ public class DrawTests (ITestOutputHelper _output)
                                                       _output);
 
         view.Clear ();
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -210,6 +353,7 @@ public class DrawTests (ITestOutputHelper _output)
         superView.LayoutSubviews ();
 
         superView.Draw ();
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -218,6 +362,7 @@ public class DrawTests (ITestOutputHelper _output)
                                                       _output);
 
         view.Clear ();
+
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
  ┌─┐
@@ -226,7 +371,6 @@ public class DrawTests (ITestOutputHelper _output)
                                                       _output);
     }
 
-
     [Fact]
     [AutoInitShutdown]
     [Trait ("Category", "Unicode")]
@@ -243,7 +387,7 @@ public class DrawTests (ITestOutputHelper _output)
         Assert.Equal (2, r.GetColumns ());
 
         var win = new Window { Title = us };
-        var view = new View { Text = r.ToString (), Height = Dim.Fill (), Width = Dim.Fill ()};
+        var view = new View { Text = r.ToString (), Height = Dim.Fill (), Width = Dim.Fill () };
         var tf = new TextField { Text = us, Y = 1, Width = 3 };
         win.Add (view, tf);
         Toplevel top = new ();
@@ -317,7 +461,7 @@ public class DrawTests (ITestOutputHelper _output)
                                       """;
 
         Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expectedOutput, _output);
-        Assert.Equal (new Rectangle (0, 0, 30, 10), pos);
+        Assert.Equal (new (0, 0, 30, 10), pos);
 
         Application.End (rsDiag);
         dg.Dispose ();
@@ -352,12 +496,13 @@ public class DrawTests (ITestOutputHelper _output)
         Toplevel top = new ();
         top.Add (viewRight, viewBottom);
 
-        Application.Begin (top);
+        var rs = Application.Begin (top);
         ((FakeDriver)Application.Driver!).SetBufferSize (7, 7);
+        Application.RunIteration (ref rs);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                         Test
                                                             
                                                             
@@ -391,13 +536,25 @@ public class DrawTests (ITestOutputHelper _output)
     public void Draw_Minimum_Full_Border_With_Empty_Viewport ()
     {
         var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
+        Assert.True (view.NeedsDisplay);
+
         view.BeginInit ();
+        Assert.True (view.NeedsDisplay);
+
         view.EndInit ();
+        Assert.True (view.NeedsDisplay);
+
         view.SetRelativeLayout (Application.Screen.Size);
+        Assert.True (view.NeedsDisplay);
+
+        view.LayoutSubviews ();
+        Assert.True (view.NeedsDisplay);
 
         Assert.Equal (new (0, 0, 2, 2), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
 
+        Assert.True (view.NeedsDisplay);
+
         view.Draw ();
 
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -415,7 +572,7 @@ public class DrawTests (ITestOutputHelper _output)
     public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Bottom ()
     {
         var view = new View { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
-        view.Border.Thickness = new Thickness (1, 1, 1, 0);
+        view.Border.Thickness = new (1, 1, 1, 0);
         view.BeginInit ();
         view.EndInit ();
         view.SetRelativeLayout (Application.Screen.Size);
@@ -433,7 +590,7 @@ public class DrawTests (ITestOutputHelper _output)
     public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Left ()
     {
         var view = new View { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
-        view.Border.Thickness = new Thickness (0, 1, 1, 1);
+        view.Border.Thickness = new (0, 1, 1, 1);
         view.BeginInit ();
         view.EndInit ();
         view.SetRelativeLayout (Application.Screen.Size);
@@ -458,7 +615,7 @@ public class DrawTests (ITestOutputHelper _output)
     public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Right ()
     {
         var view = new View { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
-        view.Border.Thickness = new Thickness (1, 1, 0, 1);
+        view.Border.Thickness = new (1, 1, 0, 1);
         view.BeginInit ();
         view.EndInit ();
         view.SetRelativeLayout (Application.Screen.Size);
@@ -483,7 +640,7 @@ public class DrawTests (ITestOutputHelper _output)
     public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Top ()
     {
         var view = new View { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
-        view.Border.Thickness = new Thickness (1, 0, 1, 1);
+        view.Border.Thickness = new (1, 0, 1, 1);
 
         view.BeginInit ();
         view.EndInit ();
@@ -494,7 +651,8 @@ public class DrawTests (ITestOutputHelper _output)
 
         view.Draw ();
 
-        TestHelpers.AssertDriverContentsWithFrameAre ("││",
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      "││",
                                                       _output
                                                      );
     }
@@ -510,40 +668,40 @@ public class DrawTests (ITestOutputHelper _output)
             Width = 1,
             Height = 7,
             Text = """
-            s
-            u
-            b
-            V
-            i
-            e
-            w
-            """
+                   s
+                   u
+                   b
+                   V
+                   i
+                   e
+                   w
+                   """
         };
 
         var view = new View
         {
             Id = "view", Width = 2, Height = 20, Text = """
-            0
-            1
-            2
-            3
-            4
-            5
-            6
-            7
-            8
-            9
-            0
-            1
-            2
-            3
-            4
-            5
-            6
-            7
-            8
-            9
-            """
+                                                        0
+                                                        1
+                                                        2
+                                                        3
+                                                        4
+                                                        5
+                                                        6
+                                                        7
+                                                        8
+                                                        9
+                                                        0
+                                                        1
+                                                        2
+                                                        3
+                                                        4
+                                                        5
+                                                        6
+                                                        7
+                                                        8
+                                                        9
+                                                        """
         };
         view.Add (subView);
         var content = new View { Id = "content", Width = 20, Height = 20 };
@@ -560,12 +718,12 @@ public class DrawTests (ITestOutputHelper _output)
         container.Add (content);
         Toplevel top = new ();
         top.Add (container);
-        Application.Driver!.Clip = container.Frame;
-        Application.Begin (top);
+        var rs = Application.Begin (top);
 
+        top.Draw ();
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        0s
                                                        1u
                                                        2b
@@ -580,7 +738,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        s
                                                        u
                                                        b
@@ -600,7 +758,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        1u
                                                        2b
                                                        3V
@@ -615,7 +773,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        6w
                                                        7 
                                                        8 
@@ -630,7 +788,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        9
                                                       """,
                                                       _output
@@ -682,9 +840,10 @@ public class DrawTests (ITestOutputHelper _output)
         top.LayoutComplete += Top_LayoutComplete;
         Application.Begin (top);
 
+        Application.Refresh ();
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        01234
                                                        subVi
                                                       """,
@@ -696,7 +855,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        12345
                                                        ubVie
                                                       """,
@@ -708,7 +867,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        ubVie
                                                       """,
                                                       _output
@@ -766,12 +925,12 @@ public class DrawTests (ITestOutputHelper _output)
         container.Add (content);
         Toplevel top = new ();
         top.Add (container);
-        Application.Driver!.Clip = container.Frame;
         Application.Begin (top);
 
+        Application.Refresh ();
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        0s
                                                        1u
                                                        2b
@@ -786,7 +945,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        s
                                                        u
                                                        b
@@ -806,7 +965,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        1u
                                                        2b
                                                        3V
@@ -821,7 +980,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        6w
                                                        7 
                                                        8 
@@ -836,7 +995,7 @@ public class DrawTests (ITestOutputHelper _output)
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       """
-
+                                                      
                                                        9
                                                       """,
                                                       _output
@@ -892,15 +1051,16 @@ public class DrawTests (ITestOutputHelper _output)
 
         var expected = """
 
-            ┌┤𝔹├─────┐
-            │𝔹       │
-            │𝔹       │
-            └────────┘
-            """;
+                       ┌┤𝔹├─────┐
+                       │𝔹       │
+                       │𝔹       │
+                       └────────┘
+                       """;
         TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
 
         TestHelpers.AssertDriverContentsAre (expected, _output);
         top.Dispose ();
+
         // This test has nothing to do with color - removing as it is not relevant and fragile
     }
 
@@ -916,15 +1076,16 @@ public class DrawTests (ITestOutputHelper _output)
         // Visible content is (1, 1, 10, 10)
         // Expected clip is (1, 1, 10, 10) - same as visible content
         Rectangle expectedClip = new (1, 1, 10, 10);
+
         // Arrange
-        var view = new View ()
+        var view = new View
         {
             Width = Dim.Fill (),
             Height = Dim.Fill (),
             ViewportSettings = ViewportSettings.ClipContentOnly
         };
         view.SetContentSize (new Size (10, 10));
-        view.Border.Thickness = new Thickness (1);
+        view.Border.Thickness = new (1);
         view.BeginInit ();
         view.EndInit ();
         Assert.Equal (view.Frame, Application.Driver?.Clip);
@@ -949,14 +1110,15 @@ public class DrawTests (ITestOutputHelper _output)
         // Visible content is (1, 1, 10, 10)
         // Expected clip is (1, 1, 23, 23) - same as Viewport
         Rectangle expectedClip = new (1, 1, 23, 23);
+
         // Arrange
-        var view = new View ()
+        var view = new View
         {
             Width = Dim.Fill (),
-            Height = Dim.Fill (),
+            Height = Dim.Fill ()
         };
         view.SetContentSize (new Size (10, 10));
-        view.Border.Thickness = new Thickness (1);
+        view.Border.Thickness = new (1);
         view.BeginInit ();
         view.EndInit ();
         Assert.Equal (view.Frame, Application.Driver?.Clip);
@@ -970,7 +1132,6 @@ public class DrawTests (ITestOutputHelper _output)
         view.Dispose ();
     }
 
-
     [Fact]
     [TestRespondersDisposed]
     public void Draw_Throws_IndexOutOfRangeException_With_Negative_Bounds ()
@@ -983,11 +1144,11 @@ public class DrawTests (ITestOutputHelper _output)
         top.Add (view);
 
         Application.Iteration += (s, a) =>
-        {
-            Assert.Equal (-2, view.X);
+                                 {
+                                     Assert.Equal (-2, view.X);
 
-            Application.RequestStop ();
-        };
+                                     Application.RequestStop ();
+                                 };
 
         try
         {
@@ -1000,8 +1161,8 @@ public class DrawTests (ITestOutputHelper _output)
         }
 
         top.Dispose ();
+
         // Shutdown must be called to safely clean up Application if Init has been called
         Application.Shutdown ();
     }
-
 }

+ 0 - 236
UnitTests/View/Layout/AbsoluteLayoutTests.cs

@@ -1,236 +0,0 @@
-using Xunit.Abstractions;
-
-namespace Terminal.Gui.LayoutTests;
-
-public class AbsoluteLayoutTests (ITestOutputHelper output)
-{
-    private readonly ITestOutputHelper _output = output;
-
-    [Fact]
-    [TestRespondersDisposed]
-    public void AbsoluteLayout_Change_Height_or_Width_Absolute ()
-    {
-        var frame = new Rectangle (1, 2, 3, 4);
-        var newFrame = new Rectangle (1, 2, 30, 40);
-
-        var v = new View { Frame = frame };
-        v.Height = newFrame.Height;
-        v.Width = newFrame.Width;
-        Assert.Equal (newFrame, v.Frame);
-
-        Assert.Equal (
-                      new (0, 0, newFrame.Width, newFrame.Height),
-                      v.Viewport
-                     ); // With Absolute Viewport *is* deterministic before Layout
-        Assert.Equal (Pos.Absolute (1), v.X);
-        Assert.Equal (Pos.Absolute (2), v.Y);
-        Assert.Equal ($"Absolute({newFrame.Height})", v.Height.ToString ());
-        Assert.Equal ($"Absolute({newFrame.Width})", v.Width.ToString ());
-        v.Dispose ();
-    }
-
-    [Fact]
-    [TestRespondersDisposed]
-    public void AbsoluteLayout_Change_Height_or_Width_MakesComputed ()
-    {
-        var v = new View { Frame = Rectangle.Empty };
-        v.Height = Dim.Fill ();
-        v.Width = Dim.Fill ();
-        v.Dispose ();
-    }
-
-    [Fact]
-    [TestRespondersDisposed]
-    public void AbsoluteLayout_Change_X_or_Y_Absolute ()
-    {
-        var frame = new Rectangle (1, 2, 3, 4);
-        var newFrame = new Rectangle (10, 20, 3, 4);
-
-        var v = new View { Frame = frame };
-        v.X = newFrame.X;
-        v.Y = newFrame.Y;
-        Assert.Equal (newFrame, v.Frame);
-
-        Assert.Equal (
-                      new (0, 0, newFrame.Width, newFrame.Height),
-                      v.Viewport
-                     ); // With Absolute Viewport *is* deterministic before Layout
-        Assert.Equal ($"Absolute({newFrame.X})", v.X.ToString ());
-        Assert.Equal ($"Absolute({newFrame.Y})", v.Y.ToString ());
-        Assert.Equal (Dim.Absolute (3), v.Width);
-        Assert.Equal (Dim.Absolute (4), v.Height);
-        v.Dispose ();
-    }
-
-    [Fact]
-    [TestRespondersDisposed]
-    public void AbsoluteLayout_Change_X_or_Y_MakesComputed ()
-    {
-        var v = new View { Frame = Rectangle.Empty };
-        v.X = Pos.Center ();
-        v.Y = Pos.Center ();
-        v.Dispose ();
-    }
-
-    [Fact]
-    [TestRespondersDisposed]
-    public void AbsoluteLayout_Change_X_Y_Height_Width_Absolute ()
-    {
-        var v = new View { Frame = Rectangle.Empty };
-        v.X = 1;
-        v.Y = 2;
-        v.Height = 3;
-        v.Width = 4;
-        v.Dispose ();
-
-        v = new() { Frame = Rectangle.Empty };
-        v.X = Pos.Center ();
-        v.Y = Pos.Center ();
-        v.Width = Dim.Fill ();
-        v.Height = Dim.Fill ();
-        v.Dispose ();
-
-        v = new() { Frame = Rectangle.Empty };
-        v.X = Pos.Center ();
-        v.Y = Pos.Center ();
-        v.Width = Dim.Fill ();
-        v.Height = Dim.Fill ();
-
-        v.X = 1;
-        v.Dispose ();
-
-        v = new() { Frame = Rectangle.Empty };
-        v.X = Pos.Center ();
-        v.Y = Pos.Center ();
-        v.Width = Dim.Fill ();
-        v.Height = Dim.Fill ();
-
-        v.Y = 2;
-        v.Dispose ();
-
-        v = new() { Frame = Rectangle.Empty };
-        v.X = Pos.Center ();
-        v.Y = Pos.Center ();
-        v.Width = Dim.Fill ();
-        v.Height = Dim.Fill ();
-
-        v.Width = 3;
-        v.Dispose ();
-
-        v = new() { Frame = Rectangle.Empty };
-        v.X = Pos.Center ();
-        v.Y = Pos.Center ();
-        v.Width = Dim.Fill ();
-        v.Height = Dim.Fill ();
-
-        v.Height = 3;
-        v.Dispose ();
-
-        v = new() { Frame = Rectangle.Empty };
-        v.X = Pos.Center ();
-        v.Y = Pos.Center ();
-        v.Width = Dim.Fill ();
-        v.Height = Dim.Fill ();
-
-        v.X = 1;
-        v.Y = 2;
-        v.Height = 3;
-        v.Width = 4;
-        v.Dispose ();
-    }
-
-    [Fact]
-    [TestRespondersDisposed]
-    public void AbsoluteLayout_Constructor ()
-    {
-        var v = new View ();
-        v.Dispose ();
-
-        var frame = Rectangle.Empty;
-        v = new() { Frame = frame };
-        Assert.Equal (frame, v.Frame);
-
-        Assert.Equal (
-                      new (0, 0, frame.Width, frame.Height),
-                      v.Viewport
-                     ); // With Absolute Viewport *is* deterministic before Layout
-        Assert.Equal (Pos.Absolute (0), v.X);
-        Assert.Equal (Pos.Absolute (0), v.Y);
-        Assert.Equal (Dim.Absolute (0), v.Width);
-        Assert.Equal (Dim.Absolute (0), v.Height);
-        v.Dispose ();
-
-        frame = new (1, 2, 3, 4);
-        v = new() { Frame = frame };
-        Assert.Equal (frame, v.Frame);
-
-        Assert.Equal (
-                      new (0, 0, frame.Width, frame.Height),
-                      v.Viewport
-                     ); // With Absolute Viewport *is* deterministic before Layout
-        Assert.Equal (Pos.Absolute (1), v.X);
-        Assert.Equal (Pos.Absolute (2), v.Y);
-        Assert.Equal (Dim.Absolute (3), v.Width);
-        Assert.Equal (Dim.Absolute (4), v.Height);
-        v.Dispose ();
-
-        v = new() { Frame = frame, Text = "v" };
-        Assert.Equal (frame, v.Frame);
-
-        Assert.Equal (
-                      new (0, 0, frame.Width, frame.Height),
-                      v.Viewport
-                     ); // With Absolute Viewport *is* deterministic before Layout
-        Assert.Equal (Pos.Absolute (1), v.X);
-        Assert.Equal (Pos.Absolute (2), v.Y);
-        Assert.Equal (Dim.Absolute (3), v.Width);
-        Assert.Equal (Dim.Absolute (4), v.Height);
-        v.Dispose ();
-
-        v = new() { X = frame.X, Y = frame.Y, Text = "v" };
-
-        Assert.Equal (new (frame.X, frame.Y, 0, 0), v.Frame);
-        Assert.Equal (new (0, 0, 0, 0), v.Viewport); // With Absolute Viewport *is* deterministic before Layout
-        Assert.Equal (Pos.Absolute (1), v.X);
-        Assert.Equal (Pos.Absolute (2), v.Y);
-        Assert.Equal (Dim.Absolute (0), v.Width);
-        Assert.Equal (Dim.Absolute (0), v.Height);
-        v.Dispose ();
-
-        v = new ();
-        Assert.Equal (new (0, 0, 0, 0), v.Frame);
-        Assert.Equal (new (0, 0, 0, 0), v.Viewport); // With Absolute Viewport *is* deterministic before Layout
-        Assert.Equal (Pos.Absolute (0), v.X);
-        Assert.Equal (Pos.Absolute (0), v.Y);
-        Assert.Equal (Dim.Absolute (0), v.Width);
-        Assert.Equal (Dim.Absolute (0), v.Height);
-        v.Dispose ();
-
-        v = new() { X = frame.X, Y = frame.Y, Width = frame.Width, Height = frame.Height };
-        Assert.Equal (new (frame.X, frame.Y, 3, 4), v.Frame);
-        Assert.Equal (new (0, 0, 3, 4), v.Viewport); // With Absolute Viewport *is* deterministic before Layout
-        Assert.Equal (Pos.Absolute (1), v.X);
-        Assert.Equal (Pos.Absolute (2), v.Y);
-        Assert.Equal (Dim.Absolute (3), v.Width);
-        Assert.Equal (Dim.Absolute (4), v.Height);
-        v.Dispose ();
-    }
-
-    [Fact]
-    [TestRespondersDisposed]
-    public void AbsoluteLayout_LayoutSubviews ()
-    {
-        var superRect = new Rectangle (0, 0, 100, 100);
-        var super = new View { Frame = superRect, Text = "super" };
-        var v1 = new View { X = 0, Y = 0, Width = 10, Height = 10 };
-
-        var v2 = new View { X = 10, Y = 10, Width = 10, Height = 10 };
-
-        super.Add (v1, v2);
-
-        super.LayoutSubviews ();
-        Assert.Equal (new (0, 0, 10, 10), v1.Frame);
-        Assert.Equal (new (10, 10, 10, 10), v2.Frame);
-        super.Dispose ();
-    }
-}

+ 13 - 11
UnitTests/View/Layout/Dim.AutoTests.cs

@@ -4,12 +4,11 @@ using static Terminal.Gui.Dim;
 
 namespace Terminal.Gui.LayoutTests;
 
-[Trait("Category", "Layout")]
+[Trait ("Category", "Layout")]
 public partial class DimAutoTests (ITestOutputHelper output)
 {
     private readonly ITestOutputHelper _output = output;
 
-    [SetupFakeDriver]
     [Fact]
     public void Change_To_Non_Auto_Resets_ContentSize ()
     {
@@ -26,6 +25,7 @@ public partial class DimAutoTests (ITestOutputHelper output)
         // Change text to a longer string
         view.Text = "0123456789";
 
+        view.Layout (new (100, 100));
         Assert.Equal (new (0, 0, 10, 1), view.Frame);
         Assert.Equal (new (10, 1), view.GetContentSize ());
 
@@ -33,6 +33,7 @@ public partial class DimAutoTests (ITestOutputHelper output)
         view.Width = 5;
         view.Height = 1;
 
+        view.SetRelativeLayout (new (100, 100));
         Assert.Equal (new (5, 1), view.GetContentSize ());
     }
 
@@ -216,7 +217,7 @@ public partial class DimAutoTests (ITestOutputHelper output)
                              Style: DimAutoStyle.Auto
                             );
 
-        var c = new DimAuto(
+        var c = new DimAuto (
                              MaximumContentDim: 2,
                              MinimumContentDim: 1,
                              Style: DimAutoStyle.Auto
@@ -966,9 +967,9 @@ public partial class DimAutoTests (ITestOutputHelper output)
     [Fact]
     public void DimAutoStyle_Content_UsesLargestSubview_WhenContentSizeNotSet ()
     {
-        var view = new View ();
-        view.Add (new View { Frame = new (0, 0, 5, 5) }); // Smaller subview
-        view.Add (new View { Frame = new (0, 0, 10, 10) }); // Larger subview
+        var view = new View { Id = "view" };
+        view.Add (new View { Id = "smaller", Frame = new (0, 0, 5, 5) }); // Smaller subview
+        view.Add (new View { Id = "larger", Frame = new (0, 0, 10, 10) }); // Larger subview
 
         Dim dim = Auto (DimAutoStyle.Content);
 
@@ -990,6 +991,8 @@ public partial class DimAutoTests (ITestOutputHelper output)
     [Fact]
     public void DimAutoStyle_Content_Pos_AnchorEnd_Locates_Correctly ()
     {
+        Application.SetScreenSize (new Size (10, 10));
+
         DimAutoTestView view = new (Auto (DimAutoStyle.Content), Auto (DimAutoStyle.Content));
 
         View subView = new ()
@@ -999,24 +1002,23 @@ public partial class DimAutoTests (ITestOutputHelper output)
         };
         view.Add (subView);
 
-        view.SetRelativeLayout (new (10, 10));
+        view.Layout ();
         Assert.Equal (new (5, 1), view.Frame.Size);
         Assert.Equal (new (0, 0), view.Frame.Location);
 
         view.X = 0;
-
         view.Y = Pos.AnchorEnd (1);
-        view.SetRelativeLayout (new (10, 10));
+        view.Layout ();
         Assert.Equal (new (5, 1), view.Frame.Size);
         Assert.Equal (new (0, 9), view.Frame.Location);
 
         view.Y = Pos.AnchorEnd ();
-        view.SetRelativeLayout (new (10, 10));
+        view.Layout ();
         Assert.Equal (new (5, 1), view.Frame.Size);
         Assert.Equal (new (0, 9), view.Frame.Location);
 
         view.Y = Pos.AnchorEnd () - 1;
-        view.SetRelativeLayout (new (10, 10));
+        view.Layout ();
         Assert.Equal (new (5, 1), view.Frame.Size);
         Assert.Equal (new (0, 8), view.Frame.Location);
     }

+ 411 - 40
UnitTests/View/Layout/LayoutTests.cs

@@ -6,6 +6,56 @@ public class LayoutTests (ITestOutputHelper output)
 {
     private readonly ITestOutputHelper _output = output;
 
+
+    [Fact]
+    [AutoInitShutdown]
+    public void Screen_Size_Change_Causes_Layout ()
+    {
+        Application.Top = new ();
+
+        var view = new View
+        {
+            X = 3,
+            Y = 2,
+            Width = 10,
+            Height = 1,
+            Text = "0123456789"
+        };
+        Application.Top.Add (view);
+
+        var rs = Application.Begin (Application.Top);
+
+        Assert.Equal (new (0, 0, 80, 25), new Rectangle (0, 0, View.Driver.Cols, View.Driver.Rows));
+        Assert.Equal (new (0, 0, View.Driver.Cols, View.Driver.Rows), Application.Top.Frame);
+        Assert.Equal (new (0, 0, 80, 25), Application.Top.Frame);
+
+        ((FakeDriver)Application.Driver!).SetBufferSize (20, 10);
+        Assert.Equal (new (0, 0, View.Driver.Cols, View.Driver.Rows), Application.Top.Frame);
+
+        Assert.Equal (new (0, 0, 20, 10), Application.Top.Frame);
+
+        Application.End (rs);
+
+    }
+
+    [Fact]
+    [TestRespondersDisposed]
+    public void LayoutSubviews ()
+    {
+        var superRect = new Rectangle (0, 0, 100, 100);
+        var super = new View { Frame = superRect, Text = "super" };
+        var v1 = new View { X = 0, Y = 0, Width = 10, Height = 10 };
+
+        var v2 = new View { X = 10, Y = 10, Width = 10, Height = 10 };
+
+        super.Add (v1, v2);
+
+        super.LayoutSubviews ();
+        Assert.Equal (new (0, 0, 10, 10), v1.Frame);
+        Assert.Equal (new (10, 10, 10, 10), v2.Frame);
+        super.Dispose ();
+    }
+
     [Fact]
     public void LayoutSubviews_No_SuperView ()
     {
@@ -35,7 +85,7 @@ public class LayoutTests (ITestOutputHelper output)
     }
 
     [Fact]
-    public void Add_Does_Not_Call_LayoutSubviews ()
+    public void Add_Does_Not_Call_Layout ()
     {
         var superView = new View { Id = "superView" };
         var view = new View { Id = "view" };
@@ -49,10 +99,7 @@ public class LayoutTests (ITestOutputHelper output)
         Assert.False (layoutStartedRaised);
         Assert.False (layoutCompleteRaised);
 
-        superView.Remove(view);
-
-        superView.BeginInit();
-        superView.EndInit ();
+        superView.Remove (view);
 
         superView.Add (view);
 
@@ -61,20 +108,6 @@ public class LayoutTests (ITestOutputHelper output)
 
     }
 
-    [Fact]
-    public void BeginEndInit_Do_Not_Call_LayoutSubviews ()
-    {
-        var superView = new View { Id = "superView" };
-        bool layoutStartedRaised = false;
-        bool layoutCompleteRaised = false;
-        superView.LayoutStarted += (sender, e) => layoutStartedRaised = true;
-        superView.LayoutComplete += (sender, e) => layoutCompleteRaised = true;
-        superView.BeginInit ();
-        superView.EndInit ();
-        Assert.False (layoutStartedRaised);
-        Assert.False (layoutCompleteRaised);
-    }
-
     [Fact]
     public void LayoutSubViews_Raises_LayoutStarted_LayoutComplete ()
     {
@@ -203,38 +236,376 @@ public class LayoutTests (ITestOutputHelper output)
     {
         var superView = new View ();
         var view = new View ();
+
+        var layoutStartedCount = 0;
+        var layoutCompleteCount = 0;
+
+        var borderLayoutStartedCount = 0;
+        var borderLayoutCompleteCount = 0;
+
+        view.LayoutStarted += (sender, e) => layoutStartedCount++;
+        view.LayoutComplete += (sender, e) => layoutCompleteCount++;
+
+        view.Border.LayoutStarted += (sender, e) => borderLayoutStartedCount++;
+        view.Border.LayoutComplete += (sender, e) => borderLayoutCompleteCount++;
+
+
         superView.Add (view);
+        Assert.Equal (0, borderLayoutStartedCount);
+        Assert.Equal (0, borderLayoutCompleteCount);
+        Assert.Equal (0, layoutStartedCount);
+        Assert.Equal (0, layoutCompleteCount);
+
         superView.BeginInit ();
+        Assert.Equal (0, borderLayoutStartedCount);
+        Assert.Equal (0, borderLayoutCompleteCount);
+        Assert.Equal (0, layoutStartedCount);
+        Assert.Equal (0, layoutCompleteCount);
+
         superView.EndInit ();
+        Assert.Equal (1, borderLayoutStartedCount);
+        Assert.Equal (1, borderLayoutCompleteCount);
+        Assert.Equal (1, layoutStartedCount);
+        Assert.Equal (1, layoutCompleteCount);
 
-        var layoutStarted = false;
-        var layoutComplete = false;
+        superView.LayoutSubviews ();
+        Assert.Equal (1, borderLayoutStartedCount);
+        Assert.Equal (1, borderLayoutCompleteCount);
+        Assert.Equal (1, layoutStartedCount);
+        Assert.Equal (1, layoutCompleteCount);
 
-        var borderLayoutStarted = false;
-        var borderLayoutComplete = false;
+        superView.SetLayoutNeeded ();
+        superView.LayoutSubviews ();
+        Assert.Equal (2, borderLayoutStartedCount);
+        Assert.Equal (2, borderLayoutCompleteCount);
+        Assert.Equal (2, layoutStartedCount);
+        Assert.Equal (2, layoutCompleteCount);
+
+        superView.Dispose ();
+    }
 
-        view.LayoutStarted += (sender, e) => layoutStarted = true;
-        view.LayoutComplete += (sender, e) => layoutComplete = true;
+    [Fact]
+    public void LayoutSubviews__Honors_IsLayoutNeeded ()
+    {
+        var superView = new View ();
+        var view = new View ();
+
+        var layoutStartedCount = 0;
+        var layoutCompleteCount = 0;
+
+        var borderLayoutStartedCount = 0;
+        var borderLayoutCompleteCount = 0;
+
+        view.LayoutStarted += (sender, e) => layoutStartedCount++;
+        view.LayoutComplete += (sender, e) => layoutCompleteCount++;
+
+        view.Border.LayoutStarted += (sender, e) => borderLayoutStartedCount++;
+        view.Border.LayoutComplete += (sender, e) => borderLayoutCompleteCount++;
+
+
+        superView.Add (view);
 
-        view.Border.LayoutStarted += (sender, e) =>
-                                     {
-                                         Assert.True (layoutStarted);
-                                         borderLayoutStarted = true;
-                                     };
-        view.Border.LayoutComplete += (sender, e) =>
-                                      {
-                                          Assert.True (layoutStarted);
-                                          Assert.False (layoutComplete);
-                                          borderLayoutComplete = true;
-                                      };
+        superView.LayoutSubviews ();
+        Assert.Equal (1, borderLayoutStartedCount);
+        Assert.Equal (1, borderLayoutCompleteCount);
+        Assert.Equal (1, layoutStartedCount);
+        Assert.Equal (1, layoutCompleteCount);
 
         superView.LayoutSubviews ();
+        Assert.Equal (1, borderLayoutStartedCount);
+        Assert.Equal (1, borderLayoutCompleteCount);
+        Assert.Equal (1, layoutStartedCount);
+        Assert.Equal (1, layoutCompleteCount);
 
-        Assert.True (borderLayoutStarted);
-        Assert.True (borderLayoutComplete);
+        superView.SetLayoutNeeded ();
+        superView.LayoutSubviews ();
+        Assert.Equal (2, borderLayoutStartedCount);
+        Assert.Equal (2, borderLayoutCompleteCount);
+        Assert.Equal (2, layoutStartedCount);
+        Assert.Equal (2, layoutCompleteCount);
 
-        Assert.True (layoutStarted);
-        Assert.True (layoutComplete);
         superView.Dispose ();
     }
+
+    [Fact]
+    public void Set_X_Does_Not_Change_Frame_Until_Layout ()
+    {
+        var v = new View ();
+        Assert.Equal (0, v.Frame.X);
+
+        v.Layout ();
+        Assert.Equal (0, v.Frame.X);
+
+        v.X = 1;
+        Assert.Equal (0, v.Frame.X);
+
+        v.Layout ();
+        Assert.Equal (1, v.Frame.X);
+
+        v.X = 2;
+        Assert.Equal (1, v.Frame.X);
+
+        v.Layout ();
+        Assert.Equal (2, v.Frame.X);
+    }
+
+
+    [Fact]
+    public void Set_Y_Does_Not_Change_Frame_Until_Layout ()
+    {
+        var v = new View ();
+        Assert.Equal (0, v.Frame.Y);
+
+        v.Layout ();
+        Assert.Equal (0, v.Frame.Y);
+
+        v.Y = 1;
+        Assert.Equal (0, v.Frame.Y);
+
+        v.Layout ();
+        Assert.Equal (1, v.Frame.Y);
+
+        v.Y = 2;
+        Assert.Equal (1, v.Frame.Y);
+
+        v.Layout ();
+        Assert.Equal (2, v.Frame.Y);
+    }
+
+
+    [Fact]
+    public void Set_Width_Does_Not_Change_Frame_Until_Layout ()
+    {
+        var v = new View ();
+        Assert.Equal (0, v.Frame.Width);
+
+        v.Layout ();
+        Assert.Equal (0, v.Frame.Width);
+
+        v.Width = 1;
+        Assert.Equal (0, v.Frame.Width);
+
+        v.Layout ();
+        Assert.Equal (1, v.Frame.Width);
+
+        v.Width = 2;
+        Assert.Equal (1, v.Frame.Width);
+
+        v.Layout ();
+        Assert.Equal (2, v.Frame.Width);
+    }
+
+
+    [Fact]
+    public void Set_Height_Does_Not_Change_Frame_Until_Layout ()
+    {
+        var v = new View ();
+        Assert.Equal (0, v.Frame.Height);
+
+        v.Layout ();
+        Assert.Equal (0, v.Frame.Height);
+
+        v.Height = 1;
+        Assert.Equal (0, v.Frame.Height);
+
+        v.Layout ();
+        Assert.Equal (1, v.Frame.Height);
+
+        v.Height = 2;
+        Assert.Equal (1, v.Frame.Height);
+
+        v.Layout ();
+        Assert.Equal (2, v.Frame.Height);
+    }
+
+    [Fact]
+    [TestRespondersDisposed]
+    public void Change_Height_or_Width_MakesComputed ()
+    {
+        var v = new View { Frame = Rectangle.Empty };
+        v.Height = Dim.Fill ();
+        v.Width = Dim.Fill ();
+        v.Dispose ();
+    }
+
+    [Fact]
+    [TestRespondersDisposed]
+    public void Change_X_or_Y_Absolute ()
+    {
+        var frame = new Rectangle (1, 2, 3, 4);
+        var newFrame = new Rectangle (10, 20, 3, 4);
+
+        var v = new View { Frame = frame };
+        v.X = newFrame.X;
+        v.Y = newFrame.Y;
+        v.Layout ();
+        Assert.Equal (newFrame, v.Frame);
+
+        Assert.Equal (
+                      new (0, 0, newFrame.Width, newFrame.Height),
+                      v.Viewport
+                     ); // With Absolute Viewport *is* deterministic before Layout
+        Assert.Equal ($"Absolute({newFrame.X})", v.X.ToString ());
+        Assert.Equal ($"Absolute({newFrame.Y})", v.Y.ToString ());
+        Assert.Equal (Dim.Absolute (3), v.Width);
+        Assert.Equal (Dim.Absolute (4), v.Height);
+        v.Dispose ();
+    }
+
+    [Fact]
+    [TestRespondersDisposed]
+    public void Change_X_or_Y_MakesComputed ()
+    {
+        var v = new View { Frame = Rectangle.Empty };
+        v.X = Pos.Center ();
+        v.Y = Pos.Center ();
+        v.Dispose ();
+    }
+
+    [Fact]
+    [TestRespondersDisposed]
+    public void Change_X_Y_Height_Width_Absolute ()
+    {
+        var v = new View { Frame = Rectangle.Empty };
+        v.X = 1;
+        v.Y = 2;
+        v.Height = 3;
+        v.Width = 4;
+        v.Dispose ();
+
+        v = new () { Frame = Rectangle.Empty };
+        v.X = Pos.Center ();
+        v.Y = Pos.Center ();
+        v.Width = Dim.Fill ();
+        v.Height = Dim.Fill ();
+        v.Dispose ();
+
+        v = new () { Frame = Rectangle.Empty };
+        v.X = Pos.Center ();
+        v.Y = Pos.Center ();
+        v.Width = Dim.Fill ();
+        v.Height = Dim.Fill ();
+
+        v.X = 1;
+        v.Dispose ();
+
+        v = new () { Frame = Rectangle.Empty };
+        v.X = Pos.Center ();
+        v.Y = Pos.Center ();
+        v.Width = Dim.Fill ();
+        v.Height = Dim.Fill ();
+
+        v.Y = 2;
+        v.Dispose ();
+
+        v = new () { Frame = Rectangle.Empty };
+        v.X = Pos.Center ();
+        v.Y = Pos.Center ();
+        v.Width = Dim.Fill ();
+        v.Height = Dim.Fill ();
+
+        v.Width = 3;
+        v.Dispose ();
+
+        v = new () { Frame = Rectangle.Empty };
+        v.X = Pos.Center ();
+        v.Y = Pos.Center ();
+        v.Width = Dim.Fill ();
+        v.Height = Dim.Fill ();
+
+        v.Height = 3;
+        v.Dispose ();
+
+        v = new () { Frame = Rectangle.Empty };
+        v.X = Pos.Center ();
+        v.Y = Pos.Center ();
+        v.Width = Dim.Fill ();
+        v.Height = Dim.Fill ();
+
+        v.X = 1;
+        v.Y = 2;
+        v.Height = 3;
+        v.Width = 4;
+        v.Dispose ();
+    }
+
+    [Fact]
+    public void Constructor ()
+    {
+        var v = new View ();
+        v.Dispose ();
+
+        var frame = Rectangle.Empty;
+        v = new () { Frame = frame };
+        v.Layout ();
+        Assert.Equal (frame, v.Frame);
+
+        Assert.Equal (
+                      new (0, 0, frame.Width, frame.Height),
+                      v.Viewport
+                     ); // With Absolute Viewport *is* deterministic before Layout
+        Assert.Equal (Pos.Absolute (0), v.X);
+        Assert.Equal (Pos.Absolute (0), v.Y);
+        Assert.Equal (Dim.Absolute (0), v.Width);
+        Assert.Equal (Dim.Absolute (0), v.Height);
+        v.Dispose ();
+
+        frame = new (1, 2, 3, 4);
+        v = new () { Frame = frame };
+        v.Layout ();
+        Assert.Equal (frame, v.Frame);
+        Assert.Equal (
+                      new (0, 0, frame.Width, frame.Height),
+                      v.Viewport
+                     ); // With Absolute Viewport *is* deterministic before Layout
+        Assert.Equal (Pos.Absolute (1), v.X);
+        Assert.Equal (Pos.Absolute (2), v.Y);
+        Assert.Equal (Dim.Absolute (3), v.Width);
+        Assert.Equal (Dim.Absolute (4), v.Height);
+        v.Dispose ();
+
+        v = new () { Frame = frame, Text = "v" };
+        v.Layout ();
+        Assert.Equal (frame, v.Frame);
+        Assert.Equal (
+                      new (0, 0, frame.Width, frame.Height),
+                      v.Viewport
+                     ); // With Absolute Viewport *is* deterministic before Layout
+        Assert.Equal (Pos.Absolute (1), v.X);
+        Assert.Equal (Pos.Absolute (2), v.Y);
+        Assert.Equal (Dim.Absolute (3), v.Width);
+        Assert.Equal (Dim.Absolute (4), v.Height);
+        v.Dispose ();
+
+        v = new () { X = frame.X, Y = frame.Y, Text = "v" };
+        v.Layout ();
+        Assert.Equal (new (frame.X, frame.Y, 0, 0), v.Frame);
+        Assert.Equal (new (0, 0, 0, 0), v.Viewport); // With Absolute Viewport *is* deterministic before Layout
+        Assert.Equal (Pos.Absolute (1), v.X);
+        Assert.Equal (Pos.Absolute (2), v.Y);
+        Assert.Equal (Dim.Absolute (0), v.Width);
+        Assert.Equal (Dim.Absolute (0), v.Height);
+        v.Dispose ();
+
+        v = new ();
+        v.Layout ();
+        Assert.Equal (new (0, 0, 0, 0), v.Frame);
+        Assert.Equal (new (0, 0, 0, 0), v.Viewport); // With Absolute Viewport *is* deterministic before Layout
+        Assert.Equal (Pos.Absolute (0), v.X);
+        Assert.Equal (Pos.Absolute (0), v.Y);
+        Assert.Equal (Dim.Absolute (0), v.Width);
+        Assert.Equal (Dim.Absolute (0), v.Height);
+        v.Dispose ();
+
+        v = new () { X = frame.X, Y = frame.Y, Width = frame.Width, Height = frame.Height };
+        v.Layout ();
+        Assert.Equal (new (frame.X, frame.Y, 3, 4), v.Frame);
+        Assert.Equal (new (0, 0, 3, 4), v.Viewport); // With Absolute Viewport *is* deterministic before Layout
+        Assert.Equal (Pos.Absolute (1), v.X);
+        Assert.Equal (Pos.Absolute (2), v.Y);
+        Assert.Equal (Dim.Absolute (3), v.Width);
+        Assert.Equal (Dim.Absolute (4), v.Height);
+        v.Dispose ();
+    }
+
 }

+ 2 - 2
UnitTests/View/Layout/Pos.CenterTests.cs

@@ -94,7 +94,7 @@ public class PosCenterTests (ITestOutputHelper output)
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (20, height);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         var expected = string.Empty;
 
         switch (height)
@@ -241,7 +241,7 @@ public class PosCenterTests (ITestOutputHelper output)
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver!).SetBufferSize (width, 7);
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         var expected = string.Empty;
 
         switch (width)

+ 2 - 1
UnitTests/View/Layout/ToScreenTests.cs

@@ -960,7 +960,7 @@ public class ToScreenTests (ITestOutputHelper output)
         };
         Application.Top.Add (view);
 
-        Application.Begin (Application.Top);
+        var rs = Application.Begin (Application.Top);
 
         Assert.Equal (new (0, 0, 80, 25), new Rectangle (0, 0, View.Driver.Cols, View.Driver.Rows));
         Assert.Equal (new (0, 0, View.Driver.Cols, View.Driver.Rows), Application.Top.Frame);
@@ -970,6 +970,7 @@ public class ToScreenTests (ITestOutputHelper output)
         Assert.Equal (new (0, 0, View.Driver.Cols, View.Driver.Rows), Application.Top.Frame);
         Assert.Equal (new (0, 0, 20, 10), Application.Top.Frame);
 
+
         _ = TestHelpers.AssertDriverContentsWithFrameAre (
                                                           @"
 ┌──────────────────┐

+ 4 - 1
UnitTests/View/Mouse/MouseTests.cs

@@ -103,12 +103,15 @@ public class MouseTests (ITestOutputHelper output) : TestsAllViews
 
         var top = new Toplevel ();
         top.Add (testView);
-        Application.Begin (top);
+
+        var rs = Application.Begin (top);
+        Assert.Equal (4, testView.Frame.X);
 
         Assert.Equal (new Point (4, 4), testView.Frame.Location);
         Application.RaiseMouseEvent (new () { ScreenPosition = new (xy, xy), Flags = MouseFlags.Button1Pressed });
 
         Application.RaiseMouseEvent (new () { ScreenPosition = new (xy + 1, xy + 1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition });
+        Application.RunIteration(ref rs, false);
 
         Assert.Equal (expectedMoved, new Point (5, 5) == testView.Frame.Location);
         top.Dispose ();

+ 1 - 1
UnitTests/View/ViewTests.cs

@@ -1025,7 +1025,7 @@ At 0,0
         view.Visible = false;
 
         var firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"

+ 8 - 8
UnitTests/Views/ContextMenuTests.cs

@@ -151,7 +151,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.RaiseMouseEvent (new MouseEventArgs { ScreenPosition = new (8, 2), Flags = MouseFlags.Button3Clicked });
 
         var firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
@@ -234,7 +234,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.RaiseMouseEvent (new MouseEventArgs { ScreenPosition = new (9, 3), Flags = MouseFlags.Button3Clicked });
 
         var firstIteration = false;
-        Application.RunIteration (ref rsDialog, ref firstIteration);
+        Application.RunIteration (ref rsDialog, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
@@ -290,7 +290,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.RaiseMouseEvent (new MouseEventArgs { ScreenPosition = new (9, 3), Flags = MouseFlags.Button3Clicked });
 
         var firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
@@ -1238,7 +1238,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.RaiseMouseEvent (new MouseEventArgs { ScreenPosition = new (6, 13), Flags = MouseFlags.Button1Clicked });
 
         var firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         Assert.Equal (new Rectangle (5, 11, 10, 5), Application.Top.Subviews [0].Frame);
         Assert.Equal (new Rectangle (5, 11, 15, 6), Application.Top.Subviews [1].Frame);
 
@@ -1256,7 +1256,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.RaiseMouseEvent (new MouseEventArgs { ScreenPosition = new (6, 12), Flags = MouseFlags.Button1Clicked });
 
         firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         Assert.Equal (new Rectangle (5, 11, 10, 5), Application.Top.Subviews [0].Frame);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1330,7 +1330,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.RaiseMouseEvent (new MouseEventArgs { ScreenPosition = new (6, 13), Flags = MouseFlags.ReportMousePosition });
 
         var firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         Assert.Equal (new Rectangle (5, 11, 10, 5), Application.Top.Subviews [0].Frame);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1347,7 +1347,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.RaiseMouseEvent (new MouseEventArgs { ScreenPosition = new (6, 14), Flags = MouseFlags.ReportMousePosition });
 
         firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         Assert.Equal (new Rectangle (5, 11, 10, 5), Application.Top.Subviews [0].Frame);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1365,7 +1365,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.RaiseMouseEvent (new MouseEventArgs { ScreenPosition = new (6, 13), Flags = MouseFlags.ReportMousePosition });
 
         firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         Assert.Equal (new Rectangle (5, 11, 10, 5), Application.Top.Subviews [0].Frame);
 
         TestHelpers.AssertDriverContentsWithFrameAre (

+ 10 - 10
UnitTests/Views/MenuBarTests.cs

@@ -591,7 +591,7 @@ public class MenuBarTests (ITestOutputHelper output)
         Assert.Equal ("File", menu.Menus [0].Title);
         menu.OpenMenu ();
         var firstIteration = false;
-        Application.RunIteration (ref rsDialog, ref firstIteration);
+        Application.RunIteration (ref rsDialog, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
@@ -619,7 +619,7 @@ public class MenuBarTests (ITestOutputHelper output)
 
         // Need to fool MainLoop into thinking it's running
         Application.MainLoop.Running = true;
-        Application.RunIteration (ref rsDialog, ref firstIteration);
+        Application.RunIteration (ref rsDialog, firstIteration);
         Assert.Equal (items [0], menu.Menus [0].Title);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -649,14 +649,14 @@ public class MenuBarTests (ITestOutputHelper output)
             Application.RaiseMouseEvent (new () { ScreenPosition = new (20, 5 + i), Flags = MouseFlags.Button1Clicked });
 
             firstIteration = false;
-            Application.RunIteration (ref rsDialog, ref firstIteration);
+            Application.RunIteration (ref rsDialog, firstIteration);
             Assert.Equal (items [i], menu.Menus [0].Title);
         }
 
         ((FakeDriver)Application.Driver!).SetBufferSize (20, 15);
         menu.OpenMenu ();
         firstIteration = false;
-        Application.RunIteration (ref rsDialog, ref firstIteration);
+        Application.RunIteration (ref rsDialog, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
@@ -792,7 +792,7 @@ public class MenuBarTests (ITestOutputHelper output)
         Assert.Equal ("File", menu.Menus [0].Title);
         menu.OpenMenu ();
         var firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
@@ -815,7 +815,7 @@ public class MenuBarTests (ITestOutputHelper output)
 
         // Need to fool MainLoop into thinking it's running
         Application.MainLoop.Running = true;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         Assert.Equal (items [0], menu.Menus [0].Title);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -834,14 +834,14 @@ public class MenuBarTests (ITestOutputHelper output)
             Application.RaiseMouseEvent (new () { ScreenPosition = new (20, 5 + i), Flags = MouseFlags.Button1Clicked });
 
             firstIteration = false;
-            Application.RunIteration (ref rs, ref firstIteration);
+            Application.RunIteration (ref rs, firstIteration);
             Assert.Equal (items [i], menu.Menus [0].Title);
         }
 
         ((FakeDriver)Application.Driver!).SetBufferSize (20, 15);
         menu.OpenMenu ();
         firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
@@ -2864,7 +2864,7 @@ Edit
 
         menu.OpenMenu ();
         var firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
@@ -2877,7 +2877,7 @@ Edit
 
         ((FakeDriver)Application.Driver!).SetBufferSize (20, 15);
         firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"

+ 1 - 2
UnitTests/Views/TextFieldTests.cs

@@ -1081,8 +1081,7 @@ public class TextFieldTests (ITestOutputHelper output)
         _textField.CursorPosition = 0;
         _textField.NewKeyDownEvent (Key.CursorRight.WithCtrl.WithShift);
 
-        var first = true;
-        Application.RunIteration (ref rs, ref first);
+        Application.RunIteration (ref rs);
         Assert.Equal (4, _textField.CursorPosition);
 
         //                                             TAB to jump between text fields.

+ 1 - 2
UnitTests/Views/TextViewTests.cs

@@ -6364,8 +6364,7 @@ This is the second line.
 
         _textView.NewKeyDownEvent (Key.CursorRight.WithCtrl.WithShift);
 
-        var first = true;
-        Application.RunIteration (ref rs, ref first);
+        Application.RunIteration (ref rs, true);
         Assert.Equal (new Point (4, 0), _textView.CursorPosition);
 
         //                                             TAB to jump between text fields.

+ 2 - 2
UnitTests/Views/ToplevelTests.cs

@@ -885,7 +885,7 @@ public partial class ToplevelTests (ITestOutputHelper output)
         Application.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.Button1Pressed });
 
         var firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         Assert.Equal (window.Border, Application.MouseGrabView);
 
         Assert.Equal (new (0, 0, 10, 3), window.Frame);
@@ -897,7 +897,7 @@ public partial class ToplevelTests (ITestOutputHelper output)
                                   });
 
         firstIteration = false;
-        Application.RunIteration (ref rs, ref firstIteration);
+        Application.RunIteration (ref rs, firstIteration);
         Assert.Equal (window.Border, Application.MouseGrabView);
         Assert.Equal (new (1, 1, 10, 3), window.Frame);