[NUI] Fix TV TCT fails (2nd)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Scrollbar.cs
1 /*
2  * Copyright(c) 2020 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17 using System;
18 using System.ComponentModel;
19 using Tizen.NUI.BaseComponents;
20 using Tizen.NUI.Binding;
21
22 namespace Tizen.NUI.Components
23 {
24     // Represents padding data : Start, End, Top, Bottom
25     using PaddingType = ValueTuple<ushort, ushort, ushort, ushort>;
26
27     /// <summary>
28     /// The Scrollbar is a component that contains track and thumb to indicate the current scrolled position of a scrollable object.
29     /// </summary>
30     [EditorBrowsable(EditorBrowsableState.Never)]
31     public class Scrollbar : ScrollbarBase
32     {
33         #region Fields
34
35         /// <summary>Bindable property of TrackThickness</summary>
36         [EditorBrowsable(EditorBrowsableState.Never)]
37         public static readonly BindableProperty TrackThicknessProperty = BindableProperty.Create(nameof(TrackThickness), typeof(float), typeof(Scrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
38         {
39             var instance = ((Scrollbar)bindable);
40             var thickness = (float?)newValue;
41
42             instance.scrollbarStyle.TrackThickness = thickness;
43             instance.UpdateTrackThickness(thickness ?? 0);
44         },
45         defaultValueCreator: (bindable) =>
46         {
47             return ((Scrollbar)bindable).scrollbarStyle.TrackThickness ?? 0;
48         });
49
50         /// <summary>Bindable property of ThumbThickness</summary>
51         [EditorBrowsable(EditorBrowsableState.Never)]
52         public static readonly BindableProperty ThumbThicknessProperty = BindableProperty.Create(nameof(ThumbThickness), typeof(float), typeof(Scrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
53         {
54             var instance = ((Scrollbar)bindable);
55             var thickness = (float?)newValue;
56
57             instance.scrollbarStyle.ThumbThickness = thickness;
58             instance.UpdateThumbThickness(thickness ?? 0);
59         },
60         defaultValueCreator: (bindable) =>
61         {
62             return ((Scrollbar)bindable).scrollbarStyle.ThumbThickness ?? 0;
63         });
64
65         /// <summary>Bindable property of TrackColor</summary>
66         [EditorBrowsable(EditorBrowsableState.Never)]
67         public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(Scrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
68         {
69             var instance = ((Scrollbar)bindable);
70             var color = (Color)newValue;
71
72             instance.scrollbarStyle.TrackColor = color;
73             instance.UpdateTrackColor(color);
74         },
75         defaultValueCreator: (bindable) =>
76         {
77             return ((Scrollbar)bindable).scrollbarStyle.TrackColor;
78         });
79
80         /// <summary>Bindable property of ThumbColor</summary>
81         [EditorBrowsable(EditorBrowsableState.Never)]
82         public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(Scrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
83         {
84             var instance = ((Scrollbar)bindable);
85             var color = (Color)newValue;
86
87             instance.scrollbarStyle.ThumbColor = color;
88             instance.UpdateThumbColor(color);
89         },
90         defaultValueCreator: (bindable) =>
91         {
92             return ((Scrollbar)bindable).scrollbarStyle.ThumbColor;
93         });
94
95         /// <summary>Bindable property of TrackPadding</summary>
96         [EditorBrowsable(EditorBrowsableState.Never)]
97         public static readonly BindableProperty TrackPaddingProperty = BindableProperty.Create(nameof(TrackPadding), typeof(Extents), typeof(Scrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
98         {
99             var instance = ((Scrollbar)bindable);
100             var trackPadding = (Extents)newValue;
101
102             instance.scrollbarStyle.TrackPadding = trackPadding;
103             instance.UpdateTrackPadding(trackPadding);
104         },
105         defaultValueCreator: (bindable) =>
106         {
107             return ((Scrollbar)bindable).scrollbarStyle.TrackPadding;
108         });
109
110         private ColorVisual trackVisual;
111         private ColorVisual thumbVisual;
112         private Animation thumbPositionAnimation;
113         private Animation thumbSizeAnimation;
114         private Calculator calculator;
115         private Size containerSize = new Size(0, 0);
116         private ScrollbarStyle scrollbarStyle => ViewStyle as ScrollbarStyle;
117         private bool mScrollEnabled = true;
118         private float previousPosition;
119
120         #endregion Fields
121
122
123         #region Constructors
124
125         /// <summary>
126         /// Create an empty Scrollbar.
127         /// </summary>
128         public Scrollbar() : base()
129         {
130         }
131
132         /// <summary>
133         /// Create a Scrollbar and initialize with properties.
134         /// </summary>
135         /// <param name="contentLength">The length of the scrollable content area.</param>
136         /// <param name="viewportLength">The length of the viewport representing the amount of visible content.</param>
137         /// <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>
138         /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical by default.</param>
139         [EditorBrowsable(EditorBrowsableState.Never)]
140         public Scrollbar(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false) : this()
141         {
142             Initialize(contentLength, viewportLength, currentPosition, isHorizontal);
143         }
144
145         /// <summary>
146         /// Create an empty Scrollbar with a ScrollbarStyle instance to set style properties.
147         /// </summary>
148         [EditorBrowsable(EditorBrowsableState.Never)]
149         public Scrollbar(ScrollbarStyle style) : base(style)
150         {
151         }
152
153         /// <summary>
154         /// Static constructor to initialize bindable properties when loading.
155         /// </summary>
156         static Scrollbar()
157         {
158         }
159
160         #endregion Constructors
161
162
163         #region Properties
164
165         /// <summary>
166         /// Return a copied Style instance of Scrollbar
167         /// </summary>
168         /// <remarks>
169         /// It returns copied Style instance and changing it does not effect to the Scrollbar.
170         /// Style setting is possible by using constructor or the function of ApplyStyle(ViewStyle viewStyle)
171         /// </remarks>
172         [EditorBrowsable(EditorBrowsableState.Never)]
173         public new ScrollbarStyle Style
174         {
175             get
176             {
177                 var result = new ScrollbarStyle(scrollbarStyle);
178                 result.CopyPropertiesFromView(this);
179                 return result;
180             }
181         }
182
183         /// <summary>
184         /// The thickness of the track.
185         /// </summary>
186         [EditorBrowsable(EditorBrowsableState.Never)]
187         public float TrackThickness
188         {
189             get => (float)GetValue(TrackThicknessProperty);
190             set => SetValue(TrackThicknessProperty, value);
191         }
192
193         /// <summary>
194         /// The thickness of the thumb.
195         /// </summary>
196         [EditorBrowsable(EditorBrowsableState.Never)]
197         public float ThumbThickness
198         {
199             get => (float)GetValue(ThumbThicknessProperty);
200             set => SetValue(ThumbThicknessProperty, value);
201         }
202
203         /// <summary>
204         /// The color of the track part.
205         /// </summary>
206         [EditorBrowsable(EditorBrowsableState.Never)]
207         public Color TrackColor
208         {
209             get => (Color)GetValue(TrackColorProperty);
210             set => SetValue(TrackColorProperty, value);
211         }
212
213         /// <summary>
214         /// The color of the thumb part.
215         /// </summary>
216         [EditorBrowsable(EditorBrowsableState.Never)]
217         public Color ThumbColor
218         {
219             get => (Color)GetValue(ThumbColorProperty);
220             set => SetValue(ThumbColorProperty, value);
221         }
222
223         /// <summary>
224         /// The padding value of the track.
225         /// Note that when the scrollbar is for vertical direction, Start value is ignored.
226         /// In case of horizontal direction, Top value is ignored.
227         /// </summary>
228         [EditorBrowsable(EditorBrowsableState.Never)]
229         public Extents TrackPadding
230         {
231             get => (Extents)GetValue(TrackPaddingProperty);
232             set => SetValue(TrackPaddingProperty, value);
233         }
234
235         #endregion Properties
236
237
238         #region Methods
239
240         /// <inheritdoc/>
241         [EditorBrowsable(EditorBrowsableState.Never)]
242         public override void Initialize(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false)
243         {
244             if (isHorizontal)
245             {
246                 calculator = new HorizontalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
247             }
248             else
249             {
250                 calculator = new VerticalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
251             }
252
253             thumbPositionAnimation?.Stop();
254             thumbPositionAnimation = null;
255
256             thumbSizeAnimation?.Stop();
257             thumbSizeAnimation = null;
258
259             PaddingType ensuredPadding = EnsurePadding(TrackPadding);
260             Size trackSize = calculator.CalculateTrackSize(TrackThickness, containerSize, ensuredPadding);
261             Vector2 trackPosition = calculator.CalculateTrackPosition(ensuredPadding);
262             Size thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackSize);
263             Vector2 thumbPosition = calculator.CalculateThumbPosition(trackSize, thumbSize, ensuredPadding);
264
265             trackVisual = new ColorVisual
266             {
267                 SuppressUpdateVisual = true,
268                 MixColor = TrackColor,
269                 SizePolicy = VisualTransformPolicyType.Absolute,
270                 Origin = calculator.CalculatorTrackAlign(),
271                 AnchorPoint = calculator.CalculatorTrackAlign(),
272                 Size = trackSize,
273                 Position = trackPosition,
274             };
275
276             AddVisual("Track", trackVisual);
277
278             thumbVisual = new ColorVisual
279             {
280                 SuppressUpdateVisual = true,
281                 MixColor = ThumbColor,
282                 SizePolicy = VisualTransformPolicyType.Absolute,
283                 Origin = calculator.CalculatorThumbAlign(),
284                 AnchorPoint = calculator.CalculatorThumbAlign(),
285                 Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f,
286                 Size = thumbSize,
287                 Position = thumbPosition,
288             };
289
290             AddVisual("Thumb", thumbVisual);
291         }
292
293         /// <inheritdoc/>
294         /// <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>
295         [EditorBrowsable(EditorBrowsableState.Never)]
296         public override void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
297         {
298             if (calculator == null)
299             {
300                 return;
301             }
302
303             calculator.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
304             previousPosition = calculator.currentPosition;
305             calculator.currentPosition = position;
306
307             thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
308             thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, EnsurePadding(TrackPadding));
309             thumbVisual.Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f;
310
311             if (durationMs == 0)
312             {
313                 thumbVisual.UpdateVisual(true);
314
315                 return;
316             }
317
318             // TODO Support non built-in alpha function for visual trainsition in DALi.
319             AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
320
321             thumbPositionAnimation?.Stop();
322             thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
323             thumbPositionAnimation.Play();
324
325             thumbSizeAnimation?.Stop();
326             thumbSizeAnimation = AnimateVisual(thumbVisual, "size", thumbVisual.Size, 0, (int)durationMs, builtinAlphaFunction);
327             thumbSizeAnimation.Play();
328         }
329
330         /// <inheritdoc/>
331         /// <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>
332         [EditorBrowsable(EditorBrowsableState.Never)]
333         public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
334         {
335             if (mScrollEnabled == false)
336             {
337                 return;
338             }
339
340             if (calculator == null)
341             {
342                 return;
343             }
344
345             previousPosition = calculator.currentPosition;
346             calculator.currentPosition = position;
347             thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, EnsurePadding(TrackPadding));
348
349             if (durationMs == 0)
350             {
351                 thumbVisual.UpdateVisual(true);
352
353                 return;
354             }
355
356             // TODO Support non built-in alpha function for visual trainsition in DALi.
357             AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
358
359             thumbPositionAnimation?.Stop();
360             thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
361             thumbPositionAnimation.Play();
362         }
363
364         /// <inheritdoc/>
365         [EditorBrowsable(EditorBrowsableState.Never)]
366         public override void OnRelayout(Vector2 size, RelayoutContainer container)
367         {
368             base.OnRelayout(size, container);
369
370             if (size.Width == containerSize.Width && size.Height == containerSize.Height)
371             {
372                 return;
373             }
374
375             containerSize = new Size(size.Width, size.Height);
376
377             if (calculator == null)
378             {
379                 return;
380             }
381
382             PaddingType ensuredPadding = EnsurePadding(TrackPadding);
383             trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, ensuredPadding);
384             trackVisual.Position = calculator.CalculateTrackPosition(ensuredPadding);
385             thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
386             thumbVisual.Position = calculator.CalculateThumbPosition(trackVisual.Size, thumbVisual.Size, ensuredPadding);
387
388             trackVisual.UpdateVisual(true);
389             thumbVisual.UpdateVisual(true);
390         }
391
392         /// <inheritdoc/>
393         [EditorBrowsable(EditorBrowsableState.Never)]
394         public override void ApplyStyle(ViewStyle viewStyle)
395         {
396             if (viewStyle is ScrollbarStyle scrollbarStyle)
397             {
398                 // Apply essential look.
399                 if (scrollbarStyle.TrackThickness == null) scrollbarStyle.TrackThickness = 6.0f;
400                 if (scrollbarStyle.ThumbThickness == null) scrollbarStyle.ThumbThickness = 6.0f;
401                 if (scrollbarStyle.TrackColor == null) scrollbarStyle.TrackColor = new Color(1.0f, 1.0f, 1.0f, 0.15f);
402                 if (scrollbarStyle.ThumbColor == null) scrollbarStyle.ThumbColor = new Color(0.6f, 0.6f, 0.6f, 1.0f);
403                 if (scrollbarStyle.TrackPadding == null) scrollbarStyle.TrackPadding = 4;
404                 if (scrollbarStyle.WidthResizePolicy == null) scrollbarStyle.WidthResizePolicy = ResizePolicyType.FillToParent;
405                 if (scrollbarStyle.HeightResizePolicy == null) scrollbarStyle.HeightResizePolicy = ResizePolicyType.FillToParent;
406             }
407
408             base.ApplyStyle(viewStyle);
409         }
410
411         /// <inheritdoc/>
412         [EditorBrowsable(EditorBrowsableState.Never)]
413         protected override ViewStyle CreateViewStyle()
414         {
415             return new ScrollbarStyle();
416         }
417
418         /// <summary>
419         /// Update TrackThickness property of the scrollbar.
420         /// </summary>
421         /// <param name="thickness">The width of the track.</param>
422         [EditorBrowsable(EditorBrowsableState.Never)]
423         protected virtual void UpdateTrackThickness(float thickness)
424         {
425             if (trackVisual == null)
426             {
427                 return;
428             }
429
430             trackVisual.Size = calculator.CalculateTrackSize(thickness, containerSize, EnsurePadding(TrackPadding));
431             trackVisual.UpdateVisual(true);
432         }
433
434         /// <summary>
435         /// Update ThumbThickness property of the scrollbar.
436         /// </summary>
437         /// <param name="thickness">The width of the track.</param>
438         [EditorBrowsable(EditorBrowsableState.Never)]
439         protected virtual void UpdateThumbThickness(float thickness)
440         {
441             if (thumbVisual == null)
442             {
443                 return;
444             }
445
446             thumbVisual.Size = calculator.CalculateThumbSize(thickness, trackVisual.Size);
447             thumbVisual.UpdateVisual(true);
448         }
449
450         /// <summary>
451         /// Update TrackColor property of the scrollbar.
452         /// </summary>
453         /// <param name="color">The color of the track.</param>
454         [EditorBrowsable(EditorBrowsableState.Never)]
455         protected virtual void UpdateTrackColor(Color color)
456         {
457             if (trackVisual == null)
458             {
459                 return;
460             }
461
462             trackVisual.MixColor = color;
463             trackVisual.UpdateVisual(true);
464         }
465
466         /// <summary>
467         /// Update ThumbColor property of the scrollbar.
468         /// </summary>
469         /// <param name="color">The color of the thumb.</param>
470         [EditorBrowsable(EditorBrowsableState.Never)]
471         protected virtual void UpdateThumbColor(Color color)
472         {
473             if (thumbVisual == null)
474             {
475                 return;
476             }
477
478             thumbVisual.MixColor = color;
479             thumbVisual.UpdateVisual(true);
480         }
481
482         /// <summary>
483         /// Update TrackPadding property of the scrollbar.
484         /// </summary>
485         /// <param name="trackPadding">The padding of the track.</param>
486         protected virtual void UpdateTrackPadding(Extents trackPadding)
487         {
488             if (calculator == null || trackVisual == null || thumbVisual == null)
489             {
490                 return;
491             }
492
493             PaddingType ensuredPadding = EnsurePadding(trackPadding);
494             trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, ensuredPadding);
495             trackVisual.Position = calculator.CalculateTrackPosition(ensuredPadding);
496             thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
497             thumbVisual.Position = calculator.CalculateThumbPaddingPosition(trackVisual.Size, thumbVisual.Size, thumbVisual.Position, ensuredPadding);
498
499             trackVisual.UpdateVisual(true);
500             thumbVisual.UpdateVisual(true);
501         }
502
503         /// <inheritdoc/>
504         [EditorBrowsable(EditorBrowsableState.Never)]
505         public override bool ScrollEnabled
506         {
507             get
508             {
509                 return mScrollEnabled;
510             }
511             set
512             {
513                 if (value != mScrollEnabled)
514                 {
515                     mScrollEnabled = value;
516                 }
517             }
518         }
519
520         /// <inheritdoc/>
521         [EditorBrowsable(EditorBrowsableState.Never)]
522         public override Position ScrollPosition
523         {
524             get
525             {
526                 if (calculator == null)
527                 {
528                     return new Position(0.0f, 0.0f);
529                 }
530
531                 float length = Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
532
533                 if (calculator is HorizontalCalculator)
534                 {
535                     return new Position(length, 0.0f);
536                 }
537                 else
538                 {
539                     return new Position(0.0f, length);
540                 }
541             }
542         }
543
544         /// <inheritdoc/>
545         [EditorBrowsable(EditorBrowsableState.Never)]
546         public override Position ScrollCurrentPosition
547         {
548             get
549             {
550                 if (calculator == null)
551                 {
552                     return new Position(0.0f, 0.0f);
553                 }
554
555                 float length = Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
556
557                 if (thumbPositionAnimation != null)
558                 {
559                     float progress = thumbPositionAnimation.CurrentProgress;
560                     float previousLength = Math.Min(Math.Max(previousPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
561
562                     length = ((1.0f - progress) * previousLength) + (progress * length);
563                 }
564
565                 if (calculator is HorizontalCalculator)
566                 {
567                     return new Position(length, 0.0f);
568                 }
569                 else
570                 {
571                     return new Position(0.0f, length);
572                 }
573             }
574         }
575
576         private PaddingType EnsurePadding(Extents padding) => padding == null ? new PaddingType(0, 0, 0 ,0) : new PaddingType(padding.Start, padding.End, padding.Top, padding.Bottom);
577
578         #endregion Methods
579
580
581         #region Classes
582
583         private abstract class Calculator
584         {
585             public float contentLength;
586             public float visibleLength;
587             public float currentPosition;
588
589             public Calculator(float contentLength, float visibleLength, float currentPosition)
590             {
591                 this.contentLength = contentLength;
592                 this.visibleLength = visibleLength;
593                 this.currentPosition = currentPosition;
594             }
595
596             public bool CalculateThumbVisibility()
597             {
598                 return contentLength > visibleLength;
599             }
600
601             public abstract Visual.AlignType CalculatorTrackAlign();
602             public abstract Visual.AlignType CalculatorThumbAlign();
603             public abstract Size CalculateTrackSize(float thickness, Size containerSize, PaddingType trackPadding);
604             public abstract Vector2 CalculateTrackPosition(PaddingType trackPadding);
605             public abstract Size CalculateThumbSize(float thickness, Size trackSize);
606             public abstract Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, PaddingType trackPadding);
607             public abstract Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, PaddingType trackPadding);
608             public abstract Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, PaddingType trackPadding);
609         }
610
611         private class HorizontalCalculator : Calculator
612         {
613             public HorizontalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
614             {
615             }
616
617             public override Visual.AlignType CalculatorTrackAlign()
618             {
619                 return Visual.AlignType.BottomBegin;
620             }
621
622             public override Visual.AlignType CalculatorThumbAlign()
623             {
624                 return Visual.AlignType.BottomBegin;
625             }
626
627             public override Size CalculateTrackSize(float thickness, Size containerSize, PaddingType trackPadding)
628             {
629                 return new Size(containerSize.Width - trackPadding.Item1 - trackPadding.Item2, thickness);
630             }
631
632             public override Vector2 CalculateTrackPosition(PaddingType trackPadding)
633             {
634                 return new Vector2(trackPadding.Item1, -trackPadding.Item4);
635             }
636
637             public override Size CalculateThumbSize(float thickness, Size trackSize)
638             {
639                 return new Size(trackSize.Width * visibleLength / contentLength, thickness);
640             }
641
642             public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, PaddingType trackPadding)
643             {
644                 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Item4;
645                 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
646                 return new Vector2(trackPadding.Item1 + trackSize.Width * pos / contentLength, -padding);
647             }
648
649             public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, PaddingType trackPadding)
650             {
651                 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Item4;
652                 return new Vector2(thumbCurrentPosition.X, -padding);
653             }
654
655             public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, PaddingType trackPadding)
656             {
657                 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
658                 return new Vector2(trackPadding.Item1 + trackSize.Width * pos / contentLength, thumbCurrentPosition.Y);
659             }
660         }
661
662         private class VerticalCalculator : Calculator
663         {
664             public VerticalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
665             {
666             }
667
668             public override Visual.AlignType CalculatorTrackAlign()
669             {
670                 return Visual.AlignType.TopEnd;
671             }
672
673             public override Visual.AlignType CalculatorThumbAlign()
674             {
675                 return Visual.AlignType.TopEnd;
676             }
677
678             public override Size CalculateTrackSize(float thickness, Size containerSize, PaddingType trackPadding)
679             {
680                 return new Size(thickness, containerSize.Height - trackPadding.Item3 - trackPadding.Item4);
681             }
682
683             public override Vector2 CalculateTrackPosition(PaddingType trackPadding)
684             {
685                 return new Vector2(-trackPadding.Item2, trackPadding.Item3);
686             }
687
688             public override Size CalculateThumbSize(float thickness, Size trackSize)
689             {
690                 return new Size(thickness, trackSize.Height * visibleLength / contentLength);
691             }
692
693             public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, PaddingType trackPadding)
694             {
695                 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.Item2;
696                 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
697                 return new Vector2(-padding, trackPadding.Item3 + trackSize.Height * pos / contentLength);
698             }
699
700             public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, PaddingType trackPadding)
701             {
702                 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.Item2;
703                 return new Vector2(-padding, thumbCurrentPosition.Y);
704             }
705
706             public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbPosition, PaddingType trackPadding)
707             {
708                 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
709                 return new Vector2(thumbPosition.X, trackPadding.Item3 + trackSize.Height * pos / contentLength);
710             }
711         }
712
713         #endregion Classes
714     }
715 }