/*
- * Copyright(c) 2018 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.
- *
- */
+* 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;
using System.Runtime.InteropServices;
using System.ComponentModel;
+using Tizen.NUI.Binding;
namespace Tizen.NUI.BaseComponents
{
/// An instance of ImageView can be created using a URL or an image instance.<br />
/// </summary>
/// <since_tizen> 3 </since_tizen>
- public class ImageView : View
+ public partial class ImageView : View
{
- private global::System.Runtime.InteropServices.HandleRef swigCPtr;
+ static ImageView() { }
- internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn) : base(NDalicPINVOKE.ImageView_SWIGUpcast(cPtr), cMemoryOwn)
+ private EventHandler<ResourceReadyEventArgs> _resourceReadyEventHandler;
+ private ResourceReadyEventCallbackType _resourceReadyEventCallback;
+ private EventHandler<ResourceLoadedEventArgs> _resourceLoadedEventHandler;
+ private _resourceLoadedCallbackType _resourceLoadedCallback;
+
+ // Collection of image-sensitive properties.
+ private bool _imagePropertyUpdatedFlag = false;
+ private bool _imagePropertyUpdateProcessAttachedFlag = false;
+ private PropertyMap _imagePropertyMap;
+ private Rectangle _border;
+ private string _resourceUrl = "";
+ private int _desired_width = -1;
+ private int _desired_height = -1;
+ private TriggerableSelector<string> resourceUrlSelector;
+ private TriggerableSelector<Rectangle> borderSelector;
+
+ /// <summary>
+ /// Creates an initialized ImageView.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public ImageView() : this(Interop.ImageView.New(), true)
{
- swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
- internal static global::System.Runtime.InteropServices.HandleRef getCPtr(ImageView obj)
+ /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ImageView(ViewStyle viewStyle) : this(Interop.ImageView.New(), true, viewStyle)
{
- return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
}
+ /// <summary>
+ /// Creates an initialized ImageView with setting the status of shown or hidden.
+ /// </summary>
+ /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
+ /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ImageView(bool shown) : this(Interop.ImageView.New(), true)
+ {
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ SetVisible(shown);
+ }
/// <summary>
- /// Event arguments of resource ready.
+ /// Creates an initialized ImageView from a URL to an image resource.<br />
+ /// If the string is empty, ImageView will not display anything.<br />
/// </summary>
+ /// <param name="url">The URL of the image resource to display.</param>
/// <since_tizen> 3 </since_tizen>
- public class ResourceReadyEventArgs : EventArgs
+ public ImageView(string url) : this(Interop.ImageView.New(url), true)
{
- private View _view;
+ ResourceUrl = url;
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
- /// <summary>
- /// The view whose resource is ready.
- /// </summary>
- /// <since_tizen> 3 </since_tizen>
- public View View
+ }
+
+ /// <summary>
+ /// Creates an initialized ImageView from a URL to an image resource with setting shown or hidden.
+ /// </summary>
+ /// <param name="url">The URL of the image resource to display.</param>
+ /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
+ /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ImageView(string url, bool shown) : this(Interop.ImageView.New(url), true)
+ {
+ ResourceUrl = url;
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ SetVisible(shown);
+ }
+
+ internal ImageView(string url, Uint16Pair size, bool shown = true) : this(Interop.ImageView.New(url, Uint16Pair.getCPtr(size)), true)
+ {
+ ResourceUrl = url;
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+
+ if (!shown)
{
- get
- {
- return _view;
- }
- set
- {
- _view = value;
- }
+ SetVisible(false);
+ }
+ }
+
+ internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, ViewStyle viewStyle, bool shown = true) : base(cPtr, cMemoryOwn, viewStyle)
+ {
+ if (!shown)
+ {
+ SetVisible(false);
+ }
+ }
+
+ internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, bool shown = true) : base(cPtr, cMemoryOwn, null)
+ {
+ if (!shown)
+ {
+ SetVisible(false);
}
}
- private EventHandler<ResourceReadyEventArgs> _resourceReadyEventHandler;
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void ResourceReadyEventCallbackType(IntPtr data);
- private ResourceReadyEventCallbackType _resourceReadyEventCallback;
+ [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+ private delegate void _resourceLoadedCallbackType(IntPtr view);
/// <summary>
/// An event for ResourceReady signal which can be used to subscribe or unsubscribe the event handler.<br />
if (_resourceReadyEventHandler == null)
{
_resourceReadyEventCallback = OnResourceReady;
- ResourceReadySignal(this).Connect(_resourceReadyEventCallback);
+ ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
+ resourceReadySignal?.Connect(_resourceReadyEventCallback);
+ resourceReadySignal?.Dispose();
}
_resourceReadyEventHandler += value;
{
_resourceReadyEventHandler -= value;
- if (_resourceReadyEventHandler == null && ResourceReadySignal(this).Empty() == false)
+ ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
+ if (_resourceReadyEventHandler == null && resourceReadySignal?.Empty() == false)
{
- ResourceReadySignal(this).Disconnect(_resourceReadyEventCallback);
+ resourceReadySignal?.Disconnect(_resourceReadyEventCallback);
}
+ resourceReadySignal?.Dispose();
}
}
- // Callback for View ResourceReady signal
- private void OnResourceReady(IntPtr data)
- {
- ResourceReadyEventArgs e = new ResourceReadyEventArgs();
- if (data != null)
- {
- e.View = Registry.GetManagedBaseHandleFromNativePtr(data) as View;
- }
-
- if (_resourceReadyEventHandler != null)
- {
- _resourceReadyEventHandler(this, e);
- }
- }
-
- /// <summary>
- /// you can override it to clean-up your own resources.
- /// </summary>
- /// <param name="type">DisposeTypes</param>
- /// <since_tizen> 3 </since_tizen>
- protected override void Dispose(DisposeTypes type)
+ internal event EventHandler<ResourceLoadedEventArgs> ResourceLoaded
{
- if (disposed)
+ add
{
- return;
- }
+ if (_resourceLoadedEventHandler == null)
+ {
+ _resourceLoadedCallback = OnResourceLoaded;
+ ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
+ resourceReadySignal?.Connect(_resourceLoadedCallback);
+ resourceReadySignal?.Dispose();
+ }
- if (type == DisposeTypes.Explicit)
- {
- //Called by User
- //Release your own managed resources here.
- //You should release all of your own disposable objects here.
- _border?.Dispose();
- _border = null;
- _nPatchMap?.Dispose();
- _nPatchMap = null;
+ _resourceLoadedEventHandler += value;
}
-
- //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.
-
- if (swigCPtr.Handle != global::System.IntPtr.Zero)
+ remove
{
- if (swigCMemOwn)
+ _resourceLoadedEventHandler -= value;
+ ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
+ if (_resourceLoadedEventHandler == null && resourceReadySignal?.Empty() == false)
{
- swigCMemOwn = false;
- NDalicPINVOKE.delete_ImageView(swigCPtr);
+ resourceReadySignal?.Disconnect(_resourceLoadedCallback);
}
- swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
+ resourceReadySignal?.Dispose();
}
-
- base.Dispose(type);
- }
-
- internal new class Property
- {
- internal static readonly int RESOURCE_URL = NDalicPINVOKE.ImageView_Property_RESOURCE_URL_get();
- internal static readonly int IMAGE = NDalicPINVOKE.ImageView_Property_IMAGE_get();
- internal static readonly int PRE_MULTIPLIED_ALPHA = NDalicPINVOKE.ImageView_Property_PRE_MULTIPLIED_ALPHA_get();
- internal static readonly int PIXEL_AREA = NDalicPINVOKE.ImageView_Property_PIXEL_AREA_get();
- internal static readonly int ACTION_RELOAD = NDalicManualPINVOKE.ImageView_IMAGE_VISUAL_ACTION_RELOAD_get();
- internal static readonly int ACTION_PLAY = NDalicManualPINVOKE.ImageView_IMAGE_VISUAL_ACTION_PLAY_get();
- internal static readonly int ACTION_PAUSE = NDalicManualPINVOKE.ImageView_IMAGE_VISUAL_ACTION_PAUSE_get();
- internal static readonly int ACTION_STOP = NDalicManualPINVOKE.ImageView_IMAGE_VISUAL_ACTION_STOP_get();
- }
-
- /// <summary>
- /// Creates an initialized ImageView.
- /// </summary>
- /// <since_tizen> 3 </since_tizen>
- public ImageView() : this(NDalicPINVOKE.ImageView_New__SWIG_0(), true)
- {
- if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-
- }
- /// <summary>
- /// Creates an initialized ImageView from a URL to an image resource.<br />
- /// If the string is empty, ImageView will not display anything.<br />
- /// </summary>
- /// <param name="url">The URL of the image resource to display.</param>
- /// <since_tizen> 3 </since_tizen>
- public ImageView(string url) : this(NDalicPINVOKE.ImageView_New__SWIG_2(url), true)
- {
- _url = url;
- if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-
- }
- internal ImageView(string url, Uint16Pair size) : this(NDalicPINVOKE.ImageView_New__SWIG_3(url, Uint16Pair.getCPtr(size)), true)
- {
- _url = url;
- if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-
}
/// <summary>
- /// Sets this ImageView from the given URL.<br />
- /// If the URL is empty, ImageView will not display anything.<br />
- /// </summary>
- /// <param name="url">The URL to the image resource to display.</param>
- /// <since_tizen> 3 </since_tizen>
- public void SetImage(string url)
- {
- _url = url;
- NDalicPINVOKE.ImageView_SetImage__SWIG_1(swigCPtr, url);
- if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
- }
- internal void SetImage(string url, Uint16Pair size)
- {
- _url = url;
- NDalicPINVOKE.ImageView_SetImage__SWIG_2(swigCPtr, url, Uint16Pair.getCPtr(size));
- if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
- }
-
- internal ViewResourceReadySignal ResourceReadySignal(View view)
- {
- ViewResourceReadySignal ret = new ViewResourceReadySignal(NDalicPINVOKE.ResourceReadySignal(View.getCPtr(view)), false);
- if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
- return ret;
- }
-
- /// <summary>
- /// Queries if all resources required by a control are loaded and ready.<br />
- /// Most resources are only loaded when the control is placed on the stage.<br />
- /// True if the resources are loaded and ready, false otherwise.<br />
- /// </summary>
- /// <since_tizen> 3 </since_tizen>
- public new bool IsResourceReady()
- {
- bool ret = NDalicPINVOKE.IsResourceReady(swigCPtr);
- if (NDalicPINVOKE.SWIGPendingException.Pending)
- throw NDalicPINVOKE.SWIGPendingException.Retrieve();
- return ret;
- }
-
- /// <summary>
- /// Force reloading of the image, all visuals using this image will get the latest one.
- /// </summary>
- /// <since_tizen> 5 </since_tizen>
- /// This will be released at Tizen.NET API Level 5, so currently this would be used as inhouse API.
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Reload()
- {
- this.DoAction(ImageView.Property.IMAGE, Property.ACTION_RELOAD, new PropertyValue(0));
- }
-
- /// <summary>
- /// Play the animated GIF. This is also Default playback mode.
- /// </summary>
- /// <since_tizen> 5 </since_tizen>
- /// This will be released at Tizen.NET API Level 5, so currently this would be used as inhouse API.
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Play()
- {
- this.DoAction(ImageView.Property.IMAGE, Property.ACTION_PLAY, new PropertyValue(0));
- }
-
- /// <summary>
- /// Pause the animated GIF.
- /// </summary>
- /// <since_tizen> 5 </since_tizen>
- /// This will be released at Tizen.NET API Level 5, so currently this would be used as inhouse API.
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Pause()
- {
- this.DoAction(ImageView.Property.IMAGE, Property.ACTION_PAUSE, new PropertyValue(0));
- }
-
- /// <summary>
- /// Stop the animated GIF.
+ /// Enumeration for LoadingStatus of image.
/// </summary>
/// <since_tizen> 5 </since_tizen>
- /// This will be released at Tizen.NET API Level 5, so currently this would be used as inhouse API.
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Stop()
+ public enum LoadingStatusType
{
- this.DoAction(ImageView.Property.IMAGE, Property.ACTION_STOP, new PropertyValue(0));
+ /// <summary>
+ /// Loading preparing status.
+ /// </summary>
+ /// <since_tizen> 5 </since_tizen>
+ Preparing,
+ /// <summary>
+ /// Loading ready status.
+ /// </summary>
+ /// <since_tizen> 5 </since_tizen>
+ Ready,
+ /// <summary>
+ /// Loading failed status.
+ /// </summary>
+ /// <since_tizen> 5 </since_tizen>
+ Failed
}
/// <summary>
/// ImageView ResourceUrl, type string.
+ /// This is one of mandatory property. Even if not set or null set, it sets empty string ("") internally.
+ /// When it is set as null, it gives empty string ("") to be read.
/// </summary>
/// <since_tizen> 3 </since_tizen>
public string ResourceUrl
{
get
{
- GetProperty(ImageView.Property.IMAGE).Get(out _url);
- return _url;
+ return (string)GetValue(ResourceUrlProperty);
}
set
{
- _url = (value == null? "" : value);
- UpdateImage();
+ SetValue(ResourceUrlProperty, value);
+ NotifyPropertyChanged();
}
}
{
get
{
+ return GetValue(ImageMapProperty) as PropertyMap;
+ }
+ set
+ {
+ SetValue(ImageMapProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private PropertyMap InternalImageMap
+ {
+ get
+ {
if (_border == null)
{
- PropertyMap temp = new PropertyMap();
- GetProperty(ImageView.Property.IMAGE).Get(temp);
- return temp;
+ // Get current properties force.
+ // TODO: Need to make some flag that we only need cached property map.
+ PropertyMap returnValue = new PropertyMap();
+ PropertyValue image = GetProperty(ImageView.Property.IMAGE);
+ image?.Get(returnValue);
+ image?.Dispose();
+ return returnValue;
}
else
{
{
if (_border == null)
{
- if (_url != null) { value.Add("url", new PropertyValue(_url)); }
- SetProperty(ImageView.Property.IMAGE, new Tizen.NUI.PropertyValue(value));
+ PropertyValue setValue = new Tizen.NUI.PropertyValue(value);
+ SetProperty(ImageView.Property.IMAGE, setValue);
+ // Image properties are changed hardly. We should ignore lazy UpdateImage
+ _imagePropertyUpdatedFlag = false;
+ _imagePropertyMap?.Dispose();
+ _imagePropertyMap = null;
+ if(value != null)
+ {
+ _imagePropertyMap = new PropertyMap(value);
+ }
+ NotifyPropertyChanged();
+ setValue?.Dispose();
}
}
}
/// <summary>
- /// ImageView Image, type PropertyMap
+ /// ImageView Image, type PropertyMap: string if it is a URL, map otherwise.
/// </summary>
+ /// <remarks>
+ /// This PropertyMap use a <see cref="ImageVisualProperty"/>. <br />
+ /// See <see cref="ImageVisualProperty"/> for a detailed description. <br />
+ /// you can also use <see cref="Visual.Property"/>. <br />
+ /// See <see cref="Visual.Property"/> for a detailed description. <br />
+ /// </remarks>
+ /// <example>
+ /// The following example demonstrates how to use the Image property.
+ /// <code>
+ /// PropertyMap map = new PropertyMap();
+ /// map.Insert(Visual.Property.Type, new PropertyValue((int)Visual.Type.Image));
+ /// map.Insert(ImageVisualProperty.AlphaMaskURL, new PropertyValue(url));
+ /// map.Insert(ImageVisualProperty.FittingMode, new PropertyValue((int)FittingModeType.ScaleToFill);
+ /// imageview.Image = map;
+ /// </code>
+ /// </example>
/// <since_tizen> 4 </since_tizen>
public PropertyMap Image
{
{
if (_border == null)
{
- PropertyMap temp = new PropertyMap();
- GetProperty(ImageView.Property.IMAGE).Get(temp);
- return temp;
+ return (PropertyMap)GetValue(ImageProperty);
}
else
{
{
if (_border == null)
{
- if(_url != null) { value.Add("url", new PropertyValue(_url)); }
- SetProperty(ImageView.Property.IMAGE, new Tizen.NUI.PropertyValue(value));
+ SetValue(ImageProperty, value);
+ NotifyPropertyChanged();
}
}
}
{
get
{
- bool temp = false;
- GetProperty(ImageView.Property.PRE_MULTIPLIED_ALPHA).Get(out temp);
- return temp;
+ return (bool)GetValue(PreMultipliedAlphaProperty);
}
set
{
- SetProperty(ImageView.Property.PRE_MULTIPLIED_ALPHA, new Tizen.NUI.PropertyValue(value));
+ SetValue(PreMultipliedAlphaProperty, value);
+ NotifyPropertyChanged();
}
}
/// ImageView PixelArea, type Vector4 (Animatable property).<br />
/// Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0].<br />
/// </summary>
+ /// <remarks>
+ /// The property cascade chaining set is possible. For example, this (imageView.PixelArea.X = 0.1f;) is possible.
+ /// </remarks>
/// <since_tizen> 3 </since_tizen>
public RelativeVector4 PixelArea
{
get
{
- Vector4 temp = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
- GetProperty(ImageView.Property.PIXEL_AREA).Get(temp);
- return temp;
+ RelativeVector4 temp = (RelativeVector4)GetValue(PixelAreaProperty);
+ return new RelativeVector4(OnPixelAreaChanged, temp.X, temp.Y, temp.Z, temp.W);
}
set
{
- SetProperty(ImageView.Property.PIXEL_AREA, new Tizen.NUI.PropertyValue(value));
+ SetValue(PixelAreaProperty, value);
+ NotifyPropertyChanged();
}
}
/// For N-Patch images only.<br />
/// Optional.
/// </summary>
+ /// <remarks>
+ /// The property cascade chaining set is possible. For example, this (imageView.Border.X = 1;) is possible.
+ /// </remarks>
/// <since_tizen> 3 </since_tizen>
public Rectangle Border
{
get
{
- return _border;
+ Rectangle temp = (Rectangle)GetValue(BorderProperty);
+ if (null == temp)
+ {
+ return null;
+ }
+ else
+ {
+ return new Rectangle(OnBorderChanged, temp.X, temp.Y, temp.Width, temp.Height);
+ }
}
set
{
- _border = value;
- UpdateImage();
+ SetValue(BorderProperty, value);
+ NotifyPropertyChanged();
}
}
{
get
{
- return _borderOnly ?? false;
+ return (bool)GetValue(BorderOnlyProperty);
}
set
{
- _borderOnly = value;
- UpdateImage();
+ SetValue(BorderOnlyProperty, value);
+ NotifyPropertyChanged();
}
}
/// <summary>
- /// Gets or sets whether to synchronos loading the resourceurl of image.<br />
+ /// Gets or sets whether to synchronous loading the resourceurl of image.<br />
/// </summary>
/// <since_tizen> 3 </since_tizen>
+ [Obsolete("Deprecated since API level 9 and will be removed in API level 11. Please use SynchronousLoading instead!")]
public bool SynchronosLoading
{
get
{
- return _synchronousLoading ?? false;
+ return SynchronousLoading;
}
set
{
- _synchronousLoading = value;
- UpdateImage();
+ SynchronousLoading = value;
}
}
/// <summary>
- /// Gets or sets whether to correct orientation of image automatically.<br />
+ /// Gets or sets whether the image of the ResourceUrl property will be loaded synchronously.<br />
/// </summary>
- /// <since_tizen> 5 </since_tizen>
- public bool OrientationCorrection
+ /// <remarks>
+ /// Changing this property make this ImageView load image synchronously at the next loading
+ /// by following operation: <see cref="Reload"/>, <see cref="SetImage(string)"/>,
+ /// and by some properties those cause reloading: <see cref="ResourceUrl"/>, <see cref="PreMultipliedAlpha"/> and etc.
+ /// </remarks>
+ /// <since_tizen> 9 </since_tizen>
+ public bool SynchronousLoading
{
get
{
- return _orientationCorrection ?? false;
+ return (bool)GetValue(SynchronousLoadingProperty);
}
set
{
- _orientationCorrection = value;
- UpdateImage();
+ SetValue(SynchronousLoadingProperty, value);
+ NotifyPropertyChanged();
}
}
-
/// <summary>
- /// Get the loading state of the visual resource.
+ /// Gets or sets whether to automatically correct the orientation of an image.<br />
/// </summary>
/// <since_tizen> 5 </since_tizen>
- public ImageView.LoadingStatusType LoadingStatus
+ public bool OrientationCorrection
{
get
{
- return (ImageView.LoadingStatusType)NDalicManualPINVOKE.View_GetVisualResourceStatus(swigCPtr, (int)Property.IMAGE);
+ return (bool)GetValue(OrientationCorrectionProperty);
+ }
+ set
+ {
+ SetValue(OrientationCorrectionProperty, value);
+ NotifyPropertyChanged();
}
}
/// <summary>
- /// Enumeration for LoadingStatus of image.
+ /// Gets the loading state of the visual resource.
/// </summary>
/// <since_tizen> 5 </since_tizen>
- public enum LoadingStatusType
+ public ImageView.LoadingStatusType LoadingStatus
{
- /// <summary>
- /// Loading preparing status.
- /// </summary>
- /// <since_tizen> 5 </since_tizen>
- Preparing,
- /// <summary>
- /// Loading ready status.
- /// </summary>
- /// <since_tizen> 5 </since_tizen>
- Ready,
- /// <summary>
- /// Loading failed status.
- /// </summary>
- /// <since_tizen> 5 </since_tizen>
- Failed
+ get
+ {
+ return (ImageView.LoadingStatusType)Interop.View.GetVisualResourceStatus(SwigCPtr, (int)Property.IMAGE);
+ }
}
-
- private void UpdateImage()
+ /// <summary>
+ /// Downcasts a handle to imageView handle.
+ /// </summary>
+ /// <exception cref="ArgumentNullException"> Thrown when handle is null. </exception>
+ /// Please do not use! this will be deprecated!
+ /// Instead please use as keyword.
+ /// <since_tizen> 3 </since_tizen>
+ [Obsolete("Please do not use! This will be deprecated! Please use as keyword instead! " +
+ "Like: " +
+ "BaseHandle handle = new ImageView(imagePath); " +
+ "ImageView image = handle as ImageView")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static ImageView DownCast(BaseHandle handle)
{
- if (_url != null)
+ if (null == handle)
{
- if (_border != null)
- { // for nine-patch image
- _nPatchMap = new PropertyMap();
- _nPatchMap.Add(Visual.Property.Type, new PropertyValue((int)Visual.Type.NPatch));
- _nPatchMap.Add(NpatchImageVisualProperty.URL, new PropertyValue(_url));
- _nPatchMap.Add(NpatchImageVisualProperty.Border, new PropertyValue(_border));
- if (_borderOnly != null) { _nPatchMap.Add(NpatchImageVisualProperty.BorderOnly, new PropertyValue((bool)_borderOnly)); }
- if (_synchronousLoading != null) { _nPatchMap.Add(NpatchImageVisualProperty.SynchronousLoading, new PropertyValue((bool)_synchronousLoading)); }
- if (_orientationCorrection != null) { _nPatchMap.Add(ImageVisualProperty.OrientationCorrection, new PropertyValue((bool)_orientationCorrection)); }
- SetProperty(ImageView.Property.IMAGE, new PropertyValue(_nPatchMap));
- }
- else if (_synchronousLoading != null || _orientationCorrection != null)
- { // for normal image, with synchronous loading property
- PropertyMap imageMap = new PropertyMap();
- imageMap.Add(Visual.Property.Type, new PropertyValue((int)Visual.Type.Image));
- imageMap.Add(ImageVisualProperty.URL, new PropertyValue(_url));
- if (_synchronousLoading != null) { imageMap.Add(ImageVisualProperty.SynchronousLoading, new PropertyValue((bool)_synchronousLoading)); }
- if (_orientationCorrection != null) { imageMap.Add(ImageVisualProperty.OrientationCorrection, new PropertyValue((bool)_orientationCorrection)); }
- SetProperty(ImageView.Property.IMAGE, new PropertyValue(imageMap));
- }
- else
- { // just for normal image
- SetProperty(ImageView.Property.IMAGE, new PropertyValue(_url));
- }
+ throw new ArgumentNullException(nameof(handle));
}
+ ImageView ret = Registry.GetManagedBaseHandleFromNativePtr(handle) as ImageView;
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ return ret;
+ }
+
+ /// <summary>
+ /// Sets this ImageView from the given URL.<br />
+ /// If the URL is empty, ImageView will not display anything.<br />
+ /// </summary>
+ /// <param name="url">The URL to the image resource to display.</param>
+ /// <exception cref="ArgumentNullException"> Thrown when url is null. </exception>
+ /// <since_tizen> 3 </since_tizen>
+ public void SetImage(string url)
+ {
+ if (null == url)
+ {
+ throw new ArgumentNullException(nameof(url));
+ }
+
+ if (url.Contains(".json"))
+ {
+ Tizen.Log.Fatal("NUI", "[ERROR] Please DO NOT set lottie file in ImageView! This is temporary checking, will be removed soon!");
+ return;
+ }
+
+ Interop.ImageView.SetImage(SwigCPtr, url);
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+
+ ResourceUrl = url;
+ }
+
+ /// <summary>
+ /// Queries if all resources required by a control are loaded and ready.<br />
+ /// Most resources are only loaded when the control is placed on the stage.<br />
+ /// True if the resources are loaded and ready, false otherwise.<br />
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public new bool IsResourceReady()
+ {
+ bool ret = Interop.View.IsResourceReady(SwigCPtr);
+ if (NDalicPINVOKE.SWIGPendingException.Pending)
+ throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ return ret;
+ }
+
+ /// <summary>
+ /// Forcefully reloads the image. All the visuals using this image will reload to the latest image.
+ /// </summary>
+ /// <since_tizen> 5 </since_tizen>
+ public void Reload()
+ {
+ PropertyValue attributes = new PropertyValue(0);
+ this.DoAction(ImageView.Property.IMAGE, ActionReload, attributes);
+ attributes?.Dispose();
+ }
+
+ /// <summary>
+ /// Plays the animated GIF. This is also the default playback mode.
+ /// </summary>
+ /// <since_tizen> 5 </since_tizen>
+ public void Play()
+ {
+ PropertyValue attributes = new PropertyValue(0);
+ this.DoAction(ImageView.Property.IMAGE, ActionPlay, attributes);
+ attributes?.Dispose();
+ }
+
+ /// <summary>
+ /// Pauses the animated GIF.
+ /// </summary>
+ /// <since_tizen> 5 </since_tizen>
+ public void Pause()
+ {
+ PropertyValue attributes = new PropertyValue(0);
+ this.DoAction(ImageView.Property.IMAGE, ActionPause, attributes);
+ attributes?.Dispose();
+ }
+
+ /// <summary>
+ /// Stops the animated GIF.
+ /// </summary>
+ /// <since_tizen> 5 </since_tizen>
+ public void Stop()
+ {
+ PropertyValue attributes = new PropertyValue(0);
+ this.DoAction(ImageView.Property.IMAGE, ActionStop, attributes);
+ attributes?.Dispose();
+ }
+
+ /// <summary>
+ /// Gets or sets the URL of the alpha mask.<br />
+ /// Optional.
+ /// </summary>
+ /// <since_tizen> 6</since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string AlphaMaskURL
+ {
+ get
+ {
+ return GetValue(AlphaMaskURLProperty) as string;
+ }
+ set
+ {
+ SetValue(AlphaMaskURLProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+
+ private string InternalAlphaMaskURL
+ {
+ get
+ {
+ string ret = "";
+
+ PropertyValue maskUrl = _imagePropertyMap?.Find(ImageVisualProperty.AlphaMaskURL);
+ maskUrl?.Get(out ret);
+ maskUrl?.Dispose();
+
+ return ret;
+ }
+ set
+ {
+ PropertyValue setValue = new PropertyValue(value ?? "");
+ UpdateImage(ImageVisualProperty.AlphaMaskURL, setValue);
+ // When we never set CropToMask property before, we should set default value as true.
+ using(PropertyValue cropToMask = _imagePropertyMap?.Find(ImageVisualProperty.CropToMask))
+ {
+ if(cropToMask == null)
+ {
+ using PropertyValue setCropValue = new PropertyValue(true);
+ UpdateImage(ImageVisualProperty.CropToMask, setCropValue);
+ }
+ }
+ setValue?.Dispose();
+ }
+ }
+
+
+ /// <summary>
+ /// Whether to crop image to mask or scale mask to fit image.
+ /// </summary>
+ /// <since_tizen> 6 </since_tizen>
+ public bool CropToMask
+ {
+ get
+ {
+ return (bool)GetValue(CropToMaskProperty);
+ }
+ set
+ {
+ SetValue(CropToMaskProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private bool InternalCropToMask
+ {
+ get
+ {
+ bool ret = false;
+
+ PropertyValue cropToMask = _imagePropertyMap?.Find(ImageVisualProperty.CropToMask);
+ cropToMask?.Get(out ret);
+ cropToMask?.Dispose();
+
+ return ret;
+ }
+ set
+ {
+ PropertyValue setValue = new PropertyValue(value);
+ UpdateImage(ImageVisualProperty.CropToMask, setValue);
+ setValue?.Dispose();
+ }
+ }
+
+ /// <summary>
+ /// Actions property value for Reload image.
+ /// </summary>
+ private int ActionReload { get; set; } = Interop.ImageView.ImageVisualActionReloadGet();
+
+ /// <summary>
+ /// Actions property value to Play animated images.
+ /// This property can be redefined by child class if it use different value.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected int ActionPlay { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet();
+
+ /// <summary>
+ /// Actions property value to Pause animated images.
+ /// This property can be redefined by child class if it use different value.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected int ActionPause { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet();
+
+ /// <summary>
+ /// Actions property value to Stop animated images.
+ /// This property can be redefined by child class if it use different value.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected int ActionStop { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionStopGet();
+
+ internal VisualFittingModeType ConvertFittingModetoVisualFittingMode(FittingModeType value)
+ {
+ switch (value)
+ {
+ case FittingModeType.ShrinkToFit:
+ return VisualFittingModeType.FitKeepAspectRatio;
+ case FittingModeType.ScaleToFill:
+ return VisualFittingModeType.OverFitKeepAspectRatio;
+ case FittingModeType.Center:
+ return VisualFittingModeType.Center;
+ case FittingModeType.Fill:
+ return VisualFittingModeType.Fill;
+ case FittingModeType.FitHeight:
+ return VisualFittingModeType.FitHeight;
+ case FittingModeType.FitWidth:
+ return VisualFittingModeType.FitWidth;
+ default:
+ return VisualFittingModeType.Fill;
+ }
+ }
+
+ internal FittingModeType ConvertVisualFittingModetoFittingMode(VisualFittingModeType value)
+ {
+ switch (value)
+ {
+ case VisualFittingModeType.FitKeepAspectRatio:
+ return FittingModeType.ShrinkToFit;
+ case VisualFittingModeType.OverFitKeepAspectRatio:
+ return FittingModeType.ScaleToFill;
+ case VisualFittingModeType.Center:
+ return FittingModeType.Center;
+ case VisualFittingModeType.Fill:
+ return FittingModeType.Fill;
+ case VisualFittingModeType.FitHeight:
+ return FittingModeType.FitHeight;
+ case VisualFittingModeType.FitWidth:
+ return FittingModeType.FitWidth;
+ default:
+ return FittingModeType.ShrinkToFit;
+ }
+ }
+
+ internal override LayoutItem CreateDefaultLayout()
+ {
+ return new ImageLayout();
+ }
+
+ /// <summary>
+ /// Gets or sets fitting options used when resizing images to fit.<br />
+ /// If not supplied, the default is FittingModeType.Fill.<br />
+ /// For normal quad images only.<br />
+ /// Optional.
+ /// </summary>
+ /// <since_tizen> 6 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public FittingModeType FittingMode
+ {
+ get
+ {
+ return (FittingModeType)GetValue(FittingModeProperty);
+ }
+ set
+ {
+ SetValue(FittingModeProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+
+ private FittingModeType InternalFittingMode
+ {
+ get
+ {
+ int ret = (int)VisualFittingModeType.Fill;
+
+ PropertyValue fittingMode = _imagePropertyMap?.Find(Visual.Property.VisualFittingMode);
+ fittingMode?.Get(out ret);
+ fittingMode?.Dispose();
+
+ return ConvertVisualFittingModetoFittingMode((VisualFittingModeType)ret);
+ }
+ set
+ {
+ VisualFittingModeType ret = ConvertFittingModetoVisualFittingMode(value);
+ PropertyValue setValue = new PropertyValue((int)ret);
+ UpdateImage(Visual.Property.VisualFittingMode, setValue);
+ setValue?.Dispose();
+ }
+ }
+
+
+
+ /// <summary>
+ /// Gets or sets the desired image width.<br />
+ /// If not specified, the actual image width is used.<br />
+ /// For normal quad images only.<br />
+ /// Optional.
+ /// </summary>
+ /// <since_tizen> 6 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int DesiredWidth
+ {
+ get
+ {
+ return (int)GetValue(DesiredWidthProperty);
+ }
+ set
+ {
+ SetValue(DesiredWidthProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private int InternalDesiredWidth
+ {
+ get
+ {
+ // Sync as current properties only if both _desired_width and _desired_height are setuped.
+ if(_desired_width != -1 && _desired_height != -1)
+ {
+ UpdateImage();
+ }
+ PropertyValue desirewidth = _imagePropertyMap?.Find(ImageVisualProperty.DesiredWidth);
+ desirewidth?.Get(out _desired_width);
+ desirewidth?.Dispose();
+
+ return _desired_width;
+ }
+ set
+ {
+ if (_desired_width != value)
+ {
+ _desired_width = value;
+ PropertyValue setValue = new PropertyValue(value);
+ UpdateImage(ImageVisualProperty.DesiredWidth, setValue);
+ setValue?.Dispose();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the desired image height.<br />
+ /// If not specified, the actual image height is used.<br />
+ /// For normal quad images only.<br />
+ /// Optional.
+ /// </summary>
+ /// <since_tizen> 6 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int DesiredHeight
+ {
+ get
+ {
+ return (int)GetValue(DesiredHeightProperty);
+ }
+ set
+ {
+ SetValue(DesiredHeightProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private int InternalDesiredHeight
+ {
+ get
+ {
+ // Sync as current properties only if both _desired_width and _desired_height are setuped.
+ if(_desired_width != -1 && _desired_height != -1)
+ {
+ UpdateImage();
+ }
+ PropertyValue desireheight = _imagePropertyMap?.Find(ImageVisualProperty.DesiredHeight);
+ desireheight?.Get(out _desired_height);
+ desireheight?.Dispose();
+
+ return _desired_height;
+ }
+ set
+ {
+ if (_desired_height != value)
+ {
+ _desired_height = value;
+ PropertyValue setValue = new PropertyValue(value);
+ UpdateImage(ImageVisualProperty.DesiredHeight, setValue);
+ setValue?.Dispose();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets ReleasePolicy for image.<br />
+ /// If not supplied, the default is ReleasePolicyType.Detached.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ReleasePolicyType ReleasePolicy
+ {
+ get
+ {
+ return (ReleasePolicyType)GetValue(ReleasePolicyProperty);
+ }
+ set
+ {
+ SetValue(ReleasePolicyProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+
+ private ReleasePolicyType InternalReleasePolicy
+ {
+ get
+ {
+ int ret = (int)ReleasePolicyType.Detached;
+
+ PropertyValue releasePoli = _imagePropertyMap?.Find(ImageVisualProperty.ReleasePolicy);
+ releasePoli?.Get(out ret);
+ releasePoli?.Dispose();
+
+ return (ReleasePolicyType)ret;
+ }
+ set
+ {
+ PropertyValue setValue = new PropertyValue((int)value);
+ UpdateImage(ImageVisualProperty.ReleasePolicy, setValue);
+ setValue?.Dispose();
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the wrap mode for the u coordinate.<br />
+ /// It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.<br />
+ /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
+ /// For normal quad images only.<br />
+ /// Optional.
+ /// </summary>
+ /// <since_tizen> 6 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public WrapModeType WrapModeU
+ {
+ get
+ {
+ return (WrapModeType)GetValue(WrapModeUProperty);
+ }
+ set
+ {
+ SetValue(WrapModeUProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+
+ private WrapModeType InternalWrapModeU
+ {
+ get
+ {
+ int ret = (int)WrapModeType.Default;
+
+ PropertyValue wrapModeU = _imagePropertyMap?.Find(ImageVisualProperty.WrapModeU);
+ wrapModeU?.Get(out ret);
+ wrapModeU?.Dispose();
+
+ return (WrapModeType)ret;
+ }
+ set
+ {
+ PropertyValue setValue = new PropertyValue((int)value);
+ UpdateImage(ImageVisualProperty.WrapModeU, setValue);
+ setValue?.Dispose();
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the wrap mode for the v coordinate.<br />
+ /// It decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.<br />
+ /// The first two elements indicate the top-left position of the area, and the last two elements are the areas of the width and the height respectively.<br />
+ /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
+ /// For normal quad images only.
+ /// Optional.
+ /// </summary>
+ /// <since_tizen> 6 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public WrapModeType WrapModeV
+ {
+ get
+ {
+ return (WrapModeType)GetValue(WrapModeVProperty);
+ }
+ set
+ {
+ SetValue(WrapModeVProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+
+ private WrapModeType InternalWrapModeV
+ {
+ get
+ {
+ int ret = (int)WrapModeType.Default;
+
+ PropertyValue wrapModeV = _imagePropertyMap?.Find(ImageVisualProperty.WrapModeV);
+ wrapModeV?.Get(out ret);
+ wrapModeV?.Dispose();
+
+ return (WrapModeType)ret;
+ }
+ set
+ {
+ PropertyValue setValue = new PropertyValue((int)value);
+ UpdateImage(ImageVisualProperty.WrapModeV, setValue);
+ setValue?.Dispose();
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
+ /// </summary>
+ /// <remarks>
+ /// This is false by default.
+ /// If this is set to be true, then the width or height value, which is not set by user explicitly, can be changed automatically
+ /// to preserve the aspect ratio of the image resource.
+ /// AdjustViewSize works only if ImageView is added to a View having Layout.
+ /// e.g. If the image resource size is (100, 100), then the ImageView requests size (100, 100) to its parent layout by default.
+ /// If the ImageView's HeightSpecification is 50 and AdjustViewSize is true, then the ImageView requests size (50, 50) instead of (100, 50).
+ /// </remarks>
+ /// <since_tizen> 9 </since_tizen>
+ public bool AdjustViewSize
+ {
+ get
+ {
+ return (bool)GetValue(AdjustViewSizeProperty);
+ }
+ set
+ {
+ SetValue(AdjustViewSizeProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private bool adjustViewSize = false;
+
+ internal Selector<string> ResourceUrlSelector
+ {
+ get => GetSelector<string>(resourceUrlSelector, ImageView.ResourceUrlProperty);
+ set
+ {
+ resourceUrlSelector?.Reset(this);
+ if (value == null) return;
+
+ if (value.HasAll()) SetResourceUrl(value.All);
+ else resourceUrlSelector = new TriggerableSelector<string>(this, value, SetResourceUrl, true);
+ }
+ }
+
+ /// <summary>
+ /// Get attributes, it is abstract function and must be override.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override ViewStyle CreateViewStyle()
+ {
+ return new ImageViewStyle();
+ }
+
+ internal void SetImage(string url, Uint16Pair size)
+ {
+ if (url.Contains(".json"))
+ {
+ Tizen.Log.Fatal("NUI", "[ERROR] Please DO NOT set lottie file in ImageView! This is temporary checking, will be removed soon!");
+ return;
+ }
+
+ Interop.ImageView.SetImage(SwigCPtr, url, Uint16Pair.getCPtr(size));
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+
+ ResourceUrl = url;
}
- private Rectangle _border = null;
- private PropertyMap _nPatchMap = null;
- private bool? _synchronousLoading = null;
- private bool? _borderOnly = null;
- private string _url = null;
- private bool? _orientationCorrection = null;
- }
+ internal ViewResourceReadySignal ResourceReadySignal(View view)
+ {
+ ViewResourceReadySignal ret = new ViewResourceReadySignal(Interop.View.ResourceReadySignal(View.getCPtr(view)), false);
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ return ret;
+ }
+
+ internal override void ApplyCornerRadius()
+ {
+ base.ApplyCornerRadius();
+
+ if (backgroundExtraData == null) return;
+
+ // Apply corner radius to IMAGE.
+ var cornerRadiusValue = backgroundExtraData.CornerRadius == null ? new PropertyValue() : new PropertyValue(backgroundExtraData.CornerRadius);
+ var cornerRadiusPolicyValue = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy);
+
+ // Make current propertyMap
+ PropertyMap currentPropertyMap = new PropertyMap();
+ currentPropertyMap[Visual.Property.CornerRadius] = cornerRadiusValue;
+ currentPropertyMap[Visual.Property.CornerRadiusPolicy] = cornerRadiusPolicyValue;
+ var temp = new PropertyValue(currentPropertyMap);
+
+ // Update corner radius properties to image by ActionUpdateProperty
+ this.DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, temp);
+
+ temp.Dispose();
+ currentPropertyMap.Dispose();
+ cornerRadiusValue.Dispose();
+ cornerRadiusPolicyValue.Dispose();
+ }
+
+ internal override void ApplyBorderline()
+ {
+ base.ApplyBorderline();
+
+ if (backgroundExtraData == null) return;
+
+ // Apply borderline to IMAGE.
+ var borderlineWidthValue = new PropertyValue(backgroundExtraData.BorderlineWidth);
+ var borderlineColorValue = backgroundExtraData.BorderlineColor == null ? new PropertyValue(Color.Black) : new PropertyValue(backgroundExtraData.BorderlineColor);
+ var borderlineOffsetValue = new PropertyValue(backgroundExtraData.BorderlineOffset);
+
+ // Make current propertyMap
+ PropertyMap currentPropertyMap = new PropertyMap();
+ currentPropertyMap[Visual.Property.BorderlineWidth] = borderlineWidthValue;
+ currentPropertyMap[Visual.Property.BorderlineColor] = borderlineColorValue;
+ currentPropertyMap[Visual.Property.BorderlineOffset] = borderlineOffsetValue;
+ var temp = new PropertyValue(currentPropertyMap);
+
+ // Update borderline properties to image by ActionUpdateProperty
+ this.DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, temp);
+
+ temp.Dispose();
+ currentPropertyMap.Dispose();
+ borderlineWidthValue.Dispose();
+ borderlineColorValue.Dispose();
+ borderlineOffsetValue.Dispose();
+ }
+
+ internal ResourceLoadingStatusType GetResourceStatus()
+ {
+ return (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
+ }
+
+ /// <summary>
+ /// you can override it to clean-up your own resources.
+ /// </summary>
+ /// <param name="type">DisposeTypes</param>
+ /// <since_tizen> 3 </since_tizen>
+ protected override void Dispose(DisposeTypes type)
+ {
+ if (disposed)
+ {
+ return;
+ }
+
+ if (type == DisposeTypes.Explicit)
+ {
+ //Called by User
+ //Release your own managed resources here.
+ //You should release all of your own disposable objects here.
+ _border?.Dispose();
+ _border = null;
+ borderSelector?.Reset(this);
+ resourceUrlSelector?.Reset(this);
+ _imagePropertyUpdatedFlag = false;
+ if (_imagePropertyUpdateProcessAttachedFlag)
+ {
+ ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
+ _imagePropertyUpdateProcessAttachedFlag = false;
+ }
+ _imagePropertyMap?.Dispose();
+ _imagePropertyMap = null;
+ }
+
+ base.Dispose(type);
+ }
+
+ /// This will not be public opened.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
+ {
+ Interop.ImageView.DeleteImageView(swigCPtr);
+ }
+
+ // Callback for View ResourceReady signal
+ private void OnResourceReady(IntPtr data)
+ {
+ ResourceReadyEventArgs e = new ResourceReadyEventArgs();
+ if (data != null)
+ {
+ e.View = Registry.GetManagedBaseHandleFromNativePtr(data) as View;
+ }
+
+ if (_resourceReadyEventHandler != null)
+ {
+ _resourceReadyEventHandler(this, e);
+ }
+ }
+
+ private void SetResourceUrl(string value)
+ {
+ value = (value == null ? "" : value);
+ if (value.StartsWith("*Resource*"))
+ {
+ string resource = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
+ value = value.Replace("*Resource*", resource);
+ }
+ if(_resourceUrl != value)
+ {
+ _resourceUrl = value;
+ UpdateImage(ImageVisualProperty.URL, new PropertyValue(value));
+ }
+ }
+
+ private void SetBorder(Rectangle value)
+ {
+ if (value == null)
+ {
+ return;
+ }
+ if(_border != value)
+ {
+ _border = new Rectangle(value);
+ UpdateImage(NpatchImageVisualProperty.Border, new PropertyValue(_border));
+ }
+ }
+
+ /// <summary>
+ /// Lazy call to UpdateImage.
+ /// Collect Properties need to be update, and set properties that starts the Processing.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected void UpdateImage(int key, PropertyValue value)
+ {
+ // If we set ResourceUrl as empty, Unregist visual.
+ if (key == ImageVisualProperty.URL && string.IsNullOrEmpty(_resourceUrl))
+ {
+ // If previous resourceUrl was already empty, we don't need to do anything. just ignore.
+ // Unregist and dettach Process only if previous resourceUrl was not empty
+ string currentResourceUrl = "";
+ PropertyValue currentResourceUrlValue = _imagePropertyMap?.Find(ImageVisualProperty.URL);
+ if((currentResourceUrlValue?.Get(out currentResourceUrl) ?? false) && !string.IsNullOrEmpty(currentResourceUrl))
+ {
+ PropertyValue emptyValue = new PropertyValue();
+
+ // Remove current registed Image.
+ SetProperty(ImageView.Property.IMAGE, emptyValue);
+
+ // Image visual is not exist anymore. We should ignore lazy UpdateImage
+ _imagePropertyUpdatedFlag = false;
+ if(_imagePropertyUpdateProcessAttachedFlag)
+ {
+ ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
+ _imagePropertyUpdateProcessAttachedFlag = false;
+ }
+ // Update resourceUrl as null
+ _imagePropertyMap[ImageVisualProperty.URL] = emptyValue;
+
+ emptyValue?.Dispose();
+ }
+ return;
+ }
+
+ // Update image property map value as inputed value.
+ if (key != 0)
+ {
+ if (_imagePropertyMap == null)
+ {
+ _imagePropertyMap = new PropertyMap();
+ }
+ _imagePropertyUpdatedFlag = true;
+ _imagePropertyMap[key] = value;
+
+ // Lazy update only if _resourceUrl is not empty and ProcessAttachedFlag is false.
+ if (!string.IsNullOrEmpty(_resourceUrl) && !_imagePropertyUpdateProcessAttachedFlag)
+ {
+ _imagePropertyUpdateProcessAttachedFlag = true;
+ ProcessorController.Instance.ProcessorOnceEvent += UpdateImage;
+ // Call process hardly.
+ ProcessorController.Instance.Awake();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Callback function to Lazy UpdateImage.
+ /// </summary>
+ private void UpdateImage(object source, EventArgs e)
+ {
+ UpdateImage();
+ _imagePropertyUpdateProcessAttachedFlag = false;
+ }
+
+ /// <summary>
+ /// Update image-relative properties synchronously.
+ /// After call this API, All image properties updated.
+ /// </summary>
+ /// <remarks>
+ /// Current version ImageView property update asynchronously.
+ /// If you want to guarantee that ImageView property setuped,
+ /// Please call this ImageView.UpdateImage() API.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected void UpdateImage()
+ {
+ if(!_imagePropertyUpdatedFlag) return;
+
+ _imagePropertyUpdatedFlag = false;
+
+ if(_imagePropertyMap == null)
+ {
+ _imagePropertyMap = new PropertyMap();
+ }
+
+ if (_border == null)
+ {
+ PropertyValue image = new PropertyValue((int)Visual.Type.Image);
+ _imagePropertyMap[Visual.Property.Type] = image;
+ image?.Dispose();
+ }
+ else
+ {
+ PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch);
+ _imagePropertyMap[Visual.Property.Type] = nPatch;
+ nPatch?.Dispose();
+ PropertyValue border = new PropertyValue(_border);
+ _imagePropertyMap[NpatchImageVisualProperty.Border] = border;
+ border?.Dispose();
+ }
+
+ if (backgroundExtraData != null && backgroundExtraData.CornerRadius != null)
+ {
+ using (var cornerRadius = new PropertyValue(backgroundExtraData.CornerRadius))
+ using (var cornerRadiusPolicy = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy))
+ {
+ _imagePropertyMap[Visual.Property.CornerRadius] = cornerRadius;
+ _imagePropertyMap[Visual.Property.CornerRadiusPolicy] = new PropertyValue((int)(backgroundExtraData.CornerRadiusPolicy));
+ }
+ }
+
+ if (backgroundExtraData != null && backgroundExtraData.BorderlineWidth > 0.0f)
+ {
+ using (var borderlineWidth = new PropertyValue(backgroundExtraData.BorderlineWidth))
+ using (var borderlineColor = new PropertyValue(backgroundExtraData.BorderlineColor))
+ using (var borderlineOffset = new PropertyValue(backgroundExtraData.BorderlineOffset))
+ {
+ _imagePropertyMap[Visual.Property.BorderlineWidth] = borderlineWidth;
+ _imagePropertyMap[Visual.Property.BorderlineColor] = borderlineColor;
+ _imagePropertyMap[Visual.Property.BorderlineOffset] = borderlineOffset;
+ }
+ }
+
+ // Do Fitting Buffer when desired dimension is set
+ if (_desired_width != -1 && _desired_height != -1)
+ {
+ if (_resourceUrl != null)
+ {
+ Size2D imageSize = ImageLoader.GetOriginalImageSize(_resourceUrl, true);
+ if( imageSize.Height > 0 && imageSize.Width > 0 && _desired_width > 0 && _desired_height > 0 )
+ {
+ int adjustedDesiredWidth, adjustedDesiredHeight;
+ float aspectOfDesiredSize = (float)_desired_height / (float)_desired_width;
+ float aspectOfImageSize = (float)imageSize.Height / (float)imageSize.Width;
+ if (aspectOfImageSize > aspectOfDesiredSize)
+ {
+ adjustedDesiredWidth = _desired_width;
+ adjustedDesiredHeight = imageSize.Height * _desired_width / imageSize.Width;
+ }
+ else
+ {
+ adjustedDesiredWidth = imageSize.Width * _desired_height / imageSize.Height;
+ adjustedDesiredHeight = _desired_height;
+ }
+
+ PropertyValue returnWidth = new PropertyValue(adjustedDesiredWidth);
+ _imagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth;
+ returnWidth?.Dispose();
+ PropertyValue returnHeight = new PropertyValue(adjustedDesiredHeight);
+ _imagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight;
+ returnHeight?.Dispose();
+ PropertyValue scaleToFit = new PropertyValue((int)FittingModeType.ScaleToFill);
+ _imagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit;
+ scaleToFit?.Dispose();
+ }
+ else
+ {
+ Tizen.Log.Fatal("NUI", "[ERROR] Can't use DesiredSize when ImageLoading is failed.");
+ }
+ imageSize?.Dispose();
+ }
+ }
+
+ UpdateImageMap();
+ }
+ private void UpdateImageMap()
+ {
+ PropertyMap imageMap = new PropertyMap();
+
+ PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
+ image?.Get(imageMap);
+ imageMap.Merge(_imagePropertyMap);
+ PropertyValue setValue = new PropertyValue(imageMap);
+ SetProperty(ImageView.Property.IMAGE, setValue);
+
+ // Sync local PropertyMap
+ // TODO: Do we need to use GetProperty(SwigCPtr, ImageView.Property.IMAGE); here?
+ _imagePropertyMap.Dispose();
+ _imagePropertyMap = new PropertyMap(imageMap);
+
+ imageMap?.Dispose();
+ image?.Dispose();
+ setValue?.Dispose();
+ }
+
+ /// <summary>
+ /// GetNaturalSize() should be guaranteed that ResourceUrl property setuped.
+ /// So before get base.GetNaturalSize(), we should synchronous image properties
+ /// </summary>
+ internal override Vector3 GetNaturalSize()
+ {
+ // Sync as current properties
+ UpdateImage();
+ return base.GetNaturalSize();
+ }
+
+ private void OnResourceLoaded(IntPtr view)
+ {
+ ResourceLoadedEventArgs e = new ResourceLoadedEventArgs();
+ e.Status = (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
+
+ if (_resourceLoadedEventHandler != null)
+ {
+ _resourceLoadedEventHandler(this, e);
+ }
+ }
+
+ /// <summary>
+ /// Event arguments of resource ready.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public class ResourceReadyEventArgs : EventArgs
+ {
+ private View _view;
+
+ /// <summary>
+ /// The view whose resource is ready.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public View View
+ {
+ get
+ {
+ return _view;
+ }
+ set
+ {
+ _view = value;
+ }
+ }
+ }
+
+ internal class ResourceLoadedEventArgs : EventArgs
+ {
+ private ResourceLoadingStatusType status = ResourceLoadingStatusType.Invalid;
+ public ResourceLoadingStatusType Status
+ {
+ get
+ {
+ return status;
+ }
+ set
+ {
+ status = value;
+ }
+ }
+ }
+
+ internal new class Property
+ {
+ internal static readonly int IMAGE = Interop.ImageView.ImageGet();
+ internal static readonly int PreMultipliedAlpha = Interop.ImageView.PreMultipliedAlphaGet();
+ internal static readonly int PixelArea = Interop.ImageView.PixelAreaGet();
+ }
+
+ private enum ImageType
+ {
+ /// <summary>
+ /// For Normal Image.
+ /// </summary>
+ Normal = 0,
+
+ /// <summary>
+ /// For normal image, with synchronous loading and orientation correction property
+ /// </summary>
+ Specific = 1,
+
+ /// <summary>
+ /// For nine-patch image
+ /// </summary>
+ Npatch = 2,
+ }
+
+ private void OnBorderChanged(int x, int y, int width, int height)
+ {
+ Border = new Rectangle(x, y, width, height);
+ }
+ private void OnPixelAreaChanged(float x, float y, float z, float w)
+ {
+ PixelArea = new RelativeVector4(x, y, z, w);
+ }
+
+ private class ImageLayout : LayoutItem
+ {
+ /// <summary>
+ /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
+ /// If this is set to be true, then the width or height, which is not set by user explicitly, can be adjusted to preserve the aspect ratio of the image resource.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool AdjustViewSize
+ {
+ get
+ {
+ return (Owner as ImageView)?.AdjustViewSize ?? false;
+ }
+ set
+ {
+ if (Owner is ImageView imageView)
+ {
+ imageView.AdjustViewSize = value;
+ }
+ }
+ }
+
+ /// <inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
+ {
+ // To not change the view size by DALi
+ Owner.WidthResizePolicy = ResizePolicyType.Fixed;
+ Owner.HeightResizePolicy = ResizePolicyType.Fixed;
+
+ float specWidth = widthMeasureSpec.Size.AsDecimal();
+ float specHeight = heightMeasureSpec.Size.AsDecimal();
+ float naturalWidth = Owner.NaturalSize.Width;
+ float naturalHeight = Owner.NaturalSize.Height;
+ float minWidth = Owner.MinimumSize.Width;
+ float maxWidth = Owner.MaximumSize.Width;
+ float minHeight = Owner.MinimumSize.Height;
+ float maxHeight = Owner.MaximumSize.Height;
+ float aspectRatio = (naturalWidth > 0) ? (naturalHeight / naturalWidth) : 0;
+
+ // Assume that the new width and height are given from the view's suggested size by default.
+ float newWidth = Math.Min(Math.Max(naturalWidth, minWidth), (maxWidth < 0 ? Int32.MaxValue : maxWidth));
+ float newHeight = Math.Min(Math.Max(naturalHeight, minHeight), (maxHeight < 0 ? Int32.MaxValue : maxHeight));
+
+ // The width and height measure specs are going to be used to set measured size.
+ // Mark that the measure specs are changed by default to update measure specs later.
+ bool widthSpecChanged = true;
+ bool heightSpecChanged = true;
+
+ if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
+ {
+ newWidth = specWidth;
+ widthSpecChanged = false;
+ if (heightMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
+ {
+ if ((AdjustViewSize) && (aspectRatio > 0))
+ {
+ newHeight = newWidth * aspectRatio;
+ }
+ }
+ }
+
+ if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
+ {
+ newHeight = specHeight;
+ heightSpecChanged = false;
+
+ if (widthMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
+ {
+ if ((AdjustViewSize) && (aspectRatio > 0))
+ {
+ newWidth = newHeight / aspectRatio;
+ }
+ }
+ }
+
+ if (widthSpecChanged)
+ {
+ widthMeasureSpec = new MeasureSpecification(new LayoutLength(newWidth), MeasureSpecification.ModeType.Exactly);
+ }
+
+ if (heightSpecChanged)
+ {
+ heightMeasureSpec = new MeasureSpecification(new LayoutLength(newHeight), MeasureSpecification.ModeType.Exactly);
+ }
+
+ MeasuredSize.StateType childWidthState = MeasuredSize.StateType.MeasuredSizeOK;
+ MeasuredSize.StateType childHeightState = MeasuredSize.StateType.MeasuredSizeOK;
+
+ SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(newWidth), widthMeasureSpec, childWidthState),
+ ResolveSizeAndState(new LayoutLength(newHeight), heightMeasureSpec, childHeightState));
+ }
+ }
+ }
}