[NUI] Make some of Progress and Slider public methods (#2872)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Progress.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17 using System;
18 using Tizen.NUI.BaseComponents;
19 using Tizen.NUI.Binding;
20 using System.ComponentModel;
21 using System.Diagnostics;
22
23 namespace Tizen.NUI.Components
24 {
25     /// <summary>
26     /// The Progress class is used to show the ongoing status with a long narrow bar.
27     /// </summary>
28     /// <since_tizen> 6 </since_tizen>
29     public class Progress : Control
30     {
31         /// <summary>
32         /// MaxValueProperty
33         /// </summary>
34         [EditorBrowsable(EditorBrowsableState.Never)]
35         public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(float), typeof(Progress), default(float), propertyChanged: (bindable, oldValue, newValue) =>
36         {
37             var instance = (Progress)bindable;
38             if (newValue != null)
39             {
40                 instance.maxValue = (float)newValue;
41                 instance.UpdateValue();
42             }
43         },
44         defaultValueCreator: (bindable) =>
45         {
46             var instance = (Progress)bindable;
47             return instance.maxValue;
48         });
49
50         /// <summary>
51         /// MinValueProperty
52         /// </summary>
53         [EditorBrowsable(EditorBrowsableState.Never)]
54         public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(float), typeof(Progress), default(float), propertyChanged: (bindable, oldValue, newValue) =>
55         {
56             var instance = (Progress)bindable;
57             if (newValue != null)
58             {
59                 instance.minValue = (float)newValue;
60                 instance.UpdateValue();
61             }
62         },
63         defaultValueCreator: (bindable) =>
64         {
65             var instance = (Progress)bindable;
66             return instance.minValue;
67         });
68
69         /// <summary>
70         /// CurrentValueProperty
71         /// </summary>
72         [EditorBrowsable(EditorBrowsableState.Never)]
73         public static readonly BindableProperty CurrentValueProperty = BindableProperty.Create(nameof(CurrentValue), typeof(float), typeof(Progress), default(float), propertyChanged: (bindable, oldValue, newValue) =>
74         {
75             var instance = (Progress)bindable;
76             if (newValue != null)
77             {
78                 if ((float)newValue > instance.maxValue || (float)newValue < instance.minValue)
79                 {
80                     return;
81                 }
82                 instance.currentValue = (float)newValue;
83                 instance.UpdateValue();
84             }
85         },
86         defaultValueCreator: (bindable) =>
87         {
88             var instance = (Progress)bindable;
89             return instance.currentValue;
90         });
91
92         /// <summary>
93         /// BufferValueProperty
94         /// </summary>
95         [EditorBrowsable(EditorBrowsableState.Never)]
96         public static readonly BindableProperty BufferValueProperty = BindableProperty.Create(nameof(BufferValue), typeof(float), typeof(Progress), default(float), propertyChanged: (bindable, oldValue, newValue) =>
97         {
98             var instance = (Progress)bindable;
99             if (newValue != null)
100             {
101                 if ((float)newValue > instance.maxValue || (float)newValue < instance.minValue)
102                 {
103                     return;
104                 }
105                 instance.bufferValue = (float)newValue;
106                 instance.UpdateValue();
107             }
108         },
109         defaultValueCreator: (bindable) =>
110         {
111             var instance = (Progress)bindable;
112             return instance.bufferValue;
113         });
114
115         /// <summary>
116         /// ProgressStateProperty
117         /// </summary>
118         [EditorBrowsable(EditorBrowsableState.Never)]
119         public static readonly BindableProperty ProgressStateProperty = BindableProperty.Create(nameof(ProgressState), typeof(ProgressStatusType), typeof(Progress), ProgressStatusType.Indeterminate, propertyChanged: (bindable, oldValue, newValue) =>
120         {
121             var instance = (Progress)bindable;
122             if (newValue != null)
123             {
124                 instance.state = (ProgressStatusType)newValue;
125                 instance.UpdateStates();
126             }
127         },
128         defaultValueCreator: (bindable) =>
129         {
130             var instance = (Progress)bindable;
131             return instance.state;
132         });
133
134         /// This needs to be considered more if public-open is necessary.
135         private ProgressStatusType state = ProgressStatusType.Determinate;
136
137         private const float round = 0.5f;
138         private ImageView trackImage = null;
139         private ImageView progressImage = null;
140         private ImageView bufferImage = null;
141         private ImageVisual indeterminateImage = null;
142         private float maxValue = 100;
143         private float minValue = 0;
144         private float currentValue = 0;
145         private float bufferValue = 0;
146         private Animation indeterminateAnimation = null;
147
148         static Progress() { }
149         /// <summary>
150         /// The constructor of Progress
151         /// </summary>
152         /// <since_tizen> 6 </since_tizen>
153         public Progress() : base()
154         {
155         }
156
157         /// <summary>
158         /// The constructor of the Progress class with specific style.
159         /// </summary>
160         /// <param name="style">style name</param>
161         /// <since_tizen> 8 </since_tizen>
162         public Progress(string style) : base(style)
163         {
164         }
165
166         /// <summary>
167         /// The constructor of the Progress class with specific style.
168         /// </summary>
169         /// <param name="progressStyle">The style object to initialize the Progress.</param>
170         /// <since_tizen> 8 </since_tizen>
171         public Progress(ProgressStyle progressStyle) : base(progressStyle)
172         {
173         }
174
175         /// <summary>
176         /// The status type of the Progress.
177         /// </summary>
178         /// <since_tizen> 6 </since_tizen>
179         public enum ProgressStatusType
180         {
181             /// <summary>
182             /// Show BufferImage
183             /// </summary>
184             /// <since_tizen> 6 </since_tizen>
185             Buffering,
186
187             /// <summary>
188             /// Show ProgressImage and BufferImage
189             /// </summary>
190             /// <since_tizen> 6 </since_tizen>
191             Determinate,
192
193             /// <summary>
194             /// Show TrackImage
195             /// </summary>
196             /// <since_tizen> 6 </since_tizen>
197             Indeterminate
198         }
199
200         /// <summary>
201         /// Return currently applied style.
202         /// </summary>
203         /// <remarks>
204         /// Modifying contents in style may cause unexpected behaviour.
205         /// </remarks>
206         /// <since_tizen> 8 </since_tizen>
207         public ProgressStyle Style => (ProgressStyle)(ViewStyle as ProgressStyle)?.Clone();
208
209         /// <summary>
210         /// The property to get/set Track image object URL of the Progress.
211         /// </summary>
212         /// <since_tizen> 6 </since_tizen>
213         public string TrackImageURL
214         {
215             get => trackImage.ResourceUrl;
216             set => trackImage.ResourceUrl = value;
217         }
218
219         /// <summary>
220         /// The property to get/set Progress object image URL of the Progress.
221         /// </summary>
222         /// <since_tizen> 6 </since_tizen>
223         public string ProgressImageURL
224         {
225             get => progressImage.ResourceUrl;
226             set => progressImage.ResourceUrl = value;
227         }
228
229         /// <summary>
230         /// The property to get/set Buffer object image resource URL of the Progress.
231         /// </summary>
232         /// <since_tizen> 6 </since_tizen>
233         public string BufferImageURL
234         {
235             get => bufferImage.ResourceUrl;
236             set => bufferImage.ResourceUrl = value;
237         }
238
239         /// <summary>
240         /// The property to get/set the indeterminate image.
241         /// </summary>
242         /// <exception cref="NullReferenceException">Thrown when setting null value.</exception>
243         /// <since_tizen> 9 </since_tizen>
244         public string IndeterminateImageUrl
245         {
246             get
247             {
248                 if (indeterminateImage == null)
249                 {
250                     return null;
251                 }
252                 else
253                 {
254                     return indeterminateImage?.URL;
255                 }
256             }
257             set
258             {
259                 if (value == null || indeterminateImage == null)
260                 {
261                     throw new NullReferenceException("Progress.IndeterminateImage is null");
262                 }
263                 else
264                 {
265                     indeterminateImage.URL = value;
266                 }
267             }
268         }
269
270         /// <summary>
271         /// The property to get/set Track object color of the Progress.
272         /// </summary>
273         /// <since_tizen> 6 </since_tizen>
274         public Color TrackColor
275         {
276             get => trackImage.BackgroundColor;
277             set => trackImage.BackgroundColor = value;
278         }
279
280         /// <summary>
281         /// The property to get/set Progress object color of the Progress.
282         /// </summary>
283         /// <since_tizen> 6 </since_tizen>
284         public Color ProgressColor
285         {
286             get => progressImage.BackgroundColor;
287             set => progressImage.BackgroundColor = value;
288         }
289
290         /// <summary>
291         /// The property to get/set Buffer object color of the Progress.
292         /// </summary>
293         /// <since_tizen> 6 </since_tizen>
294         public Color BufferColor
295         {
296             get => bufferImage.BackgroundColor;
297             set => bufferImage.BackgroundColor = value;
298         }
299
300         /// <summary>
301         /// The property to get/set the maximum value of the Progress.
302         /// </summary>
303         /// <since_tizen> 6 </since_tizen>
304         public float MaxValue
305         {
306             get
307             {
308                 return (float)GetValue(MaxValueProperty);
309             }
310             set
311             {
312                 SetValue(MaxValueProperty, value);
313             }
314         }
315
316         /// <summary>
317         /// The property to get/set the minim value of the Progress.
318         /// </summary>
319         /// <since_tizen> 6 </since_tizen>
320         public float MinValue
321         {
322             get
323             {
324                 return (float)GetValue(MinValueProperty);
325             }
326             set
327             {
328                 SetValue(MinValueProperty, value);
329             }
330         }
331
332         /// <summary>
333         /// The property to get/set the current value of the Progress.
334         /// </summary>
335         /// <since_tizen> 6 </since_tizen>
336         public float CurrentValue
337         {
338             get
339             {
340                 return (float)GetValue(CurrentValueProperty);
341             }
342             set
343             {
344                 SetValue(CurrentValueProperty, value);
345             }
346         }
347
348         /// <summary>
349         /// The property to get/set the buffer value of the Progress.
350         /// </summary>
351         /// <since_tizen> 6 </since_tizen>
352         public float BufferValue
353         {
354             get
355             {
356                 return (float)GetValue(BufferValueProperty);
357             }
358             set
359             {
360                 SetValue(BufferValueProperty, value);
361             }
362         }
363
364         /// <summary>
365         /// Gets or sets state of progress.
366         /// </summary>
367         /// <since_tizen> 6 </since_tizen>
368         public ProgressStatusType ProgressState
369         {
370             get
371             {
372                 return (ProgressStatusType)GetValue(ProgressStateProperty);
373             }
374             set
375             {
376                 SetValue(ProgressStateProperty, value);
377             }
378         }
379
380         /// <inheritdoc/>
381         [EditorBrowsable(EditorBrowsableState.Never)]
382         public override void OnInitialize()
383         {
384             base.OnInitialize();
385             // create necessary components
386             InitializeTrack();
387             InitializeBuffer();
388             InitializeProgress();
389             InitializeIndeterminate();
390
391             indeterminateAnimation?.Stop();
392             indeterminateAnimation = null;
393         }
394
395         /// <inheritdoc/>
396         [EditorBrowsable(EditorBrowsableState.Never)]
397         public override void ApplyStyle(ViewStyle style)
398         {
399             base.ApplyStyle(style);
400
401             if (style is ProgressStyle progressStyle)
402             {
403                 Debug.Assert(trackImage != null);
404                 Debug.Assert(progressImage != null);
405                 Debug.Assert(bufferImage != null);
406
407                 trackImage.ApplyStyle(progressStyle.Track);
408                 progressImage.ApplyStyle(progressStyle.Progress);
409                 bufferImage.ApplyStyle(progressStyle.Buffer);
410
411                 if (null != indeterminateImage && null != progressStyle.IndeterminateImageUrl)
412                 {
413                     indeterminateImage.URL = progressStyle.IndeterminateImageUrl;
414                 }
415             }
416         }
417
418         /// <summary>
419         /// Dispose Progress and all children on it.
420         /// </summary>
421         /// <param name="type">Dispose type.</param>
422         /// <since_tizen> 6 </since_tizen>
423         protected override void Dispose(DisposeTypes type)
424         {
425             if (disposed)
426             {
427                 return;
428             }
429
430             if (type == DisposeTypes.Explicit)
431             {
432                 //Called by User
433                 //Release your own managed resources here.
434                 //You should release all of your own disposable objects here.
435                 Utility.Dispose(trackImage);
436                 Utility.Dispose(progressImage);
437                 Utility.Dispose(bufferImage);
438                 indeterminateImage = null;
439             }
440
441             //You must call base.Dispose(type) just before exit.
442             base.Dispose(type);
443         }
444
445         /// <summary>
446         /// Change Image status. It can be override.
447         /// </summary>
448         /// This needs to be considered more if public-open is necessary.
449         [EditorBrowsable(EditorBrowsableState.Never)]
450         private void UpdateStates()
451         {
452             ChangeImageState(state);
453         }
454
455         /// <summary>
456         /// Update progress value
457         /// </summary>
458         /// This needs to be considered more if public-open is necessary.
459         [EditorBrowsable(EditorBrowsableState.Never)]
460         private void UpdateValue()
461         {
462             if (null == trackImage || null == progressImage)
463             {
464                 return;
465             }
466
467             if (minValue >= maxValue || currentValue < minValue || currentValue > maxValue)
468             {
469                 return;
470             }
471
472             float width = this.SizeWidth;
473             float height = this.SizeHeight;
474             float progressRatio = (float)(currentValue - minValue) / (float)(maxValue - minValue);
475             float progressWidth = width * progressRatio;
476             progressImage.Size2D = new Size2D((int)(progressWidth + round), (int)height); //Add const round to reach Math.Round function.
477             if (null != bufferImage)
478             {
479                 if (bufferValue < minValue || bufferValue > maxValue)
480                 {
481                     return;
482                 }
483
484                 float bufferRatio = (float)(bufferValue - minValue) / (float)(maxValue - minValue);
485                 float bufferWidth = width * bufferRatio;
486                 bufferImage.Size2D = new Size2D((int)(bufferWidth + round), (int)height); //Add const round to reach Math.Round function.
487             }
488         }
489
490         private Vector4 destinationValue = new Vector4(-1.0f, 0.0f, 10.0f, 1.0f);
491         private Vector4 initialValue = new Vector4(0.0f, 0.0f, 10.0f, 1.0f);
492
493         /// <summary>
494         /// Update Animation for Indeterminate mode.
495         /// </summary>
496         /// This will be public opened later after ACR done. Before ACR, need to be hidden as inhouse API.
497         [EditorBrowsable(EditorBrowsableState.Never)]
498         private void UpdateIndeterminateAnimation()
499         {
500             indeterminateAnimation?.Stop();
501
502             if (null != indeterminateImage)
503             {
504                 indeterminateAnimation = AnimateVisual(indeterminateImage, "pixelArea", destinationValue, 0, 1000,  AlphaFunction.BuiltinFunctions.Default, initialValue);
505                 indeterminateAnimation.Looping = true;
506                 indeterminateAnimation.Play();
507             }
508         }
509
510         /// <summary>
511         /// Get Progress style.
512         /// </summary>
513         /// <returns>The default progress style.</returns>
514         /// <since_tizen> 8 </since_tizen>
515         protected override ViewStyle CreateViewStyle()
516         {
517             return new ProgressStyle();
518         }
519
520         /// <summary>
521         /// Change Image status
522         /// </summary>
523         /// <since_tizen> 6 </since_tizen>
524         /// <param name="statusType">New status type</param>
525         protected void ChangeImageState(ProgressStatusType statusType)
526         {
527             if (statusType == ProgressStatusType.Buffering)
528             {
529                 indeterminateAnimation?.Stop();
530                 indeterminateAnimation = null;
531
532                 if (null != indeterminateImage)
533                 {
534                     indeterminateImage.Opacity = 0.0f;
535                 }
536                 progressImage.Hide();
537                 bufferImage.Show();
538             }
539             else if (statusType == ProgressStatusType.Determinate)
540             {
541                 indeterminateAnimation?.Stop();
542                 indeterminateAnimation = null;
543
544                 if (null != indeterminateImage)
545                 {
546                     indeterminateImage.Opacity = 0.0f;
547                 }
548                 bufferImage.Show();
549                 progressImage.Show();
550
551                 UpdateValue();
552             }
553             else if (statusType == ProgressStatusType.Indeterminate)
554             {
555                 bufferImage.Hide();
556                 progressImage.Hide();
557                 if (null != indeterminateImage)
558                 {
559                     indeterminateImage.Opacity = 1.0f;
560                 }
561
562                 UpdateIndeterminateAnimation();
563             }
564         }
565
566         private void InitializeTrack()
567         {
568             if (null == trackImage)
569             {
570                 trackImage = new ImageView
571                 {
572                     WidthResizePolicy = ResizePolicyType.FillToParent,
573                     HeightResizePolicy = ResizePolicyType.FillToParent,
574                     PositionUsesPivotPoint = true,
575                     ParentOrigin = NUI.ParentOrigin.TopLeft,
576                     PivotPoint = NUI.PivotPoint.TopLeft
577                 };
578                 Add(trackImage);
579             }
580         }
581
582         private void InitializeProgress()
583         {
584             if (null == progressImage)
585             {
586                 progressImage = new ImageView
587                 {
588                     WidthResizePolicy = ResizePolicyType.FillToParent,
589                     HeightResizePolicy = ResizePolicyType.FillToParent,
590                     PositionUsesPivotPoint = true,
591                     ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft,
592                     PivotPoint = Tizen.NUI.PivotPoint.TopLeft
593                 };
594                 Add(progressImage);
595             }
596         }
597
598         private void InitializeBuffer()
599         {
600             if (null == bufferImage)
601             {
602                 bufferImage = new ImageView
603                 {
604                     WidthResizePolicy = ResizePolicyType.FillToParent,
605                     HeightResizePolicy = ResizePolicyType.FillToParent,
606                     PositionUsesPivotPoint = true,
607                     ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft,
608                     PivotPoint = Tizen.NUI.PivotPoint.TopLeft
609                 };
610                 Add(bufferImage);
611             }
612         }
613
614         private void InitializeIndeterminate()
615         {
616             indeterminateImage = new ImageVisual
617             {
618                 PixelArea = new Vector4(0.0f, 0.0f, 10.0f, 1.0f),
619                 WrapModeU = WrapModeType.Repeat,
620                 SizePolicy = VisualTransformPolicyType.Relative,
621                 Origin = Visual.AlignType.Center,
622                 AnchorPoint = Visual.AlignType.Center,
623                 Opacity = 0.0f,
624                 Size = new Size2D(1, 1),
625                 URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "nui_component_default_progress_indeterminate.png"
626             };
627             AddVisual("Indeterminate", indeterminateImage);
628
629             if (state == ProgressStatusType.Indeterminate)
630             {
631                 indeterminateImage.Opacity = 1.0f;
632             }
633         }
634     }
635 }