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 NUILog.Debug($"< constructor GetId={GetId()} >");
53 currentStates.url = "";
54 currentStates.loopCount = 1;
55 currentStates.loopMode = LoopingModeType.Restart;
56 currentStates.stopEndAction = StopBehaviorType.CurrentFrame;
57 currentStates.framePlayRangeMin = -1;
58 currentStates.framePlayRangeMax = -1;
59 currentStates.totalFrame = -1;
60 currentStates.scale = scale;
61 currentStates.redrawInScalingDown = true;
62 currentStates.desiredWidth = 0;
63 currentStates.desiredHeight = 0;
64 currentStates.synchronousLoading = true;
66 // Notify to base ImageView cache that default synchronousLoading for lottie file is true.
67 base.SynchronousLoading = currentStates.synchronousLoading;
69 // Set changed flag as true when initalized state.
70 // After some properties change, LottieAnimationView.UpdateImage will apply these inital values.
71 currentStates.changed = true;
76 /// Dispose(DisposeTypes type)
78 /// <param name="type"></param>
79 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
80 [EditorBrowsable(EditorBrowsableState.Never)]
81 protected override void Dispose(DisposeTypes type)
88 CleanCallbackDictionaries();
90 //Release your own unmanaged resources here.
91 //You should not access any managed member here except static instance.
92 //because the execution order of Finalizes is non-deterministic.
94 //disconnect event signal
95 if (finishedEventHandler != null && visualEventSignalCallback != null)
97 using VisualEventSignal visualEvent = VisualEventSignal();
98 visualEvent.Disconnect(visualEventSignalCallback);
99 finishedEventHandler = null;
100 NUILog.Debug($"disconnect event signal");
106 // This is used for internal purpose. hidden API.
107 [EditorBrowsable(EditorBrowsableState.Never)]
108 protected override void Dispose(bool disposing)
110 // Note : We can clean dictionaries even this API called from GC Thread.
111 CleanCallbackDictionaries();
112 base.Dispose(disposing);
114 #endregion Constructor, Destructor, Dispose
119 /// Set or Get resource URL of Lottie file.
121 /// <since_tizen> 7 </since_tizen>
126 return GetValue(URLProperty) as string;
130 SetValue(URLProperty, value);
131 NotifyPropertyChanged();
136 /// Set or Get resource URL of Lottie file.
138 [EditorBrowsable(EditorBrowsableState.Never)]
139 public new string ResourceUrl
151 private string InternalURL
155 // Reset cached infomations.
156 currentStates.contentInfo = null;
157 currentStates.markerInfo = null;
158 currentStates.mark1 = null;
159 currentStates.mark2 = null;
160 currentStates.framePlayRangeMin = -1;
161 currentStates.framePlayRangeMax = -1;
162 currentStates.totalFrame = -1;
163 currentStates.enableFrameCache = false;
165 string ret = (value == null ? "" : value);
166 currentStates.url = ret;
168 NUILog.Debug($"<[{GetId()}]SET url={currentStates.url}");
170 // TODO : Could create new Image without additional creation?
171 using PropertyMap map = new PropertyMap();
172 using PropertyValue type = new PropertyValue((int)Visual.Type.AnimatedVectorImage);
173 using PropertyValue url = new PropertyValue(currentStates.url);
174 using PropertyValue loopCnt = new PropertyValue(currentStates.loopCount);
175 using PropertyValue stopAction = new PropertyValue((int)currentStates.stopEndAction);
176 using PropertyValue loopMode = new PropertyValue((int)currentStates.loopMode);
177 using PropertyValue redrawInScalingDown = new PropertyValue(currentStates.redrawInScalingDown);
178 using PropertyValue synchronousLoading = new PropertyValue(currentStates.synchronousLoading);
180 map.Add(Visual.Property.Type, type)
181 .Add(ImageVisualProperty.URL, url)
182 .Add(ImageVisualProperty.LoopCount, loopCnt)
183 .Add(ImageVisualProperty.StopBehavior, stopAction)
184 .Add(ImageVisualProperty.LoopingMode, loopMode)
185 .Add(ImageVisualProperty.RedrawInScalingDown, redrawInScalingDown)
186 .Add(ImageVisualProperty.SynchronousLoading, synchronousLoading);
188 if (currentStates.desiredWidth > 0)
190 using PropertyValue desiredWidth = new PropertyValue((int)currentStates.desiredWidth);
191 map.Add(ImageVisualProperty.DesiredWidth, desiredWidth);
193 if (currentStates.desiredHeight > 0)
195 using PropertyValue desiredHeight = new PropertyValue((int)currentStates.desiredHeight);
196 map.Add(ImageVisualProperty.DesiredHeight, desiredHeight);
201 if (backgroundExtraData != null)
203 if (backgroundExtraData.CornerRadius != null)
205 UpdateBackgroundExtraData(BackgroundExtraDataUpdatedFlag.ContentsCornerRadius);
207 if (backgroundExtraData.BorderlineWidth > 0.0f)
209 UpdateBackgroundExtraData(BackgroundExtraDataUpdatedFlag.ContentsBorderline);
213 // All states applied well.
214 currentStates.changed = false;
216 if (currentStates.scale != 1.0f)
218 Scale = new Vector3(currentStates.scale, currentStates.scale, currentStates.scale);
220 NUILog.Debug($"<[{GetId()}]>");
224 string ret = currentStates.url;
225 NUILog.Debug($"<[{GetId()}] GET");
226 NUILog.Debug($"gotten url={ret} >");
232 /// Gets or sets the desired image width for LottieAnimationView<br />
234 [EditorBrowsable(EditorBrowsableState.Never)]
235 public new int DesiredWidth
239 return currentStates.desiredWidth;
243 currentStates.desiredWidth = value;
244 base.DesiredWidth = currentStates.desiredWidth;
249 /// Gets or sets the desired image height for LottieAnimationView<br />
251 [EditorBrowsable(EditorBrowsableState.Never)]
252 public new int DesiredHeight
256 return currentStates.desiredHeight;
260 currentStates.desiredHeight = value;
261 base.DesiredHeight = currentStates.desiredHeight;
266 /// Gets or sets the SynchronousLoading for LottieAnimationView<br />
267 /// We should set it before setup ResourceUrl, URL property.<br />
269 [EditorBrowsable(EditorBrowsableState.Never)]
270 public new bool SynchronousLoading
274 return currentStates.synchronousLoading;
278 currentStates.synchronousLoading = value;
279 base.SynchronousLoading = currentStates.synchronousLoading;
284 /// Gets the playing state
286 /// <since_tizen> 7 </since_tizen>
287 public PlayStateType PlayState
291 NUILog.Debug($"< Get!");
294 Interop.View.InternalRetrievingVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.PlayState, out ret);
296 currentStates.playState = (PlayStateType)ret;
297 NUILog.Debug($"gotten play state={currentStates.playState} >");
299 return currentStates.playState;
304 /// Get the number of total frames.
305 /// If resouce is still not be loaded, or invalid resource, the value is 0.
307 /// <since_tizen> 7 </since_tizen>
308 public int TotalFrame
312 int ret = currentStates.totalFrame;
315 Interop.View.InternalRetrievingVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.TotalFrameNumber, out ret);
317 currentStates.totalFrame = ret;
318 NUILog.Debug($"TotalFrameNumber get! ret={ret}");
322 Tizen.Log.Error("NUI", $"Fail to get TotalFrame. Maybe file is not loaded yet, or invalid url used. url : {currentStates.url}\n");
330 /// Set or get the current frame. When setting a specific frame, it is displayed as a still image.
333 /// 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.
336 /// We assume that the animation in myLottie.json file has 100 frames originally. If so, its frame index will be 0 - 99.
338 /// LottieAnimationView myLottie = new LottieAnimationView();
339 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
340 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
341 /// myLottie.CurrentFrame = 200; //display 99 frame
342 /// myLottie.SetMinMaxFrame(10, 20);
343 /// myLottie.CurrentFrame = 15; //display 15 frame
344 /// myLottie.CurrentFrame = 50; //display 20 frame, because the MinMax is set (10,20) above
347 /// <since_tizen> 7 </since_tizen>
348 public int CurrentFrame
352 return (int)GetValue(CurrentFrameProperty);
356 SetValue(CurrentFrameProperty, value);
357 NotifyPropertyChanged();
361 private int InternalCurrentFrame
365 NUILog.Debug($"<[{GetId()}]SET frame={value}>");
367 Interop.View.DoActionWithSingleIntAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionJumpTo, value);
373 Interop.View.InternalRetrievingVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.CurrentFrameNumber, out ret);
375 NUILog.Debug($"CurrentFrameNumber get! val={ret}");
381 /// Sets or gets the looping mode of Lottie animation.
383 /// <since_tizen> 7 </since_tizen>
384 public LoopingModeType LoopingMode
388 return (LoopingModeType)GetValue(LoopingModeProperty);
392 SetValue(LoopingModeProperty, value);
393 NotifyPropertyChanged();
397 private LoopingModeType InternalLoopingMode
401 if (currentStates.loopMode != (LoopingModeType)value)
403 currentStates.changed = true;
404 currentStates.loopMode = (LoopingModeType)value;
406 NUILog.Debug($"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
408 Interop.View.InternalUpdateVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.LoopingMode, (int)currentStates.loopMode);
413 NUILog.Debug($"LoopMode get! {currentStates.loopMode}");
414 return currentStates.loopMode;
419 /// Sets or gets the loop count.
422 /// The minus value means the infinite loop count.
426 /// LottieAnimationView myLottie = new LottieAnimationView();
427 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
428 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
429 /// myLottie.LoopCount = -1; //infinite loop
431 /// myLottie.Stop(); //it plays continuously unless Stop() is called
432 /// myLottie.LoopCount = 2;
433 /// myLottie.Play(); //it plays only 2 times and stops automatically
436 /// <since_tizen> 7 </since_tizen>
441 return (int)GetValue(LoopCountProperty);
445 SetValue(LoopCountProperty, value);
446 NotifyPropertyChanged();
450 private int InternalLoopCount
454 if (currentStates.loopCount != value)
456 currentStates.changed = true;
457 currentStates.loopCount = value;
459 NUILog.Debug($"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
461 Interop.View.InternalUpdateVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.LoopCount, currentStates.loopCount);
466 NUILog.Debug($"LoopCount get! {currentStates.loopCount}");
467 return currentStates.loopCount;
472 /// Sets or gets the stop behavior.
474 /// <since_tizen> 7 </since_tizen>
475 public StopBehaviorType StopBehavior
479 return (StopBehaviorType)GetValue(StopBehaviorProperty);
483 SetValue(StopBehaviorProperty, value);
484 NotifyPropertyChanged();
488 private StopBehaviorType InternalStopBehavior
492 if (currentStates.stopEndAction != (StopBehaviorType)value)
494 currentStates.changed = true;
495 currentStates.stopEndAction = (StopBehaviorType)value;
497 NUILog.Debug($"<[{GetId()}]SET val={currentStates.stopEndAction}>");
499 Interop.View.InternalUpdateVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.StopBehavior, (int)currentStates.stopEndAction);
504 NUILog.Debug($"StopBehavior get! {currentStates.stopEndAction}");
505 return currentStates.stopEndAction;
510 /// Whether to redraw the image when the visual is scaled down.
514 /// It is used in the AnimatedVectorImageVisual.The default is true.
516 [EditorBrowsable(EditorBrowsableState.Never)]
517 public bool RedrawInScalingDown
521 return (bool)GetValue(RedrawInScalingDownProperty);
525 SetValue(RedrawInScalingDownProperty, value);
526 NotifyPropertyChanged();
530 private bool InternalRedrawInScalingDown
534 if (currentStates.redrawInScalingDown != value)
536 currentStates.changed = true;
537 currentStates.redrawInScalingDown = value;
539 NUILog.Debug($"<[{GetId()}]SET currentStates.redrawInScalingDown={currentStates.redrawInScalingDown}>");
541 Interop.View.InternalUpdateVisualPropertyBool(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.RedrawInScalingDown, currentStates.redrawInScalingDown);
546 NUILog.Debug($"RedrawInScalingDown get! {currentStates.redrawInScalingDown}");
547 return currentStates.redrawInScalingDown;
552 [EditorBrowsable(EditorBrowsableState.Never)]
553 public bool EnableFrameCache
557 return (bool)GetValue(EnableFrameCacheProperty);
561 SetValue(EnableFrameCacheProperty, value);
562 NotifyPropertyChanged();
566 private bool InternalEnableFrameCache
570 if (currentStates.enableFrameCache != value)
572 currentStates.changed = true;
573 currentStates.enableFrameCache = value;
575 NUILog.Debug($"<[{GetId()}]SET currentStates.EnableFrameCache={currentStates.enableFrameCache}>");
577 Interop.View.InternalUpdateVisualPropertyBool(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.EnableFrameCache, currentStates.enableFrameCache);
582 NUILog.Debug($"EnableFrameCache get! {currentStates.enableFrameCache}");
583 return currentStates.enableFrameCache;
591 /// Set the minimum and the maximum frame.
593 /// <param name="minFrame">minimum frame</param>
594 /// <param name="maxFrame">maximum frame</param>
595 /// <since_tizen> 7 </since_tizen>
596 public void SetMinMaxFrame(int minFrame, int maxFrame)
598 if (currentStates.framePlayRangeMin != minFrame || currentStates.framePlayRangeMax != maxFrame)
600 NUILog.Debug($"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
601 currentStates.changed = true;
602 currentStates.framePlayRangeMin = minFrame;
603 currentStates.framePlayRangeMax = maxFrame;
605 // Remove marker information.
606 currentStates.mark1 = null;
607 currentStates.mark2 = null;
609 Interop.View.InternalUpdateVisualPropertyIntPair(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.PlayRange, currentStates.framePlayRangeMin, currentStates.framePlayRangeMax);
611 NUILog.Debug($" [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
618 /// <since_tizen> 7 </since_tizen>
619 public new void Play()
621 NUILog.Debug($"<[{GetId()}] Play()");
624 NUILog.Debug($"[{GetId()}]>");
630 /// <since_tizen> 7 </since_tizen>
631 public new void Pause()
633 NUILog.Debug($"<[{GetId()}] Pause()>");
636 NUILog.Debug($"[{GetId()}]>");
642 /// <since_tizen> 7 </since_tizen>
643 public new void Stop()
645 NUILog.Debug($"<[{GetId()}] Stop()");
648 NUILog.Debug($"[{GetId()}]>");
652 /// Get the list of layers' information such as the start frame and the end frame in the Lottie file.
654 /// <returns>List of Tuple (string of layer name, integer of start frame, integer of end frame)</returns>
655 /// <since_tizen> 7 </since_tizen>
656 public List<Tuple<string, int, int>> GetContentInfo()
658 if (currentStates.contentInfo != null)
660 return currentStates.contentInfo;
665 PropertyMap imageMap = base.Image;
666 if (imageMap != null)
668 if (TotalFrame > 0) // Check whether image file loaded successfuly.
670 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
671 PropertyMap contentMap = new PropertyMap();
672 if (val?.Get(ref contentMap) == true)
674 currentStates.contentInfo = new List<Tuple<string, int, int>>();
675 for (uint i = 0; i < contentMap.Count(); i++)
677 using PropertyKey propertyKey = contentMap.GetKeyAt(i);
678 string key = propertyKey.StringKey;
680 using PropertyValue arrVal = contentMap.GetValue(i);
681 using PropertyArray arr = new PropertyArray();
685 using PropertyValue start = arr.GetElementAt(0);
686 start?.Get(out startFrame);
689 using PropertyValue end = arr.GetElementAt(1);
690 end?.Get(out endFrame);
692 NUILog.Debug($"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
694 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
696 currentStates.contentInfo?.Add(item);
700 contentMap.Dispose();
706 return currentStates.contentInfo;
710 /// Get the list of markers' information such as the start frame and the end frame in the Lottie file.
712 /// <returns>List of Tuple (string of marker name, integer of start frame, integer of end frame)</returns>
713 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
714 [EditorBrowsable(EditorBrowsableState.Never)]
715 public List<Tuple<string, int, int>> GetMarkerInfo()
717 if (currentStates.markerInfo != null)
719 return currentStates.markerInfo;
724 PropertyMap imageMap = base.Image;
725 if (imageMap != null)
727 if (TotalFrame > 0) // Check whether image file loaded successfuly.
729 PropertyValue val = imageMap.Find(ImageVisualProperty.MarkerInfo);
730 PropertyMap markerMap = new PropertyMap();
731 if (val?.Get(ref markerMap) == true)
733 currentStates.markerInfo = new List<Tuple<string, int, int>>();
734 for (uint i = 0; i < markerMap.Count(); i++)
736 using PropertyKey propertyKey = markerMap.GetKeyAt(i);
737 string key = propertyKey.StringKey;
739 using PropertyValue arrVal = markerMap.GetValue(i);
740 using PropertyArray arr = new PropertyArray();
744 using PropertyValue start = arr.GetElementAt(0);
745 start?.Get(out startFrame);
748 using PropertyValue end = arr.GetElementAt(1);
749 end?.Get(out endFrame);
751 NUILog.Debug($"[{i}] marker name={key}, startFrame={startFrame}, endFrame={endFrame}");
753 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
755 currentStates.markerInfo?.Add(item);
765 return currentStates.markerInfo;
769 /// A marker has its start frame and end frame.
770 /// Animation will play between the start frame and the end frame of the marker if one marker is specified.
771 /// 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.
773 /// <param name="marker1">First marker</param>
774 /// <param name="marker2">Second marker</param>
775 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
776 [EditorBrowsable(EditorBrowsableState.Never)]
777 public void SetMinMaxFrameByMarker(string marker1, string marker2 = null)
779 string marker1OrEmpty = marker1 ?? ""; // mark1 should not be null
780 if (currentStates.mark1 != marker1OrEmpty || currentStates.mark2 != marker2)
782 NUILog.Debug($"< [{GetId()}] SetMinMaxFrameByMarker({marker1OrEmpty}, {marker2})");
784 currentStates.changed = true;
785 currentStates.mark1 = marker1OrEmpty;
786 currentStates.mark2 = marker2;
788 // Remove frame information.
789 currentStates.framePlayRangeMin = -1;
790 currentStates.framePlayRangeMax = -1;
792 if (string.IsNullOrEmpty(currentStates.mark2))
794 Interop.View.InternalUpdateVisualPropertyString(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.PlayRange, currentStates.mark1);
798 Interop.View.InternalUpdateVisualPropertyStringPair(this.SwigCPtr, ImageView.Property.IMAGE, ImageVisualProperty.PlayRange, currentStates.mark1, currentStates.mark2);
801 NUILog.Debug($" [{GetId()}] currentStates.mark1:{currentStates.mark1}, mark2:{currentStates.mark2} >");
808 /// <returns>Tuple of Min and Max frames</returns>
809 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
810 [EditorBrowsable(EditorBrowsableState.Never)]
811 public Tuple<int, int> GetMinMaxFrame()
813 NUILog.Debug($"< [{GetId()}] GetMinMaxFrame()! total frame={currentStates.totalFrame}");
815 using PropertyMap map = Image;
818 using PropertyValue val = map.Find(ImageVisualProperty.PlayRange);
821 using PropertyArray array = new PropertyArray();
824 uint cnt = array.Count();
825 int item1 = -1, item2 = -1;
826 for (uint i = 0; i < cnt; i++)
828 using PropertyValue v = array.GetElementAt(i);
830 if (v.Get(out intRet))
832 NUILog.Debug($"Got play range of string [{i}]: {intRet}");
844 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#1");
847 NUILog.Debug($" [{GetId()}] GetMinMaxFrame(min:{item1}, max:{item2})! >");
848 return new Tuple<int, int>(item1, item2);
852 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#2");
853 return new Tuple<int, int>(-1, -1);
856 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
857 [EditorBrowsable(EditorBrowsableState.Never)]
858 public void DoActionExtension(LottieAnimationViewDynamicProperty info)
860 dynamicPropertyCallbackId++;
862 weakReferencesOfLottie?.Add(dynamicPropertyCallbackId, new WeakReference<LottieAnimationView>(this));
863 InternalSavedDynamicPropertyCallbacks?.Add(dynamicPropertyCallbackId, info.Callback);
865 Interop.View.DoActionExtension(SwigCPtr, ImageView.Property.IMAGE, ActionSetDynamicProperty, dynamicPropertyCallbackId, info.KeyPath, (int)info.Property, Marshal.GetFunctionPointerForDelegate<System.Delegate>(rootCallback));
867 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
870 private void CleanCallbackDictionaries()
872 if (weakReferencesOfLottie?.Count > 0 && InternalSavedDynamicPropertyCallbacks != null)
874 foreach (var key in InternalSavedDynamicPropertyCallbacks?.Keys)
876 if (weakReferencesOfLottie.ContainsKey(key))
878 weakReferencesOfLottie.Remove(key);
882 InternalSavedDynamicPropertyCallbacks?.Clear();
883 InternalSavedDynamicPropertyCallbacks = null;
887 /// Update lottie-image-relative properties synchronously.
888 /// After call this API, All image properties updated.
890 [EditorBrowsable(EditorBrowsableState.Never)]
891 protected override void UpdateImage()
898 if (!imagePropertyUpdatedFlag) return;
900 // Update currentStates properties to cachedImagePropertyMap
901 if(currentStates.changed)
903 UpdateImage(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount), false);
904 UpdateImage(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction), false);
905 UpdateImage(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode), false);
906 UpdateImage(ImageVisualProperty.RedrawInScalingDown, new PropertyValue(currentStates.redrawInScalingDown), false);
907 UpdateImage(ImageVisualProperty.SynchronousLoading, new PropertyValue(currentStates.synchronousLoading), false);
909 // Do not cache PlayRange and TotalFrameNumber into cachedImagePropertyMap.
910 // (To keep legacy implements behaviour)
911 currentStates.changed = false;
918 /// Update NUI cached animated image visual property map by inputed property map.
919 /// And call base.MergeCachedImageVisualProperty()
922 /// For performance issue, we will collect only "cachedLottieAnimationPropertyKeyList" hold in this class.
924 [EditorBrowsable(EditorBrowsableState.Never)]
925 protected override void MergeCachedImageVisualProperty(PropertyMap map)
927 if (map == null) return;
928 if (cachedImagePropertyMap == null)
930 cachedImagePropertyMap = new PropertyMap();
932 foreach (var key in cachedLottieAnimationPropertyKeyList)
934 PropertyValue value = map.Find(key);
937 // Update-or-Insert new value
938 cachedImagePropertyMap[key] = value;
941 base.MergeCachedImageVisualProperty(map);
946 #region Event, Enum, Struct, ETC
948 /// Animation finished event.
950 /// <since_tizen> 7 </since_tizen>
951 public event EventHandler Finished
955 if (finishedEventHandler == null)
957 NUILog.Debug($"<[{GetId()}] Finished eventhandler added>");
958 visualEventSignalCallback = onVisualEventSignal;
959 using VisualEventSignal visualEvent = VisualEventSignal();
960 visualEvent.Connect(visualEventSignalCallback);
962 finishedEventHandler += value;
966 NUILog.Debug($"<[{GetId()}] Finished eventhandler removed>");
967 finishedEventHandler -= value;
968 if (finishedEventHandler == null && visualEventSignalCallback != null)
970 using VisualEventSignal visualEvent = VisualEventSignal();
971 visualEvent.Disconnect(visualEventSignalCallback);
972 if (visualEvent?.Empty() == true)
974 visualEventSignalCallback = null;
981 /// Enumeration for what state the vector animation is in
983 /// <since_tizen> 7 </since_tizen>
984 public enum PlayStateType
989 /// <since_tizen> 7 </since_tizen>
992 /// Vector Animation has stopped
994 /// <since_tizen> 7 </since_tizen>
997 /// The vector animation is playing
999 /// <since_tizen> 7 </since_tizen>
1002 /// The vector animation is paused
1004 /// <since_tizen> 7 </since_tizen>
1009 /// Enumeration for what to do when the animation is stopped.
1011 /// <since_tizen> 7 </since_tizen>
1012 public enum StopBehaviorType
1015 /// When the animation is stopped, the current frame is shown.
1017 /// <since_tizen> 7 </since_tizen>
1020 /// When the animation is stopped, the min frame (first frame) is shown.
1022 /// <since_tizen> 7 </since_tizen>
1025 /// When the animation is stopped, the max frame (last frame) is shown.
1027 /// <since_tizen> 7 </since_tizen>
1032 /// Enumeration for what looping mode is in.
1034 /// <since_tizen> 7 </since_tizen>
1035 public enum LoopingModeType
1038 /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
1040 /// <since_tizen> 7 </since_tizen>
1043 /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
1045 /// <since_tizen> 7 </since_tizen>
1052 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
1053 [EditorBrowsable(EditorBrowsableState.Never)]
1054 public enum VectorProperty
1057 /// Fill color of the object, Type of <see cref="Vector3"/>
1059 [EditorBrowsable(EditorBrowsableState.Never)]
1063 /// Fill opacity of the object, Type of float
1065 [EditorBrowsable(EditorBrowsableState.Never)]
1069 /// Stroke color of the object, Type of <see cref="Vector3"/>
1071 [EditorBrowsable(EditorBrowsableState.Never)]
1075 /// Stroke opacity of the object, Type of float
1077 [EditorBrowsable(EditorBrowsableState.Never)]
1081 /// Stroke width of the object, Type of float
1083 [EditorBrowsable(EditorBrowsableState.Never)]
1087 /// Transform anchor of the Layer and Group object, Type of <see cref="Vector2"/>
1089 [EditorBrowsable(EditorBrowsableState.Never)]
1093 /// Transform position of the Layer and Group object, Type of <see cref="Vector2"/>
1095 [EditorBrowsable(EditorBrowsableState.Never)]
1099 /// Transform scale of the Layer and Group object, Type of <see cref="Vector2"/>, Value range of [0..100]
1101 [EditorBrowsable(EditorBrowsableState.Never)]
1105 /// Transform rotation of the Layer and Group object, Type of float, Value range of [0..360] in degrees
1107 [EditorBrowsable(EditorBrowsableState.Never)]
1111 /// Transform opacity of the Layer and Group object, Type of float
1113 [EditorBrowsable(EditorBrowsableState.Never)]
1117 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
1118 [EditorBrowsable(EditorBrowsableState.Never)]
1119 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1120 public delegate PropertyValue DynamicPropertyCallbackType(int returnType, uint frameNumber);
1121 #endregion Event, Enum, Struct, ETC
1126 /// Actions property value to Jump to the specified frame.
1128 internal static readonly int ActionJumpTo = Interop.LottieAnimationView.AnimatedVectorImageVisualActionJumpToGet();
1130 // This is used for internal purpose.
1131 internal static readonly int ActionSetDynamicProperty = Interop.LottieAnimationView.AnimatedVectorImageVisualActionSetDynamicPropertyGet();
1132 internal static readonly int ActionFlush = Interop.LottieAnimationView.AnimatedVectorImageVisualActionFlushGet();
1134 internal class VisualEventSignalArgs : EventArgs
1136 public int VisualIndex
1148 internal event EventHandler<VisualEventSignalArgs> VisualEvent
1152 if (visualEventSignalHandler == null)
1154 visualEventSignalCallback = onVisualEventSignal;
1155 using VisualEventSignal visualEvent = VisualEventSignal();
1156 visualEvent?.Connect(visualEventSignalCallback);
1158 visualEventSignalHandler += value;
1162 visualEventSignalHandler -= value;
1163 if (visualEventSignalHandler == null && visualEventSignalCallback != null)
1165 using VisualEventSignal visualEvent = VisualEventSignal();
1166 visualEvent?.Disconnect(visualEventSignalCallback);
1167 if (visualEvent?.Empty() == true)
1169 visualEventSignalCallback = null;
1175 internal void EmitVisualEventSignal(int visualIndex, int signalId)
1177 using VisualEventSignal visualEvent = VisualEventSignal();
1178 visualEvent?.Emit(this, visualIndex, signalId);
1181 internal VisualEventSignal VisualEventSignal()
1183 VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
1184 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1188 internal Dictionary<int, DynamicPropertyCallbackType> InternalSavedDynamicPropertyCallbacks = new Dictionary<int, DynamicPropertyCallbackType>();
1190 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1191 internal delegate void RootCallbackType(int id, int returnType, uint frameNumber, ref float val1, ref float val2, ref float val3);
1193 static internal RootCallbackType rootCallback = RootCallback;
1195 static internal void RootCallback(int id, int returnType, uint frameNumber, ref float val1, ref float val2, ref float val3)
1197 WeakReference<LottieAnimationView> current = null;
1198 LottieAnimationView currentView = null;
1199 DynamicPropertyCallbackType currentCallback = null;
1200 PropertyValue ret = null;
1202 if (weakReferencesOfLottie.TryGetValue(id, out current))
1204 if (current.TryGetTarget(out currentView) && (currentView != null) && !currentView.Disposed && !currentView.IsDisposeQueued)
1206 if (currentView.InternalSavedDynamicPropertyCallbacks != null &&
1207 currentView.InternalSavedDynamicPropertyCallbacks.TryGetValue(id, out currentCallback))
1209 ret = currentCallback?.Invoke(returnType, frameNumber);
1213 Tizen.Log.Error("NUI", "can't find the callback in LottieAnimationView, just return here!");
1219 Tizen.Log.Error("NUI", "can't find the callback in LottieAnimationView, just return here!");
1225 Tizen.Log.Error("NUI", "can't find LottieAnimationView by id, just return here!");
1231 case (int)(VectorProperty.FillColor):
1232 case (int)(VectorProperty.StrokeColor):
1233 Vector3 tmpVector3 = new Vector3(-1, -1, -1);
1234 if ((ret != null) && ret.Get(tmpVector3))
1236 val1 = tmpVector3.X;
1237 val2 = tmpVector3.Y;
1238 val3 = tmpVector3.Z;
1242 case (int)(VectorProperty.TransformAnchor):
1243 case (int)(VectorProperty.TransformPosition):
1244 case (int)(VectorProperty.TransformScale):
1245 Vector2 tmpVector2 = new Vector2(-1, -1);
1246 if ((ret != null) && ret.Get(tmpVector2))
1248 val1 = tmpVector2.X;
1249 val2 = tmpVector2.Y;
1253 case (int)(VectorProperty.FillOpacity):
1254 case (int)(VectorProperty.StrokeOpacity):
1255 case (int)(VectorProperty.StrokeWidth):
1256 case (int)(VectorProperty.TransformRotation):
1257 case (int)(VectorProperty.TransformOpacity):
1258 float tmpFloat = -1;
1259 if ((ret != null) && ret.Get(out tmpFloat))
1271 internal void FlushLottieMessages()
1273 NUILog.Debug($"<[{GetId()}]FLUSH>");
1275 Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionFlush);
1282 // Collection of lottie-image-sensitive properties.
1283 private static readonly List<int> cachedLottieAnimationPropertyKeyList = new List<int> {
1284 ImageVisualProperty.LoopCount,
1285 ImageVisualProperty.StopBehavior,
1286 ImageVisualProperty.LoopingMode,
1287 ImageVisualProperty.RedrawInScalingDown,
1290 private struct states
1292 internal string url;
1293 internal int loopCount;
1294 internal LoopingModeType loopMode;
1295 internal StopBehaviorType stopEndAction;
1296 internal int framePlayRangeMin;
1297 internal int framePlayRangeMax;
1298 internal int totalFrame;
1299 internal float scale;
1300 internal PlayStateType playState;
1301 internal List<Tuple<string, int, int>> contentInfo;
1302 internal List<Tuple<string, int, int>> markerInfo;
1303 internal string mark1, mark2;
1304 internal bool redrawInScalingDown;
1305 internal int desiredWidth, desiredHeight;
1306 internal bool synchronousLoading;
1307 internal bool enableFrameCache;
1308 internal bool changed;
1310 private states currentStates;
1312 private const string tag = "NUITEST";
1313 private event EventHandler finishedEventHandler;
1315 private void OnFinished()
1317 NUILog.Debug($"<[{GetId()}] OnFinished()>");
1318 finishedEventHandler?.Invoke(this, null);
1321 private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
1325 if (targetView != IntPtr.Zero)
1327 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
1330 NUILog.Debug($"targetView is not null! name={v.Name}");
1334 NUILog.Debug($"target is something created from dali");
1337 VisualEventSignalArgs e = new VisualEventSignalArgs();
1338 e.VisualIndex = visualIndex;
1339 e.SignalId = signalId;
1340 visualEventSignalHandler?.Invoke(this, e);
1342 NUILog.Debug($"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
1345 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1346 private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
1348 private VisualEventSignalCallbackType visualEventSignalCallback;
1349 private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
1351 static private int dynamicPropertyCallbackId = 0;
1352 //static private Dictionary<int, DynamicPropertyCallbackType> dynamicPropertyCallbacks = new Dictionary<int, DynamicPropertyCallbackType>();
1353 static private Dictionary<int, WeakReference<LottieAnimationView>> weakReferencesOfLottie = new Dictionary<int, WeakReference<LottieAnimationView>>();
1355 private void debugPrint()
1357 NUILog.Debug($"===================================");
1358 NUILog.Debug($"<[{GetId()}] get currentStates : url={currentStates.url}, loopCount={currentStates.loopCount}, \nframePlayRangeMin/Max({currentStates.framePlayRangeMin},{currentStates.framePlayRangeMax}) ");
1359 NUILog.Debug($" get from Property : StopBehavior={StopBehavior}, LoopMode={LoopingMode}, LoopCount={LoopCount}, PlayState={PlayState}");
1360 NUILog.Debug($" RedrawInScalingDown={RedrawInScalingDown} >");
1361 NUILog.Debug($"===================================");
1368 /// A class containing frame informations for a LottieAnimationView.
1370 [EditorBrowsable(EditorBrowsableState.Never)]
1371 public class LottieFrameInfo : ICloneable
1374 /// Creates a new instance with a playing range.
1376 [EditorBrowsable(EditorBrowsableState.Never)]
1377 public LottieFrameInfo(int startFrame, int endFrame)
1379 StartFrame = startFrame;
1380 EndFrame = endFrame;
1384 /// Creates a new instance with a still image frame.
1386 [EditorBrowsable(EditorBrowsableState.Never)]
1387 public LottieFrameInfo(int stillImageFrame) : this(stillImageFrame, stillImageFrame)
1392 /// Create a new instance from a pair notation.
1394 [EditorBrowsable(EditorBrowsableState.Never)]
1395 public static implicit operator LottieFrameInfo((int, int) pair)
1397 return new LottieFrameInfo(pair.Item1, pair.Item2);
1401 /// Create a new instance from an int value.
1403 [EditorBrowsable(EditorBrowsableState.Never)]
1404 public static implicit operator LottieFrameInfo(int stillImageFrame)
1406 return new LottieFrameInfo(stillImageFrame);
1410 /// Create a new instance from string.
1411 /// Possible input : "0, 10", "10"
1413 [EditorBrowsable(EditorBrowsableState.Never)]
1414 public static implicit operator LottieFrameInfo(string pair)
1421 string[] parts = pair.Split(',');
1422 if (parts.Length == 1)
1424 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture));
1426 else if (parts.Length == 2)
1428 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture), Int32.Parse(parts[1].Trim(), CultureInfo.InvariantCulture));
1431 Tizen.Log.Error("NUI", $"Can not convert string {pair} to LottieFrameInfo");
1436 /// The start frame of the lottie animation.
1438 [EditorBrowsable(EditorBrowsableState.Never)]
1439 public int StartFrame { get; }
1442 /// The end frame of the lottie animation.
1444 [EditorBrowsable(EditorBrowsableState.Never)]
1445 public int EndFrame { get; }
1448 /// Create LottieFrameInfo struct with animation range information
1450 [EditorBrowsable(EditorBrowsableState.Never)]
1451 public static LottieFrameInfo CreateAnimationRange(int startFrame, int endFrame)
1453 return new LottieFrameInfo(startFrame, endFrame);
1457 /// Create LottieFrameInfo struct with still image information
1459 [EditorBrowsable(EditorBrowsableState.Never)]
1460 public static LottieFrameInfo CreateStillImage(int stillImageFrame)
1462 return new LottieFrameInfo(stillImageFrame, stillImageFrame);
1467 /// Whether this LottieFrameInfo represents one frame or more.
1469 [EditorBrowsable(EditorBrowsableState.Never)]
1470 public bool IsStillImage()
1472 return StartFrame == EndFrame;
1477 /// Play specified LottieAnimationView with this frame information.
1479 /// <param name="lottieView">The target LottieAnimationView to play.</param>
1480 /// <param name="noPlay">Whether go direct to the EndFrame. It is false by default.</param>
1481 [EditorBrowsable(EditorBrowsableState.Never)]
1482 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062: Validate arguments of public methods", Justification = "The null checking is done by BeReadyToShow()")]
1483 public void Show(LottieAnimationView lottieView, bool noPlay = false)
1485 if (!BeReadyToShow(lottieView))
1490 lottieView.SetMinMaxFrame(StartFrame, Math.Min(EndFrame, lottieView.TotalFrame - 1));
1492 if (IsStillImage() || noPlay)
1494 lottieView.CurrentFrame = EndFrame;
1498 lottieView.CurrentFrame = StartFrame;
1504 [EditorBrowsable(EditorBrowsableState.Never)]
1505 public object Clone() => new LottieFrameInfo(StartFrame, EndFrame);
1507 private bool BeReadyToShow(LottieAnimationView lottieView)
1509 // Validate input lottieView
1510 if (null == lottieView || lottieView.PlayState == LottieAnimationView.PlayStateType.Invalid)
1515 // Stop if it was playing
1516 if (lottieView.PlayState == LottieAnimationView.PlayStateType.Playing)
1525 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
1526 [EditorBrowsable(EditorBrowsableState.Never)]
1527 public struct LottieAnimationViewDynamicProperty : IEquatable<LottieAnimationViewDynamicProperty>
1529 [EditorBrowsable(EditorBrowsableState.Never)]
1530 public string KeyPath { get; set; }
1532 [EditorBrowsable(EditorBrowsableState.Never)]
1533 public LottieAnimationView.VectorProperty Property { get; set; }
1535 [EditorBrowsable(EditorBrowsableState.Never)]
1536 public LottieAnimationView.DynamicPropertyCallbackType Callback { get; set; }
1538 public override bool Equals(object obj)
1540 if (obj is LottieAnimationViewDynamicProperty target)
1542 if (KeyPath == target.KeyPath && Property == target.Property && Callback == target.Callback)
1550 public override int GetHashCode()
1552 return base.GetHashCode();
1555 public static bool operator ==(LottieAnimationViewDynamicProperty left, LottieAnimationViewDynamicProperty right)
1557 return left.Equals(right);
1560 public static bool operator !=(LottieAnimationViewDynamicProperty left, LottieAnimationViewDynamicProperty right)
1562 return !(left == right);
1565 public bool Equals(LottieAnimationViewDynamicProperty other)
1567 if (KeyPath == other.KeyPath && Property == other.Property && Callback == other.Callback)