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 Tizen.NUI.BaseComponents;
19 using Tizen.NUI.Binding;
20 using Tizen.NUI.Components;
21 using System.ComponentModel;
23 namespace Tizen.NUI.Wearable
26 /// Value Changed event data.
28 [EditorBrowsable(EditorBrowsableState.Never)]
29 public class CircularSliderValueChangedEventArgs : EventArgs
31 private float currentValue = 0.0f;
36 [EditorBrowsable(EditorBrowsableState.Never)]
37 public float CurrentValue
39 get { return currentValue; }
40 set { currentValue = value; }
45 /// The CircularSlider class of Wearable is used to let users select a value from a continuous or discrete range of values by moving the slider thumb.
46 /// CircularSlider shows the current value with the length of the line.
48 [EditorBrowsable(EditorBrowsableState.Never)]
49 public class CircularSlider : Control
53 /// <summary>Bindable property of Thickness</summary>
54 [EditorBrowsable(EditorBrowsableState.Never)]
55 public static readonly BindableProperty ThicknessProperty = BindableProperty.Create(nameof(Thickness), typeof(float), typeof(CircularSlider), default(float), propertyChanged: (bindable, oldValue, newValue) =>
57 var instance = ((CircularSlider)bindable);
58 instance.CurrentStyle.Thickness = (float)newValue;
59 instance.UpdateVisualThickness((float)newValue);
61 defaultValueCreator: (bindable) =>
63 return ((CircularSlider)bindable).CurrentStyle.Thickness;
66 /// <summary>Bindable property of MaxValue</summary>
67 [EditorBrowsable(EditorBrowsableState.Never)]
68 public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(float), typeof(CircularSlider), default(float), propertyChanged: (bindable, oldValue, newValue) =>
70 var instance = (CircularSlider)bindable;
73 instance.maxValue = (float)newValue;
74 instance.UpdateValue();
77 defaultValueCreator: (bindable) =>
79 var instance = (CircularSlider)bindable;
80 return instance.maxValue;
83 /// <summary>Bindable property of MinValue</summary>
84 [EditorBrowsable(EditorBrowsableState.Never)]
85 public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(float), typeof(CircularSlider), default(float), propertyChanged: (bindable, oldValue, newValue) =>
87 var instance = (CircularSlider)bindable;
90 instance.minValue = (float)newValue;
91 instance.UpdateValue();
94 defaultValueCreator: (bindable) =>
96 var instance = (CircularSlider)bindable;
97 return instance.minValue;
100 /// <summary>Bindable property of CurrentValue</summary>
101 [EditorBrowsable(EditorBrowsableState.Never)]
102 public static readonly BindableProperty CurrentValueProperty = BindableProperty.Create(nameof(CurrentValue), typeof(float), typeof(CircularSlider), default(float), propertyChanged: (bindable, oldValue, newValue) =>
104 var instance = (CircularSlider)bindable;
105 if (newValue != null)
107 if ((float)newValue > instance.maxValue || (float)newValue < instance.minValue)
111 instance.currentValue = (float)newValue;
112 instance.UpdateValue();
115 defaultValueCreator: (bindable) =>
117 var instance = (CircularSlider)bindable;
118 return instance.currentValue;
121 /// <summary>Bindable property of TrackColor</summary>
122 [EditorBrowsable(EditorBrowsableState.Never)]
123 public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(CircularSlider), null, propertyChanged: (bindable, oldValue, newValue) =>
125 var instance = (CircularSlider)bindable;
126 instance.CurrentStyle.TrackColor = (Color)newValue;
127 instance.UpdateTrackVisualColor((Color)newValue);
129 defaultValueCreator: (bindable) =>
131 return ((CircularSlider)bindable).CurrentStyle.TrackColor;
134 /// <summary>Bindable property of ProgressColor</summary>
135 [EditorBrowsable(EditorBrowsableState.Never)]
136 public static readonly BindableProperty ProgressColorProperty = BindableProperty.Create(nameof(ProgressColor), typeof(Color), typeof(CircularSlider), null, propertyChanged: (bindable, oldValue, newValue) =>
138 var instance = (CircularSlider)bindable;
139 instance.CurrentStyle.ProgressColor = (Color)newValue;
140 instance.UpdateProgressVisualColor((Color)newValue);
142 defaultValueCreator: (bindable) =>
144 return ((CircularSlider)bindable).CurrentStyle.ProgressColor;
147 /// <summary>Bindable property of ThumbSize</summary>
148 [EditorBrowsable(EditorBrowsableState.Never)]
149 public static readonly BindableProperty ThumbSizeProperty = BindableProperty.Create(nameof(ThumbSize), typeof(Size), typeof(CircularSlider), new Size(0,0), propertyChanged: (bindable, oldValue, newValue) =>
151 var instance = (CircularSlider)bindable;
152 if (newValue != null)
154 instance.thumbSize = (Size)newValue;
155 instance.UpdateThumbVisualSize((Size)newValue);
158 defaultValueCreator: (bindable) =>
160 var instance = (CircularSlider)bindable;
161 return instance.thumbSize;
164 /// <summary>Bindable property of ThumbColor</summary>
165 [EditorBrowsable(EditorBrowsableState.Never)]
166 public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(CircularSlider), null, propertyChanged: (bindable, oldValue, newValue) =>
168 var instance = (CircularSlider)bindable;
169 instance.CurrentStyle.ThumbColor = (Color)newValue;
170 instance.UpdateThumbVisualColor((Color)newValue);
172 defaultValueCreator: (bindable) =>
174 return ((CircularSlider)bindable).CurrentStyle.ThumbColor;
177 /// <summary>Bindable property of IsEnabled</summary>
178 [EditorBrowsable(EditorBrowsableState.Never)]
179 public static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(nameof(IsEnabled), typeof(bool), typeof(CircularSlider), true, propertyChanged: (bindable, oldValue, newValue) =>
181 var instance = (CircularSlider)bindable;
182 if (newValue != null)
184 instance.privateIsEnabled = (bool)newValue;
187 defaultValueCreator: (bindable) =>
189 var instance = (CircularSlider)bindable;
190 return instance.privateIsEnabled;
193 private const string TrackVisualName = "Track";
194 private const string ProgressVisualName = "Progress";
195 private const string ThumbVisualName = "Thumb";
196 private ArcVisual trackVisual;
197 private ArcVisual progressVisual;
198 private ArcVisual thumbVisual;
200 private float maxValue = 100;
201 private float minValue = 0;
202 private float currentValue = 0;
203 private Size thumbSize;
204 private bool isEnabled = true;
206 float sliderPadding = 6.0f;
208 private Animation sweepAngleAnimation;
209 private Animation thumbAnimation;
216 static CircularSlider()
218 ThemeManager.AddPackageTheme(new DefaultThemeCreator());
222 /// The constructor of CircularSlider.
224 [EditorBrowsable(EditorBrowsableState.Never)]
225 public CircularSlider() : base()
231 /// The constructor of the CircularSlider class with specific style.
233 /// <param name="progressStyle">The style object to initialize the CircularSlider.</param>
234 [EditorBrowsable(EditorBrowsableState.Never)]
235 public CircularSlider(CircularSliderStyle progressStyle) : base(progressStyle)
240 #endregion Constructors
245 /// The value changed event handler.
247 [EditorBrowsable(EditorBrowsableState.Never)]
248 public event EventHandler<CircularSliderValueChangedEventArgs> ValueChanged;
255 /// Return a copied Style instance of CircularSlider
258 /// It returns copied Style instance and changing it does not effect to the CircularSlider.
259 /// Style setting is possible by using constructor or the function of ApplyStyle(ViewStyle viewStyle)
261 [EditorBrowsable(EditorBrowsableState.Never)]
262 public new CircularSliderStyle Style
266 var result = new CircularSliderStyle(ViewStyle as CircularSliderStyle);
267 result.CopyPropertiesFromView(this);
273 /// The thickness of the track and progress.
275 [EditorBrowsable(EditorBrowsableState.Never)]
276 public float Thickness
280 return (float)GetValue(ThicknessProperty);
284 SetValue(ThicknessProperty, value);
289 /// The property to get/set the maximum value of the CircularSlider.
290 /// The default value is 100.
292 [EditorBrowsable(EditorBrowsableState.Never)]
293 public float MaxValue
297 return (float)GetValue(MaxValueProperty);
301 SetValue(MaxValueProperty, value);
306 /// The property to get/set the minimum value of the CircularSlider.
307 /// The default value is 0.
309 [EditorBrowsable(EditorBrowsableState.Never)]
310 public float MinValue
314 return (float)GetValue(MinValueProperty);
318 SetValue(MinValueProperty, value);
323 /// The property to get/set the current value of the CircularSlider.
324 /// The default value is 0.
326 [EditorBrowsable(EditorBrowsableState.Never)]
327 public float CurrentValue
331 return (float)GetValue(CurrentValueProperty);
335 if (sweepAngleAnimation)
337 sweepAngleAnimation.Stop();
339 // For the first Animation effect
340 sweepAngleAnimation = AnimateVisual(progressVisual, "sweepAngle", progressVisual.SweepAngle, 0, 100, AlphaFunction.BuiltinFunctions.EaseIn);
342 SetValue(CurrentValueProperty, value);
349 /// The property to get/set Track object color of the CircularSlider.
351 [EditorBrowsable(EditorBrowsableState.Never)]
352 public Color TrackColor
356 return (Color)GetValue(TrackColorProperty);
360 SetValue(TrackColorProperty, value);
365 /// The property to get/set Progress object color of the CircularSlider.
367 [EditorBrowsable(EditorBrowsableState.Never)]
368 public Color ProgressColor
372 return (Color)GetValue(ProgressColorProperty);
376 SetValue(ProgressColorProperty, value);
381 /// Gets or sets the size of the thumb of Slider.
383 [EditorBrowsable(EditorBrowsableState.Never)]
384 public Size ThumbSize
388 return (Size)GetValue(ThumbSizeProperty);
392 SetValue(ThumbSizeProperty, value);
397 /// The property to get/set Thumb object color of the CircularSlider.
399 [EditorBrowsable(EditorBrowsableState.Never)]
400 public Color ThumbColor
404 return (Color)GetValue(ThumbColorProperty);
408 SetValue(ThumbColorProperty, value);
413 /// Flag to be enabled or disabled in CircularSlider.
415 [EditorBrowsable(EditorBrowsableState.Never)]
416 public bool IsEnabled
420 return (bool)GetValue(IsEnabledProperty);
424 SetValue(IsEnabledProperty, value);
427 private bool privateIsEnabled
438 UpdateTrackVisualColor(new Color(0.0f, 0.16f, 0.30f, 1.0f)); // #002A4D
442 UpdateTrackVisualColor(new Color(0.25f, 0.25f, 0.25f, 1.0f)); // #404040
447 private CircularSliderStyle CurrentStyle => ViewStyle as CircularSliderStyle;
449 #endregion Properties
455 /// Dispose Progress and all children on it.
457 /// <param name="type">Dispose type.</param>
458 [EditorBrowsable(EditorBrowsableState.Never)]
459 protected override void Dispose(DisposeTypes type)
466 if (type == DisposeTypes.Explicit)
469 progressVisual = null;
477 /// Update progress value
479 [EditorBrowsable(EditorBrowsableState.Never)]
480 protected virtual void UpdateValue()
482 if (null == trackVisual || null == progressVisual || null == thumbVisual)
487 if (minValue >= maxValue || currentValue < minValue || currentValue > maxValue)
492 HandleProgressVisualVisibility();
494 UpdateProgressVisualSweepAngle();
498 /// Get Progress style.
500 /// <returns>The default progress style.</returns>
501 [EditorBrowsable(EditorBrowsableState.Never)]
502 protected override ViewStyle CreateViewStyle()
504 return new CircularSliderStyle();
507 private void Initialize()
509 Size = new Size(360.0f, 360.0f);
511 sweepAngleAnimation?.Stop();
512 sweepAngleAnimation = null;
514 thumbAnimation?.Stop();
515 thumbAnimation = null;
517 trackVisual = new ArcVisual
519 SuppressUpdateVisual = true,
520 Size = new Size(this.Size.Width - sliderPadding, this.Size.Height - sliderPadding),
521 SizePolicy = VisualTransformPolicyType.Absolute,
522 Thickness = this.Thickness,
523 Cap = ArcVisual.CapType.Butt,
524 MixColor = TrackColor,
528 this.AddVisual(TrackVisualName, trackVisual);
530 progressVisual = new ArcVisual
532 SuppressUpdateVisual = true,
533 Size = new Size(this.Size.Width - sliderPadding, this.Size.Height - sliderPadding),
534 SizePolicy = VisualTransformPolicyType.Absolute,
535 Thickness = this.Thickness,
536 Cap = ArcVisual.CapType.Butt,
537 MixColor = ProgressColor,
541 this.AddVisual(ProgressVisualName, progressVisual);
543 thumbVisual = new ArcVisual
545 SuppressUpdateVisual = true,
546 Size = new Size(this.Size.Width + sliderPadding, this.Size.Height + sliderPadding),
547 SizePolicy = VisualTransformPolicyType.Absolute,
548 Thickness = this.ThumbSize.Width,
549 Cap = ArcVisual.CapType.Round,
550 MixColor = this.ThumbColor,
554 this.AddVisual(ThumbVisualName, thumbVisual);
556 HandleProgressVisualVisibility();
558 UpdateProgressVisualSweepAngle();
561 private void HandleProgressVisualVisibility()
565 progressVisual.Opacity = 1.0f;
569 progressVisual.Opacity = 0.6f;
573 private void UpdateVisualThickness(float thickness)
575 if (trackVisual == null)
580 trackVisual.Thickness = thickness;
581 progressVisual.Thickness = thickness;
583 trackVisual.UpdateVisual(true);
584 progressVisual.UpdateVisual(true);
587 private void UpdateProgressVisualSweepAngle()
589 float progressRatio = (float)(currentValue - minValue) / (float)(maxValue - minValue);
590 float progressWidth = 360.0f * progressRatio; // Circle
592 progressVisual.SweepAngle = progressWidth;
593 thumbVisual.StartAngle = progressWidth;
595 if (!sweepAngleAnimation)
597 progressVisual.UpdateVisual(true);
598 thumbVisual.UpdateVisual(true);
602 private void UpdateAnimation()
604 // TODO : Currently not sure which effect is needed.
605 AlphaFunction.BuiltinFunctions builtinAlphaFunction = AlphaFunction.BuiltinFunctions.EaseOut;
607 if (sweepAngleAnimation)
609 sweepAngleAnimation.Stop();
613 thumbAnimation.Stop();
616 sweepAngleAnimation = AnimateVisual(progressVisual, "sweepAngle", progressVisual.SweepAngle, 0, 500, builtinAlphaFunction);
617 thumbAnimation = AnimateVisual(thumbVisual, "startAngle", thumbVisual.StartAngle, 0, 500, builtinAlphaFunction);
619 if (sweepAngleAnimation)
621 sweepAngleAnimation.Play();
622 thumbAnimation.Play();
625 ValueChanged?.Invoke(this, new CircularSliderValueChangedEventArgs() { CurrentValue = currentValue });
628 private void UpdateTrackVisualColor(Color trackColor)
630 if (trackVisual == null)
635 trackVisual.MixColor = trackColor;
636 trackVisual.UpdateVisual(true);
639 private void UpdateProgressVisualColor(Color progressColor)
641 if (progressVisual == null)
646 progressVisual.MixColor = progressColor;
647 if (!isEnabled) // Dim state
649 progressVisual.Opacity = 0.6f;
652 progressVisual.UpdateVisual(true);
655 private void UpdateThumbVisualSize(Size thumbSize)
657 if (thumbVisual == null)
662 thumbVisual.Thickness = thumbSize.Width;
663 thumbVisual.UpdateVisual(true);
666 private void UpdateThumbVisualColor(Color thumbColor)
668 if (thumbVisual == null)
673 thumbVisual.MixColor = thumbColor;
674 thumbVisual.UpdateVisual(true);