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()
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) : this()
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 public override void ApplyStyle(ViewStyle viewStyle)
407 base.ApplyStyle(viewStyle);
409 if (viewStyle is ScrollbarStyle scrollbarStyle)
411 // Apply essential look.
412 if (scrollbarStyle.TrackThickness == null) scrollbarStyle.TrackThickness = 6.0f;
413 if (scrollbarStyle.ThumbThickness == null) scrollbarStyle.ThumbThickness = 6.0f;
414 if (scrollbarStyle.TrackColor == null) scrollbarStyle.TrackColor = new Color(1.0f, 1.0f, 1.0f, 0.15f);
415 if (scrollbarStyle.ThumbColor == null) scrollbarStyle.ThumbColor = new Color(0.6f, 0.6f, 0.6f, 1.0f);
416 if (scrollbarStyle.TrackPadding == null) scrollbarStyle.TrackPadding = 4;
417 if (scrollbarStyle.WidthResizePolicy == null) scrollbarStyle.WidthResizePolicy = ResizePolicyType.FillToParent;
418 if (scrollbarStyle.HeightResizePolicy == null) scrollbarStyle.HeightResizePolicy = ResizePolicyType.FillToParent;
423 [EditorBrowsable(EditorBrowsableState.Never)]
424 protected override ViewStyle CreateViewStyle()
426 return new ScrollbarStyle();
430 /// Update TrackThickness property of the scrollbar.
432 /// <param name="thickness">The width of the track.</param>
433 [EditorBrowsable(EditorBrowsableState.Never)]
434 protected virtual void UpdateTrackThickness(float thickness)
436 if (trackVisual == null)
441 trackVisual.Size = calculator.CalculateTrackSize(thickness, containerSize, TrackPadding);
442 trackVisual.UpdateVisual(true);
446 /// Update ThumbThickness property of the scrollbar.
448 /// <param name="thickness">The width of the track.</param>
449 [EditorBrowsable(EditorBrowsableState.Never)]
450 protected virtual void UpdateThumbThickness(float thickness)
452 if (thumbVisual == null)
457 thumbVisual.Size = calculator.CalculateThumbSize(thickness, trackVisual.Size);
458 thumbVisual.UpdateVisual(true);
462 /// Update TrackColor property of the scrollbar.
464 /// <param name="color">The color of the track.</param>
465 [EditorBrowsable(EditorBrowsableState.Never)]
466 protected virtual void UpdateTrackColor(Color color)
468 if (trackVisual == null)
473 trackVisual.MixColor = color;
474 trackVisual.UpdateVisual(true);
478 /// Update ThumbColor property of the scrollbar.
480 /// <param name="color">The color of the thumb.</param>
481 [EditorBrowsable(EditorBrowsableState.Never)]
482 protected virtual void UpdateThumbColor(Color color)
484 if (thumbVisual == null)
489 thumbVisual.MixColor = color;
490 thumbVisual.UpdateVisual(true);
494 /// Update TrackPadding property of the scrollbar.
496 /// <param name="trackPadding">The padding of the track.</param>
497 protected virtual void UpdateTrackPadding(Extents trackPadding)
499 if (calculator == null)
504 trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
505 trackVisual.Position = calculator.CalculateTrackPosition(trackPadding);
506 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
507 thumbVisual.Position = calculator.CalculateThumbPaddingPosition(trackVisual.Size, thumbVisual.Size, thumbVisual.Position, trackPadding);
509 trackVisual.UpdateVisual(true);
510 thumbVisual.UpdateVisual(true);
514 [EditorBrowsable(EditorBrowsableState.Never)]
515 public override bool ScrollEnabled
519 return mScrollEnabled;
523 if (value != mScrollEnabled)
525 mScrollEnabled = value;
531 [EditorBrowsable(EditorBrowsableState.Never)]
532 public override Position ScrollPosition
536 if (calculator == null)
538 return new Position(0.0f, 0.0f);
541 float length = Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
543 if (calculator is HorizontalCalculator)
545 return new Position(length, 0.0f);
549 return new Position(0.0f, length);
555 [EditorBrowsable(EditorBrowsableState.Never)]
556 public override Position ScrollCurrentPosition
560 if (calculator == null)
562 return new Position(0.0f, 0.0f);
565 float length = Math.Min(Math.Max(calculator.currentPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
567 if (thumbPositionAnimation != null)
569 float progress = thumbPositionAnimation.CurrentProgress;
570 float previousLength = Math.Min(Math.Max(previousPosition, 0.0f), calculator.contentLength - calculator.visibleLength);
572 length = ((1.0f - progress) * previousLength) + (progress * length);
575 if (calculator is HorizontalCalculator)
577 return new Position(length, 0.0f);
581 return new Position(0.0f, length);
591 private abstract class Calculator
593 public float contentLength;
594 public float visibleLength;
595 public float currentPosition;
597 public Calculator(float contentLength, float visibleLength, float currentPosition)
599 this.contentLength = contentLength;
600 this.visibleLength = visibleLength;
601 this.currentPosition = currentPosition;
604 public bool CalculateThumbVisibility()
606 return contentLength > visibleLength;
609 public abstract Visual.AlignType CalculatorTrackAlign();
610 public abstract Visual.AlignType CalculatorThumbAlign();
611 public abstract Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding);
612 public abstract Vector2 CalculateTrackPosition(Extents trackPadding);
613 public abstract Size CalculateThumbSize(float thickness, Size trackSize);
614 public abstract Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding);
615 public abstract Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding);
616 public abstract Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding);
619 private class HorizontalCalculator : Calculator
621 public HorizontalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
625 public override Visual.AlignType CalculatorTrackAlign()
627 return Visual.AlignType.BottomCenter;
630 public override Visual.AlignType CalculatorThumbAlign()
632 return Visual.AlignType.BottomBegin;
635 public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
637 return new Size(containerSize.Width - trackPadding?.Start ?? 0 - trackPadding?.End ?? 0, thickness);
640 public override Vector2 CalculateTrackPosition(Extents trackPadding)
642 return new Vector2(0, -trackPadding?.Bottom ?? 0);
645 public override Size CalculateThumbSize(float thickness, Size trackSize)
647 return new Size(trackSize.Width * visibleLength / contentLength, thickness);
650 public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
652 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding?.Bottom ?? 0;
653 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
654 return new Vector2(trackPadding?.Start ?? 0 + trackSize.Width * pos / contentLength, -padding);
657 public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
659 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding?.Bottom ?? 0;
660 return new Vector2(thumbCurrentPosition.X, -padding);
663 public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding)
665 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
666 return new Vector2(trackPadding?.Start ?? 0 + trackSize.Width * pos / contentLength, thumbCurrentPosition.Y);
670 private class VerticalCalculator : Calculator
672 public VerticalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
676 public override Visual.AlignType CalculatorTrackAlign()
678 return Visual.AlignType.CenterEnd;
681 public override Visual.AlignType CalculatorThumbAlign()
683 return Visual.AlignType.TopEnd;
686 public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
688 return new Size(thickness, containerSize.Height - trackPadding?.Top ?? 0 - trackPadding?.Bottom ?? 0);
691 public override Vector2 CalculateTrackPosition(Extents trackPadding)
693 return new Vector2(-trackPadding?.End ?? 0, 0);
696 public override Size CalculateThumbSize(float thickness, Size trackSize)
698 return new Size(thickness, trackSize.Height * visibleLength / contentLength);
701 public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
703 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding?.End ?? 0;
704 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
705 return new Vector2(-padding, trackPadding?.Top ?? 0 + trackSize.Height * pos / contentLength);
708 public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
710 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding?.End ?? 0;
711 return new Vector2(-padding, thumbCurrentPosition.Y);
714 public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbPosition, Extents trackPadding)
716 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
717 return new Vector2(thumbPosition.X, trackPadding?.Top ?? 0 + trackSize.Height * pos / contentLength);