Pārlūkot izejas kodu

Merge pull request #3584 from tig/v2_3583-ShadowStyleOpaque

Fixes #3583. `ShadowStyle.Opaque` broke
Tig 1 gadu atpakaļ
vecāks
revīzija
01dd3ef6fc

+ 113 - 104
Terminal.Gui/View/Adornment/Margin.cs

@@ -1,7 +1,5 @@
 #nullable enable
 
-using System.Drawing;
-
 namespace Terminal.Gui;
 
 /// <summary>The Margin for a <see cref="View"/>.</summary>
@@ -28,58 +26,68 @@ public class Margin : Adornment
         CanFocus = false;
     }
 
-    private void Margin_LayoutStarted (object? sender, LayoutEventArgs e)
+    private bool _pressed;
+
+    private ShadowView? _bottomShadow;
+    private ShadowView? _rightShadow;
+
+    /// <inheritdoc/>
+    public override void BeginInit ()
     {
-        // Adjust the shadow such that it is drawn aligned with the Border
-        if (ShadowStyle != Gui.ShadowStyle.None && _rightShadow is { } && _bottomShadow is { })
+        base.BeginInit ();
+
+        if (Parent is null)
         {
-            _rightShadow.Y = Parent.Border.Thickness.Top > 0 ? Parent.Border.Thickness.Top - (Parent.Border.Thickness.Top > 2 && Parent.Border.ShowTitle ? 1 : 0) : 1;
-            _bottomShadow.X = Parent.Border.Thickness.Left > 0 ? Parent.Border.Thickness.Left : 1;
+            return;
         }
+
+        ShadowStyle = base.ShadowStyle;
+
+        Add (
+             _rightShadow = new()
+             {
+                 X = Pos.AnchorEnd (1),
+                 Y = 0,
+                 Width = 1,
+                 Height = Dim.Fill (),
+                 ShadowStyle = ShadowStyle,
+                 Orientation = Orientation.Vertical
+             },
+             _bottomShadow = new()
+             {
+                 X = 0,
+                 Y = Pos.AnchorEnd (1),
+                 Width = Dim.Fill (),
+                 Height = 1,
+                 ShadowStyle = ShadowStyle,
+                 Orientation = Orientation.Horizontal
+             }
+            );
     }
 
-    private bool _pressed;
-    private void Margin_Highlight (object? sender, CancelEventArgs<HighlightStyle> e)
+    /// <summary>
+    ///     The color scheme for the Margin. If set to <see langword="null"/>, gets the <see cref="Adornment.Parent"/>'s
+    ///     <see cref="View.SuperView"/> scheme. color scheme.
+    /// </summary>
+    public override ColorScheme ColorScheme
     {
-        if (ShadowStyle != Gui.ShadowStyle.None)
+        get
         {
-            if (_pressed && e.CurrentValue == HighlightStyle.None)
+            if (base.ColorScheme is { })
             {
-                Thickness = new (Thickness.Left - 1, Thickness.Top, Thickness.Right + 1, Thickness.Bottom);
-
-                if (_rightShadow is { })
-                {
-                    _rightShadow.Visible = true;
-                }
-
-                if (_bottomShadow is { })
-                {
-                    _bottomShadow.Visible = true;
-                }
-
-                _pressed = false;
-                return;
+                return base.ColorScheme;
             }
 
-            if (!_pressed && (e.CurrentValue.HasFlag (HighlightStyle.Pressed) /*|| e.HighlightStyle.HasFlag (HighlightStyle.PressedOutside)*/))
-            {
-                Thickness = new (Thickness.Left + 1, Thickness.Top, Thickness.Right - 1, Thickness.Bottom);
-                _pressed = true;
-                if (_rightShadow is { })
-                {
-                    _rightShadow.Visible = false;
-                }
-
-                if (_bottomShadow is { })
-                {
-                    _bottomShadow.Visible = false;
-                }
-            }
+            return (Parent?.SuperView?.ColorScheme ?? Colors.ColorSchemes ["TopLevel"])!;
+        }
+        set
+        {
+            base.ColorScheme = value;
+            Parent?.SetNeedsDisplay ();
         }
-
     }
 
-    /// <inheritdoc />
+    /// <inheritdoc/>
     public override void OnDrawContent (Rectangle viewport)
     {
         Rectangle screen = ViewportToScreen (viewport);
@@ -87,12 +95,12 @@ public class Margin : Adornment
 
         Driver?.SetAttribute (normalAttr);
 
-
         // This just draws/clears the thickness, not the insides.
         if (ShadowStyle != ShadowStyle.None)
         {
             screen = Rectangle.Inflate (screen, -1, -1);
         }
+
         Thickness.Draw (screen, ToString ());
 
         if (Subviews.Count > 0)
@@ -105,12 +113,14 @@ public class Margin : Adornment
                                                                         view => view.Visible
                                                                                 && (view.NeedsDisplay || view.SubViewNeedsDisplay || view.LayoutNeeded)
                                                                        );
