[NUI] Cache url when we call SetImage + Make way to skip visual creation
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / AnimatedImageView.cs
index db53ca4..e878923 100755 (executable)
 using System.Collections.Generic;
 using System.ComponentModel;
 
-#if (NUI_DEBUG_ON)
-using tlog = Tizen.Log;
-#endif
-
 namespace Tizen.NUI.BaseComponents
 {
     /// <summary>
@@ -29,9 +25,24 @@ namespace Tizen.NUI.BaseComponents
     /// </summary>
     // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
     [EditorBrowsable(EditorBrowsableState.Never)]
-    public class AnimatedImageView : ImageView
+    public partial class AnimatedImageView : ImageView
     {
-        #region Constructor, Distructor, Dispose
+        #region Internal
+        #endregion Internal
+
+        #region Private
+        // Collection of animated-image-sensitive properties.
+        private static readonly List<int> cachedAnimatedImagePropertyKeyList = new List<int> {
+            ImageVisualProperty.BatchSize,
+            ImageVisualProperty.CacheSize,
+            ImageVisualProperty.FrameDelay,
+            ImageVisualProperty.LoopCount,
+            ImageVisualProperty.StopBehavior,
+        };
+        private List<string> resourceURLs = new List<string>();
+        #endregion Private
+
+        #region Constructor, Destructor, Dispose
         /// <summary>
         /// Construct AnimatedImageView
         /// </summary>
@@ -39,7 +50,9 @@ namespace Tizen.NUI.BaseComponents
         [EditorBrowsable(EditorBrowsableState.Never)]
         public AnimatedImageView() : base()
         {
-            mDirtyFlag = true;
+            ActionPlay = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet();
+            ActionPause = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet();
+            ActionStop = Interop.AnimatedImageView.AnimatedImageVisualActionStopGet();
         }
 
         /// <summary>
@@ -60,56 +73,57 @@ namespace Tizen.NUI.BaseComponents
             //because the execution order of Finalizes is non-deterministic.
             base.Dispose(type);
         }
-        #endregion Constructor, Distructor, Dispose
+        #endregion Constructor, Destructor, Dispose
 
         #region Property
         /// <summary>
-        /// Image URL for Animated-GIF
+        ///  Image URL list for Image-Array
         /// </summary>
         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public new string ResourceUrl
+        public List<string> URLs
         {
             get
             {
-                return mUrl;
-            }
-            set
-            {
-                mDirtyFlag = true;
-                mUrl = value;
+                return resourceURLs;
             }
         }
 
         /// <summary>
-        ///  Image URL list for Image-Array
+        /// Defines the batch size for pre-loading images in the Image-Array animation.
+        /// number of images to pre-load before starting to play. Default value: 1.
         /// </summary>
         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public List<string> URLs
+        public int BatchSize
         {
             get
             {
-                return mResourceURLs;
+                return (int)GetValue(BatchSizeProperty);
+            }
+            set
+            {
+                SetValue(BatchSizeProperty, value);
+                NotifyPropertyChanged();
             }
         }
 
-        /// <summary>
-        /// Defines the batch size for pre-loading images in the Image-Array animation.
-        /// number of images to pre-load before starting to play. Default value: 1.
-        /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public int BatchSize
+        private int InternalBatchSize
         {
             get
             {
-                return mBatchSize;
+                int ret = 1;
+
+                PropertyValue batchSize = GetCachedImageVisualProperty(ImageVisualProperty.BatchSize);
+                batchSize?.Get(out ret);
+                batchSize?.Dispose();
+
+                return ret;
             }
             set
             {
-                mDirtyFlag = true;
-                mBatchSize = value;
+                using PropertyValue setValue = new PropertyValue(value);
+                UpdateImage(ImageVisualProperty.BatchSize, setValue);
             }
         }
 
@@ -127,12 +141,31 @@ namespace Tizen.NUI.BaseComponents
         {
             get
             {
-                return mCacheSize;
+                return (int)GetValue(CacheSizeProperty);
+            }
+            set
+            {
+                SetValue(CacheSizeProperty, value);
+                NotifyPropertyChanged();
+            }
+        }
+
+        private int InternalCacheSize
+        {
+            get
+            {
+                int ret = 1;
+
+                PropertyValue cacheSize = GetCachedImageVisualProperty(ImageVisualProperty.CacheSize);
+                cacheSize?.Get(out ret);
+                cacheSize?.Dispose();
+
+                return ret;
             }
             set
             {
-                mDirtyFlag = true;
-                mCacheSize = value;
+                using PropertyValue setValue = new PropertyValue(value);
+                UpdateImage(ImageVisualProperty.CacheSize, setValue);
             }
         }
 
@@ -149,12 +182,31 @@ namespace Tizen.NUI.BaseComponents
         {
             get
             {
-                return mFrameDelay;
+                return (int)GetValue(FrameDelayProperty);
             }
             set
             {
-                mDirtyFlag = true;
-                mFrameDelay = value;
+                SetValue(FrameDelayProperty, value);
+                NotifyPropertyChanged();
+            }
+        }
+
+        private int InternalFrameDelay
+        {
+            get
+            {
+                int ret = 0;
+
+                PropertyValue frameDelay = GetCachedImageVisualProperty(ImageVisualProperty.FrameDelay);
+                frameDelay?.Get(out ret);
+                frameDelay?.Dispose();
+
+                return ret;
+            }
+            set
+            {
+                using PropertyValue setValue = new PropertyValue(value);
+                UpdateImage(ImageVisualProperty.FrameDelay, setValue);
             }
         }
 
@@ -167,131 +219,254 @@ namespace Tizen.NUI.BaseComponents
         {
             get
             {
-                return mLoopCount;
+                return (int)GetValue(LoopCountProperty);
             }
             set
             {
-                mDirtyFlag = true;
-                mLoopCount = value;
+                SetValue(LoopCountProperty, value);
+                NotifyPropertyChanged();
+            }
+        }
+
+        private int InternalLoopCount
+        {
+            get
+            {
+                int ret = -1;
+
+                PropertyValue loopCount = GetCachedImageVisualProperty(ImageVisualProperty.LoopCount);
+                loopCount?.Get(out ret);
+                loopCount?.Dispose();
+
+                return ret;
+            }
+            set
+            {
+                using PropertyValue setValue = new PropertyValue(value);
+                UpdateImage(ImageVisualProperty.LoopCount, setValue);
             }
         }
-        #endregion Property
 
-        #region Method
         /// <summary>
-        /// To make the properies be set. This should be called after the properties are set.
+        /// Sets or gets the stop behavior.
         /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public void SetValues()
+        public StopBehaviorType StopBehavior
         {
-            if (mDirtyFlag == false)
+            get
             {
-                return;
+                return (StopBehaviorType)GetValue(StopBehaviorProperty);
+            }
+            set
+            {
+                SetValue(StopBehaviorProperty, value);
+                NotifyPropertyChanged();
+            }
+        }
+
+        private StopBehaviorType InternalStopBehavior
+        {
+            get
+            {
+                int ret = 0;
+
+                PropertyValue stopBehavior = GetCachedImageVisualProperty(ImageVisualProperty.StopBehavior);
+                stopBehavior?.Get(out ret);
+                stopBehavior?.Dispose();
+
+                return (StopBehaviorType)ret;
+            }
+            set
+            {
+                using PropertyValue setValue = new PropertyValue((int)value);
+                UpdateImage(ImageVisualProperty.StopBehavior, setValue);
             }
-            mDirtyFlag = false;
+        }
 
-            PropertyMap tMap = new PropertyMap();
-            PropertyValue animatiedImage = new PropertyValue((int)Visual.Type.AnimatedImage);
-            tMap.Insert(Visual.Property.Type, animatiedImage);
-            if (mResourceURLs?.Count != 0)
+        /// <summary>
+        /// Get the number of total frames
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int TotalFrame
+        {
+            get
             {
-                PropertyArray mArray = new PropertyArray();
-                PropertyArray returnedArr = new PropertyArray();
-                PropertyValue index = new PropertyValue();
-                foreach (var iter in mResourceURLs)
+                int ret = -1;
+                PropertyMap map = base.Image;
+                if (map != null)
                 {
-                    index = new PropertyValue(iter);
-                    returnedArr = mArray.Add(index);
+                    PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
+                    if (val != null)
+                    {
+                        if (val.Get(out ret))
+                        {
+                            return ret;
+                        }
+                    }
                 }
-                index.Dispose();
-                returnedArr.Dispose();
-                PropertyValue array = new PropertyValue(mArray);
-                tMap.Insert(ImageVisualProperty.URL, array);
-                PropertyValue batchSize = new PropertyValue(mBatchSize);
-                tMap.Insert(ImageVisualProperty.BatchSize, batchSize);
-                PropertyValue cacheSize = new PropertyValue(mCacheSize);
-                tMap.Insert(ImageVisualProperty.CacheSize, cacheSize);
-                PropertyValue frameDelay = new PropertyValue(mFrameDelay);
-                tMap.Insert(ImageVisualProperty.FrameDelay, frameDelay);
-                PropertyValue loopCount = new PropertyValue(mLoopCount);
-                tMap.Insert(ImageVisualProperty.LoopCount, loopCount);
-
-                loopCount.Dispose();
-                frameDelay.Dispose();
-                cacheSize.Dispose();
-                batchSize.Dispose();
-                mArray.Dispose();
-                array.Dispose();
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Set or get the current frame. When setting a specific frame, it is displayed as a still image.
+        /// </summary>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int CurrentFrame
+        {
+            get
+            {
+                return (int)GetValue(CurrentFrameProperty);
             }
-            else
+            set
             {
-                PropertyValue url = new PropertyValue(mUrl);
-                tMap.Insert(ImageVisualProperty.URL, url);
-                url.Dispose();
+                SetValue(CurrentFrameProperty, value);
+                NotifyPropertyChanged();
             }
+        }
 
-            mMap = tMap;
-            PropertyValue map = new PropertyValue(mMap);
-            SetProperty(ImageView.Property.IMAGE, map);
-            map.Dispose();
+        private int InternalCurrentFrame
+        {
+            set
+            {
+                // Sync as current properties
+                UpdateImage();
 
-            tMap.Dispose();
-            animatiedImage.Dispose();
+                DoAction(ImageView.Property.IMAGE, ActionJumpTo, new PropertyValue(value));
+            }
+            get
+            {
+                int ret = -1;
+                PropertyMap map = base.Image;
+                if (map != null)
+                {
+                    PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
+                    if (val != null)
+                    {
+                        if (val.Get(out ret))
+                        {
+                            return ret;
+                        }
+                    }
+                }
+                return ret;
+            }
         }
 
         /// <summary>
-        /// Play animation
+        /// Actions property value to Jump to the specified frame.
+        /// This property can be redefined by child class if it use different value.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected int ActionJumpTo { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionJumpToGet();
+        #endregion Property
+
+        #region Method
+        /// <summary>
+        /// To make the properies be set. This should be called after the properties are set.
         /// </summary>
         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public new void Play()
+        public void SetValues()
         {
-            SetValues();
-            base.Play();
+            // This API assume that Animated relative properties setuped forcely.
+            imagePropertyUpdatedFlag = true;
+
+            // Sync as current properties
+            UpdateImage();
         }
 
         /// <summary>
-        /// Pause animation. Currently pause and stop are same
+        /// Update animated-image-relative properties synchronously.
+        /// After call this API, All image properties updated.
         /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public new void Pause()
+        protected override void UpdateImage()
         {
-            SetValues();
-            base.Pause();
+            if (!imagePropertyUpdatedFlag) return;
+
+            if (resourceURLs != null && resourceURLs.Count != 0)
+            {
+                using (PropertyArray indexPropertyArray = new PropertyArray())
+                {
+                    PropertyArray returnedArr = new PropertyArray();
+                    foreach (var iter in resourceURLs)
+                    {
+                        using (PropertyValue index = new PropertyValue(iter))
+                        {
+                            returnedArr = indexPropertyArray.Add(index);
+                        }
+                    }
+                    returnedArr.Dispose();
+                    using PropertyValue arrayProperty = new PropertyValue(indexPropertyArray);
+
+                    // Trigger the ImageView so that we have something update
+                    UpdateImage(ImageVisualProperty.URL, arrayProperty, false);
+                }
+            }
+
+            using PropertyValue animatiedImage = new PropertyValue((int)Visual.Type.AnimatedImage);
+            UpdateImage(Visual.Property.Type, animatiedImage, false);
+
+            base.UpdateImage();
         }
 
         /// <summary>
-        /// Stop animation. Currently pause and stop are same
+        /// Update NUI cached animated image visual property map by inputed property map.
+        /// And call base.MergeCachedImageVisualProperty()
         /// </summary>
-        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+        /// <remarks>
+        /// For performance issue, we will collect only "cachedAnimatedImagePropertyKeyList" hold in this class.
+        /// </remarks>
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public new void Stop()
+        protected override void MergeCachedImageVisualProperty(PropertyMap map)
         {
-            SetValues();
-            base.Stop();
+            if (map == null) return;
+            if (cachedImagePropertyMap == null)
+            {
+                cachedImagePropertyMap = new PropertyMap();
+            }
+            foreach (var key in cachedAnimatedImagePropertyKeyList)
+            {
+                PropertyValue value = map.Find(key);
+                if (value != null)
+                {
+                    // Update-or-Insert new value
+                    cachedImagePropertyMap[key] = value;
+                }
+            }
+            base.MergeCachedImageVisualProperty(map);
         }
         #endregion Method
 
-
         #region Event, Enum, Struct, ETC
-        #endregion Event, Enum, Struct, ETC
-
-
-        #region Internal
-        #endregion Internal
 
+        /// <summary>
+        /// Enumeration for what to do when the animation is stopped.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public enum StopBehaviorType
+        {
+            /// <summary>
+            /// When the animation is stopped, the current frame is shown.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            CurrentFrame,
+            /// <summary>
+            /// When the animation is stopped, the min frame (first frame) is shown.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            MinimumFrame,
+            /// <summary>
+            /// When the animation is stopped, the max frame (last frame) is shown.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            MaximumFrame
+        }
 
-        #region Private
-        string mUrl = "";
-        List<string> mResourceURLs = new List<string>();
-        int mBatchSize = 1;
-        int mCacheSize = 1;
-        int mFrameDelay = 0;
-        int mLoopCount = -1;
-        bool mDirtyFlag = false;
-        PropertyMap mMap;
-        #endregion Private
+        #endregion Event, Enum, Struct, ETC
     }
 }