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
32 #region Constructor, Destructor, Dispose
34 /// LottieAnimationView constructor
36 /// <param name="scale">The factor of scaling image, default : 1.0f</param>
37 /// <param name="shown">false : not displayed (hidden), true : displayed (shown), default : true</param>
39 /// If the shown parameter is false, the animation is not visible even if the LottieAnimationView instance is created.
43 /// LottieAnimationView myLottie = new LottieAnimationView();
44 /// LottieAnimationView myLottie2 = new LottieAnimationView(2.0f);
45 /// LottieAnimationView myLottie3 = new LottieAnimationView(1.0f, false);
48 /// <since_tizen> 7 </since_tizen>
49 public LottieAnimationView(float scale = 1.0f, bool shown = true) : base()
51 NUILog.Debug($"< constructor GetId={GetId()} >");
52 currentStates.url = "";
53 currentStates.frame = -1;
54 currentStates.loopCount = 1;
55 currentStates.loopMode = LoopingModeType.Restart;
56 currentStates.stopEndAction = StopBehaviorType.CurrentFrame;
57 currentStates.framePlayRangeMin = -1;
58 currentStates.framePlayRangeMax = -1;
59 currentStates.changed = false;
60 currentStates.totalFrame = -1;
61 currentStates.scale = scale;
62 currentStates.redrawInScalingDown = true;
67 /// Dispose(DisposeTypes type)
69 /// <param name="type"></param>
70 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
71 [EditorBrowsable(EditorBrowsableState.Never)]
72 protected override void Dispose(DisposeTypes type)
79 //Release your own unmanaged resources here.
80 //You should not access any managed member here except static instance.
81 //because the execution order of Finalizes is non-deterministic.
83 //disconnect event signal
84 if (finishedEventHandler != null && visualEventSignalCallback != null)
86 VisualEventSignal().Disconnect(visualEventSignalCallback);
87 finishedEventHandler = null;
88 NUILog.Debug($"disconnect event signal");
93 #endregion Constructor, Destructor, Dispose
98 /// Set or Get resource URL of Lottie file.
100 /// <since_tizen> 7 </since_tizen>
105 return GetValue(URLProperty) as string;
109 SetValue(URLProperty, value);
110 NotifyPropertyChanged();
114 private string InternalURL
118 string ret = (value == null ? "" : value);
119 currentStates.url = ret;
120 currentStates.changed = true;
122 NUILog.Debug($"<[{GetId()}]SET url={currentStates.url}");
124 PropertyMap map = new PropertyMap();
125 map.Add(Visual.Property.Type, new PropertyValue((int)DevelVisual.Type.AnimatedVectorImage))
126 .Add(ImageVisualProperty.URL, new PropertyValue(currentStates.url))
127 .Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount))
128 .Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction))
129 .Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
132 currentStates.contentInfo = null;
134 if (currentStates.scale != 1.0f)
136 Scale = new Vector3(currentStates.scale, currentStates.scale, 0.0f);
138 NUILog.Debug($"<[{GetId()}]>");
142 string ret = currentStates.url;
143 NUILog.Debug($"<[{GetId()}] GET");
145 PropertyMap map = Image;
148 PropertyValue val = map.Find(ImageVisualProperty.URL);
151 if (val.Get(out ret))
153 NUILog.Debug($"gotten url={ret} >");
158 Tizen.Log.Error(tag, $" [ERROR][{GetId()}](LottieAnimationView) Fail to get URL from dali >");
164 /// Gets the playing state
166 /// <since_tizen> 7 </since_tizen>
167 public PlayStateType PlayState
171 NUILog.Debug($"< Get!");
172 PropertyMap map = base.Image;
176 PropertyValue val = map.Find(ImageVisualProperty.PlayState);
179 if (val.Get(out ret))
181 currentStates.playState = (PlayStateType)ret;
182 NUILog.Debug($"gotten play state={ret} >");
188 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}]Fail to get PlayState from dali currentStates.playState={currentStates.playState}>");
190 return currentStates.playState;
195 /// Get the number of total frames
197 /// <since_tizen> 7 </since_tizen>
198 public int TotalFrame
203 PropertyMap map = Image;
206 PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
209 if (val.Get(out ret))
211 //NUILog.Debug( $"TotalFrameNumber get! ret={ret}");
212 currentStates.totalFrame = ret;
217 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get TotalFrameNumber from dali>");
223 /// Set or get the current frame. When setting a specific frame, it is displayed as a still image.
226 /// 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.
229 /// We assume that the animation in myLottie.json file has 100 frames originally. If so, its frame index will be 0 - 99.
231 /// LottieAnimationView myLottie = new LottieAnimationView();
232 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
233 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
234 /// myLottie.CurrentFrame = 200; //display 99 frame
235 /// myLottie.SetMinMaxFrame(10, 20);
236 /// myLottie.CurrentFrame = 15; //display 15 frame
237 /// myLottie.CurrentFrame = 50; //display 20 frame, because the MinMax is set (10,20) above
240 /// <since_tizen> 7 </since_tizen>
241 public int CurrentFrame
245 return (int)GetValue(CurrentFrameProperty);
249 SetValue(CurrentFrameProperty, value);
250 NotifyPropertyChanged();
254 private int InternalCurrentFrame
258 currentStates.frame = value;
259 NUILog.Debug($"<[{GetId()}]SET frame={currentStates.frame}>");
260 DoAction(ImageView.Property.IMAGE, (int)actionType.jumpTo, new PropertyValue(currentStates.frame));
265 PropertyMap map = Image;
268 PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
271 if (val.Get(out ret))
273 //NUILog.Debug( $"CurrentFrameNumber get! val={ret}");
278 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get CurrentFrameNumber from dali!! ret={ret}>");
284 /// Sets or gets the looping mode of Lottie animation.
286 /// <since_tizen> 7 </since_tizen>
287 public LoopingModeType LoopingMode
291 return (LoopingModeType)GetValue(LoopingModeProperty);
295 SetValue(LoopingModeProperty, value);
296 NotifyPropertyChanged();
300 private LoopingModeType InternalLoopingMode
304 currentStates.loopMode = (LoopingModeType)value;
305 currentStates.changed = true;
307 NUILog.Debug($"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
308 PropertyMap map = new PropertyMap();
309 map.Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
310 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
314 //NUILog.Debug( $"LoopMode get!");
315 PropertyMap map = base.Image;
319 PropertyValue val = map.Find(ImageVisualProperty.LoopingMode);
322 if (val.Get(out ret))
324 //NUILog.Debug( $"gotten LoopMode={ret}");
325 if (ret != (int)currentStates.loopMode && ret > 0)
327 NUILog.Debug($" [ERROR][{GetId()}](LottieAnimationView) different LoopMode! gotten={ret}, loopMode={currentStates.loopMode}");
329 currentStates.loopMode = (LoopingModeType)ret;
330 return (LoopingModeType)ret;
334 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get loopMode from dali>");
335 return currentStates.loopMode;
340 /// Sets or gets the loop count.
343 /// The minus value means the infinite loop count.
347 /// LottieAnimationView myLottie = new LottieAnimationView();
348 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
349 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
350 /// myLottie.LoopCount = -1; //infinite loop
352 /// myLottie.Stop(); //it plays continuously unless Stop() is called
353 /// myLottie.LoopCount = 2;
354 /// myLottie.Play(); //it plays only 2 times and stops automatically
357 /// <since_tizen> 7 </since_tizen>
362 return (int)GetValue(LoopCountProperty);
366 SetValue(LoopCountProperty, value);
367 NotifyPropertyChanged();
371 private int InternalLoopCount
375 currentStates.changed = true;
376 currentStates.loopCount = value;
377 NUILog.Debug($"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
378 PropertyMap map = new PropertyMap();
379 map.Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount));
380 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
384 //NUILog.Debug( $"LoopCount get!");
385 PropertyMap map = base.Image;
389 PropertyValue val = map.Find(ImageVisualProperty.LoopCount);
392 if (val.Get(out ret))
394 //NUILog.Debug( $"gotten loop count={ret}");
395 if (ret != currentStates.loopCount && ret > 0)
397 NUILog.Debug($"<[ERROR][{GetId()}](LottieAnimationView) different loop count! gotten={ret}, loopCount={currentStates.loopCount}>");
399 currentStates.loopCount = ret;
400 return currentStates.loopCount;
404 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get LoopCount from dali currentStates.loopCount={currentStates.loopCount}>");
405 return currentStates.loopCount;
410 /// Sets or gets the stop behavior.
412 /// <since_tizen> 7 </since_tizen>
413 public StopBehaviorType StopBehavior
417 return (StopBehaviorType)GetValue(StopBehaviorProperty);
421 SetValue(StopBehaviorProperty, value);
422 NotifyPropertyChanged();
426 private StopBehaviorType InternalStopBehavior
430 currentStates.stopEndAction = (StopBehaviorType)value;
431 currentStates.changed = true;
433 NUILog.Debug($"<[{GetId()}]SET val={currentStates.stopEndAction}>");
434 PropertyMap map = new PropertyMap();
435 map.Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction));
436 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
440 //NUILog.Debug( $"StopBehavior get!");
441 PropertyMap map = base.Image;
445 PropertyValue val = map.Find(ImageVisualProperty.StopBehavior);
448 if (val.Get(out ret))
450 //NUILog.Debug( $"gotten StopBehavior={ret}");
451 if (ret != (int)currentStates.stopEndAction)
453 NUILog.Debug($"<[ERROR][{GetId()}](LottieAnimationView) different StopBehavior! gotten={ret}, StopBehavior={currentStates.stopEndAction}>");
455 currentStates.stopEndAction = (StopBehaviorType)ret;
456 return (StopBehaviorType)ret;
460 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get StopBehavior from dali>");
461 return currentStates.stopEndAction;
466 /// Whether to redraw the image when the visual is scaled down.
470 /// It is used in the AnimatedVectorImageVisual.The default is true.
472 [EditorBrowsable(EditorBrowsableState.Never)]
473 public bool RedrawInScalingDown
477 return (bool)GetValue(RedrawInScalingDownProperty);
481 SetValue(RedrawInScalingDownProperty, value);
482 NotifyPropertyChanged();
486 private bool InternalRedrawInScalingDown
490 currentStates.changed = true;
491 currentStates.redrawInScalingDown = value;
492 NUILog.Debug($"<[{GetId()}]SET currentStates.redrawInScalingDown={currentStates.redrawInScalingDown}>");
493 PropertyMap map = new PropertyMap();
494 map.Add(ImageVisualProperty.RedrawInScalingDown, new PropertyValue(currentStates.redrawInScalingDown));
495 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
499 PropertyMap map = base.Image;
503 PropertyValue val = map.Find(ImageVisualProperty.RedrawInScalingDown);
506 if (val.Get(out ret))
508 if (ret != currentStates.redrawInScalingDown)
510 NUILog.Debug($"<[ERROR][{GetId()}](LottieAnimationView) different redrawInScalingDown! gotten={ret}, redrawInScalingDown={currentStates.redrawInScalingDown}>");
512 currentStates.redrawInScalingDown = ret;
513 return currentStates.redrawInScalingDown;
517 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get redrawInScalingDown from dali currentStates.redrawInScalingDown={currentStates.redrawInScalingDown}>");
518 return currentStates.redrawInScalingDown;
526 /// Set the minimum and the maximum frame.
528 /// <param name="minFrame">minimum frame</param>
529 /// <param name="maxFrame">maximum frame</param>
530 /// <since_tizen> 7 </since_tizen>
531 public void SetMinMaxFrame(int minFrame, int maxFrame)
533 NUILog.Debug($"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
535 currentStates.changed = true;
536 currentStates.framePlayRangeMin = minFrame;
537 currentStates.framePlayRangeMax = maxFrame;
539 PropertyArray array = new PropertyArray();
540 array.PushBack(new PropertyValue(currentStates.framePlayRangeMin));
541 array.PushBack(new PropertyValue(currentStates.framePlayRangeMax));
543 PropertyMap map = new PropertyMap();
544 map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
545 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
546 NUILog.Debug($" [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
552 /// <since_tizen> 7 </since_tizen>
553 public new void Play()
555 NUILog.Debug($"<[{GetId()}] Play()");
558 NUILog.Debug($"[{GetId()}]>");
564 /// <since_tizen> 7 </since_tizen>
565 public new void Pause()
567 NUILog.Debug($"<[{GetId()}] Pause()>");
570 NUILog.Debug($"[{GetId()}]>");
576 /// <since_tizen> 7 </since_tizen>
577 public new void Stop()
579 NUILog.Debug($"<[{GetId()}] Stop()");
582 NUILog.Debug($"[{GetId()}]>");
586 /// Get the list of layers' information such as the start frame and the end frame in the Lottie file.
588 /// <returns>List of Tuple (string of layer name, integer of start frame, integer of end frame)</returns>
589 /// <since_tizen> 7 </since_tizen>
590 public List<Tuple<string, int, int>> GetContentInfo()
593 if (currentStates.contentInfo != null)
595 return currentStates.contentInfo;
598 PropertyMap imageMap = base.Image;
599 PropertyMap contentMap = new PropertyMap();
600 if (imageMap != null)
602 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
605 if (val.Get(contentMap))
607 currentStates.contentInfo = new List<Tuple<string, int, int>>();
608 for (uint i = 0; i < contentMap.Count(); i++)
610 string key = contentMap.GetKeyAt(i).StringKey;
611 PropertyArray arr = new PropertyArray();
612 contentMap.GetValue(i).Get(arr);
615 int startFrame, endFrame;
616 arr.GetElementAt(0).Get(out startFrame);
617 arr.GetElementAt(1).Get(out endFrame);
619 NUILog.Debug($"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
621 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
623 currentStates.contentInfo?.Add(item);
630 return currentStates.contentInfo;
634 /// A marker has its start frame and end frame.
635 /// Animation will play between the start frame and the end frame of the marker if one marker is specified.
636 /// 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. *
638 /// <param name="marker1">First marker</param>
639 /// <param name="marker2">Second marker</param>
640 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
641 [EditorBrowsable(EditorBrowsableState.Never)]
642 public void SetMinMaxFrameByMarker(string marker1, string marker2 = null)
644 NUILog.Debug($"< [{GetId()}] SetMinMaxFrameByMarker({marker1}, {marker2})");
646 currentStates.changed = true;
647 currentStates.mark1 = marker1;
648 currentStates.mark2 = marker2;
650 PropertyArray array = new PropertyArray();
651 array.PushBack(new PropertyValue(currentStates.mark1));
654 array.PushBack(new PropertyValue(currentStates.mark2));
657 PropertyMap map = new PropertyMap();
658 map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
659 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
660 NUILog.Debug($" [{GetId()}] currentStates.mark1:{currentStates.mark1}, mark2:{currentStates.mark2} >");
666 /// <returns>Tuple of Min and Max frames</returns>
667 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
668 [EditorBrowsable(EditorBrowsableState.Never)]
669 public Tuple<int, int> GetMinMaxFrame()
671 NUILog.Debug($"< [{GetId()}] GetMinMaxFrame()! total frame={currentStates.totalFrame}");
673 PropertyMap map = Image;
676 PropertyValue val = map.Find(ImageVisualProperty.PlayRange);
679 PropertyArray array = new PropertyArray();
682 uint cnt = array.Count();
683 int item1 = -1, item2 = -1;
684 for (uint i = 0; i < cnt; i++)
686 PropertyValue v = array.GetElementAt(i);
688 if (v.Get(out intRet))
690 NUILog.Debug($"Got play range of string [{i}]: {intRet}");
702 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#1");
705 NUILog.Debug($" [{GetId()}] GetMinMaxFrame(min:{item1}, max:{item2})! >");
706 return new Tuple<int, int>(item1, item2);
710 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#2");
711 return new Tuple<int, int>(-1, -1);
716 #region Event, Enum, Struct, ETC
718 /// Animation finished event.
720 /// <since_tizen> 7 </since_tizen>
721 public event EventHandler Finished
725 if (finishedEventHandler == null)
727 NUILog.Debug($"<[{GetId()}] Finished eventhandler added>");
728 visualEventSignalCallback = onVisualEventSignal;
729 VisualEventSignal().Connect(visualEventSignalCallback);
731 finishedEventHandler += value;
735 NUILog.Debug($"<[{GetId()}] Finished eventhandler removed>");
736 finishedEventHandler -= value;
737 if (finishedEventHandler == null && visualEventSignalCallback != null)
739 VisualEventSignal().Disconnect(visualEventSignalCallback);
745 /// Enumeration for what state the vector animation is in
747 /// <since_tizen> 7 </since_tizen>
748 public enum PlayStateType
753 /// <since_tizen> 7 </since_tizen>
756 /// Vector Animation has stopped
758 /// <since_tizen> 7 </since_tizen>
761 /// The vector animation is playing
763 /// <since_tizen> 7 </since_tizen>
766 /// The vector animation is paused
768 /// <since_tizen> 7 </since_tizen>
773 /// Enumeration for what to do when the animation is stopped.
775 /// <since_tizen> 7 </since_tizen>
776 public enum StopBehaviorType
779 /// When the animation is stopped, the current frame is shown.
781 /// <since_tizen> 7 </since_tizen>
784 /// When the animation is stopped, the min frame (first frame) is shown.
786 /// <since_tizen> 7 </since_tizen>
789 /// When the animation is stopped, the max frame (last frame) is shown.
791 /// <since_tizen> 7 </since_tizen>
796 /// Enumeration for what looping mode is in.
798 /// <since_tizen> 7 </since_tizen>
799 public enum LoopingModeType
802 /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
804 /// <since_tizen> 7 </since_tizen>
807 /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
809 /// <since_tizen> 7 </since_tizen>
812 #endregion Event, Enum, Struct, ETC
816 internal class VisualEventSignalArgs : EventArgs
818 public int VisualIndex
830 internal event EventHandler<VisualEventSignalArgs> VisualEvent
834 if (visualEventSignalHandler == null)
836 visualEventSignalCallback = onVisualEventSignal;
837 VisualEventSignal().Connect(visualEventSignalCallback);
839 visualEventSignalHandler += value;
843 visualEventSignalHandler -= value;
844 if (visualEventSignalHandler == null && VisualEventSignal().Empty() == false)
846 VisualEventSignal().Disconnect(visualEventSignalCallback);
851 internal void EmitVisualEventSignal(int visualIndex, int signalId)
853 VisualEventSignal().Emit(this, visualIndex, signalId);
856 internal VisualEventSignal VisualEventSignal()
858 VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
859 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
866 private struct states
870 internal int loopCount;
871 internal LoopingModeType loopMode;
872 internal StopBehaviorType stopEndAction;
873 internal int framePlayRangeMin;
874 internal int framePlayRangeMax;
875 internal bool changed;
876 internal int totalFrame;
877 internal float scale;
878 internal PlayStateType playState;
879 internal List<Tuple<string, int, int>> contentInfo;
880 internal string mark1, mark2;
881 internal bool redrawInScalingDown;
883 private states currentStates;
885 private enum actionType
894 private struct DevelVisual
898 AnimatedGradient = Visual.Type.AnimatedImage + 1,
899 AnimatedVectorImage = Visual.Type.AnimatedImage + 2,
903 private const string tag = "NUITEST";
904 private event EventHandler finishedEventHandler;
906 private void OnFinished()
908 NUILog.Debug($"<[{GetId()}] OnFinished()>");
909 finishedEventHandler?.Invoke(this, null);
912 private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
916 if (targetView != IntPtr.Zero)
918 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
921 NUILog.Debug($"targetView is not null! name={v.Name}");
925 NUILog.Debug($"target is something created from dali");
928 VisualEventSignalArgs e = new VisualEventSignalArgs();
929 e.VisualIndex = visualIndex;
930 e.SignalId = signalId;
931 visualEventSignalHandler?.Invoke(this, e);
933 NUILog.Debug($"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
936 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
937 private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
939 private VisualEventSignalCallbackType visualEventSignalCallback;
940 private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
942 private void debugPrint()
944 NUILog.Debug($"===================================");
945 NUILog.Debug($"<[{GetId()}] get currentStates : url={currentStates.url}, loopCount={currentStates.loopCount}, \nframePlayRangeMin/Max({currentStates.framePlayRangeMin},{currentStates.framePlayRangeMax}) ");
946 NUILog.Debug($" get from Property : StopBehavior={StopBehavior}, LoopMode={LoopingMode}, LoopCount={LoopCount}, PlayState={PlayState}");
947 NUILog.Debug($" RedrawInScalingDown={RedrawInScalingDown} >");
948 NUILog.Debug($"===================================");
954 /// A class containing frame informations for a LottieAnimationView.
956 [EditorBrowsable(EditorBrowsableState.Never)]
957 public class LottieFrameInfo : ICloneable
960 /// Creates a new instance with a playing range.
962 [EditorBrowsable(EditorBrowsableState.Never)]
963 public LottieFrameInfo(int startFrame, int endFrame)
965 StartFrame = startFrame;
970 /// Creates a new instance with a still image frame.
972 [EditorBrowsable(EditorBrowsableState.Never)]
973 public LottieFrameInfo(int stillImageFrame) : this(stillImageFrame, stillImageFrame)
978 /// Create a new instance from a pair notation.
980 [EditorBrowsable(EditorBrowsableState.Never)]
981 public static implicit operator LottieFrameInfo((int, int) pair)
983 return new LottieFrameInfo(pair.Item1, pair.Item2);
987 /// Create a new instance from an int value.
989 [EditorBrowsable(EditorBrowsableState.Never)]
990 public static implicit operator LottieFrameInfo(int stillImageFrame)
992 return new LottieFrameInfo(stillImageFrame);
996 /// Create a new instance from string.
997 /// Possible input : "0, 10", "10"
999 [EditorBrowsable(EditorBrowsableState.Never)]
1000 public static implicit operator LottieFrameInfo(string pair)
1007 string[] parts = pair.Split(',');
1008 if (parts.Length == 1)
1010 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture));
1012 else if (parts.Length == 2)
1014 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture), Int32.Parse(parts[1].Trim(), CultureInfo.InvariantCulture));
1017 Tizen.Log.Error("NUI", $"Can not convert string {pair} to LottieFrameInfo");
1022 /// The start frame of the lottie animation.
1024 [EditorBrowsable(EditorBrowsableState.Never)]
1025 public int StartFrame { get; }
1028 /// The end frame of the lottie animation.
1030 [EditorBrowsable(EditorBrowsableState.Never)]
1031 public int EndFrame { get; }
1034 /// Create LottieFrameInfo struct with animation range information
1036 [EditorBrowsable(EditorBrowsableState.Never)]
1037 public static LottieFrameInfo CreateAnimationRange(int startFrame, int endFrame)
1039 return new LottieFrameInfo(startFrame, endFrame);
1043 /// Create LottieFrameInfo struct with still image information
1045 [EditorBrowsable(EditorBrowsableState.Never)]
1046 public static LottieFrameInfo CreateStillImage(int stillImageFrame)
1048 return new LottieFrameInfo(stillImageFrame, stillImageFrame);
1053 /// Whether this LottieFrameInfo represents one frame or more.
1055 [EditorBrowsable(EditorBrowsableState.Never)]
1056 public bool IsStillImage()
1058 return StartFrame == EndFrame;
1063 /// Play specified LottieAnimationView with this frame information.
1065 /// <param name="lottieView">The target LottieAnimationView to play.</param>
1066 /// <param name="noPlay">Whether go direct to the EndFrame. It is false by default.</param>
1067 [EditorBrowsable(EditorBrowsableState.Never)]
1068 public void Show(LottieAnimationView lottieView, bool noPlay = false)
1070 if (!BeReadyToShow(lottieView))
1075 lottieView.SetMinMaxFrame(StartFrame, Math.Min(EndFrame, lottieView.TotalFrame - 1));
1077 if (IsStillImage() || noPlay)
1079 lottieView.CurrentFrame = EndFrame;
1083 lottieView.CurrentFrame = StartFrame;
1089 [EditorBrowsable(EditorBrowsableState.Never)]
1090 public object Clone() => new LottieFrameInfo(StartFrame, EndFrame);
1092 private bool BeReadyToShow(LottieAnimationView lottieView)
1094 // Validate input lottieView
1095 if (null == lottieView || lottieView.PlayState == LottieAnimationView.PlayStateType.Invalid)
1100 // Stop if it was playing
1101 if (lottieView.PlayState == LottieAnimationView.PlayStateType.Playing)