Browse Source

Merge pull request #3337 from tig/v2_3332-Clipping-SetSubViewNeedsDisplay

Fixes #3332.  `ClearNeedsDisplay` needs to iterate through sub views
Tig 1 year ago
parent
commit
6badd0de12
3 changed files with 85 additions and 18 deletions
  1. 21 11
      Terminal.Gui/View/ViewDrawing.cs
  2. 13 7
      UICatalog/Scenarios/Clipping.cs
  3. 51 0
      UnitTests/View/NeedsDisplayTests.cs

+ 21 - 11
Terminal.Gui/View/ViewDrawing.cs

@@ -2,8 +2,6 @@
 
 public partial class View
 {
-    // The view-relative region that needs to be redrawn. Marked internal for unit tests.
-    internal Rectangle _needsDisplayRect = Rectangle.Empty;
     private ColorScheme _colorScheme;
 
     /// <summary>The color scheme for this view, if it is not defined, it returns the <see cref="SuperView"/>'s color scheme.</summary>
@@ -32,6 +30,9 @@ public partial class View
     /// <remarks><see cref="Border"/> adds border lines to this LineCanvas.</remarks>
     public LineCanvas LineCanvas { get; } = new ();
 
+    // The view-relative region that needs to be redrawn. Marked internal for unit tests.
+    internal Rectangle _needsDisplayRect = Rectangle.Empty;
+
     /// <summary>Gets or sets whether the view needs to be redrawn.</summary>
     public bool NeedsDisplay
     {
@@ -502,7 +503,7 @@ public partial class View
     ///     redrawn will be the <paramref name="region"/>.
     /// </remarks>
     /// <param name="region">The Bounds-relative region that needs to be redrawn.</param>
-    public virtual void SetNeedsDisplay (Rectangle region)
+    public void SetNeedsDisplay (Rectangle region)
     {
         if (!IsInitialized)
         {
@@ -523,11 +524,11 @@ public partial class View
             _needsDisplayRect = new (x, y, w, h);
         }
 
-        _superView?.SetSubViewNeedsDisplay ();
+        SuperView?.SetSubViewNeedsDisplay ();
 
-        Margin?.SetNeedsDisplay (Margin.Bounds);
-        Border?.SetNeedsDisplay (Border.Bounds);
-        Padding?.SetNeedsDisplay (Padding.Bounds);
+        Margin?.SetNeedsDisplay ();
+        Border?.SetNeedsDisplay ();
+        Padding?.SetNeedsDisplay ();
 
         foreach (View subview in Subviews)
         {
@@ -541,22 +542,31 @@ public partial class View
         }
     }
 
-    /// <summary>Indicates that any Subviews (in the <see cref="Subviews"/> list) need to be repainted.</summary>
+    /// <summary>Sets <see cref="SubViewNeedsDisplay"/> to <see langword="true"/> for this View and all Superviews.</summary>
     public void SetSubViewNeedsDisplay ()
     {
         SubViewNeedsDisplay = true;
 
-        if (_superView is { } && !_superView.SubViewNeedsDisplay)
+        if (SuperView is { SubViewNeedsDisplay: false })
         {
-            _superView.SetSubViewNeedsDisplay ();
+            SuperView.SetSubViewNeedsDisplay ();
         }
     }
 
     /// <summary>Clears <see cref="NeedsDisplay"/> and <see cref="SubViewNeedsDisplay"/>.</summary>
-    protected virtual void ClearNeedsDisplay ()
+    protected void ClearNeedsDisplay ()
     {
         _needsDisplayRect = Rectangle.Empty;
         SubViewNeedsDisplay = false;
+
+        Margin?.ClearNeedsDisplay ();
+        Border?.ClearNeedsDisplay ();
+        Padding?.ClearNeedsDisplay ();
+
+        foreach (View subview in Subviews)
+        {
+            subview.ClearNeedsDisplay();
+        }
     }
 
     // INTENT: Isn't this just intersection? It isn't used anyway.

+ 13 - 7
UICatalog/Scenarios/Clipping.cs

@@ -32,7 +32,7 @@ public class Clipping : Scenario
         //scrollView.ShowVerticalScrollIndicator = true;
         //scrollView.ShowHorizontalScrollIndicator = true;
 
-        var embedded1 = new Window
+        var embedded1 = new View
         {
             Title = "1",
             X = 3,
@@ -40,22 +40,26 @@ public class Clipping : Scenario
             Width = Dim.Fill (3),
             Height = Dim.Fill (3),
             ColorScheme = Colors.ColorSchemes ["Dialog"],
-            Id = "1"
+            Id = "1",
+            BorderStyle = LineStyle.Rounded,
+            Arrangement = ViewArrangement.Movable
         };
 
-        var embedded2 = new Window
+        var embedded2 = new View
         {
-            Title = "1",
+            Title = "2",
             X = 3,
             Y = 3,
             Width = Dim.Fill (3),
             Height = Dim.Fill (3),
             ColorScheme = Colors.ColorSchemes ["Error"],
-            Id = "2"
+            Id = "2",
+            BorderStyle = LineStyle.Rounded,
+            Arrangement = ViewArrangement.Movable
         };
         embedded1.Add (embedded2);
 
-        var embedded3 = new Window
+        var embedded3 = new View
         {
             Title = "3",
             X = 3,
@@ -63,7 +67,9 @@ public class Clipping : Scenario
             Width = Dim.Fill (3),
             Height = Dim.Fill (3),
             ColorScheme = Colors.ColorSchemes ["TopLevel"],
-            Id = "3"
+            Id = "3",
+            BorderStyle = LineStyle.Rounded,
+            Arrangement = ViewArrangement.Movable
         };
 
         var testButton = new Button { X = 2, Y = 2, Text = "click me" };

+ 51 - 0
UnitTests/View/NeedsDisplayTests.cs

@@ -0,0 +1,51 @@
+#nullable enable
+using System.Text;
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+
+[Trait("Category","Output")]
+public class NeedsDisplayTests (ITestOutputHelper output)
+{
+    [Fact]
+    public void NeedsDisplay_False_If_Width_Height_Zero ()
+    {
+        View view = new () { Width = 0, Height = 0};
+        view.BeginInit();
+        view.EndInit();
+        Assert.False (view.NeedsDisplay);
+        Assert.False (view.SubViewNeedsDisplay);
+    }
+
+
+    [Fact]
+    public void NeedsDisplay_True_Initially_If_Width_Height_Not_Zero ()
+    {
+        View superView = new () { Width = 1, Height = 1};
+        View view1 = new () { Width = 1, Height = 1 };
+        View view2 = new () { Width = 1, Height = 1 };
+
+        superView.Add(view1, view2);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        Assert.True (superView.NeedsDisplay);
+        Assert.True (superView.SubViewNeedsDisplay);
+        Assert.True (view1.NeedsDisplay);
+        Assert.True (view2.NeedsDisplay);
+
+        superView.Draw ();
+
+        Assert.False (superView.NeedsDisplay);
+        Assert.False (superView.SubViewNeedsDisplay);
+        Assert.False (view1.NeedsDisplay);
+        Assert.False (view2.NeedsDisplay);
+
+        superView.SetNeedsDisplay();
+
+        Assert.True (superView.NeedsDisplay);
+        Assert.True (superView.SubViewNeedsDisplay);
+        Assert.True (view1.NeedsDisplay);
+        Assert.True (view2.NeedsDisplay);
+    }
+}