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 /// 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.
27 /// CircularSlider shows the current value with the length of the line.
29 [EditorBrowsable(EditorBrowsableState.Never)]
30 public class CircularSlider : Control
34 /// <summary>Bindable property of Thickness</summary>
35 [EditorBrowsable(EditorBrowsableState.Never)]
36 public static readonly BindableProperty ThicknessProperty = BindableProperty.Create(nameof(Thickness), typeof(float), typeof(CircularSlider), default(float), propertyChanged: (bindable, oldValue, newValue) =>
38 var instance = ((CircularSlider)bindable);
40 // TODO Set viewStyle.Thickness after style refactoring done.
42 instance.UpdateVisualThickness((float)newValue);
44 defaultValueCreator: (bindable) =>
46 return ((CircularSliderStyle)((CircularSlider)bindable).viewStyle)?.Thickness;
49 /// <summary>Bindable property of MaxValue</summary>
50 [EditorBrowsable(EditorBrowsableState.Never)]
51 public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(float), typeof(CircularSlider), default(float), propertyChanged: (bindable, oldValue, newValue) =>
53 var instance = (CircularSlider)bindable;
56 instance.maxValue = (float)newValue;
57 instance.UpdateValue();
60 defaultValueCreator: (bindable) =>
62 var instance = (CircularSlider)bindable;
63 return instance.maxValue;
66 /// <summary>Bindable property of MinValue</summary>
67 [EditorBrowsable(EditorBrowsableState.Never)]
68 public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(float), typeof(CircularSlider), default(float), propertyChanged: (bindable, oldValue, newValue) =>
70 var instance = (CircularSlider)bindable;
73 instance.minValue = (float)newValue;
74 instance.UpdateValue();
77 defaultValueCreator: (bindable) =>
79 var instance = (CircularSlider)bindable;
80 return instance.minValue;
83 /// <summary>Bindable property of CurrentValue</summary>
84 [EditorBrowsable(EditorBrowsableState.Never)]
85 public static readonly BindableProperty CurrentValueProperty = BindableProperty.Create(nameof(CurrentValue), typeof(float), typeof(CircularSlider), default(float), propertyChanged: (bindable, oldValue, newValue) =>
87 var instance = (CircularSlider)bindable;
90 if ((float)newValue > instance.maxValue || (float)newValue < instance.minValue)
94 instance.currentValue = (float)newValue;
95 instance.UpdateValue();
98 defaultValueCreator: (bindable) =>
100 var instance = (CircularSlider)bindable;
101 return instance.currentValue;
104 /// <summary>Bindable property of TrackColor</summary>
105 [EditorBrowsable(EditorBrowsableState.Never)]
106 public static readonly BindableProperty TrackColorProperty = BindableProperty.Create(nameof(TrackColor), typeof(Color), typeof(CircularSlider), null, propertyChanged: (bindable, oldValue, newValue) =>
108 var instance = (CircularSlider)bindable;
110 // TODO : Set viewStyle.TrackColor after style refactoring done.
112 instance.UpdateTrackVisualColor((Color)newValue);
114 defaultValueCreator: (bindable) =>
116 return ((CircularSliderStyle)((CircularSlider)bindable).viewStyle)?.TrackColor;
119 /// <summary>Bindable property of ProgressColor</summary>
120 [EditorBrowsable(EditorBrowsableState.Never)]
121 public static readonly BindableProperty ProgressColorProperty = BindableProperty.Create(nameof(ProgressColor), typeof(Color), typeof(CircularSlider), null, propertyChanged: (bindable, oldValue, newValue) =>
123 var instance = (CircularSlider)bindable;
125 // TODO : Set viewStyle.ProgressColor after style refactoring done.
127 instance.UpdateProgressVisualColor((Color)newValue);
129 defaultValueCreator: (bindable) =>
131 return ((CircularSliderStyle)((CircularSlider)bindable).viewStyle)?.ProgressColor;
134 /// <summary>Bindable property of ThumbSize</summary>
135 [EditorBrowsable(EditorBrowsableState.Never)]
136 public static readonly BindableProperty ThumbSizeProperty = BindableProperty.Create(nameof(ThumbSize), typeof(Size), typeof(CircularSlider), new Size(0,0), propertyChanged: (bindable, oldValue, newValue) =>
138 var instance = (CircularSlider)bindable;
139 if (newValue != null)
141 instance.thumbSize = (Size)newValue;
142 instance.UpdateThumbVisualSize((Size)newValue);
145 defaultValueCreator: (bindable) =>
147 var instance = (CircularSlider)bindable;
148 return instance.thumbSize;
151 /// <summary>Bindable property of ThumbColor</summary>
152 [EditorBrowsable(EditorBrowsableState.Never)]
153 public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(CircularSlider), null, propertyChanged: (bindable, oldValue, newValue) =>
155 var instance = (CircularSlider)bindable;
157 // TODO : Set viewStyle.ThumbColor after style refactoring done.
159 instance.UpdateThumbVisualColor((Color)newValue);
161 defaultValueCreator: (bindable) =>
163 return ((CircularSliderStyle)((CircularSlider)bindable).viewStyle)?.ThumbColor;
166 /// <summary>Bindable property of IsEnabled</summary>
167 [EditorBrowsable(EditorBrowsableState.Never)]
168 public static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(nameof(IsEnabled), typeof(bool), typeof(CircularSlider), true, propertyChanged: (bindable, oldValue, newValue) =>
170 var instance = (CircularSlider)bindable;
171 if (newValue != null)
173 instance.privateIsEnabled = (bool)newValue;
176 defaultValueCreator: (bindable) =>
178 var instance = (CircularSlider)bindable;
179 return instance.privateIsEnabled;
182 private const string TrackVisualName = "Track";
183 private const string ProgressVisualName = "Progress";
184 private const string ThumbVisualName = "Thumb";
185 private ArcVisual trackVisual;
186 private ArcVisual progressVisual;
187 private ArcVisual thumbVisual;
189 private float maxValue = 100;
190 private float minValue = 0;
191 private float currentValue = 0;
192 private Size thumbSize;
193 private bool isEnabled = true;
195 float sliderPadding = 6.0f;
197 private Animation sweepAngleAnimation;
198 private Animation thumbAnimation;
201 /// Get style of progress.
203 [EditorBrowsable(EditorBrowsableState.Never)]
204 public new CircularSliderStyle Style => ViewStyle as CircularSliderStyle;
207 /// Value Changed event data.
209 [EditorBrowsable(EditorBrowsableState.Never)]
210 public class ValueChangedEventArgs : EventArgs
212 private float currentValue = 0.0f;
217 [EditorBrowsable(EditorBrowsableState.Never)]
218 public float CurrentValue
220 get { return currentValue; }
221 set { currentValue = value; }
230 static CircularSlider() { }
232 /// The constructor of CircularSlider.
234 [EditorBrowsable(EditorBrowsableState.Never)]
235 public CircularSlider() : base(new CircularSliderStyle())
241 /// The constructor of the CircularSlider class with specific style.
243 /// <param name="progressStyle">The style object to initialize the CircularSlider.</param>
244 [EditorBrowsable(EditorBrowsableState.Never)]
245 public CircularSlider(CircularSliderStyle progressStyle) : base(progressStyle)
250 #endregion Constructors
255 /// The value changed event handler.
257 [EditorBrowsable(EditorBrowsableState.Never)]
258 public event EventHandler<ValueChangedEventArgs> ValueChanged;
265 /// The thickness of the track and progress.
267 [EditorBrowsable(EditorBrowsableState.Never)]
268 public float Thickness
272 return (float)GetValue(ThicknessProperty);
276 SetValue(ThicknessProperty, value);
281 /// The property to get/set the maximum value of the CircularSlider.
282 /// The default value is 100.
284 [EditorBrowsable(EditorBrowsableState.Never)]
285 public float MaxValue
289 return (float)GetValue(MaxValueProperty);
293 SetValue(MaxValueProperty, value);
298 /// The property to get/set the minimum value of the CircularSlider.
299 /// The default value is 0.
301 [EditorBrowsable(EditorBrowsableState.Never)]
302 public float MinValue
306 return (float)GetValue(MinValueProperty);
310 SetValue(MinValueProperty, value);
315 /// The property to get/set the current value of the CircularSlider.
316 /// The default value is 0.
318 [EditorBrowsable(EditorBrowsableState.Never)]
319 public float CurrentValue
323 return (float)GetValue(CurrentValueProperty);
327 if (sweepAngleAnimation)
329 sweepAngleAnimation.Stop();
331 // For the first Animation effect
332 sweepAngleAnimation = AnimateVisual(progressVisual, "sweepAngle", progressVisual.SweepAngle, 0, 100, AlphaFunction.BuiltinFunctions.EaseIn);
334 SetValue(CurrentValueProperty, value);
341 /// The property to get/set Track object color of the CircularSlider.
343 [EditorBrowsable(EditorBrowsableState.Never)]
344 public Color TrackColor
348 return (Color)GetValue(TrackColorProperty);
352 SetValue(TrackColorProperty, value);
357 /// The property to get/set Progress object color of the CircularSlider.
359 [EditorBrowsable(EditorBrowsableState.Never)]
360 public Color ProgressColor
364 return (Color)GetValue(ProgressColorProperty);
368 SetValue(ProgressColorProperty, value);
373 /// Gets or sets the size of the thumb of Slider.
375 [EditorBrowsable(EditorBrowsableState.Never)]
376 public Size ThumbSize
380 return (Size)GetValue(ThumbSizeProperty);
384 SetValue(ThumbSizeProperty, value);
389 /// The property to get/set Thumb object color of the CircularSlider.
391 [EditorBrowsable(EditorBrowsableState.Never)]
392 public Color ThumbColor
396 return (Color)GetValue(ThumbColorProperty);
400 SetValue(ThumbColorProperty, value);
405 /// Flag to be enabled or disabled in CircularSlider.
407 [EditorBrowsable(EditorBrowsableState.Never)]
408 public bool IsEnabled
412 return (bool)GetValue(IsEnabledProperty);
416 SetValue(IsEnabledProperty, value);
419 private bool privateIsEnabled
430 UpdateTrackVisualColor(new Color(0.0f, 0.16f, 0.30f, 1.0f)); // #002A4D
434 UpdateTrackVisualColor(new Color(0.25f, 0.25f, 0.25f, 1.0f)); // #404040
439 #endregion Properties
445 /// Dispose Progress and all children on it.
447 /// <param name="type">Dispose type.</param>
448 [EditorBrowsable(EditorBrowsableState.Never)]
449 protected override void Dispose(DisposeTypes type)
456 if (type == DisposeTypes.Explicit)
459 progressVisual = null;
467 /// Update progress value
469 [EditorBrowsable(EditorBrowsableState.Never)]
470 protected virtual void UpdateValue()
472 if (null == trackVisual || null == progressVisual || null == thumbVisual)
477 if (minValue >= maxValue || currentValue < minValue || currentValue > maxValue)
482 HandleProgressVisualVisibility();
484 UpdateProgressVisualSweepAngle();
488 /// Get Progress style.
490 /// <returns>The default progress style.</returns>
491 [EditorBrowsable(EditorBrowsableState.Never)]
492 protected override ViewStyle CreateViewStyle()
494 return new CircularSliderStyle();
497 private void Initialize()
499 Size = new Size(360.0f, 360.0f);
501 sweepAngleAnimation?.Stop();
502 sweepAngleAnimation = null;
504 thumbAnimation?.Stop();
505 thumbAnimation = null;
507 trackVisual = new ArcVisual
509 SuppressUpdateVisual = true,
510 Size = new Size(this.Size.Width - sliderPadding, this.Size.Height - sliderPadding),
511 SizePolicy = VisualTransformPolicyType.Absolute,
512 Thickness = this.Thickness,
513 Cap = ArcVisual.CapType.Butt,
514 MixColor = TrackColor,
518 this.AddVisual(TrackVisualName, trackVisual);
520 progressVisual = new ArcVisual
522 SuppressUpdateVisual = true,
523 Size = new Size(this.Size.Width - sliderPadding, this.Size.Height - sliderPadding),
524 SizePolicy = VisualTransformPolicyType.Absolute,
525 Thickness = this.Thickness,
526 Cap = ArcVisual.CapType.Butt,
527 MixColor = ProgressColor,
531 this.AddVisual(ProgressVisualName, progressVisual);
533 thumbVisual = new ArcVisual
535 SuppressUpdateVisual = true,
536 Size = new Size(this.Size.Width + sliderPadding, this.Size.Height + sliderPadding),
537 SizePolicy = VisualTransformPolicyType.Absolute,
538 Thickness = this.ThumbSize.Width,
539 Cap = ArcVisual.CapType.Round,
540 MixColor = this.ThumbColor,
544 this.AddVisual(ThumbVisualName, thumbVisual);
546 HandleProgressVisualVisibility();
548 UpdateProgressVisualSweepAngle();
551 private void HandleProgressVisualVisibility()
555 progressVisual.Opacity = 1.0f;
559 progressVisual.Opacity = 0.6f;
563 private void UpdateVisualThickness(float thickness)
565 if (trackVisual == null)
570 trackVisual.Thickness = thickness;
571 progressVisual.Thickness = thickness;
573 trackVisual.UpdateVisual(true);
574 progressVisual.UpdateVisual(true);
577 private void UpdateProgressVisualSweepAngle()
579 float progressRatio = (float)(currentValue - minValue) / (float)(maxValue - minValue);
580 float progressWidth = 360.0f * progressRatio; // Circle
582 progressVisual.SweepAngle = progressWidth;
583 thumbVisual.StartAngle = progressWidth;
585 if (!sweepAngleAnimation)
587 progressVisual.UpdateVisual(true);
588 thumbVisual.UpdateVisual(true);
592 private void UpdateAnimation()
594 // TODO : Currently not sure which effect is needed.
595 AlphaFunction.BuiltinFunctions builtinAlphaFunction = AlphaFunction.BuiltinFunctions.EaseOut;
597 if (sweepAngleAnimation)
599 sweepAngleAnimation.Stop();
603 thumbAnimation.Stop();
606 sweepAngleAnimation = AnimateVisual(progressVisual, "sweepAngle", progressVisual.SweepAngle, 0, 500, builtinAlphaFunction);
607 thumbAnimation = AnimateVisual(thumbVisual, "startAngle", thumbVisual.StartAngle, 0, 500, builtinAlphaFunction);
609 if (sweepAngleAnimation)
611 sweepAngleAnimation.Play();
612 thumbAnimation.Play();
615 ValueChanged?.Invoke(this, new ValueChangedEventArgs() { CurrentValue = currentValue });
618 private void UpdateTrackVisualColor(Color trackColor)
620 if (trackVisual == null)
625 trackVisual.MixColor = trackColor;
626 trackVisual.UpdateVisual(true);
629 private void UpdateProgressVisualColor(Color progressColor)
631 if (progressVisual == null)
636 progressVisual.MixColor = progressColor;
637 if (!isEnabled) // Dim state
639 progressVisual.Opacity = 0.6f;
642 progressVisual.UpdateVisual(true);
645 private void UpdateThumbVisualSize(Size thumbSize)
647 if (thumbVisual == null)
652 thumbVisual.Thickness = thumbSize.Width;
653 thumbVisual.UpdateVisual(true);
656 private void UpdateThumbVisualColor(Color thumbColor)
658 if (thumbVisual == null)
663 thumbVisual.MixColor = thumbColor;
664 thumbVisual.UpdateVisual(true);