Explorar el Código

Consolidating GetPositionFromSliderLocation and GetSliderLocationDimensionFromPosition methods.

BDisp hace 11 meses
padre
commit
d47188f1f0

+ 2 - 5
Terminal.Gui/Views/Scroll/Scroll.cs

@@ -39,7 +39,7 @@ public class Scroll : View
     internal readonly ScrollBar? _host;
     internal bool _wasSliderLayoutComplete = true;
 
-    private readonly ScrollSlider _slider;
+    internal readonly ScrollSlider _slider;
     private Orientation _orientation;
     private int _position;
     private int _size;
@@ -100,10 +100,7 @@ public class Scroll : View
 
             _position = value;
 
-            if (!_slider._wasSliderMouse)
-            {
-                AdjustScroll ();
-            }
+            AdjustScroll ();
 
             OnPositionChanged (_position);
         }

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

@@ -13,8 +13,6 @@ internal class ScrollSlider : View
         WantMousePositionReports = true;
     }
 
-    internal bool _wasSliderMouse;
-
     private readonly Scroll _host;
     private int _lastLocation = -1;
     private ColorScheme? _savedColorScheme;
@@ -93,8 +91,6 @@ internal class ScrollSlider : View
         }
         else if (mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition))
         {
-            _wasSliderMouse = true;
-
             if (_host.Orientation == Orientation.Vertical)
             {
                 Y = Frame.Y + offset < 0 ? 0 :
@@ -157,7 +153,7 @@ internal class ScrollSlider : View
         _host._wasSliderLayoutComplete = true;
     }
 
-    private int GetPositionFromSliderLocation (int location)
+    internal int GetPositionFromSliderLocation (int location)
     {
         if (_host.GetContentSize ().Height == 0 || _host.GetContentSize ().Width == 0)
         {
@@ -168,17 +164,16 @@ internal class ScrollSlider : View
 
         // Ensure the Position is valid if the slider is at end
         // We use Frame here instead of ContentSize because even if the slider has a margin or border, Frame indicates the actual size
-        if ((_host.Orientation == Orientation.Vertical && location + Frame.Height == scrollSize)
-            || (_host.Orientation == Orientation.Horizontal && location + Frame.Width == scrollSize))
+        if ((_host.Orientation == Orientation.Vertical && location + Frame.Height >= scrollSize)
+            || (_host.Orientation == Orientation.Horizontal && location + Frame.Width >= scrollSize))
         {
-            return _host.Size - scrollSize;
+                return _host.Size - scrollSize;
         }
 
-        return Math.Min ((location * _host.Size + location) / scrollSize, _host.Size - scrollSize);
+        return (int)Math.Min (Math.Round ((double)(location * _host.Size + location) / scrollSize), _host.Size - scrollSize);
     }
 
-    // QUESTION: This method is only called from one place. Should it be inlined? Or, should it be made internal and unit tests be provided?
-    private (int Location, int Dimension) GetSliderLocationDimensionFromPosition ()
+    internal (int Location, int Dimension) GetSliderLocationDimensionFromPosition ()
     {
         if (_host.GetContentSize ().Height == 0 || _host.GetContentSize ().Width == 0)
         {
@@ -199,7 +194,7 @@ internal class ScrollSlider : View
                 _host.Position = _host.Size - scrollSize;
             }
 
-            location = Math.Min ((_host.Position * scrollSize + _host.Position) / _host.Size, scrollSize - dimension);
+            location = (int)Math.Min (Math.Round ((double)_host.Position * scrollSize / (_host.Size + 1)), scrollSize - dimension);
 
             if (_host.Position == _host.Size - scrollSize && location + dimension < scrollSize)
             {

+ 100 - 0
UnitTests/Views/ScrollSliderTests.cs

@@ -0,0 +1,100 @@
+namespace Terminal.Gui.ViewsTests;
+
+public class ScrollSliderTests
+{
+    // Test for GetPositionFromSliderLocation to GetSliderLocationDimensionFromPosition
+    [Theory]
+    [InlineData (Orientation.Vertical, 26, 236, -1, 0)]
+    [InlineData (Orientation.Vertical, 26, 236, 0, 0)]
+    [InlineData (Orientation.Vertical, 26, 236, 5, 46)]
+    [InlineData (Orientation.Vertical, 26, 236, 10, 91)]
+    [InlineData (Orientation.Vertical, 26, 236, 15, 137)]
+    [InlineData (Orientation.Vertical, 26, 236, 20, 182)]
+    [InlineData (Orientation.Vertical, 26, 236, 26, 210)]
+    [InlineData (Orientation.Vertical, 26, 236, 27, 210)]
+    [InlineData (Orientation.Vertical, 37, 236, 2, 13)]
+    [InlineData (Orientation.Vertical, 42, 236, 29, 164)]
+    public void Test_Position_Location_Consistency (Orientation orientation, int scrollLength, int size, int location, int expectedPosition)
+    {
+        // Arrange
+        Scroll host = new ()
+        {
+            Orientation = orientation,
+            Width = orientation == Orientation.Vertical ? 1 : scrollLength,
+            Height = orientation == Orientation.Vertical ? scrollLength : 1,
+            Size = size
+        };
+
+        host.BeginInit ();
+        host.EndInit ();
+
+        // Act
+        host.Position = host._slider.GetPositionFromSliderLocation (location);
+        (int calculatedLocation, int calculatedDimension) = host._slider.GetSliderLocationDimensionFromPosition ();
+        int calculatedPosition = host._slider.GetPositionFromSliderLocation (calculatedLocation);
+
+        // Assert
+        AssertLocation (scrollLength, location, calculatedLocation, calculatedDimension);
+
+        Assert.Equal (host.Position, expectedPosition);
+        Assert.Equal (calculatedPosition, expectedPosition);
+    }
+
+    // Randomized Test for more extensive testing
+    [Theory]
+    [InlineData (Orientation.Vertical, 26, 236, 5)]
+    public void Test_Position_Location_Consistency_Random (Orientation orientation, int scrollLength, int size, int testCount)
+    {
+        var random = new Random ();
+
+        Scroll host = new ()
+        {
+            Orientation = orientation,
+            Width = orientation == Orientation.Vertical ? 1 : scrollLength,
+            Height = orientation == Orientation.Vertical ? scrollLength : 1,
+            Size = size
+        };
+
+        host.BeginInit ();
+        host.EndInit ();
+
+        // Number of random tests to run
+        for (var i = 0; i < testCount; i++)
+        {
+            // Arrange
+            int randomScrollLength = random.Next (0, 60); // Random content size length
+            int randomLocation = random.Next (0, randomScrollLength); // Random location
+
+            host.Width = host.Orientation == Orientation.Vertical ? 1 : randomScrollLength;
+            host.Height = host.Orientation == Orientation.Vertical ? randomScrollLength : 1;
+            // Slider may have changed content size
+            host.LayoutSubviews ();
+
+            // Act
+            host.Position = host._slider.GetPositionFromSliderLocation (randomLocation);
+            (int calculatedLocation, int calculatedDimension) = host._slider.GetSliderLocationDimensionFromPosition ();
+            int calculatedPosition = host._slider.GetPositionFromSliderLocation (calculatedLocation);
+
+            // Assert
+            AssertLocation (randomScrollLength, randomLocation, calculatedLocation, calculatedDimension);
+
+            Assert.Equal (host.Position, calculatedPosition);
+        }
+    }
+
+    private static void AssertLocation (int scrollLength, int location, int calculatedLocation, int calculatedDimension)
+    {
+        if (location < 0)
+        {
+            Assert.Equal (0, calculatedLocation);
+        }
+        else if (location + calculatedDimension >= scrollLength)
+        {
+            Assert.Equal (scrollLength - calculatedDimension, calculatedLocation);
+        }
+        else
+        {
+            Assert.Equal (location, calculatedLocation);
+        }
+    }
+}