+
                 foreach (View view in subviewsNeedingDraw)
                 {
                     if (view.LayoutNeeded)
                     {
                         view.LayoutSubviews ();
                     }
+
                     view.Draw ();
                 }
             }
@@ -118,39 +128,7 @@ public class Margin : Adornment
     }
 
     /// <summary>
-    ///     The color scheme for the Margin. If set to <see langword="null"/>, gets the <see cref="Adornment.Parent"/>'s
-    ///     <see cref="View.SuperView"/> scheme. color scheme.
-    /// </summary>
-    public override ColorScheme ColorScheme
-    {
-        get
-        {
-            if (base.ColorScheme is { })
-            {
-                return base.ColorScheme;
-            }
-
-            return (Parent?.SuperView?.ColorScheme ?? Colors.ColorSchemes ["TopLevel"])!;
-        }
-        set
-        {
-            base.ColorScheme = value;
-            Parent?.SetNeedsDisplay ();
-        }
-    }
-
-    /// <inheritdoc />
-    public override ShadowStyle ShadowStyle
-    {
-        get => base.ShadowStyle;
-        set
-        {
-            base.ShadowStyle = SetShadow (value);
-        }
-    }
-
-    /// <summary>
-    ///    Sets whether the Margin includes a shadow effect. The shadow is drawn on the right and bottom sides of the
+    ///     Sets whether the Margin includes a shadow effect. The shadow is drawn on the right and bottom sides of the
     ///     Margin.
     /// </summary>
     public ShadowStyle SetShadow (ShadowStyle style)
@@ -181,42 +159,73 @@ public class Margin : Adornment
         {
             _bottomShadow.ShadowStyle = style;
         }
+
         return style;
     }
 
-    private ShadowView? _bottomShadow;
-    private ShadowView? _rightShadow;
-
     /// <inheritdoc/>
-    public override void BeginInit ()
+    public override ShadowStyle ShadowStyle
     {
-        base.BeginInit ();
+        get => base.ShadowStyle;
+        set => base.ShadowStyle = SetShadow (value);
+    }
 
-        if (Parent is null)
+    private void Margin_Highlight (object? sender, CancelEventArgs<HighlightStyle> e)
+    {
+        if (ShadowStyle != ShadowStyle.None)
         {
-            return;
+            if (_pressed && e.NewValue == HighlightStyle.None)
+            {
+                // If the view is pressed and the highlight is being removed, move the shadow back.
+                // Note, for visual effects reasons, we only move horizontally.
+                // TODO: Add a setting or flag that lets the view move vertically as well.
+                Thickness = new (Thickness.Left - 1, Thickness.Top, Thickness.Right + 1, Thickness.Bottom);
+
+                if (_rightShadow is { })
+                {
+                    _rightShadow.Visible = true;
+                }
+
+                if (_bottomShadow is { })
+                {
+                    _bottomShadow.Visible = true;
+                }
+
+                _pressed = false;
+
+                return;
+            }
+
+            if (!_pressed && e.NewValue.HasFlag (HighlightStyle.Pressed))
+            {
+                // If the view is not pressed and we want highlight move the shadow
+                // Note, for visual effects reasons, we only move horizontally.
+                // TODO: Add a setting or flag that lets the view move vertically as well.
+                Thickness = new (Thickness.Left + 1, Thickness.Top, Thickness.Right - 1, Thickness.Bottom);
+                _pressed = true;
+
+                if (_rightShadow is { })
+                {
+                    _rightShadow.Visible = false;
+                }
+
+                if (_bottomShadow is { })
+                {
+                    _bottomShadow.Visible = false;
+                }
+            }
         }
+    }
 
-        ShadowStyle = base.ShadowStyle;
-        Add (
-             _rightShadow = new ShadowView
-             {
-                 X = Pos.AnchorEnd (1),
-                 Y = 0,
-                 Width = 1,
-                 Height = Dim.Fill (),
-                 ShadowStyle = ShadowStyle,
-                 Orientation = Orientation.Vertical
-             },
-             _bottomShadow = new ShadowView
-             {
-                 X = 0,
-                 Y = Pos.AnchorEnd (1),
-                 Width = Dim.Fill (),
-                 Height = 1,
-                 ShadowStyle = ShadowStyle,
-                 Orientation = Orientation.Horizontal
-             }
-            );
+    private void Margin_LayoutStarted (object? sender, LayoutEventArgs e)
+    {
+        // Adjust the shadow such that it is drawn aligned with the Border
+        if (ShadowStyle != ShadowStyle.None && _rightShadow is { } && _bottomShadow is { })
+        {
+            _rightShadow.Y = Parent.Border.Thickness.Top > 0
+                                 ? Parent.Border.Thickness.Top - (Parent.Border.Thickness.Top > 2 && Parent.Border.ShowTitle ? 1 : 0)
+                                 : 1;
+            _bottomShadow.X = Parent.Border.Thickness.Left > 0 ? Parent.Border.Thickness.Left : 1;
+        }
     }
-}
+}

+ 3 - 3
UnitTests/View/Adornment/MarginTests.cs

