2 * Copyright(c) 2019 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 using global::System.Runtime.InteropServices;
20 using System.ComponentModel;
21 using System.Collections.Generic;
23 namespace Tizen.NUI.BaseComponents
26 using tlog = Tizen.Log;
30 /// LottieAnimationView renders an animated vector image (Lottie file).
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
36 #region Constructor, Distructor, Dispose
38 /// LottieAnimationView
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()
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;
61 /// Dispose(DisposeTypes type)
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)
73 tlog.Fatal(tag, $"<[{GetId()}] type={type}");
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.
79 //disconnect event signal
80 if (finishedEventHandler != null && visualEventSignalCallback != null)
82 VisualEventSignal().Disconnect(visualEventSignalCallback);
83 finishedEventHandler = null;
84 tlog.Fatal(tag, $"disconnect event signal");
88 tlog.Fatal(tag, $"[{GetId()}]>");
90 #endregion Constructor, Distructor, Dispose
97 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
98 [EditorBrowsable(EditorBrowsableState.Never)]
103 string ret = (value == null ? "" : value);
104 currentStates.url = ret;
105 currentStates.changed = true;
107 tlog.Fatal(tag, $"<[{GetId()}]SET url={currentStates.url}");
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));
117 currentStates.contentInfo = null;
119 if(currentStates.scale != 1.0f)
121 Scale = new Vector3(currentStates.scale, currentStates.scale, 0.0f);
123 tlog.Fatal(tag, $"<[{GetId()}]>");
127 string ret = currentStates.url;
128 tlog.Fatal(tag, $"<[{GetId()}] GET");
130 PropertyMap map = Image;
133 PropertyValue val = map.Find(ImageVisualProperty.URL);
136 if (val.Get(out ret))
138 tlog.Fatal(tag, $"gotten url={ret} >");
143 Tizen.Log.Error(tag, $" [ERROR][{GetId()}](LottieAnimationView) Fail to get URL from dali >");
149 /// The playing state
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
157 tlog.Fatal(tag, $"< Get!");
158 PropertyMap map = base.Image;
162 PropertyValue val = map.Find(ImageVisualProperty.PlayState);
165 if (val.Get(out ret))
167 currentStates.playState = (PlayStateType)ret;
168 tlog.Fatal(tag, $"gotten play state={ret} >");
174 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}]Fail to get PlayState from dali currentStates.playState={currentStates.playState}>");
176 return currentStates.playState;
181 /// The number of total frame
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
190 PropertyMap map = Image;
193 PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
196 if (val.Get(out ret))
198 //tlog.Fatal(tag, $"TotalFrameNumber get! ret={ret}");
199 currentStates.totalFrame = ret;
204 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get TotalFrameNumber from dali>");
210 /// CurrentFrameNumber
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
218 currentStates.frame = value;
219 tlog.Fatal(tag, $"<[{GetId()}]SET frame={currentStates.frame}>");
220 DoAction(vectorImageVisualIndex, (int)actionType.jumpTo, new PropertyValue(currentStates.frame));
225 PropertyMap map = Image;
228 PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
231 if (val.Get(out ret))
233 //tlog.Fatal(tag, $"CurrentFrameNumber get! val={ret}");
238 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get CurrentFrameNumber from dali!! ret={ret}>");
244 /// Loop Mode of animation.
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
252 currentStates.loopMode = (LoopingModeType)value;
253 currentStates.changed = true;
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));
262 //tlog.Fatal(tag, $"LoopMode get!");
263 PropertyMap map = base.Image;
267 PropertyValue val = map.Find(ImageVisualProperty.LoopingMode);
270 if (val.Get(out ret))
272 //tlog.Fatal(tag, $"gotten LoopMode={ret}");
273 if (ret != (int)currentStates.loopMode && ret > 0)
275 tlog.Fatal(tag, $" [ERROR][{GetId()}](LottieAnimationView) different LoopMode! gotten={ret}, loopMode={currentStates.loopMode}");
277 currentStates.loopMode = (LoopingModeType)ret;
278 return (LoopingModeType)ret;
282 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get loopMode from dali>");
283 return currentStates.loopMode;
290 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
291 [EditorBrowsable(EditorBrowsableState.Never)]
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));
305 //tlog.Fatal(tag, $"LoopCount get!");
306 PropertyMap map = base.Image;
310 PropertyValue val = map.Find(ImageVisualProperty.LoopCount);
313 if (val.Get(out ret))
315 //tlog.Fatal(tag, $"gotten loop count={ret}");
316 if (ret != currentStates.loopCount && ret > 0)
318 tlog.Fatal(tag, $"<[ERROR][{GetId()}](LottieAnimationView) different loop count! gotten={ret}, loopCount={currentStates.loopCount}>");
320 currentStates.loopCount = ret;
321 return currentStates.loopCount;
325 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get LoopCount from dali currentStates.loopCount={currentStates.loopCount}>");
326 return currentStates.loopCount;
331 /// Stop Behavior (Stop End Action)
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
339 currentStates.stopEndAction = (StopBehaviorType)value;
340 currentStates.changed = true;
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));
349 //tlog.Fatal(tag, $"StopBehavior get!");
350 PropertyMap map = base.Image;
354 PropertyValue val = map.Find(ImageVisualProperty.StopBehavior);
357 if (val.Get(out ret))
359 //tlog.Fatal(tag, $"gotten StopBehavior={ret}");
360 if (ret != (int)currentStates.stopEndAction)
362 tlog.Fatal(tag, $"<[ERROR][{GetId()}](LottieAnimationView) different StopBehavior! gotten={ret}, StopBehavior={currentStates.stopEndAction}>");
364 currentStates.stopEndAction = (StopBehaviorType)ret;
365 return (StopBehaviorType)ret;
369 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get StopBehavior from dali>");
370 return currentStates.stopEndAction;
378 /// SetMinMaxFrame(int startFrame, int endFrame)
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)
386 tlog.Fatal(tag, $"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
388 currentStates.changed = true;
389 currentStates.framePlayRangeMin = minFrame;
390 currentStates.framePlayRangeMax = maxFrame;
392 PropertyArray array = new PropertyArray();
393 array.PushBack(new PropertyValue(currentStates.framePlayRangeMin));
394 array.PushBack(new PropertyValue(currentStates.framePlayRangeMax));
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})>");
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()
409 tlog.Fatal(tag, $"<[{GetId()}] Play()");
412 tlog.Fatal(tag, $"[{GetId()}]>");
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()
422 tlog.Fatal(tag, $"<[{GetId()}] Pause()>");
425 tlog.Fatal(tag, $"[{GetId()}]>");
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()
435 tlog.Fatal(tag, $"<[{GetId()}] Stop()");
438 tlog.Fatal(tag, $"[{GetId()}]>");
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()
448 tlog.Fatal(tag, $"<");
449 if(currentStates.contentInfo != null)
451 return currentStates.contentInfo;
454 PropertyMap imageMap = base.Image;
455 PropertyMap contentMap = new PropertyMap();
456 if (imageMap != null)
458 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
461 if (val.Get(contentMap))
463 currentStates.contentInfo = new List<Tuple<string, int, int>>();
464 for (uint i = 0; i < contentMap.Count(); i++)
466 string key = contentMap.GetKeyAt(i).StringKey;
467 PropertyArray arr = new PropertyArray();
468 contentMap.GetValue(i).Get(arr);
471 int startFrame, endFrame;
472 arr.GetElementAt(0).Get(out startFrame);
473 arr.GetElementAt(1).Get(out endFrame);
475 tlog.Fatal(tag, $"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
477 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame );
479 currentStates.contentInfo?.Add(item);
485 tlog.Fatal(tag, $">");
486 return currentStates.contentInfo;
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. *
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)
500 tlog.Fatal(tag, $"< [{GetId()}] SetMinMaxFrameByMarker({marker1}, {marker2})");
502 currentStates.changed = true;
503 currentStates.mark1 = marker1;
504 currentStates.mark2 = marker2;
506 PropertyArray array = new PropertyArray();
507 array.PushBack(new PropertyValue(currentStates.mark1));
510 array.PushBack(new PropertyValue(currentStates.mark2));
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} >");
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()
527 tlog.Fatal(tag, $"< [{GetId()}] GetMinMaxFrame()! total frame={currentStates.totalFrame}");
529 PropertyMap map = Image;
532 PropertyValue val = map.Find(ImageVisualProperty.PlayRange);
535 PropertyArray array = new PropertyArray();
538 uint cnt = array.Count();
539 int item1 = -1, item2 = -1;
540 for (uint i = 0; i < cnt; i++)
542 PropertyValue v = array.GetElementAt(i);
544 if (v.Get(out intRet))
546 tlog.Fatal(tag, $"Got play range of string [{i}]: {intRet}");
558 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#1");
561 tlog.Fatal(tag, $" [{GetId()}] GetMinMaxFrame(min:{item1}, max:{item2})! >");
562 return new Tuple<int, int>(item1, item2);
566 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#2");
567 return new Tuple<int, int>(-1, -1);
572 #region Event, Enum, Struct, ETC
574 /// Animation finished event
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
582 if (finishedEventHandler == null)
584 tlog.Fatal(tag, $"<[{GetId()}] Finished eventhandler added>");
585 visualEventSignalCallback = onVisualEventSignal;
586 VisualEventSignal().Connect(visualEventSignalCallback);
588 finishedEventHandler += value;
592 tlog.Fatal(tag, $"<[{GetId()}] Finished eventhandler removed>");
593 finishedEventHandler -= value;
594 if (finishedEventHandler == null && visualEventSignalCallback != null)
596 VisualEventSignal().Disconnect(visualEventSignalCallback);
602 /// Enumeration for what state the vector animation is in
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
611 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
612 [EditorBrowsable(EditorBrowsableState.Never)]
615 /// Vector Animation has stopped
617 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
618 [EditorBrowsable(EditorBrowsableState.Never)]
621 /// The vector animation is playing
623 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
624 [EditorBrowsable(EditorBrowsableState.Never)]
627 /// The vector animation is paused
629 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
630 [EditorBrowsable(EditorBrowsableState.Never)]
635 /// @brief Enumeration for what to do when the animation is stopped.
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
642 /// When the animation is stopped, the current frame is shown.
644 [EditorBrowsable(EditorBrowsableState.Never)]
645 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
648 /// When the animation is stopped, the min frame (first frame) is shown.
650 [EditorBrowsable(EditorBrowsableState.Never)]
651 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
654 /// When the animation is stopped, the max frame (last frame) is shown.
656 [EditorBrowsable(EditorBrowsableState.Never)]
657 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
662 /// @brief Enumeration for what looping mode is in.
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
669 /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
671 [EditorBrowsable(EditorBrowsableState.Never)]
672 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
675 /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
677 [EditorBrowsable(EditorBrowsableState.Never)]
678 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
681 #endregion Event, Enum, Struct, ETC
685 internal class VisualEventSignalArgs : EventArgs
687 public int VisualIndex
699 internal event EventHandler<VisualEventSignalArgs> VisualEvent
703 if (visualEventSignalHandler == null)
705 visualEventSignalCallback = onVisualEventSignal;
706 VisualEventSignal().Connect(visualEventSignalCallback);
708 visualEventSignalHandler += value;
712 visualEventSignalHandler -= value;
713 if (visualEventSignalHandler == null && VisualEventSignal().Empty() == false)
715 VisualEventSignal().Disconnect(visualEventSignalCallback);
720 internal void EmitVisualEventSignal(int visualIndex, int signalId)
722 VisualEventSignal().Emit(this, visualIndex, signalId);
725 internal VisualEventSignal VisualEventSignal()
727 VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
728 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
735 private struct states
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;
751 private states currentStates;
753 private enum actionType
762 private struct DevelVisual
766 AnimatedGradient = Visual.Type.AnimatedImage + 1,
767 AnimatedVectorImage = Visual.Type.AnimatedImage + 2,
771 private const string tag = "NUITEST";
772 private const int vectorImageVisualIndex = 10000000 + 1000 + 2;
773 private event EventHandler finishedEventHandler;
775 private void OnFinished()
777 tlog.Fatal(tag, $"<[{GetId()}] OnFinished()>");
778 finishedEventHandler?.Invoke(this, null);
781 private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
785 if (targetView != IntPtr.Zero)
787 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
790 tlog.Fatal(tag, $"targetView is not null! name={v.Name}");
794 tlog.Fatal(tag, $"target is something created from dali");
797 VisualEventSignalArgs e = new VisualEventSignalArgs();
798 e.VisualIndex = visualIndex;
799 e.SignalId = signalId;
800 visualEventSignalHandler?.Invoke(this, e);
802 tlog.Fatal(tag, $"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
805 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
806 private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
808 private VisualEventSignalCallbackType visualEventSignalCallback;
809 private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
811 private void debugPrint()
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, $"===================================");