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