Browse Source

Fix scroll slider when moving mouse outside the host.

BDisp 11 months ago
parent
commit
9b896573ec
2 changed files with 119 additions and 83 deletions
  1. 10 12
      Terminal.Gui/Views/Scroll/ScrollSlider.cs
  2. 109 71
      UnitTests/Views/ScrollTests.cs

+ 10 - 12
Terminal.Gui/Views/Scroll/ScrollSlider.cs

@@ -87,23 +87,21 @@ internal class ScrollSlider : View
         }
         }
         else if (mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition))
         else if (mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition))
         {
         {
+            _wasSliderMouse = true;
+
             if (_host.Orientation == Orientation.Vertical)
             if (_host.Orientation == Orientation.Vertical)
             {
             {
-                if (Frame.Y + offset >= 0 && Frame.Y + offset + Frame.Height <= barSize)
-                {
-                    _wasSliderMouse = true;
-                    Y = Frame.Y + offset;
-                    _host.Position = GetPositionFromSliderLocation (Frame.Y);
-                }
+                Y = Frame.Y + offset < 0 ? 0 :
+                    Frame.Y + offset + Frame.Height > barSize ? Math.Max (barSize - Frame.Height, 0) : Frame.Y + offset;
+
+                _host.Position = GetPositionFromSliderLocation (Frame.Y);
             }
             }
             else
             else
             {
             {
-                if (Frame.X + offset >= 0 && Frame.X + offset + Frame.Width <= barSize)
-                {
-                    _wasSliderMouse = true;
-                    X = Frame.X + offset;
-                    _host.Position = GetPositionFromSliderLocation (Frame.X);
-                }
+                X = Frame.X + offset < 0 ? 0 :
+                    Frame.X + offset + Frame.Width > barSize ? Math.Max (barSize - Frame.Width, 0) : Frame.X + offset;
+
+                _host.Position = GetPositionFromSliderLocation (Frame.X);
             }
             }
         }
         }
         else if (mouseEvent.Flags == MouseFlags.Button1Released)
         else if (mouseEvent.Flags == MouseFlags.Button1Released)

+ 109 - 71
UnitTests/Views/ScrollTests.cs

@@ -707,6 +707,45 @@ public class ScrollTests
         Assert.Null (Application.MouseGrabView);
         Assert.Null (Application.MouseGrabView);
     }
     }
 
 
+    [Theory]
+    [AutoInitShutdown]
+    [InlineData (Orientation.Vertical)]
+    public void Moving_Mouse_Outside_Host_Ensures_Correct_Location (Orientation orientation)
+    {
+        var scroll = new Scroll
+        {
+            X = 10, Y = 10, Width = orientation == Orientation.Vertical ? 1 : 10, Height = orientation == Orientation.Vertical ? 10 : 1, Size = 20,
+            Position = 5, Orientation = orientation
+        };
+        var top = new Toplevel ();
+        top.Add (scroll);
+        Application.Begin (top);
+
+        Rectangle scrollSliderFrame = scroll.Subviews.FirstOrDefault (x => x.Id == "scrollSlider")!.Frame;
+        Assert.Equal (scrollSliderFrame, orientation == Orientation.Vertical ? new (0, 2, 1, 5) : new (2, 0, 5, 1));
+
+        Application.OnMouseEvent (new () { Position = orientation == Orientation.Vertical ? new (10, 12) : new (12, 10), Flags = MouseFlags.Button1Pressed });
+
+        Application.OnMouseEvent (
+                                  new ()
+                                  {
+                                      Position = orientation == Orientation.Vertical ? new (10, 0) : new (0, 10),
+                                      Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
+                                  });
+        Assert.Equal (new (0, 0), scroll.Subviews.FirstOrDefault (x => x.Id == "scrollSlider")!.Frame.Location);
+
+        Application.OnMouseEvent (
+                                  new ()
+                                  {
+                                      Position = orientation == Orientation.Vertical ? new (0, 25) : new (80, 0),
+                                      Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
+                                  });
+
+        Assert.Equal (
+                      orientation == Orientation.Vertical ? new (0, 5) : new (5, 0),
+                      scroll.Subviews.FirstOrDefault (x => x.Id == "scrollSlider")!.Frame.Location);
+    }
+
     [Theory]
     [Theory]
     [InlineData (Orientation.Vertical, 20, 10)]
     [InlineData (Orientation.Vertical, 20, 10)]
     [InlineData (Orientation.Vertical, 40, 30)]
     [InlineData (Orientation.Vertical, 40, 30)]
@@ -754,6 +793,76 @@ public class ScrollTests
         Assert.Equal (1, changedCount);
         Assert.Equal (1, changedCount);
     }
     }
 
 
