2 * Copyright(c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 using global::System.Runtime.InteropServices;
20 using System.ComponentModel;
21 using System.Collections.Generic;
24 using tlog = Tizen.Log;
27 namespace Tizen.NUI.BaseComponents
30 /// LottieAnimationView renders an animated vector image (Lottie file).
32 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
33 [EditorBrowsable(EditorBrowsableState.Never)]
34 public class LottieAnimationView : ImageView
36 #region Constructor, Distructor, Dispose
38 /// LottieAnimationView
40 /// <param name="scale">The factor of scaling image, default : 1.0f</param>
41 /// <param name="shown">false : Not displayed (hidden), true : displayed (shown), default : true</param>
42 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
43 [EditorBrowsable(EditorBrowsableState.Never)]
44 public LottieAnimationView(float scale = 1.0f, bool shown = true) : base()
46 tlog.Fatal(tag, $"< constructor GetId={GetId()} >");
47 currentStates.url = "";
48 currentStates.frame = -1;
49 currentStates.loopCount = 1;
50 currentStates.loopMode = LoopingModeType.Restart;
51 currentStates.stopEndAction = StopBehaviorType.CurrentFrame;
52 currentStates.framePlayRangeMin = -1;
53 currentStates.framePlayRangeMax = -1;
54 currentStates.changed = false;
55 currentStates.totalFrame = -1;
56 currentStates.scale = scale;
61 /// Dispose(DisposeTypes type)
63 /// <param name="type"></param>
64 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
65 [EditorBrowsable(EditorBrowsableState.Never)]
66 protected override void Dispose(DisposeTypes type)
73 tlog.Fatal(tag, $"<[{GetId()}] type={type}");
75 //Release your own unmanaged resources here.
76 //You should not access any managed member here except static instance.
77 //because the execution order of Finalizes is non-deterministic.
79 //disconnect event signal
80 if (finishedEventHandler != null && visualEventSignalCallback != null)
82 VisualEventSignal().Disconnect(visualEventSignalCallback);
83 finishedEventHandler = null;
84 tlog.Fatal(tag, $"disconnect event signal");
88 tlog.Fatal(tag, $"[{GetId()}]>");
90 #endregion Constructor, Distructor, Dispose
97 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
98 [EditorBrowsable(EditorBrowsableState.Never)]
103 string ret = (value == null ? "" : value);
104 currentStates.url = ret;
105 currentStates.changed = true;
107 tlog.Fatal(tag, $"<[{GetId()}]SET url={currentStates.url}");
109 PropertyMap map = new PropertyMap();
110 map.Add(Visual.Property.Type, new PropertyValue((int)DevelVisual.Type.AnimatedVectorImage))
111 .Add(ImageVisualProperty.URL, new PropertyValue(currentStates.url))
112 .Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount))
113 .Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction))
114 .Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
117 currentStates.contentInfo = null;
119 if(currentStates.scale != 1.0f)
121 Scale = new Vector3(currentStates.scale, currentStates.scale, 0.0f);
123 tlog.Fatal(tag, $"<[{GetId()}]>");
127 string ret = currentStates.url;
128 tlog.Fatal(tag, $"<[{GetId()}] GET");
130 PropertyMap map = Image;
133 PropertyValue val = map.Find(ImageVisualProperty.URL);
136 if (val.Get(out ret))
138 tlog.Fatal(tag, $"gotten url={ret} >");
143 Tizen.Log.Error(tag, $" [ERROR][{GetId()}](LottieAnimationView) Fail to get URL from dali >");
149 /// The playing state
151 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
152 [EditorBrowsable(EditorBrowsableState.Never)]
153 public PlayStateType PlayState
157 tlog.Fatal(tag, $"< Get!");
158 PropertyMap map = base.Image;
162 PropertyValue val = map.Find(ImageVisualProperty.PlayState);
165 if (val.Get(out ret))
167 currentStates.playState = (PlayStateType)ret;
168 tlog.Fatal(tag, $"gotten play state={ret} >");
169 return currentStates.playState;
173 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}]Fail to get PlayState from dali currentStates.playState={currentStates.playState}>");
174 return currentStates.playState;
179 /// The number of total frame
181 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
182 [EditorBrowsable(EditorBrowsableState.Never)]
183 public int TotalFrame
188 PropertyMap map = Image;
191 PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
194 if (val.Get(out ret))
196 //tlog.Fatal(tag, $"TotalFrameNumber get! ret={ret}");
197 currentStates.totalFrame = ret;
202 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get TotalFrameNumber from dali>");
208 /// CurrentFrameNumber
210 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
211 [EditorBrowsable(EditorBrowsableState.Never)]
212 public int CurrentFrame
216 currentStates.frame = value;
217 tlog.Fatal(tag, $"<[{GetId()}]SET frame={currentStates.frame}>");
218 DoAction(vectorImageVisualIndex, (int)actionType.jumpTo, new PropertyValue(currentStates.frame));
223 PropertyMap map = Image;
226 PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
229 if (val.Get(out ret))
231 //tlog.Fatal(tag, $"CurrentFrameNumber get! val={ret}");
236 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get CurrentFrameNumber from dali!! ret={ret}>");
242 /// Loop Mode of animation.
244 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
245 [EditorBrowsable(EditorBrowsableState.Never)]
246 public LoopingModeType LoopingMode
250 currentStates.loopMode = (LoopingModeType)value;
251 currentStates.changed = true;
253 tlog.Fatal(tag, $"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
254 PropertyMap map = new PropertyMap();
255 map.Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
256 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
260 //tlog.Fatal(tag, $"LoopMode get!");
261 PropertyMap map = base.Image;
265 PropertyValue val = map.Find(ImageVisualProperty.LoopingMode);
268 if (val.Get(out ret))
270 //tlog.Fatal(tag, $"gotten LoopMode={ret}");
271 if (ret != (int)currentStates.loopMode && ret > 0)
273 tlog.Fatal(tag, $" [ERROR][{GetId()}](LottieAnimationView) different LoopMode! gotten={ret}, loopMode={currentStates.loopMode}");
275 currentStates.loopMode = (LoopingModeType)ret;
276 return (LoopingModeType)ret;
280 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get loopMode from dali>");
281 return currentStates.loopMode;
288 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
289 [EditorBrowsable(EditorBrowsableState.Never)]
294 currentStates.changed = true;
295 currentStates.loopCount = value;
296 tlog.Fatal(tag, $"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
297 PropertyMap map = new PropertyMap();
298 map.Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount));
299 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
303 //tlog.Fatal(tag, $"LoopCount get!");
304 PropertyMap map = base.Image;
308 PropertyValue val = map.Find(ImageVisualProperty.LoopCount);
311 if (val.Get(out ret))
313 //tlog.Fatal(tag, $"gotten loop count={ret}");
314 if (ret != currentStates.loopCount && ret > 0)
316 tlog.Fatal(tag, $"<[ERROR][{GetId()}](LottieAnimationView) different loop count! gotten={ret}, loopCount={currentStates.loopCount}>");
318 currentStates.loopCount = ret;
319 return currentStates.loopCount;
323 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get LoopCount from dali currentStates.loopCount={currentStates.loopCount}>");
324 return currentStates.loopCount;
329 /// Stop Behavior (Stop End Action)
331 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
332 [EditorBrowsable(EditorBrowsableState.Never)]
333 public StopBehaviorType StopBehavior
337 currentStates.stopEndAction = (StopBehaviorType)value;
338 currentStates.changed = true;
340 tlog.Fatal(tag, $"<[{GetId()}]SET val={currentStates.stopEndAction}>");
341 PropertyMap map = new PropertyMap();
342 map.Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction));
343 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
347 //tlog.Fatal(tag, $"StopBehavior get!");
348 PropertyMap map = base.Image;
352 PropertyValue val = map.Find(ImageVisualProperty.StopBehavior);
355 if (val.Get(out ret))
357 //tlog.Fatal(tag, $"gotten StopBehavior={ret}");
358 if (ret != (int)currentStates.stopEndAction)
360 tlog.Fatal(tag, $"<[ERROR][{GetId()}](LottieAnimationView) different StopBehavior! gotten={ret}, StopBehavior={currentStates.stopEndAction}>");
362 currentStates.stopEndAction = (StopBehaviorType)ret;
363 return (StopBehaviorType)ret;
367 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get StopBehavior from dali>");
368 return currentStates.stopEndAction;
376 /// SetMinMaxFrame(int startFrame, int endFrame)
378 /// <param name="minFrame"></param>
379 /// <param name="maxFrame"></param>
380 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
381 [EditorBrowsable(EditorBrowsableState.Never)]
382 public void SetMinMaxFrame(int minFrame, int maxFrame)
384 tlog.Fatal(tag, $"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
386 currentStates.changed = true;
387 currentStates.framePlayRangeMin = minFrame;
388 currentStates.framePlayRangeMax = maxFrame;
390 PropertyArray array = new PropertyArray();
391 array.PushBack(new PropertyValue(currentStates.framePlayRangeMin));
392 array.PushBack(new PropertyValue(currentStates.framePlayRangeMax));
394 PropertyMap map = new PropertyMap();
395 map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
396 DoAction(vectorImageVisualIndex, (int)actionType.updateProperty, new PropertyValue(map));
397 tlog.Fatal(tag, $" [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
403 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
404 [EditorBrowsable(EditorBrowsableState.Never)]
405 public new void Play()
407 tlog.Fatal(tag, $"<[{GetId()}] Play()");
410 tlog.Fatal(tag, $"[{GetId()}]>");
416 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
417 [EditorBrowsable(EditorBrowsableState.Never)]
418 public new void Pause()
420 tlog.Fatal(tag, $"<[{GetId()}] Pause()>");
423 tlog.Fatal(tag, $"[{GetId()}]>");
429 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
430 [EditorBrowsable(EditorBrowsableState.Never)]
431 public new void Stop()
433 tlog.Fatal(tag, $"<[{GetId()}] Stop()");
436 tlog.Fatal(tag, $"[{GetId()}]>");
442 /// <returns>list of Tuple (string of layer name, integer of start frame, integer of end frame)</returns>
443 [EditorBrowsable(EditorBrowsableState.Never)]
444 public List<Tuple<string, int, int>> GetContentInfo()
446 tlog.Fatal(tag, $"<");
447 if(currentStates.contentInfo != null)
449 return currentStates.contentInfo;
452 PropertyMap imageMap = base.Image;
453 PropertyMap contentMap = new PropertyMap();
454 if (imageMap != null)
456 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
459 if (val.Get(contentMap))
461 for (uint i = 0; i < contentMap.Count(); i++)
463 string key = contentMap.GetKeyAt(i).StringKey;
464 PropertyArray arr = new PropertyArray();
465 contentMap.GetValue(i).Get(arr);
468 int startFrame, endFrame;
469 arr.GetElementAt(0).Get(out startFrame);
470 arr.GetElementAt(1).Get(out endFrame);
472 tlog.Fatal(tag, $"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
474 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame );
476 currentStates.contentInfo?.Add(item);
482 tlog.Fatal(tag, $">");
483 return currentStates.contentInfo;
488 #region Event, Enum, Struct, ETC
490 /// Animation finished event
492 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
493 [EditorBrowsable(EditorBrowsableState.Never)]
494 public event EventHandler Finished
498 if (finishedEventHandler == null)
500 tlog.Fatal(tag, $"<[{GetId()}] Finished eventhandler added>");
501 visualEventSignalCallback = onVisualEventSignal;
502 VisualEventSignal().Connect(visualEventSignalCallback);
504 finishedEventHandler += value;
508 tlog.Fatal(tag, $"<[{GetId()}] Finished eventhandler removed>");
509 finishedEventHandler -= value;
510 if (finishedEventHandler == null && visualEventSignalCallback != null)
512 VisualEventSignal().Disconnect(visualEventSignalCallback);
518 /// Enumeration for what state the vector animation is in
520 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
521 [EditorBrowsable(EditorBrowsableState.Never)]
522 public enum PlayStateType
527 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
528 [EditorBrowsable(EditorBrowsableState.Never)]
531 /// Vector Animation has stopped
533 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
534 [EditorBrowsable(EditorBrowsableState.Never)]
537 /// The vector animation is playing
539 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
540 [EditorBrowsable(EditorBrowsableState.Never)]
543 /// The vector animation is paused
545 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
546 [EditorBrowsable(EditorBrowsableState.Never)]
551 /// @brief Enumeration for what to do when the animation is stopped.
553 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
554 [EditorBrowsable(EditorBrowsableState.Never)]
555 public enum StopBehaviorType
558 /// When the animation is stopped, the current frame is shown.
560 [EditorBrowsable(EditorBrowsableState.Never)]
561 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
564 /// When the animation is stopped, the min frame (first frame) is shown.
566 [EditorBrowsable(EditorBrowsableState.Never)]
567 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
570 /// When the animation is stopped, the max frame (last frame) is shown.
572 [EditorBrowsable(EditorBrowsableState.Never)]
573 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
578 /// @brief Enumeration for what looping mode is in.
580 [EditorBrowsable(EditorBrowsableState.Never)]
581 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
582 public enum LoopingModeType
585 /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
587 [EditorBrowsable(EditorBrowsableState.Never)]
588 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
591 /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
593 [EditorBrowsable(EditorBrowsableState.Never)]
594 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
597 #endregion Event, Enum, Struct, ETC
601 internal class VisualEventSignalArgs : EventArgs
603 public int VisualIndex
615 internal event EventHandler<VisualEventSignalArgs> VisualEvent
619 if (visualEventSignalHandler == null)
621 visualEventSignalCallback = onVisualEventSignal;
622 VisualEventSignal().Connect(visualEventSignalCallback);
624 visualEventSignalHandler += value;
628 visualEventSignalHandler -= value;
629 if (visualEventSignalHandler == null && VisualEventSignal().Empty() == false)
631 VisualEventSignal().Disconnect(visualEventSignalCallback);
636 internal void EmitVisualEventSignal(int visualIndex, int signalId)
638 VisualEventSignal().Emit(this, visualIndex, signalId);
641 internal VisualEventSignal VisualEventSignal()
643 VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
644 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
651 private struct states
655 internal int loopCount;
656 internal LoopingModeType loopMode;
657 internal StopBehaviorType stopEndAction;
658 internal int framePlayRangeMin;
659 internal int framePlayRangeMax;
660 internal bool changed;
661 internal int totalFrame;
662 internal float scale;
663 internal PlayStateType playState;
664 internal List<Tuple<string, int, int>> contentInfo;
666 private states currentStates;
668 private enum actionType
677 private struct DevelVisual
681 AnimatedGradient = Visual.Type.AnimatedImage + 1,
682 AnimatedVectorImage = Visual.Type.AnimatedImage + 2,
686 private const string tag = "NUITEST";
687 private const int vectorImageVisualIndex = 10000000 + 1000 + 2;
688 private event EventHandler finishedEventHandler;
690 private void OnFinished()
692 tlog.Fatal(tag, $"<[{GetId()}] OnFinished()>");
693 finishedEventHandler?.Invoke(this, null);
696 private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
700 if (targetView != IntPtr.Zero)
702 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
705 tlog.Fatal(tag, $"targetView is not null! name={v.Name}");
709 tlog.Fatal(tag, $"target is something created from dali");
712 VisualEventSignalArgs e = new VisualEventSignalArgs();
713 e.VisualIndex = visualIndex;
714 e.SignalId = signalId;
715 visualEventSignalHandler?.Invoke(this, e);
717 tlog.Fatal(tag, $"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
720 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
721 private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
723 private VisualEventSignalCallbackType visualEventSignalCallback;
724 private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
726 private void debugPrint()
728 tlog.Fatal(tag, $"===================================");
729 tlog.Fatal(tag, $"<[{GetId()}] get currentStates : url={currentStates.url}, loopCount={currentStates.loopCount}, framePlayRangeMin/Max({currentStates.framePlayRangeMin},{currentStates.framePlayRangeMax}) ");
730 tlog.Fatal(tag, $" get from Property : StopBehavior={StopBehavior}, LoopMode={LoopingMode}, LoopCount={LoopCount}, PlayState={PlayState} >");
731 tlog.Fatal(tag, $"===================================");