From 88bb3984c06ea1cad42d40e9d2d101a2c865ca28 Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 6 Jul 2024 16:19:35 -0600 Subject: [PATCH 1/4] Fixed bug. Added unit tests --- Terminal.Gui/View/Adornment/Margin.cs | 4 +- UnitTests/View/Adornment/MarginTests.cs | 1 + UnitTests/View/Adornment/ShadowStyletests.cs | 126 +++++++++++++++++++ UnitTests/View/MouseTests.cs | 1 - 4 files changed, 129 insertions(+), 3 deletions(-) diff --git a/Terminal.Gui/View/Adornment/Margin.cs b/Terminal.Gui/View/Adornment/Margin.cs index 11ae2dd2b..a7273a74c 100644 --- a/Terminal.Gui/View/Adornment/Margin.cs +++ b/Terminal.Gui/View/Adornment/Margin.cs @@ -43,7 +43,7 @@ public class Margin : Adornment { if (ShadowStyle != Gui.ShadowStyle.None) { - if (_pressed && e.CurrentValue == HighlightStyle.None) + if (_pressed && e.NewValue == HighlightStyle.None) { Thickness = new (Thickness.Left - 1, Thickness.Top, Thickness.Right + 1, Thickness.Bottom); @@ -61,7 +61,7 @@ public class Margin : Adornment return; } - if (!_pressed && (e.CurrentValue.HasFlag (HighlightStyle.Pressed) /*|| e.HighlightStyle.HasFlag (HighlightStyle.PressedOutside)*/)) + if (!_pressed && (e.NewValue.HasFlag (HighlightStyle.Pressed) /*|| e.HighlightStyle.HasFlag (HighlightStyle.PressedOutside)*/)) { Thickness = new (Thickness.Left + 1, Thickness.Top, Thickness.Right - 1, Thickness.Bottom); _pressed = true; diff --git a/UnitTests/View/Adornment/MarginTests.cs b/UnitTests/View/Adornment/MarginTests.cs index 87f76f45f..58b6d1dce 100644 --- a/UnitTests/View/Adornment/MarginTests.cs +++ b/UnitTests/View/Adornment/MarginTests.cs @@ -40,4 +40,5 @@ MMM", ); TestHelpers.AssertDriverAttributesAre ("0", null, superView.GetNormalColor ()); } + } diff --git a/UnitTests/View/Adornment/ShadowStyletests.cs b/UnitTests/View/Adornment/ShadowStyletests.cs index c8f3f8063..967720e36 100644 --- a/UnitTests/View/Adornment/ShadowStyletests.cs +++ b/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)] diff --git a/UnitTests/View/MouseTests.cs b/UnitTests/View/MouseTests.cs index 956f4b202..5c5453f3a 100644 --- a/UnitTests/View/MouseTests.cs +++ b/UnitTests/View/MouseTests.cs @@ -647,5 +647,4 @@ public class MouseTests (ITestOutputHelper output) : TestsAllViews } } } - } From 2497419a2876f8451591248c86f926dc0b2b74ce Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 6 Jul 2024 16:27:37 -0600 Subject: [PATCH 2/4] Added comments --- Terminal.Gui/View/Adornment/Margin.cs | 253 +++++++++++++------------- 1 file changed, 131 insertions(+), 122 deletions(-) diff --git a/Terminal.Gui/View/Adornment/Margin.cs b/Terminal.Gui/View/Adornment/Margin.cs index a7273a74c..f76f0e8b8 100644 --- a/Terminal.Gui/View/Adornment/Margin.cs +++ b/Terminal.Gui/View/Adornment/Margin.cs @@ -1,7 +1,5 @@ #nullable enable -using System.Drawing; - namespace Terminal.Gui; /// The Margin for a . @@ -28,93 +26,43 @@ public class Margin : Adornment CanFocus = false; } - private void Margin_LayoutStarted (object? sender, LayoutEventArgs e) - { - // Adjust the shadow such that it is drawn aligned with the Border - if (ShadowStyle != Gui.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; - } - } - private bool _pressed; - private void Margin_Highlight (object? sender, CancelEventArgs e) + + private ShadowView? _bottomShadow; + private ShadowView? _rightShadow; + + /// + public override void BeginInit () { - if (ShadowStyle != Gui.ShadowStyle.None) + base.BeginInit (); + + if (Parent is null) { - if (_pressed && e.NewValue == HighlightStyle.None) - { - 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) /*|| 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; } - } + ShadowStyle = base.ShadowStyle; - /// - public override void OnDrawContent (Rectangle viewport) - { - Rectangle screen = ViewportToScreen (viewport); - Attribute normalAttr = GetNormalColor (); - - 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) - { - // Draw subviews - // TODO: Implement OnDrawSubviews (cancelable); - if (Subviews is { } && SubViewNeedsDisplay) - { - IEnumerable subviewsNeedingDraw = Subviews.Where ( - view => view.Visible - && (view.NeedsDisplay || view.SubViewNeedsDisplay || view.LayoutNeeded) - ); - foreach (View view in subviewsNeedingDraw) - { - if (view.LayoutNeeded) - { - view.LayoutSubviews (); - } - view.Draw (); - } - } - } + 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 + } + ); } /// @@ -139,18 +87,48 @@ public class Margin : Adornment } } - /// - public override ShadowStyle ShadowStyle + /// + public override void OnDrawContent (Rectangle viewport) { - get => base.ShadowStyle; - set + Rectangle screen = ViewportToScreen (viewport); + Attribute normalAttr = GetNormalColor (); + + Driver?.SetAttribute (normalAttr); + + // This just draws/clears the thickness, not the insides. + if (ShadowStyle != ShadowStyle.None) { - base.ShadowStyle = SetShadow (value); + screen = Rectangle.Inflate (screen, -1, -1); + } + + Thickness.Draw (screen, ToString ()); + + if (Subviews.Count > 0) + { + // Draw subviews + // TODO: Implement OnDrawSubviews (cancelable); + if (Subviews is { } && SubViewNeedsDisplay) + { + IEnumerable subviewsNeedingDraw = Subviews.Where ( + view => view.Visible + && (view.NeedsDisplay || view.SubViewNeedsDisplay || view.LayoutNeeded) + ); + + foreach (View view in subviewsNeedingDraw) + { + if (view.LayoutNeeded) + { + view.LayoutSubviews (); + } + + view.Draw (); + } + } } } /// - /// 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. /// public ShadowStyle SetShadow (ShadowStyle style) @@ -181,42 +159,73 @@ public class Margin : Adornment { _bottomShadow.ShadowStyle = style; } + return style; } - private ShadowView? _bottomShadow; - private ShadowView? _rightShadow; - /// - public override void BeginInit () + public override ShadowStyle ShadowStyle { - base.BeginInit (); - - if (Parent is null) - { - return; - } - - 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 - } - ); + get => base.ShadowStyle; + set => base.ShadowStyle = SetShadow (value); } -} \ No newline at end of file + + private void Margin_Highlight (object? sender, CancelEventArgs e) + { + if (ShadowStyle != ShadowStyle.None) + { + 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 shadow 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 shadow 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; + } + } + } + } + + 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; + } + } +} From 6f92d6db40c4196a7f7cc978abce1924ddc676fb Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 6 Jul 2024 16:29:19 -0600 Subject: [PATCH 3/4] Added comments --- Terminal.Gui/View/Adornment/Margin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Terminal.Gui/View/Adornment/Margin.cs b/Terminal.Gui/View/Adornment/Margin.cs index f76f0e8b8..2e1ea5760 100644 --- a/Terminal.Gui/View/Adornment/Margin.cs +++ b/Terminal.Gui/View/Adornment/Margin.cs @@ -178,7 +178,7 @@ public class Margin : Adornment { // 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 shadow move vertically as well. + // 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 { }) @@ -200,7 +200,7 @@ public class Margin : Adornment { // 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 shadow move vertically as well. + // 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; From 8125357ce4950d1fa94ffa48f9287bbf90af70ae Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 6 Jul 2024 16:31:16 -0600 Subject: [PATCH 4/4] code cleanup --- UnitTests/View/Adornment/MarginTests.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/UnitTests/View/Adornment/MarginTests.cs b/UnitTests/View/Adornment/MarginTests.cs index 58b6d1dce..1cfe6f0d1 100644 --- a/UnitTests/View/Adornment/MarginTests.cs +++ b/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); @@ -40,5 +40,4 @@ MMM", ); TestHelpers.AssertDriverAttributesAre ("0", null, superView.GetNormalColor ()); } - }