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;
122 /// Create an empty Scrollbar.
124 public Scrollbar() : base(new ScrollbarStyle())
129 /// Create a Scrollbar and initialize with properties.
131 /// <param name="contentLength">The length of the scrollable content area.</param>
132 /// <param name="viewportLength">The length of the viewport representing the amount of visible content.</param>
133 /// <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>
134 /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical by default.</param>
135 [EditorBrowsable(EditorBrowsableState.Never)]
136 public Scrollbar(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false) : base(new ScrollbarStyle())
138 Initialize(contentLength, viewportLength, currentPosition, isHorizontal);
142 /// Create an empty Scrollbar with a ScrollbarStyle instance to set style properties.
144 [EditorBrowsable(EditorBrowsableState.Never)]
145 public Scrollbar(ScrollbarStyle style) : base(style)
150 /// Static constructor to initialize bindable properties when loading.
156 #endregion Constructors
162 /// Return a copied Style instance of Scrollbar
165 /// It returns copied Style instance and changing it does not effect to the Scrollbar.
166 /// Style setting is possible by using constructor or the function of ApplyStyle(ViewStyle viewStyle)
168 [EditorBrowsable(EditorBrowsableState.Never)]
169 public new ScrollbarStyle Style
173 var result = new ScrollbarStyle(scrollbarStyle);
174 result.CopyPropertiesFromView(this);
180 /// The thickness of the track.
182 [EditorBrowsable(EditorBrowsableState.Never)]
183 public float TrackThickness
185 get => (float)GetValue(TrackThicknessProperty);
186 set => SetValue(TrackThicknessProperty, value);
190 /// The thickness of the thumb.
192 [EditorBrowsable(EditorBrowsableState.Never)]
193 public float ThumbThickness
195 get => (float)GetValue(ThumbThicknessProperty);
196 set => SetValue(ThumbThicknessProperty, value);
200 /// The color of the track part.
202 [EditorBrowsable(EditorBrowsableState.Never)]
203 public Color TrackColor
205 get => (Color)GetValue(TrackColorProperty);
206 set => SetValue(TrackColorProperty, value);
210 /// The color of the thumb part.
212 [EditorBrowsable(EditorBrowsableState.Never)]
213 public Color ThumbColor
215 get => (Color)GetValue(ThumbColorProperty);
216 set => SetValue(ThumbColorProperty, value);
220 /// The padding value of the track.
222 [EditorBrowsable(EditorBrowsableState.Never)]
223 public Extents TrackPadding
225 get => (Extents)GetValue(TrackPaddingProperty);
226 set => SetValue(TrackPaddingProperty, value);
229 #endregion Properties
235 [EditorBrowsable(EditorBrowsableState.Never)]
236 public override void Initialize(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false)
240 calculator = new HorizontalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
244 calculator = new VerticalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
247 thumbPositionAnimation?.Stop();
248 thumbPositionAnimation = null;
250 thumbSizeAnimation?.Stop();
251 thumbSizeAnimation = null;
253 Size trackSize = calculator.CalculateTrackSize(TrackThickness, containerSize, TrackPadding);
254 Vector2 trackPosition = calculator.CalculateTrackPosition(TrackPadding);
255 Size thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackSize);
256 Vector2 thumbPosition = calculator.CalculateThumbPosition(trackSize, thumbSize, TrackPadding);
258 if (trackVisual == null)
260 trackVisual = new ColorVisual
262 SuppressUpdateVisual = true,
264 SizePolicy = VisualTransformPolicyType.Absolute,
265 Origin = calculator.CalculatorTrackAlign(),
266 AnchorPoint = calculator.CalculatorTrackAlign(),
268 Position = trackPosition,
271 AddVisual("Track", trackVisual);
275 trackVisual.Size = trackSize;
276 trackVisual.Position = trackPosition;
277 trackVisual.UpdateVisual(true);
280 if (thumbVisual == null)
282 thumbVisual = new ColorVisual
284 SuppressUpdateVisual = true,
285 MixColor = ThumbColor,
286 SizePolicy = VisualTransformPolicyType.Absolute,
287 Origin = calculator.CalculatorThumbAlign(),
288 AnchorPoint = calculator.CalculatorThumbAlign(),
289 Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f,
291 Position = thumbPosition,
294 AddVisual("Thumb", thumbVisual);
298 thumbVisual.Size = thumbSize;
299 thumbVisual.Position = thumbPosition;
300 thumbVisual.UpdateVisual(true);
305 /// <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>
306 [EditorBrowsable(EditorBrowsableState.Never)]
307 public override void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
309 if (calculator == null)
314 calculator.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
315 calculator.currentPosition = position;
317 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
318 thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, TrackPadding);
319 thumbVisual.Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f;
323 thumbVisual.UpdateVisual(true);
328 // TODO Support non built-in alpha function for visual trainsition in DALi.
329 AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
331 thumbPositionAnimation?.Stop();
332 thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
333 thumbPositionAnimation.Play();
335 thumbSizeAnimation?.Stop();
336 thumbSizeAnimation = AnimateVisual(thumbVisual, "size", thumbVisual.Size, 0, (int)durationMs, builtinAlphaFunction);
337 thumbSizeAnimation.Play();
341 /// <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>
342 [EditorBrowsable(EditorBrowsableState.Never)]
343 public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
345 if (mScrollEnabled == false)
350 if (calculator == null)
355 calculator.currentPosition = position;
356 thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, TrackPadding);
360 thumbVisual.UpdateVisual(true);
365 // TODO Support non built-in alpha function for visual trainsition in DALi.
366 AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
368 thumbPositionAnimation?.Stop();
369 thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
370 thumbPositionAnimation.Play();
374 [EditorBrowsable(EditorBrowsableState.Never)]
375 public override void OnRelayout(Vector2 size, RelayoutContainer container)
377 base.OnRelayout(size, container);
379 if (size.Width == containerSize.Width && size.Height == containerSize.Height)
384 containerSize = new Size(size.Width, size.Height);
386 if (calculator == null)
391 trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, TrackPadding);
392 trackVisual.Position = calculator.CalculateTrackPosition(TrackPadding);
393 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
394 thumbVisual.Position = calculator.CalculateThumbPosition(trackVisual.Size, thumbVisual.Size, TrackPadding);
396 trackVisual.UpdateVisual(true);
397 thumbVisual.UpdateVisual(true);
401 [EditorBrowsable(EditorBrowsableState.Never)]
402 protected override ViewStyle CreateViewStyle()
404 return new ScrollbarStyle();
408 /// Update TrackThickness property of the scrollbar.
410 /// <param name="thickness">The width of the track.</param>
411 [EditorBrowsable(EditorBrowsableState.Never)]
412 protected virtual void UpdateTrackThickness(float thickness)
414 if (trackVisual == null)
419 trackVisual.Size = calculator.CalculateTrackSize(thickness, containerSize, TrackPadding);
420 trackVisual.UpdateVisual(true);
424 /// Update ThumbThickness property of the scrollbar.
426 /// <param name="thickness">The width of the track.</param>
427 [EditorBrowsable(EditorBrowsableState.Never)]
428 protected virtual void UpdateThumbThickness(float thickness)
430 if (thumbVisual == null)
435 thumbVisual.Size = calculator.CalculateThumbSize(thickness, trackVisual.Size);
436 thumbVisual.UpdateVisual(true);
440 /// Update TrackColor property of the scrollbar.
442 /// <param name="color">The color of the track.</param>
443 [EditorBrowsable(EditorBrowsableState.Never)]
444 protected virtual void UpdateTrackColor(Color color)
446 if (trackVisual == null)
451 trackVisual.MixColor = color;
452 trackVisual.UpdateVisual(true);
456 /// Update ThumbColor property of the scrollbar.
458 /// <param name="color">The color of the thumb.</param>
459 [EditorBrowsable(EditorBrowsableState.Never)]
460 protected virtual void UpdateThumbColor(Color color)
462 if (thumbVisual == null)
467 thumbVisual.MixColor = color;
468 thumbVisual.UpdateVisual(true);
472 /// Update TrackPadding property of the scrollbar.
474 /// <param name="trackPadding">The padding of the track.</param>
475 protected virtual void UpdateTrackPadding(Extents trackPadding)
477 if (calculator == null)
482 trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
483 trackVisual.Position = calculator.CalculateTrackPosition(trackPadding);
484 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
485 thumbVisual.Position = calculator.CalculateThumbPaddingPosition(trackVisual.Size, thumbVisual.Size, thumbVisual.Position, trackPadding);
487 trackVisual.UpdateVisual(true);
488 thumbVisual.UpdateVisual(true);
492 [EditorBrowsable(EditorBrowsableState.Never)]
493 public override bool ScrollEnabled
497 return mScrollEnabled;
501 if (value != mScrollEnabled)
503 mScrollEnabled = value;
513 private abstract class Calculator
515 public float contentLength;
516 public float visibleLength;
517 public float currentPosition;
519 public Calculator(float contentLength, float visibleLength, float currentPosition)
521 this.contentLength = contentLength;
522 this.visibleLength = visibleLength;
523 this.currentPosition = currentPosition;
526 public bool CalculateThumbVisibility()
528 return contentLength > visibleLength;
531 public abstract Visual.AlignType CalculatorTrackAlign();
532 public abstract Visual.AlignType CalculatorThumbAlign();
533 public abstract Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding);
534 public abstract Vector2 CalculateTrackPosition(Extents trackPadding);
535 public abstract Size CalculateThumbSize(float thickness, Size trackSize);
536 public abstract Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding);
537 public abstract Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding);
538 public abstract Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding);
541 private class HorizontalCalculator : Calculator
543 public HorizontalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
547 public override Visual.AlignType CalculatorTrackAlign()
549 return Visual.AlignType.BottomCenter;
552 public override Visual.AlignType CalculatorThumbAlign()
554 return Visual.AlignType.BottomBegin;
557 public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
559 return new Size(containerSize.Width - trackPadding.Start - trackPadding.End, thickness);
562 public override Vector2 CalculateTrackPosition(Extents trackPadding)
564 return new Vector2(0, -trackPadding.Bottom);
567 public override Size CalculateThumbSize(float thickness, Size trackSize)
569 return new Size(trackSize.Width * visibleLength / contentLength, thickness);
572 public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
574 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Bottom;
575 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
576 return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, -padding);
579 public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
581 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Bottom;
582 return new Vector2(thumbCurrentPosition.X, -padding);
585 public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding)
587 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
588 return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, thumbCurrentPosition.Y);
592 private class VerticalCalculator : Calculator
594 public VerticalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
598 public override Visual.AlignType CalculatorTrackAlign()
600 return Visual.AlignType.CenterEnd;
603 public override Visual.AlignType CalculatorThumbAlign()
605 return Visual.AlignType.TopEnd;
608 public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
610 return new Size(thickness, containerSize.Height - trackPadding.Top - trackPadding.Bottom);
613 public override Vector2 CalculateTrackPosition(Extents trackPadding)
615 return new Vector2(-trackPadding.End, 0);
618 public override Size CalculateThumbSize(float thickness, Size trackSize)
620 return new Size(thickness, trackSize.Height * visibleLength / contentLength);
623 public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
625 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.End;
626 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
627 return new Vector2(-padding, trackPadding.Top + trackSize.Height * pos / contentLength);
630 public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
632 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.End;
633 return new Vector2(-padding, thumbCurrentPosition.Y);
636 public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbPosition, Extents trackPadding)
638 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
639 return new Vector2(thumbPosition.X, trackPadding.Top + trackSize.Height * pos / contentLength);