From: Seoyeon2Kim <34738918+Seoyeon2Kim@users.noreply.github.com> Date: Wed, 27 May 2020 08:28:25 +0000 (+0900) Subject: [NUI] Add CircularProgress to Wearable components (#1609) X-Git-Tag: accepted/tizen/unified/20210219.040944~729 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f58db4ed237cd8c0919e86ec1c00536daf77e8dd;hp=ca6836864090154c87f0262f629253970ecab5f5;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git [NUI] Add CircularProgress to Wearable components (#1609) * [NUI] Add CircularProgress to Wearable components Signed-off-by: Seoyeon Kim * [NUI] Add Animation to CircularProgress angle Signed-off-by: Seoyeon Kim * Fix typo --- diff --git a/src/Tizen.NUI.Wearable/src/public/CircularProgress.cs b/src/Tizen.NUI.Wearable/src/public/CircularProgress.cs new file mode 100755 index 0000000..faaf86b --- /dev/null +++ b/src/Tizen.NUI.Wearable/src/public/CircularProgress.cs @@ -0,0 +1,532 @@ +/* + * Copyright(c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +using System; +using Tizen.NUI.BaseComponents; +using Tizen.NUI.Binding; +using Tizen.NUI.Components; +using System.ComponentModel; + +namespace Tizen.NUI.Wearable +{ + /// + /// The CircularProgress class of Wearable is used to show the ongoing status with a circular bar. + /// CircularProgress can be counted in its percentage. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class CircularProgress : Control + { + #region Fields + + /// Bindable property of Thickness + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty ThicknessProperty = BindableProperty.Create(nameof(Thickness), typeof(float), typeof(CircularProgress), default(float), propertyChanged: (bindable, oldValue, newValue) => + { + var instance = ((CircularProgress)bindable); + + // TODO Set viewStyle.Thickness after style refactoring done. + + instance.UpdateVisualThickness((float)newValue); + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)((CircularProgress)bindable).viewStyle)?.Thickness; + }); + + /// Bindable property of MaxValue + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(float), typeof(CircularProgress), default(float), propertyChanged: (bindable, oldValue, newValue) => + { + var instance = (CircularProgress)bindable; + if (newValue != null) + { + instance.maxValue = (float)newValue; + instance.UpdateValue(); + } + }, + defaultValueCreator: (bindable) => + { + var instance = (CircularProgress)bindable; + return instance.maxValue; + }); + + /// Bindable property of MinValue + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(float), typeof(CircularProgress), default(float), propertyChanged: (bindable, oldValue, newValue) => + { + var instance = (CircularProgress)bindable; + if (newValue != null) + { + instance.minValue = (float)newValue; + instance.UpdateValue(); + } + }, + defaultValueCreator: (bindable) => + { + var instance = (CircularProgress)bindable; + return instance.minValue; + }); + + /// Bindable property of CurrentValue + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty CurrentValueProperty = BindableProperty.Create("currentValue", typeof(float), typeof(CircularProgress), default(float), propertyChanged: (bindable, oldValue, newValue) => + { + var instance = (CircularProgress)bindable; + if (newValue != null) + { + if ((float)newValue > instance.maxValue || (float)newValue < instance.minValue) + { + return; + } + instance.currentValue = (float)newValue; + instance.UpdateValue(); + } + }, + defaultValueCreator: (bindable) => + { + var instance = (CircularProgress)bindable; + return instance.currentValue; + }); + + /// Bindable property of TrackColor + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty TrackColorProperty = BindableProperty.Create("trackColor", typeof(Color), typeof(CircularProgress), null, propertyChanged: (bindable, oldValue, newValue) => + { + var instance = (CircularProgress)bindable; + + // TODO : Set viewStyle.TrackColor after style refactoring done. + + instance.UpdateTrackVisualColor((Color)newValue); + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)((CircularProgress)bindable).viewStyle)?.TrackColor; + }); + + /// Bindable property of ProgressColor + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty ProgressColorProperty = BindableProperty.Create("progressColor", typeof(Color), typeof(CircularProgress), null, propertyChanged: (bindable, oldValue, newValue) => + { + var instance = (CircularProgress)bindable; + + // TODO : Set viewStyle.ProgressColor after style refactoring done. + + instance.UpdateProgressVisualColor((Color)newValue); + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)((CircularProgress)bindable).viewStyle)?.ProgressColor; + }); + + /// Bindable property of IsEnabled + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(nameof(IsEnabled), typeof(bool), typeof(CircularProgress), true, propertyChanged: (bindable, oldValue, newValue) => + { + var instance = (CircularProgress)bindable; + if (newValue != null) + { + instance.privateIsEnabled = (bool)newValue; + } + }, + defaultValueCreator: (bindable) => + { + var instance = (CircularProgress)bindable; + return instance.privateIsEnabled; + }); + + private static readonly string TrackVisualName = "Track"; + private static readonly string ProgressVisualName = "Progress"; + private ArcVisual trackVisual; + private ArcVisual progressVisual; + + private float maxValue = 100; + private float minValue = 0; + private float currentValue = 0; + private bool isEnabled = true; + + private Animation sweepAngleAnimation; + + /// + /// Get style of progress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public new CircularProgressStyle Style => ViewStyle as CircularProgressStyle; + + #endregion Fields + + + #region Constructors + + static CircularProgress() { } + /// + /// The constructor of CircularProgress. + /// Basically, CircularProgress is for full screen. (360 x 360) + /// But, it also can be displayed on the button or the list for small size. + /// User can set its size. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public CircularProgress() : base(new CircularProgressStyle()) + { + Initialize(); + } + + /// + /// The constructor of the CircularProgress class with specific style. + /// + /// style name + [EditorBrowsable(EditorBrowsableState.Never)] + public CircularProgress(string style) : base(style) + { + Initialize(); + } + + /// + /// The constructor of the CircularProgress class with specific style. + /// + /// The style object to initialize the CircularProgress. + [EditorBrowsable(EditorBrowsableState.Never)] + public CircularProgress(CircularProgressStyle progressStyle) : base(progressStyle) + { + Initialize(); + } + + #endregion Constructors + + + #region Properties + + /// + /// The thickness of the track and progress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float Thickness + { + get + { + return (float)GetValue(ThicknessProperty); + } + set + { + SetValue(ThicknessProperty, value); + } + } + + /// + /// The property to get/set the maximum value of the CircularProgress. + /// The default value is 100. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float MaxValue + { + get + { + return (float)GetValue(MaxValueProperty); + } + set + { + SetValue(MaxValueProperty, value); + } + } + + /// + /// The property to get/set the minimum value of the CircularProgress. + /// The default value is 0. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float MinValue + { + get + { + return (float)GetValue(MinValueProperty); + } + set + { + SetValue(MinValueProperty, value); + } + } + + /// + /// The property to get/set the current value of the CircularProgress. + /// The default value is 0. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float CurrentValue + { + get + { + return (float)GetValue(CurrentValueProperty); + } + set + { + sweepAngleAnimation = AnimateVisual(progressVisual, "sweepAngle", progressVisual.SweepAngle, 0, 100, AlphaFunction.BuiltinFunctions.EaseIn); + + SetValue(CurrentValueProperty, value); + + UpdateAnimation(); + } + } + + /// + /// The property to get/set Track object color of the CircularProgress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Color TrackColor + { + get + { + return (Color)GetValue(TrackColorProperty); + } + set + { + SetValue(TrackColorProperty, value); + } + } + + /// + /// The property to get/set Progress object color of the CircularProgress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Color ProgressColor + { + get + { + return (Color)GetValue(ProgressColorProperty); + } + set + { + SetValue(ProgressColorProperty, value); + } + } + + /// + /// Flag to be enabled or disabled in CircularProgress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool IsEnabled + { + get + { + return (bool)GetValue(IsEnabledProperty); + } + set + { + SetValue(IsEnabledProperty, value); + } + } + private bool privateIsEnabled + { + get + { + return isEnabled; + } + set + { + isEnabled = value; + if(isEnabled) + { + UpdateTrackVisualColor(new Color(0.0f, 0.16f, 0.30f, 1.0f)); // #002A4D + } + else + { + UpdateTrackVisualColor(new Color(0.25f, 0.25f, 0.25f, 1.0f)); // #404040 + } + } + } + + #endregion Properties + + + + #region Methods + + /// + /// Dispose Progress and all children on it. + /// + /// Dispose type. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void Dispose(DisposeTypes type) + { + if (disposed) + { + return; + } + + if (type == DisposeTypes.Explicit) + { + trackVisual = null; + progressVisual = null; + } + + base.Dispose(type); + } + + /// + /// Update progress value + /// + [EditorBrowsable(EditorBrowsableState.Never)] + protected virtual void UpdateValue() + { + if (null == trackVisual || null == progressVisual) + { + return; + } + + if (minValue >= maxValue || currentValue < minValue || currentValue > maxValue) + { + return; + } + + HandleProgressVisualVisibility(); + + UpdateProgressVisualSweepAngle(); + } + + /// + /// Get Progress style. + /// + /// The default progress style. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override ViewStyle GetViewStyle() + { + return new CircularProgressStyle(); + } + + + private void Initialize() + { + Size = new Size(360.0f, 360.0f); + + sweepAngleAnimation?.Stop(); + sweepAngleAnimation = null; + + trackVisual = new ArcVisual + { + SuppressUpdateVisual = true, + Thickness = this.Thickness, + Cap = ArcVisual.CapType.Butt, + MixColor = TrackColor, + StartAngle = 0.0f, + SweepAngle = 360.0f + }; + this.AddVisual(TrackVisualName, trackVisual); + + progressVisual = new ArcVisual + { + SuppressUpdateVisual = true, + Thickness = this.Thickness, + Cap = ArcVisual.CapType.Butt, + MixColor = ProgressColor, + StartAngle = 0.0f, + SweepAngle = 0.0f + }; + this.AddVisual(ProgressVisualName, progressVisual); + + HandleProgressVisualVisibility(); + + UpdateProgressVisualSweepAngle(); + } + + private void HandleProgressVisualVisibility() + { + if (minValue == currentValue) + { + progressVisual.Opacity = 0.0f; + } + else if (isEnabled) + { + progressVisual.Opacity = 1.0f; + } + else if (!isEnabled) + { + progressVisual.Opacity = 0.6f; + } + } + + private void UpdateVisualThickness(float thickness) + { + if (trackVisual == null) + { + return; + } + + trackVisual.Thickness = thickness; + progressVisual.Thickness = thickness; + + trackVisual.UpdateVisual(true); + progressVisual.UpdateVisual(true); + } + + private void UpdateProgressVisualSweepAngle() + { + float progressRatio = (float)(currentValue - minValue) / (float)(maxValue - minValue); + float progressWidth = 360.0f * progressRatio; // Circle + progressVisual.SweepAngle = progressWidth; + + if (!sweepAngleAnimation) + { + progressVisual.UpdateVisual(true); + } + } + + private void UpdateAnimation() + { + // TODO : Currently not sure which effect is needed. + AlphaFunction.BuiltinFunctions builtinAlphaFunction = AlphaFunction.BuiltinFunctions.EaseIn; + + if (sweepAngleAnimation) + { + sweepAngleAnimation?.Stop(); + } + + sweepAngleAnimation = AnimateVisual(progressVisual, "sweepAngle", progressVisual.SweepAngle, 0, 100, builtinAlphaFunction); + + if (sweepAngleAnimation) + { + sweepAngleAnimation.Play(); + } + + } + + private void UpdateTrackVisualColor(Color trackColor) + { + if (trackVisual == null) + { + return; + } + + trackVisual.MixColor = trackColor; + trackVisual.UpdateVisual(true); + } + + private void UpdateProgressVisualColor(Color progressColor) + { + if (progressVisual == null) + { + return; + } + + progressVisual.MixColor = progressColor; + if( !isEnabled ) // Dim state + { + progressVisual.Opacity = 0.6f; + } + + progressVisual.UpdateVisual(true); + } + + #endregion Methods + } +} diff --git a/src/Tizen.NUI.Wearable/src/public/WearableStyle/CircularProgressStyle.cs b/src/Tizen.NUI.Wearable/src/public/WearableStyle/CircularProgressStyle.cs new file mode 100755 index 0000000..df9b0be --- /dev/null +++ b/src/Tizen.NUI.Wearable/src/public/WearableStyle/CircularProgressStyle.cs @@ -0,0 +1,283 @@ +/* + * Copyright(c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +using System.ComponentModel; +using Tizen.NUI.BaseComponents; +using Tizen.NUI.Binding; +using Tizen.NUI.Components; + +namespace Tizen.NUI.Wearable +{ + /// + /// CircularProgressStyle is a class which saves CircularProgress's ux data. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class CircularProgressStyle : ControlStyle + { + /// Bindable property of Thickness + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty ThicknessProperty = BindableProperty.Create(nameof(Thickness), typeof(float?), typeof(CircularProgressStyle), null, propertyChanged: (bindable, oldValue, newValue) => + { + ((CircularProgressStyle)bindable).thickness = (float?)newValue; + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)bindable).thickness; + }); + + /// Bindable property of MaxValue + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(float), typeof(CircularProgressStyle), default(float), propertyChanged: (bindable, oldValue, newValue) => + { + ((CircularProgressStyle)bindable).maxValue = (float)newValue; + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)bindable).maxValue; + }); + + /// Bindable property of MinValue + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(float), typeof(CircularProgressStyle), default(float), propertyChanged: (bindable, oldValue, newValue) => + { + ((CircularProgressStyle)bindable).minValue = (float)newValue; + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)bindable).minValue; + }); + + /// Bindable property of CurrentValue + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty CurrentValueProperty = BindableProperty.Create("currentValue", typeof(float), typeof(CircularProgressStyle), default(float), propertyChanged: (bindable, oldValue, newValue) => + { + ((CircularProgressStyle)bindable).currentValue = (float)newValue; + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)bindable).currentValue; + }); + + /// Bindable property of TrackColor + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty TrackColorProperty = BindableProperty.Create("trackColor", typeof(Color), typeof(CircularProgressStyle), null, propertyChanged: (bindable, oldValue, newValue) => + { + ((CircularProgressStyle)bindable).trackColor = (Color)newValue; + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)bindable).trackColor; + }); + + /// Bindable property of ProgressColor + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty ProgressColorProperty = BindableProperty.Create("progressColor", typeof(Color), typeof(CircularProgressStyle), null, propertyChanged: (bindable, oldValue, newValue) => + { + ((CircularProgressStyle)bindable).progressColor = (Color)newValue; + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)bindable).progressColor; + }); + + /// Bindable property of IsEnabled + [EditorBrowsable(EditorBrowsableState.Never)] + public static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(nameof(IsEnabled), typeof(bool?), typeof(CircularProgressStyle), null, propertyChanged: (bindable, oldValue, newValue) => + { + ((CircularProgressStyle)bindable).isEnabled = (bool?)newValue; + }, + defaultValueCreator: (bindable) => + { + return ((CircularProgressStyle)bindable).isEnabled; + }); + + private float? thickness; + private float maxValue; + private float minValue; + private float currentValue; + private Color trackColor; + private Color progressColor; + private bool? isEnabled; + + static CircularProgressStyle() { } + + /// + /// Creates a new instance of a CircularProgressStyle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public CircularProgressStyle() : base() + { + Initialize(); + } + + /// + /// Creates a new instance of a CircularProgressStyle with style. + /// + /// Create CircularProgressStyle by style customized by user. + [EditorBrowsable(EditorBrowsableState.Never)] + public CircularProgressStyle(CircularProgressStyle style) : base(style) + { + if (null == style) return; + this.CopyFrom(style); + } + + /// + /// The thickness of the track and progress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float? Thickness + { + get + { + return (float?)GetValue(ThicknessProperty); + } + set + { + SetValue(ThicknessProperty, value); + } + } + + /// + /// The property to get/set the maximum value of the CircularProgress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float MaxValue + { + get + { + return (float)GetValue(MaxValueProperty); + } + set + { + SetValue(MaxValueProperty, value); + } + } + + /// + /// The property to get/set the minim value of the CircularProgress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float MinValue + { + get + { + return (float)GetValue(MinValueProperty); + } + set + { + SetValue(MinValueProperty, value); + } + } + + /// + /// The property to get/set the current value of the CircularProgress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float CurrentValue + { + get + { + return (float)GetValue(CurrentValueProperty); + } + set + { + SetValue(CurrentValueProperty, value); + } + } + + /// + /// The property to get/set Track object color of the CircularProgress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Color TrackColor + { + get + { + return (Color)GetValue(TrackColorProperty); + } + set + { + SetValue(TrackColorProperty, value); + } + } + + /// + /// The property to get/set Progress object color of the CircularProgress. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Color ProgressColor + { + get + { + return (Color)GetValue(ProgressColorProperty); + } + set + { + SetValue(ProgressColorProperty, value); + } + } + + /// + /// Flag to be enabled or disabled in CircularProgress. + /// + /// 8 + public bool? IsEnabled + { + get + { + return (bool?)GetValue(IsEnabledProperty); + } + set + { + SetValue(IsEnabledProperty, value); + } + } + + /// + /// Style's clone function. + /// + /// The style that need to copy. + [EditorBrowsable(EditorBrowsableState.Never)] + public override void CopyFrom(BindableObject bindableObject) + { + base.CopyFrom(bindableObject); + + CircularProgressStyle progressStyle = bindableObject as CircularProgressStyle; + + if (null != progressStyle) + { + isEnabled = progressStyle.isEnabled; + thickness = progressStyle.Thickness; + maxValue = progressStyle.maxValue; + minValue = progressStyle.minValue; + currentValue = progressStyle.currentValue; + trackColor = progressStyle.trackColor; + progressColor = progressStyle.progressColor; + } + } + + private void Initialize() + { + isEnabled = true; + thickness = 6.0f; + maxValue = 100.0f; + minValue = 0.0f; + currentValue = 0.0f; + trackColor = new Color(0.0f, 0.16f, 0.30f, 1.0f); + progressColor = new Color(0.0f, 0.55f, 1.0f, 1.0f); + } + } +}