--- /dev/null
+/*
+ * Copyright(c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System.Collections.Generic;
+using System.ComponentModel;
+
+#if (NUI_DEBUG_ON)
+using tlog = Tizen.Log;
+#endif
+
+namespace Tizen.NUI.BaseComponents
+{
+ /// <summary>
+ /// AnimatedImageView is a class for displaying Animated-GIF and Image-Array
+ /// </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
+ {
+ #region Constructor, Distructor, Dispose
+ /// <summary>
+ /// Construct AnimatedImageView
+ /// </summary>
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public AnimatedImageView() : base()
+ {
+ mDirtyFlag = true;
+ }
+
+ /// <summary>
+ /// You can override it to clean-up your own resources
+ /// </summary>
+ /// <param name="type">DisposeTypes</param>
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void Dispose(DisposeTypes type)
+ {
+ if (disposed)
+ {
+ return;
+ }
+
+ //Release your own unmanaged resources here.
+ //You should not access any managed member here except static instance.
+ //because the execution order of Finalizes is non-deterministic.
+ base.Dispose(type);
+ }
+ #endregion Constructor, Distructor, Dispose
+
+ #region Property
+ /// <summary>
+ /// Image URL for Animated-GIF
+ /// </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
+ {
+ get
+ {
+ return mUrl;
+ }
+ set
+ {
+ mDirtyFlag = true;
+ mUrl = value;
+ }
+ }
+
+ /// <summary>
+ /// 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 List<string> URLs
+ {
+ get
+ {
+ return mResourceURLs;
+ }
+ set
+ {
+ mDirtyFlag = true;
+ mResourceURLs = value;
+ }
+ }
+
+ /// <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
+ {
+ get
+ {
+ return mBatchSize;
+ }
+ set
+ {
+ mDirtyFlag = true;
+ mBatchSize = value;
+ }
+ }
+
+ /// <summary>
+ /// Defines the cache size for loading images in the Image-Array animation.
+ /// number of images to keep cached ahead during playback. Default value: 1.
+ ///</summary>
+ ///<remarks>
+ /// cacheSize should be >= batchSize. If it isn't, then the cache will automatically be changed to batchSize.
+ /// because of the defaults, it is expected that the application developer tune the batch and cache sizes to their particular use case.
+ /// </remarks>
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int CacheSize
+ {
+ get
+ {
+ return mCacheSize;
+ }
+ set
+ {
+ mDirtyFlag = true;
+ mCacheSize = value;
+ }
+ }
+
+ /// <summary>
+ /// The number of milliseconds between each frame in the Image-Array animation.
+ /// The number of milliseconds between each frame.
+ /// </summary>
+ /// <remarks>
+ /// This is only used when URLs(multiple string) are provided.
+ /// </remarks>
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int FrameDelay
+ {
+ get
+ {
+ return mFrameDelay;
+ }
+ set
+ {
+ mDirtyFlag = true;
+ mFrameDelay = value;
+ }
+ }
+
+ /// <summary>
+ /// The number of looping.
+ /// </summary>
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int LoopCount
+ {
+ get
+ {
+ return mLoopCount;
+ }
+ set
+ {
+ mDirtyFlag = true;
+ mLoopCount = value;
+ }
+ }
+ #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 void SetValues()
+ {
+ if (mDirtyFlag == false)
+ {
+ return;
+ }
+ mDirtyFlag = false;
+
+ PropertyMap tMap = new PropertyMap();
+ tMap.Insert(Visual.Property.Type, new PropertyValue((int)Visual.Type.AnimatedImage));
+ if (mResourceURLs?.Count != 0)
+ {
+ PropertyArray tArr = new PropertyArray();
+ foreach (var iter in mResourceURLs)
+ {
+ tArr.Add(new PropertyValue(iter));
+ }
+ tMap.Insert(ImageVisualProperty.URL, new PropertyValue(tArr));
+ tMap.Insert(ImageVisualProperty.BatchSize, new PropertyValue(mBatchSize));
+ tMap.Insert(ImageVisualProperty.CacheSize, new PropertyValue(mCacheSize));
+ tMap.Insert(ImageVisualProperty.FrameDelay, new PropertyValue(mFrameDelay));
+ tMap.Insert(ImageVisualProperty.LoopCount, new PropertyValue(mLoopCount));
+
+ }
+ else
+ {
+ tMap.Insert(ImageVisualProperty.URL, new PropertyValue(mUrl));
+ }
+
+ mMap = tMap;
+ SetProperty(ImageView.Property.IMAGE, new PropertyValue(mMap));
+ }
+
+ /// <summary>
+ /// Play animation
+ /// </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()
+ {
+ SetValues();
+ base.Play();
+ }
+
+ /// <summary>
+ /// Pause animation. Currently pause and stop are same
+ /// </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()
+ {
+ SetValues();
+ base.Pause();
+ }
+
+ /// <summary>
+ /// Stop animation. Currently pause and stop are same
+ /// </summary>
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new void Stop()
+ {
+ SetValues();
+ base.Stop();
+ }
+ #endregion Method
+
+
+ #region Event, Enum, Struct, ETC
+ #endregion Event, Enum, Struct, ETC
+
+
+ #region Internal
+ #endregion Internal
+
+
+ #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;
+ const string tag = "NUITEST";
+ #endregion Private
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Components;
+
+namespace Tizen.NUI.Samples
+{
+ using tlog = Tizen.Log;
+ public class AnimatedImageViewTest : IExample
+ {
+ View root;
+ Box box, box2;
+ string resPath;
+ const string tag = "NUITEST";
+
+ internal static int GetRatio(int percent, float value)
+ {
+ return (int)(value * (percent / 100.0f));
+ }
+
+ public class Box : View
+ {
+ public TextLabel title;
+ public AnimatedImageView image;
+ public TextLabel status;
+ public Button but1;
+ public Button but2;
+ public Button but3;
+
+ public Box(Size2D boxSize, string boxTitle, string imageUrl)
+ {
+ this.Size2D = boxSize;
+ this.Margin = new Extents(0, 0, 20, 20);
+ this.BackgroundColor = Color.Magenta;
+
+ title = new TextLabel(boxTitle);
+ title.Size2D = new Size2D(boxSize.Width, GetRatio(20, boxSize.Height));
+ title.Position2D = new Position2D(0, 0);
+ title.MultiLine = true;
+ title.BackgroundColor = Color.Blue;
+ title.TextColor = Color.Yellow;
+ this.Add(title);
+
+ image = new AnimatedImageView();
+ image.Size2D = new Size2D(boxSize.Width, GetRatio(50, boxSize.Height));
+ image.Position2D = new Position2D(0, title.Size2D.Height);
+ image.ResourceUrl = imageUrl;
+ image.Play();
+ this.Add(image);
+
+ status = new TextLabel("Initialized");
+ status.Size2D = new Size2D(boxSize.Width, GetRatio(20, boxSize.Height));
+ status.Position2D = new Position2D(0, image.Position2D.Y + image.Size2D.Height);
+ status.MultiLine = true;
+ status.BackgroundColor = Color.White;
+ status.PointSize = 20;
+ this.Add(status);
+
+ ButtonStyle aStyle = new ButtonStyle
+ {
+ IsSelectable = true,
+ BackgroundImage = new Selector<string>
+ {
+ Normal = CommonResource.GetFHResourcePath() + "3. Button/[Button] App Primary Color/rectangle_toggle_btn_normal_24c447.png",
+ Selected = CommonResource.GetFHResourcePath() + "3. Button/[Button] App Primary Color/rectangle_point_btn_normal_24c447.png",
+ },
+ BackgroundImageBorder = new Selector<Rectangle> { All = new Rectangle(5, 5, 5, 5) },
+
+ Shadow = new ImageViewStyle
+ {
+ ResourceUrl = new Selector<string> { All = CommonResource.GetFHResourcePath() + "3. Button/rectangle_btn_shadow.png" },
+ Border = new Selector<Rectangle> { All = new Rectangle(5, 5, 5, 5) }
+ },
+
+ Overlay = new ImageViewStyle
+ {
+ ResourceUrl = new Selector<string> { Pressed = CommonResource.GetFHResourcePath() + "3. Button/rectangle_btn_press_overlay.png", Other = "" },
+ Border = new Selector<Rectangle> { All = new Rectangle(5, 5, 5, 5) },
+ },
+
+ Text = new TextLabelStyle
+ {
+ PointSize = new Selector<float?> { All = 20 },
+ HorizontalAlignment = HorizontalAlignment.Center,
+ VerticalAlignment = VerticalAlignment.Center,
+ WidthResizePolicy = ResizePolicyType.FillToParent,
+ HeightResizePolicy = ResizePolicyType.FillToParent,
+
+ TextColor = new Selector<Color>
+ {
+ Normal = new Color(0.141f, 0.769f, 0.278f, 1),
+ Selected = new Color(1, 1, 1, 1),
+ },
+ }
+ };
+ but1 = new Button(aStyle);
+ but1.Size2D = new Size2D(GetRatio(32, boxSize.Width), GetRatio(10, boxSize.Height));
+ but1.PositionUsesPivotPoint = true;
+ but1.ParentOrigin = Tizen.NUI.ParentOrigin.BottomLeft;
+ but1.PivotPoint = Tizen.NUI.ParentOrigin.BottomLeft;
+ but1.Style.Text.Text = new Selector<string>
+ {
+ Normal = "Button1 Normal",
+ Selected = "Button1 Selected",
+ Disabled = "Button2 Disabled",
+ };
+ this.Add(but1);
+
+ but2 = new Button(aStyle);
+ but2.Size2D = new Size2D(GetRatio(32, boxSize.Width), GetRatio(10, boxSize.Height));
+ but2.PositionUsesPivotPoint = true;
+ but2.ParentOrigin = Tizen.NUI.ParentOrigin.BottomCenter;
+ but2.PivotPoint = Tizen.NUI.ParentOrigin.BottomCenter;
+ but2.Style.Text.Text = new Selector<string>
+ {
+ Normal = "Button2 Normal",
+ Selected = "Button2 Selected",
+ Disabled = "Button2 Disabled",
+ };
+ this.Add(but2);
+
+ but3 = new Button(aStyle);
+ but3.Size2D = new Size2D(GetRatio(32, boxSize.Width), GetRatio(10, boxSize.Height));
+ but3.PositionUsesPivotPoint = true;
+ but3.ParentOrigin = Tizen.NUI.ParentOrigin.BottomRight;
+ but3.PivotPoint = Tizen.NUI.ParentOrigin.BottomRight;
+ but3.Style.Text.Text = new Selector<string>
+ {
+ Normal = "Button3 Normal",
+ Selected = "Button3 Selected",
+ Disabled = "Button2 Disabled",
+ };
+ this.Add(but3);
+ }
+
+ }
+ public void Activate()
+ {
+ resPath = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
+ root = new View();
+ root.BackgroundColor = Color.Green;
+ root.Size2D = new Size2D(Window.Instance.Size.Width, Window.Instance.Size.Height);
+ var layer = new LinearLayout();
+ layer.LinearAlignment = LinearLayout.Alignment.CenterHorizontal;
+ layer.LinearOrientation = LinearLayout.Orientation.Vertical;
+ root.Layout = layer;
+ Window.Instance.GetDefaultLayer().Add(root);
+
+ box = new Box(new Size2D(root.Size2D.Width, GetRatio(40, root.Size2D.Height)), "AGIF Test", resPath + "images/AGIF/dali-logo-anim.gif");
+ root.Add(box);
+
+ box.image.SetValues();
+ box.but1.ClickEvent += But1_ClickEvent;
+ box.but1.Style.Text.Text = new Selector<string>
+ {
+ Normal = "Pause !",
+ Selected = "Play !"
+ };
+ box.but2.ClickEvent += But2_ClickEvent;
+ box.but2.Style.Text.Text = new Selector<string>
+ {
+ Normal = "Stop !",
+ Selected = "Play !"
+ };
+ box.status.Text = "playing now";
+ box.but3.IsEnabled = false;
+
+ box2 = new Box(new Size2D(root.Size2D.Width, GetRatio(40, root.Size2D.Height)), "Image array Test", "");
+ root.Add(box2);
+
+ var list = new List<string>();
+ for (int i = 1; i <= 8; i++)
+ {
+ list.Add(resPath + "images/AGIF/dog-anim-00" + i + ".png");
+ }
+ box2.image.URLs = list;
+ box2.image.Play();
+
+ box2.but1.ClickEvent += But1_ClickEvent1;
+ box2.but1.Style.Text.Text = new Selector<string>
+ {
+ Normal = "Pause !",
+ Selected = "Play by reseting frame dalay and loop count!",
+ };
+ box2.but1.Style.Text.PointSize = new Selector<float?>
+ {
+ Normal = 20,
+ Selected = 15,
+ };
+ box2.but1.Style.Text.MultiLine = true;
+
+
+ box2.but2.ClickEvent += But2_ClickEvent1;
+ box2.but2.IsSelectable = false;
+ box2.but2.Style.Text.Text = new Selector<string>
+ {
+ Normal = "Increase frame delay",
+ Pressed = "Up 100ms",
+ };
+
+ box2.but3.ClickEvent += But3_ClickEvent;
+ box2.but3.IsSelectable = false;
+ box2.but3.Style.Text.Text = new Selector<string>
+ {
+ Normal = "Increase loop count",
+ Pressed = "Up 1 count",
+ };
+ box2.status.Text = $"playing now, frame delay: {box2.image.FrameDelay}ms, loop count: {box2.image.LoopCount}";
+
+ }
+
+ private void But3_ClickEvent(object sender, Button.ClickEventArgs e)
+ {
+ tlog.Fatal(tag, $"But3_ClickEvent()!");
+ var src = sender as Button;
+ if (src != null)
+ {
+ box2.image.LoopCount += 1;
+ box2.image.Play();
+ box2.status.Text = $"playing now, frame delay: {box2.image.FrameDelay}ms, loop count: {box2.image.LoopCount}";
+ }
+ }
+
+ private void But2_ClickEvent1(object sender, Button.ClickEventArgs e)
+ {
+ tlog.Fatal(tag, $"But2_ClickEvent1()!");
+ var src = sender as Button;
+ if (src != null)
+ {
+ box2.image.FrameDelay += 100;
+ box2.image.Play();
+ box2.status.Text = $"playing now, frame delay: {box2.image.FrameDelay}ms, loop count: {box2.image.LoopCount}";
+ }
+ }
+ private void But1_ClickEvent1(object sender, Button.ClickEventArgs e)
+ {
+ tlog.Fatal(tag, $"But1_ClickEvent1()!");
+ var src = sender as Button;
+ if (src != null)
+ {
+ tlog.Fatal(tag, $"is selected: {src.IsSelected}");
+ if (src.IsSelected)
+ {
+ box2.image.Pause();
+ box2.status.Text = $"paused, frame delay: {box2.image.FrameDelay}ms, loop count: {box2.image.LoopCount}";
+ }
+ else
+ {
+ box2.image.FrameDelay = 0;
+ box2.image.LoopCount = -1;
+ box2.image.Play();
+ box2.status.Text = $"playing now, frame delay: {box2.image.FrameDelay}ms, loop count: {box2.image.LoopCount}";
+ }
+ }
+ }
+
+ private void But2_ClickEvent(object sender, Button.ClickEventArgs e)
+ {
+ tlog.Fatal(tag, $"But2_ClickEvent()!");
+ var src = sender as Button;
+ if (src != null)
+ {
+ if (src.IsSelected)
+ {
+ box.image.Stop();
+ box.status.Text = "stopped";
+ }
+ else
+ {
+ box.image.Play();
+ box.status.Text = "playing now";
+ }
+ }
+ }
+
+ private void But1_ClickEvent(object sender, Button.ClickEventArgs e)
+ {
+ tlog.Fatal(tag, $"But1_ClickEvent()!");
+ var src = sender as Button;
+ if (src != null)
+ {
+ tlog.Fatal(tag, $"is selected: {src.IsSelected}");
+ if (src.IsSelected)
+ {
+ box.image.Pause();
+ box.status.Text = "paused";
+ }
+ else
+ {
+ box.image.Play();
+ box.status.Text = "playing now";
+ }
+ }
+ }
+
+ public void Deactivate()
+ {
+ }
+ }
+}