From ecfa51cf93038e2493bc06e8084be1ac19b74a6c Mon Sep 17 00:00:00 2001 From: Tig Date: Fri, 15 Nov 2024 12:45:28 -0700 Subject: [PATCH] We're back! --- Terminal.Gui/Views/ScrollBar/ScrollBar.cs | 102 ++---- Terminal.Gui/Views/ScrollBar/ScrollSlider.cs | 92 ++++- .../Scenarios/CharacterMap/CharacterMap.cs | 12 +- UnitTests/Views/ScrollBarTests.cs | 6 +- UnitTests/Views/ScrollSliderTests.cs | 335 +++++++++++++++++- 5 files changed, 471 insertions(+), 76 deletions(-) diff --git a/Terminal.Gui/Views/ScrollBar/ScrollBar.cs b/Terminal.Gui/Views/ScrollBar/ScrollBar.cs index 5f8a3e49f..abfd13c75 100644 --- a/Terminal.Gui/Views/ScrollBar/ScrollBar.cs +++ b/Terminal.Gui/Views/ScrollBar/ScrollBar.cs @@ -86,9 +86,10 @@ public class ScrollBar : View, IOrientation, IDesignable } else { - _slider.VisibleContentSize = Viewport.Width ; + _slider.VisibleContentSize = Viewport.Width; } + _slider.Size = CalculateSliderSize (); ShowHide (); } @@ -109,7 +110,8 @@ public class ScrollBar : View, IOrientation, IDesignable } _slider.Size = CalculateSliderSize (); - _slider.Position = CalculateSliderPosition (_position, NavigationDirection.Forward); + _sliderPosition = CalculateSliderPositionFromContentPosition (_position, NavigationDirection.Forward); + _slider.Position = _sliderPosition.Value; } /// @@ -210,7 +212,7 @@ public class ScrollBar : View, IOrientation, IDesignable /// The default is 1. /// public int Increment { get; set; } = 1; - + private bool _autoHide = true; /// @@ -356,25 +358,18 @@ public class ScrollBar : View, IOrientation, IDesignable _position = newContentPosition; + _sliderPosition = CalculateSliderPositionFromContentPosition (_position, direction); + + if (_slider.Position != _sliderPosition) + { + _slider.Position = _sliderPosition.Value; + } + OnPositionChanged (_position); PositionChanged?.Invoke (this, new (in _position)); OnScrolled (distance); Scrolled?.Invoke (this, new (in distance)); - - int currentSliderPosition = _slider.Position; - - //_slider.Size = CalculateSliderSize (); - - //int calculatedSliderPosition = CalculateSliderPosition (_position, direction); - - //_slider.MoveToPosition (calculatedSliderPosition); - - _slider.Size = CalculateSliderSize (); - int calculatedSliderPosition = CalculateSliderPosition (_position, direction); - - RaiseSliderPositionChangeEvents (calculatedSliderPosition, currentSliderPosition); - } } @@ -411,29 +406,19 @@ public class ScrollBar : View, IOrientation, IDesignable /// /// /// - internal int CalculatePosition (int sliderPosition) + internal int CalculatePositionFromSliderPosition (int sliderPosition) { - // Clamp the slider - int clampedSliderPosition = _slider.ClampPosition (sliderPosition); int scrollBarSize = Orientation == Orientation.Vertical ? Viewport.Height : Viewport.Width; - double pos = (double)(clampedSliderPosition) / - (scrollBarSize - _slider.Size - _slider.SliderPadding) * (ScrollableContentSize - VisibleContentSize); - - if (pos is double.NaN) - { - return 0; - } - double rounded = Math.Ceiling (pos); - - // Clamp between 0 and Size - SliderSize - return (int)Math.Clamp (rounded, 0, Math.Max (0, ScrollableContentSize - _slider.Size)); + return ScrollSlider.CalculateContentPosition (ScrollableContentSize, VisibleContentSize, sliderPosition, scrollBarSize - _slider.SliderPadding); } #endregion ContentPosition #region Slider Management - + + private int? _sliderPosition; + /// /// INTERNAL (for unit tests). Calculates the size of the slider based on the Orientation, VisibleContentSize, the actual Viewport, and Size. /// @@ -441,19 +426,7 @@ public class ScrollBar : View, IOrientation, IDesignable internal int CalculateSliderSize () { int maxSliderSize = (Orientation == Orientation.Vertical ? Viewport.Height : Viewport.Width) - 2; - - if (maxSliderSize < 1 || VisibleContentSize == 0) - { - return 1; - } - - //if (ScrollableContentSize < VisibleContentSize) - //{ - // return maxSliderSize ; - //} - - int size = (int)Math.Clamp (Math.Floor ((double)VisibleContentSize / ScrollableContentSize * (maxSliderSize)), 1, VisibleContentSize); - return Math.Clamp (size, 1, maxSliderSize); + return ScrollSlider.CalculateSize (ScrollableContentSize, VisibleContentSize, maxSliderSize); } private void SliderOnPositionChanged (object? sender, EventArgs e) @@ -463,9 +436,7 @@ public class ScrollBar : View, IOrientation, IDesignable return; } - int pos = e.CurrentValue; - - RaiseSliderPositionChangeEvents (_slider.Position, pos); + RaiseSliderPositionChangeEvents (_sliderPosition, e.CurrentValue); } private void SliderOnScroll (object? sender, EventArgs e) @@ -475,29 +446,31 @@ public class ScrollBar : View, IOrientation, IDesignable return; } - int calculatedSliderPos = CalculateSliderPosition (_position, e.CurrentValue >= 0 ? NavigationDirection.Forward : NavigationDirection.Backward); + int calculatedSliderPos = CalculateSliderPositionFromContentPosition (_position, e.CurrentValue >= 0 ? NavigationDirection.Forward : NavigationDirection.Backward); + + if (calculatedSliderPos == _sliderPosition) + { + return; + } int sliderScrolledAmount = e.CurrentValue; - int scrolledAmount = CalculatePosition (sliderScrolledAmount); + int calculatedPosition = CalculatePositionFromSliderPosition (calculatedSliderPos + sliderScrolledAmount); - RaiseSliderPositionChangeEvents (calculatedSliderPos, _slider.Position); - - Position = _position + scrolledAmount; + Position = calculatedPosition; } /// /// Gets or sets the position of the start of the Scroll slider, within the Viewport. /// - public int GetSliderPosition () => CalculateSliderPosition (_position); + public int GetSliderPosition () => CalculateSliderPositionFromContentPosition (_position); - private void RaiseSliderPositionChangeEvents (int calculatedSliderPosition, int newSliderPosition) + private void RaiseSliderPositionChangeEvents (int? currentSliderPosition, int newSliderPosition) { - if (calculatedSliderPosition == newSliderPosition) + if (currentSliderPosition == newSliderPosition) { return; } - // This sets the slider position and clamps the value - _slider.Position = newSliderPosition; + _sliderPosition = newSliderPosition; OnSliderPositionChanged (newSliderPosition); SliderPositionChanged?.Invoke (this, new (in newSliderPosition)); @@ -515,17 +488,10 @@ public class ScrollBar : View, IOrientation, IDesignable /// /// /// - internal int CalculateSliderPosition (int contentPosition, NavigationDirection direction = NavigationDirection.Forward) + internal int CalculateSliderPositionFromContentPosition (int contentPosition, NavigationDirection direction = NavigationDirection.Forward) { int scrollBarSize = Orientation == Orientation.Vertical ? Viewport.Height : Viewport.Width; - if (scrollBarSize < 3 || ScrollableContentSize - VisibleContentSize == 0) - { - return 0; - } - - double newSliderPosition = (double)(contentPosition - 1) / (ScrollableContentSize - VisibleContentSize) * (scrollBarSize - _slider.Size - _slider.SliderPadding); - - return Math.Clamp (direction == NavigationDirection.Forward ? (int)Math.Floor (newSliderPosition) : (int)Math.Ceiling (newSliderPosition), 0, scrollBarSize - _slider.Size - _slider.SliderPadding); + return ScrollSlider.CalculatePosition (ScrollableContentSize, VisibleContentSize, contentPosition, scrollBarSize - 2, direction); } @@ -542,7 +508,7 @@ public class ScrollBar : View, IOrientation, IDesignable { FillRect (Viewport with { X = Viewport.X + 1, Width = Viewport.Width - 2 }, Glyphs.Stipple); } - + SetNeedsDraw (); return true; } diff --git a/Terminal.Gui/Views/ScrollBar/ScrollSlider.cs b/Terminal.Gui/Views/ScrollBar/ScrollSlider.cs index d82082e86..9f3314e5d 100644 --- a/Terminal.Gui/Views/ScrollBar/ScrollSlider.cs +++ b/Terminal.Gui/Views/ScrollBar/ScrollSlider.cs @@ -1,6 +1,8 @@ #nullable enable using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; namespace Terminal.Gui; @@ -254,7 +256,7 @@ public class ScrollSlider : View, IOrientation, IDesignable /// internal int ClampPosition (int newPosition) { - return Math.Clamp (newPosition, 0, Math.Max (0, VisibleContentSize - SliderPadding - Size)); + return Math.Clamp (newPosition, 0, Math.Max (SliderPadding / 2, VisibleContentSize - SliderPadding - Size)); } private void RaisePositionChangeEvents (int newPosition) @@ -390,6 +392,8 @@ public class ScrollSlider : View, IOrientation, IDesignable currentLocation = Frame.X; } + currentLocation -= SliderPadding / 2; + // location does not account for the ShrinkBy int sliderLowerBound = SliderPadding / 2; int sliderUpperBound = superViewDimension - SliderPadding / 2 - Size; @@ -429,10 +433,94 @@ public class ScrollSlider : View, IOrientation, IDesignable /// public bool EnableForDesign () { -// Orientation = Orientation.Horizontal; + // Orientation = Orientation.Horizontal; ShowPercent = true; Size = 5; return true; } + + /// + /// Gets the slider size. + /// + /// The size of the content. + /// The size of the visible content. + /// The bounds of the area the slider moves in (e.g. the size of the minus 2). + public static int CalculateSize ( + int scrollableContentSize, + int visibleContentSize, + int sliderBounds + ) + { + if (scrollableContentSize <= 0 || sliderBounds <= 0) + { + return 1; // Slider must be at least 1 + } + + if (visibleContentSize <= 0 || scrollableContentSize <= visibleContentSize) + { + return sliderBounds; + } + + double sliderSizeD = ((double)visibleContentSize / scrollableContentSize) * sliderBounds; + + int sliderSize = (int)Math.Floor (sliderSizeD); + + return Math.Clamp (sliderSize, 1, sliderBounds); + } + + /// + /// Gets the slider position. + /// + /// The size of the content. + /// The size of the visible content. + /// The position in the content (between 0 and ). + /// The bounds of the area the slider moves in (e.g. the size of the minus 2). + /// The direction the slider is moving. + public static int CalculatePosition ( + int scrollableContentSize, + int visibleContentSize, + int contentPosition, + int sliderBounds, + NavigationDirection direction + ) + { + if (scrollableContentSize - visibleContentSize <= 0 || sliderBounds <= 0) + { + return 0; + } + + int calculatedSliderSize = CalculateSize (scrollableContentSize, visibleContentSize, sliderBounds); + + double newSliderPosition = ((double)contentPosition / (scrollableContentSize - visibleContentSize)) * (sliderBounds - calculatedSliderSize); + + return Math.Clamp ((int)Math.Round (newSliderPosition), 0, sliderBounds - calculatedSliderSize); + } + + /// + /// Gets the content position. + /// + /// The size of the content. + /// The size of the visible content. + /// The position of the slider. + /// The bounds of the area the slider moves in (e.g. the size of the minus 2). + public static int CalculateContentPosition ( + int scrollableContentSize, + int visibleContentSize, + int sliderPosition, + int sliderBounds + ) + { + int sliderSize = CalculateSize (scrollableContentSize, visibleContentSize, sliderBounds); + + double pos = ((double)(sliderPosition) / (sliderBounds - sliderSize)) * (scrollableContentSize - visibleContentSize); + + if (pos is double.NaN) + { + return 0; + } + double rounded = Math.Ceiling (pos); + + return (int)Math.Clamp (rounded, 0, Math.Max (0, scrollableContentSize - sliderSize)); + } } diff --git a/UICatalog/Scenarios/CharacterMap/CharacterMap.cs b/UICatalog/Scenarios/CharacterMap/CharacterMap.cs index 3456ade77..b6c7c1117 100644 --- a/UICatalog/Scenarios/CharacterMap/CharacterMap.cs +++ b/UICatalog/Scenarios/CharacterMap/CharacterMap.cs @@ -66,7 +66,17 @@ public class CharacterMap : Scenario }; top.Add (jumpEdit); - _charMap.SelectedCodePointChanged += (sender, args) => jumpEdit.Text = ((Rune)args.CurrentValue).ToString (); + _charMap.SelectedCodePointChanged += (sender, args) => + { + if (Rune.IsValid (args.CurrentValue)) + { + jumpEdit.Text = ((Rune)args.CurrentValue).ToString (); + } + else + { + jumpEdit.Text = $"U+{args.CurrentValue:x5}"; + } + }; _errorLabel = new () { diff --git a/UnitTests/Views/ScrollBarTests.cs b/UnitTests/Views/ScrollBarTests.cs index bc7cd8ce8..8b16d0ea9 100644 --- a/UnitTests/Views/ScrollBarTests.cs +++ b/UnitTests/Views/ScrollBarTests.cs @@ -473,7 +473,7 @@ public class ScrollBarTests (ITestOutputHelper output) scrollBar.Width = visibleContentSize; // Act - var sliderPosition= scrollBar.CalculateSliderPosition (contentPosition, NavigationDirection.Forward); + var sliderPosition= scrollBar.CalculateSliderPositionFromContentPosition (contentPosition, NavigationDirection.Forward); // Assert Assert.Equal (expectedSliderPosition, sliderPosition); @@ -575,7 +575,7 @@ public class ScrollBarTests (ITestOutputHelper output) scrollBar.Frame = new (0, 0, visibleContentSize, 0); // Act - var contentPosition = scrollBar.CalculatePosition (sliderPosition); + var contentPosition = scrollBar.CalculatePositionFromSliderPosition (sliderPosition); // Assert Assert.Equal (expectedContentPosition, contentPosition); @@ -1150,7 +1150,7 @@ public class ScrollBarTests (ITestOutputHelper output) scrollBar.ScrollableContentSize = contentSize; scrollBar.Position = contentPosition; - int sliderPos = scrollBar.CalculateSliderPosition (contentPosition, NavigationDirection.Forward); + int sliderPos = scrollBar.CalculateSliderPositionFromContentPosition (contentPosition, NavigationDirection.Forward); super.BeginInit (); super.EndInit (); diff --git a/UnitTests/Views/ScrollSliderTests.cs b/UnitTests/Views/ScrollSliderTests.cs index b44101795..194645add 100644 --- a/UnitTests/Views/ScrollSliderTests.cs +++ b/UnitTests/Views/ScrollSliderTests.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Runtime.InteropServices; using Microsoft.VisualStudio.TestPlatform.Utilities; using Xunit.Abstractions; using static Unix.Terminal.Delegates; @@ -131,6 +132,73 @@ public class ScrollSliderTests (ITestOutputHelper output) Assert.True (scrollSlider.Size <= dimension); } + + [Theory] + [CombinatorialData] + + public void CalculateSize_ScrollBounds_0_Returns_1 ([CombinatorialRange (-1, 5, 1)] int visibleContentSize, [CombinatorialRange (-1, 5, 1)] int scrollableContentSize) + { + // Arrange + + // Act + var sliderSize = ScrollSlider.CalculateSize (scrollableContentSize, visibleContentSize, 0); + + // Assert + Assert.Equal (1, sliderSize); + } + + [Theory] + [CombinatorialData] + + public void CalculateSize_ScrollableContentSize_0_Returns_1 ([CombinatorialRange (-1, 5, 1)] int visibleContentSize, [CombinatorialRange (-1, 5, 1)] int sliderBounds) + { + // Arrange + + // Act + var sliderSize = ScrollSlider.CalculateSize (0, visibleContentSize, sliderBounds); + + // Assert + Assert.Equal (1, sliderSize); + } + + + //[Theory] + //[CombinatorialData] + + //public void CalculateSize_VisibleContentSize_0_Returns_0 ([CombinatorialRange (-1, 5, 1)] int scrollableContentSize, [CombinatorialRange (-1, 5, 1)] int sliderBounds) + //{ + // // Arrange + + // // Act + // var sliderSize = ScrollSlider.CalculateSize (scrollableContentSize, 0, sliderBounds); + + // // Assert + // Assert.Equal (0, sliderSize); + //} + + + [Theory] + [InlineData (0, 1, 1, 1)] + [InlineData (1, 1, 1, 1)] + [InlineData (1, 2, 1, 1)] + [InlineData (0, 5, 5, 5)] + [InlineData (1, 5, 5, 1)] + [InlineData (2, 5, 5, 2)] + [InlineData (3, 5, 5, 3)] + [InlineData (4, 5, 5, 4)] + [InlineData (5, 5, 5, 5)] + [InlineData (6, 5, 5, 5)] + public void CalculateSize_Calculates_Correctly (int visibleContentSize, int scrollableContentSize, int scrollBounds, int expectedSliderSize) + { + // Arrange + + // Act + var sliderSize = ScrollSlider.CalculateSize (scrollableContentSize, visibleContentSize, scrollBounds); + + // Assert + Assert.Equal (expectedSliderSize, sliderSize); + } + [Fact] public void VisibleContentSize_Not_Set_Uses_SuperView () { @@ -210,6 +278,269 @@ public class ScrollSliderTests (ITestOutputHelper output) Assert.InRange (scrollSlider.VisibleContentSize, 1, 10); } + [Theory] + //// 0123456789 + //// --------- + //// ◄█► + //[InlineData (3, 3, 0, 1, 0)] + //[InlineData (3, 3, 1, 1, 0)] + //[InlineData (3, 3, 2, 1, 0)] + + //// 0123456789 + //// --------- + //// ◄██► + //[InlineData (4, 4, 0, 2, 0)] + //[InlineData (4, 4, 1, 2, 0)] + //[InlineData (4, 4, 2, 2, 0)] + //[InlineData (4, 4, 3, 2, 0)] + //[InlineData (4, 4, 4, 2, 0)] + + // 012345 + // ^---- + // █░ + [InlineData (2, 5, 0, 0)] + // -^--- + // █░ + [InlineData (2, 5, 1, 0)] + // --^-- + // █░ + [InlineData (2, 5, 2, 0)] + // ---^- + // ░█ + [InlineData (2, 5, 3, 1)] + // ----^ + // ░█ + [InlineData (2, 5, 4, 1)] + + // 012345 + // ^---- + // █░░ + [InlineData (3, 5, 0, 0)] + // -^--- + // ░█░ + [InlineData (3, 5, 1, 1)] + // --^-- + // ░░█ + [InlineData (3, 5, 2, 2)] + // ---^- + // ░░█ + [InlineData (3, 5, 3, 2)] + // ----^ + // ░░█ + [InlineData (3, 5, 4, 2)] + + + // 0123456789 + // ^----- + // █░░ + [InlineData (3, 6, 0, 0)] + // -^---- + // █░░ + [InlineData (3, 6, 1, 0)] + // --^--- + // ░█░ + [InlineData (3, 6, 2, 1)] + // ---^-- + // ░░█ + [InlineData (3, 6, 3, 2)] + // ----^- + // ░░█ + [InlineData (3, 6, 4, 2)] + + // -----^ + // ░░█ + [InlineData (3, 6, 5, 2)] + + // 012345 + // ^---- + // ███░ + [InlineData (4, 5, 0, 0)] + // -^--- + // ░███ + [InlineData (4, 5, 1, 1)] + // --^-- + // ░███ + [InlineData (4, 5, 2, 1)] + // ---^- + // ░███ + [InlineData (4, 5, 3, 1)] + // ----^ + // ░███ + [InlineData (4, 5, 4, 1)] + + //// 01234 + //// ^--------- + //// ◄█░░► + //[InlineData (5, 10, 0, 1, 0)] + //// -^-------- + //// ◄█░░► + //[InlineData (5, 10, 1, 1, 0)] + //// --^------- + //// ◄█░░► + //[InlineData (5, 10, 2, 1, 0)] + //// ---^------ + //// ◄█░░► + //[InlineData (5, 10, 3, 1, 0)] + //// ----^---- + //// ◄░█░► + //[InlineData (5, 10, 4, 1, 1)] + //// -----^--- + //// ◄░█░► + //[InlineData (5, 10, 5, 1, 1)] + //// ------^-- + //// ◄░░█► + //[InlineData (5, 10, 6, 1, 2)] + //// ------^-- + //// ◄░░█► + //[InlineData (5, 10, 7, 1, 2)] + //// -------^- + //// ◄░░█► + //[InlineData (5, 10, 8, 1, 2)] + //// --------^ + //// ◄░░█► + //[InlineData (5, 10, 9, 1, 2)] + + // 0123456789 + // ████░░░░ + // ^----------------- + // 012345678901234567890123456789 + // ░████░░░ + // ----^------------- + // 012345678901234567890123456789 + // ░░████░░ + // --------^--------- + // 012345678901234567890123456789 + // ░░░████░ + // ------------^----- + // 012345678901234567890123456789 + // ░░░░████ + // ----------------^-- + + + + // 0123456789 + // ███░░░░░ + // ^----------------- + + // 012345678901234567890123456789 + // ░░███░░░ + // --------^--------- + // 012345678901234567890123456789 + // ░░░███░░ + // ------------^----- + // 012345678901234567890123456789 + // ░░░░███░ + // ----------------^-- + // 012345678901234567890123456789 + // ░░░░░███ + // ----------------^-- + + + [InlineData (8, 18, 0, 0)] + [InlineData (8, 18, 1, 0)] + // 012345678901234567890123456789 + // ░███░░░░ + // --^--------------- + [InlineData (8, 18, 2, 1)] + [InlineData (8, 18, 3, 1)] + [InlineData (8, 18, 4, 2)] + [InlineData (8, 18, 5, 2)] + [InlineData (8, 18, 6, 3)] + [InlineData (8, 18, 7, 3)] + [InlineData (8, 18, 8, 4)] + [InlineData (8, 18, 9, 4)] + + // 012345678901234567890123456789 + // ░░░░░███ + // ----------^-------- + [InlineData (8, 18, 10, 5)] + [InlineData (8, 18, 11, 5)] + [InlineData (8, 18, 12, 5)] + [InlineData (8, 18, 13, 5)] + [InlineData (8, 18, 14, 4)] + [InlineData (8, 18, 15, 5)] + [InlineData (8, 18, 16, 5)] + [InlineData (8, 18, 17, 5)] + [InlineData (8, 18, 18, 5)] + [InlineData (8, 18, 19, 5)] + [InlineData (8, 18, 20, 5)] + [InlineData (8, 18, 21, 5)] + [InlineData (8, 18, 22, 5)] + [InlineData (8, 18, 23, 5)] + // ------------------ ^ + [InlineData (8, 18, 24, 5)] + [InlineData (8, 18, 25, 5)] + + //// 0123456789 + //// ◄████░░░░► + //// ^----------------- + //[InlineData (10, 20, 0, 5, 0)] + //[InlineData (10, 20, 1, 5, 0)] + //[InlineData (10, 20, 2, 5, 0)] + //[InlineData (10, 20, 3, 5, 0)] + //[InlineData (10, 20, 4, 5, 1)] + //[InlineData (10, 20, 5, 5, 1)] + //[InlineData (10, 20, 6, 5, 1)] + //[InlineData (10, 20, 7, 5, 2)] + //[InlineData (10, 20, 8, 5, 2)] + //[InlineData (10, 20, 9, 5, 2)] + //[InlineData (10, 20, 10, 5, 3)] + //[InlineData (10, 20, 11, 5, 3)] + //[InlineData (10, 20, 12, 5, 3)] + //[InlineData (10, 20, 13, 5, 3)] + //[InlineData (10, 20, 14, 5, 4)] + //[InlineData (10, 20, 15, 5, 4)] + //[InlineData (10, 20, 16, 5, 4)] + //[InlineData (10, 20, 17, 5, 5)] + //[InlineData (10, 20, 18, 5, 5)] + //[InlineData (10, 20, 19, 5, 5)] + //[InlineData (10, 20, 20, 5, 6)] + //[InlineData (10, 20, 21, 5, 6)] + //[InlineData (10, 20, 22, 5, 6)] + //[InlineData (10, 20, 23, 5, 6)] + //[InlineData (10, 20, 24, 5, 6)] + //[InlineData (10, 20, 25, 5, 6)] + + public void CalculatePosition_Calculates_Correctly (int visibleContentSize, int scrollableContentSize, int contentPosition, int expectedSliderPosition) + { + // Arrange + + // Act + var sliderPosition = ScrollSlider.CalculatePosition ( + scrollableContentSize: scrollableContentSize, + visibleContentSize: visibleContentSize, + contentPosition: contentPosition, + sliderBounds: visibleContentSize, + NavigationDirection.Forward); + + // Assert + Assert.Equal (expectedSliderPosition, sliderPosition); + } + + [Theory] + [InlineData (8, 18, 0, 0)] + + public void CalculateContentPosition_Calculates_Correctly ( + int visibleContentSize, + int scrollableContentSize, + int sliderPosition, + int expectedContentPosition + ) + { + // Arrange + + // Act + var contentPosition = ScrollSlider.CalculateContentPosition ( + scrollableContentSize: scrollableContentSize, + visibleContentSize: visibleContentSize, + sliderPosition: sliderPosition, + sliderBounds: visibleContentSize); + + // Assert + Assert.Equal (expectedContentPosition, contentPosition); + } + + [Theory] [CombinatorialData] public void ClampPosition_WithSuperView_Clamps_To_ViewPort_Minus_Size_If_VisibleContentSize_Not_Set ([CombinatorialRange (10, 10, 1)] int dimension, [CombinatorialRange (1, 5, 1)] int sliderSize, [CombinatorialRange (-1, 10, 2)] int sliderPosition, Orientation orientation) @@ -228,7 +559,7 @@ public class ScrollSliderTests (ITestOutputHelper output) super.Add (scrollSlider); super.Layout (); - Assert.Equal(dimension, scrollSlider.VisibleContentSize); + Assert.Equal (dimension, scrollSlider.VisibleContentSize); int clampedPosition = scrollSlider.ClampPosition (sliderPosition); @@ -277,7 +608,7 @@ public class ScrollSliderTests (ITestOutputHelper output) [Theory] [CombinatorialData] - public void Position_Clamps_To_VisibleContentSize ([CombinatorialRange (0, 5, 1)] int dimension, [CombinatorialRange(1, 5, 1)] int sliderSize, [CombinatorialRange (-1, 10, 2)] int sliderPosition, Orientation orientation) + public void Position_Clamps_To_VisibleContentSize ([CombinatorialRange (0, 5, 1)] int dimension, [CombinatorialRange (1, 5, 1)] int sliderSize, [CombinatorialRange (-1, 10, 2)] int sliderPosition, Orientation orientation) { var scrollSlider = new ScrollSlider {