2 * Copyright(c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.ComponentModel;
19 using System.Diagnostics;
20 using Tizen.NUI.BaseComponents;
21 using Tizen.NUI.Binding;
23 namespace Tizen.NUI.Components
25 // Represents padding data : Start, End, Top, Bottom
26 using PaddingType = ValueTuple<ushort, ushort, ushort, ushort>;
29 /// The Scrollbar is a component that contains track and thumb to indicate the current scrolled position of a scrollable object.
31 [EditorBrowsable(EditorBrowsableState.Never)]
32 public class Scrollbar : ScrollbarBase
36 /// <summary>Bindable property of TrackThickness</summary>
37 [EditorBrowsable(EditorBrowsableState.Never)]
38 public static readonly BindableProperty TrackThicknessProperty = BindableProperty.Create(nameof(TrackThickness), typeof(float), typeof(Scrollbar), default(float),
39 propertyChanged: (bindable, oldValue, newValue) => ((Scrollbar)bindable).UpdateTrackThickness((float?)newValue ?? 0),
40 defaultValueCreator: (bindable) => ((Scrollbar)bindable).trackThickness
43 /// <summary>Bindable property of ThumbThickness</summary>
44 [EditorBrowsable(EditorBrowsableState.Never)]
45 public static readonly BindableProperty ThumbThicknessProperty = BindableProperty.Create(nameof(ThumbThickness), typeof(float), typeof(Scrollbar), default(float),
46 propertyChanged: (bindable, oldValue, newValue) => ((Scrollbar)bindable).UpdateThumbThickness((float?)newValue ?? 0),
47 defaultValueCreator: (bindable) => ((Scrollbar)bindable).thumbThickness
50 /// <summary>Bindable property of TrackColor</summary>
51 [EditorBrowsable(EditorBrowsableState.Never)]
52 public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(Scrollbar), null,
53 propertyChanged: (bindable, oldValue, newValue) => ((Scrollbar)bindable).trackView.BackgroundColor = (Color)newValue,
54 defaultValueCreator: (bindable) => ((Scrollbar)bindable).trackView.BackgroundColor
57 /// <summary>Bindable property of ThumbColor</summary>
58 [EditorBrowsable(EditorBrowsableState.Never)]
59 public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(Scrollbar), null,
60 propertyChanged: (bindable, oldValue, newValue) => ((Scrollbar)bindable).UpdateThumbColor((Color)newValue),
61 defaultValueCreator: (bindable) => ((Scrollbar)bindable).thumbColor
64 /// <summary>Bindable property of TrackPadding</summary>
65 [EditorBrowsable(EditorBrowsableState.Never)]
66 public static readonly BindableProperty TrackPaddingProperty = BindableProperty.Create(nameof(TrackPadding), typeof(Extents), typeof(Scrollbar), null,
67 propertyChanged: (bindable, oldValue, newValue) => ((Scrollbar)bindable).UpdateTrackPadding((Extents)newValue),
68 defaultValueCreator: (bindable) => ((Scrollbar)bindable).trackPadding
71 /// <summary>Bindable property of ThumbVerticalImageUrl</summary>
72 [EditorBrowsable(EditorBrowsableState.Never)]
73 public static readonly BindableProperty ThumbVerticalImageUrlProperty = BindableProperty.Create(nameof(ThumbVerticalImageUrl), typeof(string), typeof(Scrollbar), null,
74 propertyChanged: (bindable, oldValue, newValue) => ((Scrollbar)bindable).UpdateThumbImage((string)newValue, false),
75 defaultValueCreator: (bindable) => ((Scrollbar)bindable).thumbVerticalImageUrl
78 /// <summary>Bindable property of ThumbHorizontalImageUrl</summary>
79 [EditorBrowsable(EditorBrowsableState.Never)]
80 public static readonly BindableProperty ThumbHorizontalImageUrlProperty = BindableProperty.Create(nameof(ThumbHorizontalImageUrl), typeof(string), typeof(Scrollbar), null,
81 propertyChanged: (bindable, oldValue, newValue) => ((Scrollbar)bindable).UpdateThumbImage((string)newValue, true),
82 defaultValueCreator: (bindable) => ((Scrollbar)bindable).thumbHorizontalImageUrl
86 private View trackView;
87 private ImageView thumbView;
88 private Animation thumbPositionAnimation;
89 private Animation thumbSizeAnimation;
90 private Animation opacityAnimation;
91 private Calculator calculator;
92 private Size containerSize = new Size(0, 0);
93 private float previousPosition;
94 private float trackThickness = 6.0f;
95 private float thumbThickness = 6.0f;
96 private string thumbVerticalImageUrl;
97 private string thumbHorizontalImageUrl;
98 private Color thumbColor;
99 private PaddingType trackPadding = new PaddingType(4, 4, 4, 4);
100 private bool isHorizontal;
108 /// Create an empty Scrollbar.
115 /// Create a Scrollbar and initialize with properties.
117 /// <param name="contentLength">The length of the scrollable content area.</param>
118 /// <param name="viewportLength">The length of the viewport representing the amount of visible content.</param>
119 /// <param name="currentPosition">The current position of the viewport in scrollable content area. This is the viewport's top position if the scroller is vertical, otherwise, left.</param>
120 /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical by default.</param>
121 [EditorBrowsable(EditorBrowsableState.Never)]
122 public Scrollbar(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false) : this()
124 Initialize(contentLength, viewportLength, currentPosition, isHorizontal);
128 /// Create an empty Scrollbar with a ScrollbarStyle instance to set style properties.
130 [EditorBrowsable(EditorBrowsableState.Never)]
131 public Scrollbar(ScrollbarStyle style) : base(style)
136 /// Static constructor to initialize bindable properties when loading.
142 #endregion Constructors
148 /// The thickness of the track.
150 [EditorBrowsable(EditorBrowsableState.Never)]
151 public float TrackThickness
153 get => (float)GetValue(TrackThicknessProperty);
154 set => SetValue(TrackThicknessProperty, value);
158 /// The thickness of the thumb.
160 [EditorBrowsable(EditorBrowsableState.Never)]
161 public float ThumbThickness
163 get => (float)GetValue(ThumbThicknessProperty);
164 set => SetValue(ThumbThicknessProperty, value);
168 /// The color of the track part.
170 [EditorBrowsable(EditorBrowsableState.Never)]
171 public Color TrackColor
173 get => (Color)GetValue(TrackColorProperty);
174 set => SetValue(TrackColorProperty, value);
178 /// The color of the thumb part.
180 [EditorBrowsable(EditorBrowsableState.Never)]
181 public Color ThumbColor
183 get => (Color)GetValue(ThumbColorProperty);
184 set => SetValue(ThumbColorProperty, value);
188 /// The padding value of the track.
189 /// Note that when the scrollbar is for vertical direction, Start value is ignored.
190 /// In case of horizontal direction, Top value is ignored.
192 [EditorBrowsable(EditorBrowsableState.Never)]
193 public Extents TrackPadding
195 get => (Extents)GetValue(TrackPaddingProperty);
196 set => SetValue(TrackPaddingProperty, value);
200 /// The image url of the vertical thumb.
202 [EditorBrowsable(EditorBrowsableState.Never)]
203 public string ThumbVerticalImageUrl
205 get => (string)GetValue(ThumbVerticalImageUrlProperty);
206 set => SetValue(ThumbVerticalImageUrlProperty, value);
210 /// The image url of the horizontal thumb.
212 [EditorBrowsable(EditorBrowsableState.Never)]
213 public string ThumbHorizontalImageUrl
215 get => (string)GetValue(ThumbHorizontalImageUrlProperty);
216 set => SetValue(ThumbHorizontalImageUrlProperty, value);
220 [EditorBrowsable(EditorBrowsableState.Never)]
221 public override float ScrollPosition
225 if (calculator == null)
230 return Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
235 [EditorBrowsable(EditorBrowsableState.Never)]
236 public override float ScrollCurrentPosition
240 if (calculator == null)
245 float length = Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
247 if (thumbPositionAnimation != null)
249 float progress = thumbPositionAnimation.CurrentProgress;
250 float previousLength = Math.Min(Math.Max(previousPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
252 length = ((1.0f - progress) * previousLength) + (progress * length);
259 #endregion Properties
265 [EditorBrowsable(EditorBrowsableState.Never)]
266 public override void OnInitialize()
270 trackView = new View()
272 PositionUsesPivotPoint = true,
273 BackgroundColor = new Color(1.0f, 1.0f, 1.0f, 0.15f)
277 thumbView = new ImageView()
279 PositionUsesPivotPoint = true,
280 BackgroundColor = new Color(0.6f, 0.6f, 0.6f, 1.0f)
284 WidthResizePolicy = ResizePolicyType.FillToParent;
285 HeightResizePolicy = ResizePolicyType.FillToParent;
287 EnableControlState = false;
291 [EditorBrowsable(EditorBrowsableState.Never)]
292 public override void Initialize(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false)
294 this.isHorizontal = isHorizontal;
297 if (thumbHorizontalImageUrl != null)
299 thumbView.ResourceUrl = thumbHorizontalImageUrl;
300 thumbView.Color = thumbColor;
301 thumbView.BackgroundColor = Color.Transparent;
303 calculator = new HorizontalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
307 if (thumbVerticalImageUrl != null)
309 thumbView.ResourceUrl = thumbVerticalImageUrl;
310 thumbView.Color = thumbColor;
311 thumbView.BackgroundColor = Color.Transparent;
313 calculator = new VerticalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
316 thumbPositionAnimation?.Clear();
317 thumbPositionAnimation = null;
319 thumbSizeAnimation?.Clear();
320 thumbSizeAnimation = null;
322 opacityAnimation?.Clear();
323 opacityAnimation = null;
325 var trackSize = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
326 var trackPosition = calculator.CalculateTrackPosition(trackPadding);
327 var thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackSize);
328 var thumbPosition = calculator.CalculateThumbPosition(trackSize, thumbSize, trackPadding);
330 Debug.Assert(trackView != null);
331 trackView.ParentOrigin = calculator.CalculatorTrackAlign();
332 trackView.PivotPoint = calculator.CalculatorTrackAlign();
333 trackView.Size = trackSize;
334 trackView.Position = trackPosition;
336 Debug.Assert(thumbView != null);
337 thumbView.ParentOrigin = calculator.CalculatorThumbAlign();
338 thumbView.PivotPoint = calculator.CalculatorThumbAlign();
339 thumbView.Size = thumbSize;
340 thumbView.Position = thumbPosition;;
342 Opacity = calculator.IsScrollable() ? 1.0f : 0.0f;
346 /// <exception cref="InvalidOperationException">Thrown when the scrollabr not yet initialized.</exception>
347 [EditorBrowsable(EditorBrowsableState.Never)]
348 public override void Update(float contentLength, float viewportLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
350 if (calculator == null)
352 throw new InvalidOperationException("Scrollbar is not initialized. Please call Initialize() first.");
355 calculator.visibleLength = viewportLength;
356 Update(contentLength, position, durationMs, alphaFunction);
360 /// <exception cref="InvalidOperationException">Thrown when the scrollabr not yet initialized.</exception>
361 [EditorBrowsable(EditorBrowsableState.Never)]
362 public override void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
364 if (calculator == null)
366 throw new InvalidOperationException("Scrollbar is not initialized. Please call Initialize() first.");
369 calculator.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
370 calculator.currentPosition = position;
372 float newOpacity = calculator.IsScrollable() ? 1.0f : 0.0f;
373 bool opacityChanged = (int)Opacity != (int)newOpacity;
375 var thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackView.Size);
376 var thumbPosition = calculator.CalculateThumbScrollPosition(trackView.Size, thumbView.Position, trackPadding);
380 thumbView.Position = thumbPosition;
381 thumbView.Size = thumbSize;
385 Opacity = newOpacity;
390 EnsureThumbPositionAnimation().AnimateTo(thumbView, "Position", thumbPosition, 0, (int)durationMs, alphaFunction);
391 thumbPositionAnimation.Play();
393 EnsureThumbSizeAnimation().AnimateTo(thumbView, "Size", thumbSize, 0, (int)durationMs, alphaFunction);
394 thumbSizeAnimation.Play();
398 EnsureOpacityAnimation().AnimateTo(this, "Opacity", newOpacity, 0, (int)durationMs, alphaFunction);
399 opacityAnimation.Play();
404 /// <remarks>Please note that, for now, only alpha functions created with BuiltinFunctions are valid when animating. Otherwise, it will be treated as a linear alpha function. </remarks>
405 [EditorBrowsable(EditorBrowsableState.Never)]
406 public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
408 if (ControlState == ControlState.Disabled)
413 if (calculator == null)
418 previousPosition = calculator.currentPosition;
419 calculator.currentPosition = position;
420 var thumbPosition = calculator.CalculateThumbScrollPosition(trackView.Size, thumbView.Position, trackPadding);
424 thumbView.Position = thumbPosition;
428 EnsureThumbPositionAnimation().AnimateTo(thumbView, "position", thumbPosition, 0, (int)durationMs, alphaFunction);
429 thumbPositionAnimation.Play();
433 [EditorBrowsable(EditorBrowsableState.Never)]
434 public override void OnRelayout(Vector2 size, RelayoutContainer container)
436 base.OnRelayout(size, container);
438 if (size.Width == containerSize.Width && size.Height == containerSize.Height)
443 containerSize = new Size(size.Width, size.Height);
445 if (calculator == null)
450 trackView.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
451 trackView.Position = calculator.CalculateTrackPosition(trackPadding);
452 thumbView.Size = calculator.CalculateThumbSize(ThumbThickness, trackView.Size);
453 thumbView.Position = calculator.CalculateThumbPosition(trackView.Size, thumbView.Size, trackPadding);
457 [EditorBrowsable(EditorBrowsableState.Never)]
458 public override void ApplyStyle(ViewStyle viewStyle)
460 if (viewStyle is ScrollbarStyle scrollbarStyle)
462 // Apply essential look.
463 if (scrollbarStyle.TrackThickness == null) scrollbarStyle.TrackThickness = 6.0f;
464 if (scrollbarStyle.ThumbThickness == null) scrollbarStyle.ThumbThickness = 6.0f;
465 if (scrollbarStyle.TrackColor == null) scrollbarStyle.TrackColor = new Color(1.0f, 1.0f, 1.0f, 0.15f);
466 if (scrollbarStyle.ThumbColor == null) scrollbarStyle.ThumbColor = new Color(0.6f, 0.6f, 0.6f, 1.0f);
467 if (scrollbarStyle.TrackPadding == null) scrollbarStyle.TrackPadding = 4;
468 if (scrollbarStyle.WidthResizePolicy == null) scrollbarStyle.WidthResizePolicy = ResizePolicyType.FillToParent;
469 if (scrollbarStyle.HeightResizePolicy == null) scrollbarStyle.HeightResizePolicy = ResizePolicyType.FillToParent;
472 base.ApplyStyle(viewStyle);
476 [EditorBrowsable(EditorBrowsableState.Never)]
477 protected override ViewStyle CreateViewStyle()
479 return new ScrollbarStyle();
483 /// Update TrackThickness property of the scrollbar.
485 /// <param name="thickness">The width of the track.</param>
486 private void UpdateTrackThickness(float thickness)
488 trackThickness = thickness;
490 if (calculator == null)
495 trackView.Size = calculator.CalculateTrackSize(thickness, containerSize, trackPadding);
499 /// Update ThumbThickness property of the scrollbar.
501 /// <param name="thickness">The width of the track.</param>
502 private void UpdateThumbThickness(float thickness)
504 thumbThickness = thickness;
506 if (calculator == null)
511 thumbView.Size = calculator.CalculateThumbSize(thickness, trackView.Size);
515 /// Update TrackPadding property of the scrollbar.
517 /// <param name="padding">The padding of the track.</param>
518 private void UpdateTrackPadding(Extents padding)
520 trackPadding = padding == null ? new PaddingType(0, 0, 0, 0) : new PaddingType(padding.Start, padding.End, padding.Top, padding.Bottom);
522 if (calculator == null)
527 trackView.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
528 trackView.Position = calculator.CalculateTrackPosition(trackPadding);
529 thumbView.Size = calculator.CalculateThumbSize(ThumbThickness, trackView.Size);
530 thumbView.Position = calculator.CalculateThumbPaddingPosition(trackView.Size, thumbView.Size, thumbView.Position, trackPadding);
532 private void UpdateThumbColor(Color color)
535 if (!String.IsNullOrEmpty(thumbView.ResourceUrl))
537 thumbView.Color = color;
538 thumbView.BackgroundColor = Color.Transparent;
542 thumbView.BackgroundColor = color;
546 private void UpdateThumbImage(string url, bool isHorizontal)
550 thumbHorizontalImageUrl = url;
551 if (this.isHorizontal)
553 thumbView.ResourceUrl = url;
554 thumbView.Color = thumbColor;
555 thumbView.BackgroundColor = Color.Transparent;
560 thumbVerticalImageUrl = url;
561 if (!this.isHorizontal)
563 thumbView.ResourceUrl = url;
564 thumbView.Color = thumbColor;
565 thumbView.BackgroundColor = Color.Transparent;
570 private Animation EnsureThumbPositionAnimation()
572 if (thumbPositionAnimation == null)
574 thumbPositionAnimation = new Animation();
578 thumbPositionAnimation.Stop();
579 thumbPositionAnimation.Clear();
581 return thumbPositionAnimation;
584 private Animation EnsureThumbSizeAnimation()
586 if (thumbSizeAnimation == null)
588 thumbSizeAnimation = new Animation();
592 thumbSizeAnimation.Stop();
593 thumbSizeAnimation.Clear();
595 return thumbSizeAnimation;
598 private Animation EnsureOpacityAnimation()
600 if (opacityAnimation == null)
602 opacityAnimation = new Animation();
606 opacityAnimation.Stop();
607 opacityAnimation.Clear();
609 return opacityAnimation;
617 private abstract class Calculator
619 public float contentLength;
620 public float visibleLength;
621 public float currentPosition;
623 public Calculator(float contentLength, float visibleLength, float currentPosition)
625 this.contentLength = contentLength;
626 this.visibleLength = visibleLength;
627 this.currentPosition = currentPosition;
630 public bool IsScrollable()
632 return contentLength > visibleLength;
635 public abstract Position CalculatorTrackAlign();
636 public abstract Position CalculatorThumbAlign();
637 public abstract Size CalculateTrackSize(float thickness, Size containerSize, PaddingType trackPadding);
638 public abstract Position CalculateTrackPosition(PaddingType trackPadding);
639 public abstract Size CalculateThumbSize(float thickness, Size trackSize);
640 public abstract Position CalculateThumbPosition(Size trackSize, Size thumbSize, PaddingType trackPadding);
641 public abstract Position CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Position thumbCurrentPosition, PaddingType trackPadding);
642 public abstract Position CalculateThumbScrollPosition(Size trackSize, Position thumbCurrentPosition, PaddingType trackPadding);
645 private class HorizontalCalculator : Calculator
647 public HorizontalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
651 public override Position CalculatorTrackAlign()
653 return Tizen.NUI.ParentOrigin.BottomLeft;
656 public override Position CalculatorThumbAlign()
658 return Tizen.NUI.ParentOrigin.BottomLeft;
661 public override Size CalculateTrackSize(float thickness, Size containerSize, PaddingType trackPadding)
663 return new Size(containerSize.Width - trackPadding.Item1 - trackPadding.Item2, thickness);
666 public override Position CalculateTrackPosition(PaddingType trackPadding)
668 return new Position(trackPadding.Item1, -trackPadding.Item4);
671 public override Size CalculateThumbSize(float thickness, Size trackSize)
673 return new Size(trackSize.Width * (IsScrollable() ? (visibleLength / contentLength) : 0.0f), thickness);
676 public override Position CalculateThumbPosition(Size trackSize, Size thumbSize, PaddingType trackPadding)
678 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Item4;
679 return new Position(trackPadding.Item1 + (IsScrollable() ? (trackSize.Width * (Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength)) / contentLength) : 0.0f), -padding);
682 public override Position CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Position thumbCurrentPosition, PaddingType trackPadding)
684 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Item4;
685 return new Position(thumbCurrentPosition.X, -padding);
688 public override Position CalculateThumbScrollPosition(Size trackSize, Position thumbCurrentPosition, PaddingType trackPadding)
690 return new Position(trackPadding.Item1 + (IsScrollable() ? (trackSize.Width * (Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength)) / contentLength) : 0.0f), thumbCurrentPosition.Y);
694 private class VerticalCalculator : Calculator
696 public VerticalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
700 public override Position CalculatorTrackAlign()
702 return Tizen.NUI.ParentOrigin.TopRight;
705 public override Position CalculatorThumbAlign()
707 return Tizen.NUI.ParentOrigin.TopRight;
710 public override Size CalculateTrackSize(float thickness, Size containerSize, PaddingType trackPadding)
712 return new Size(thickness, containerSize.Height - trackPadding.Item3 - trackPadding.Item4);
715 public override Position CalculateTrackPosition(PaddingType trackPadding)
717 return new Position(-trackPadding.Item2, trackPadding.Item3);
720 public override Size CalculateThumbSize(float thickness, Size trackSize)
722 return new Size(thickness, trackSize.Height * (IsScrollable() ? (visibleLength / contentLength) : 0.0f));
725 public override Position CalculateThumbPosition(Size trackSize, Size thumbSize, PaddingType trackPadding)
727 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.Item2;
728 return new Position(-padding, trackPadding.Item3 + (IsScrollable() ? (trackSize.Height * Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength) / contentLength) : 0.0f));
731 public override Position CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Position thumbCurrentPosition, PaddingType trackPadding)
733 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.Item2;
734 return new Position(-padding, thumbCurrentPosition.Y);
737 public override Position CalculateThumbScrollPosition(Size trackSize, Position thumbPosition, PaddingType trackPadding)
739 return new Position(thumbPosition.X, trackPadding.Item3 + (IsScrollable() ? (trackSize.Height * Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength) / contentLength) : 0.0f));