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 Tizen.NUI.BaseComponents;
20 using Tizen.NUI.Binding;
22 namespace Tizen.NUI.Components
25 /// The Scrollbar is a component that contains track and thumb to indicate the current scrolled position of a scrollable object.
27 [EditorBrowsable(EditorBrowsableState.Never)]
28 public class Scrollbar : ScrollbarBase
32 /// <summary>Bindable property of TrackThickness</summary>
33 [EditorBrowsable(EditorBrowsableState.Never)]
34 public static readonly BindableProperty TrackThicknessProperty = BindableProperty.Create(nameof(TrackThickness), typeof(float), typeof(Scrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
36 var instance = ((Scrollbar)bindable);
37 var thickness = (float?)newValue;
39 instance.scrollbarStyle.TrackThickness = thickness;
40 instance.UpdateTrackThickness(thickness ?? 0);
42 defaultValueCreator: (bindable) =>
44 return ((Scrollbar)bindable).scrollbarStyle.TrackThickness ?? 0;
47 /// <summary>Bindable property of ThumbThickness</summary>
48 [EditorBrowsable(EditorBrowsableState.Never)]
49 public static readonly BindableProperty ThumbThicknessProperty = BindableProperty.Create(nameof(ThumbThickness), typeof(float), typeof(Scrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
51 var instance = ((Scrollbar)bindable);
52 var thickness = (float?)newValue;
54 instance.scrollbarStyle.ThumbThickness = thickness;
55 instance.UpdateThumbThickness(thickness ?? 0);
57 defaultValueCreator: (bindable) =>
59 return ((Scrollbar)bindable).scrollbarStyle.ThumbThickness ?? 0;
62 /// <summary>Bindable property of TrackColor</summary>
63 [EditorBrowsable(EditorBrowsableState.Never)]
64 public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(Scrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
66 var instance = ((Scrollbar)bindable);
67 var color = (Color)newValue;
69 instance.scrollbarStyle.TrackColor = color;
70 instance.UpdateTrackColor(color);
72 defaultValueCreator: (bindable) =>
74 return ((Scrollbar)bindable).scrollbarStyle.TrackColor;
77 /// <summary>Bindable property of ThumbColor</summary>
78 [EditorBrowsable(EditorBrowsableState.Never)]
79 public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(Scrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
81 var instance = ((Scrollbar)bindable);
82 var color = (Color)newValue;
84 instance.scrollbarStyle.ThumbColor = color;
85 instance.UpdateThumbColor(color);
87 defaultValueCreator: (bindable) =>
89 return ((Scrollbar)bindable).scrollbarStyle.ThumbColor;
92 /// <summary>Bindable property of TrackPadding</summary>
93 [EditorBrowsable(EditorBrowsableState.Never)]
94 public static readonly BindableProperty TrackPaddingProperty = BindableProperty.Create(nameof(TrackPadding), typeof(Extents), typeof(Scrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
96 var instance = ((Scrollbar)bindable);
97 var trackPadding = (Extents)newValue;
99 instance.scrollbarStyle.TrackPadding = trackPadding;
100 instance.UpdateTrackPadding(trackPadding);
102 defaultValueCreator: (bindable) =>
104 return ((Scrollbar)bindable).scrollbarStyle.TrackPadding;
107 private ColorVisual trackVisual;
108 private ColorVisual thumbVisual;
109 private Animation thumbPositionAnimation;
110 private Animation thumbSizeAnimation;
111 private Calculator calculator;
112 private Size containerSize = new Size(0, 0);
113 private ScrollbarStyle scrollbarStyle => ViewStyle as ScrollbarStyle;
114 private bool mScrollEnabled = true;
115 private float previousPosition;
123 /// Create an empty Scrollbar.
125 public Scrollbar() : base(new ScrollbarStyle())
130 /// Create a Scrollbar and initialize with properties.
132 /// <param name="contentLength">The length of the scrollable content area.</param>
133 /// <param name="viewportLength">The length of the viewport representing the amount of visible content.</param>
134 /// <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>
135 /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical by default.</param>
136 [EditorBrowsable(EditorBrowsableState.Never)]
137 public Scrollbar(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false) : base(new ScrollbarStyle())
139 Initialize(contentLength, viewportLength, currentPosition, isHorizontal);
143 /// Create an empty Scrollbar with a ScrollbarStyle instance to set style properties.
145 [EditorBrowsable(EditorBrowsableState.Never)]
146 public Scrollbar(ScrollbarStyle style) : base(style)
151 /// Static constructor to initialize bindable properties when loading.
157 #endregion Constructors
163 /// Return a copied Style instance of Scrollbar
166 /// It returns copied Style instance and changing it does not effect to the Scrollbar.
167 /// Style setting is possible by using constructor or the function of ApplyStyle(ViewStyle viewStyle)
169 [EditorBrowsable(EditorBrowsableState.Never)]
170 public new ScrollbarStyle Style
174 var result = new ScrollbarStyle(scrollbarStyle);
175 result.CopyPropertiesFromView(this);
181 /// The thickness of the track.
183 [EditorBrowsable(EditorBrowsableState.Never)]
184 public float TrackThickness
186 get => (float)GetValue(TrackThicknessProperty);
187 set => SetValue(TrackThicknessProperty, value);
191 /// The thickness of the thumb.
193 [EditorBrowsable(EditorBrowsableState.Never)]
194 public float ThumbThickness
196 get => (float)GetValue(ThumbThicknessProperty);
197 set => SetValue(ThumbThicknessProperty, value);
201 /// The color of the track part.
203 [EditorBrowsable(EditorBrowsableState.Never)]
204 public Color TrackColor
206 get => (Color)GetValue(TrackColorProperty);
207 set => SetValue(TrackColorProperty, value);
211 /// The color of the thumb part.
213 [EditorBrowsable(EditorBrowsableState.Never)]
214 public Color ThumbColor
216 get => (Color)GetValue(ThumbColorProperty);
217 set => SetValue(ThumbColorProperty, value);
221 /// The padding value of the track.
223 [EditorBrowsable(EditorBrowsableState.Never)]
224 public Extents TrackPadding
226 get => (Extents)GetValue(TrackPaddingProperty);
227 set => SetValue(TrackPaddingProperty, value);
230 #endregion Properties
236 [EditorBrowsable(EditorBrowsableState.Never)]
237 public override void Initialize(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false)
241 calculator = new HorizontalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
245 calculator = new VerticalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
248 thumbPositionAnimation?.Stop();
249 thumbPositionAnimation = null;
251 thumbSizeAnimation?.Stop();
252 thumbSizeAnimation = null;
254 Size trackSize = calculator.CalculateTrackSize(TrackThickness, containerSize, TrackPadding);
255 Vector2 trackPosition = calculator.CalculateTrackPosition(TrackPadding);
256 Size thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackSize);
257 Vector2 thumbPosition = calculator.CalculateThumbPosition(trackSize, thumbSize, TrackPadding);
259 if (trackVisual == null)
261 trackVisual = new ColorVisual
263 SuppressUpdateVisual = true,
265 SizePolicy = VisualTransformPolicyType.Absolute,
266 Origin = calculator.CalculatorTrackAlign(),
267 AnchorPoint = calculator.CalculatorTrackAlign(),
269 Position = trackPosition,
272 AddVisual("Track", trackVisual);
276 trackVisual.Size = trackSize;
277 trackVisual.Position = trackPosition;
278 trackVisual.UpdateVisual(true);
281 if (thumbVisual == null)
283 thumbVisual = new ColorVisual
285 SuppressUpdateVisual = true,
286 MixColor = ThumbColor,
287 SizePolicy = VisualTransformPolicyType.Absolute,
288 Origin = calculator.CalculatorThumbAlign(),
289 AnchorPoint = calculator.CalculatorThumbAlign(),
290 Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f,
292 Position = thumbPosition,
295 AddVisual("Thumb", thumbVisual);
299 thumbVisual.Size = thumbSize;
300 thumbVisual.Position = thumbPosition;
301 thumbVisual.UpdateVisual(true);
306 /// <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>
307 [EditorBrowsable(EditorBrowsableState.Never)]
308 public override void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
310 if (calculator == null)
315 calculator.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
316 previousPosition = calculator.currentPosition;
317 calculator.currentPosition = position;
319 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
320 thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, TrackPadding);
321 thumbVisual.Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f;
325 thumbVisual.UpdateVisual(true);
330 // TODO Support non built-in alpha function for visual trainsition in DALi.
331 AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
333 thumbPositionAnimation?.Stop();
334 thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
335 thumbPositionAnimation.Play();
337 thumbSizeAnimation?.Stop();
338 thumbSizeAnimation = AnimateVisual(thumbVisual, "size", thumbVisual.Size, 0, (int)durationMs, builtinAlphaFunction);
339 thumbSizeAnimation.Play();
343 /// <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>
344 [EditorBrowsable(EditorBrowsableState.Never)]
345 public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
347 if (mScrollEnabled == false)
352 if (calculator == null)
357 previousPosition = calculator.currentPosition;
358 calculator.currentPosition = position;
359 thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, TrackPadding);
363 thumbVisual.UpdateVisual(true);
368 // TODO Support non built-in alpha function for visual trainsition in DALi.
369 AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
371 thumbPositionAnimation?.Stop();
372 thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
373 thumbPositionAnimation.Play();
377 [EditorBrowsable(EditorBrowsableState.Never)]
378 public override void OnRelayout(Vector2 size, RelayoutContainer container)
380 base.OnRelayout(size, container);
382 if (size.Width == containerSize.Width && size.Height == containerSize.Height)
387 containerSize = new Size(size.Width, size.Height);
389 if (calculator == null)
394 trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, TrackPadding);
395 trackVisual.Position = calculator.CalculateTrackPosition(TrackPadding);
396 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
397 thumbVisual.Position = calculator.CalculateThumbPosition(trackVisual.Size, thumbVisual.Size, TrackPadding);
399 trackVisual.UpdateVisual(true);
400 thumbVisual.UpdateVisual(true);
404 [EditorBrowsable(EditorBrowsableState.Never)]
405 protected override ViewStyle CreateViewStyle()
407 return new ScrollbarStyle();
411 /// Update TrackThickness property of the scrollbar.
413 /// <param name="thickness">The width of the track.</param>
414 [EditorBrowsable(EditorBrowsableState.Never)]
415 protected virtual void UpdateTrackThickness(float thickness)
417 if (trackVisual == null)
422 trackVisual.Size = calculator.CalculateTrackSize(thickness, containerSize, TrackPadding);
423 trackVisual.UpdateVisual(true);
427 /// Update ThumbThickness property of the scrollbar.
429 /// <param name="thickness">The width of the track.</param>
430 [EditorBrowsable(EditorBrowsableState.Never)]
431 protected virtual void UpdateThumbThickness(float thickness)
433 if (thumbVisual == null)
438 thumbVisual.Size = calculator.CalculateThumbSize(thickness, trackVisual.Size);
439 thumbVisual.UpdateVisual(true);
443 /// Update TrackColor property of the scrollbar.
445 /// <param name="color">The color of the track.</param>
446 [EditorBrowsable(EditorBrowsableState.Never)]
447 protected virtual void UpdateTrackColor(Color color)
449 if (trackVisual == null)
454 trackVisual.MixColor = color;
455 trackVisual.UpdateVisual(true);
459 /// Update ThumbColor property of the scrollbar.
461 /// <param name="color">The color of the thumb.</param>
462 [EditorBrowsable(EditorBrowsableState.Never)]
463 protected virtual void UpdateThumbColor(Color color)
465 if (thumbVisual == null)
470 thumbVisual.MixColor = color;
471 thumbVisual.UpdateVisual(true);
475 /// Update TrackPadding property of the scrollbar.
477 /// <param name="trackPadding">The padding of the track.</param>
478 protected virtual void UpdateTrackPadding(Extents trackPadding)
480 if (calculator == null)
485 trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
486 trackVisual.Position = calculator.CalculateTrackPosition(trackPadding);
487 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
488 thumbVisual.Position = calculator.CalculateThumbPaddingPosition(trackVisual.Size, thumbVisual.Size, thumbVisual.Position, trackPadding);
490 trackVisual.UpdateVisual(true);
491 thumbVisual.UpdateVisual(true);
495 [EditorBrowsable(EditorBrowsableState.Never)]
496 public override bool ScrollEnabled
500 return mScrollEnabled;
504 if (value != mScrollEnabled)
506 mScrollEnabled = value;
512 [EditorBrowsable(EditorBrowsableState.Never)]
513 public override Position ScrollPosition
517 if (calculator == null)
519 return new Position(0.0f, 0.0f);
522 float length = Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
524 if (calculator is HorizontalCalculator)
526 return new Position(length, 0.0f);
530 return new Position(0.0f, length);
536 [EditorBrowsable(EditorBrowsableState.Never)]
537 public override Position ScrollCurrentPosition
541 if (calculator == null)
543 return new Position(0.0f, 0.0f);
546 float length = Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
548 if (thumbPositionAnimation != null)
550 float progress = thumbPositionAnimation.CurrentProgress;
551 float previousLength = Math.Min(Math.Max(previousPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
553 length = ((1.0f - progress) * previousLength) + (progress * length);
556 if (calculator is HorizontalCalculator)
558 return new Position(length, 0.0f);
562 return new Position(0.0f, length);
572 private abstract class Calculator
574 public float contentLength;
575 public float visibleLength;
576 public float currentPosition;
578 public Calculator(float contentLength, float visibleLength, float currentPosition)
580 this.contentLength = contentLength;
581 this.visibleLength = visibleLength;
582 this.currentPosition = currentPosition;
585 public bool CalculateThumbVisibility()
587 return contentLength > visibleLength;
590 public abstract Visual.AlignType CalculatorTrackAlign();
591 public abstract Visual.AlignType CalculatorThumbAlign();
592 public abstract Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding);
593 public abstract Vector2 CalculateTrackPosition(Extents trackPadding);
594 public abstract Size CalculateThumbSize(float thickness, Size trackSize);
595 public abstract Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding);
596 public abstract Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding);
597 public abstract Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding);
600 private class HorizontalCalculator : Calculator
602 public HorizontalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
606 public override Visual.AlignType CalculatorTrackAlign()
608 return Visual.AlignType.BottomCenter;
611 public override Visual.AlignType CalculatorThumbAlign()
613 return Visual.AlignType.BottomBegin;
616 public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
618 return new Size(containerSize.Width - trackPadding.Start - trackPadding.End, thickness);
621 public override Vector2 CalculateTrackPosition(Extents trackPadding)
623 return new Vector2(0, -trackPadding.Bottom);
626 public override Size CalculateThumbSize(float thickness, Size trackSize)
628 return new Size(trackSize.Width * visibleLength / contentLength, thickness);
631 public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
633 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Bottom;
634 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
635 return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, -padding);
638 public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
640 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Bottom;
641 return new Vector2(thumbCurrentPosition.X, -padding);
644 public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding)
646 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
647 return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, thumbCurrentPosition.Y);
651 private class VerticalCalculator : Calculator
653 public VerticalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
657 public override Visual.AlignType CalculatorTrackAlign()
659 return Visual.AlignType.CenterEnd;
662 public override Visual.AlignType CalculatorThumbAlign()
664 return Visual.AlignType.TopEnd;
667 public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
669 return new Size(thickness, containerSize.Height - trackPadding.Top - trackPadding.Bottom);
672 public override Vector2 CalculateTrackPosition(Extents trackPadding)
674 return new Vector2(-trackPadding.End, 0);
677 public override Size CalculateThumbSize(float thickness, Size trackSize)
679 return new Size(thickness, trackSize.Height * visibleLength / contentLength);
682 public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
684 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.End;
685 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
686 return new Vector2(-padding, trackPadding.Top + trackSize.Height * pos / contentLength);
689 public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
691 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.End;
692 return new Vector2(-padding, thumbCurrentPosition.Y);
695 public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbPosition, Extents trackPadding)
697 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
698 return new Vector2(thumbPosition.X, trackPadding.Top + trackSize.Height * pos / contentLength);