+    [Fact]
+    public void PositionChanging_PositionChanged_Events_Only_Raises_Once_If_Position_Was_Really_Changed ()
+    {
+        var changing = 0;
+        var cancel = false;
+        var changed = 0;
+        var scroll = new Scroll { Height = 10, Size = 20 };
+        scroll.PositionChanging += Scroll_PositionChanging;
+        scroll.PositionChanged += Scroll_PositionChanged;
+
+        Assert.Equal (Orientation.Vertical, scroll.Orientation);
+        Assert.Equal (new (0, 0, 1, 10), scroll.Viewport);
+        Assert.Equal (0, scroll.Position);
+        Assert.Equal (0, changing);
+        Assert.Equal (0, changed);
+
+        scroll.Position = 0;
+        Assert.Equal (0, scroll.Position);
+        Assert.Equal (0, changing);
+        Assert.Equal (0, changed);
+
+        scroll.Position = 1;
+        Assert.Equal (1, scroll.Position);
+        Assert.Equal (1, changing);
+        Assert.Equal (1, changed);
+
+        Reset ();
+        cancel = true;
+        scroll.Position = 2;
+        Assert.Equal (1, scroll.Position);
+        Assert.Equal (1, changing);
+        Assert.Equal (0, changed);
+
+        Reset ();
+        scroll.Position = 10;
+        Assert.Equal (10, scroll.Position);
+        Assert.Equal (1, changing);
+        Assert.Equal (1, changed);
+
+        Reset ();
+        scroll.Position = 11;
+        Assert.Equal (10, scroll.Position);
+        Assert.Equal (0, changing);
+        Assert.Equal (0, changed);
+
+        Reset ();
+        scroll.Position = 0;
+        Assert.Equal (0, scroll.Position);
+        Assert.Equal (1, changing);
+        Assert.Equal (1, changed);
+
+        scroll.PositionChanging -= Scroll_PositionChanging;
+        scroll.PositionChanged -= Scroll_PositionChanged;
+
+        void Scroll_PositionChanging (object sender, CancelEventArgs<int> e)
+        {
+            changing++;
+            e.Cancel = cancel;
+        }
+
+        void Scroll_PositionChanged (object sender, EventArgs<int> e) { changed++; }
+
+        void Reset ()
+        {
+            changing = 0;
+            cancel = false;
+            changed = 0;
+        }
+    }
+
     [Fact]
     [Fact]
     public void SizeChanged_Event ()
     public void SizeChanged_Event ()
     {
     {
@@ -843,75 +952,4 @@ public class ScrollTests
 
 
         _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
         _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
     }
     }
-
-    [Fact]
-    public void PositionChanging_PositionChanged_Events_Only_Raises_Once_If_Position_Was_Really_Changed ()
-    {
-        var changing = 0;
-        var cancel = false;
-        var changed = 0;
-        var scroll = new Scroll { Height = 10, Size = 20 };
-        scroll.PositionChanging += Scroll_PositionChanging;
-        scroll.PositionChanged += Scroll_PositionChanged;
-
-        Assert.Equal (Orientation.Vertical, scroll.Orientation);
-        Assert.Equal (new (0, 0, 1, 10), scroll.Viewport);
-        Assert.Equal (0, scroll.Position);
-        Assert.Equal (0, changing);
-        Assert.Equal (0, changed);
-
-        scroll.Position = 0;
-        Assert.Equal (0, scroll.Position);
-        Assert.Equal (0, changing);
-        Assert.Equal (0, changed);
-
-        scroll.Position = 1;
-        Assert.Equal (1, scroll.Position);
-        Assert.Equal (1, changing);
-        Assert.Equal (1, changed);
-
-        Reset ();
-        cancel = true;
-        scroll.Position = 2;
-        Assert.Equal (1, scroll.Position);
-        Assert.Equal (1, changing);
-        Assert.Equal (0, changed);
-
-        Reset ();
-        scroll.Position = 10;
-        Assert.Equal (10, scroll.Position);
-        Assert.Equal (1, changing);
-        Assert.Equal (1, changed);
-
-        Reset ();
-        scroll.Position = 11;
-        Assert.Equal (10, scroll.Position);
-        Assert.Equal (0, changing);
-        Assert.Equal (0, changed);
-
-        Reset ();
-        scroll.Position = 0;
-        Assert.Equal (0, scroll.Position);
-        Assert.Equal (1, changing);
-        Assert.Equal (1, changed);
-
-        scroll.PositionChanging -= Scroll_PositionChanging;
-        scroll.PositionChanged -= Scroll_PositionChanged;
-
-
-        void Scroll_PositionChanging (object sender, CancelEventArgs<int> e)
-        {
-            changing++;
-            e.Cancel = cancel;
-        }
-
-        void Scroll_PositionChanged (object sender, EventArgs<int> e) => changed++;
-
-        void Reset ()
-        {
-            changing = 0;
-            cancel = false;
-            changed = 0;
-        }
-    }
 }
 }