2 * Copyright(c) 2022 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.
19 using System.ComponentModel;
20 using System.Diagnostics;
21 using Tizen.NUI.Accessibility;
22 using Tizen.NUI.BaseComponents;
23 using Tizen.NUI.Binding;
25 namespace Tizen.NUI.Components
28 /// The Progress class is used to show the ongoing status with a long narrow bar.
30 /// <since_tizen> 6 </since_tizen>
31 public partial class Progress : Control, IAtspiValue
33 private const int IndeterminateAnimationDuration = 2000;
38 [EditorBrowsable(EditorBrowsableState.Never)]
39 public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(float), typeof(Progress), default(float), propertyChanged: (bindable, oldValue, newValue) =>
41 var instance = (Progress)bindable;
44 instance.maxValue = (float)newValue;
45 instance.UpdateValue();
48 defaultValueCreator: (bindable) =>
50 var instance = (Progress)bindable;
51 return instance.maxValue;
57 [EditorBrowsable(EditorBrowsableState.Never)]
58 public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(float), typeof(Progress), default(float), propertyChanged: (bindable, oldValue, newValue) =>
60 var instance = (Progress)bindable;
63 instance.minValue = (float)newValue;
64 instance.UpdateValue();
67 defaultValueCreator: (bindable) =>
69 var instance = (Progress)bindable;
70 return instance.minValue;
74 /// CurrentValueProperty
76 [EditorBrowsable(EditorBrowsableState.Never)]
77 public static readonly BindableProperty CurrentValueProperty = BindableProperty.Create(nameof(CurrentValue), typeof(float), typeof(Progress), default(float), propertyChanged: (bindable, oldValue, newValue) =>
79 var instance = (Progress)bindable;
82 if ((float)newValue > instance.maxValue || (float)newValue < instance.minValue)
86 instance.currentValue = (float)newValue;
87 instance.UpdateValue();
90 defaultValueCreator: (bindable) =>
92 var instance = (Progress)bindable;
93 return instance.currentValue;
97 /// BufferValueProperty
99 [EditorBrowsable(EditorBrowsableState.Never)]
100 public static readonly BindableProperty BufferValueProperty = BindableProperty.Create(nameof(BufferValue), typeof(float), typeof(Progress), default(float), propertyChanged: (bindable, oldValue, newValue) =>
102 var instance = (Progress)bindable;
103 if (newValue != null)
105 if ((float)newValue > instance.maxValue || (float)newValue < instance.minValue)
109 instance.bufferValue = (float)newValue;
110 instance.UpdateValue();
113 defaultValueCreator: (bindable) =>
115 var instance = (Progress)bindable;
116 return instance.bufferValue;
120 /// ProgressStateProperty
122 [EditorBrowsable(EditorBrowsableState.Never)]
123 public static readonly BindableProperty ProgressStateProperty = BindableProperty.Create(nameof(ProgressState), typeof(ProgressStatusType), typeof(Progress), ProgressStatusType.Indeterminate, propertyChanged: (bindable, oldValue, newValue) =>
125 var instance = (Progress)bindable;
126 if (newValue != null)
128 instance.state = (ProgressStatusType)newValue;
129 instance.UpdateStates();
132 defaultValueCreator: (bindable) =>
134 var instance = (Progress)bindable;
135 return instance.state;
138 /// This needs to be considered more if public-open is necessary.
139 private ProgressStatusType state = ProgressStatusType.Determinate;
141 private Vector2 size = null;
142 private const float round = 0.5f;
143 private ImageView trackImage = null;
144 private ImageView progressImage = null;
145 private ImageView bufferImage = null;
146 private ImageView indeterminateImage = null;
147 private float maxValue = 100;
148 private float minValue = 0;
149 private float currentValue = 0;
150 private float bufferValue = 0;
151 private Animation indeterminateAnimation = null;
153 static Progress() { }
155 /// The constructor of Progress
157 /// <since_tizen> 6 </since_tizen>
158 public Progress() : base()
164 /// The constructor of the Progress class with specific style.
166 /// <param name="style">style name</param>
167 /// <since_tizen> 8 </since_tizen>
168 public Progress(string style) : base(style)
174 /// The constructor of the Progress class with specific style.
176 /// <param name="progressStyle">The style object to initialize the Progress.</param>
177 /// <since_tizen> 8 </since_tizen>
178 public Progress(ProgressStyle progressStyle) : base(progressStyle)
184 /// The status type of the Progress.
186 /// <since_tizen> 6 </since_tizen>
187 public enum ProgressStatusType
192 /// <since_tizen> 6 </since_tizen>
196 /// Show ProgressImage and BufferImage
198 /// <since_tizen> 6 </since_tizen>
204 /// <since_tizen> 6 </since_tizen>
209 /// Return currently applied style.
212 /// Modifying contents in style may cause unexpected behaviour.
214 /// <since_tizen> 8 </since_tizen>
215 public ProgressStyle Style => (ProgressStyle)(ViewStyle as ProgressStyle)?.Clone();
218 /// The property to get/set Track image object URL of the Progress.
220 /// <since_tizen> 6 </since_tizen>
221 public string TrackImageURL
225 return GetValue(TrackImageURLProperty) as string;
229 SetValue(TrackImageURLProperty, value);
230 NotifyPropertyChanged();
233 private string InternalTrackImageURL
235 get => trackImage.ResourceUrl;
236 set => trackImage.ResourceUrl = value;
240 /// The property to get/set Progress object image URL of the Progress.
242 /// <since_tizen> 6 </since_tizen>
243 public string ProgressImageURL
247 return GetValue(ProgressImageURLProperty) as string;
251 SetValue(ProgressImageURLProperty, value);
252 NotifyPropertyChanged();
255 private string InternalProgressImageURL
257 get => progressImage.ResourceUrl;
258 set => progressImage.ResourceUrl = value;
262 /// The property to get/set Buffer object image resource URL of the Progress.
264 /// <since_tizen> 6 </since_tizen>
265 public string BufferImageURL
269 return GetValue(BufferImageURLProperty) as string;
273 SetValue(BufferImageURLProperty, value);
274 NotifyPropertyChanged();
277 private string InternalBufferImageURL
279 get => bufferImage.ResourceUrl;
280 set => bufferImage.ResourceUrl = value;
284 /// The property to get/set the indeterminate image.
286 /// <exception cref="NullReferenceException">Thrown when setting null value.</exception>
287 /// <since_tizen> 9 </since_tizen>
288 public string IndeterminateImageUrl
292 return GetValue(IndeterminateImageUrlProperty) as string;
296 SetValue(IndeterminateImageUrlProperty, value);
297 NotifyPropertyChanged();
300 private string InternalIndeterminateImageUrl
304 if (indeterminateImage == null)
310 return indeterminateImage?.ResourceUrl;
315 if (value == null || indeterminateImage == null)
317 throw new NullReferenceException("Progress.IndeterminateImage is null");
321 indeterminateImage.ResourceUrl = value;
327 /// The property to get/set Track object color of the Progress.
329 /// <since_tizen> 6 </since_tizen>
330 public Color TrackColor
334 return GetValue(TrackColorProperty) as Color;
338 SetValue(TrackColorProperty, value);
339 NotifyPropertyChanged();
342 private Color InternalTrackColor
344 get => trackImage.BackgroundColor;
345 set => trackImage.BackgroundColor = value;
349 /// The property to get/set Progress object color of the Progress.
351 /// <since_tizen> 6 </since_tizen>
352 public Color ProgressColor
356 return GetValue(ProgressColorProperty) as Color;
360 SetValue(ProgressColorProperty, value);
361 NotifyPropertyChanged();
364 private Color InternalProgressColor
366 get => progressImage.BackgroundColor;
367 set => progressImage.BackgroundColor = value;
371 /// The property to get/set Buffer object color of the Progress.
373 /// <since_tizen> 6 </since_tizen>
374 public Color BufferColor
378 return GetValue(BufferColorProperty) as Color;
382 SetValue(BufferColorProperty, value);
383 NotifyPropertyChanged();
386 private Color InternalBufferColor
388 get => bufferImage.BackgroundColor;
389 set => bufferImage.BackgroundColor = value;
393 /// The property to get/set the maximum value of the Progress.
395 /// <since_tizen> 6 </since_tizen>
396 public float MaxValue
400 return (float)GetValue(MaxValueProperty);
404 SetValue(MaxValueProperty, value);
409 /// The property to get/set the minim value of the Progress.
411 /// <since_tizen> 6 </since_tizen>
412 public float MinValue
416 return (float)GetValue(MinValueProperty);
420 SetValue(MinValueProperty, value);
425 /// The property to get/set the current value of the Progress.
427 /// <since_tizen> 6 </since_tizen>
428 public float CurrentValue
432 return (float)GetValue(CurrentValueProperty);
436 SetValue(CurrentValueProperty, value);
437 if (Accessibility.Accessibility.IsEnabled && IsHighlighted)
439 EmitAccessibilityEvent(AccessibilityPropertyChangeEvent.Value);
445 /// The property to get/set the buffer value of the Progress.
447 /// <since_tizen> 6 </since_tizen>
448 public float BufferValue
452 return (float)GetValue(BufferValueProperty);
456 SetValue(BufferValueProperty, value);
461 /// Gets or sets state of progress.
463 /// <since_tizen> 6 </since_tizen>
464 public ProgressStatusType ProgressState
468 return (ProgressStatusType)GetValue(ProgressStateProperty);
472 SetValue(ProgressStateProperty, value);
477 [EditorBrowsable(EditorBrowsableState.Never)]
478 public override void OnInitialize()
481 AccessibilityRole = Role.ProgressBar;
482 // create necessary components
485 InitializeProgress();
486 InitializeIndeterminate();
488 indeterminateAnimation?.Stop();
489 indeterminateAnimation = null;
493 [EditorBrowsable(EditorBrowsableState.Never)]
494 public override void ApplyStyle(ViewStyle style)
496 base.ApplyStyle(style);
498 if (style is ProgressStyle progressStyle)
500 Debug.Assert(trackImage != null);
501 Debug.Assert(progressImage != null);
502 Debug.Assert(bufferImage != null);
503 Debug.Assert(indeterminateImage != null);
505 trackImage.ApplyStyle(progressStyle.Track);
506 progressImage.ApplyStyle(progressStyle.Progress);
507 bufferImage.ApplyStyle(progressStyle.Buffer);
509 if (null != indeterminateImage && null != progressStyle.IndeterminateImageUrl)
511 indeterminateImage.ResourceUrl = progressStyle.IndeterminateImageUrl;
517 /// Gets minimum value for Accessibility.
519 [EditorBrowsable(EditorBrowsableState.Never)]
520 double IAtspiValue.AccessibilityGetMinimum()
522 if (this.ProgressState == Progress.ProgressStatusType.Determinate)
524 return (double)MinValue;
533 /// Gets the current value for Accessibility.
535 [EditorBrowsable(EditorBrowsableState.Never)]
536 double IAtspiValue.AccessibilityGetCurrent()
538 if (this.ProgressState == Progress.ProgressStatusType.Determinate)
540 return (double)CurrentValue;
548 [EditorBrowsable(EditorBrowsableState.Never)]
549 bool IAtspiValue.AccessibilitySetCurrent(double value)
555 /// Gets maximum value for Accessibility.
557 [EditorBrowsable(EditorBrowsableState.Never)]
558 double IAtspiValue.AccessibilityGetMaximum()
560 if (this.ProgressState == Progress.ProgressStatusType.Determinate)
562 return (double)MaxValue;
570 [EditorBrowsable(EditorBrowsableState.Never)]
571 double IAtspiValue.AccessibilityGetMinimumIncrement()
577 /// Dispose Progress and all children on it.
579 /// <param name="type">Dispose type.</param>
580 /// <since_tizen> 6 </since_tizen>
581 protected override void Dispose(DisposeTypes type)
588 if (type == DisposeTypes.Explicit)
591 //Release your own managed resources here.
592 //You should release all of your own disposable objects here.
593 Utility.Dispose(trackImage);
594 Utility.Dispose(progressImage);
595 Utility.Dispose(bufferImage);
596 Utility.Dispose(indeterminateImage);
599 //You must call base.Dispose(type) just before exit.
604 /// Change Image status. It can be override.
606 /// This needs to be considered more if public-open is necessary.
607 [EditorBrowsable(EditorBrowsableState.Never)]
608 private void UpdateStates()
610 ChangeImageState(state);
614 [EditorBrowsable(EditorBrowsableState.Never)]
615 public override void OnRelayout(Vector2 size, RelayoutContainer container)
617 if (size == null) return;
619 if (size.Equals(this.size))
624 this.size = new Vector2(size);
627 if (state == ProgressStatusType.Indeterminate) UpdateIndeterminateAnimation();
631 /// Update progress value
633 /// This needs to be considered more if public-open is necessary.
634 [EditorBrowsable(EditorBrowsableState.Never)]
635 private void UpdateValue()
637 if (null == trackImage || null == progressImage)
642 if (minValue >= maxValue || currentValue < minValue || currentValue > maxValue)
647 float width = this.SizeWidth;
648 float height = this.SizeHeight;
649 float progressRatio = (float)(currentValue - minValue) / (float)(maxValue - minValue);
650 float progressWidth = width * progressRatio;
651 progressImage.Size2D = new Size2D((int)(progressWidth + round), (int)height); //Add const round to reach Math.Round function.
652 if (null != bufferImage)
654 if (bufferValue < minValue || bufferValue > maxValue)
659 float bufferRatio = (float)(bufferValue - minValue) / (float)(maxValue - minValue);
660 float bufferWidth = width * bufferRatio;
661 bufferImage.Size2D = new Size2D((int)(bufferWidth + round), (int)height); //Add const round to reach Math.Round function.
665 private Vector4 destinationValue = new Vector4(-1.0f, 0.0f, 10.0f, 1.0f);
666 private Vector4 initialValue = new Vector4(0.0f, 0.0f, 10.0f, 1.0f);
669 /// Update Animation for Indeterminate mode.
671 /// This will be public opened later after ACR done. Before ACR, need to be hidden as inhouse API.
672 [EditorBrowsable(EditorBrowsableState.Never)]
673 private void UpdateIndeterminateAnimation()
675 if (indeterminateImage == null) return;
677 if (indeterminateAnimation == null)
679 indeterminateAnimation = new Animation(IndeterminateAnimationDuration);
683 indeterminateAnimation.Stop();
684 indeterminateAnimation.Clear();
687 float destination = (this.SizeWidth - indeterminateImage.SizeWidth);
689 KeyFrames keyFrames = new KeyFrames();
690 keyFrames.Add(0.0f /* 0%*/, new Position(0, 0));
691 AlphaFunction ease = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseInOut);
692 keyFrames.Add(0.5f /* 50%*/, new Position(destination, 0), ease);
693 keyFrames.Add(1.0f /*100%*/, new Position(0, 0), ease);
696 indeterminateAnimation.AnimateBetween(indeterminateImage, "Position", keyFrames);
697 indeterminateAnimation.Looping = true;
698 indeterminateAnimation.Play();
702 /// Get Progress style.
704 /// <returns>The default progress style.</returns>
705 /// <since_tizen> 8 </since_tizen>
706 protected override ViewStyle CreateViewStyle()
708 return new ProgressStyle();
712 /// Change Image status
714 /// <since_tizen> 6 </since_tizen>
715 /// <param name="statusType">New status type</param>
716 protected void ChangeImageState(ProgressStatusType statusType)
720 ControlState = ControlState.Disabled;
722 indeterminateAnimation?.Stop();
723 indeterminateAnimation = null;
725 if (null != indeterminateImage)
727 indeterminateImage.Hide();
729 progressImage.Hide();
734 if (statusType == ProgressStatusType.Buffering)
736 indeterminateAnimation?.Stop();
737 indeterminateAnimation = null;
739 if (null != indeterminateImage)
741 indeterminateImage.Hide();
743 progressImage.Hide();
746 else if (statusType == ProgressStatusType.Determinate)
748 indeterminateAnimation?.Stop();
749 indeterminateAnimation = null;
751 if (null != indeterminateImage)
753 indeterminateImage.Hide();
756 progressImage.Show();
760 else if (statusType == ProgressStatusType.Indeterminate)
763 progressImage.Hide();
764 if (null != indeterminateImage)
766 indeterminateImage.Show();
769 UpdateIndeterminateAnimation();
774 [EditorBrowsable(EditorBrowsableState.Never)]
775 protected override void OnEnabled(bool enabled)
777 base.OnEnabled(enabled);
781 private void Initialize()
783 AccessibilityHighlightable = true;
786 private void InitializeTrack()
788 if (null == trackImage)
790 trackImage = new ImageView
792 WidthResizePolicy = ResizePolicyType.FillToParent,
793 HeightResizePolicy = ResizePolicyType.FillToParent,
794 PositionUsesPivotPoint = true,
795 ParentOrigin = NUI.ParentOrigin.TopLeft,
796 PivotPoint = NUI.PivotPoint.TopLeft,
797 AccessibilityHidden = true,
803 private void InitializeProgress()
805 if (null == progressImage)
807 progressImage = new ImageView
809 WidthResizePolicy = ResizePolicyType.FillToParent,
810 HeightResizePolicy = ResizePolicyType.FillToParent,
811 PositionUsesPivotPoint = true,
812 ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft,
813 PivotPoint = Tizen.NUI.PivotPoint.TopLeft,
814 AccessibilityHidden = true,
820 private void InitializeBuffer()
822 if (null == bufferImage)
824 bufferImage = new ImageView
826 WidthResizePolicy = ResizePolicyType.FillToParent,
827 HeightResizePolicy = ResizePolicyType.FillToParent,
828 PositionUsesPivotPoint = true,
829 ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft,
830 PivotPoint = Tizen.NUI.PivotPoint.TopLeft,
831 AccessibilityHidden = true,
834 bufferImage.Hide(); // At first, buffer image does not show.
838 private void InitializeIndeterminate()
840 indeterminateImage = new ImageView
842 Size = new Size(16, 16),
843 PositionUsesPivotPoint = true,
844 ParentOrigin = Tizen.NUI.ParentOrigin.CenterLeft,
845 PivotPoint = Tizen.NUI.PivotPoint.CenterLeft,
846 AccessibilityHidden = true,
848 trackImage.Add(indeterminateImage);
849 indeterminateImage.Hide();
851 if (state == ProgressStatusType.Indeterminate)
853 indeterminateImage.Show();