2 * Copyright(c) 2020 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;
22 using System.Globalization;
24 namespace Tizen.NUI.BaseComponents
27 /// LottieAnimationView renders an animated vector image (Lottie file).
29 /// <since_tizen> 7 </since_tizen>
30 public partial class LottieAnimationView : ImageView
33 #region Constructor, Destructor, Dispose
35 /// LottieAnimationView constructor
37 /// <param name="scale">The factor of scaling image, default : 1.0f</param>
38 /// <param name="shown">false : not displayed (hidden), true : displayed (shown), default : true</param>
40 /// If the shown parameter is false, the animation is not visible even if the LottieAnimationView instance is created.
44 /// LottieAnimationView myLottie = new LottieAnimationView();
45 /// LottieAnimationView myLottie2 = new LottieAnimationView(2.0f);
46 /// LottieAnimationView myLottie3 = new LottieAnimationView(1.0f, false);
49 /// <since_tizen> 7 </since_tizen>
50 public LottieAnimationView(float scale = 1.0f, bool shown = true) : base()
52 ActionPlay = Interop.LottieAnimationView.AnimatedVectorImageVisualActionPlayGet();
53 ActionPause = Interop.LottieAnimationView.AnimatedVectorImageVisualActionPauseGet();
54 ActionStop = Interop.LottieAnimationView.AnimatedVectorImageVisualActionStopGet();
56 NUILog.Debug($"< constructor GetId={GetId()} >");
57 currentStates.url = "";
58 currentStates.loopCount = 1;
59 currentStates.loopMode = LoopingModeType.Restart;
60 currentStates.stopEndAction = StopBehaviorType.CurrentFrame;
61 currentStates.framePlayRangeMin = -1;
62 currentStates.framePlayRangeMax = -1;
63 currentStates.changed = false;
64 currentStates.totalFrame = -1;
65 currentStates.scale = scale;
66 currentStates.redrawInScalingDown = true;
71 /// Dispose(DisposeTypes type)
73 /// <param name="type"></param>
74 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
75 [EditorBrowsable(EditorBrowsableState.Never)]
76 protected override void Dispose(DisposeTypes type)
83 CleanCallbackDictionaries();
85 //Release your own unmanaged resources here.
86 //You should not access any managed member here except static instance.
87 //because the execution order of Finalizes is non-deterministic.
89 //disconnect event signal
90 if (finishedEventHandler != null && visualEventSignalCallback != null)
92 using VisualEventSignal visualEvent = VisualEventSignal();
93 visualEvent.Disconnect(visualEventSignalCallback);
94 finishedEventHandler = null;
95 NUILog.Debug($"disconnect event signal");
101 // This is used for internal purpose. hidden API.
102 [EditorBrowsable(EditorBrowsableState.Never)]
103 protected override void Dispose(bool disposing)
105 // Note : We can clean dictionaries even this API called from GC Thread.
106 CleanCallbackDictionaries();
107 base.Dispose(disposing);
109 #endregion Constructor, Destructor, Dispose
114 /// Set or Get resource URL of Lottie file.
116 /// <since_tizen> 7 </since_tizen>
121 return GetValue(URLProperty) as string;
125 SetValue(URLProperty, value);
126 NotifyPropertyChanged();
130 private string InternalURL
134 string ret = (value == null ? "" : value);
135 currentStates.url = ret;
136 currentStates.changed = true;
137 currentStates.totalFrame = -1; // Reset cached totalFrame value;
138 currentStates.enableFrameCache = false;
140 NUILog.Debug($"<[{GetId()}]SET url={currentStates.url}");
142 // TODO : Could create new Image without additional creation?
143 using PropertyMap map = new PropertyMap();
144 using PropertyValue type = new PropertyValue((int)DevelVisual.Type.AnimatedVectorImage);
145 using PropertyValue url = new PropertyValue(currentStates.url);
146 using PropertyValue loopCnt = new PropertyValue(currentStates.loopCount);
147 using PropertyValue stopAction = new PropertyValue((int)currentStates.stopEndAction);
148 using PropertyValue loopMode = new PropertyValue((int)currentStates.loopMode);
150 map.Add(Visual.Property.Type, type)
151 .Add(ImageVisualProperty.URL, url)
152 .Add(ImageVisualProperty.LoopCount, loopCnt)
153 .Add(ImageVisualProperty.StopBehavior, stopAction)
154 .Add(ImageVisualProperty.LoopingMode, loopMode);
157 currentStates.contentInfo = null;
159 if (currentStates.scale != 1.0f)
161 Scale = new Vector3(currentStates.scale, currentStates.scale, currentStates.scale);
163 NUILog.Debug($"<[{GetId()}]>");
167 string ret = currentStates.url;
168 NUILog.Debug($"<[{GetId()}] GET");
169 NUILog.Debug($"gotten url={ret} >");
175 /// Gets the playing state
177 /// <since_tizen> 7 </since_tizen>
178 public PlayStateType PlayState
182 NUILog.Debug($"< Get!");
185 Interop.View.InternalRetrievingVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.PlayState, out ret);
187 currentStates.playState = (PlayStateType)ret;
188 NUILog.Debug($"gotten play state={currentStates.playState} >");
190 return currentStates.playState;
195 /// Get the number of total frames
197 /// <since_tizen> 7 </since_tizen>
198 public int TotalFrame
202 int ret = currentStates.totalFrame;
205 Interop.View.InternalRetrievingVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.TotalFrameNumber, out ret);
207 currentStates.totalFrame = ret;
208 NUILog.Debug($"TotalFrameNumber get! ret={ret}");
212 Tizen.Log.Error("NUI", $"Fail to get TotalFrame. Maybe file is not loaded yet, or invalid url used. url : {currentStates.url}\n");
220 /// Set or get the current frame. When setting a specific frame, it is displayed as a still image.
223 /// Gets the value set by a user. If the setting value is out-ranged, it is reset as a minimum frame or a maximum frame.
226 /// We assume that the animation in myLottie.json file has 100 frames originally. If so, its frame index will be 0 - 99.
228 /// LottieAnimationView myLottie = new LottieAnimationView();
229 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
230 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
231 /// myLottie.CurrentFrame = 200; //display 99 frame
232 /// myLottie.SetMinMaxFrame(10, 20);
233 /// myLottie.CurrentFrame = 15; //display 15 frame
234 /// myLottie.CurrentFrame = 50; //display 20 frame, because the MinMax is set (10,20) above
237 /// <since_tizen> 7 </since_tizen>
238 public int CurrentFrame
242 return (int)GetValue(CurrentFrameProperty);
246 SetValue(CurrentFrameProperty, value);
247 NotifyPropertyChanged();
251 private int InternalCurrentFrame
255 NUILog.Debug($"<[{GetId()}]SET frame={value}>");
257 Interop.View.DoActionWithSingleIntAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionJumpTo, value);
263 Interop.View.InternalRetrievingVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.CurrentFrameNumber, out ret);
265 NUILog.Debug($"CurrentFrameNumber get! val={ret}");
271 /// Sets or gets the looping mode of Lottie animation.
273 /// <since_tizen> 7 </since_tizen>
274 public LoopingModeType LoopingMode
278 return (LoopingModeType)GetValue(LoopingModeProperty);
282 SetValue(LoopingModeProperty, value);
283 NotifyPropertyChanged();
287 private LoopingModeType InternalLoopingMode
291 if (currentStates.loopMode != (LoopingModeType)value)
293 currentStates.changed = true;
294 currentStates.loopMode = (LoopingModeType)value;
296 NUILog.Debug($"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
298 Interop.View.InternalUpdateVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.LoopingMode, (int)currentStates.loopMode);
303 NUILog.Debug($"LoopMode get! {currentStates.loopMode}");
304 return currentStates.loopMode;
309 /// Sets or gets the loop count.
312 /// The minus value means the infinite loop count.
316 /// LottieAnimationView myLottie = new LottieAnimationView();
317 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
318 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
319 /// myLottie.LoopCount = -1; //infinite loop
321 /// myLottie.Stop(); //it plays continuously unless Stop() is called
322 /// myLottie.LoopCount = 2;
323 /// myLottie.Play(); //it plays only 2 times and stops automatically
326 /// <since_tizen> 7 </since_tizen>
331 return (int)GetValue(LoopCountProperty);
335 SetValue(LoopCountProperty, value);
336 NotifyPropertyChanged();
340 private int InternalLoopCount
344 if (currentStates.loopCount != value)
346 currentStates.changed = true;
347 currentStates.loopCount = value;
349 NUILog.Debug($"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
351 Interop.View.InternalUpdateVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.LoopCount, currentStates.loopCount);
356 NUILog.Debug($"LoopCount get! {currentStates.loopCount}");
357 return currentStates.loopCount;
362 /// Sets or gets the stop behavior.
364 /// <since_tizen> 7 </since_tizen>
365 public StopBehaviorType StopBehavior
369 return (StopBehaviorType)GetValue(StopBehaviorProperty);
373 SetValue(StopBehaviorProperty, value);
374 NotifyPropertyChanged();
378 private StopBehaviorType InternalStopBehavior
382 if (currentStates.stopEndAction != (StopBehaviorType)value)
384 currentStates.changed = true;
385 currentStates.stopEndAction = (StopBehaviorType)value;
387 NUILog.Debug($"<[{GetId()}]SET val={currentStates.stopEndAction}>");
389 Interop.View.InternalUpdateVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.StopBehavior, (int)currentStates.stopEndAction);
394 NUILog.Debug($"StopBehavior get! {currentStates.stopEndAction}");
395 return currentStates.stopEndAction;
400 /// Whether to redraw the image when the visual is scaled down.
404 /// It is used in the AnimatedVectorImageVisual.The default is true.
406 [EditorBrowsable(EditorBrowsableState.Never)]
407 public bool RedrawInScalingDown
411 return (bool)GetValue(RedrawInScalingDownProperty);
415 SetValue(RedrawInScalingDownProperty, value);
416 NotifyPropertyChanged();
420 private bool InternalRedrawInScalingDown
424 if (currentStates.redrawInScalingDown != value)
426 currentStates.changed = true;
427 currentStates.redrawInScalingDown = value;
429 NUILog.Debug($"<[{GetId()}]SET currentStates.redrawInScalingDown={currentStates.redrawInScalingDown}>");
431 Interop.View.InternalUpdateVisualPropertyBool(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.RedrawInScalingDown, currentStates.redrawInScalingDown);
436 NUILog.Debug($"RedrawInScalingDown get! {currentStates.redrawInScalingDown}");
437 return currentStates.redrawInScalingDown;
443 /// Actions property value to Jump to the specified frame.
444 /// This property can be redefined by child class if it use different value.
446 [EditorBrowsable(EditorBrowsableState.Never)]
447 protected int ActionJumpTo { get; set; } = Interop.LottieAnimationView.AnimatedVectorImageVisualActionJumpToGet();
449 // This is used for internal purpose. hidden API.
450 [EditorBrowsable(EditorBrowsableState.Never)]
451 protected int SetDynamicProperty => ActionJumpTo + 1;
452 [EditorBrowsable(EditorBrowsableState.Never)]
453 public bool EnableFrameCache
457 return (bool)GetValue(EnableFrameCacheProperty);
461 SetValue(EnableFrameCacheProperty, value);
462 NotifyPropertyChanged();
466 private bool InternalEnableFrameCache
470 if (currentStates.enableFrameCache != value)
472 currentStates.changed = true;
473 currentStates.enableFrameCache = value;
475 NUILog.Debug($"<[{GetId()}]SET currentStates.EnableFrameCache={currentStates.enableFrameCache}>");
477 Interop.View.InternalUpdateVisualPropertyBool(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.EnableFrameCache, currentStates.enableFrameCache);
482 NUILog.Debug($"EnableFrameCache get! {currentStates.enableFrameCache}");
483 return currentStates.enableFrameCache;
491 /// Set the minimum and the maximum frame.
493 /// <param name="minFrame">minimum frame</param>
494 /// <param name="maxFrame">maximum frame</param>
495 /// <since_tizen> 7 </since_tizen>
496 public void SetMinMaxFrame(int minFrame, int maxFrame)
498 if (currentStates.framePlayRangeMin != minFrame || currentStates.framePlayRangeMax != maxFrame)
500 NUILog.Debug($"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
501 currentStates.changed = true;
502 currentStates.framePlayRangeMin = minFrame;
503 currentStates.framePlayRangeMax = maxFrame;
505 Interop.View.InternalUpdateVisualPropertyIntPair(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.PlayRange, currentStates.framePlayRangeMin, currentStates.framePlayRangeMax);
507 NUILog.Debug($" [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
514 /// <since_tizen> 7 </since_tizen>
515 public new void Play()
517 NUILog.Debug($"<[{GetId()}] Play()");
520 NUILog.Debug($"[{GetId()}]>");
526 /// <since_tizen> 7 </since_tizen>
527 public new void Pause()
529 NUILog.Debug($"<[{GetId()}] Pause()>");
532 NUILog.Debug($"[{GetId()}]>");
538 /// <since_tizen> 7 </since_tizen>
539 public new void Stop()
541 NUILog.Debug($"<[{GetId()}] Stop()");
544 NUILog.Debug($"[{GetId()}]>");
548 /// Get the list of layers' information such as the start frame and the end frame in the Lottie file.
550 /// <returns>List of Tuple (string of layer name, integer of start frame, integer of end frame)</returns>
551 /// <since_tizen> 7 </since_tizen>
552 public List<Tuple<string, int, int>> GetContentInfo()
554 if (currentStates.contentInfo != null)
556 return currentStates.contentInfo;
561 PropertyMap imageMap = base.Image;
562 if (imageMap != null)
564 if (TotalFrame > 0) // Check whether image file loaded successfuly.
566 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
567 PropertyMap contentMap = new PropertyMap();
568 if (val?.Get(ref contentMap) == true)
570 currentStates.contentInfo = new List<Tuple<string, int, int>>();
571 for (uint i = 0; i < contentMap.Count(); i++)
573 using PropertyKey propertyKey = contentMap.GetKeyAt(i);
574 string key = propertyKey.StringKey;
576 using PropertyValue arrVal = contentMap.GetValue(i);
577 using PropertyArray arr = new PropertyArray();
581 using PropertyValue start = arr.GetElementAt(0);
582 start?.Get(out startFrame);
585 using PropertyValue end = arr.GetElementAt(1);
586 end?.Get(out endFrame);
588 NUILog.Debug($"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
590 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
592 currentStates.contentInfo?.Add(item);
596 contentMap.Dispose();
602 return currentStates.contentInfo;
606 /// Get the list of markers' information such as the start frame and the end frame in the Lottie file.
608 /// <returns>List of Tuple (string of marker name, integer of start frame, integer of end frame)</returns>
609 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
610 [EditorBrowsable(EditorBrowsableState.Never)]
611 public List<Tuple<string, int, int>> GetMarkerInfo()
613 if (currentStates.markerInfo != null)
615 return currentStates.markerInfo;
620 PropertyMap imageMap = base.Image;
621 if (imageMap != null)
623 if (TotalFrame > 0) // Check whether image file loaded successfuly.
625 PropertyValue val = imageMap.Find(ImageVisualProperty.MarkerInfo);
626 PropertyMap markerMap = new PropertyMap();
627 if (val?.Get(ref markerMap) == true)
629 currentStates.markerInfo = new List<Tuple<string, int, int>>();
630 for (uint i = 0; i < markerMap.Count(); i++)
632 using PropertyKey propertyKey = markerMap.GetKeyAt(i);
633 string key = propertyKey.StringKey;
635 using PropertyValue arrVal = markerMap.GetValue(i);
636 using PropertyArray arr = new PropertyArray();
640 using PropertyValue start = arr.GetElementAt(0);
641 start?.Get(out startFrame);
644 using PropertyValue end = arr.GetElementAt(1);
645 end?.Get(out endFrame);
647 NUILog.Debug($"[{i}] marker name={key}, startFrame={startFrame}, endFrame={endFrame}");
649 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
651 currentStates.markerInfo?.Add(item);
661 return currentStates.markerInfo;
665 /// A marker has its start frame and end frame.
666 /// Animation will play between the start frame and the end frame of the marker if one marker is specified.
667 /// 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. *
669 /// <param name="marker1">First marker</param>
670 /// <param name="marker2">Second marker</param>
671 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
672 [EditorBrowsable(EditorBrowsableState.Never)]
673 public void SetMinMaxFrameByMarker(string marker1, string marker2 = null)
675 if (currentStates.mark1 != marker1 || currentStates.mark2 != marker2)
677 NUILog.Debug($"< [{GetId()}] SetMinMaxFrameByMarker({marker1}, {marker2})");
679 currentStates.changed = true;
680 currentStates.mark1 = marker1;
681 currentStates.mark2 = marker2;
683 if (string.IsNullOrEmpty(currentStates.mark2))
685 Interop.View.InternalUpdateVisualPropertyString(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.PlayRange, currentStates.mark1);
689 Interop.View.InternalUpdateVisualPropertyStringPair(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.PlayRange, currentStates.mark1, currentStates.mark2);
692 NUILog.Debug($" [{GetId()}] currentStates.mark1:{currentStates.mark1}, mark2:{currentStates.mark2} >");
699 /// <returns>Tuple of Min and Max frames</returns>
700 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
701 [EditorBrowsable(EditorBrowsableState.Never)]
702 public Tuple<int, int> GetMinMaxFrame()
704 NUILog.Debug($"< [{GetId()}] GetMinMaxFrame()! total frame={currentStates.totalFrame}");
706 using PropertyMap map = Image;
709 using PropertyValue val = map.Find(ImageVisualProperty.PlayRange);
712 using PropertyArray array = new PropertyArray();
715 uint cnt = array.Count();
716 int item1 = -1, item2 = -1;
717 for (uint i = 0; i < cnt; i++)
719 using PropertyValue v = array.GetElementAt(i);
721 if (v.Get(out intRet))
723 NUILog.Debug($"Got play range of string [{i}]: {intRet}");
735 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#1");
738 NUILog.Debug($" [{GetId()}] GetMinMaxFrame(min:{item1}, max:{item2})! >");
739 return new Tuple<int, int>(item1, item2);
743 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#2");
744 return new Tuple<int, int>(-1, -1);
747 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
748 [EditorBrowsable(EditorBrowsableState.Never)]
749 public void DoActionExtension(LottieAnimationViewDynamicProperty info)
751 dynamicPropertyCallbackId++;
753 weakReferencesOfLottie?.Add(dynamicPropertyCallbackId, new WeakReference<LottieAnimationView>(this));
754 InternalSavedDynamicPropertyCallbacks?.Add(dynamicPropertyCallbackId, info.Callback);
756 Interop.View.DoActionExtension(SwigCPtr, ImageView.Property.IMAGE, SetDynamicProperty, dynamicPropertyCallbackId, info.KeyPath, (int)info.Property, Marshal.GetFunctionPointerForDelegate<System.Delegate>(rootCallback));
758 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
761 private void CleanCallbackDictionaries()
763 if (weakReferencesOfLottie?.Count > 0 && InternalSavedDynamicPropertyCallbacks != null)
765 foreach (var key in InternalSavedDynamicPropertyCallbacks?.Keys)
767 if (weakReferencesOfLottie.ContainsKey(key))
769 weakReferencesOfLottie.Remove(key);
773 InternalSavedDynamicPropertyCallbacks?.Clear();
774 InternalSavedDynamicPropertyCallbacks = null;
779 #region Event, Enum, Struct, ETC
781 /// Animation finished event.
783 /// <since_tizen> 7 </since_tizen>
784 public event EventHandler Finished
788 if (finishedEventHandler == null)
790 NUILog.Debug($"<[{GetId()}] Finished eventhandler added>");
791 visualEventSignalCallback = onVisualEventSignal;
792 using VisualEventSignal visualEvent = VisualEventSignal();
793 visualEvent.Connect(visualEventSignalCallback);
795 finishedEventHandler += value;
799 NUILog.Debug($"<[{GetId()}] Finished eventhandler removed>");
800 finishedEventHandler -= value;
801 if (finishedEventHandler == null && visualEventSignalCallback != null)
803 using VisualEventSignal visualEvent = VisualEventSignal();
804 visualEvent.Disconnect(visualEventSignalCallback);
805 if (visualEvent?.Empty() == true)
807 visualEventSignalCallback = null;
814 /// Enumeration for what state the vector animation is in
816 /// <since_tizen> 7 </since_tizen>
817 public enum PlayStateType
822 /// <since_tizen> 7 </since_tizen>
825 /// Vector Animation has stopped
827 /// <since_tizen> 7 </since_tizen>
830 /// The vector animation is playing
832 /// <since_tizen> 7 </since_tizen>
835 /// The vector animation is paused
837 /// <since_tizen> 7 </since_tizen>
842 /// Enumeration for what to do when the animation is stopped.
844 /// <since_tizen> 7 </since_tizen>
845 public enum StopBehaviorType
848 /// When the animation is stopped, the current frame is shown.
850 /// <since_tizen> 7 </since_tizen>
853 /// When the animation is stopped, the min frame (first frame) is shown.
855 /// <since_tizen> 7 </since_tizen>
858 /// When the animation is stopped, the max frame (last frame) is shown.
860 /// <since_tizen> 7 </since_tizen>
865 /// Enumeration for what looping mode is in.
867 /// <since_tizen> 7 </since_tizen>
868 public enum LoopingModeType
871 /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
873 /// <since_tizen> 7 </since_tizen>
876 /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
878 /// <since_tizen> 7 </since_tizen>
885 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
886 [EditorBrowsable(EditorBrowsableState.Never)]
887 public enum VectorProperty
890 /// Fill color of the object, Type of <see cref="Vector3"/>
892 [EditorBrowsable(EditorBrowsableState.Never)]
896 /// Fill opacity of the object, Type of float
898 [EditorBrowsable(EditorBrowsableState.Never)]
902 /// Stroke color of the object, Type of <see cref="Vector3"/>
904 [EditorBrowsable(EditorBrowsableState.Never)]
908 /// Stroke opacity of the object, Type of float
910 [EditorBrowsable(EditorBrowsableState.Never)]
914 /// Stroke width of the object, Type of float
916 [EditorBrowsable(EditorBrowsableState.Never)]
920 /// Transform anchor of the Layer and Group object, Type of <see cref="Vector2"/>
922 [EditorBrowsable(EditorBrowsableState.Never)]
926 /// Transform position of the Layer and Group object, Type of <see cref="Vector2"/>
928 [EditorBrowsable(EditorBrowsableState.Never)]
932 /// Transform scale of the Layer and Group object, Type of <see cref="Vector2"/>, Value range of [0..100]
934 [EditorBrowsable(EditorBrowsableState.Never)]
938 /// Transform rotation of the Layer and Group object, Type of float, Value range of [0..360] in degrees
940 [EditorBrowsable(EditorBrowsableState.Never)]
944 /// Transform opacity of the Layer and Group object, Type of float
946 [EditorBrowsable(EditorBrowsableState.Never)]
950 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
951 [EditorBrowsable(EditorBrowsableState.Never)]
952 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
953 public delegate PropertyValue DynamicPropertyCallbackType(int returnType, uint frameNumber);
954 #endregion Event, Enum, Struct, ETC
958 internal class VisualEventSignalArgs : EventArgs
960 public int VisualIndex
972 internal event EventHandler<VisualEventSignalArgs> VisualEvent
976 if (visualEventSignalHandler == null)
978 visualEventSignalCallback = onVisualEventSignal;
979 using VisualEventSignal visualEvent = VisualEventSignal();
980 visualEvent?.Connect(visualEventSignalCallback);
982 visualEventSignalHandler += value;
986 visualEventSignalHandler -= value;
987 if (visualEventSignalHandler == null && visualEventSignalCallback != null)
989 using VisualEventSignal visualEvent = VisualEventSignal();
990 visualEvent?.Disconnect(visualEventSignalCallback);
991 if (visualEvent?.Empty() == true)
993 visualEventSignalCallback = null;
999 internal void EmitVisualEventSignal(int visualIndex, int signalId)
1001 using VisualEventSignal visualEvent = VisualEventSignal();
1002 visualEvent?.Emit(this, visualIndex, signalId);
1005 internal VisualEventSignal VisualEventSignal()
1007 VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
1008 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1012 internal Dictionary<int, DynamicPropertyCallbackType> InternalSavedDynamicPropertyCallbacks = new Dictionary<int, DynamicPropertyCallbackType>();
1014 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1015 internal delegate void RootCallbackType(int id, int returnType, uint frameNumber, ref float val1, ref float val2, ref float val3);
1017 internal RootCallbackType rootCallback = RootCallback;
1019 static internal void RootCallback(int id, int returnType, uint frameNumber, ref float val1, ref float val2, ref float val3)
1021 WeakReference<LottieAnimationView> current = null;
1022 LottieAnimationView currentView = null;
1023 DynamicPropertyCallbackType currentCallback = null;
1024 PropertyValue ret = null;
1026 if (weakReferencesOfLottie.TryGetValue(id, out current))
1028 if (current.TryGetTarget(out currentView))
1030 if (currentView != null && currentView.InternalSavedDynamicPropertyCallbacks != null &&
1031 currentView.InternalSavedDynamicPropertyCallbacks.TryGetValue(id, out currentCallback))
1033 ret = currentCallback?.Invoke(returnType, frameNumber);
1037 Tizen.Log.Error("NUI", "can't find the callback in LottieAnimationView, just return here!");
1043 Tizen.Log.Error("NUI", "can't find the callback in LottieAnimationView, just return here!");
1049 Tizen.Log.Error("NUI", "can't find LottieAnimationView by id, just return here!");
1055 case (int)(VectorProperty.FillColor):
1056 case (int)(VectorProperty.StrokeColor):
1057 Vector3 tmpVector3 = new Vector3(-1, -1, -1);
1058 if ((ret != null) && ret.Get(tmpVector3))
1060 val1 = tmpVector3.X;
1061 val2 = tmpVector3.Y;
1062 val3 = tmpVector3.Z;
1064 tmpVector3.Dispose();
1067 case (int)(VectorProperty.TransformAnchor):
1068 case (int)(VectorProperty.TransformPosition):
1069 case (int)(VectorProperty.TransformScale):
1070 Vector2 tmpVector2 = new Vector2(-1, -1);
1071 if ((ret != null) && ret.Get(tmpVector2))
1073 val1 = tmpVector2.X;
1074 val2 = tmpVector2.Y;
1076 tmpVector2.Dispose();
1079 case (int)(VectorProperty.FillOpacity):
1080 case (int)(VectorProperty.StrokeOpacity):
1081 case (int)(VectorProperty.StrokeWidth):
1082 case (int)(VectorProperty.TransformRotation):
1083 case (int)(VectorProperty.TransformOpacity):
1084 float tmpFloat = -1;
1085 if ((ret != null) && ret.Get(out tmpFloat))
1100 private struct states
1102 internal string url;
1103 internal int loopCount;
1104 internal LoopingModeType loopMode;
1105 internal StopBehaviorType stopEndAction;
1106 internal int framePlayRangeMin;
1107 internal int framePlayRangeMax;
1108 internal bool changed;
1109 internal int totalFrame;
1110 internal float scale;
1111 internal PlayStateType playState;
1112 internal List<Tuple<string, int, int>> contentInfo;
1113 internal List<Tuple<string, int, int>> markerInfo;
1114 internal string mark1, mark2;
1115 internal bool redrawInScalingDown;
1116 internal bool enableFrameCache;
1118 private states currentStates;
1120 private struct DevelVisual
1124 AnimatedGradient = Visual.Type.AnimatedImage + 1,
1125 AnimatedVectorImage = Visual.Type.AnimatedImage + 2,
1129 private const string tag = "NUITEST";
1130 private event EventHandler finishedEventHandler;
1132 private void OnFinished()
1134 NUILog.Debug($"<[{GetId()}] OnFinished()>");
1135 finishedEventHandler?.Invoke(this, null);
1138 private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
1142 if (targetView != IntPtr.Zero)
1144 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
1147 NUILog.Debug($"targetView is not null! name={v.Name}");
1151 NUILog.Debug($"target is something created from dali");
1154 VisualEventSignalArgs e = new VisualEventSignalArgs();
1155 e.VisualIndex = visualIndex;
1156 e.SignalId = signalId;
1157 visualEventSignalHandler?.Invoke(this, e);
1159 NUILog.Debug($"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
1162 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
1163 private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
1165 private VisualEventSignalCallbackType visualEventSignalCallback;
1166 private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
1168 static private int dynamicPropertyCallbackId = 0;
1169 //static private Dictionary<int, DynamicPropertyCallbackType> dynamicPropertyCallbacks = new Dictionary<int, DynamicPropertyCallbackType>();
1170 static private Dictionary<int, WeakReference<LottieAnimationView>> weakReferencesOfLottie = new Dictionary<int, WeakReference<LottieAnimationView>>();
1172 private void debugPrint()
1174 NUILog.Debug($"===================================");
1175 NUILog.Debug($"<[{GetId()}] get currentStates : url={currentStates.url}, loopCount={currentStates.loopCount}, \nframePlayRangeMin/Max({currentStates.framePlayRangeMin},{currentStates.framePlayRangeMax}) ");
1176 NUILog.Debug($" get from Property : StopBehavior={StopBehavior}, LoopMode={LoopingMode}, LoopCount={LoopCount}, PlayState={PlayState}");
1177 NUILog.Debug($" RedrawInScalingDown={RedrawInScalingDown} >");
1178 NUILog.Debug($"===================================");
1185 /// A class containing frame informations for a LottieAnimationView.
1187 [EditorBrowsable(EditorBrowsableState.Never)]
1188 public class LottieFrameInfo : ICloneable
1191 /// Creates a new instance with a playing range.
1193 [EditorBrowsable(EditorBrowsableState.Never)]
1194 public LottieFrameInfo(int startFrame, int endFrame)
1196 StartFrame = startFrame;
1197 EndFrame = endFrame;
1201 /// Creates a new instance with a still image frame.
1203 [EditorBrowsable(EditorBrowsableState.Never)]
1204 public LottieFrameInfo(int stillImageFrame) : this(stillImageFrame, stillImageFrame)
1209 /// Create a new instance from a pair notation.
1211 [EditorBrowsable(EditorBrowsableState.Never)]
1212 public static implicit operator LottieFrameInfo((int, int) pair)
1214 return new LottieFrameInfo(pair.Item1, pair.Item2);
1218 /// Create a new instance from an int value.
1220 [EditorBrowsable(EditorBrowsableState.Never)]
1221 public static implicit operator LottieFrameInfo(int stillImageFrame)
1223 return new LottieFrameInfo(stillImageFrame);
1227 /// Create a new instance from string.
1228 /// Possible input : "0, 10", "10"
1230 [EditorBrowsable(EditorBrowsableState.Never)]
1231 public static implicit operator LottieFrameInfo(string pair)
1238 string[] parts = pair.Split(',');
1239 if (parts.Length == 1)
1241 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture));
1243 else if (parts.Length == 2)
1245 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture), Int32.Parse(parts[1].Trim(), CultureInfo.InvariantCulture));
1248 Tizen.Log.Error("NUI", $"Can not convert string {pair} to LottieFrameInfo");
1253 /// The start frame of the lottie animation.
1255 [EditorBrowsable(EditorBrowsableState.Never)]
1256 public int StartFrame { get; }
1259 /// The end frame of the lottie animation.
1261 [EditorBrowsable(EditorBrowsableState.Never)]
1262 public int EndFrame { get; }
1265 /// Create LottieFrameInfo struct with animation range information
1267 [EditorBrowsable(EditorBrowsableState.Never)]
1268 public static LottieFrameInfo CreateAnimationRange(int startFrame, int endFrame)
1270 return new LottieFrameInfo(startFrame, endFrame);
1274 /// Create LottieFrameInfo struct with still image information
1276 [EditorBrowsable(EditorBrowsableState.Never)]
1277 public static LottieFrameInfo CreateStillImage(int stillImageFrame)
1279 return new LottieFrameInfo(stillImageFrame, stillImageFrame);
1284 /// Whether this LottieFrameInfo represents one frame or more.
1286 [EditorBrowsable(EditorBrowsableState.Never)]
1287 public bool IsStillImage()
1289 return StartFrame == EndFrame;
1294 /// Play specified LottieAnimationView with this frame information.
1296 /// <param name="lottieView">The target LottieAnimationView to play.</param>
1297 /// <param name="noPlay">Whether go direct to the EndFrame. It is false by default.</param>
1298 [EditorBrowsable(EditorBrowsableState.Never)]
1299 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062: Validate arguments of public methods", Justification = "The null checking is done by BeReadyToShow()")]
1300 public void Show(LottieAnimationView lottieView, bool noPlay = false)
1302 if (!BeReadyToShow(lottieView))
1307 lottieView.SetMinMaxFrame(StartFrame, Math.Min(EndFrame, lottieView.TotalFrame - 1));
1309 if (IsStillImage() || noPlay)
1311 lottieView.CurrentFrame = EndFrame;
1315 lottieView.CurrentFrame = StartFrame;
1321 [EditorBrowsable(EditorBrowsableState.Never)]
1322 public object Clone() => new LottieFrameInfo(StartFrame, EndFrame);
1324 private bool BeReadyToShow(LottieAnimationView lottieView)
1326 // Validate input lottieView
1327 if (null == lottieView || lottieView.PlayState == LottieAnimationView.PlayStateType.Invalid)
1332 // Stop if it was playing
1333 if (lottieView.PlayState == LottieAnimationView.PlayStateType.Playing)
1342 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
1343 [EditorBrowsable(EditorBrowsableState.Never)]
1344 public struct LottieAnimationViewDynamicProperty : IEquatable<LottieAnimationViewDynamicProperty>
1346 [EditorBrowsable(EditorBrowsableState.Never)]
1347 public string KeyPath { get; set; }
1349 [EditorBrowsable(EditorBrowsableState.Never)]
1350 public LottieAnimationView.VectorProperty Property { get; set; }
1352 [EditorBrowsable(EditorBrowsableState.Never)]
1353 public LottieAnimationView.DynamicPropertyCallbackType Callback { get; set; }
1355 public override bool Equals(object obj)
1357 if (obj is LottieAnimationViewDynamicProperty target)
1359 if (KeyPath == target.KeyPath && Property == target.Property && Callback == target.Callback)
1367 public override int GetHashCode()
1369 return base.GetHashCode();
1372 public static bool operator ==(LottieAnimationViewDynamicProperty left, LottieAnimationViewDynamicProperty right)
1374 return left.Equals(right);
1377 public static bool operator !=(LottieAnimationViewDynamicProperty left, LottieAnimationViewDynamicProperty right)
1379 return !(left == right);
1382 public bool Equals(LottieAnimationViewDynamicProperty other)
1386 if (KeyPath == other.KeyPath && Property == other.Property && Callback == other.Callback)