@@ -10,13 +10,13 @@ public class MarginTests (ITestOutputHelper output)
     {
         ((FakeDriver)Application.Driver).SetBufferSize (5, 5);
         var view = new View { Height = 3, Width = 3 };
-        view.Margin.Thickness = new Thickness (1);
+        view.Margin.Thickness = new (1);
 
         var superView = new View ();
 
-        superView.ColorScheme = new ColorScheme
+        superView.ColorScheme = new()
         {
-            Normal = new Attribute (Color.Red, Color.Green), Focus = new Attribute (Color.Green, Color.Red)
+            Normal = new (Color.Red, Color.Green), Focus = new (Color.Green, Color.Red)
         };
 
         superView.Add (view);

+ 126 - 0
UnitTests/View/Adornment/ShadowStyletests.cs

@@ -27,6 +27,132 @@ public class ShadowStyleTests (ITestOutputHelper _output)
         view.Dispose ();
     }
 
+    [Theory]
+    [InlineData (ShadowStyle.None, 0, 0, 0, 0)]
+    [InlineData (ShadowStyle.Opaque, 1, 0, 0, 1)]
+    [InlineData (ShadowStyle.Transparent, 1, 0, 0, 1)]
+    public void ShadowStyle_Button1Pressed_Causes_Movement (ShadowStyle style, int expectedLeft, int expectedTop, int expectedRight, int expectedBottom)
+    {
+        var superView = new View
+        {
+            Height = 10, Width = 10
+        };
+
+        View view = new ()
+        {
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+            Text = "0123",
+            HighlightStyle = HighlightStyle.Pressed,
+            ShadowStyle = style,
+            CanFocus = true
+        };
+
+        superView.Add (view);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        Thickness origThickness = view.Margin.Thickness;
+        view.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed, Position = new (0, 0) });
+        Assert.Equal (new (expectedLeft, expectedTop, expectedRight, expectedBottom), view.Margin.Thickness);
+
+        view.NewMouseEvent (new () { Flags = MouseFlags.Button1Released, Position = new (0, 0) });
+        Assert.Equal (origThickness, view.Margin.Thickness);
+    }
+
+    [Theory]
+    [InlineData (ShadowStyle.None, 0, 0, 0, 0)]
+    [InlineData (ShadowStyle.Opaque, 0, 0, 1, 1)]
+    [InlineData (ShadowStyle.Transparent, 0, 0, 1, 1)]
+    public void ShadowStyle_Margin_Thickness (ShadowStyle style, int expectedLeft, int expectedTop, int expectedRight, int expectedBottom)
+    {
+        var superView = new View
+        {
+            Height = 10, Width = 10
+        };
+
+        View view = new ()
+        {
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+            Text = "0123",
+            HighlightStyle = HighlightStyle.Pressed,
+            ShadowStyle = style,
+            CanFocus = true
+        };
+
+        superView.Add (view);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        Assert.Equal (new (expectedLeft, expectedTop, expectedRight, expectedBottom), view.Margin.Thickness);
+    }
+
+    [Theory]
+    [InlineData (
+                    ShadowStyle.None,
+                    """
+                    011
+                    111
+                    111
+                    """)]
+    [InlineData (
+                    ShadowStyle.Transparent,
+                    """
+                    011
+                    131
+                    111
+                    """)]
+    [InlineData (
+                    ShadowStyle.Opaque,
+                    """
+                    011
+                    121
+                    111
+                    """)]
+    [SetupFakeDriver]
+    public void ShadowView_Colors (ShadowStyle style, string expectedAttrs)
+    {
+        Color fg = Color.Red;
+        Color bg = Color.Green;
+
+        // 0 - View
+        // 1 - SuperView
+        // 2 - Opaque - fg is Black, bg is SuperView.Bg
+        // 3 - Transparent - fg is darker fg, bg is darker bg
+        Attribute [] attributes =
+        {
+            Attribute.Default,
+            new (fg, bg),
+            new (Color.Black, bg),
+            new (fg.GetDarkerColor (), bg.GetDarkerColor ())
+        };
+
+        var superView = new View
+        {
+            Height = 3,
+            Width = 3,
+            Text = "012ABC!@#",
+            ColorScheme = new (new Attribute (fg, bg))
+        };
+        superView.TextFormatter.WordWrap = true;
+
+        View view = new ()
+        {
+            Width = Dim.Auto (),
+            Height = Dim.Auto (),
+            Text = " ",
+            ShadowStyle = style,
+            ColorScheme = new (Attribute.Default)
+        };
+        superView.Add (view);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        superView.Draw ();
+        TestHelpers.AssertDriverAttributesAre (expectedAttrs, Application.Driver, attributes);
+    }
+
     [Theory]
     [InlineData (ShadowStyle.None, 3)]
     [InlineData (ShadowStyle.Opaque, 4)]

+ 0 - 1
UnitTests/View/MouseTests.cs

@@ -647,5 +647,4 @@ public class MouseTests (ITestOutputHelper output) : TestsAllViews
             }
         }
     }
-
 }