瀏覽代碼

Non-rectangular clip reigion support basically works

Tig 9 月之前
父節點
當前提交
17e3fe8c5f
共有 61 個文件被更改,包括 548 次插入204 次删除
  1. 10 1
      Terminal.Gui/Application/Application.Run.cs
  2. 4 0
      Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
  3. 15 1
      Terminal.Gui/Drawing/Region.cs
  4. 1 1
      Terminal.Gui/Text/Autocomplete/PopupAutocomplete.PopUp.cs
  5. 7 4
      Terminal.Gui/View/Adornment/Adornment.cs
  6. 11 9
      Terminal.Gui/View/Adornment/Border.cs
  7. 2 2
      Terminal.Gui/View/Adornment/Margin.cs
  8. 10 11
      Terminal.Gui/View/Adornment/ShadowView.cs
  9. 62 5
      Terminal.Gui/View/View.Drawing.Clipping.cs
  10. 1 1
      Terminal.Gui/View/View.Drawing.Primitives.cs
  11. 123 62
      Terminal.Gui/View/View.Drawing.cs
  12. 9 1
      Terminal.Gui/View/View.Layout.cs
  13. 2 2
      Terminal.Gui/Views/ColorBar.cs
  14. 3 5
      Terminal.Gui/Views/ColorPicker.16.cs
  15. 1 1
      Terminal.Gui/Views/ColorPicker.cs
  16. 2 2
      Terminal.Gui/Views/ComboBox.cs
  17. 1 1
      Terminal.Gui/Views/DatePicker.cs
  18. 1 1
      Terminal.Gui/Views/FileDialog.cs
  19. 2 2
      Terminal.Gui/Views/GraphView/Annotations.cs
  20. 1 1
      Terminal.Gui/Views/GraphView/GraphView.cs
  21. 4 4
      Terminal.Gui/Views/HexView.cs
  22. 2 2
      Terminal.Gui/Views/Line.cs
  23. 1 1
      Terminal.Gui/Views/LineView.cs
  24. 1 1
      Terminal.Gui/Views/ListView.cs
  25. 1 1
      Terminal.Gui/Views/Menu/Menu.cs
  26. 1 1
      Terminal.Gui/Views/Menu/MenuBar.cs
  27. 1 1
      Terminal.Gui/Views/NumericUpDown.cs
  28. 1 1
      Terminal.Gui/Views/ProgressBar.cs
  29. 1 1
      Terminal.Gui/Views/RadioGroup.cs
  30. 1 1
      Terminal.Gui/Views/ScrollBarView.cs
  31. 1 1
      Terminal.Gui/Views/ScrollView.cs
  32. 1 1
      Terminal.Gui/Views/Slider.cs
  33. 2 2
      Terminal.Gui/Views/SpinnerView/SpinnerView.cs
  34. 10 10
      Terminal.Gui/Views/TabView.cs
  35. 1 1
      Terminal.Gui/Views/TableView/TableView.cs
  36. 1 1
      Terminal.Gui/Views/TextField.cs
  37. 1 1
      Terminal.Gui/Views/TextValidateField.cs
  38. 3 3
      Terminal.Gui/Views/TextView.cs
  39. 4 2
      Terminal.Gui/Views/TileView.cs
  40. 1 1
      Terminal.Gui/Views/TreeView/TreeView.cs
  41. 1 0
      UICatalog/BenchmarkResults.cs
  42. 1 1
      UICatalog/Properties/launchSettings.json
  43. 13 12
      UICatalog/Scenario.cs
  44. 17 10
      UICatalog/Scenarios/Adornments.cs
  45. 151 0
      UICatalog/Scenarios/AdvancedClipping.cs
  46. 2 2
      UICatalog/Scenarios/AllViewsTester.cs
  47. 1 1
      UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs
  48. 2 2
      UICatalog/Scenarios/CharacterMap.cs
  49. 1 1
      UICatalog/Scenarios/Editors/EventLog.cs
  50. 9 9
      UICatalog/Scenarios/Images.cs
  51. 2 2
      UICatalog/Scenarios/LineDrawing.cs
  52. 7 1
      UICatalog/Scenarios/ShadowStyles.cs
  53. 17 4
      UICatalog/Scenarios/SimpleDialog.cs
  54. 1 1
      UICatalog/Scenarios/Snake.cs
  55. 3 3
      UICatalog/Scenarios/TextEffectsScenario.cs
  56. 4 2
      UnitTests/UICatalog/ScenarioTests.cs
  57. 2 2
      UnitTests/View/Draw/DrawTests.cs
  58. 1 1
      UnitTests/View/ViewTests.cs
  59. 6 0
      docfx/docs/drawing.md
  60. 二進制
      local_packages/Terminal.Gui.2.0.0.nupkg
  61. 二進制
      local_packages/Terminal.Gui.2.0.0.snupkg

+ 10 - 1
Terminal.Gui/Application/Application.Run.cs

@@ -537,14 +537,23 @@ public static partial class Application // Run (Begin, Run, End, Stop)
     // TODO: Rename this to DrawRunnables in https://github.com/gui-cs/Terminal.Gui/issues/2491
     private static void DrawToplevels (bool forceDraw)
     {
-        foreach (Toplevel tl in TopLevels.Reverse ())
+        // Reset the clip region to the entire screen
+        if (Driver is { })
+        {
+            Driver.Clip = new (Screen);
+        }
+
+        foreach (Toplevel tl in TopLevels)
         {
             if (forceDraw)
             {
                 tl.SetNeedsDraw ();
             }
 
+            //Region? saved = Driver?.Clip.Clone ();
             tl.Draw ();
+            //Driver.Clip = saved;
+            Driver?.Clip.Exclude (tl.FrameToScreen ());
         }
     }
 

