Fix components issue 1216 (#1194) (#1201)
[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     // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
33     [EditorBrowsable(EditorBrowsableState.Never)]
34     public class LottieAnimationView : ImageView
35     {
36         #region Constructor, Distructor, Dispose
37         /// <summary>
38         /// LottieAnimationView
39         /// </summary>
40         /// <param name="scale">The factor of scaling image, default : 1.0f</param>
41         /// <param name="shown">false : Not displayed (hidden), true : displayed (shown), default : true</param>
42         /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
43         [EditorBrowsable(EditorBrowsableState.Never)]
44         public LottieAnimationView(float scale = 1.0f, bool shown = true) : base()
45         {
46             tlog.Fatal(tag,  $"< constructor GetId={GetId()} >");
47             currentStates.url = "";
48             currentStates.frame = -1;
49             currentStates.loopCount = 1;
50             currentStates.loopMode = LoopingModeType.Restart;
51             currentStates.stopEndAction = StopBehaviorType.CurrentFrame;
52             currentStates.framePlayRangeMin = -1;
53             currentStates.framePlayRangeMax = -1;
54             currentStates.changed = false;
55             currentStates.totalFrame = -1;
56             currentStates.scale = scale;
57             SetVisible(shown);
58         }
59
60         /// <summary>
61         /// Dispose(DisposeTypes type)
62         /// </summary>
63         /// <param name="type"></param>
64         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
65         [EditorBrowsable(EditorBrowsableState.Never)]
66         protected override void Dispose(DisposeTypes type)
67         {
68             if (disposed)
69             {
70                 return;
71             }
72
73             tlog.Fatal(tag,  $"<[{GetId()}] type={type}");
74
75             //Release your own unmanaged resources here.
76             //You should not access any managed member here except static instance.
77             //because the execution order of Finalizes is non-deterministic.
78
79             //disconnect event signal
80             if (finishedEventHandler != null && visualEventSignalCallback != null)
81             {
82                 VisualEventSignal().Disconnect(visualEventSignalCallback);
83                 finishedEventHandler = null;
84                 tlog.Fatal(tag,  $"disconnect event signal");
85             }
86
87             base.Dispose(type);
88             tlog.Fatal(tag,  $"[{GetId()}]>");
89         }
90         #endregion Constructor, Distructor, Dispose
91
92
93         #region Property
94         /// <summary>
95         /// URL
96         /// </summary>
97         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
98         [EditorBrowsable(EditorBrowsableState.Never)]
99         public string URL
100         {
101             set
102             {
103                 string ret = (value == null ? "" : value);
104                 currentStates.url = ret;
105                 currentStates.changed = true;
106
107                 tlog.Fatal(tag,  $"<[{GetId()}]SET url={currentStates.url}");
108
109                 PropertyMap map = new PropertyMap();
110                 map.Add(Visual.Property.Type, new PropertyValue((int)DevelVisual.Type.AnimatedVectorImage))
111                     .Add(ImageVisualProperty.URL, new PropertyValue(currentStates.url))
112                     .Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount))
113                     .Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction))
114                     .Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
115                 Image = map;
116
117                 currentStates.contentInfo = null;
118
119                 if(currentStates.scale != 1.0f)
120                 {
121                     Scale = new Vector3(currentStates.scale, currentStates.scale, 0.0f);
122                 }
123                 tlog.Fatal(tag,  $"<[{GetId()}]>");
124             }
125             get
126             {
127                 string ret = currentStates.url;
128                 tlog.Fatal(tag,  $"<[{GetId()}] GET");
129
130                 PropertyMap map = Image;
131                 if (map != null)
132                 {
133                     PropertyValue val = map.Find(ImageVisualProperty.URL);
134                     if (val != null)
135                     {
136                         if (val.Get(out ret))
137                         {
138                             tlog.Fatal(tag,  $"gotten url={ret} >");
139                             return ret;
140                         }
141                     }
142                 }
143                 Tizen.Log.Error(tag, $"  [ERROR][{GetId()}](LottieAnimationView) Fail to get URL from dali >");
144                 return ret;
145             }
146         }
147
148         /// <summary>
149         /// The playing state
150         /// </summary>
151         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
152         [EditorBrowsable(EditorBrowsableState.Never)]
153         public PlayStateType PlayState
154         {
155             get
156             {
157                 tlog.Fatal(tag,  $"< Get!");
158                 PropertyMap map = base.Image;
159                 var ret = 0;
160                 if (map != null)
161                 {
162                     PropertyValue val = map.Find(ImageVisualProperty.PlayState);
163                     if (val != null)
164                     {
165                         if (val.Get(out ret))
166                         {
167                             currentStates.playState = (PlayStateType)ret;
168                             tlog.Fatal(tag,  $"gotten play state={ret} >");
169                             return currentStates.playState;
170                         }
171                     }
172                 }
173                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}]Fail to get PlayState from dali currentStates.playState={currentStates.playState}>");
174                 return currentStates.playState;
175             }
176         }
177
178         /// <summary>
179         /// The number of total frame
180         /// </summary>
181         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
182         [EditorBrowsable(EditorBrowsableState.Never)]
183         public int TotalFrame
184         {
185             get
186             {
187                 int ret = -1;
188                 PropertyMap map = Image;
189                 if (map != null)
190                 {
191                     PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
192                     if (val != null)
193                     {
194                         if (val.Get(out ret))
195                         {
196                             //tlog.Fatal(tag,  $"TotalFrameNumber get! ret={ret}");
197                             currentStates.totalFrame = ret;
198                             return ret;
199                         }
200                     }
201                 }
202                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get TotalFrameNumber from dali>");
203                 return ret;
204             }
205         }
206
207         /// <summary>
208         /// CurrentFrameNumber
209         /// </summary>
210         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
211         [EditorBrowsable(EditorBrowsableState.Never)]
212         public int CurrentFrame
213         {
214             set
215             {
216                 currentStates.frame = value;
217                 tlog.Fatal(tag,  $"<[{GetId()}]SET frame={currentStates.frame}>");
218                 DoAction(vectorImageVisualIndex, (int)actionType.jumpTo, new PropertyValue(currentStates.frame));
219             }
220             get
221             {
222                 int ret = 0;
223                 PropertyMap map = Image;
224                 if (map != null)
225                 {
226                     PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
227                     if (val != null)
228                     {
229                         if (val.Get(out ret))
230                         {
231                             //tlog.Fatal(tag,  $"CurrentFrameNumber get! val={ret}");
232                             return ret;
233                         }
234                     }
235                 }
236                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get CurrentFrameNumber from dali!! ret={ret}>");
237                 return ret;
238             }
239         }
240
241         /// <summary>
242         /// Loop Mode of animation.
243         /// </summary>
244         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
245         [EditorBrowsable(EditorBrowsableState.Never)]
246         public LoopingModeType LoopingMode
247         {
248             set
249             {
250                 currentStates.loopMode = (LoopingModeType)value;
251                 currentStates.changed = true;
252
253                 tlog.Fatal(tag,  $"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
254                 PropertyMap map = new PropertyMap();
255                 map.Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
256                 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
257             }
258             get
259             {
260                 //tlog.Fatal(tag,  $"LoopMode get!");
261                 PropertyMap map = base.Image;
262                 var ret = 0;
263                 if (map != null)
264                 {
265                     PropertyValue val = map.Find(ImageVisualProperty.LoopingMode);
266                     if (val != null)
267                     {
268                         if (val.Get(out ret))
269                         {
270                             //tlog.Fatal(tag,  $"gotten LoopMode={ret}");
271                             if (ret != (int)currentStates.loopMode && ret > 0)
272                             {
273                                 tlog.Fatal(tag,  $" [ERROR][{GetId()}](LottieAnimationView) different LoopMode! gotten={ret}, loopMode={currentStates.loopMode}");
274                             }
275                             currentStates.loopMode = (LoopingModeType)ret;
276                             return (LoopingModeType)ret;
277                         }
278                     }
279                 }
280                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get loopMode from dali>");
281                 return currentStates.loopMode;
282             }
283         }
284
285         /// <summary>
286         /// LoopCount
287         /// </summary>
288         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
289         [EditorBrowsable(EditorBrowsableState.Never)]
290         public int LoopCount
291         {
292             set
293             {
294                 currentStates.changed = true;
295                 currentStates.loopCount = value;
296                 tlog.Fatal(tag,  $"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
297                 PropertyMap map = new PropertyMap();
298                 map.Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount));
299                 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
300             }
301             get
302             {
303                 //tlog.Fatal(tag,  $"LoopCount get!");
304                 PropertyMap map = base.Image;
305                 var ret = 0;
306                 if (map != null)
307                 {
308                     PropertyValue val = map.Find(ImageVisualProperty.LoopCount);
309                     if (val != null)
310                     {
311                         if (val.Get(out ret))
312                         {
313                             //tlog.Fatal(tag,  $"gotten loop count={ret}");
314                             if (ret != currentStates.loopCount && ret > 0)
315                             {
316                                 tlog.Fatal(tag,  $"<[ERROR][{GetId()}](LottieAnimationView) different loop count! gotten={ret}, loopCount={currentStates.loopCount}>");
317                             }
318                             currentStates.loopCount = ret;
319                             return currentStates.loopCount;
320                         }
321                     }
322                 }
323                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get LoopCount from dali  currentStates.loopCount={currentStates.loopCount}>");
324                 return currentStates.loopCount;
325             }
326         }
327
328         /// <summary>
329         /// Stop Behavior (Stop End Action)
330         /// </summary>
331         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
332         [EditorBrowsable(EditorBrowsableState.Never)]
333         public StopBehaviorType StopBehavior
334         {
335             set
336             {
337                 currentStates.stopEndAction = (StopBehaviorType)value;
338                 currentStates.changed = true;
339
340                 tlog.Fatal(tag,  $"<[{GetId()}]SET val={currentStates.stopEndAction}>");
341                 PropertyMap map = new PropertyMap();
342                 map.Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction));
343                 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
344             }
345             get
346             {
347                 //tlog.Fatal(tag,  $"StopBehavior get!");
348                 PropertyMap map = base.Image;
349                 var ret = 0;
350                 if (map != null)
351                 {
352                     PropertyValue val = map.Find(ImageVisualProperty.StopBehavior);
353                     if (val != null)
354                     {
355                         if (val.Get(out ret))
356                         {
357                             //tlog.Fatal(tag,  $"gotten StopBehavior={ret}");
358                             if (ret != (int)currentStates.stopEndAction)
359                             {
360                                 tlog.Fatal(tag,  $"<[ERROR][{GetId()}](LottieAnimationView) different StopBehavior! gotten={ret}, StopBehavior={currentStates.stopEndAction}>");
361                             }
362                             currentStates.stopEndAction = (StopBehaviorType)ret;
363                             return (StopBehaviorType)ret;
364                         }
365                     }
366                 }
367                 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get StopBehavior from dali>");
368                 return currentStates.stopEndAction;
369             }
370         }
371         #endregion Property
372
373
374         #region Method
375         /// <summary>
376         /// SetMinMaxFrame(int startFrame, int endFrame)
377         /// </summary>
378         /// <param name="minFrame"></param>
379         /// <param name="maxFrame"></param>
380         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
381         [EditorBrowsable(EditorBrowsableState.Never)]
382         public void SetMinMaxFrame(int minFrame, int maxFrame)
383         {
384             tlog.Fatal(tag,  $"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
385
386             currentStates.changed = true;
387             currentStates.framePlayRangeMin = minFrame;
388             currentStates.framePlayRangeMax = maxFrame;
389
390             PropertyArray array = new PropertyArray();
391             array.PushBack(new PropertyValue(currentStates.framePlayRangeMin));
392             array.PushBack(new PropertyValue(currentStates.framePlayRangeMax));
393
394             PropertyMap map = new PropertyMap();
395             map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
396             DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
397             tlog.Fatal(tag,  $"  [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
398         }
399
400         /// <summary>
401         /// Play Animation.
402         /// </summary>
403         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
404         [EditorBrowsable(EditorBrowsableState.Never)]
405         public new void Play()
406         {
407             tlog.Fatal(tag,  $"<[{GetId()}] Play()");
408             debugPrint();
409             base.Play();
410             tlog.Fatal(tag,  $"[{GetId()}]>");
411         }
412
413         /// <summary>
414         /// Pause Animation.
415         /// </summary>
416         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
417         [EditorBrowsable(EditorBrowsableState.Never)]
418         public new void Pause()
419         {
420             tlog.Fatal(tag,  $"<[{GetId()}] Pause()>");
421             debugPrint();
422             base.Pause();
423             tlog.Fatal(tag,  $"[{GetId()}]>");
424         }
425
426         /// <summary>
427         /// Stop Animation.
428         /// </summary>
429         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
430         [EditorBrowsable(EditorBrowsableState.Never)]
431         public new void Stop()
432         {
433             tlog.Fatal(tag,  $"<[{GetId()}] Stop()");
434             debugPrint();
435             base.Stop();
436             tlog.Fatal(tag,  $"[{GetId()}]>");
437         }
438
439         /// <summary>
440         /// GetContentInfo()
441         /// </summary>
442         /// <returns>list of Tuple (string of layer name, integer of start frame, integer of end frame)</returns>
443         [EditorBrowsable(EditorBrowsableState.Never)]
444         public List<Tuple<string, int, int>> GetContentInfo()
445         {
446             tlog.Fatal(tag, $"<");
447             if(currentStates.contentInfo != null)
448             {
449                 return currentStates.contentInfo;
450             }
451
452             PropertyMap imageMap = base.Image;
453             PropertyMap contentMap = new PropertyMap();
454             if (imageMap != null)
455             {
456                 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
457                 if (val != null)
458                 {
459                     if (val.Get(contentMap))
460                     {
461                         for (uint i = 0; i < contentMap.Count(); i++)
462                         {
463                             string key = contentMap.GetKeyAt(i).StringKey;
464                             PropertyArray arr = new PropertyArray();
465                             contentMap.GetValue(i).Get(arr);
466                             if (arr != null)
467                             {
468                                 int startFrame, endFrame;
469                                 arr.GetElementAt(0).Get(out startFrame);
470                                 arr.GetElementAt(1).Get(out endFrame);
471
472                                 tlog.Fatal(tag, $"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
473
474                                 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame );
475
476                                 currentStates.contentInfo?.Add(item);
477                             }
478                         }
479                     }
480                 }
481             }
482             tlog.Fatal(tag, $">");
483             return currentStates.contentInfo;
484         }
485         #endregion Method
486
487
488         #region Event, Enum, Struct, ETC
489         /// <summary>
490         /// Animation finished event
491         /// </summary>
492         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
493         [EditorBrowsable(EditorBrowsableState.Never)]
494         public event EventHandler Finished
495         {
496             add
497             {
498                 if (finishedEventHandler == null)
499                 {
500                     tlog.Fatal(tag,  $"<[{GetId()}] Finished eventhandler added>");
501                     visualEventSignalCallback = onVisualEventSignal;
502                     VisualEventSignal().Connect(visualEventSignalCallback);
503                 }
504                 finishedEventHandler += value;
505             }
506             remove
507             {
508                 tlog.Fatal(tag,  $"<[{GetId()}] Finished eventhandler removed>");
509                 finishedEventHandler -= value;
510                 if (finishedEventHandler == null && visualEventSignalCallback != null)
511                 {
512                     VisualEventSignal().Disconnect(visualEventSignalCallback);
513                 }
514             }
515         }
516
517         /// <summary>
518         /// Enumeration for what state the vector animation is in
519         /// </summary>
520         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
521         [EditorBrowsable(EditorBrowsableState.Never)]
522         public enum PlayStateType
523         {
524             /// <summary>
525             /// Invalid
526             /// </summary>
527             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
528             [EditorBrowsable(EditorBrowsableState.Never)]
529             Invalid = -1,
530             /// <summary>
531             /// Vector Animation has stopped
532             /// </summary>
533             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
534             [EditorBrowsable(EditorBrowsableState.Never)]
535             Stopped = 0,
536             /// <summary>
537             /// The vector animation is playing
538             /// </summary>
539             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
540             [EditorBrowsable(EditorBrowsableState.Never)]
541             Playing = 1,
542             /// <summary>
543             /// The vector animation is paused
544             /// </summary>
545             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
546             [EditorBrowsable(EditorBrowsableState.Never)]
547             Paused = 2
548         }
549
550         /// <summary>
551         /// @brief Enumeration for what to do when the animation is stopped.
552         /// </summary>
553         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
554         [EditorBrowsable(EditorBrowsableState.Never)]
555         public enum StopBehaviorType
556         {
557             /// <summary>
558             /// When the animation is stopped, the current frame is shown.
559             /// </summary>
560             [EditorBrowsable(EditorBrowsableState.Never)]
561             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
562             CurrentFrame,
563             /// <summary>
564             /// When the animation is stopped, the min frame (first frame) is shown.
565             /// </summary>
566             [EditorBrowsable(EditorBrowsableState.Never)]
567             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
568             MinimumFrame,
569             /// <summary>
570             /// When the animation is stopped, the max frame (last frame) is shown.
571             /// </summary>
572             [EditorBrowsable(EditorBrowsableState.Never)]
573             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
574             MaximumFrame
575         }
576
577         /// <summary>
578         /// @brief Enumeration for what looping mode is in.
579         /// </summary>
580         [EditorBrowsable(EditorBrowsableState.Never)]
581         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
582         public enum LoopingModeType
583         {
584             /// <summary>
585             /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
586             /// </summary>
587             [EditorBrowsable(EditorBrowsableState.Never)]
588             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
589             Restart,
590             /// <summary>
591             /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
592             /// </summary>
593             [EditorBrowsable(EditorBrowsableState.Never)]
594             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
595             AutoReverse
596         }
597         #endregion Event, Enum, Struct, ETC
598
599
600         #region Internal
601         internal class VisualEventSignalArgs : EventArgs
602         {
603             public int VisualIndex
604             {
605                 set;
606                 get;
607             }
608             public int SignalId
609             {
610                 set;
611                 get;
612             }
613         }
614
615         internal event EventHandler<VisualEventSignalArgs> VisualEvent
616         {
617             add
618             {
619                 if (visualEventSignalHandler == null)
620                 {
621                     visualEventSignalCallback = onVisualEventSignal;
622                     VisualEventSignal().Connect(visualEventSignalCallback);
623                 }
624                 visualEventSignalHandler += value;
625             }
626             remove
627             {
628                 visualEventSignalHandler -= value;
629                 if (visualEventSignalHandler == null && VisualEventSignal().Empty() == false)
630                 {
631                     VisualEventSignal().Disconnect(visualEventSignalCallback);
632                 }
633             }
634         }
635
636         internal void EmitVisualEventSignal(int visualIndex, int signalId)
637         {
638             VisualEventSignal().Emit(this, visualIndex, signalId);
639         }
640
641         internal VisualEventSignal VisualEventSignal()
642         {
643             VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
644             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
645             return ret;
646         }
647         #endregion Internal
648
649
650         #region Private
651         private struct states
652         {
653             internal string url;
654             internal int frame;
655             internal int loopCount;
656             internal LoopingModeType loopMode;
657             internal StopBehaviorType stopEndAction;
658             internal int framePlayRangeMin;
659             internal int framePlayRangeMax;
660             internal bool changed;
661             internal int totalFrame;
662             internal float scale;
663             internal PlayStateType playState;
664             internal List<Tuple<string, int, int>> contentInfo;
665         };
666         private states currentStates;
667
668         private enum actionType
669         {
670             play,
671             pause,
672             stop,
673             jumpTo,
674             updateProperty,
675         };
676
677         private struct DevelVisual
678         {
679             internal enum Type
680             {
681                 AnimatedGradient = Visual.Type.AnimatedImage + 1,
682                 AnimatedVectorImage = Visual.Type.AnimatedImage + 2,
683             }
684         }
685
686         private const string tag = "NUITEST";
687         private const int vectorImageVisualIndex = 10000000 + 1000 + 2;
688         private event EventHandler finishedEventHandler;
689
690         private void OnFinished()
691         {
692             tlog.Fatal(tag,  $"<[{GetId()}] OnFinished()>");
693             finishedEventHandler?.Invoke(this, null);
694         }
695
696         private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
697         {
698             OnFinished();
699
700             if (targetView != IntPtr.Zero)
701             {
702                 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
703                 if (v != null)
704                 {
705                     tlog.Fatal(tag,  $"targetView is not null! name={v.Name}");
706                 }
707                 else
708                 {
709                     tlog.Fatal(tag,  $"target is something created from dali");
710                 }
711             }
712             VisualEventSignalArgs e = new VisualEventSignalArgs();
713             e.VisualIndex = visualIndex;
714             e.SignalId = signalId;
715             visualEventSignalHandler?.Invoke(this, e);
716
717             tlog.Fatal(tag,  $"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
718         }
719
720         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
721         private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
722
723         private VisualEventSignalCallbackType visualEventSignalCallback;
724         private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
725
726         private void debugPrint()
727         {
728             tlog.Fatal(tag,  $"===================================");
729             tlog.Fatal(tag,  $"<[{GetId()}] get currentStates : url={currentStates.url}, loopCount={currentStates.loopCount}, framePlayRangeMin/Max({currentStates.framePlayRangeMin},{currentStates.framePlayRangeMax}) ");
730             tlog.Fatal(tag,  $"  get from Property : StopBehavior={StopBehavior}, LoopMode={LoopingMode}, LoopCount={LoopCount}, PlayState={PlayState} >");
731             tlog.Fatal(tag,  $"===================================");
732         }
733         #endregion Private
734     }
735 }