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.totalFrame = -1;
64 currentStates.scale = scale;
65 currentStates.redrawInScalingDown = true;
67 // Set changed flag as true when initalized state.
68 // After some properties change, LottieAnimationView.UpdateImage will apply these inital values.
69 currentStates.changed = true;
74 /// Dispose(DisposeTypes type)
76 /// <param name="type"></param>
77 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
78 [EditorBrowsable(EditorBrowsableState.Never)]
79 protected override void Dispose(DisposeTypes type)
86 CleanCallbackDictionaries();
88 //Release your own unmanaged resources here.
89 //You should not access any managed member here except static instance.
90 //because the execution order of Finalizes is non-deterministic.
92 //disconnect event signal
93 if (finishedEventHandler != null && visualEventSignalCallback != null)
95 using VisualEventSignal visualEvent = VisualEventSignal();
96 visualEvent.Disconnect(visualEventSignalCallback);
97 finishedEventHandler = null;
98 NUILog.Debug($"disconnect event signal");
104 // This is used for internal purpose. hidden API.
105 [EditorBrowsable(EditorBrowsableState.Never)]
106 protected override void Dispose(bool disposing)
108 CleanCallbackDictionaries();
109 base.Dispose(disposing);
111 #endregion Constructor, Destructor, Dispose
116 /// Set or Get resource URL of Lottie file.
118 /// <since_tizen> 7 </since_tizen>
123 return GetValue(URLProperty) as string;
127 SetValue(URLProperty, value);
128 NotifyPropertyChanged();
132 private string InternalURL
136 string ret = (value == null ? "" : value);
137 currentStates.url = ret;
138 currentStates.totalFrame = -1; // Reset cached totalFrame value;
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)Visual.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);
149 using PropertyValue redrawInScalingDown = new PropertyValue(currentStates.redrawInScalingDown);
151 map.Add(Visual.Property.Type, type)
152 .Add(ImageVisualProperty.URL, url)
153 .Add(ImageVisualProperty.LoopCount, loopCnt)
154 .Add(ImageVisualProperty.StopBehavior, stopAction)
155 .Add(ImageVisualProperty.LoopingMode, loopMode)
156 .Add(ImageVisualProperty.RedrawInScalingDown, redrawInScalingDown);
159 // All states applied well.
160 currentStates.changed = false;
162 currentStates.contentInfo = null;
164 if (currentStates.scale != 1.0f)
166 Scale = new Vector3(currentStates.scale, currentStates.scale, currentStates.scale);
168 NUILog.Debug($"<[{GetId()}]>");
172 string ret = currentStates.url;
173 NUILog.Debug($"<[{GetId()}] GET");
174 NUILog.Debug($"gotten url={ret} >");
180 /// Gets the playing state
182 /// <since_tizen> 7 </since_tizen>
183 public PlayStateType PlayState
187 NUILog.Debug($"< Get!");
188 using PropertyMap map = base.Image;
192 using PropertyValue val = map.Find(ImageVisualProperty.PlayState);
195 if (val.Get(out ret))
197 currentStates.playState = (PlayStateType)ret;
198 NUILog.Debug($"gotten play state={ret} >");
204 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}]Fail to get PlayState from dali currentStates.playState={currentStates.playState}>");
206 return currentStates.playState;
211 /// Get the number of total frames
213 /// <since_tizen> 7 </since_tizen>
214 public int TotalFrame
218 int ret = currentStates.totalFrame;
221 // TODO : Could we get this value without base.Image?
222 using PropertyMap map = base.Image;
225 using PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
228 if (val.Get(out ret))
230 NUILog.Debug($"TotalFrameNumber get! ret={ret}");
231 currentStates.totalFrame = ret;
236 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get TotalFrameNumber from dali>");
243 /// Set or get the current frame. When setting a specific frame, it is displayed as a still image.
246 /// 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.
249 /// We assume that the animation in myLottie.json file has 100 frames originally. If so, its frame index will be 0 - 99.
251 /// LottieAnimationView myLottie = new LottieAnimationView();
252 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
253 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
254 /// myLottie.CurrentFrame = 200; //display 99 frame
255 /// myLottie.SetMinMaxFrame(10, 20);
256 /// myLottie.CurrentFrame = 15; //display 15 frame
257 /// myLottie.CurrentFrame = 50; //display 20 frame, because the MinMax is set (10,20) above
260 /// <since_tizen> 7 </since_tizen>
261 public int CurrentFrame
265 return (int)GetValue(CurrentFrameProperty);
269 SetValue(CurrentFrameProperty, value);
270 NotifyPropertyChanged();
274 private int InternalCurrentFrame
278 NUILog.Debug($"<[{GetId()}]SET frame={value}>");
279 using PropertyValue attribute = new PropertyValue(value);
280 DoAction(ImageView.Property.IMAGE, ActionJumpTo, attribute);
284 // TODO : Could we get this value without base.Image?
286 using PropertyMap map = base.Image;
289 using PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
292 if (val.Get(out ret))
294 NUILog.Debug($"CurrentFrameNumber get! val={ret}");
299 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get CurrentFrameNumber from dali!! ret={ret}>");
305 /// Sets or gets the looping mode of Lottie animation.
307 /// <since_tizen> 7 </since_tizen>
308 public LoopingModeType LoopingMode
312 return (LoopingModeType)GetValue(LoopingModeProperty);
316 SetValue(LoopingModeProperty, value);
317 NotifyPropertyChanged();
321 private LoopingModeType InternalLoopingMode
325 if (currentStates.loopMode != (LoopingModeType)value)
327 currentStates.changed = true;
328 currentStates.loopMode = (LoopingModeType)value;
330 NUILog.Debug($"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
331 using PropertyMap map = new PropertyMap();
332 using PropertyValue loopMode = new PropertyValue((int)currentStates.loopMode);
333 map.Add(ImageVisualProperty.LoopingMode, loopMode);
334 using PropertyValue attribute = new PropertyValue(map);
335 DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, attribute);
340 NUILog.Debug($"LoopMode get! {currentStates.loopMode}");
341 return currentStates.loopMode;
346 /// Sets or gets the loop count.
349 /// The minus value means the infinite loop count.
353 /// LottieAnimationView myLottie = new LottieAnimationView();
354 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
355 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
356 /// myLottie.LoopCount = -1; //infinite loop
358 /// myLottie.Stop(); //it plays continuously unless Stop() is called
359 /// myLottie.LoopCount = 2;
360 /// myLottie.Play(); //it plays only 2 times and stops automatically
363 /// <since_tizen> 7 </since_tizen>
368 return (int)GetValue(LoopCountProperty);
372 SetValue(LoopCountProperty, value);
373 NotifyPropertyChanged();
377 private int InternalLoopCount
381 if (currentStates.loopCount != value)
383 currentStates.changed = true;
384 currentStates.loopCount = value;
386 NUILog.Debug($"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
387 using PropertyMap map = new PropertyMap();
388 using PropertyValue loopCnt = new PropertyValue(currentStates.loopCount);
389 map.Add(ImageVisualProperty.LoopCount, loopCnt);
390 using PropertyValue attribute = new PropertyValue(map);
391 DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, attribute);
396 NUILog.Debug($"LoopCount get! {currentStates.loopCount}");
397 return currentStates.loopCount;
402 /// Sets or gets the stop behavior.
404 /// <since_tizen> 7 </since_tizen>
405 public StopBehaviorType StopBehavior
409 return (StopBehaviorType)GetValue(StopBehaviorProperty);
413 SetValue(StopBehaviorProperty, value);
414 NotifyPropertyChanged();
418 private StopBehaviorType InternalStopBehavior
422 if (currentStates.stopEndAction != (StopBehaviorType)value)
424 currentStates.changed = true;
425 currentStates.stopEndAction = (StopBehaviorType)value;
427 NUILog.Debug($"<[{GetId()}]SET val={currentStates.stopEndAction}>");
428 using PropertyMap map = new PropertyMap();
429 using PropertyValue stopAction = new PropertyValue((int)currentStates.stopEndAction);
430 map.Add(ImageVisualProperty.StopBehavior, stopAction);
431 using PropertyValue attribute = new PropertyValue(map);
432 DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, attribute);
437 NUILog.Debug($"StopBehavior get! {currentStates.stopEndAction}");
438 return currentStates.stopEndAction;
443 /// Whether to redraw the image when the visual is scaled down.
447 /// It is used in the AnimatedVectorImageVisual.The default is true.
449 [EditorBrowsable(EditorBrowsableState.Never)]
450 public bool RedrawInScalingDown
454 return (bool)GetValue(RedrawInScalingDownProperty);
458 SetValue(RedrawInScalingDownProperty, value);
459 NotifyPropertyChanged();
463 private bool InternalRedrawInScalingDown
467 if (currentStates.redrawInScalingDown != value)
469 currentStates.changed = true;
470 currentStates.redrawInScalingDown = value;
472 NUILog.Debug($"<[{GetId()}]SET currentStates.redrawInScalingDown={currentStates.redrawInScalingDown}>");
473 using PropertyMap map = new PropertyMap();
474 using PropertyValue redraw = new PropertyValue(currentStates.redrawInScalingDown);
475 map.Add(ImageVisualProperty.RedrawInScalingDown, redraw);
476 using PropertyValue action = new PropertyValue(map);
477 DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, action);
482 NUILog.Debug($"RedrawInScalingDown get! {currentStates.redrawInScalingDown}");
483 return currentStates.redrawInScalingDown;
489 /// Actions property value to Jump to the specified frame.
490 /// This property can be redefined by child class if it use different value.
492 [EditorBrowsable(EditorBrowsableState.Never)]
493 protected int ActionJumpTo { get; set; } = Interop.LottieAnimationView.AnimatedVectorImageVisualActionJumpToGet();
495 // This is used for internal purpose. hidden API.
496 [EditorBrowsable(EditorBrowsableState.Never)]
497 protected int SetDynamicProperty => ActionJumpTo + 1;
503 /// Set the minimum and the maximum frame.
505 /// <param name="minFrame">minimum frame</param>
506 /// <param name="maxFrame">maximum frame</param>
507 /// <since_tizen> 7 </since_tizen>
508 public void SetMinMaxFrame(int minFrame, int maxFrame)
510 if (currentStates.framePlayRangeMin != minFrame || currentStates.framePlayRangeMax != maxFrame)
512 NUILog.Debug($"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
513 currentStates.changed = true;
514 currentStates.framePlayRangeMin = minFrame;
515 currentStates.framePlayRangeMax = maxFrame;
517 using PropertyArray array = new PropertyArray();
518 using PropertyValue min = new PropertyValue(currentStates.framePlayRangeMin);
519 using PropertyValue max = new PropertyValue(currentStates.framePlayRangeMax);
523 using PropertyMap map = new PropertyMap();
524 using PropertyValue range = new PropertyValue(array);
525 map.Add(ImageVisualProperty.PlayRange, range);
526 using PropertyValue action = new PropertyValue(map);
527 DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, action);
528 NUILog.Debug($" [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
535 /// <since_tizen> 7 </since_tizen>
536 public new void Play()
538 NUILog.Debug($"<[{GetId()}] Play()");
541 NUILog.Debug($"[{GetId()}]>");
547 /// <since_tizen> 7 </since_tizen>
548 public new void Pause()
550 NUILog.Debug($"<[{GetId()}] Pause()>");
553 NUILog.Debug($"[{GetId()}]>");
559 /// <since_tizen> 7 </since_tizen>
560 public new void Stop()
562 NUILog.Debug($"<[{GetId()}] Stop()");
565 NUILog.Debug($"[{GetId()}]>");
569 /// Get the list of layers' information such as the start frame and the end frame in the Lottie file.
571 /// <returns>List of Tuple (string of layer name, integer of start frame, integer of end frame)</returns>
572 /// <since_tizen> 7 </since_tizen>
573 public List<Tuple<string, int, int>> GetContentInfo()
575 if (currentStates.contentInfo != null)
577 return currentStates.contentInfo;
582 PropertyMap imageMap = base.Image;
583 if (imageMap != null)
585 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
586 PropertyMap contentMap = new PropertyMap();
587 if (val?.Get(ref contentMap) == true)
589 currentStates.contentInfo = new List<Tuple<string, int, int>>();
590 for (uint i = 0; i < contentMap.Count(); i++)
592 using PropertyKey propertyKey = contentMap.GetKeyAt(i);
593 string key = propertyKey.StringKey;
595 using PropertyValue arrVal = contentMap.GetValue(i);
596 using PropertyArray arr = new PropertyArray();
600 using PropertyValue start = arr.GetElementAt(0);
601 start?.Get(out startFrame);
604 using PropertyValue end = arr.GetElementAt(1);
605 end?.Get(out endFrame);
607 NUILog.Debug($"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
609 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
611 currentStates.contentInfo?.Add(item);
615 contentMap.Dispose();
620 return currentStates.contentInfo;
624 /// A marker has its start frame and end frame.
625 /// Animation will play between the start frame and the end frame of the marker if one marker is specified.
626 /// 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. *
628 /// <param name="marker1">First marker</param>
629 /// <param name="marker2">Second marker</param>
630 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
631 [EditorBrowsable(EditorBrowsableState.Never)]
632 public void SetMinMaxFrameByMarker(string marker1, string marker2 = null)
634 if (currentStates.mark1 != marker1 || currentStates.mark2 != marker2)
636 NUILog.Debug($"< [{GetId()}] SetMinMaxFrameByMarker({marker1}, {marker2})");
638 currentStates.changed = true;
639 currentStates.mark1 = marker1;
640 currentStates.mark2 = marker2;
642 using PropertyArray array = new PropertyArray();
643 using PropertyValue mark1 = new PropertyValue(currentStates.mark1);
644 array.PushBack(mark1);
645 using PropertyValue mark2 = new PropertyValue(currentStates.mark2);
648 array.PushBack(mark2);
651 using PropertyMap map = new PropertyMap();
652 using PropertyValue range = new PropertyValue(array);
653 map.Add(ImageVisualProperty.PlayRange, range);
654 using PropertyValue actionProperty = new PropertyValue(map);
655 DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, actionProperty);
656 NUILog.Debug($" [{GetId()}] currentStates.mark1:{currentStates.mark1}, mark2:{currentStates.mark2} >");
663 /// <returns>Tuple of Min and Max frames</returns>
664 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
665 [EditorBrowsable(EditorBrowsableState.Never)]
666 public Tuple<int, int> GetMinMaxFrame()
668 NUILog.Debug($"< [{GetId()}] GetMinMaxFrame()! total frame={currentStates.totalFrame}");
670 using PropertyMap map = Image;
673 using PropertyValue val = map.Find(ImageVisualProperty.PlayRange);
676 using PropertyArray array = new PropertyArray();
679 uint cnt = array.Count();
680 int item1 = -1, item2 = -1;
681 for (uint i = 0; i < cnt; i++)
683 using PropertyValue v = array.GetElementAt(i);
685 if (v.Get(out intRet))
687 NUILog.Debug($"Got play range of string [{i}]: {intRet}");
699 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#1");
702 NUILog.Debug($" [{GetId()}] GetMinMaxFrame(min:{item1}, max:{item2})! >");
703 return new Tuple<int, int>(item1, item2);
707 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#2");
708 return new Tuple<int, int>(-1, -1);
711 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
712 [EditorBrowsable(EditorBrowsableState.Never)]
713 public void DoActionExtension(LottieAnimationViewDynamicProperty info)
715 dynamicPropertyCallbackId++;
717 weakReferencesOfLottie?.Add(dynamicPropertyCallbackId, new WeakReference<LottieAnimationView>(this));
718 InternalSavedDynamicPropertyCallbacks?.Add(dynamicPropertyCallbackId, info.Callback);
720 Interop.View.DoActionExtension(SwigCPtr, ImageView.Property.IMAGE, SetDynamicProperty, dynamicPropertyCallbackId, info.KeyPath, (int)info.Property, Marshal.GetFunctionPointerForDelegate<System.Delegate>(rootCallback));
722 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
725 private void CleanCallbackDictionaries()
727 if (weakReferencesOfLottie?.Count > 0 && InternalSavedDynamicPropertyCallbacks != null)
729 foreach (var key in InternalSavedDynamicPropertyCallbacks?.Keys)
731 if (weakReferencesOfLottie.ContainsKey(key))
733 weakReferencesOfLottie.Remove(key);
737 InternalSavedDynamicPropertyCallbacks?.Clear();
738 InternalSavedDynamicPropertyCallbacks = null;
742 /// Update lottie-image-relative properties synchronously.
743 /// After call this API, All image properties updated.
745 [EditorBrowsable(EditorBrowsableState.Never)]
746 protected override void UpdateImage()
748 if (!imagePropertyUpdatedFlag) return;
750 // Update currentStates properties to cachedImagePropertyMap
751 if(currentStates.changed)
753 UpdateImage(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount), false);
754 UpdateImage(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction), false);
755 UpdateImage(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode), false);
756 UpdateImage(ImageVisualProperty.RedrawInScalingDown, new PropertyValue(currentStates.redrawInScalingDown), false);
758 // Do not cache PlayRange and TotalFrameNumber into cachedImagePropertyMap.
759 // (To keep legacy implements behaviour)
760 currentStates.changed = false;
763 using PropertyValue animatiedImage = new PropertyValue((int)Visual.Type.AnimatedVectorImage);
764 UpdateImage(Visual.Property.Type, animatiedImage, false);
770 /// Update NUI cached animated image visual property map by inputed property map.
771 /// And call base.MergeCachedImageVisualProperty()
774 /// For performance issue, we will collect only "cachedLottieAnimationPropertyKeyList" hold in this class.
776 [EditorBrowsable(EditorBrowsableState.Never)]
777 protected override void MergeCachedImageVisualProperty(PropertyMap map)
779 if (map == null) return;
780 if (cachedImagePropertyMap == null)
782 cachedImagePropertyMap = new PropertyMap();
784 foreach (var key in cachedLottieAnimationPropertyKeyList)
786 PropertyValue value = map.Find(key);
789 // Update-or-Insert new value
790 cachedImagePropertyMap[key] = value;
793 base.MergeCachedImageVisualProperty(map);
798 #region Event, Enum, Struct, ETC
800 /// Animation finished event.
802 /// <since_tizen> 7 </since_tizen>
803 public event EventHandler Finished
807 if (finishedEventHandler == null)
809 NUILog.Debug($"<[{GetId()}] Finished eventhandler added>");
810 visualEventSignalCallback = onVisualEventSignal;
811 using VisualEventSignal visualEvent = VisualEventSignal();
812 visualEvent.Connect(visualEventSignalCallback);
814 finishedEventHandler += value;
818 NUILog.Debug($"<[{GetId()}] Finished eventhandler removed>");
819 finishedEventHandler -= value;
820 if (finishedEventHandler == null && visualEventSignalCallback != null)
822 using VisualEventSignal visualEvent = VisualEventSignal();
823 visualEvent.Disconnect(visualEventSignalCallback);
824 if (visualEvent?.Empty() == true)
826 visualEventSignalCallback = null;
833 /// Enumeration for what state the vector animation is in
835 /// <since_tizen> 7 </since_tizen>
836 public enum PlayStateType
841 /// <since_tizen> 7 </since_tizen>
844 /// Vector Animation has stopped
846 /// <since_tizen> 7 </since_tizen>
849 /// The vector animation is playing
851 /// <since_tizen> 7 </since_tizen>
854 /// The vector animation is paused
856 /// <since_tizen> 7 </since_tizen>
861 /// Enumeration for what to do when the animation is stopped.
863 /// <since_tizen> 7 </since_tizen>
864 public enum StopBehaviorType
867 /// When the animation is stopped, the current frame is shown.
869 /// <since_tizen> 7 </since_tizen>
872 /// When the animation is stopped, the min frame (first frame) is shown.
874 /// <since_tizen> 7 </since_tizen>
877 /// When the animation is stopped, the max frame (last frame) is shown.
879 /// <since_tizen> 7 </since_tizen>
884 /// Enumeration for what looping mode is in.
886 /// <since_tizen> 7 </since_tizen>
887 public enum LoopingModeType
890 /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
892 /// <since_tizen> 7 </since_tizen>
895 /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
897 /// <since_tizen> 7 </since_tizen>
904 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
905 [EditorBrowsable(EditorBrowsableState.Never)]
906 public enum VectorProperty
909 /// Fill color of the object, Type of <see cref="Vector3"/>
911 [EditorBrowsable(EditorBrowsableState.Never)]
915 /// Fill opacity of the object, Type of float
917 [EditorBrowsable(EditorBrowsableState.Never)]
921 /// Stroke color of the object, Type of <see cref="Vector3"/>
923 [EditorBrowsable(EditorBrowsableState.Never)]
927 /// Stroke opacity of the object, Type of float
929 [EditorBrowsable(EditorBrowsableState.Never)]
933 /// Stroke width of the object, Type of float
935 [EditorBrowsable(EditorBrowsableState.Never)]
939 /// Transform anchor of the Layer and Group object, Type of <see cref="Vector2"/>
941 [EditorBrowsable(EditorBrowsableState.Never)]
945 /// Transform position of the Layer and Group object, Type of <see cref="Vector2"/>
947 [EditorBrowsable(EditorBrowsableState.Never)]
951 /// Transform scale of the Layer and Group object, Type of <see cref="Vector2"/>, Value range of [0..100]
953 [EditorBrowsable(EditorBrowsableState.Never)]
957 /// Transform rotation of the Layer and Group object, Type of float, Value range of [0..360] in degrees
959 [EditorBrowsable(EditorBrowsableState.Never)]
963 /// Transform opacity of the Layer and Group object, Type of float
965 [EditorBrowsable(EditorBrowsableState.Never)]
969 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
970 [EditorBrowsable(EditorBrowsableState.Never)]
971 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
972 public delegate PropertyValue DynamicPropertyCallbackType(int returnType, uint frameNumber);
973 #endregion Event, Enum, Struct, ETC
977 internal class VisualEventSignalArgs : EventArgs
979 public int VisualIndex
991 internal event EventHandler<VisualEventSignalArgs> VisualEvent
995 if (visualEventSignalHandler == null)
997 visualEventSignalCallback = onVisualEventSignal;
998 using VisualEventSignal visualEvent = VisualEventSignal();
999 visualEvent?.Connect(visualEventSignalCallback);
1001 visualEventSignalHandler += value;
1005 visualEventSignalHandler -= value;
1006 if (visualEventSignalHandler == null && visualEventSignalCallback != null)
1008 using VisualEventSignal visualEvent = VisualEventSignal();
1009 visualEvent?.Disconnect(visualEventSignalCallback);
1010 if (visualEvent?.Empty() == true)
1012 visualEventSignalCallback = null;
1018 internal void EmitVisualEventSignal(int visualIndex, int signalId)
1020 using VisualEventSignal visualEvent = VisualEventSignal();
1021 visualEvent?.Emit(this, visualIndex, signalId);
1024 internal VisualEventSignal VisualEventSignal()
1026 VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
1027 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1031 internal Dictionary<int, DynamicPropertyCallbackType> InternalSavedDynamicPropertyCallbacks = new Dictionary<int, DynamicPropertyCallbackType>();
1033 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1034 internal delegate void RootCallbackType(int id, int returnType, uint frameNumber, ref float val1, ref float val2, ref float val3);
1036 internal RootCallbackType rootCallback = RootCallback;
1038 static internal void RootCallback(int id, int returnType, uint frameNumber, ref float val1, ref float val2, ref float val3)
1040 WeakReference<LottieAnimationView> current = null;
1041 LottieAnimationView currentView = null;
1042 DynamicPropertyCallbackType currentCallback = null;
1043 PropertyValue ret = null;
1045 if (weakReferencesOfLottie.TryGetValue(id, out current))
1047 if (current.TryGetTarget(out currentView))
1049 if (currentView != null && currentView.InternalSavedDynamicPropertyCallbacks != null &&
1050 currentView.InternalSavedDynamicPropertyCallbacks.TryGetValue(id, out currentCallback))
1052 ret = currentCallback?.Invoke(returnType, frameNumber);
1056 Tizen.Log.Error("NUI", "can't find the callback in LottieAnimationView, just return here!");
1062 Tizen.Log.Error("NUI", "can't find the callback in LottieAnimationView, just return here!");
1068 Tizen.Log.Error("NUI", "can't find LottieAnimationView by id, just return here!");
1074 case (int)(VectorProperty.FillColor):
1075 case (int)(VectorProperty.StrokeColor):
1076 Vector3 tmpVector3 = new Vector3(-1, -1, -1);
1077 if ((ret != null) && ret.Get(tmpVector3))
1079 val1 = tmpVector3.X;
1080 val2 = tmpVector3.Y;
1081 val3 = tmpVector3.Z;
1083 tmpVector3.Dispose();
1086 case (int)(VectorProperty.TransformAnchor):
1087 case (int)(VectorProperty.TransformPosition):
1088 case (int)(VectorProperty.TransformScale):
1089 Vector2 tmpVector2 = new Vector2(-1, -1);
1090 if ((ret != null) && ret.Get(tmpVector2))
1092 val1 = tmpVector2.X;
1093 val2 = tmpVector2.Y;
1095 tmpVector2.Dispose();
1098 case (int)(VectorProperty.FillOpacity):
1099 case (int)(VectorProperty.StrokeOpacity):
1100 case (int)(VectorProperty.StrokeWidth):
1101 case (int)(VectorProperty.TransformRotation):
1102 case (int)(VectorProperty.TransformOpacity):
1103 float tmpFloat = -1;
1104 if ((ret != null) && ret.Get(out tmpFloat))
1120 // Collection of lottie-image-sensitive properties.
1121 private static readonly List<int> cachedLottieAnimationPropertyKeyList = new List<int> {
1122 ImageVisualProperty.LoopCount,
1123 ImageVisualProperty.StopBehavior,
1124 ImageVisualProperty.LoopingMode,
1125 ImageVisualProperty.RedrawInScalingDown,
1128 private struct states
1130 internal string url;
1131 internal int loopCount;
1132 internal LoopingModeType loopMode;
1133 internal StopBehaviorType stopEndAction;
1134 internal int framePlayRangeMin;
1135 internal int framePlayRangeMax;
1136 internal int totalFrame;
1137 internal float scale;
1138 internal PlayStateType playState;
1139 internal List<Tuple<string, int, int>> contentInfo;
1140 internal string mark1, mark2;
1141 internal bool redrawInScalingDown;
1142 internal bool changed;
1144 private states currentStates;
1146 private const string tag = "NUITEST";
1147 private event EventHandler finishedEventHandler;
1149 private void OnFinished()
1151 NUILog.Debug($"<[{GetId()}] OnFinished()>");
1152 finishedEventHandler?.Invoke(this, null);
1155 private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
1159 if (targetView != IntPtr.Zero)
1161 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
1164 NUILog.Debug($"targetView is not null! name={v.Name}");
1168 NUILog.Debug($"target is something created from dali");
1171 VisualEventSignalArgs e = new VisualEventSignalArgs();
1172 e.VisualIndex = visualIndex;
1173 e.SignalId = signalId;
1174 visualEventSignalHandler?.Invoke(this, e);
1176 NUILog.Debug($"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
1179 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
1180 private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
1182 private VisualEventSignalCallbackType visualEventSignalCallback;
1183 private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
1185 static private int dynamicPropertyCallbackId = 0;
1186 //static private Dictionary<int, DynamicPropertyCallbackType> dynamicPropertyCallbacks = new Dictionary<int, DynamicPropertyCallbackType>();
1187 static private Dictionary<int, WeakReference<LottieAnimationView>> weakReferencesOfLottie = new Dictionary<int, WeakReference<LottieAnimationView>>();
1189 private void debugPrint()
1191 NUILog.Debug($"===================================");
1192 NUILog.Debug($"<[{GetId()}] get currentStates : url={currentStates.url}, loopCount={currentStates.loopCount}, \nframePlayRangeMin/Max({currentStates.framePlayRangeMin},{currentStates.framePlayRangeMax}) ");
1193 NUILog.Debug($" get from Property : StopBehavior={StopBehavior}, LoopMode={LoopingMode}, LoopCount={LoopCount}, PlayState={PlayState}");
1194 NUILog.Debug($" RedrawInScalingDown={RedrawInScalingDown} >");
1195 NUILog.Debug($"===================================");
1202 /// A class containing frame informations for a LottieAnimationView.
1204 [EditorBrowsable(EditorBrowsableState.Never)]
1205 public class LottieFrameInfo : ICloneable
1208 /// Creates a new instance with a playing range.
1210 [EditorBrowsable(EditorBrowsableState.Never)]
1211 public LottieFrameInfo(int startFrame, int endFrame)
1213 StartFrame = startFrame;
1214 EndFrame = endFrame;
1218 /// Creates a new instance with a still image frame.
1220 [EditorBrowsable(EditorBrowsableState.Never)]
1221 public LottieFrameInfo(int stillImageFrame) : this(stillImageFrame, stillImageFrame)
1226 /// Create a new instance from a pair notation.
1228 [EditorBrowsable(EditorBrowsableState.Never)]
1229 public static implicit operator LottieFrameInfo((int, int) pair)
1231 return new LottieFrameInfo(pair.Item1, pair.Item2);
1235 /// Create a new instance from an int value.
1237 [EditorBrowsable(EditorBrowsableState.Never)]
1238 public static implicit operator LottieFrameInfo(int stillImageFrame)
1240 return new LottieFrameInfo(stillImageFrame);
1244 /// Create a new instance from string.
1245 /// Possible input : "0, 10", "10"
1247 [EditorBrowsable(EditorBrowsableState.Never)]
1248 public static implicit operator LottieFrameInfo(string pair)
1255 string[] parts = pair.Split(',');
1256 if (parts.Length == 1)
1258 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture));
1260 else if (parts.Length == 2)
1262 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture), Int32.Parse(parts[1].Trim(), CultureInfo.InvariantCulture));
1265 Tizen.Log.Error("NUI", $"Can not convert string {pair} to LottieFrameInfo");
1270 /// The start frame of the lottie animation.
1272 [EditorBrowsable(EditorBrowsableState.Never)]
1273 public int StartFrame { get; }
1276 /// The end frame of the lottie animation.
1278 [EditorBrowsable(EditorBrowsableState.Never)]
1279 public int EndFrame { get; }
1282 /// Create LottieFrameInfo struct with animation range information
1284 [EditorBrowsable(EditorBrowsableState.Never)]
1285 public static LottieFrameInfo CreateAnimationRange(int startFrame, int endFrame)
1287 return new LottieFrameInfo(startFrame, endFrame);
1291 /// Create LottieFrameInfo struct with still image information
1293 [EditorBrowsable(EditorBrowsableState.Never)]
1294 public static LottieFrameInfo CreateStillImage(int stillImageFrame)
1296 return new LottieFrameInfo(stillImageFrame, stillImageFrame);
1301 /// Whether this LottieFrameInfo represents one frame or more.
1303 [EditorBrowsable(EditorBrowsableState.Never)]
1304 public bool IsStillImage()
1306 return StartFrame == EndFrame;
1311 /// Play specified LottieAnimationView with this frame information.
1313 /// <param name="lottieView">The target LottieAnimationView to play.</param>
1314 /// <param name="noPlay">Whether go direct to the EndFrame. It is false by default.</param>
1315 [EditorBrowsable(EditorBrowsableState.Never)]
1316 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062: Validate arguments of public methods", Justification = "The null checking is done by BeReadyToShow()")]
1317 public void Show(LottieAnimationView lottieView, bool noPlay = false)
1319 if (!BeReadyToShow(lottieView))
1324 lottieView.SetMinMaxFrame(StartFrame, Math.Min(EndFrame, lottieView.TotalFrame - 1));
1326 if (IsStillImage() || noPlay)
1328 lottieView.CurrentFrame = EndFrame;
1332 lottieView.CurrentFrame = StartFrame;
1338 [EditorBrowsable(EditorBrowsableState.Never)]
1339 public object Clone() => new LottieFrameInfo(StartFrame, EndFrame);
1341 private bool BeReadyToShow(LottieAnimationView lottieView)
1343 // Validate input lottieView
1344 if (null == lottieView || lottieView.PlayState == LottieAnimationView.PlayStateType.Invalid)
1349 // Stop if it was playing
1350 if (lottieView.PlayState == LottieAnimationView.PlayStateType.Playing)
1359 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
1360 [EditorBrowsable(EditorBrowsableState.Never)]
1361 public struct LottieAnimationViewDynamicProperty : IEquatable<LottieAnimationViewDynamicProperty>
1363 [EditorBrowsable(EditorBrowsableState.Never)]
1364 public string KeyPath { get; set; }
1366 [EditorBrowsable(EditorBrowsableState.Never)]
1367 public LottieAnimationView.VectorProperty Property { get; set; }
1369 [EditorBrowsable(EditorBrowsableState.Never)]
1370 public LottieAnimationView.DynamicPropertyCallbackType Callback { get; set; }
1372 public override bool Equals(object obj)
1374 if (obj is LottieAnimationViewDynamicProperty target)
1376 if (KeyPath == target.KeyPath && Property == target.Property && Callback == target.Callback)
1384 public override int GetHashCode()
1386 return base.GetHashCode();
1389 public static bool operator ==(LottieAnimationViewDynamicProperty left, LottieAnimationViewDynamicProperty right)
1391 return left.Equals(right);
1394 public static bool operator !=(LottieAnimationViewDynamicProperty left, LottieAnimationViewDynamicProperty right)
1396 return !(left == right);
1399 public bool Equals(LottieAnimationViewDynamicProperty other)
1403 if (KeyPath == other.KeyPath && Property == other.Property && Callback == other.Callback)