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 ((ScrollbarStyle)instance.viewStyle).TrackThickness = thickness;
40 instance.UpdateTrackThickness(thickness ?? 0);
42 defaultValueCreator: (bindable) =>
44 return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.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 ((ScrollbarStyle)instance.viewStyle).ThumbThickness = thickness;
55 instance.UpdateThumbThickness(thickness ?? 0);
57 defaultValueCreator: (bindable) =>
59 return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.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 ((ScrollbarStyle)instance.viewStyle).TrackColor = color;
70 instance.UpdateTrackColor(color);
72 defaultValueCreator: (bindable) =>
74 return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.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 ((ScrollbarStyle)instance.viewStyle).ThumbColor = color;
85 instance.UpdateThumbColor(color);
87 defaultValueCreator: (bindable) =>
89 return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.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 ((ScrollbarStyle)instance.viewStyle).TrackPadding = trackPadding;
100 instance.UpdateTrackPadding(trackPadding);
102 defaultValueCreator: (bindable) =>
104 return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.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 float currentPosition;
121 /// Create an empty Scrollbar.
123 public Scrollbar() : base(new ScrollbarStyle())
128 /// Create a Scrollbar and initialize with properties.
130 /// <param name="contentLength">The length of the scrollable content area.</param>
131 /// <param name="viewportLength">The length of the viewport representing the amount of visible content.</param>
132 /// <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>
133 /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical by default.</param>
134 [EditorBrowsable(EditorBrowsableState.Never)]
135 public Scrollbar(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false) : base(new ScrollbarStyle())
137 Initialize(contentLength, viewportLength, currentPosition, isHorizontal);
141 /// Create an empty Scrollbar with a ScrollbarStyle instance to set style properties.
143 [EditorBrowsable(EditorBrowsableState.Never)]
144 public Scrollbar(ScrollbarStyle style) : base(style)
149 /// Static constructor to initialize bindable properties when loading.
155 #endregion Constructors
161 /// The thickness of the track.
163 [EditorBrowsable(EditorBrowsableState.Never)]
164 public float TrackThickness
166 get => (float)GetValue(TrackThicknessProperty);
167 set => SetValue(TrackThicknessProperty, value);
171 /// The thickness of the thumb.
173 [EditorBrowsable(EditorBrowsableState.Never)]
174 public float ThumbThickness
176 get => (float)GetValue(ThumbThicknessProperty);
177 set => SetValue(ThumbThicknessProperty, value);
181 /// The color of the track part.
183 [EditorBrowsable(EditorBrowsableState.Never)]
184 public Color TrackColor
186 get => (Color)GetValue(TrackColorProperty);
187 set => SetValue(TrackColorProperty, value);
191 /// The color of the thumb part.
193 [EditorBrowsable(EditorBrowsableState.Never)]
194 public Color ThumbColor
196 get => (Color)GetValue(ThumbColorProperty);
197 set => SetValue(ThumbColorProperty, value);
201 /// The padding value of the track.
203 [EditorBrowsable(EditorBrowsableState.Never)]
204 public Extents TrackPadding
206 get => (Extents)GetValue(TrackPaddingProperty);
207 set => SetValue(TrackPaddingProperty, value);
210 #endregion Properties
216 [EditorBrowsable(EditorBrowsableState.Never)]
217 public override void Initialize(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false)
221 calculator = new HorizontalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
225 calculator = new VerticalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
228 thumbPositionAnimation?.Stop();
229 thumbPositionAnimation = null;
231 thumbSizeAnimation?.Stop();
232 thumbSizeAnimation = null;
234 Size trackSize = calculator.CalculateTrackSize(TrackThickness, containerSize, TrackPadding);
235 Vector2 trackPosition = calculator.CalculateTrackPosition(TrackPadding);
236 Size thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackSize);
237 Vector2 thumbPosition = calculator.CalculateThumbPosition(trackSize, thumbSize, TrackPadding);
239 if (trackVisual == null)
241 trackVisual = new ColorVisual
243 SuppressUpdateVisual = true,
245 SizePolicy = VisualTransformPolicyType.Absolute,
246 Origin = calculator.CalculatorTrackAlign(),
247 AnchorPoint = calculator.CalculatorTrackAlign(),
249 Position = trackPosition,
252 AddVisual("Track", trackVisual);
256 trackVisual.Size = trackSize;
257 trackVisual.Position = trackPosition;
258 trackVisual.UpdateVisual(true);
261 if (thumbVisual == null)
263 thumbVisual = new ColorVisual
265 SuppressUpdateVisual = true,
266 MixColor = ThumbColor,
267 SizePolicy = VisualTransformPolicyType.Absolute,
268 Origin = calculator.CalculatorThumbAlign(),
269 AnchorPoint = calculator.CalculatorThumbAlign(),
270 Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f,
272 Position = thumbPosition,
275 AddVisual("Thumb", thumbVisual);
279 thumbVisual.Size = thumbSize;
280 thumbVisual.Position = thumbPosition;
281 thumbVisual.UpdateVisual(true);
286 /// <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>
287 [EditorBrowsable(EditorBrowsableState.Never)]
288 public override void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
290 if (calculator == null)
295 calculator.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
296 calculator.currentPosition = position;
298 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
299 thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, TrackPadding);
300 thumbVisual.Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f;
304 thumbVisual.UpdateVisual(true);
309 // TODO Support non built-in alpha function for visual trainsition in DALi.
310 AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
312 thumbPositionAnimation?.Stop();
313 thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
314 thumbPositionAnimation.Play();
316 thumbSizeAnimation?.Stop();
317 thumbSizeAnimation = AnimateVisual(thumbVisual, "size", thumbVisual.Size, 0, (int)durationMs, builtinAlphaFunction);
318 thumbSizeAnimation.Play();
322 /// <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>
323 [EditorBrowsable(EditorBrowsableState.Never)]
324 public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
326 if (calculator == null)
331 calculator.currentPosition = position;
332 thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, TrackPadding);
336 thumbVisual.UpdateVisual(true);
341 // TODO Support non built-in alpha function for visual trainsition in DALi.
342 AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
344 thumbPositionAnimation?.Stop();
345 thumbPositionAnimation = AnimateVisual(thumbVisual, "position", thumbVisual.Position, 0, (int)durationMs, builtinAlphaFunction);
346 thumbPositionAnimation.Play();
350 [EditorBrowsable(EditorBrowsableState.Never)]
351 public override void OnRelayout(Vector2 size, RelayoutContainer container)
353 base.OnRelayout(size, container);
355 if (size.Width == containerSize.Width && size.Height == containerSize.Height)
360 containerSize = new Size(size.Width, size.Height);
362 if (calculator == null)
367 trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, TrackPadding);
368 trackVisual.Position = calculator.CalculateTrackPosition(TrackPadding);
369 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
370 thumbVisual.Position = calculator.CalculateThumbPosition(trackVisual.Size, thumbVisual.Size, TrackPadding);
372 trackVisual.UpdateVisual(true);
373 thumbVisual.UpdateVisual(true);
377 [EditorBrowsable(EditorBrowsableState.Never)]
378 protected override ViewStyle GetViewStyle()
380 return new ScrollbarStyle();
384 /// Update TrackThickness property of the scrollbar.
386 /// <param name="thickness">The width of the track.</param>
387 [EditorBrowsable(EditorBrowsableState.Never)]
388 protected virtual void UpdateTrackThickness(float thickness)
390 if (trackVisual == null)
395 trackVisual.Size = calculator.CalculateTrackSize(thickness, containerSize, TrackPadding);
396 trackVisual.UpdateVisual(true);
400 /// Update ThumbThickness property of the scrollbar.
402 /// <param name="thickness">The width of the track.</param>
403 [EditorBrowsable(EditorBrowsableState.Never)]
404 protected virtual void UpdateThumbThickness(float thickness)
406 if (thumbVisual == null)
411 thumbVisual.Size = calculator.CalculateThumbSize(thickness, trackVisual.Size);
412 thumbVisual.UpdateVisual(true);
416 /// Update TrackColor property of the scrollbar.
418 /// <param name="color">The color of the track.</param>
419 [EditorBrowsable(EditorBrowsableState.Never)]
420 protected virtual void UpdateTrackColor(Color color)
422 if (trackVisual == null)
427 trackVisual.MixColor = color;
428 trackVisual.UpdateVisual(true);
432 /// Update ThumbColor property of the scrollbar.
434 /// <param name="color">The color of the thumb.</param>
435 [EditorBrowsable(EditorBrowsableState.Never)]
436 protected virtual void UpdateThumbColor(Color color)
438 if (thumbVisual == null)
443 thumbVisual.MixColor = color;
444 thumbVisual.UpdateVisual(true);
448 /// Update TrackPadding property of the scrollbar.
450 /// <param name="trackPadding">The padding of the track.</param>
451 protected virtual void UpdateTrackPadding(Extents trackPadding)
453 if (calculator == null)
458 trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
459 trackVisual.Position = calculator.CalculateTrackPosition(trackPadding);
460 thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
461 thumbVisual.Position = calculator.CalculateThumbPaddingPosition(trackVisual.Size, thumbVisual.Size, thumbVisual.Position, trackPadding);
463 trackVisual.UpdateVisual(true);
464 thumbVisual.UpdateVisual(true);
472 private abstract class Calculator
474 public float contentLength;
475 public float visibleLength;
476 public float currentPosition;
478 public Calculator(float contentLength, float visibleLength, float currentPosition)
480 this.contentLength = contentLength;
481 this.visibleLength = visibleLength;
482 this.currentPosition = currentPosition;
485 public bool CalculateThumbVisibility()
487 return contentLength > visibleLength;
490 public abstract Visual.AlignType CalculatorTrackAlign();
491 public abstract Visual.AlignType CalculatorThumbAlign();
492 public abstract Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding);
493 public abstract Vector2 CalculateTrackPosition(Extents trackPadding);
494 public abstract Size CalculateThumbSize(float thickness, Size trackSize);
495 public abstract Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding);
496 public abstract Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding);
497 public abstract Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding);
500 private class HorizontalCalculator : Calculator
502 public HorizontalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
506 public override Visual.AlignType CalculatorTrackAlign()
508 return Visual.AlignType.BottomCenter;
511 public override Visual.AlignType CalculatorThumbAlign()
513 return Visual.AlignType.BottomBegin;
516 public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
518 return new Size(containerSize.Width - trackPadding.Start - trackPadding.End, thickness);
521 public override Vector2 CalculateTrackPosition(Extents trackPadding)
523 return new Vector2(0, -trackPadding.Bottom);
526 public override Size CalculateThumbSize(float thickness, Size trackSize)
528 return new Size(trackSize.Width * visibleLength / contentLength, thickness);
531 public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
533 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Bottom;
534 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
535 return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, -padding);
538 public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
540 float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Bottom;
541 return new Vector2(thumbCurrentPosition.X, -padding);
544 public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding)
546 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
547 return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, thumbCurrentPosition.Y);
551 private class VerticalCalculator : Calculator
553 public VerticalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
557 public override Visual.AlignType CalculatorTrackAlign()
559 return Visual.AlignType.CenterEnd;
562 public override Visual.AlignType CalculatorThumbAlign()
564 return Visual.AlignType.TopEnd;
567 public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
569 return new Size(thickness, containerSize.Height - trackPadding.Top - trackPadding.Bottom);
572 public override Vector2 CalculateTrackPosition(Extents trackPadding)
574 return new Vector2(-trackPadding.End, 0);
577 public override Size CalculateThumbSize(float thickness, Size trackSize)
579 return new Size(thickness, trackSize.Height * visibleLength / contentLength);
582 public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
584 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.End;
585 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
586 return new Vector2(-padding, trackPadding.Top + trackSize.Height * pos / contentLength);
589 public override Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding)
591 float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.End;
592 return new Vector2(-padding, thumbCurrentPosition.Y);
595 public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbPosition, Extents trackPadding)
597 float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
598 return new Vector2(thumbPosition.X, trackPadding.Top + trackSize.Height * pos / contentLength);