[NUI] Introduce Button extentions and styles (#1515)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / LottieAnimationView.cs
1 /*
2  * Copyright(c) 2019 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 global::System.Runtime.InteropServices;
20 using System.ComponentModel;
21 using System.Collections.Generic;
22
23 namespace Tizen.NUI.BaseComponents
24 {
25     #if (NUI_DEBUG_ON)
26     using tlog = Tizen.Log;
27     #endif
28
29     /// <summary>
30     /// LottieAnimationView renders an animated vector image (Lottie file).
31     /// </summary>
32     /// <since_tizen> 7 </since_tizen>
33     public class LottieAnimationView : ImageView
34     {
35         #region Constructor, Distructor, Dispose
36         /// <summary>
37         /// LottieAnimationView constructor
38         /// </summary>
39         /// <param name="scale">The factor of scaling image, default : 1.0f</param>
40         /// <param name="shown">false : not displayed (hidden), true : displayed (shown), default : true</param>
41         /// <remarks>
42         /// If shown parameter is false, it is not visible even the LottieAnimationView instance is created.
43         /// </remarks>
44         /// <example>
45         /// <code>
46         /// LottieAnimationView myLottie = new LottieAnimationView();
47         /// LottieAnimationView myLottie2 = new LottieAnimationView(2.0f);
48         /// LottieAnimationView myLottie3 = new LottieAnimationView(1.0f, false);
49         /// </code>
50         /// </example>
51         /// <since_tizen> 7 </since_tizen>
52         public LottieAnimationView(float scale = 1.0f, bool shown = true) : base()
53         {
54             tlog.Fatal(tag, $"< constructor GetId={GetId()} >");
55             currentStates.url = "";
56             currentStates.frame = -1;
57             currentStates.loopCount = 1;
58             currentStates.loopMode = LoopingModeType.Restart;
59             currentStates.stopEndAction = StopBehaviorType.CurrentFrame;
60             currentStates.framePlayRangeMin = -1;
61             currentStates.framePlayRangeMax = -1;
62             currentStates.changed = false;
63             currentStates.totalFrame = -1;
64             currentStates.scale = scale;
65             SetVisible(shown);
66         }
67
68         /// <summary>
69         /// Dispose(DisposeTypes type)
70         /// </summary>
71         /// <param name="type"></param>
72         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
73         [EditorBrowsable(EditorBrowsableState.Never)]
74         protected override void Dispose(DisposeTypes type)
75         {
76             if (disposed)
77             {
78                 return;
79             }
80
81             tlog.Fatal(tag, $"<[{GetId()}] type={type}");
82
83             //Release your own unmanaged resources here.
84             //You should not access any managed member here except static instance.
85             //because the execution order of Finalizes is non-deterministic.
86
87             //disconnect event signal
88             if (finishedEventHandler != null && visualEventSignalCallback != null)
89             {
90                 VisualEventSignal().Disconnect(visualEventSignalCallback);
91                 finishedEventHandler = null;
92                 tlog.Fatal(tag, $"disconnect event signal");
93             }
94
95             base.Dispose(type);
96             tlog.Fatal(tag, $"[{GetId()}]>");
97         }
98         #endregion Constructor, Distructor, Dispose
99
100
101         #region Property
102         /// <summary>
103         /// Set or Get resource URL of Lottie file.
104         /// </summary>
105         /// <since_tizen> 7 </since_tizen>
106         public string URL
107         {
108             set
109             {
110                 string ret = (value == null ? "" : value);
111                 currentStates.url = ret;
112                 currentStates.changed = true;
113
114                 tlog.Fatal(tag, $"<[{GetId()}]SET url={currentStates.url}");
115
116                 PropertyMap map = new PropertyMap();
117                 map.Add(Visual.Property.Type, new PropertyValue((int)DevelVisual.Type.AnimatedVectorImage))
118                     .Add(ImageVisualProperty.URL, new PropertyValue(currentStates.url))
119                     .Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount))
120                     .Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction))
121                     .Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
122                 Image = map;
123
124                 currentStates.contentInfo = null;
125
126                 if (currentStates.scale != 1.0f)
127                 {
128                     Scale = new Vector3(currentStates.scale, currentStates.scale, 0.0f);
129                 }
130                 tlog.Fatal(tag, $"<[{GetId()}]>");
131             }
132             get
133             {
134                 string ret = currentStates.url;
135                 tlog.Fatal(tag, $"<[{GetId()}] GET");
136
137                 PropertyMap map = Image;
138                 if (map != null)
139                 {
140                     PropertyValue val = map.Find(ImageVisualProperty.URL);
141                     if (val != null)
142                     {
143                         if (val.Get(out ret))
144                         {
145                             tlog.Fatal(tag, $"gotten url={ret} >");
146                             return ret;
147                         }
148                     }
149                 }
150                 Tizen.Log.Error(tag, $"  [ERROR][{GetId()}](LottieAnimationView) Fail to get URL from dali >");
151                 return ret;
152             }
153         }
154
155         /// <summary>
156         /// Get playing state
157         /// </summary>
158         /// <since_tizen> 7 </since_tizen>
159         public PlayStateType PlayState
160         {
161             get
162             {
163                 tlog.Fatal(tag, $"< Get!");
164                 PropertyMap map = base.Image;
165                 var ret = 0;
166                 if (map != null)
167                 {
168                     PropertyValue val = map.Find(ImageVisualProperty.PlayState);
169                     if (val != null)
170                     {
171                         if (val.Get(out ret))
172                         {
173                             currentStates.playState = (PlayStateType)ret;
174                             tlog.Fatal(tag, $"gotten play state={ret} >");
175                         }
176                     }
177                 }
178                 else
179                 {
180                     Tizen.Log.Error(tag, $"<[ERROR][{GetId()}]Fail to get PlayState from dali currentStates.playState={currentStates.playState}>");
181                 }
182                 return currentStates.playState;
183             }
184         }
185
186         /// <summary>
187         /// Get the number of total frame
188         /// </summary>
189         /// <since_tizen> 7 </since_tizen>
190         public int TotalFrame
191         {
192             get
193             {
194                 int ret = -1;
195                 PropertyMap map = Image;
196                 if (map != null)
197                 {
198                     PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
199                     if (val != null)
200                     {
201                         if (val.Get(out ret))
202                         {
203                             //tlog.Fatal(tag,  $"TotalFrameNumber get! ret={ret}");
204                             currentStates.totalFrame = ret;
205                             return ret;
206                         }
207                     }
208                 }
209                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get TotalFrameNumber from dali>");
210                 return ret;
211             }
212         }
213
214         /// <summary>
215         /// Set or Get current frame. When setting a specific frame, it is displayed as a still image.
216         /// </summary>
217         /// <remarks>
218         /// Giving user set value when getting. If the out ranged frame is set, it is reset as minimum frame or maximum frame.
219         /// </remarks>
220         /// <example>
221         /// Let's say myLottie.json file has 100 frames originally, then it will have 0 ~ 99 range of frame index.
222         /// <code>
223         /// LottieAnimationView myLottie = new LottieAnimationView();
224         /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
225         /// Window.Instance.GetDefaultLayer().Add(myLottie);
226         /// myLottie.CurrentFrame = 200; //display 99 frame
227         /// myLottie.SetMinMaxFrame(10, 20);
228         /// myLottie.CurrentFrame = 15; //display 15 frame
229         /// myLottie.CurrentFrame = 50; //display 20 frame, because the MinMax is set (10,20) above
230         /// </code>
231         /// </example>
232         /// <since_tizen> 7 </since_tizen>
233         public int CurrentFrame
234         {
235             set
236             {
237                 currentStates.frame = value;
238                 tlog.Fatal(tag, $"<[{GetId()}]SET frame={currentStates.frame}>");
239                 DoAction(vectorImageVisualIndex, (int)actionType.jumpTo, new PropertyValue(currentStates.frame));
240             }
241             get
242             {
243                 int ret = 0;
244                 PropertyMap map = Image;
245                 if (map != null)
246                 {
247                     PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
248                     if (val != null)
249                     {
250                         if (val.Get(out ret))
251                         {
252                             //tlog.Fatal(tag,  $"CurrentFrameNumber get! val={ret}");
253                             return ret;
254                         }
255                     }
256                 }
257                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get CurrentFrameNumber from dali!! ret={ret}>");
258                 return ret;
259             }
260         }
261
262         /// <summary>
263         /// Set or Get looping mode of Lottie animation.
264         /// </summary>
265         /// <since_tizen> 7 </since_tizen>
266         public LoopingModeType LoopingMode
267         {
268             set
269             {
270                 currentStates.loopMode = (LoopingModeType)value;
271                 currentStates.changed = true;
272
273                 tlog.Fatal(tag, $"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
274                 PropertyMap map = new PropertyMap();
275                 map.Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
276                 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
277             }
278             get
279             {
280                 //tlog.Fatal(tag,  $"LoopMode get!");
281                 PropertyMap map = base.Image;
282                 var ret = 0;
283                 if (map != null)
284                 {
285                     PropertyValue val = map.Find(ImageVisualProperty.LoopingMode);
286                     if (val != null)
287                     {
288                         if (val.Get(out ret))
289                         {
290                             //tlog.Fatal(tag,  $"gotten LoopMode={ret}");
291                             if (ret != (int)currentStates.loopMode && ret > 0)
292                             {
293                                 tlog.Fatal(tag, $" [ERROR][{GetId()}](LottieAnimationView) different LoopMode! gotten={ret}, loopMode={currentStates.loopMode}");
294                             }
295                             currentStates.loopMode = (LoopingModeType)ret;
296                             return (LoopingModeType)ret;
297                         }
298                     }
299                 }
300                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get loopMode from dali>");
301                 return currentStates.loopMode;
302             }
303         }
304
305         /// <summary>
306         /// Set or Get loop count. 
307         /// </summary>
308         /// <remarks>
309         /// Minus value means infinite loop count.
310         /// </remarks>
311         /// <example>
312         /// <code>
313         /// LottieAnimationView myLottie = new LottieAnimationView();
314         /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
315         /// Window.Instance.GetDefaultLayer().Add(myLottie);
316         /// myLottie.LoopCount = -1; //infinite loop
317         /// myLottie.Play();
318         /// myLottie.Stop(); //it plays continuously unless Stop() is called
319         /// myLottie.LoopCount = 2;
320         /// myLottie.Play(); //it plays only 2 times and stops automatically
321         /// </code>
322         /// </example>
323         /// <since_tizen> 7 </since_tizen>
324         public int LoopCount
325         {
326             set
327             {
328                 currentStates.changed = true;
329                 currentStates.loopCount = value;
330                 tlog.Fatal(tag, $"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
331                 PropertyMap map = new PropertyMap();
332                 map.Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount));
333                 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
334             }
335             get
336             {
337                 //tlog.Fatal(tag,  $"LoopCount get!");
338                 PropertyMap map = base.Image;
339                 var ret = 0;
340                 if (map != null)
341                 {
342                     PropertyValue val = map.Find(ImageVisualProperty.LoopCount);
343                     if (val != null)
344                     {
345                         if (val.Get(out ret))
346                         {
347                             //tlog.Fatal(tag,  $"gotten loop count={ret}");
348                             if (ret != currentStates.loopCount && ret > 0)
349                             {
350                                 tlog.Fatal(tag, $"<[ERROR][{GetId()}](LottieAnimationView) different loop count! gotten={ret}, loopCount={currentStates.loopCount}>");
351                             }
352                             currentStates.loopCount = ret;
353                             return currentStates.loopCount;
354                         }
355                     }
356                 }
357                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get LoopCount from dali  currentStates.loopCount={currentStates.loopCount}>");
358                 return currentStates.loopCount;
359             }
360         }
361
362         /// <summary>
363         /// Set or Get stop behavior.
364         /// </summary>
365         /// <since_tizen> 7 </since_tizen>
366         public StopBehaviorType StopBehavior
367         {
368             set
369             {
370                 currentStates.stopEndAction = (StopBehaviorType)value;
371                 currentStates.changed = true;
372
373                 tlog.Fatal(tag, $"<[{GetId()}]SET val={currentStates.stopEndAction}>");
374                 PropertyMap map = new PropertyMap();
375                 map.Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction));
376                 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
377             }
378             get
379             {
380                 //tlog.Fatal(tag,  $"StopBehavior get!");
381                 PropertyMap map = base.Image;
382                 var ret = 0;
383                 if (map != null)
384                 {
385                     PropertyValue val = map.Find(ImageVisualProperty.StopBehavior);
386                     if (val != null)
387                     {
388                         if (val.Get(out ret))
389                         {
390                             //tlog.Fatal(tag,  $"gotten StopBehavior={ret}");
391                             if (ret != (int)currentStates.stopEndAction)
392                             {
393                                 tlog.Fatal(tag, $"<[ERROR][{GetId()}](LottieAnimationView) different StopBehavior! gotten={ret}, StopBehavior={currentStates.stopEndAction}>");
394                             }
395                             currentStates.stopEndAction = (StopBehaviorType)ret;
396                             return (StopBehaviorType)ret;
397                         }
398                     }
399                 }
400                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get StopBehavior from dali>");
401                 return currentStates.stopEndAction;
402             }
403         }
404         #endregion Property
405
406
407         #region Method
408         /// <summary>
409         /// Set minimum and maximum frame.
410         /// </summary>
411         /// <param name="minFrame">minimum frame</param>
412         /// <param name="maxFrame">maximum frame</param>
413         /// <since_tizen> 7 </since_tizen>
414         public void SetMinMaxFrame(int minFrame, int maxFrame)
415         {
416             tlog.Fatal(tag, $"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
417
418             currentStates.changed = true;
419             currentStates.framePlayRangeMin = minFrame;
420             currentStates.framePlayRangeMax = maxFrame;
421
422             PropertyArray array = new PropertyArray();
423             array.PushBack(new PropertyValue(currentStates.framePlayRangeMin));
424             array.PushBack(new PropertyValue(currentStates.framePlayRangeMax));
425
426             PropertyMap map = new PropertyMap();
427             map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
428             DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
429             tlog.Fatal(tag, $"  [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
430         }
431
432         /// <summary>
433         /// Play Animation.
434         /// </summary>
435         /// <since_tizen> 7 </since_tizen>
436         public new void Play()
437         {
438             tlog.Fatal(tag, $"<[{GetId()}] Play()");
439             debugPrint();
440             base.Play();
441             tlog.Fatal(tag, $"[{GetId()}]>");
442         }
443
444         /// <summary>
445         /// Pause Animation.
446         /// </summary>
447         /// <since_tizen> 7 </since_tizen>
448         public new void Pause()
449         {
450             tlog.Fatal(tag, $"<[{GetId()}] Pause()>");
451             debugPrint();
452             base.Pause();
453             tlog.Fatal(tag, $"[{GetId()}]>");
454         }
455
456         /// <summary>
457         /// Stop Animation.
458         /// </summary>
459         /// <since_tizen> 7 </since_tizen>
460         public new void Stop()
461         {
462             tlog.Fatal(tag, $"<[{GetId()}] Stop()");
463             debugPrint();
464             base.Stop();
465             tlog.Fatal(tag, $"[{GetId()}]>");
466         }
467
468         /// <summary>
469         /// Get the list of layers' information (start frame, end frame) in Lottie file.
470         /// </summary>
471         /// <returns>List of Tuple (string of layer name, integer of start frame, integer of end frame)</returns>
472         /// <since_tizen> 7 </since_tizen>
473         public List<Tuple<string, int, int>> GetContentInfo()
474         {
475             tlog.Fatal(tag, $"<");
476             if (currentStates.contentInfo != null)
477             {
478                 return currentStates.contentInfo;
479             }
480
481             PropertyMap imageMap = base.Image;
482             PropertyMap contentMap = new PropertyMap();
483             if (imageMap != null)
484             {
485                 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
486                 if (val != null)
487                 {
488                     if (val.Get(contentMap))
489                     {
490                         currentStates.contentInfo = new List<Tuple<string, int, int>>();
491                         for (uint i = 0; i < contentMap.Count(); i++)
492                         {
493                             string key = contentMap.GetKeyAt(i).StringKey;
494                             PropertyArray arr = new PropertyArray();
495                             contentMap.GetValue(i).Get(arr);
496                             if (arr != null)
497                             {
498                                 int startFrame, endFrame;
499                                 arr.GetElementAt(0).Get(out startFrame);
500                                 arr.GetElementAt(1).Get(out endFrame);
501
502                                 tlog.Fatal(tag, $"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
503
504                                 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
505
506                                 currentStates.contentInfo?.Add(item);
507                             }
508                         }
509                     }
510                 }
511             }
512             tlog.Fatal(tag, $">");
513             return currentStates.contentInfo;
514         }
515
516         /// <summary>
517         /// A marker has its start frame and end frame. 
518         /// Animation will play between the start frame and the end frame of the marker if one marker is specified.
519         /// 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.   *
520         /// </summary>
521         /// <param name="marker1">First marker</param>
522         /// <param name="marker2">Second marker</param>
523         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
524         [EditorBrowsable(EditorBrowsableState.Never)]
525         public void SetMinMaxFrameByMarker(string marker1, string marker2 = null)
526         {
527             tlog.Fatal(tag, $"< [{GetId()}] SetMinMaxFrameByMarker({marker1}, {marker2})");
528
529             currentStates.changed = true;
530             currentStates.mark1 = marker1;
531             currentStates.mark2 = marker2;
532
533             PropertyArray array = new PropertyArray();
534             array.PushBack(new PropertyValue(currentStates.mark1));
535             if (marker2 != null)
536             {
537                 array.PushBack(new PropertyValue(currentStates.mark2));
538             }
539
540             PropertyMap map = new PropertyMap();
541             map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
542             DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
543             tlog.Fatal(tag, $"  [{GetId()}] currentStates.mark1:{currentStates.mark1}, mark2:{currentStates.mark2} >");
544         }
545
546         /// <summary>
547         /// Get MinMax Frame
548         /// </summary>
549         /// <returns>Tuple of Min and Max frames</returns>
550         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
551         [EditorBrowsable(EditorBrowsableState.Never)]
552         public Tuple<int, int> GetMinMaxFrame()
553         {
554             tlog.Fatal(tag, $"< [{GetId()}] GetMinMaxFrame()! total frame={currentStates.totalFrame}");
555
556             PropertyMap map = Image;
557             if (map != null)
558             {
559                 PropertyValue val = map.Find(ImageVisualProperty.PlayRange);
560                 if (val != null)
561                 {
562                     PropertyArray array = new PropertyArray();
563                     if (val.Get(array))
564                     {
565                         uint cnt = array.Count();
566                         int item1 = -1, item2 = -1;
567                         for (uint i = 0; i < cnt; i++)
568                         {
569                             PropertyValue v = array.GetElementAt(i);
570                             int intRet;
571                             if (v.Get(out intRet))
572                             {
573                                 tlog.Fatal(tag, $"Got play range of string [{i}]: {intRet}");
574                                 if (i == 0)
575                                 {
576                                     item1 = intRet;
577                                 }
578                                 else if (i == 1)
579                                 {
580                                     item2 = intRet;
581                                 }
582                             }
583                             else
584                             {
585                                 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#1");
586                             }
587                         }
588                         tlog.Fatal(tag, $"  [{GetId()}] GetMinMaxFrame(min:{item1}, max:{item2})! >");
589                         return new Tuple<int, int>(item1, item2);
590                     }
591                 }
592             }
593             Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#2");
594             return new Tuple<int, int>(-1, -1);
595         }
596         #endregion Method
597
598
599         #region Event, Enum, Struct, ETC
600         /// <summary>
601         /// Animation finished event.
602         /// </summary>
603         /// <since_tizen> 7 </since_tizen>
604         public event EventHandler Finished
605         {
606             add
607             {
608                 if (finishedEventHandler == null)
609                 {
610                     tlog.Fatal(tag, $"<[{GetId()}] Finished eventhandler added>");
611                     visualEventSignalCallback = onVisualEventSignal;
612                     VisualEventSignal().Connect(visualEventSignalCallback);
613                 }
614                 finishedEventHandler += value;
615             }
616             remove
617             {
618                 tlog.Fatal(tag, $"<[{GetId()}] Finished eventhandler removed>");
619                 finishedEventHandler -= value;
620                 if (finishedEventHandler == null && visualEventSignalCallback != null)
621                 {
622                     VisualEventSignal().Disconnect(visualEventSignalCallback);
623                 }
624             }
625         }
626
627         /// <summary>
628         /// Enumeration for what state the vector animation is in
629         /// </summary>
630         /// <since_tizen> 7 </since_tizen>
631         public enum PlayStateType
632         {
633             /// <summary>
634             /// Invalid
635             /// </summary>
636             /// <since_tizen> 7 </since_tizen>
637             Invalid = -1,
638             /// <summary>
639             /// Vector Animation has stopped
640             /// </summary>
641             /// <since_tizen> 7 </since_tizen>
642             Stopped = 0,
643             /// <summary>
644             /// The vector animation is playing
645             /// </summary>
646             /// <since_tizen> 7 </since_tizen>
647             Playing = 1,
648             /// <summary>
649             /// The vector animation is paused
650             /// </summary>
651             /// <since_tizen> 7 </since_tizen>
652             Paused = 2
653         }
654
655         /// <summary>
656         /// Enumeration for what to do when the animation is stopped.
657         /// </summary>
658         /// <since_tizen> 7 </since_tizen>
659         public enum StopBehaviorType
660         {
661             /// <summary>
662             /// When the animation is stopped, the current frame is shown.
663             /// </summary>
664             /// <since_tizen> 7 </since_tizen>
665             CurrentFrame,
666             /// <summary>
667             /// When the animation is stopped, the min frame (first frame) is shown.
668             /// </summary>
669             /// <since_tizen> 7 </since_tizen>
670             MinimumFrame,
671             /// <summary>
672             /// When the animation is stopped, the max frame (last frame) is shown.
673             /// </summary>
674             /// <since_tizen> 7 </since_tizen>
675             MaximumFrame
676         }
677
678         /// <summary>
679         /// Enumeration for what looping mode is in.
680         /// </summary>
681         /// <since_tizen> 7 </since_tizen>
682         public enum LoopingModeType
683         {
684             /// <summary>
685             /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
686             /// </summary>
687             /// <since_tizen> 7 </since_tizen>
688             Restart,
689             /// <summary>
690             /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
691             /// </summary>
692             /// <since_tizen> 7 </since_tizen>
693             AutoReverse
694         }
695         #endregion Event, Enum, Struct, ETC
696
697
698         #region Internal
699         internal class VisualEventSignalArgs : EventArgs
700         {
701             public int VisualIndex
702             {
703                 set;
704                 get;
705             }
706             public int SignalId
707             {
708                 set;
709                 get;
710             }
711         }
712
713         internal event EventHandler<VisualEventSignalArgs> VisualEvent
714         {
715             add
716             {
717                 if (visualEventSignalHandler == null)
718                 {
719                     visualEventSignalCallback = onVisualEventSignal;
720                     VisualEventSignal().Connect(visualEventSignalCallback);
721                 }
722                 visualEventSignalHandler += value;
723             }
724             remove
725             {
726                 visualEventSignalHandler -= value;
727                 if (visualEventSignalHandler == null && VisualEventSignal().Empty() == false)
728                 {
729                     VisualEventSignal().Disconnect(visualEventSignalCallback);
730                 }
731             }
732         }
733
734         internal void EmitVisualEventSignal(int visualIndex, int signalId)
735         {
736             VisualEventSignal().Emit(this, visualIndex, signalId);
737         }
738
739         internal VisualEventSignal VisualEventSignal()
740         {
741             VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
742             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
743             return ret;
744         }
745         #endregion Internal
746
747
748         #region Private
749         private struct states
750         {
751             internal string url;
752             internal int frame;
753             internal int loopCount;
754             internal LoopingModeType loopMode;
755             internal StopBehaviorType stopEndAction;
756             internal int framePlayRangeMin;
757             internal int framePlayRangeMax;
758             internal bool changed;
759             internal int totalFrame;
760             internal float scale;
761             internal PlayStateType playState;
762             internal List<Tuple<string, int, int>> contentInfo;
763             internal string mark1, mark2;
764         };
765         private states currentStates;
766
767         private enum actionType
768         {
769             play,
770             pause,
771             stop,
772             jumpTo,
773             updateProperty,
774         };
775
776         private struct DevelVisual
777         {
778             internal enum Type
779             {
780                 AnimatedGradient = Visual.Type.AnimatedImage + 1,
781                 AnimatedVectorImage = Visual.Type.AnimatedImage + 2,
782             }
783         }
784
785         private const string tag = "NUITEST";
786         private const int vectorImageVisualIndex = 10000000 + 1000 + 2;
787         private event EventHandler finishedEventHandler;
788
789         private void OnFinished()
790         {
791             tlog.Fatal(tag, $"<[{GetId()}] OnFinished()>");
792             finishedEventHandler?.Invoke(this, null);
793         }
794
795         private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
796         {
797             OnFinished();
798
799             if (targetView != IntPtr.Zero)
800             {
801                 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
802                 if (v != null)
803                 {
804                     tlog.Fatal(tag, $"targetView is not null! name={v.Name}");
805                 }
806                 else
807                 {
808                     tlog.Fatal(tag, $"target is something created from dali");
809                 }
810             }
811             VisualEventSignalArgs e = new VisualEventSignalArgs();
812             e.VisualIndex = visualIndex;
813             e.SignalId = signalId;
814             visualEventSignalHandler?.Invoke(this, e);
815
816             tlog.Fatal(tag, $"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
817         }
818
819         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
820         private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
821
822         private VisualEventSignalCallbackType visualEventSignalCallback;
823         private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
824
825         private void debugPrint()
826         {
827             tlog.Fatal(tag, $"===================================");
828             tlog.Fatal(tag, $"<[{GetId()}] get currentStates : url={currentStates.url}, loopCount={currentStates.loopCount}, framePlayRangeMin/Max({currentStates.framePlayRangeMin},{currentStates.framePlayRangeMax}) ");
829             tlog.Fatal(tag, $"  get from Property : StopBehavior={StopBehavior}, LoopMode={LoopingMode}, LoopCount={LoopCount}, PlayState={PlayState} >");
830             tlog.Fatal(tag, $"===================================");
831         }
832         #endregion Private
833     }
834
835     /// <summary>
836     /// A class containing frame informations for a LottieAnimationView.
837     /// </summary>
838     [EditorBrowsable(EditorBrowsableState.Never)]
839     public class LottieFrameInfo
840     {
841         /// <summary>
842         /// Creates a new instance with a playing range.
843         /// </summary>
844         [EditorBrowsable(EditorBrowsableState.Never)]
845         public LottieFrameInfo(int startFrame, int endFrame)
846         {
847             StartFrame = startFrame;
848             EndFrame = endFrame;
849         }
850
851         /// <summary>
852         /// Creates a new instance with a still image frame.
853         /// </summary>
854         [EditorBrowsable(EditorBrowsableState.Never)]
855         public LottieFrameInfo(int stillImageFrame) : this(stillImageFrame, stillImageFrame)
856         {
857         }
858
859         /// <summary>
860         /// Create a new instance from a pair notation.
861         /// </summary>
862         [EditorBrowsable(EditorBrowsableState.Never)]
863         public static implicit operator LottieFrameInfo((int, int) pair)
864         {
865             return new LottieFrameInfo(pair.Item1, pair.Item2);
866         }
867
868         /// <summary>
869         /// Create a new instance from an int value.
870         /// </summary>
871         [EditorBrowsable(EditorBrowsableState.Never)]
872         public static implicit operator LottieFrameInfo(int stillImageFrame)
873         {
874             return new LottieFrameInfo(stillImageFrame);
875         }
876
877         /// <summary>
878         /// The start frame of the lottie animation.
879         /// </summary>
880         [EditorBrowsable(EditorBrowsableState.Never)]
881         public int StartFrame { get; }
882
883         /// <summary>
884         /// The end frame of the lottie animation.
885         /// </summary>
886         [EditorBrowsable(EditorBrowsableState.Never)]
887         public int EndFrame { get; }
888
889         /// <summary>
890         /// Create LottieFrameInfo struct with animation range information
891         /// </summary>
892         [EditorBrowsable(EditorBrowsableState.Never)]
893         public static LottieFrameInfo CreateAnimationRange(int startFrame, int endFrame)
894         {
895             return new LottieFrameInfo(startFrame, endFrame);
896         }
897
898         /// <summary>
899         /// Create LottieFrameInfo struct with still image information
900         /// </summary>
901         [EditorBrowsable(EditorBrowsableState.Never)]
902         public static LottieFrameInfo CreateStillImage(int stillImageFrame)
903         {
904             return new LottieFrameInfo(stillImageFrame, stillImageFrame);
905         }
906
907         internal bool IsStillImage()
908         {
909             return StartFrame == EndFrame;
910         }
911
912         internal void Show(LottieAnimationView lottieView, bool noPlay = false)
913         {
914             if (!BeReadyToShow(lottieView))
915             {
916                 return;
917             }
918
919             lottieView.SetMinMaxFrame(StartFrame, Math.Min(EndFrame, lottieView.TotalFrame - 1));
920             lottieView.CurrentFrame = StartFrame;
921
922             if (!noPlay && !IsStillImage())
923             {
924                 lottieView.Play();
925             }
926         }
927
928         private bool BeReadyToShow(LottieAnimationView lottieView)
929         {
930             // Validate input lottieView
931             if (null== lottieView || lottieView.PlayState == LottieAnimationView.PlayStateType.Invalid)
932             {
933                 return false;
934             }
935
936             // Stop if it was playing
937             if (lottieView.PlayState == LottieAnimationView.PlayStateType.Playing)
938             {
939                 lottieView.Stop();
940             }
941
942             return true;
943         }
944     }
945 }