[NUI] fix AnimatedVectorImageView's current frame set defect
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / AnimatedVectorImageView.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
18 using global::System;
19 using System.ComponentModel;
20
21 namespace Tizen.NUI.BaseComponents
22 {
23     /// <summary>
24     /// AnimatedVectorImageView is a class for displaying a vector resource.
25     /// </summary>
26     [EditorBrowsable(EditorBrowsableState.Never)]
27     public partial class AnimatedVectorImageView : LottieAnimationView
28     {
29         #region Constructor, Destructor, Dispose
30         /// <summary>
31         /// Construct VectorAnimationView.
32         /// </summary>
33         [EditorBrowsable(EditorBrowsableState.Never)]
34         public AnimatedVectorImageView() : base()
35         {
36             NUILog.Debug($"[AnimatedVectorImageView START[ constructor objId={GetId()} ] END]");
37         }
38
39         /// <summary>
40         /// Construct VectorAnimationView.
41         /// </summary>
42         /// <param name="scale">Set scaling factor for Vector Animation, while creating.</param>
43         [EditorBrowsable(EditorBrowsableState.Never)]
44         public AnimatedVectorImageView(float scale) : base(scale)
45         {
46             NUILog.Debug($"[AnimatedVectorImageView START[ constructor scale={scale}) objId={GetId()} ] END]");
47         }
48
49         /// <summary>
50         /// You can override it to clean-up your own resources
51         /// </summary>
52         /// <param name="type">DisposeTypes</param>
53         [EditorBrowsable(EditorBrowsableState.Never)]
54         protected override void Dispose(DisposeTypes type)
55         {
56             if (disposed)
57             {
58                 return;
59             }
60             NUILog.Debug($"AnimatedVectorImageView START");
61
62             //Release your own unmanaged resources here.
63             //You should not access any managed member here except static instance.
64             //because the execution order of Finalizes is non-deterministic.
65
66             base.Dispose(type);
67
68             NUILog.Debug($"AnimatedVectorImageView END");
69         }
70         #endregion Constructor, Destructor, Dispose
71
72
73         #region Property
74         /// <summary>
75         /// Set Resource URL
76         /// </summary>
77         // Suppress warning : This has been being used by users, so that the interface can not be changed.
78         [EditorBrowsable(EditorBrowsableState.Never)]
79         public string ResourceURL
80         {
81             get
82             {
83                 return GetValue(ResourceURLProperty) as string;
84             }
85             set
86             {
87                 SetValue(ResourceURLProperty, value);
88                 NotifyPropertyChanged();
89             }
90         }
91
92         private string InternalResourceURL
93         {
94             set
95             {
96                 NUILog.Debug($"[AnimatedVectorImageView START[ [{GetId()}] ResourceURL SET");
97
98                 if (value == resourceUrl)
99                 {
100                     NUILog.Debug($"set same URL! ");
101                     return;
102                 }
103                 resourceUrl = (value == null) ? "" : value;
104                 URL = resourceUrl;
105                 isMinMaxFrameSet = minMaxSetTypes.NotSetByUser;
106                 NUILog.Debug($" [{GetId()}] resourceUrl={resourceUrl}) ]AnimatedVectorImageView END]");
107             }
108             get => resourceUrl;
109         }
110
111         /// <summary>
112         /// Set Resource URL
113         /// </summary>
114         // Suppress warning : This has been being used by users, so that the interface can not be changed.
115         [EditorBrowsable(EditorBrowsableState.Never)]
116         public new string ResourceUrl
117         {
118             get
119             {
120                 return GetValue(ResourceUrlProperty) as string;
121             }
122             set
123             {
124                 SetValue(ResourceUrlProperty, value);
125                 NotifyPropertyChanged();
126             }
127         }
128
129         private string InternalResourceUrl
130         {
131             set
132             {
133                 NUILog.Debug($"[AnimatedVectorImageView START[ [{GetId()}] ResourceUrl SET");
134                 this.ResourceURL = value;
135                 NUILog.Debug($" [{GetId()}] value={value}) ]AnimatedVectorImageView END]");
136             }
137             get
138             {
139                 NUILog.Debug($"[AnimatedVectorImageView [ [{GetId()}] ResourceUrl GET");
140                 return this.ResourceURL;
141             }
142         }
143
144
145         /// <summary>
146         /// RepeatCount of animation.
147         /// The repeat count is 0 by default.
148         /// If the RepeatCount is 0, the animation is never repeated.
149         /// If the RepeatCount is greater than 0, the repeat mode will be taken into account.
150         /// If RepeatCount is -1, animation is infinite loops.
151         /// </summary>
152         [EditorBrowsable(EditorBrowsableState.Never)]
153         public int RepeatCount
154         {
155             get
156             {
157                 return (int)GetValue(RepeatCountProperty);
158             }
159             set
160             {
161                 SetValue(RepeatCountProperty, value);
162                 NotifyPropertyChanged();
163             }
164         }
165
166         private int InternalRepeatCount
167         {
168             set
169             {
170                 NUILog.Debug($"[AnimatedVectorImageView START[ [{GetId()}] RepeatCount SET");
171
172                 repeatCnt = (value < -1) ? -1 : value;
173                 LoopCount = (repeatCnt < 0) ? repeatCnt : repeatCnt + 1;
174
175                 NUILog.Debug($"[{GetId()}] repeatCnt={repeatCnt} ]AnimatedVectorImageView END]");
176             }
177             get => repeatCnt;
178         }
179
180         /// <summary>
181         /// TotalFrame of animation.
182         /// </summary>
183         [EditorBrowsable(EditorBrowsableState.Never)]
184         public new int TotalFrame
185         {
186             get => totalFrameNum;
187         }
188
189         private int totalFrameNum
190         {
191             get => base.TotalFrame;
192         }
193
194         /// <summary>
195         /// CurrentFrame of animation.
196         /// </summary>
197         /// <returns> Returns user set value for the current frame. Cannot provide actual playing current frame. </returns>
198         [EditorBrowsable(EditorBrowsableState.Never)]
199         public new int CurrentFrame
200         {
201             get
202             {
203                 return (int)GetValue(CurrentFrameProperty);
204             }
205             set
206             {
207                 SetValue(CurrentFrameProperty, value);
208                 NotifyPropertyChanged();
209             }
210         }
211
212         private int InternalCurrentFrame
213         {
214             set
215             {
216                 NUILog.Debug($"[AnimatedVectorImageView START[ [{GetId()}] CurrentFrame SET");
217
218                 if (string.IsNullOrEmpty(resourceUrl))
219                 {
220                     throw new InvalidOperationException("Resource Url not yet Set");
221                 }
222
223                 if (value < 0)
224                 {
225                     value = 0;
226                 }
227
228                 innerCurrentFrame = value;
229                 AnimationState = AnimationStates.Paused;
230
231                 base.SetMinMaxFrame(0, IntegerMaxValue);
232                 base.CurrentFrame = innerCurrentFrame;
233
234                 NUILog.Debug($" [{GetId()}] innerCurrentFrame={innerCurrentFrame}) ]AnimatedVectorImageView END]");
235             }
236             get => innerCurrentFrame;
237         }
238
239         /// <summary>
240         /// RepeatMode of animation.
241         /// </summary>
242         [EditorBrowsable(EditorBrowsableState.Never)]
243         public RepeatModes RepeatMode
244         {
245             get
246             {
247                 return (RepeatModes)GetValue(RepeatModeProperty);
248             }
249             set
250             {
251                 SetValue(RepeatModeProperty, value);
252                 NotifyPropertyChanged();
253             }
254         }
255
256         private RepeatModes InternalRepeatMode
257         {
258             set
259             {
260                 NUILog.Debug($"[AnimatedVectorImageView START[ [{GetId()}] RepeatMode SET");
261                 repeatMode = value;
262
263                 switch (repeatMode)
264                 {
265                     case RepeatModes.Restart:
266                         LoopingMode = LoopingModeType.Restart;
267                         break;
268                     case RepeatModes.Reverse:
269                         LoopingMode = LoopingModeType.AutoReverse;
270                         break;
271                     default:
272                         LoopingMode = LoopingModeType.Restart;
273                         break;
274                 }
275
276                 NUILog.Debug($" [{GetId()}] repeatMode={repeatMode}) ]AnimatedVectorImageView END]");
277             }
278             get => repeatMode;
279         }
280
281         /// <summary>
282         /// Get state of animation.
283         /// </summary>
284         [EditorBrowsable(EditorBrowsableState.Never)]
285         public AnimationStates AnimationState
286         {
287             private set
288             {
289                 CurrentAnimationState = value;
290             }
291             get
292             {
293                 if (CurrentAnimationState == AnimationStates.Playing)
294                 {
295                     if (PlayState == PlayStateType.Stopped)
296                     {
297                         CurrentAnimationState = AnimationStates.Stopped;
298                     }
299                 }
300                 return CurrentAnimationState;
301             }
302         }
303         #endregion Property
304
305
306         #region Method
307         /// <summary>
308         /// Set minimum frame and maximum frame
309         /// </summary>
310         /// <param name="minFrame">minimum frame.</param>
311         /// <param name="maxFrame">maximum frame.</param>
312         [EditorBrowsable(EditorBrowsableState.Never)]
313         public void SetMinAndMaxFrame(int minFrame, int maxFrame)
314         {
315             NUILog.Debug($"[AnimatedVectorImageView START[ [{GetId()}] SetMinAndMaxFrame({minFrame}, {maxFrame})");
316
317             minimumFrame = (minFrame) > 0 ? minFrame : 0;
318             maximumFrame = (maxFrame) > 0 ? maxFrame : 0;
319             isMinMaxFrameSet = minMaxSetTypes.SetByMinAndMaxFrameMethod;
320
321             if (minimumFrame > maximumFrame)
322             {
323                 NUILog.Debug($" [{GetId()}] minimumFrame:{minimumFrame} > maximumFrame:{maximumFrame}) ]AnimatedVectorImageView END]");
324                 return;
325             }
326
327             NUILog.Debug($" [{GetId()}] minimumFrame:{minimumFrame}, maximumFrame:{maximumFrame}) ]AnimatedVectorImageView END]");
328         }
329
330         /// <summary>
331         /// SetMinMaxFrame(int startFrame, int endFrame)
332         /// </summary>
333         /// <param name="minFrame"></param>
334         /// <param name="maxFrame"></param>
335         [EditorBrowsable(EditorBrowsableState.Never)]
336         public new void SetMinMaxFrame(int minFrame, int maxFrame)
337         {
338             NUILog.Debug($"SetMinMaxFrame({minFrame}, {maxFrame})!!!");
339
340             minimumFrame = (minFrame) > 0 ? minFrame : 0;
341             maximumFrame = (maxFrame) > 0 ? maxFrame : 0;
342             isMinMaxFrameSet = minMaxSetTypes.SetByBaseSetMinMaxFrameMethod;
343
344             if (minimumFrame >= totalFrameNum)
345             {
346                 minimumFrame = totalFrameNum - 1;
347             }
348
349             if (maximumFrame >= totalFrameNum)
350             {
351                 maximumFrame = totalFrameNum - 1;
352             }
353
354             base.SetMinMaxFrame(minimumFrame, maximumFrame);
355         }
356
357         /// <summary>
358         /// A marker has its start frame and end frame. 
359         /// Animation will play between the start frame and the end frame of the marker if one marker is specified.
360         /// Or animation will play between the start frame of the first marker and the end frame of the second marker if two markers are specified.   *
361         /// </summary>
362         /// <param name="marker1">First marker</param>
363         /// <param name="marker2">Second marker</param>
364         [EditorBrowsable(EditorBrowsableState.Never)]
365         public new void SetMinMaxFrameByMarker(string marker1, string marker2 = null)
366         {
367             NUILog.Debug($"SetMinMaxFrameByMarker({marker1}, {marker2})");
368             isMinMaxFrameSet = minMaxSetTypes.SetByMarker;
369             base.SetMinMaxFrameByMarker(marker1, marker2);
370         }
371
372         /// <summary>
373         /// Play Animation.
374         /// </summary>
375         [EditorBrowsable(EditorBrowsableState.Never)]
376         public new void Play()
377         {
378             NUILog.Debug($"[AnimatedVectorImageView START[ [{GetId()}] AnimationState={AnimationState}, PlayState={PlayState}");
379
380             if (string.IsNullOrEmpty(resourceUrl))
381             {
382                 throw new InvalidOperationException("Resource Url not yet Set");
383             }
384
385             switch (isMinMaxFrameSet)
386             {
387                 case minMaxSetTypes.NotSetByUser:
388                     base.SetMinMaxFrame(0, totalFrameNum - 1);
389                     base.CurrentFrame = 0;
390                     innerCurrentFrame = 0;
391                     break;
392
393                 case minMaxSetTypes.SetByMinAndMaxFrameMethod:
394                     base.SetMinMaxFrame(minimumFrame, maximumFrame);
395                     base.CurrentFrame = minimumFrame;
396                     innerCurrentFrame = minimumFrame;
397                     break;
398
399                 case minMaxSetTypes.SetByMarker:
400                 case minMaxSetTypes.SetByBaseSetMinMaxFrameMethod:
401                 default:
402                     //do nothing!
403                     break;
404             }
405
406             //temporal fix
407             Extents tmp = base.Margin;
408             base.Margin = tmp;
409
410             base.Play();
411             AnimationState = AnimationStates.Playing;
412
413             NUILog.Debug($" [{GetId()}] isMinMaxFrameSet={isMinMaxFrameSet}) ]AnimatedVectorImageView END]");
414         }
415
416         /// <summary>
417         /// Pause Animation.
418         /// </summary>
419         [EditorBrowsable(EditorBrowsableState.Never)]
420         public new void Pause()
421         {
422             NUILog.Debug($"[AnimatedVectorImageView START[ [{GetId()}] AnimationState={AnimationState}, PlayState={PlayState}");
423
424             if (string.IsNullOrEmpty(resourceUrl))
425             {
426                 throw new InvalidOperationException("Resource Url not yet Set");
427             }
428
429             base.Pause();
430             AnimationState = AnimationStates.Paused;
431
432             NUILog.Debug($" [{GetId()}] ]AnimatedVectorImageView END]");
433         }
434
435         /// <summary>
436         /// Stop Animation.
437         /// </summary>
438         /// <param name="endAction">Defines, what should be behaviour after cancel operation
439         /// End action is Cancel, Animation Stops at the Current Frame.
440         /// End action is Discard, Animation Stops at the Min Frame
441         /// End action is StopFinal, Animation Stops at the Max Frame
442         /// </param>
443         [EditorBrowsable(EditorBrowsableState.Never)]
444         public void Stop(EndActions endAction = EndActions.Cancel)
445         {
446             NUILog.Debug($"[AnimatedVectorImageView START[ [{GetId()}] endAction:({endAction}), PlayState={PlayState}");
447
448             if (string.IsNullOrEmpty(resourceUrl))
449             {
450                 throw new InvalidOperationException("Resource Url not yet Set");
451             }
452
453             if (AnimationState == AnimationStates.Stopped)
454             {
455                 return;
456             }
457
458             if (innerEndAction != endAction)
459             {
460                 innerEndAction = endAction;
461                 switch (endAction)
462                 {
463                     case EndActions.Cancel:
464                         StopBehavior = StopBehaviorType.CurrentFrame;
465                         break;
466                     case EndActions.Discard:
467                         StopBehavior = StopBehaviorType.MinimumFrame;
468                         break;
469                     case EndActions.StopFinal:
470                         StopBehavior = StopBehaviorType.MaximumFrame;
471                         break;
472                     default:
473                         NUILog.Debug($" [{GetId()}] no endAction : default set");
474                         break;
475                 }
476             }
477             AnimationState = AnimationStates.Stopped;
478
479             base.Stop();
480
481             NUILog.Debug($"isMinMaxFrameSet:{isMinMaxFrameSet}, base.CurrentFrame:{base.CurrentFrame}, totalFrameNum:{totalFrameNum}, minimumFrame:{minimumFrame}, maximumFrame:{maximumFrame}, StopBehavior:{StopBehavior}, endAction:{endAction}");
482
483             switch (isMinMaxFrameSet)
484             {
485                 case minMaxSetTypes.NotSetByUser:
486                     switch(endAction)
487                     {
488                         case EndActions.Cancel:
489                             innerCurrentFrame = base.CurrentFrame;
490                             break;
491                         case EndActions.Discard:
492                             base.CurrentFrame = innerCurrentFrame = 0;
493                             break;
494                         case EndActions.StopFinal:
495                             base.CurrentFrame = innerCurrentFrame= totalFrameNum - 1;
496                             break;
497                     }
498                     break;
499
500                 case minMaxSetTypes.SetByMinAndMaxFrameMethod:
501                     switch (endAction)
502                     {
503                         case EndActions.Cancel:
504                             innerCurrentFrame = base.CurrentFrame;
505                             break;
506                         case EndActions.Discard:
507                             base.CurrentFrame = innerCurrentFrame = minimumFrame;
508                             break;
509                         case EndActions.StopFinal:
510                             base.CurrentFrame = innerCurrentFrame = maximumFrame;
511                             break;
512                     }
513                     break;
514                 case minMaxSetTypes.SetByMarker:
515                 case minMaxSetTypes.SetByBaseSetMinMaxFrameMethod:
516                 default:
517                     //do nothing!
518                     break;
519             }
520             NUILog.Debug($" [{GetId()}] innerCurrentFrame={innerCurrentFrame}, base.CurrentFrame={base.CurrentFrame}");
521             NUILog.Debug($" [{GetId()}] ]AnimatedVectorImageView END]");
522         }
523         #endregion Method
524
525
526         #region Event, Enum, Struct, ETC
527         /// <summary>
528         /// RepeatMode of animation.
529         /// </summary>
530         // Suppress warning : This has been being used by users, so that the interface can not be changed.
531         [System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1717:Only FlagsAttribute enums should have plural names", Justification = "<Pending>")]
532         [EditorBrowsable(EditorBrowsableState.Never)]
533         public enum RepeatModes
534         {
535             /// <summary>
536             /// When the animation reaches the end and RepeatCount is nonZero, the animation restarts from the beginning. 
537             /// </summary>
538             [EditorBrowsable(EditorBrowsableState.Never)]
539             Restart = LoopingModeType.Restart,
540             /// <summary>
541             /// When the animation reaches the end and RepeatCount nonZero, the animation reverses direction on every animation cycle. 
542             /// </summary>
543             [EditorBrowsable(EditorBrowsableState.Never)]
544             Reverse = LoopingModeType.AutoReverse
545         }
546
547         /// <summary>
548         /// EndActions of animation.
549         /// </summary>
550         // Suppress warning : This has been being used by users, so that the interface can not be changed.
551         [System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1717:Only FlagsAttribute enums should have plural names", Justification = "<Pending>")]
552         [EditorBrowsable(EditorBrowsableState.Never)]
553         public enum EndActions
554         {
555             /// <summary> End action is Cancel, Animation Stops at the Current Frame.</summary>
556             [EditorBrowsable(EditorBrowsableState.Never)]
557             Cancel = 0,
558             /// <summary>  End action is Discard, Animation Stops at the Min Frame</summary>
559             [EditorBrowsable(EditorBrowsableState.Never)]
560             Discard = 1,
561             /// <summary> End action is StopFinal, Animation Stops at the Max Frame</summary>
562             [EditorBrowsable(EditorBrowsableState.Never)]
563             StopFinal = 2
564         }
565
566         /// <summary>
567         /// AnimationStates of animation.
568         /// </summary>
569         // Suppress warning : This has been being used by users, so that the interface can not be changed.
570         [System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1717:Only FlagsAttribute enums should have plural names", Justification = "<Pending>")]
571         [EditorBrowsable(EditorBrowsableState.Never)]
572         public enum AnimationStates
573         {
574             /// <summary> The animation has stopped.</summary>
575             [EditorBrowsable(EditorBrowsableState.Never)]
576             Stopped = PlayStateType.Stopped,
577             /// <summary> The animation is playing.</summary>
578             [EditorBrowsable(EditorBrowsableState.Never)]
579             Playing = PlayStateType.Playing,
580             /// <summary> The animation is paused.</summary>
581             [EditorBrowsable(EditorBrowsableState.Never)]
582             Paused = PlayStateType.Paused
583         }
584         #endregion Event, Enum, Struct, ETC
585
586
587         #region Internal
588         #endregion Internal
589
590
591         #region Private
592         private string resourceUrl = null;
593         private int repeatCnt = 0;
594         private RepeatModes repeatMode = RepeatModes.Restart;
595         private int minimumFrame = -1, maximumFrame = -1;
596         private minMaxSetTypes isMinMaxFrameSet = minMaxSetTypes.NotSetByUser;
597         private int innerCurrentFrame = -1;
598         private EndActions innerEndAction = EndActions.Cancel;
599         private enum minMaxSetTypes
600         {
601             NotSetByUser,
602             SetByMinAndMaxFrameMethod,
603             SetByMarker,
604             SetByBaseSetMinMaxFrameMethod,
605         }
606
607         private AnimationStates CurrentAnimationState = AnimationStates.Stopped;
608         private const int IntegerMaxValue = 0x7FFFFFFF;
609         #endregion Private
610     }
611 }