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 /// The constructor of CircularSlider.
220 [EditorBrowsable(EditorBrowsableState.Never)]
221 public CircularSlider() : base()
227 /// The constructor of the CircularSlider class with specific style.
229 /// <param name="progressStyle">The style object to initialize the CircularSlider.</param>
230 [EditorBrowsable(EditorBrowsableState.Never)]
231 public CircularSlider(CircularSliderStyle progressStyle) : base(progressStyle)
236 #endregion Constructors
241 /// The value changed event handler.
243 [EditorBrowsable(EditorBrowsableState.Never)]
244 public event EventHandler<CircularSliderValueChangedEventArgs> ValueChanged;
251 /// Return a copied Style instance of CircularSlider
254 /// It returns copied Style instance and changing it does not effect to the CircularSlider.
255 /// Style setting is possible by using constructor or the function of ApplyStyle(ViewStyle viewStyle)
257 [EditorBrowsable(EditorBrowsableState.Never)]
258 public new CircularSliderStyle Style
262 var result = new CircularSliderStyle(ViewStyle as CircularSliderStyle);
263 result.CopyPropertiesFromView(this);
269 /// The thickness of the track and progress.
271 [EditorBrowsable(EditorBrowsableState.Never)]
272 public float Thickness
276 return (float)GetValue(ThicknessProperty);
280 SetValue(ThicknessProperty, value);
285 /// The property to get/set the maximum value of the CircularSlider.
286 /// The default value is 100.
288 [EditorBrowsable(EditorBrowsableState.Never)]
289 public float MaxValue
293 return (float)GetValue(MaxValueProperty);
297 SetValue(MaxValueProperty, value);
302 /// The property to get/set the minimum value of the CircularSlider.
303 /// The default value is 0.
305 [EditorBrowsable(EditorBrowsableState.Never)]
306 public float MinValue
310 return (float)GetValue(MinValueProperty);
314 SetValue(MinValueProperty, value);
319 /// The property to get/set the current value of the CircularSlider.
320 /// The default value is 0.
322 [EditorBrowsable(EditorBrowsableState.Never)]
323 public float CurrentValue
327 return (float)GetValue(CurrentValueProperty);
331 if (sweepAngleAnimation)
333 sweepAngleAnimation.Stop();
335 // For the first Animation effect
336 sweepAngleAnimation = AnimateVisual(progressVisual, "sweepAngle", progressVisual.SweepAngle, 0, 100, AlphaFunction.BuiltinFunctions.EaseIn);
338 SetValue(CurrentValueProperty, value);
345 /// The property to get/set Track object color of the CircularSlider.
347 [EditorBrowsable(EditorBrowsableState.Never)]
348 public Color TrackColor
352 return (Color)GetValue(TrackColorProperty);
356 SetValue(TrackColorProperty, value);
361 /// The property to get/set Progress object color of the CircularSlider.
363 [EditorBrowsable(EditorBrowsableState.Never)]
364 public Color ProgressColor
368 return (Color)GetValue(ProgressColorProperty);
372 SetValue(ProgressColorProperty, value);
377 /// Gets or sets the size of the thumb of Slider.
379 [EditorBrowsable(EditorBrowsableState.Never)]
380 public Size ThumbSize
384 return (Size)GetValue(ThumbSizeProperty);
388 SetValue(ThumbSizeProperty, value);
393 /// The property to get/set Thumb object color of the CircularSlider.
395 [EditorBrowsable(EditorBrowsableState.Never)]
396 public Color ThumbColor
400 return (Color)GetValue(ThumbColorProperty);
404 SetValue(ThumbColorProperty, value);
409 /// Flag to be enabled or disabled in CircularSlider.
411 [EditorBrowsable(EditorBrowsableState.Never)]
412 public bool IsEnabled
416 return (bool)GetValue(IsEnabledProperty);
420 SetValue(IsEnabledProperty, value);
423 private bool privateIsEnabled
434 UpdateTrackVisualColor(new Color(0.0f, 0.16f, 0.30f, 1.0f)); // #002A4D
438 UpdateTrackVisualColor(new Color(0.25f, 0.25f, 0.25f, 1.0f)); // #404040
443 private CircularSliderStyle CurrentStyle => ViewStyle as CircularSliderStyle;
445 #endregion Properties
451 /// Dispose Progress and all children on it.
453 /// <param name="type">Dispose type.</param>
454 [EditorBrowsable(EditorBrowsableState.Never)]
455 protected override void Dispose(DisposeTypes type)
462 if (type == DisposeTypes.Explicit)
465 progressVisual = null;
473 /// Update progress value
475 [EditorBrowsable(EditorBrowsableState.Never)]
476 protected virtual void UpdateValue()
478 if (null == trackVisual || null == progressVisual || null == thumbVisual)
483 if (minValue >= maxValue || currentValue < minValue || currentValue > maxValue)
488 HandleProgressVisualVisibility();
490 UpdateProgressVisualSweepAngle();
494 /// Get Progress style.
496 /// <returns>The default progress style.</returns>
497 [EditorBrowsable(EditorBrowsableState.Never)]
498 protected override ViewStyle CreateViewStyle()
500 return new CircularSliderStyle();
503 private void Initialize()
505 Size = new Size(360.0f, 360.0f);
507 sweepAngleAnimation?.Stop();
508 sweepAngleAnimation = null;
510 thumbAnimation?.Stop();
511 thumbAnimation = null;
513 trackVisual = new ArcVisual
515 SuppressUpdateVisual = true,
516 Size = new Size(this.Size.Width - sliderPadding, this.Size.Height - sliderPadding),
517 SizePolicy = VisualTransformPolicyType.Absolute,
518 Thickness = this.Thickness,
519 Cap = ArcVisual.CapType.Butt,
520 MixColor = TrackColor,
524 this.AddVisual(TrackVisualName, trackVisual);
526 progressVisual = new ArcVisual
528 SuppressUpdateVisual = true,
529 Size = new Size(this.Size.Width - sliderPadding, this.Size.Height - sliderPadding),
530 SizePolicy = VisualTransformPolicyType.Absolute,
531 Thickness = this.Thickness,
532 Cap = ArcVisual.CapType.Butt,
533 MixColor = ProgressColor,
537 this.AddVisual(ProgressVisualName, progressVisual);
539 thumbVisual = new ArcVisual
541 SuppressUpdateVisual = true,
542 Size = new Size(this.Size.Width + sliderPadding, this.Size.Height + sliderPadding),
543 SizePolicy = VisualTransformPolicyType.Absolute,
544 Thickness = this.ThumbSize.Width,
545 Cap = ArcVisual.CapType.Round,
546 MixColor = this.ThumbColor,
550 this.AddVisual(ThumbVisualName, thumbVisual);
552 HandleProgressVisualVisibility();
554 UpdateProgressVisualSweepAngle();
557 private void HandleProgressVisualVisibility()
561 progressVisual.Opacity = 1.0f;
565 progressVisual.Opacity = 0.6f;
569 private void UpdateVisualThickness(float thickness)
571 if (trackVisual == null)
576 trackVisual.Thickness = thickness;
577 progressVisual.Thickness = thickness;
579 trackVisual.UpdateVisual(true);
580 progressVisual.UpdateVisual(true);
583 private void UpdateProgressVisualSweepAngle()
585 float progressRatio = (float)(currentValue - minValue) / (float)(maxValue - minValue);
586 float progressWidth = 360.0f * progressRatio; // Circle
588 progressVisual.SweepAngle = progressWidth;
589 thumbVisual.StartAngle = progressWidth;
591 if (!sweepAngleAnimation)
593 progressVisual.UpdateVisual(true);
594 thumbVisual.UpdateVisual(true);
598 private void UpdateAnimation()
600 // TODO : Currently not sure which effect is needed.
601 AlphaFunction.BuiltinFunctions builtinAlphaFunction = AlphaFunction.BuiltinFunctions.EaseOut;
603 if (sweepAngleAnimation)
605 sweepAngleAnimation.Stop();
609 thumbAnimation.Stop();
612 sweepAngleAnimation = AnimateVisual(progressVisual, "sweepAngle", progressVisual.SweepAngle, 0, 500, builtinAlphaFunction);
613 thumbAnimation = AnimateVisual(thumbVisual, "startAngle", thumbVisual.StartAngle, 0, 500, builtinAlphaFunction);
615 if (sweepAngleAnimation)
617 sweepAngleAnimation.Play();
618 thumbAnimation.Play();
621 ValueChanged?.Invoke(this, new CircularSliderValueChangedEventArgs() { CurrentValue = currentValue });
624 private void UpdateTrackVisualColor(Color trackColor)
626 if (trackVisual == null)
631 trackVisual.MixColor = trackColor;
632 trackVisual.UpdateVisual(true);
635 private void UpdateProgressVisualColor(Color progressColor)
637 if (progressVisual == null)
642 progressVisual.MixColor = progressColor;
643 if (!isEnabled) // Dim state
645 progressVisual.Opacity = 0.6f;
648 progressVisual.UpdateVisual(true);
651 private void UpdateThumbVisualSize(Size thumbSize)
653 if (thumbVisual == null)
658 thumbVisual.Thickness = thumbSize.Width;
659 thumbVisual.UpdateVisual(true);
662 private void UpdateThumbVisualColor(Color thumbColor)
664 if (thumbVisual == null)
669 thumbVisual.MixColor = thumbColor;
670 thumbVisual.UpdateVisual(true);