[NUI] Publish LottieAnimationView : TCSACR-293 (#1129)
[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 #if (NUI_DEBUG_ON)
24 using tlog = Tizen.Log;
25 #endif
26
27 namespace Tizen.NUI.BaseComponents
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                             return currentStates.playState;
176                         }
177                     }
178                 }
179                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}]Fail to get PlayState from dali currentStates.playState={currentStates.playState}>");
180                 return currentStates.playState;
181             }
182         }
183
184         /// <summary>
185         /// Get the number of total frame
186         /// </summary>
187         /// <since_tizen> 7 </since_tizen>
188         public int TotalFrame
189         {
190             get
191             {
192                 int ret = -1;
193                 PropertyMap map = Image;
194                 if (map != null)
195                 {
196                     PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
197                     if (val != null)
198                     {
199                         if (val.Get(out ret))
200                         {
201                             //tlog.Fatal(tag,  $"TotalFrameNumber get! ret={ret}");
202                             currentStates.totalFrame = ret;
203                             return ret;
204                         }
205                     }
206                 }
207                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get TotalFrameNumber from dali>");
208                 return ret;
209             }
210         }
211
212         /// <summary>
213         /// Set or Get current frame. When setting a specific frame, it is displayed as a still image.
214         /// </summary>
215         /// <remarks>
216         /// Giving user set value when getting. If the out ranged frame is set, it is reset as minimum frame or maximum frame.
217         /// </remarks>
218         /// <example>
219         /// Let's say myLottie.json file has 100 frames originally, then it will have 0 ~ 99 range of frame index.
220         /// <code>
221         /// LottieAnimationView myLottie = new LottieAnimationView();
222         /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
223         /// Window.Instance.GetDefaultLayer().Add(myLottie);
224         /// myLottie.CurrentFrame = 200; //display 99 frame
225         /// myLottie.SetMinMaxFrame(10, 20);
226         /// myLottie.CurrentFrame = 15; //display 15 frame
227         /// myLottie.CurrentFrame = 50; //display 20 frame, because the MinMax is set (10,20) above
228         /// </code>
229         /// </example>
230         /// <since_tizen> 7 </since_tizen>
231         public int CurrentFrame
232         {
233             set
234             {
235                 currentStates.frame = value;
236                 tlog.Fatal(tag, $"<[{GetId()}]SET frame={currentStates.frame}>");
237                 DoAction(vectorImageVisualIndex, (int)actionType.jumpTo, new PropertyValue(currentStates.frame));
238             }
239             get
240             {
241                 int ret = 0;
242                 PropertyMap map = Image;
243                 if (map != null)
244                 {
245                     PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
246                     if (val != null)
247                     {
248                         if (val.Get(out ret))
249                         {
250                             //tlog.Fatal(tag,  $"CurrentFrameNumber get! val={ret}");
251                             return ret;
252                         }
253                     }
254                 }
255                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get CurrentFrameNumber from dali!! ret={ret}>");
256                 return ret;
257             }
258         }
259
260         /// <summary>
261         /// Set or Get looping mode of Lottie animation.
262         /// </summary>
263         /// <since_tizen> 7 </since_tizen>
264         public LoopingModeType LoopingMode
265         {
266             set
267             {
268                 currentStates.loopMode = (LoopingModeType)value;
269                 currentStates.changed = true;
270
271                 tlog.Fatal(tag, $"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
272                 PropertyMap map = new PropertyMap();
273                 map.Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
274                 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
275             }
276             get
277             {
278                 //tlog.Fatal(tag,  $"LoopMode get!");
279                 PropertyMap map = base.Image;
280                 var ret = 0;
281                 if (map != null)
282                 {
283                     PropertyValue val = map.Find(ImageVisualProperty.LoopingMode);
284                     if (val != null)
285                     {
286                         if (val.Get(out ret))
287                         {
288                             //tlog.Fatal(tag,  $"gotten LoopMode={ret}");
289                             if (ret != (int)currentStates.loopMode && ret > 0)
290                             {
291                                 tlog.Fatal(tag, $" [ERROR][{GetId()}](LottieAnimationView) different LoopMode! gotten={ret}, loopMode={currentStates.loopMode}");
292                             }
293                             currentStates.loopMode = (LoopingModeType)ret;
294                             return (LoopingModeType)ret;
295                         }
296                     }
297                 }
298                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get loopMode from dali>");
299                 return currentStates.loopMode;
300             }
301         }
302
303         /// <summary>
304         /// Set or Get loop count. 
305         /// </summary>
306         /// <remarks>
307         /// Minus value means infinite loop count.
308         /// </remarks>
309         /// <example>
310         /// <code>
311         /// LottieAnimationView myLottie = new LottieAnimationView();
312         /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
313         /// Window.Instance.GetDefaultLayer().Add(myLottie);
314         /// myLottie.LoopCount = -1; //infinite loop
315         /// myLottie.Play();
316         /// myLottie.Stop(); //it plays continuously unless Stop() is called
317         /// myLottie.LoopCount = 2;
318         /// myLottie.Play(); //it plays only 2 times and stops automatically
319         /// </code>
320         /// </example>
321         /// <since_tizen> 7 </since_tizen>
322         public int LoopCount
323         {
324             set
325             {
326                 currentStates.changed = true;
327                 currentStates.loopCount = value;
328                 tlog.Fatal(tag, $"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
329                 PropertyMap map = new PropertyMap();
330                 map.Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount));
331                 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
332             }
333             get
334             {
335                 //tlog.Fatal(tag,  $"LoopCount get!");
336                 PropertyMap map = base.Image;
337                 var ret = 0;
338                 if (map != null)
339                 {
340                     PropertyValue val = map.Find(ImageVisualProperty.LoopCount);
341                     if (val != null)
342                     {
343                         if (val.Get(out ret))
344                         {
345                             //tlog.Fatal(tag,  $"gotten loop count={ret}");
346                             if (ret != currentStates.loopCount && ret > 0)
347                             {
348                                 tlog.Fatal(tag, $"<[ERROR][{GetId()}](LottieAnimationView) different loop count! gotten={ret}, loopCount={currentStates.loopCount}>");
349                             }
350                             currentStates.loopCount = ret;
351                             return currentStates.loopCount;
352                         }
353                     }
354                 }
355                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get LoopCount from dali  currentStates.loopCount={currentStates.loopCount}>");
356                 return currentStates.loopCount;
357             }
358         }
359
360         /// <summary>
361         /// Set or Get stop behavior.
362         /// </summary>
363         /// <since_tizen> 7 </since_tizen>
364         public StopBehaviorType StopBehavior
365         {
366             set
367             {
368                 currentStates.stopEndAction = (StopBehaviorType)value;
369                 currentStates.changed = true;
370
371                 tlog.Fatal(tag, $"<[{GetId()}]SET val={currentStates.stopEndAction}>");
372                 PropertyMap map = new PropertyMap();
373                 map.Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction));
374                 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
375             }
376             get
377             {
378                 //tlog.Fatal(tag,  $"StopBehavior get!");
379                 PropertyMap map = base.Image;
380                 var ret = 0;
381                 if (map != null)
382                 {
383                     PropertyValue val = map.Find(ImageVisualProperty.StopBehavior);
384                     if (val != null)
385                     {
386                         if (val.Get(out ret))
387                         {
388                             //tlog.Fatal(tag,  $"gotten StopBehavior={ret}");
389                             if (ret != (int)currentStates.stopEndAction)
390                             {
391                                 tlog.Fatal(tag, $"<[ERROR][{GetId()}](LottieAnimationView) different StopBehavior! gotten={ret}, StopBehavior={currentStates.stopEndAction}>");
392                             }
393                             currentStates.stopEndAction = (StopBehaviorType)ret;
394                             return (StopBehaviorType)ret;
395                         }
396                     }
397                 }
398                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get StopBehavior from dali>");
399                 return currentStates.stopEndAction;
400             }
401         }
402         #endregion Property
403
404
405         #region Method
406         /// <summary>
407         /// Set minimum and maximum frame.
408         /// </summary>
409         /// <param name="minFrame">minimum frame</param>
410         /// <param name="maxFrame">maximum frame</param>
411         /// <since_tizen> 7 </since_tizen>
412         public void SetMinMaxFrame(int minFrame, int maxFrame)
413         {
414             tlog.Fatal(tag, $"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
415
416             currentStates.changed = true;
417             currentStates.framePlayRangeMin = minFrame;
418             currentStates.framePlayRangeMax = maxFrame;
419
420             PropertyArray array = new PropertyArray();
421             array.PushBack(new PropertyValue(currentStates.framePlayRangeMin));
422             array.PushBack(new PropertyValue(currentStates.framePlayRangeMax));
423
424             PropertyMap map = new PropertyMap();
425             map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
426             DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
427             tlog.Fatal(tag, $"  [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
428         }
429
430         /// <summary>
431         /// Play Animation.
432         /// </summary>
433         /// <since_tizen> 7 </since_tizen>
434         public new void Play()
435         {
436             tlog.Fatal(tag, $"<[{GetId()}] Play()");
437             debugPrint();
438             base.Play();
439             tlog.Fatal(tag, $"[{GetId()}]>");
440         }
441
442         /// <summary>
443         /// Pause Animation.
444         /// </summary>
445         /// <since_tizen> 7 </since_tizen>
446         public new void Pause()
447         {
448             tlog.Fatal(tag, $"<[{GetId()}] Pause()>");
449             debugPrint();
450             base.Pause();
451             tlog.Fatal(tag, $"[{GetId()}]>");
452         }
453
454         /// <summary>
455         /// Stop Animation.
456         /// </summary>
457         /// <since_tizen> 7 </since_tizen>
458         public new void Stop()
459         {
460             tlog.Fatal(tag, $"<[{GetId()}] Stop()");
461             debugPrint();
462             base.Stop();
463             tlog.Fatal(tag, $"[{GetId()}]>");
464         }
465
466         /// <summary>
467         /// Get the list of layers' information (start frame, end frame) in Lottie file.
468         /// </summary>
469         /// <returns>List of Tuple (string of layer name, integer of start frame, integer of end frame)</returns>
470         /// <since_tizen> 7 </since_tizen>
471         public List<Tuple<string, int, int>> GetContentInfo()
472         {
473             tlog.Fatal(tag, $"<");
474             if (currentStates.contentInfo != null)
475             {
476                 return currentStates.contentInfo;
477             }
478
479             PropertyMap imageMap = base.Image;
480             PropertyMap contentMap = new PropertyMap();
481             if (imageMap != null)
482             {
483                 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
484                 if (val != null)
485                 {
486                     if (val.Get(contentMap))
487                     {
488                         for (uint i = 0; i < contentMap.Count(); i++)
489                         {
490                             string key = contentMap.GetKeyAt(i).StringKey;
491                             PropertyArray arr = new PropertyArray();
492                             contentMap.GetValue(i).Get(arr);
493                             if (arr != null)
494                             {
495                                 int startFrame, endFrame;
496                                 arr.GetElementAt(0).Get(out startFrame);
497                                 arr.GetElementAt(1).Get(out endFrame);
498
499                                 tlog.Fatal(tag, $"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
500
501                                 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
502
503                                 currentStates.contentInfo?.Add(item);
504                             }
505                         }
506                     }
507                 }
508             }
509             tlog.Fatal(tag, $">");
510             return currentStates.contentInfo;
511         }
512         #endregion Method
513
514
515         #region Event, Enum, Struct, ETC
516         /// <summary>
517         /// Animation finished event.
518         /// </summary>
519         /// <since_tizen> 7 </since_tizen>
520         public event EventHandler Finished
521         {
522             add
523             {
524                 if (finishedEventHandler == null)
525                 {
526                     tlog.Fatal(tag, $"<[{GetId()}] Finished eventhandler added>");
527                     visualEventSignalCallback = onVisualEventSignal;
528                     VisualEventSignal().Connect(visualEventSignalCallback);
529                 }
530                 finishedEventHandler += value;
531             }
532             remove
533             {
534                 tlog.Fatal(tag, $"<[{GetId()}] Finished eventhandler removed>");
535                 finishedEventHandler -= value;
536                 if (finishedEventHandler == null && visualEventSignalCallback != null)
537                 {
538                     VisualEventSignal().Disconnect(visualEventSignalCallback);
539                 }
540             }
541         }
542
543         /// <summary>
544         /// Enumeration for what state the vector animation is in
545         /// </summary>
546         /// <since_tizen> 7 </since_tizen>
547         public enum PlayStateType
548         {
549             /// <summary>
550             /// Invalid
551             /// </summary>
552             /// <since_tizen> 7 </since_tizen>
553             Invalid = -1,
554             /// <summary>
555             /// Vector Animation has stopped
556             /// </summary>
557             /// <since_tizen> 7 </since_tizen>
558             Stopped = 0,
559             /// <summary>
560             /// The vector animation is playing
561             /// </summary>
562             /// <since_tizen> 7 </since_tizen>
563             Playing = 1,
564             /// <summary>
565             /// The vector animation is paused
566             /// </summary>
567             /// <since_tizen> 7 </since_tizen>
568             Paused = 2
569         }
570
571         /// <summary>
572         /// Enumeration for what to do when the animation is stopped.
573         /// </summary>
574         /// <since_tizen> 7 </since_tizen>
575         public enum StopBehaviorType
576         {
577             /// <summary>
578             /// When the animation is stopped, the current frame is shown.
579             /// </summary>
580             /// <since_tizen> 7 </since_tizen>
581             CurrentFrame,
582             /// <summary>
583             /// When the animation is stopped, the min frame (first frame) is shown.
584             /// </summary>
585             /// <since_tizen> 7 </since_tizen>
586             MinimumFrame,
587             /// <summary>
588             /// When the animation is stopped, the max frame (last frame) is shown.
589             /// </summary>
590             /// <since_tizen> 7 </since_tizen>
591             MaximumFrame
592         }
593
594         /// <summary>
595         /// Enumeration for what looping mode is in.
596         /// </summary>
597         /// <since_tizen> 7 </since_tizen>
598         public enum LoopingModeType
599         {
600             /// <summary>
601             /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
602             /// </summary>
603             /// <since_tizen> 7 </since_tizen>
604             Restart,
605             /// <summary>
606             /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
607             /// </summary>
608             /// <since_tizen> 7 </since_tizen>
609             AutoReverse
610         }
611         #endregion Event, Enum, Struct, ETC
612
613
614         #region Internal
615         internal class VisualEventSignalArgs : EventArgs
616         {
617             public int VisualIndex
618             {
619                 set;
620                 get;
621             }
622             public int SignalId
623             {
624                 set;
625                 get;
626             }
627         }
628
629         internal event EventHandler<VisualEventSignalArgs> VisualEvent
630         {
631             add
632             {
633                 if (visualEventSignalHandler == null)
634                 {
635                     visualEventSignalCallback = onVisualEventSignal;
636                     VisualEventSignal().Connect(visualEventSignalCallback);
637                 }
638                 visualEventSignalHandler += value;
639             }
640             remove
641             {
642                 visualEventSignalHandler -= value;
643                 if (visualEventSignalHandler == null && VisualEventSignal().Empty() == false)
644                 {
645                     VisualEventSignal().Disconnect(visualEventSignalCallback);
646                 }
647             }
648         }
649
650         internal void EmitVisualEventSignal(int visualIndex, int signalId)
651         {
652             VisualEventSignal().Emit(this, visualIndex, signalId);
653         }
654
655         internal VisualEventSignal VisualEventSignal()
656         {
657             VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
658             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
659             return ret;
660         }
661         #endregion Internal
662
663
664         #region Private
665         private struct states
666         {
667             internal string url;
668             internal int frame;
669             internal int loopCount;
670             internal LoopingModeType loopMode;
671             internal StopBehaviorType stopEndAction;
672             internal int framePlayRangeMin;
673             internal int framePlayRangeMax;
674             internal bool changed;
675             internal int totalFrame;
676             internal float scale;
677             internal PlayStateType playState;
678             internal List<Tuple<string, int, int>> contentInfo;
679         };
680         private states currentStates;
681
682         private enum actionType
683         {
684             play,
685             pause,
686             stop,
687             jumpTo,
688             updateProperty,
689         };
690
691         private struct DevelVisual
692         {
693             internal enum Type
694             {
695                 AnimatedGradient = Visual.Type.AnimatedImage + 1,
696                 AnimatedVectorImage = Visual.Type.AnimatedImage + 2,
697             }
698         }
699
700         private const string tag = "NUITEST";
701         private const int vectorImageVisualIndex = 10000000 + 1000 + 2;
702         private event EventHandler finishedEventHandler;
703
704         private void OnFinished()
705         {
706             tlog.Fatal(tag, $"<[{GetId()}] OnFinished()>");
707             finishedEventHandler?.Invoke(this, null);
708         }
709
710         private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
711         {
712             OnFinished();
713
714             if (targetView != IntPtr.Zero)
715             {
716                 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
717                 if (v != null)
718                 {
719                     tlog.Fatal(tag, $"targetView is not null! name={v.Name}");
720                 }
721                 else
722                 {
723                     tlog.Fatal(tag, $"target is something created from dali");
724                 }
725             }
726             VisualEventSignalArgs e = new VisualEventSignalArgs();
727             e.VisualIndex = visualIndex;
728             e.SignalId = signalId;
729             visualEventSignalHandler?.Invoke(this, e);
730
731             tlog.Fatal(tag, $"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
732         }
733
734         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
735         private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
736
737         private VisualEventSignalCallbackType visualEventSignalCallback;
738         private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
739
740         private void debugPrint()
741         {
742             tlog.Fatal(tag, $"===================================");
743             tlog.Fatal(tag, $"<[{GetId()}] get currentStates : url={currentStates.url}, loopCount={currentStates.loopCount}, framePlayRangeMin/Max({currentStates.framePlayRangeMin},{currentStates.framePlayRangeMax}) ");
744             tlog.Fatal(tag, $"  get from Property : StopBehavior={StopBehavior}, LoopMode={LoopingMode}, LoopCount={LoopCount}, PlayState={PlayState} >");
745             tlog.Fatal(tag, $"===================================");
746         }
747         #endregion Private
748     }
749 }