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;
21 using Tizen.NUI.Components;
23 namespace Tizen.NUI.Wearable
26 /// The CircualrScrollbar is a wearable NUI component that can be linked to the scrollable objects
27 /// indicating the current scroll position of the scrollable object.<br />
29 [Obsolete("This has been deprecated in API12")]
30 [EditorBrowsable(EditorBrowsableState.Never)]
31 public class CircularScrollbar : ScrollbarBase
35 /// <summary>Bindable property of Thickness</summary>
36 [Obsolete("This has been deprecated in API12")]
37 [EditorBrowsable(EditorBrowsableState.Never)]
38 public static readonly BindableProperty ThicknessProperty = BindableProperty.Create(nameof(Thickness), typeof(float), typeof(CircularScrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
40 var instance = ((CircularScrollbar)bindable);
41 float value = (float?)newValue ?? 0;
42 instance.CurrentStyle.Thickness = value;
43 instance.UpdateVisualThickness(value);
45 defaultValueCreator: (bindable) =>
47 var instance = (CircularScrollbar)bindable;
48 return instance.CurrentStyle.Thickness ?? 0;
51 /// <summary>Bindable property of TrackSweepAngle</summary>
52 [EditorBrowsable(EditorBrowsableState.Never)]
53 public static readonly BindableProperty TrackSweepAngleProperty = BindableProperty.Create(nameof(TrackSweepAngle), typeof(float), typeof(CircularScrollbar), default(float), propertyChanged: (bindable, oldValue, newValue) =>
55 var instance = ((CircularScrollbar)bindable);
56 float value = (float?)newValue ?? 0;
57 instance.CurrentStyle.TrackSweepAngle = value;
58 instance.UpdateTrackVisualSweepAngle(value);
60 defaultValueCreator: (bindable) =>
62 var instance = (CircularScrollbar)bindable;
63 return instance.CurrentStyle.TrackSweepAngle ?? 0;
66 /// <summary>Bindable property of TrackColor</summary>
67 [EditorBrowsable(EditorBrowsableState.Never)]
68 public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(CircularScrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
70 var instance = ((CircularScrollbar)bindable);
71 instance.CurrentStyle.TrackColor = (Color)newValue;
72 instance.UpdateTrackVisualColor((Color)newValue);
74 defaultValueCreator: (bindable) =>
76 return ((CircularScrollbar)bindable).CurrentStyle.TrackColor;
79 /// <summary>Bindable property of ThumbColor</summary>
80 [EditorBrowsable(EditorBrowsableState.Never)]
81 public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(CircularScrollbar), null, propertyChanged: (bindable, oldValue, newValue) =>
83 var instance = ((CircularScrollbar)bindable);
84 instance.CurrentStyle.ThumbColor = (Color)newValue;
85 instance.UpdateThumbVisualColor((Color)newValue);
87 defaultValueCreator: (bindable) =>
89 return ((CircularScrollbar)bindable).CurrentStyle.ThumbColor;
92 private ArcVisual trackVisual;
93 private ArcVisual thumbVisual;
94 private float contentLength;
95 private float visibleLength;
96 private float previousPosition;
97 private float currentPosition;
98 private float directionAlpha;
99 private Size containerSize = new Size(0, 0);
100 private Animation thumbStartAngleAnimation;
101 private Animation thumbSweepAngleAnimation;
109 /// Create an empty CircularScrollbar.
111 [Obsolete("This has been deprecated in API12")]
112 public CircularScrollbar() : base()
117 /// Create a CircularScrollbar and initialize with properties.
119 /// <param name="contentLength">The length of the scrollable content area.</param>
120 /// <param name="viewportLength">The length of the viewport representing the amount of visible content.</param>
121 /// <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>
122 /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical by default.</param>
123 [Obsolete("This has been deprecated in API12")]
124 [EditorBrowsable(EditorBrowsableState.Never)]
125 public CircularScrollbar(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false) : base()
127 Initialize(contentLength, viewportLength, currentPosition, isHorizontal);
131 /// Create an empty CircularScrollbar with a CircularScrollbarStyle instance to set style properties.
133 [Obsolete("This has been deprecated in API12")]
134 [EditorBrowsable(EditorBrowsableState.Never)]
135 public CircularScrollbar(CircularScrollbarStyle style) : base(style)
140 /// Static constructor to initialize bindable properties when loading.
142 static CircularScrollbar()
144 ThemeManager.AddPackageTheme(DefaultThemeCreator.Instance);
147 #endregion Constructors
153 /// The thickness of the scrollbar and track.
155 [Obsolete("This has been deprecated in API12")]
156 [EditorBrowsable(EditorBrowsableState.Never)]
157 public float Thickness
159 get => (float)GetValue(ThicknessProperty);
160 set => SetValue(ThicknessProperty, value);
164 /// The sweep angle of track area in degrees.
167 /// Values below 6 degrees are treated as 6 degrees.
168 /// Values exceeding 180 degrees are treated as 180 degrees.
170 [Obsolete("This has been deprecated in API12")]
171 [EditorBrowsable(EditorBrowsableState.Never)]
172 public float TrackSweepAngle
174 get => (float)GetValue(TrackSweepAngleProperty);
175 set => SetValue(TrackSweepAngleProperty, value);
179 /// The color of the track part.
181 [Obsolete("This has been deprecated in API12")]
182 [EditorBrowsable(EditorBrowsableState.Never)]
183 public Color TrackColor
185 get => (Color)GetValue(TrackColorProperty);
186 set => SetValue(TrackColorProperty, value);
190 /// The color of the thumb part.
192 [Obsolete("This has been deprecated in API12")]
193 [EditorBrowsable(EditorBrowsableState.Never)]
194 public Color ThumbColor
196 get => (Color)GetValue(ThumbColorProperty);
197 set => SetValue(ThumbColorProperty, value);
200 private CircularScrollbarStyle CurrentStyle => ViewStyle as CircularScrollbarStyle;
202 #endregion Properties
208 [Obsolete("This has been deprecated in API12")]
209 [EditorBrowsable(EditorBrowsableState.Never)]
210 public override void Initialize(float contentLength, float viewportLenth, float currentPosition, bool isHorizontal = false)
212 this.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
213 this.visibleLength = viewportLenth;
214 this.currentPosition = currentPosition;
215 this.directionAlpha = isHorizontal ? 270.0f : 0.0f;
217 thumbStartAngleAnimation?.Stop();
218 thumbStartAngleAnimation = null;
220 thumbSweepAngleAnimation?.Stop();
221 thumbSweepAngleAnimation = null;
224 float trackSweepAngle = CalculateTrackSweepAngle(TrackSweepAngle);
225 float trackStartAngle = CalculateTrackStartAngle(trackSweepAngle);
226 float thumbSweepAngle = CalculateThumbSweepAngle(TrackSweepAngle);
227 float thumbStartAngle = CalculateThumbStartAngle(currentPosition, trackStartAngle, trackSweepAngle, thumbSweepAngle);
229 if (trackVisual == null)
231 trackVisual = new ArcVisual
233 SuppressUpdateVisual = true,
234 Thickness = this.Thickness,
235 Cap = ArcVisual.CapType.Round,
236 MixColor = TrackColor,
237 Size = containerSize - new Size(2, 2),
238 SizePolicy = VisualTransformPolicyType.Absolute,
239 SweepAngle = trackSweepAngle,
240 StartAngle = trackStartAngle,
243 AddVisual("Track", trackVisual);
247 trackVisual.SweepAngle = trackSweepAngle;
248 trackVisual.StartAngle = trackStartAngle;
249 trackVisual.UpdateVisual(true);
252 if (thumbVisual == null)
254 thumbVisual = new ArcVisual
256 SuppressUpdateVisual = true,
257 Thickness = trackVisual.Thickness,
258 Cap = ArcVisual.CapType.Round,
259 MixColor = ThumbColor,
260 Size = containerSize - new Size(2, 2),
261 SizePolicy = VisualTransformPolicyType.Absolute,
262 SweepAngle = thumbSweepAngle,
263 StartAngle = thumbStartAngle,
264 Opacity = CalculateThumbVisibility() ? 1.0f : 0.0f,
267 AddVisual("Thumb", thumbVisual);
271 thumbVisual.SweepAngle = thumbSweepAngle;
272 thumbVisual.StartAngle = thumbStartAngle;
273 thumbVisual.UpdateVisual(true);
278 [Obsolete("This has been deprecated in API12")]
279 [EditorBrowsable(EditorBrowsableState.Never)]
280 public override void Update(float contentLength, float viewportLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
282 this.visibleLength = viewportLength;
283 Update(contentLength, position, durationMs, alphaFunction);
287 [Obsolete("This has been deprecated in API12")]
288 [EditorBrowsable(EditorBrowsableState.Never)]
289 public override void Update(float contentLength, float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
291 this.previousPosition = this.currentPosition;
292 this.currentPosition = position;
293 this.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
295 if (thumbVisual == null)
300 thumbVisual.SweepAngle = CalculateThumbSweepAngle(TrackSweepAngle);
301 thumbVisual.StartAngle = CalculateThumbStartAngle(position, trackVisual.StartAngle, trackVisual.SweepAngle, thumbVisual.SweepAngle);
302 thumbVisual.Opacity = CalculateThumbVisibility() ? 1.0f : 0.0f;
306 thumbVisual.UpdateVisual(true);
311 // TODO Support non built-in alpha function for visual trainsition in DALi.
312 AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
314 thumbStartAngleAnimation?.Stop();
315 thumbStartAngleAnimation = AnimateVisual(thumbVisual, "startAngle", thumbVisual.StartAngle, 0, (int)durationMs, builtinAlphaFunction);
316 thumbStartAngleAnimation.Play();
318 thumbSweepAngleAnimation?.Stop();
319 thumbSweepAngleAnimation = AnimateVisual(thumbVisual, "sweepAngle", thumbVisual.SweepAngle, 0, (int)durationMs, builtinAlphaFunction);
320 thumbSweepAngleAnimation.Play();
324 [Obsolete("This has been deprecated in API12")]
325 [EditorBrowsable(EditorBrowsableState.Never)]
326 public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
328 previousPosition = currentPosition;
329 currentPosition = position;
331 if (ControlState == ControlState.Disabled)
336 if (thumbVisual == null)
341 var oldThumbStartAngle = thumbVisual.StartAngle;
343 thumbVisual.StartAngle = CalculateThumbStartAngle(position, trackVisual.StartAngle, trackVisual.SweepAngle, thumbVisual.SweepAngle);
347 thumbVisual.UpdateVisual(true);
352 // TODO Support non built-in alpha function for visual trainsition in DALi.
353 AlphaFunction.BuiltinFunctions builtinAlphaFunction = alphaFunction?.GetBuiltinFunction() ?? AlphaFunction.BuiltinFunctions.Default;
355 thumbStartAngleAnimation?.Stop();
356 thumbStartAngleAnimation = AnimateVisual(thumbVisual, "startAngle", thumbVisual.StartAngle, 0, (int)durationMs, builtinAlphaFunction);
357 thumbStartAngleAnimation.Play();
361 [Obsolete("This has been deprecated in API12")]
362 [EditorBrowsable(EditorBrowsableState.Never)]
363 public override void OnRelayout(Vector2 size, RelayoutContainer container)
365 base.OnRelayout(size, container);
367 if (size == null || container == null || containerSize == null)
372 if (size.Width == containerSize.Width && size.Height == containerSize.Height)
377 containerSize = new Size(size.Width, size.Height);
379 if (trackVisual == null)
384 trackVisual.Size = containerSize - new Size(2, 2);
385 thumbVisual.Size = containerSize - new Size(2, 2);
387 trackVisual.UpdateVisual(true);
388 thumbVisual.UpdateVisual(true);
392 [Obsolete("This has been deprecated in API12")]
393 [EditorBrowsable(EditorBrowsableState.Never)]
394 public override void ApplyStyle(ViewStyle viewStyle)
396 if (viewStyle == null) return;
397 if (viewStyle.WidthResizePolicy == null) viewStyle.WidthResizePolicy = ResizePolicyType.FillToParent;
398 if (viewStyle.HeightResizePolicy == null) viewStyle.HeightResizePolicy = ResizePolicyType.FillToParent;
400 base.ApplyStyle(viewStyle);
404 [Obsolete("This has been deprecated in API12")]
405 [EditorBrowsable(EditorBrowsableState.Never)]
406 protected override ViewStyle CreateViewStyle()
408 return new CircularScrollbarStyle();
411 private float CalculateTrackStartAngle(float currentTrackSweepAngle)
413 return ((180.0f - currentTrackSweepAngle) / 2.0f) + directionAlpha;
416 private float CalculateTrackSweepAngle(float inputTrackSweepAngle)
418 return Math.Min(Math.Max(inputTrackSweepAngle, 3), 180);
421 private float CalculateThumbStartAngle(float position, float trackStartAngle, float trackSweepAngle, float thumbSweepAngle)
423 float minAngle = trackStartAngle;
424 float maxAngle = trackStartAngle + trackSweepAngle - thumbSweepAngle;
425 float resultAngle = trackStartAngle + (trackSweepAngle * (position < 0.0f ? 0.0f : position) / contentLength);
427 return Math.Min(Math.Max(resultAngle, minAngle), maxAngle);
430 private float CalculateThumbSweepAngle(float trackSweepAngle)
432 return trackSweepAngle * visibleLength / contentLength;
435 private bool CalculateThumbVisibility()
437 return contentLength > visibleLength;
440 private void UpdateVisualThickness(float thickness)
442 if (trackVisual == null)
447 trackVisual.Thickness = thickness;
448 thumbVisual.Thickness = thickness;
450 trackVisual.UpdateVisual(true);
451 thumbVisual.UpdateVisual(true);
454 private void UpdateTrackVisualSweepAngle(float trackSweepAngle)
456 if (trackVisual == null || thumbVisual == null)
461 trackVisual.SweepAngle = CalculateTrackSweepAngle(trackSweepAngle);
462 trackVisual.StartAngle = CalculateTrackStartAngle(trackVisual.SweepAngle);
464 thumbVisual.SweepAngle = CalculateThumbSweepAngle(TrackSweepAngle);
465 thumbVisual.StartAngle = CalculateThumbStartAngle(currentPosition, trackVisual.StartAngle, trackVisual.SweepAngle, thumbVisual.SweepAngle);
467 trackVisual.UpdateVisual(true);
468 thumbVisual.UpdateVisual(true);
471 private void UpdateTrackVisualColor(Color trackColor)
473 if (trackVisual == null)
478 trackVisual.MixColor = trackColor;
479 trackVisual.UpdateVisual(true);
482 private void UpdateThumbVisualColor(Color thumbColor)
484 if (thumbVisual == null)
489 thumbVisual.MixColor = thumbColor;
490 thumbVisual.UpdateVisual(true);
494 [Obsolete("This has been deprecated in API12")]
495 [EditorBrowsable(EditorBrowsableState.Never)]
496 public override float ScrollPosition
498 get => Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
502 [Obsolete("This has been deprecated in API12")]
503 [EditorBrowsable(EditorBrowsableState.Never)]
504 public override float ScrollCurrentPosition
508 float length = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
510 if (thumbStartAngleAnimation != null)
512 float progress = thumbStartAngleAnimation.CurrentProgress;
513 float previousLength = Math.Min(Math.Max(previousPosition, 0.0f), contentLength - visibleLength);
515 length = ((1.0f - progress) * previousLength) + (progress * length);