[NUI] fix scroll bar resources and add samples
[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 System.Diagnostics;
20 using Tizen.NUI.BaseComponents;
21 using Tizen.NUI.Binding;
22
23 namespace Tizen.NUI.Components
24 {
25     // Represents padding data : Start, End, Top, Bottom
26     using PaddingType = ValueTuple<ushort, ushort, ushort, ushort>;
27
28     /// <summary>
29     /// The Scrollbar is a component that contains track and thumb to indicate the current scrolled position of a scrollable object.
30     /// </summary>
31     [EditorBrowsable(EditorBrowsableState.Never)]
32     public class Scrollbar : ScrollbarBase
33     {
34         #region Fields
35
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
41         );
42
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
48         );
49
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
55         );
56
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
62         );
63
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
69         );
70
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
76         );
77
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
83         );
84
85
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;
101
102         #endregion Fields
103
104
105         #region Constructors
106
107         /// <summary>
108         /// Create an empty Scrollbar.
109         /// </summary>
110         public Scrollbar()
111         {
112         }
113
114         /// <summary>
115         /// Create a Scrollbar and initialize with properties.
116         /// </summary>
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()
123         {
124             Initialize(contentLength, viewportLength, currentPosition, isHorizontal);
125         }
126
127         /// <summary>
128         /// Create an empty Scrollbar with a ScrollbarStyle instance to set style properties.
129         /// </summary>
130         [EditorBrowsable(EditorBrowsableState.Never)]
131         public Scrollbar(ScrollbarStyle style) : base(style)
132         {
133         }
134
135         /// <summary>
136         /// Static constructor to initialize bindable properties when loading.
137         /// </summary>
138         static Scrollbar()
139         {
140         }
141
142         #endregion Constructors
143
144
145         #region Properties
146
147         /// <summary>
148         /// The thickness of the track.
149         /// </summary>
150         [EditorBrowsable(EditorBrowsableState.Never)]
151         public float TrackThickness
152         {
153             get => (float)GetValue(TrackThicknessProperty);
154             set => SetValue(TrackThicknessProperty, value);
155         }
156
157         /// <summary>
158         /// The thickness of the thumb.
159         /// </summary>
160         [EditorBrowsable(EditorBrowsableState.Never)]
161         public float ThumbThickness
162         {
163             get => (float)GetValue(ThumbThicknessProperty);
164             set => SetValue(ThumbThicknessProperty, value);
165         }
166
167         /// <summary>
168         /// The color of the track part.
169         /// </summary>
170         [EditorBrowsable(EditorBrowsableState.Never)]
171         public Color TrackColor
172         {
173             get => (Color)GetValue(TrackColorProperty);
174             set => SetValue(TrackColorProperty, value);
175         }
176
177         /// <summary>
178         /// The color of the thumb part.
179         /// </summary>
180         [EditorBrowsable(EditorBrowsableState.Never)]
181         public Color ThumbColor
182         {
183             get => (Color)GetValue(ThumbColorProperty);
184             set => SetValue(ThumbColorProperty, value);
185         }
186
187         /// <summary>
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.
191         /// </summary>
192         [EditorBrowsable(EditorBrowsableState.Never)]
193         public Extents TrackPadding
194         {
195             get => (Extents)GetValue(TrackPaddingProperty);
196             set => SetValue(TrackPaddingProperty, value);
197         }
198
199         /// <summary>
200         /// The image url of the vertical thumb.
201         /// </summary>
202         [EditorBrowsable(EditorBrowsableState.Never)]
203         public string ThumbVerticalImageUrl
204         {
205             get => (string)GetValue(ThumbVerticalImageUrlProperty);
206             set => SetValue(ThumbVerticalImageUrlProperty, value);
207         }
208
209         /// <summary>
210         /// The image url of the horizontal thumb.
211         /// </summary>
212         [EditorBrowsable(EditorBrowsableState.Never)]
213         public string ThumbHorizontalImageUrl
214         {
215             get => (string)GetValue(ThumbHorizontalImageUrlProperty);
216             set => SetValue(ThumbHorizontalImageUrlProperty, value);
217         }
218
219         /// <inheritdoc/>
220         [EditorBrowsable(EditorBrowsableState.Never)]
221         public override float ScrollPosition
222         {
223             get
224             {
225                 if (calculator == null)
226                 {
227                     return 0.0f;
228                 }
229
230                 return Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
231             }
232         }
233
234         /// <inheritdoc/>
235         [EditorBrowsable(EditorBrowsableState.Never)]
236         public override float ScrollCurrentPosition
237         {
238             get
239             {
240                 if (calculator == null)
241                 {
242                     return 0.0f;
243                 }
244
245                 float length = Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
246
247                 if (thumbPositionAnimation != null)
248                 {
249                     float progress = thumbPositionAnimation.CurrentProgress;
250                     float previousLength = Math.Min(Math.Max(previousPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
251
252                     length = ((1.0f - progress) * previousLength) + (progress * length);
253                 }
254
255                 return length;
256             }
257         }
258
259         #endregion Properties
260
261
262         #region Methods
263
264         /// <inheritdoc/>
265         [EditorBrowsable(EditorBrowsableState.Never)]
266         public override void OnInitialize()
267         {
268             base.OnInitialize();
269
270             trackView = new View()
271             {
272                 PositionUsesPivotPoint = true,
273                 BackgroundColor = new Color(1.0f, 1.0f, 1.0f, 0.15f)
274             };
275             Add(trackView);
276
277             thumbView = new ImageView()
278             {
279                 PositionUsesPivotPoint = true,
280                 BackgroundColor = new Color(0.6f, 0.6f, 0.6f, 1.0f)
281             };
282             Add(thumbView);
283
284             WidthResizePolicy = ResizePolicyType.FillToParent;
285             HeightResizePolicy = ResizePolicyType.FillToParent;
286         }
287
288         /// <inheritdoc/>
289         [EditorBrowsable(EditorBrowsableState.Never)]
290         public override void Initialize(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false)
291         {
292             this.isHorizontal = isHorizontal;
293             if (isHorizontal)
294             {
295                 if (thumbHorizontalImageUrl != null)
296                 {
297                     thumbView.ResourceUrl = thumbHorizontalImageUrl;
298                     thumbView.Color = thumbColor;
299                     thumbView.BackgroundColor = Color.Transparent;
300                 }
301                 calculator = new HorizontalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
302             }
303             else
304             {
305                 if (thumbVerticalImageUrl != null)
306                 {
307                     thumbView.ResourceUrl = thumbVerticalImageUrl;
308                     thumbView.Color = thumbColor;
309                     thumbView.BackgroundColor = Color.Transparent;
310                 }
311                 calculator = new VerticalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
312             }
313
314             thumbPositionAnimation?.Clear();
315             thumbPositionAnimation = null;
316
317             thumbSizeAnimation?.Clear();
318             thumbSizeAnimation = null;
319
320             opacityAnimation?.Clear();
321             opacityAnimation = null;
322
323             var trackSize = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
324             var trackPosition = calculator.CalculateTrackPosition(trackPadding);
325             var thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackSize);
326             var thumbPosition = calculator.CalculateThumbPosition(trackSize, thumbSize, trackPadding);
327
328             Debug.Assert(trackView != null);
329             trackView.ParentOrigin = calculator.CalculatorTrackAlign();
330             trackView.PivotPoint = calculator.CalculatorTrackAlign();
331             trackView.Size = trackSize;
332             trackView.Position = trackPosition;
333
334             Debug.Assert(thumbView != null);
335             thumbView.ParentOrigin = calculator.CalculatorThumbAlign();
336             thumbView.PivotPoint = calculator.CalculatorThumbAlign();
337             thumbView.Size = thumbSize;
338             thumbView.Position = thumbPosition;;
339
340             Opacity = calculator.IsScrollable() ? 1.0f : 0.0f;
341         }
342
343         /// <inheritdoc/>
344         /// <exception cref="InvalidOperationException">Thrown when the scrollabr not yet initialized.</exception>
345         [EditorBrowsable(EditorBrowsableState.Never)]
346         public override void Update(float contentLength, float viewportLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
347         {
348             if (calculator == null)
349             {
350                 throw new InvalidOperationException("Scrollbar is not initialized. Please call Initialize() first.");
351             }
352
353             calculator.visibleLength = viewportLength;
354             Update(contentLength, position, durationMs, alphaFunction);
355         }
356
357         /// <inheritdoc/>
358         /// <exception cref="InvalidOperationException">Thrown when the scrollabr not yet initialized.</exception>
359         [EditorBrowsable(EditorBrowsableState.Never)]
360         public override void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
361         {
362             if (calculator == null)
363             {
364                 throw new InvalidOperationException("Scrollbar is not initialized. Please call Initialize() first.");
365             }
366
367             calculator.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
368             calculator.currentPosition = position;
369
370             float newOpacity = calculator.IsScrollable() ? 1.0f : 0.0f;
371             bool opacityChanged = (int)Opacity != (int)newOpacity;
372
373             var thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackView.Size);
374             var thumbPosition = calculator.CalculateThumbScrollPosition(trackView.Size, thumbView.Position, trackPadding);
375
376             if (durationMs == 0)
377             {
378                 thumbView.Position = thumbPosition;
379                 thumbView.Size = thumbSize;
380
381                 if (opacityChanged)
382                 {
383                     Opacity = newOpacity;
384                 }
385                 return;
386             }
387
388             EnsureThumbPositionAnimation().AnimateTo(thumbView, "Position", thumbPosition, 0, (int)durationMs, alphaFunction);
389             thumbPositionAnimation.Play();
390
391             EnsureThumbSizeAnimation().AnimateTo(thumbView, "Size", thumbSize, 0, (int)durationMs, alphaFunction);
392             thumbSizeAnimation.Play();
393
394             if (opacityChanged)
395             {
396                 EnsureOpacityAnimation().AnimateTo(this, "Opacity", newOpacity, 0, (int)durationMs, alphaFunction);
397                 opacityAnimation.Play();
398             }
399         }
400
401         /// <inheritdoc/>
402         /// <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>
403         [EditorBrowsable(EditorBrowsableState.Never)]
404         public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
405         {
406             if (ControlState == ControlState.Disabled)
407             {
408                 return;
409             }
410
411             if (calculator == null)
412             {
413                 return;
414             }
415
416             previousPosition = calculator.currentPosition;
417             calculator.currentPosition = position;
418             var thumbPosition = calculator.CalculateThumbScrollPosition(trackView.Size, thumbView.Position, trackPadding);
419
420             if (durationMs == 0)
421             {
422                 thumbView.Position = thumbPosition;
423                 return;
424             }
425
426             EnsureThumbPositionAnimation().AnimateTo(thumbView, "position", thumbPosition, 0, (int)durationMs, alphaFunction);
427             thumbPositionAnimation.Play();
428         }
429
430         /// <inheritdoc/>
431         [EditorBrowsable(EditorBrowsableState.Never)]
432         public override void OnRelayout(Vector2 size, RelayoutContainer container)
433         {
434             base.OnRelayout(size, container);
435
436             if (size.Width == containerSize.Width && size.Height == containerSize.Height)
437             {
438                 return;
439             }
440
441             containerSize = new Size(size.Width, size.Height);
442
443             if (calculator == null)
444             {
445                 return;
446             }
447
448             trackView.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
449             trackView.Position = calculator.CalculateTrackPosition(trackPadding);
450             thumbView.Size = calculator.CalculateThumbSize(ThumbThickness, trackView.Size);
451             thumbView.Position = calculator.CalculateThumbPosition(trackView.Size, thumbView.Size, trackPadding);
452         }
453
454         /// <inheritdoc/>
455         [EditorBrowsable(EditorBrowsableState.Never)]
456         public override void ApplyStyle(ViewStyle viewStyle)
457         {
458             if (viewStyle is ScrollbarStyle scrollbarStyle)
459             {
460                 // Apply essential look.
461                 if (scrollbarStyle.TrackThickness == null) scrollbarStyle.TrackThickness = 6.0f;
462                 if (scrollbarStyle.ThumbThickness == null) scrollbarStyle.ThumbThickness = 6.0f;
463                 if (scrollbarStyle.TrackColor == null) scrollbarStyle.TrackColor = new Color(1.0f, 1.0f, 1.0f, 0.15f);
464                 if (scrollbarStyle.ThumbColor == null) scrollbarStyle.ThumbColor = new Color(0.6f, 0.6f, 0.6f, 1.0f);
465                 if (scrollbarStyle.TrackPadding == null) scrollbarStyle.TrackPadding = 4;
466                 if (scrollbarStyle.WidthResizePolicy == null) scrollbarStyle.WidthResizePolicy = ResizePolicyType.FillToParent;
467                 if (scrollbarStyle.HeightResizePolicy == null) scrollbarStyle.HeightResizePolicy = ResizePolicyType.FillToParent;
468             }
469
470             base.ApplyStyle(viewStyle);
471         }
472
473         /// <inheritdoc/>
474         [EditorBrowsable(EditorBrowsableState.Never)]
475         protected override ViewStyle CreateViewStyle()
476         {
477             return new ScrollbarStyle();
478         }
479
480         /// <summary>
481         /// Update TrackThickness property of the scrollbar.
482         /// </summary>
483         /// <param name="thickness">The width of the track.</param>
484         private void UpdateTrackThickness(float thickness)
485         {
486             trackThickness = thickness;
487
488             if (calculator == null)
489             {
490                 return;
491             }
492
493             trackView.Size = calculator.CalculateTrackSize(thickness, containerSize, trackPadding);
494         }
495
496         /// <summary>
497         /// Update ThumbThickness property of the scrollbar.
498         /// </summary>
499         /// <param name="thickness">The width of the track.</param>
500         private void UpdateThumbThickness(float thickness)
501         {
502             thumbThickness = thickness;
503
504             if (calculator == null)
505             {
506                 return;
507             }
508
509             thumbView.Size = calculator.CalculateThumbSize(thickness, trackView.Size);
510         }
511
512         /// <summary>
513         /// Update TrackPadding property of the scrollbar.
514         /// </summary>
515         /// <param name="padding">The padding of the track.</param>
516         private void UpdateTrackPadding(Extents padding)
517         {
518             trackPadding = padding == null ? new PaddingType(0, 0, 0, 0) : new PaddingType(padding.Start, padding.End, padding.Top, padding.Bottom);
519
520             if (calculator == null)
521             {
522                 return;
523             }
524
525             trackView.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
526             trackView.Position = calculator.CalculateTrackPosition(trackPadding);
527             thumbView.Size = calculator.CalculateThumbSize(ThumbThickness, trackView.Size);
528             thumbView.Position = calculator.CalculateThumbPaddingPosition(trackView.Size, thumbView.Size, thumbView.Position, trackPadding);
529         }
530         private void UpdateThumbColor(Color color)
531         {
532             thumbColor = color;
533             if (thumbView.ResourceUrl != "")
534             {
535                 thumbView.Color = color;
536                 thumbView.BackgroundColor = Color.Transparent;
537             }
538             else
539             {
540                 thumbView.BackgroundColor = color;
541             }
542         }
543
544         private void UpdateThumbImage(string url, bool isHorizontal)
545         {
546             if (isHorizontal)
547             {
548                 thumbHorizontalImageUrl = url;
549                 if (this.isHorizontal)
550                 {
551                     thumbView.ResourceUrl = url;
552                     thumbView.Color = thumbColor;
553                     thumbView.BackgroundColor = Color.Transparent;
554                 }
555             }
556             else
557             {
558                 thumbVerticalImageUrl = url;
559                 if (!this.isHorizontal)
560                 {
561                     thumbView.ResourceUrl = url;
562                     thumbView.Color = thumbColor;
563                     thumbView.BackgroundColor = Color.Transparent;
564                 }
565             }
566         }
567
568         private Animation EnsureThumbPositionAnimation()
569         {
570             if (thumbPositionAnimation == null)
571             {
572                 thumbPositionAnimation = new Animation();
573             }
574             else
575             {
576                 thumbPositionAnimation.Stop();
577                 thumbPositionAnimation.Clear();
578             }
579             return thumbPositionAnimation;
580         }
581
582         private Animation EnsureThumbSizeAnimation()
583         {
584             if (thumbSizeAnimation == null)
585             {
586                 thumbSizeAnimation = new Animation();
587             }
588             else
589             {
590                 thumbSizeAnimation.Stop();
591                 thumbSizeAnimation.Clear();
592             }
593             return thumbSizeAnimation;
594         }
595
596         private Animation EnsureOpacityAnimation()
597         {
598             if (opacityAnimation == null)
599             {
600                 opacityAnimation = new Animation();
601             }
602             else
603             {
604                 opacityAnimation.Stop();
605                 opacityAnimation.Clear();
606             }
607             return opacityAnimation;
608         }
609
610         #endregion Methods
611
612
613         #region Classes
614
615         private abstract class Calculator
616         {
617             public float contentLength;
618             public float visibleLength;
619             public float currentPosition;
620
621             public Calculator(float contentLength, float visibleLength, float currentPosition)
622             {
623                 this.contentLength = contentLength;
624                 this.visibleLength = visibleLength;
625                 this.currentPosition = currentPosition;
626             }
627
628             public bool IsScrollable()
629             {
630                 return contentLength > visibleLength;
631             }
632
633             public abstract Position CalculatorTrackAlign();
634             public abstract Position CalculatorThumbAlign();
635             public abstract Size CalculateTrackSize(float thickness, Size containerSize, PaddingType trackPadding);
636             public abstract Position CalculateTrackPosition(PaddingType trackPadding);
637             public abstract Size CalculateThumbSize(float thickness, Size trackSize);
638             public abstract Position CalculateThumbPosition(Size trackSize, Size thumbSize, PaddingType trackPadding);
639             public abstract Position CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Position thumbCurrentPosition, PaddingType trackPadding);
640             public abstract Position CalculateThumbScrollPosition(Size trackSize, Position thumbCurrentPosition, PaddingType trackPadding);
641         }
642
643         private class HorizontalCalculator : Calculator
644         {
645             public HorizontalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
646             {
647             }
648
649             public override Position CalculatorTrackAlign()
650             {
651                 return Tizen.NUI.ParentOrigin.BottomLeft;
652             }
653
654             public override Position CalculatorThumbAlign()
655             {
656                 return Tizen.NUI.ParentOrigin.BottomLeft;
657             }
658
659             public override Size CalculateTrackSize(float thickness, Size containerSize, PaddingType trackPadding)
660             {
661                 return new Size(containerSize.Width - trackPadding.Item1 - trackPadding.Item2, thickness);
662             }
663
664             public override Position CalculateTrackPosition(PaddingType trackPadding)
665             {
666                 return new Position(trackPadding.Item1, -trackPadding.Item4);
667             }
668
669             public override Size CalculateThumbSize(float thickness, Size trackSize)
670             {
671                 return new Size(trackSize.Width * (IsScrollable() ? (visibleLength / contentLength) : 0.0f), thickness);
672             }
673
674             public override Position CalculateThumbPosition(Size trackSize, Size thumbSize, PaddingType trackPadding)
675             {
676                 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Item4;
677                 return new Position(trackPadding.Item1 + (IsScrollable() ? (trackSize.Width * (Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength)) / contentLength) : 0.0f), -padding);
678             }
679
680             public override Position CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Position thumbCurrentPosition, PaddingType trackPadding)
681             {
682                 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Item4;
683                 return new Position(thumbCurrentPosition.X, -padding);
684             }
685
686             public override Position CalculateThumbScrollPosition(Size trackSize, Position thumbCurrentPosition, PaddingType trackPadding)
687             { 
688                 return new Position(trackPadding.Item1 + (IsScrollable() ? (trackSize.Width * (Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength)) / contentLength) : 0.0f), thumbCurrentPosition.Y);
689             }
690         }
691
692         private class VerticalCalculator : Calculator
693         {
694             public VerticalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
695             {
696             }
697
698             public override Position CalculatorTrackAlign()
699             {
700                 return Tizen.NUI.ParentOrigin.TopRight;
701             }
702
703             public override Position CalculatorThumbAlign()
704             {
705                 return Tizen.NUI.ParentOrigin.TopRight;
706             }
707
708             public override Size CalculateTrackSize(float thickness, Size containerSize, PaddingType trackPadding)
709             {
710                 return new Size(thickness, containerSize.Height - trackPadding.Item3 - trackPadding.Item4);
711             }
712
713             public override Position CalculateTrackPosition(PaddingType trackPadding)
714             {
715                 return new Position(-trackPadding.Item2, trackPadding.Item3);
716             }
717
718             public override Size CalculateThumbSize(float thickness, Size trackSize)
719             {
720                 return new Size(thickness, trackSize.Height * (IsScrollable() ? (visibleLength / contentLength) : 0.0f));
721             }
722
723             public override Position CalculateThumbPosition(Size trackSize, Size thumbSize, PaddingType trackPadding)
724             {
725                 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.Item2;
726                 return new Position(-padding, trackPadding.Item3 + (IsScrollable() ? (trackSize.Height * Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength) / contentLength) : 0.0f));
727             }
728
729             public override Position CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Position thumbCurrentPosition, PaddingType trackPadding)
730             {
731                 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.Item2;
732                 return new Position(-padding, thumbCurrentPosition.Y);
733             }
734
735             public override Position CalculateThumbScrollPosition(Size trackSize, Position thumbPosition, PaddingType trackPadding)
736             {
737                 return new Position(thumbPosition.X, trackPadding.Item3 + (IsScrollable() ? (trackSize.Height * Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength) / contentLength) : 0.0f));
738             }
739         }
740
741         #endregion Classes
742     }
743 }