+ 4 - 0
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -392,6 +392,10 @@ public abstract class ConsoleDriver
             {
                 for (int c = rect.X; c < rect.X + rect.Width; c++)
                 {
+                    if (!IsValidLocation (c, r))
+                    {
+                        continue;
+                    }
                     Contents [r, c] = new Cell
                     {
                         Rune = (rune != default ? rune : (Rune)' '),

+ 15 - 1
Terminal.Gui/Drawing/Region.cs

@@ -15,7 +15,7 @@ public class Region : IDisposable
     ///     Initializes a new instance of the <see cref="Region"/> class with the specified rectangle.
     /// </summary>
     /// <param name="rectangle">The initial rectangle for the region.</param>
-    public Region (Rectangle rectangle) { _rectangles = new() { rectangle }; }
+    public Region (Rectangle rectangle) { _rectangles = new () { rectangle }; }
 
     /// <summary>
     ///     Adds the specified rectangle to the region.
@@ -169,6 +169,20 @@ public class Region : IDisposable
     /// <returns>An array of <see cref="Rectangle"/> objects that make up the region.</returns>
     public Rectangle [] GetRegionScans () { return _rectangles.ToArray (); }
 
+    /// <summary>
+    ///     Offsets all rectangles in the region by the specified amounts.
+    /// </summary>
+    /// <param name="offsetX">The amount to offset along the x-axis.</param>
+    /// <param name="offsetY">The amount to offset along the y-axis.</param>
+    public void Offset (int offsetX, int offsetY)
+    {
+        for (int i = 0; i < _rectangles.Count; i++)
+        {
+            var rect = _rectangles [i];
+            _rectangles [i] = new Rectangle (rect.Left + offsetX, rect.Top + offsetY, rect.Width, rect.Height);
+        }
+    }
+
     /// <summary>
     ///     Merges overlapping rectangles into a minimal set of non-overlapping rectangles.
     /// </summary>

+ 1 - 1
Terminal.Gui/Text/Autocomplete/PopupAutocomplete.PopUp.cs

@@ -15,7 +15,7 @@ public abstract partial class PopupAutocomplete
 
         private readonly PopupAutocomplete _autoComplete;
 
-        protected override bool OnDrawingContent (Rectangle viewport)
+        protected override bool OnDrawingContent ()
         {
             if (!_autoComplete.LastPopupPos.HasValue)
             {

+ 7 - 4
Terminal.Gui/View/Adornment/Adornment.cs

@@ -162,7 +162,7 @@ public class Adornment : View, IDesignable
     /// </summary>
     /// <param name="viewport"></param>
     /// <returns><see langword="true"/> to stop further clearing.</returns>
-    protected override bool OnClearingViewport (Rectangle viewport)
+    protected override bool OnClearingViewport ()
     {
         if (Thickness == Thickness.Empty)
         {
@@ -173,18 +173,21 @@ public class Adornment : View, IDesignable
         SetAttribute (normalAttr);
 
         // This just draws/clears the thickness, not the insides.
-        Thickness.Draw (ViewportToScreen (viewport), Diagnostics, ToString ());
+        Thickness.Draw (ViewportToScreen (Viewport), Diagnostics, ToString ());
+
+        //NeedsDraw = true;
 
         return true;
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingText (Rectangle viewport) { return Thickness == Thickness.Empty; }
+    protected override bool OnDrawingText () { return Thickness == Thickness.Empty; }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingSubviews (Rectangle viewport) { return Thickness == Thickness.Empty; }
+    protected override bool OnDrawingSubviews () { return Thickness == Thickness.Empty; }
 
     /// <summary>Does nothing for Adornment</summary>
+    /// <param name="clipRegion"></param>
     /// <returns></returns>
     protected override bool OnRenderingLineCanvas () { return true; }
 

+ 11 - 9
Terminal.Gui/View/Adornment/Border.cs

@@ -107,13 +107,13 @@ public class Border : Adornment
 #endif
         if (View.Diagnostics.HasFlag (ViewDiagnosticFlags.DrawIndicator))
         {
-            _drawIndicator = new SpinnerView ()
+            DrawIndicator = new SpinnerView ()
             {
                 X = 1,
                 Style = new SpinnerStyle.Dots2 (),
                 SpinDelay = 0,
             };
-            Add (_drawIndicator);
+            Add (DrawIndicator);
         }
     }
 
@@ -613,14 +613,14 @@ public class Border : Adornment
     #endregion Mouse Support
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         if (Thickness == Thickness.Empty)
         {
             return true;
         }
 
-        Rectangle screenBounds = ViewportToScreen (viewport);
+        Rectangle screenBounds = ViewportToScreen (Viewport);
 
         // TODO: v2 - this will eventually be two controls: "BorderView" and "Label" (for the title)
 
@@ -914,17 +914,19 @@ public class Border : Adornment
             }
         }
 
-        return true;
+        return true; ;
     }
 
-    private SpinnerView? _drawIndicator = null;
+    public SpinnerView? DrawIndicator { get; private set; } = null;
+
+    /// <param name="clipRegion"></param>
     /// <inheritdoc />
     protected override bool OnRenderingLineCanvas ()
     {
-        if (_drawIndicator is { })
+        if (DrawIndicator is { })
         {
-            _drawIndicator.AdvanceAnimation (false);
-            _drawIndicator.DrawText();
+            //DrawIndicator.AdvanceAnimation (false);
+            //DrawIndicator.DrawText();
         }
 
         RenderLineCanvas ();

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

@@ -68,14 +68,14 @@ public class Margin : Adornment
     }
 
     /// <inheritdoc />
-    protected override bool OnClearingViewport (Rectangle viewport)
+    protected override bool OnClearingViewport ()
     {
         if (Thickness == Thickness.Empty)
         {
             return true;
         }
 
-        Rectangle screen = ViewportToScreen (viewport);
+        Rectangle screen = ViewportToScreen (Viewport);
 
         if (ShadowStyle != ShadowStyle.None)
         {

+ 10 - 11
Terminal.Gui/View/Adornment/ShadowView.cs

@@ -37,25 +37,25 @@ internal class ShadowView : View
     }
 
     /// <inheritdoc />
-    protected override bool OnClearingViewport (Rectangle viewport)
+    protected override bool OnClearingViewport ()
     {
         // Prevent clearing (so we can have transparency)
         return true;
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         switch (ShadowStyle)
         {
             case ShadowStyle.Opaque:
                 if (Orientation == Orientation.Vertical)
                 {
-                    DrawVerticalShadowOpaque (viewport);
+                    DrawVerticalShadowOpaque (Viewport);
                 }
                 else
                 {
-                    DrawHorizontalShadowOpaque (viewport);
+                    DrawHorizontalShadowOpaque (Viewport);
                 }
 
                 break;
@@ -67,11 +67,11 @@ internal class ShadowView : View
 
                 if (Orientation == Orientation.Vertical)
                 {
-                    DrawVerticalShadowTransparent (viewport);
+                    DrawVerticalShadowTransparent (Viewport);
                 }
                 else
                 {
-                    DrawHorizontalShadowTransparent (viewport);
+                    DrawHorizontalShadowTransparent (Viewport);
                 }
 
                 //SetAttribute (prevAttr);
@@ -114,10 +114,9 @@ internal class ShadowView : View
 
     private void DrawHorizontalShadowTransparent (Rectangle viewport)
     {
-        Rectangle screen = ViewportToScreen (viewport);
+        Rectangle screen = ViewportToScreen (Viewport);
 
-        // Fill the rest of the rectangle - note we skip the last since vertical will draw it
-        for (int i = Math.Max(0, screen.X + 1); i < screen.X + screen.Width - 1; i++)
+        for (int i = Math.Max(0, screen.X + 1); i < screen.X + screen.Width; i++)
         {
             Driver?.Move (i, screen.Y);
 
@@ -134,7 +133,7 @@ internal class ShadowView : View
         AddRune (0, 0, Glyphs.ShadowVerticalStart);
 
         // Fill the rest of the rectangle with the glyph
-        for (var i = 1; i < viewport.Height; i++)
+        for (var i = 1; i < viewport.Height - 1; i++)
         {
             AddRune (0, i, Glyphs.ShadowVertical);
         }
@@ -142,7 +141,7 @@ internal class ShadowView : View
 
     private void DrawVerticalShadowTransparent (Rectangle viewport)
     {
-        Rectangle screen = ViewportToScreen (viewport);
+        Rectangle screen = ViewportToScreen (Viewport);
 
         // Fill the rest of the rectangle
         for (int i = Math.Max (0, screen.Y); i < screen.Y + viewport.Height; i++)

+ 62 - 5
Terminal.Gui/View/View.Drawing.Clipping.cs

@@ -3,6 +3,32 @@ namespace Terminal.Gui;
 
 public partial class View
 {
+    internal Region? SetClipToFrame ()
+    {
+        if (Driver is null)
+        {
+            return null;
+        }
+
+        Region previous = Driver.Clip ?? new (Application.Screen);
+
+        Region frameRegion = Driver.Clip!.Clone ();
+        // Translate viewportRegion to screen-relative coords
+        Rectangle screenRect = FrameToScreen ();
+        frameRegion.Intersect (screenRect);
+
+        if (this is Adornment adornment && adornment.Thickness != Thickness.Empty)
+        {
+            // Ensure adornments can't draw outside thier thickness
+            frameRegion.Exclude (adornment.Thickness.GetInside (Frame));
+        }
+
+        Driver.Clip = frameRegion;
+
+        return previous;
+
+    }
+
     /// <summary>Sets the <see cref="ConsoleDriver"/>'s clip region to <see cref="Viewport"/>.</summary>
     /// <remarks>
     ///     <para>
@@ -19,7 +45,7 @@ public partial class View
     ///     The current screen-relative clip region, which can be then re-applied by setting
     ///     <see cref="ConsoleDriver.Clip"/>.
     /// </returns>
-    public Region? SetClip ()
+    public Region? SetClipToViewport ()
     {
         if (Driver is null)
         {
@@ -28,19 +54,50 @@ public partial class View
 
         Region previous = Driver.Clip ?? new (Application.Screen);
 
-        // Clamp the Clip to the entire visible area
-        Rectangle clip = Rectangle.Intersect (ViewportToScreen (Viewport with { Location = Point.Empty }), previous.GetBounds());
+        Region viewportRegion = Driver.Clip!.Clone ();
+
+        Rectangle viewport = ViewportToScreen (new Rectangle (Point.Empty, Viewport.Size));
+        viewportRegion?.Intersect (viewport);
 
         if (ViewportSettings.HasFlag (ViewportSettings.ClipContentOnly))
         {
             // Clamp the Clip to the just content area that is within the viewport
             Rectangle visibleContent = ViewportToScreen (new Rectangle (new (-Viewport.X, -Viewport.Y), GetContentSize ()));
-            clip = Rectangle.Intersect (clip, visibleContent);
+            viewportRegion?.Intersect (visibleContent);
+        }
+
+        if (this is Adornment adornment && adornment.Thickness != Thickness.Empty)
+        {
+            // Ensure adornments can't draw outside their thickness
+            viewportRegion?.Exclude (adornment.Thickness.GetInside (viewport));
         }
 
-        Driver.Clip = new (clip);// !.Complement(clip);
+        Driver.Clip = viewportRegion;
 
         return previous;
     }
 
+    /// <summary>Gets the view-relative clip region.</summary>
+    public Region? GetClip ()
+    {
+        // get just the portion of the application clip that is within this view's Viewport
+        if (Driver is null)
+        {
+            return null;
+        }
+
+        // Get our Viewport in screen coordinates
+        Rectangle screen = ViewportToScreen (Viewport with { Location = Point.Empty });
+
+        // Get the clip region in screen coordinates
+        Region? clip = Driver.Clip;
+        if (clip is null)
+        {
+            return null;
+        }
+        Region? previous = Driver.Clip;
+        clip = clip.Clone ();
+        clip.Intersect (screen);
+        return clip;
+    }
 }

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

@@ -116,7 +116,7 @@ public partial class View
             return;
         }
 
-        Region prevClip = SetClip ();
+        Region prevClip = SetClipToViewport ();
         Rectangle toClear = ViewportToScreen (rect);
         Attribute prev = SetAttribute (new (color ?? GetNormalColor ().Background));
         Driver.FillRect (toClear);

+ 123 - 62
Terminal.Gui/View/View.Drawing.cs

@@ -1,5 +1,5 @@
 #nullable enable
-#define HACK_DRAW_OVERLAPPED
+//#define HACK_DRAW_OVERLAPPED
 using System.ComponentModel;
 using System.Diagnostics;
 
@@ -24,36 +24,71 @@ public partial class View // Drawing APIs
     {
         if (!CanBeVisible (this) || (!NeedsDraw && !SubViewNeedsDraw))
         {
+            if (this is not Adornment)
+            {
+                Driver?.Clip.Exclude (FrameToScreen ());
+            }
+
             return;
         }
 
+        if (Border is { Diagnostics: ViewDiagnosticFlags.DrawIndicator })
+        {
+            if (Border.DrawIndicator is { })
+            {
+                Border.DrawIndicator.AdvanceAnimation (false);
+                Border.DrawIndicator.DrawText ();
+
+            }
+        }
+
+        // Frame/View-relative relative, thus the bounds location should be 0,0
+        //Debug.Assert(clipRegion.GetBounds().X == 0 && clipRegion.GetBounds ().Y == 0);
+
+        Region? saved = SetClipToFrame ();
         DoDrawAdornments ();
         DoSetAttribute ();
-
+        if (saved is { })
+        {
+            Driver!.Clip = saved;
+        }
         // By default, we clip to the viewport preventing drawing outside the viewport
         // We also clip to the content, but if a developer wants to draw outside the viewport, they can do
         // so via settings. SetClip honors the ViewportSettings.DisableVisibleContentClipping flag.
-        Region prevClip = SetClip ();
+        // Get our Viewport in screen coordinates
+
+        saved = SetClipToViewport ();
 
-        DoClearViewport (Viewport);
-        DoDrawText (Viewport);
-        DoDrawContent (Viewport);
+        DoClearViewport ();
+        DoDrawText ();
+        DoDrawContent ();
 
-        DoDrawSubviews (Viewport);
+        DoDrawSubviews ();
 
         // Restore the clip before rendering the line canvas and adornment subviews
         // because they may draw outside the viewport.
-        if (Driver is { })
+        if (saved is { })
         {
-            Driver.Clip = prevClip;
+            Driver!.Clip = saved;
         }
 
+        saved = SetClipToFrame ();
         DoRenderLineCanvas ();
         DoDrawAdornmentSubViews ();
         ClearNeedsDraw ();
 
         // We're done
         DoDrawComplete ();
+        if (saved is { })
+        {
+            Driver!.Clip = saved;
+        }
+
+        if (this is not Adornment)
+        {
+            Driver?.Clip.Exclude (FrameToScreen ());
+        }
+
     }
 
     #region DrawAdornments
@@ -62,34 +97,45 @@ public partial class View // Drawing APIs
     {
         // This causes the Adornment's subviews to be REDRAWN
         // TODO: Figure out how to make this more efficient
-        if (Margin?.Subviews is { })
+        if (Margin?.Subviews is { } && Margin.Thickness != Thickness.Empty)
         {
             foreach (View subview in Margin.Subviews)
             {
                 subview.SetNeedsDraw ();
             }
 
-            Margin?.DoDrawSubviews (Margin.Viewport);
+            Region? saved = Margin?.SetClipToFrame ();
+            Margin?.DoDrawSubviews ();
+            if (saved is { })
+            {
+                Driver!.Clip = saved;
+            }
         }
 
-        if (Border?.Subviews is { })
+        if (Border?.Subviews is { } && Border.Thickness != Thickness.Empty)
         {
             foreach (View subview in Border.Subviews)
             {
                 subview.SetNeedsDraw ();
             }
 
-            Border?.DoDrawSubviews (Border.Viewport);
+            Border?.DoDrawSubviews ();
         }
 
-        if (Padding?.Subviews is { })
+        if (Padding?.Subviews is { } && Padding.Thickness != Thickness.Empty)
         {
             foreach (View subview in Padding.Subviews)
             {
                 subview.SetNeedsDraw ();
             }
 
-            Padding?.DoDrawSubviews (Padding.Viewport);
+            Region? saved = Padding?.SetClipToFrame ();
+            Padding?.DoDrawSubviews ();
+            if (saved is { })
+            {
+                Driver!.Clip = saved;
+            }
+
         }
     }
 
@@ -102,12 +148,6 @@ public partial class View // Drawing APIs
 
         // TODO: add event.
 
-        // Subviews of Adornments count as subviews
-        if (!NeedsDraw && !SubViewNeedsDraw)
-        {
-            return;
-        }
-
         DrawAdornments ();
     }
 
@@ -118,9 +158,20 @@ public partial class View // Drawing APIs
     {
         // Each of these renders lines to either this View's LineCanvas 
         // Those lines will be finally rendered in OnRenderLineCanvas
-        Margin?.Draw ();
-        Border?.Draw ();
-        Padding?.Draw ();
+        if (Margin is { } && Margin.Thickness != Thickness.Empty)
+        {
+            Margin?.Draw ();
+        }
+
+        if (Border is { } && Border.Thickness != Thickness.Empty)
+        {
+            Border?.Draw ();
+        }
+
+        if (Padding is { } && Padding.Thickness != Thickness.Empty)
+        {
+            Padding?.Draw ();
+        }
     }
 
     /// <summary>
@@ -129,6 +180,7 @@ public partial class View // Drawing APIs
     ///     <see cref="LineCanvas"/> of this view's subviews will be rendered. If <see cref="SuperViewRendersLineCanvas"/> is
     ///     false (the default), this method will cause the <see cref="LineCanvas"/> be prepared to be rendered.
     /// </summary>
+    /// <param name="clipRegion"></param>
     /// <returns><see langword="true"/> to stop further drawing of the Adornments.</returns>
     protected virtual bool OnDrawingAdornments () { return false; }
 
@@ -151,11 +203,6 @@ public partial class View // Drawing APIs
             return;
         }
 
-        if (!NeedsDraw && !SubViewNeedsDraw)
-        {
-            return;
-        }
-
         SetNormalAttribute ();
     }
 
@@ -187,11 +234,10 @@ public partial class View // Drawing APIs
     #endregion
     #region ClearViewport
 
-    private void DoClearViewport (Rectangle viewport)
+    private void DoClearViewport ()
     {
-        Debug.Assert (viewport == Viewport);
 
-        if (OnClearingViewport (Viewport))
+        if (OnClearingViewport ())
         {
             return;
         }
@@ -215,9 +261,8 @@ public partial class View // Drawing APIs
     /// <summary>
     ///     Called when the <see cref="Viewport"/> is to be cleared.
     /// </summary>
-    /// <param name="viewport"></param>
     /// <returns><see langword="true"/> to stop further clearing.</returns>
-    protected virtual bool OnClearingViewport (Rectangle viewport) { return false; }
+    protected virtual bool OnClearingViewport () { return false; }
 
     /// <summary>Event invoked when the content area of the View is to be drawn.</summary>
     /// <remarks>
@@ -267,11 +312,10 @@ public partial class View // Drawing APIs
 
     #region DrawText
 
-    private void DoDrawText (Rectangle viewport)
+    private void DoDrawText ()
     {
-        Debug.Assert (viewport == Viewport);
 
-        if (OnDrawingText (Viewport))
+        if (OnDrawingText ())
         {
             return;
         }
@@ -295,9 +339,8 @@ public partial class View // Drawing APIs
     /// <summary>
     ///     Called when the <see cref="Text"/> of the View is to be drawn.
     /// </summary>
-    /// <param name="viewport"></param>
     /// <returns><see langword="true"/> to stop further drawing of  <see cref="Text"/>.</returns>
-    protected virtual bool OnDrawingText (Rectangle viewport) { return false; }
+    protected virtual bool OnDrawingText () { return false; }
 
     /// <summary>Raised when the <see cref="Text"/> of the View is to be drawn.</summary>
     /// <returns>
@@ -335,11 +378,9 @@ public partial class View // Drawing APIs
 
     #region DrawContent
 
-    private void DoDrawContent (Rectangle viewport)
+    private void DoDrawContent ()
     {
-        Debug.Assert (viewport == Viewport);
-
-        if (OnDrawingContent (Viewport))
+        if (OnDrawingContent ())
         {
             return;
         }
@@ -359,7 +400,7 @@ public partial class View // Drawing APIs
     /// <remarks>
     /// </remarks>
     /// <returns><see langword="true"/> to stop further drawing content.</returns>
-    protected virtual bool OnDrawingContent (Rectangle viewport) { return false; }
+    protected virtual bool OnDrawingContent () { return false; }
 
     /// <summary>Raised when  the View's content is to be drawn.</summary>
     /// <remarks>
@@ -375,11 +416,9 @@ public partial class View // Drawing APIs
 
     #region DrawSubviews
 
-    private void DoDrawSubviews (Rectangle viewport)
+    private void DoDrawSubviews ()
     {
-        Debug.Assert (viewport == Viewport);
-
-        if (OnDrawingSubviews (Viewport))
+        if (OnDrawingSubviews ())
         {
             return;
         }
@@ -403,9 +442,8 @@ public partial class View // Drawing APIs
     /// <summary>
     ///     Called when the <see cref="Subviews"/> are to be drawn.
     /// </summary>
-    /// <param name="viewport"></param>
     /// <returns><see langword="true"/> to stop further drawing of <see cref="Subviews"/>.</returns>
-    protected virtual bool OnDrawingSubviews (Rectangle viewport) { return false; }
+    protected virtual bool OnDrawingSubviews () { return false; }
 
     /// <summary>Raised when the <see cref="Subviews"/> are to be drawn.</summary>
     /// <remarks>
@@ -421,7 +459,7 @@ public partial class View // Drawing APIs
     /// </summary>
     public void DrawSubviews ()
     {
-        if (_subviews is null || !SubViewNeedsDraw)
+        if (_subviews is null)
         {
             return;
         }
@@ -430,10 +468,10 @@ public partial class View // Drawing APIs
         IEnumerable<View> subviewsNeedingDraw = _subviews.Where (view => (view.Visible && (view.NeedsDraw || view.SubViewNeedsDraw))
                                                                       || view.Arrangement.HasFlag (ViewArrangement.Overlapped));
 #else
-        IEnumerable<View> subviewsNeedingDraw = _subviews.Where (view => (view.Visible && (view.NeedsDraw || view.SubViewNeedsDraw)));
+        IEnumerable<View> subviewsNeedingDraw = _subviews.Where (view => (view.Visible));
 #endif
 
-        foreach (View view in subviewsNeedingDraw)
+        foreach (View view in subviewsNeedingDraw.Reverse())
         {
 #if HACK_DRAW_OVERLAPPED
             if (view.Arrangement.HasFlag (ViewArrangement.Overlapped))
@@ -443,8 +481,8 @@ public partial class View // Drawing APIs
             }
 #endif
             view.Draw ();
-
         }
+
     }
 
     #endregion DrawSubviews
@@ -466,6 +504,7 @@ public partial class View // Drawing APIs
     /// <summary>
     ///     Called when the <see cref="View.LineCanvas"/> is to be rendered. See <see cref="RenderLineCanvas"/>.
     /// </summary>
+    /// <param name="clipRegion"></param>
     /// <returns><see langword="true"/> to stop further drawing of <see cref="LineCanvas"/>.</returns>
     protected virtual bool OnRenderingLineCanvas () { return false; }
 
@@ -548,7 +587,7 @@ public partial class View // Drawing APIs
     {
         OnDrawComplete ();
 
-        DrawComplete?.Invoke (this, EventArgs.Empty);
+        DrawComplete?.Invoke (this, new (Viewport, Viewport));
 
         // Default implementation does nothing.
     }
@@ -561,7 +600,7 @@ public partial class View // Drawing APIs
     /// <summary>Raised when the View is completed drawing.</summary>
     /// <remarks>
     /// </remarks>
-    public event EventHandler<EventArgs>? DrawComplete;
+    public event EventHandler<DrawEventArgs>? DrawComplete;
 
     #endregion DrawComplete
 
@@ -648,9 +687,20 @@ public partial class View // Drawing APIs
             _needsDrawRect = new (x, y, w, h);
         }
 
-        Margin?.SetNeedsDraw ();
-        Border?.SetNeedsDraw ();
-        Padding?.SetNeedsDraw ();
+        if (Margin is { } && Margin.Thickness != Thickness.Empty)
+        {
+            Margin?.SetNeedsDraw ();
+        }
+
+        if (Border is { } && Border.Thickness != Thickness.Empty)
+        {
+            Border?.SetNeedsDraw ();
+        }
+
+        if (Padding is { } && Padding.Thickness != Thickness.Empty)
+        {
+            Padding?.SetNeedsDraw ();
+        }
 
         SuperView?.SetSubViewNeedsDraw ();
 
@@ -693,10 +743,21 @@ public partial class View // Drawing APIs
         _needsDrawRect = Rectangle.Empty;
         SubViewNeedsDraw = false;
 
-        Margin?.ClearNeedsDraw ();
-        Border?.ClearNeedsDraw ();
-        Padding?.ClearNeedsDraw ();
 
+        if (Margin is { } && Margin.Thickness != Thickness.Empty)
+        {
+            Margin?.ClearNeedsDraw ();
+        }
+
+        if (Border is { } && Border.Thickness != Thickness.Empty)
+        {
+            Border?.ClearNeedsDraw ();
+        }
+
+        if (Padding is { } && Padding.Thickness != Thickness.Empty)
+        {
+            Padding?.ClearNeedsDraw ();
+        }
         foreach (View subview in Subviews)
         {
             subview.ClearNeedsDraw ();

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

@@ -118,7 +118,7 @@ public partial class View // Layout APIs
                 // Now add our Frame location
                 parentScreen.Offset (screen.X, screen.Y);
 
-                return parentScreen;
+                return parentScreen with { Size = Frame.Size };
             }
 
             Point viewportOffset = current.GetViewportOffsetFromFrame ();
@@ -732,6 +732,14 @@ public partial class View // Layout APIs
             SuperView?.SetNeedsLayout ();
         }
 
+        if (SuperView is null)
+        {
+            foreach (var tl in Application.TopLevels)
+            {
+                tl.SetNeedsDraw ();
+            }
+        }
+
         if (this is not Adornment adornment)
         {
             return;

+ 2 - 2
Terminal.Gui/Views/ColorBar.cs

@@ -82,7 +82,7 @@ internal abstract class ColorBar : View, IColorBar
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         var xOffset = 0;
 
@@ -96,7 +96,7 @@ internal abstract class ColorBar : View, IColorBar
             xOffset = Text.EnumerateRunes ().Sum (c => c.GetColumns ());
         }
 
-        _barWidth = viewport.Width - xOffset;
+        _barWidth = Viewport.Width - xOffset;
         _barStartsAt = xOffset;
 
         DrawBar (xOffset, 0, _barWidth);

+ 3 - 5
Terminal.Gui/Views/ColorPicker.16.cs

@@ -131,16 +131,14 @@ public class ColorPicker16 : View
     }
 
     ///<inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
-        base.OnDrawingContent (viewport);
-
         SetAttribute (HasFocus ? ColorScheme.Focus : GetNormalColor ());
         var colorIndex = 0;
 
-        for (var y = 0; y < Math.Max (2, viewport.Height / BoxHeight); y++)
+        for (var y = 0; y < Math.Max (2, Viewport.Height / BoxHeight); y++)
         {
-            for (var x = 0; x < Math.Max (8, viewport.Width / BoxWidth); x++)
+            for (var x = 0; x < Math.Max (8, Viewport.Width / BoxWidth); x++)
             {
                 int foregroundColorIndex = y == 0 ? colorIndex + _cols : colorIndex - _cols;
 

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

@@ -99,7 +99,7 @@ public partial class ColorPicker : View
     public event EventHandler<ColorEventArgs>? ColorChanged;
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         Attribute normal = GetNormalColor ();
         SetAttribute (new (SelectedColor, normal.Background));

+ 2 - 2
Terminal.Gui/Views/ComboBox.cs

@@ -294,7 +294,7 @@ public class ComboBox : View, IDesignable
     public virtual void OnCollapsed () { Collapsed?.Invoke (this, EventArgs.Empty); }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
 
         if (!_autoHide)
@@ -889,7 +889,7 @@ public class ComboBox : View, IDesignable
             return res;
         }
 
-        protected override bool OnDrawingContent (Rectangle viewport)
+        protected override bool OnDrawingContent ()
         {
             Attribute current = ColorScheme?.Focus ?? Attribute.Default;
             SetAttribute (current);

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

@@ -288,7 +288,7 @@ public class DatePicker : View
     }
 
     /// <inheritdoc />
-    protected override bool OnDrawingText (Rectangle viewport) { return true; }
+    protected override bool OnDrawingText () { return true; }
 
     private static string StandardizeDateFormat (string format)
     {

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

@@ -382,7 +382,7 @@ public class FileDialog : Dialog, IDesignable
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         if (!string.IsNullOrWhiteSpace (_feedback))
         {

+ 2 - 2
Terminal.Gui/Views/GraphView/Annotations.cs

@@ -130,12 +130,12 @@ public class LegendAnnotation : View, IAnnotation
     // BUGBUG: Legend annotations are subviews. But for some reason the are rendered directly in OnDrawContent 
     // BUGBUG: instead of just being normal subviews. They get rendered as blank rects and thus we disable subview drawing.
     /// <inheritdoc />
-    protected override bool OnDrawingText (Rectangle viewport) { return true; }
+    protected override bool OnDrawingText () { return true; }
 
     // BUGBUG: Legend annotations are subviews. But for some reason the are rendered directly in OnDrawContent 
     // BUGBUG: instead of just being normal subviews. They get rendered as blank rects and thus we disable subview drawing.
     /// <inheritdoc />
-    protected override bool OnClearingViewport (Rectangle viewport) { return true; }
+    protected override bool OnClearingViewport () { return true; }
 
 
     /// <summary>Draws the Legend and all entries into the area within <see cref="View.Viewport"/></summary>

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

@@ -197,7 +197,7 @@ public class GraphView : View, IDesignable
     }
 
     ///<inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         if (CellSize.X == 0 || CellSize.Y == 0)
         {

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

@@ -421,7 +421,7 @@ public class HexView : View, IDesignable
     }
 
     ///<inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         if (Source is null)
         {
@@ -434,16 +434,16 @@ public class HexView : View, IDesignable
         Move (0, 0);
 
         int nBlocks = BytesPerLine / NUM_BYTES_PER_HEX_COLUMN;
-        var data = new byte [nBlocks * NUM_BYTES_PER_HEX_COLUMN * viewport.Height];
+        var data = new byte [nBlocks * NUM_BYTES_PER_HEX_COLUMN * Viewport.Height];
         Source.Position = _displayStart;
         int n = _source!.Read (data, 0, data.Length);
 
         Attribute selectedAttribute = GetHotNormalColor ();
         Attribute editedAttribute = new Attribute (GetNormalColor ().Foreground.GetHighlightColor (), GetNormalColor ().Background);
         Attribute editingAttribute = new Attribute (GetFocusColor ().Background, GetFocusColor ().Foreground);
-        for (var line = 0; line < viewport.Height; line++)
+        for (var line = 0; line < Viewport.Height; line++)
         {
-            Rectangle lineRect = new (0, line, viewport.Width, 1);
+            Rectangle lineRect = new (0, line, Viewport.Width, 1);
 
             if (!Viewport.Contains (lineRect))
             {

+ 2 - 2
Terminal.Gui/Views/Line.cs

@@ -64,7 +64,7 @@ public class Line : View, IOrientation
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         LineCanvas lc = LineCanvas;
 
@@ -78,7 +78,7 @@ public class Line : View, IOrientation
             lc = adornment.Parent?.LineCanvas;
         }
 
-        Point pos = ViewportToScreen (viewport).Location;
+        Point pos = ViewportToScreen (Viewport).Location;
         int length = Orientation == Orientation.Horizontal ? Frame.Width : Frame.Height;
 
         if (SuperView is {} && SuperViewRendersLineCanvas && Orientation == Orientation.Horizontal)

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

@@ -54,7 +54,7 @@ public class LineView : View
     public Rune? StartingAnchor { get; set; }
 
     /// <summary>Draws the line including any starting/ending anchors</summary>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         Move (0, 0);
         SetAttribute (GetNormalColor ());

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

@@ -769,7 +769,7 @@ public class ListView : View, IDesignable
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         Attribute current = ColorScheme?.Focus ?? Attribute.Default;
         SetAttribute (current);

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

@@ -394,7 +394,7 @@ internal sealed class Menu : View
     }
 
     // By doing this we draw last, over everything else.
-    private void Top_DrawComplete (object? sender, EventArgs e)
+    private void Top_DrawComplete (object? sender, DrawEventArgs e)
     {
         if (!Visible)
         {

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

@@ -297,7 +297,7 @@ public class MenuBar : View, IDesignable
     public event EventHandler<MenuOpeningEventArgs>? MenuOpening;
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         var pos = 0;
 

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

@@ -264,7 +264,7 @@ public class NumericUpDown<T> : View where T : notnull
 
     // Prevent the drawing of Text
     /// <inheritdoc />
-    protected override bool OnDrawingText (Rectangle viewport) { return true; }
+    protected override bool OnDrawingText () { return true; }
 }
 
 /// <summary>

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

@@ -139,7 +139,7 @@ public class ProgressBar : View, IDesignable
     }
 
     ///<inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         SetAttribute (GetHotNormalColor ());
 

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

@@ -360,7 +360,7 @@ public class RadioGroup : View, IDesignable, IOrientation
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         SetAttribute (GetNormalColor ());
 

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

@@ -446,7 +446,7 @@ public class ScrollBarView : View
     public virtual void OnChangedPosition () { ChangedPosition?.Invoke (this, EventArgs.Empty); }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         if (ColorScheme is null || ((!ShowScrollIndicator || Size == 0) && AutoHideScrollBars && Visible))
         {

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

@@ -372,7 +372,7 @@ public class ScrollView : View
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         SetViewsNeedsDraw ();
 

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

@@ -775,7 +775,7 @@ public class Slider<T> : View, IOrientation
     #region Drawing
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         // TODO: make this more surgical to reduce repaint
 

+ 2 - 2
Terminal.Gui/Views/SpinnerView/SpinnerView.cs

@@ -183,10 +183,10 @@ public class SpinnerView : View, IDesignable
     }
 
     /// <inheritdoc />
-    protected override bool OnClearingViewport (Rectangle viewport) { return true; }
+    protected override bool OnClearingViewport () { return true; }
 
     /// <inheritdoc />
-    protected override bool OnDrawingText (Rectangle viewport)
+    protected override bool OnDrawingText ()
     {
         if (Sequence is { Length: > 0 } && _currentIdx < Sequence.Length)
         {

+ 10 - 10
Terminal.Gui/Views/TabView.cs

@@ -58,7 +58,7 @@ public class TabView : View
                     () =>
                     {
                         TabScrollOffset = Tabs.Count - 1;
-                        SelectedTab = Tabs.LastOrDefault()!;
+                        SelectedTab = Tabs.LastOrDefault ()!;
 
                         return true;
                     }
@@ -306,19 +306,19 @@ public class TabView : View
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         if (Tabs.Any ())
         {
-            Region savedClip = SetClip ();
+            // Region savedClip = SetClip ();
             _tabsBar.Draw ();
             _contentView.SetNeedsDraw ();
             _contentView.Draw ();
 
-            if (Driver is { })
-            {
-                Driver.Clip = savedClip;
-            }
+            //if (Driver is { })
+            //{
+            //    Driver.Clip = savedClip;
+            //}
         }
 
         return true;
@@ -656,7 +656,7 @@ public class TabView : View
         }
 
         /// <inheritdoc />
-        protected override bool OnClearingViewport (Rectangle viewport)
+        protected override bool OnClearingViewport ()
         {
             // clear any old text
             ClearViewport ();
@@ -664,7 +664,7 @@ public class TabView : View
             return true;
         }
 
-        protected override bool OnDrawingContent (Rectangle viewport)
+        protected override bool OnDrawingContent ()
         {
             _host._tabLocations = _host.CalculateViewport (Viewport).ToArray ();
 
@@ -675,7 +675,7 @@ public class TabView : View
         }
 
         /// <inheritdoc />
-        protected override bool OnDrawingSubviews (Rectangle viewport)
+        protected override bool OnDrawingSubviews ()
         {
             RenderTabLine ();
 

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

@@ -911,7 +911,7 @@ public class TableView : View, IDesignable
     }
 
     ///<inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         Move (0, 0);
 

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

@@ -931,7 +931,7 @@ public class TextField : View
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         _isDrawing = true;
 

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

@@ -553,7 +553,7 @@ namespace Terminal.Gui
         }
 
         /// <inheritdoc/>
-        protected override bool OnDrawingContent (Rectangle viewport)
+        protected override bool OnDrawingContent ()
         {
             if (_provider is null)
             {

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

@@ -3550,7 +3550,7 @@ public class TextView : View
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         _isDrawing = true;
 
@@ -3616,7 +3616,7 @@ public class TextView : View
                     cols = Math.Max (cols, 1);
                 }
 
-                if (!TextModel.SetCol (ref col, viewport.Right, cols))
+                if (!TextModel.SetCol (ref col, Viewport.Right, cols))
                 {
                     break;
                 }
@@ -3639,7 +3639,7 @@ public class TextView : View
         if (row < bottom)
         {
             SetNormalColor ();
-            ClearRegion (viewport.Left, row, right, bottom);
+            ClearRegion (Viewport.Left, row, right, bottom);
         }
 
         //PositionCursor ();

+ 4 - 2
Terminal.Gui/Views/TileView.cs

@@ -174,9 +174,11 @@ public class TileView : View
     // BUG: v2 fix this hack
     // QUESTION: Does this need to be fixed before events are refactored?
     /// <summary>Overridden so no Frames get drawn</summary>
+    /// <param name="clipRegion"></param>
     /// <returns></returns>
     protected override bool OnDrawingAdornments () { return true; }
 
+    /// <param name="clipRegion"></param>
     /// <inheritdoc/>
     protected override bool OnRenderingLineCanvas () { return false; }
 
@@ -982,9 +984,9 @@ public class TileView : View
         }
 
         /// <inheritdoc/>
-        protected override bool OnClearingViewport (Rectangle viewport) { return true; }
+        protected override bool OnClearingViewport () { return true; }
 
-        protected override bool OnDrawingContent (Rectangle viewport)
+        protected override bool OnDrawingContent ()
         {
             DrawSplitterSymbol ();
 

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

@@ -1146,7 +1146,7 @@ public class TreeView<T> : View, ITreeView where T : class
     public event EventHandler<ObjectActivatedEventArgs<T>> ObjectActivated;
 
     ///<inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         if (roots is null)
         {

+ 1 - 0
UICatalog/BenchmarkResults.cs

@@ -21,6 +21,7 @@ public class BenchmarkResults
     public int UpdatedCount { get; set; } = 0;
     [JsonInclude]
     public int DrawCompleteCount { get; set; } = 0;
+
     [JsonInclude]
     public int LaidOutCount { get; set; } = 0;
 }

+ 1 - 1
UICatalog/Properties/launchSettings.json

@@ -46,7 +46,7 @@
     },
     "Charmap": {
       "commandName": "Project",
-      "commandLineArgs": "\"Character Map\" -b"
+      "commandLineArgs": "Bars -b"
     }
   }
 }

+ 13 - 12
UICatalog/Scenario.cs

@@ -226,18 +226,6 @@ public class Scenario : IDisposable
 
     private void OnApplicationNotifyNewRunState (object? sender, RunStateEventArgs e)
     {
-        // Get a list of all subviews under Application.Top (and their subviews, etc.)
-        // and subscribe to their DrawComplete event
-        void SubscribeAllSubviews (View view)
-        {
-            view.DrawComplete += (s, a) => BenchmarkResults.DrawCompleteCount++;
-            view.SubviewsLaidOut += (s, a) => BenchmarkResults.LaidOutCount++;
-            foreach (View subview in view.Subviews)
-            {
-                SubscribeAllSubviews (subview);
-            }
-        }
-
         SubscribeAllSubviews (Application.Top!);
 
         _currentDemoKey = 0;
@@ -257,6 +245,19 @@ public class Scenario : IDisposable
                                     return true;
                                 });
 
+        return;
+
+        // Get a list of all subviews under Application.Top (and their subviews, etc.)
+        // and subscribe to their DrawComplete event
+        void SubscribeAllSubviews (View view)
+        {
+            view.DrawComplete += (s, a) => BenchmarkResults.DrawCompleteCount++;
+            view.SubviewsLaidOut += (s, a) => BenchmarkResults.LaidOutCount++;
+            foreach (View subview in view.Subviews)
+            {
+                SubscribeAllSubviews (subview);
+            }
+        }
     }
 
     // If the scenario doesn't close within the abort time, this will force it to quit

+ 17 - 10
UICatalog/Scenarios/Adornments.cs

@@ -13,7 +13,8 @@ public class Adornments : Scenario
 
         Window app = new ()
         {
-            Title = GetQuitKeyAndName ()
+            Title = GetQuitKeyAndName (),
+            BorderStyle = LineStyle.None
         };
 
         var editor = new AdornmentsEditor
@@ -79,17 +80,21 @@ public class Adornments : Scenario
             Width = 40,
             Height = Dim.Percent (20),
             Text = "Label\nY=AnchorEnd(),Height=Dim.Percent(10)",
-            ColorScheme = Colors.ColorSchemes ["Error"]
+            ColorScheme = Colors.ColorSchemes ["Dialog"]
         };
 
         window.Margin.Data = "Margin";
-        window.Margin.Thickness = new (3);
+        window.Margin.Text = "Margin Text"; 
+        window.Margin.Thickness = new (0);
 
         window.Border.Data = "Border";
-        window.Border.Thickness = new (3);
+        window.Border.Text = "Border Text";
+        window.Border.Thickness = new (0);
 
         window.Padding.Data = "Padding";
+        window.Padding.Text = "Padding Text line 1\nPadding Text line 3\nPadding Text line 3\nPadding Text line 4\nPadding Text line 5";
         window.Padding.Thickness = new (3);
+        window.Padding.ColorScheme = Colors.ColorSchemes ["Error"];
         window.Padding.CanFocus = true;
 
         var longLabel = new Label
@@ -99,20 +104,21 @@ public class Adornments : Scenario
         longLabel.TextFormatter.WordWrap = true;
         window.Add (tf1, color, button, label, btnButtonInWindow, labelAnchorEnd, longLabel);
 
+        window.ClearingViewport += (s, e) => e.Cancel = true;
         window.Initialized += (s, e) =>
                               {
                                   editor.ViewToEdit = window;
 
                                   editor.ShowViewIdentifier = true;
 
-                                  var labelInPadding = new Label { X = 1, Y = 0, Title = "_Text:" };
+                                  var labelInPadding = new Label { X = 0, Y = 1, Title = "_Text:" };
                                   window.Padding.Add (labelInPadding);
 
                                   var textFieldInPadding = new TextField
                                   {
                                       X = Pos.Right (labelInPadding) + 1,
-                                      Y = Pos.Top (labelInPadding), Width = 15,
-                                      Text = "some text",
+                                      Y = Pos.Top (labelInPadding), Width = 10,
+                                      Text = "text (Y = 1)",
                                       CanFocus = true
                                   };
                                   textFieldInPadding.Accepting += (s, e) => MessageBox.Query (20, 7, "TextField", textFieldInPadding.Text, "Ok");
@@ -121,9 +127,10 @@ public class Adornments : Scenario
                                   var btnButtonInPadding = new Button
                                   {
                                       X = Pos.Center (),
-                                      Y = 0,
-                                      Text = "_Button in Padding",
-                                      CanFocus = true
+                                      Y = 1,
+                                      Text = "_Button in Padding Y = 1",
+                                      CanFocus = true,
+                                      HighlightStyle = HighlightStyle.None,
                                   };
                                   btnButtonInPadding.Accepting += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok");
                                   btnButtonInPadding.BorderStyle = LineStyle.Dashed;

+ 151 - 0
UICatalog/Scenarios/AdvancedClipping.cs

@@ -0,0 +1,151 @@
+using System.Text;
+using System.Timers;
+using Terminal.Gui;
+
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("AdvancedClipping", "AdvancedClipping Tester")]
+[ScenarioCategory ("AdvancedClipping")]
+public class AdvancedClipping : Scenario
+{
+    private int _hotkeyCount;
+
+    public override void Main ()
+    {
+        Application.Init ();
+
+        Window app = new ()
+        {
+            Title = GetQuitKeyAndName (),
+            BorderStyle = LineStyle.None
+        };
+
+        //var arrangementEditor = new ArrangementEditor()
+        //{
+        //    X = Pos.AnchorEnd (),
+        //    Y = 0,
+        //    AutoSelectViewToEdit = true,
+        //};
+        //app.Add (arrangementEditor);
+
+        View tiledView1 = CreateTiledView (1, 0, 0);
+
+
+        ProgressBar tiledProgressBar = new ()
+        {
+            X = 0,
+            Y = 1,
+            Width = Dim.Fill (),
+            Id = "tiledProgressBar",
+           // BorderStyle = LineStyle.Rounded
+        };
+        tiledView1.Add (tiledProgressBar);
+
+        View tiledView2 = CreateTiledView (2, 2, 2);
+
+        app.Add (tiledView1);
+        app.Add (tiledView2);
+
+        //View tiledView3 = CreateTiledView (3, 6, 6);
+        //app.Add (tiledView3);
+
+        //using View overlappedView1 = CreateOverlappedView (1, 30, 2);
+
+        //ProgressBar progressBar = new ()
+        //{
+        //    X = Pos.AnchorEnd (),
+        //    Y = Pos.AnchorEnd (),
+        //    Width = Dim.Fill (),
+        //    Id = "progressBar",
+        //    BorderStyle = LineStyle.Rounded
+        //};
+        //overlappedView1.Add (progressBar);
+
+
+        //View overlappedView2 = CreateOverlappedView (2, 32, 4);
+        //View overlappedView3 = CreateOverlappedView (3, 34, 6);
+
+        //app.Add (overlappedView1);
+        //app.Add (overlappedView2);
+        //app.Add (overlappedView3);
+
+        Timer progressTimer = new Timer (250)
+        {
+            AutoReset = true
+        };
+
+        progressTimer.Elapsed += (s, e) =>
+                                 {
+
+                                     if (tiledProgressBar.Fraction == 1.0)
+                                     {
+                                         tiledProgressBar.Fraction = 0;
+                                     }
+
+                                     Application.Wakeup ();
+
+                                     tiledProgressBar.Fraction += 0.1f;
+                                    // tiledProgressBar.SetNeedsDraw ();
+                                 };
+
+        progressTimer.Start ();
+        Application.Run (app);
+        progressTimer.Stop ();
+        app.Dispose ();
+        Application.Shutdown ();
+
+        return;
+    }
+
+    private View CreateOverlappedView (int id, Pos x, Pos y)
+    {
+        var overlapped = new View
+        {
+            X = x,
+            Y = y,
+            Height = Dim.Auto (minimumContentDim: 4),
+            Width = Dim.Auto (minimumContentDim: 14),
+            Title = $"Overlapped{id} _{GetNextHotKey ()}",
+            ColorScheme = Colors.ColorSchemes ["Toplevel"],
+            Id = $"Overlapped{id}",
+            ShadowStyle = ShadowStyle.Transparent,
+            BorderStyle = LineStyle.Double,
+            CanFocus = true, // Can't drag without this? BUGBUG
+            TabStop = TabBehavior.TabGroup,
+            Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped | ViewArrangement.Resizable
+        };
+        return overlapped;
+    }
+
+    private View CreateTiledView (int id, Pos x, Pos y)
+    {
+        var tiled = new View
+        {
+            X = x,
+            Y = y,
+            Height = Dim.Auto (minimumContentDim: 4),
+            Width = Dim.Auto (minimumContentDim: 14),
+            Title = $"Tiled{id} _{GetNextHotKey ()}",
+            Id = $"Tiled{id}",
+            Text = $"Tiled{id}",
+            BorderStyle = LineStyle.Single,
+            CanFocus = true, // Can't drag without this? BUGBUG
+            TabStop = TabBehavior.TabStop,
+            Arrangement = ViewArrangement.Movable | ViewArrangement.Resizable
+        };
+        tiled.Padding.Thickness = new (1);
+        tiled.Padding.Diagnostics =  ViewDiagnosticFlags.Thickness;
+
+        FrameView fv = new ()
+        {
+            Title = "FrameView",
+            Width = 15,
+            Height = 1,
+        };
+        tiled.Add (fv);
+        
+        return tiled;
+    }
+
+    private char GetNextHotKey () { return (char)('A' + _hotkeyCount++); }
+}

+ 2 - 2
UICatalog/Scenarios/AllViewsTester.cs

@@ -171,7 +171,7 @@ public class AllViewsTester : Scenario
 
         _settingsPane.Add (label, _demoTextView);
 
-        _eventLog = new()
+        _eventLog = new ()
         {
             // X = Pos.Right(_layoutEditor)
         };
@@ -254,7 +254,7 @@ public class AllViewsTester : Scenario
 
         // Instantiate view
         var view = (View)Activator.CreateInstance (type)!;
-        _eventLog!.ViewToLog = _curView;
+        _eventLog!.ViewToLog = view;
 
         if (view is IDesignable designable)
         {

+ 1 - 1
UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs

@@ -179,7 +179,7 @@ public class AnimationScenario : Scenario
         private Rectangle oldSize = Rectangle.Empty;
         public void NextFrame () { currentFrame = (currentFrame + 1) % frameCount; }
 
-        protected override bool OnDrawingContent (Rectangle viewport)
+        protected override bool OnDrawingContent ()
         {
             if (frameCount == 0)
             {

+ 2 - 2
UICatalog/Scenarios/CharacterMap.cs

@@ -681,9 +681,9 @@ internal class CharMap : View, IDesignable
     private static int RowWidth => RowLabelWidth + COLUMN_WIDTH * 16;
     public event EventHandler<ListViewItemEventArgs> Hover;
 
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
-        if (viewport.Height == 0 || viewport.Width == 0)
+        if (Viewport.Height == 0 || Viewport.Width == 0)
         {
             return true;
         }

+ 1 - 1
UICatalog/Scenarios/Editors/EventLog.cs

@@ -22,7 +22,7 @@ public class EventLog : ListView
 
         X = Pos.AnchorEnd ();
         Y = 0;
-        Width = Dim.Func (() => Math.Min (SuperView!.Viewport.Width / 2, MaxLength + GetAdornmentsThickness ().Horizontal));
+        Width = Dim.Func (() => Math.Min (SuperView!.Viewport.Width / 3, MaxLength + GetAdornmentsThickness ().Horizontal));
         Height = Dim.Fill ();
 
         ExpandButton = new ()

+ 9 - 9
UICatalog/Scenarios/Images.cs

@@ -624,7 +624,7 @@ public class Images : Scenario
         public Image<Rgba32> FullResImage;
         private Image<Rgba32> _matchSize;
 
-        protected override bool OnDrawingContent (Rectangle bounds)
+        protected override bool OnDrawingContent ()
         {
             if (FullResImage == null)
             {
@@ -632,15 +632,15 @@ public class Images : Scenario
             }
 
             // if we have not got a cached resized image of this size
-            if (_matchSize == null || bounds.Width != _matchSize.Width || bounds.Height != _matchSize.Height)
+            if (_matchSize == null || Viewport.Width != _matchSize.Width || Viewport.Height != _matchSize.Height)
             {
                 // generate one
-                _matchSize = FullResImage.Clone (x => x.Resize (bounds.Width, bounds.Height));
+                _matchSize = FullResImage.Clone (x => x.Resize (Viewport.Width, Viewport.Height));
             }
 
-            for (var y = 0; y < bounds.Height; y++)
+            for (var y = 0; y < Viewport.Height; y++)
             {
-                for (var x = 0; x < bounds.Width; x++)
+                for (var x = 0; x < Viewport.Width; x++)
                 {
                     Rgba32 rgb = _matchSize [x, y];
 
@@ -682,8 +682,8 @@ public class Images : Scenario
         private (int columns, int rows) CalculateGridSize (Rectangle bounds)
         {
             // Characters are twice as wide as they are tall, so use 2:1 width-to-height ratio
-            int availableWidth = bounds.Width / 2; // Each color block is 2 character wide
-            int availableHeight = bounds.Height;
+            int availableWidth = Viewport.Width / 2; // Each color block is 2 character wide
+            int availableHeight = Viewport.Height;
 
             int numColors = _palette.Count;
 
@@ -701,7 +701,7 @@ public class Images : Scenario
             return (columns, rows);
         }
 
-        protected override bool OnDrawingContent (Rectangle bounds)
+        protected override bool OnDrawingContent ()
         {
             if (_palette == null || _palette.Count == 0)
             {
@@ -709,7 +709,7 @@ public class Images : Scenario
             }
 
             // Calculate the grid size based on the bounds
-            (int columns, int rows) = CalculateGridSize (bounds);
+            (int columns, int rows) = CalculateGridSize (Viewport);
 
             // Draw the colors in the palette
             for (var i = 0; i < _palette.Count && i < columns * rows; i++)

+ 2 - 2
UICatalog/Scenarios/LineDrawing.cs

@@ -268,7 +268,7 @@ public class DrawingArea : View
     public ITool CurrentTool { get; set; } = new DrawLineTool ();
     public DrawingArea () { AddLayer (); }
 
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         foreach (LineCanvas canvas in Layers)
         {
@@ -375,7 +375,7 @@ public class AttributeView : View
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
         Color fg = Value.Foreground;
         Color bg = Value.Background;

+ 7 - 1
UICatalog/Scenarios/ShadowStyles.cs

@@ -40,9 +40,15 @@ public class ShadowStyles : Scenario
             Title = "Shadow Window",
             Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped,
             BorderStyle = LineStyle.Double,
-            ShadowStyle = ShadowStyle.Transparent
+            ShadowStyle = ShadowStyle.Transparent,
         };
 
+        app.DrawingText += (s, e) =>
+                           {
+                               Application.Driver?.FillRect (app.ViewportToScreen (app.Viewport), '*');
+                               e.Cancel = true;
+                           };
+
         var buttonInWin = new Button
         {
             X = Pos.Center (),

+ 17 - 4
UICatalog/Scenarios/SimpleDialog.cs

@@ -15,17 +15,30 @@ public sealed class SimpleDialog : Scenario
         Window appWindow = new ()
         {
             Title = GetQuitKeyAndName (),
+            BorderStyle = LineStyle.None
         };
 
+
+        appWindow.DrawingText += (s, e) =>
+                                 {
+                                     Application.Driver?.FillRect (appWindow.ViewportToScreen (appWindow.Viewport), '*');
+                                     e.Cancel = true;
+                                 };
+
         Dialog dialog = new () { Id = "dialog", Width = 20, Height = 4, Title = "Dialog" };
         dialog.Arrangement |= ViewArrangement.Resizable;
 
         var button = new Button
         {
-            Id = "button", X = Pos.Center (), Y = 1, Text = "_Press me!",
-            WantContinuousButtonPressed = false,
+            Id = "button", 
+            X = 0,
+            Y = 0, 
+            NoDecorations = true,
+            NoPadding = true,
+            Text = "A",
+            //WantContinuousButtonPressed = false,
             HighlightStyle = HighlightStyle.None,
-            ShadowStyle = ShadowStyle.None,
+            ShadowStyle = ShadowStyle.Transparent,
         };
 
         button.Accepting += (s, e) =>
@@ -34,7 +47,7 @@ public sealed class SimpleDialog : Scenario
                                 e.Cancel = true;
                             };
         appWindow.Add (button);
-        
+
         // Run - Start the application.
         Application.Run (appWindow);
         dialog.Dispose ();

+ 1 - 1
UICatalog/Scenarios/Snake.cs

@@ -314,7 +314,7 @@ public class Snake : Scenario
 
         public SnakeState State { get; }
 
-        protected override bool OnDrawingContent (Rectangle viewport)
+        protected override bool OnDrawingContent ()
         {
             SetAttribute (white);
             ClearViewport ();

+ 3 - 3
UICatalog/Scenarios/TextEffectsScenario.cs

@@ -132,9 +132,9 @@ internal class GradientsView : View
     private const int LABEL_HEIGHT = 1;
     private const int GRADIENT_WITH_LABEL_HEIGHT = GRADIENT_HEIGHT + LABEL_HEIGHT + 1; // +1 for spacing
 
-    protected override bool OnDrawingContent (Rectangle viewport)
+    protected override bool OnDrawingContent ()
     {
-        DrawTopLineGradient (viewport);
+        DrawTopLineGradient (Viewport);
 
         var x = 2;
         var y = 3;
@@ -149,7 +149,7 @@ internal class GradientsView : View
 
         foreach ((string label, GradientDirection direction) in gradients)
         {
-            if (x + GRADIENT_WIDTH > viewport.Width)
+            if (x + GRADIENT_WIDTH > Viewport.Width)
             {
                 x = 2; // Reset to left margin
                 y += GRADIENT_WITH_LABEL_HEIGHT; // Move down to next row

+ 4 - 2
UnitTests/UICatalog/ScenarioTests.cs

@@ -137,13 +137,12 @@ public class ScenarioTests : TestsAllViews
         }
     }
 
-
     /// <summary>
     ///     <para>This runs through all Scenarios defined in UI Catalog, calling Init, Setup, and Run and measuring the perf of each.</para>
     /// </summary>
     [Theory]
     [MemberData (nameof (AllScenarioTypes))]
-    public void All_Scenarios_Time (Type scenarioType)
+    public void All_Scenarios_Benchmark (Type scenarioType)
     {
         Assert.Null (_timeoutLock);
         _timeoutLock = new ();
@@ -167,6 +166,7 @@ public class ScenarioTests : TestsAllViews
         int updatedCount = 0;
         int drawCompleteCount = 0;
 
+        int addedCount = 0;
         int laidOutCount = 0;
 
         _output.WriteLine ($"Running Scenario '{scenarioType}'");
@@ -201,6 +201,7 @@ public class ScenarioTests : TestsAllViews
         _output.WriteLine ($"  called Driver.Refresh {refreshedCount} times.");
         _output.WriteLine ($"    which updated the screen {updatedCount} times.");
         _output.WriteLine ($"  called View.Draw {drawCompleteCount} times.");
+        _output.WriteLine ($"  added {addedCount} views.");
         _output.WriteLine ($"  called View.LayoutComplete {laidOutCount} times.");
 
         // Restore the configuration locations
@@ -264,6 +265,7 @@ public class ScenarioTests : TestsAllViews
             {
                 view.DrawComplete += (s, a) => drawCompleteCount++;
                 view.SubviewsLaidOut += (s, a) => laidOutCount++;
+                view.Added += (s, a) => addedCount++;
                 foreach (View subview in view.Subviews)
                 {
                     SubscribeAllSubviews (subview);

+ 2 - 2
UnitTests/View/Draw/DrawTests.cs

@@ -947,7 +947,7 @@ public class DrawTests (ITestOutputHelper _output)
         Assert.Equal (view.Frame, Application.Driver?.Clip?.GetBounds ());
 
         // Act
-        view.SetClip ();
+        view.SetClipToViewport ();
 
         // Assert
         Assert.Equal (expectedClip, Application.Driver?.Clip?.GetBounds());
@@ -981,7 +981,7 @@ public class DrawTests (ITestOutputHelper _output)
         view.Viewport = view.Viewport with { X = 1, Y = 1 };
 
         // Act
-        view.SetClip ();
+        view.SetClipToViewport ();
 
         // Assert
         Assert.Equal (expectedClip, Application.Driver?.Clip.GetBounds ());

+ 1 - 1
UnitTests/View/ViewTests.cs

@@ -1102,7 +1102,7 @@ At 0,0
         public bool IsKeyUp { get; set; }
         public override string Text { get; set; }
 
-        protected override bool OnDrawingContent (Rectangle viewport)
+        protected override bool OnDrawingContent ()
         {
             var idx = 0;
 

+ 6 - 0
docfx/docs/drawing.md

@@ -41,6 +41,12 @@ Each of these steps can be overridden by developers using the standard [Terminal
 
 If a View need to redraw because something changed within it's Content Area it can call @Terminal.Gui.View.SetNeedsDraw. If a View needs to be redrawn because something has changed the size of the Viewport, it can call @Terminal.Gui.View.SetNeedsLayout.
 
+### Clipping
+
+Clipping enables better performance by ensuring on regions of the terminal that need to be drawn actually get drawn by the @Terminal.Gui.ConsoleDriver. Terminal.Gui supports non-rectangular clip regions with @Terminal.Gui.Region. @Terminal.Gui.ConsoleDriver.Clip is the application managed clip region and is managed by @Terminal.Gui.Application. Developers cannot change this directly.
+
+The View drawing APIs, e.g. @Terminal.Gui.View.OnDrawingSubviews, are passed the clip region currently enforced in Viewport-relative coordinates. 
+
 ## Coordinate System for Drawing
 
 The @Terminal.Gui.View draw APIs all take coordinates specified in *Viewport-Relative* coordinates. That is, `0, 0` is the top-left cell visible to the user.

二進制
local_packages/Terminal.Gui.2.0.0.nupkg


二進制
local_packages/Terminal.Gui.2.0.0.snupkg