Pārlūkot izejas kodu

Tons of Layout refactoring. LayoutSubviews is now internal.

Tig 10 mēneši atpakaļ
vecāks
revīzija
8c7982f9c0
47 mainītis faili ar 928 papildinājumiem un 701 dzēšanām
  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);