/*
* 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
{
///
/// ImageView is a class for displaying an image resource.
/// An instance of ImageView can be created using a URL or an image instance.
///
/// 3
public class ImageView : View
{
static ImageView() { }
/// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty ResourceUrlProperty = BindableProperty.Create(nameof(ImageView.ResourceUrl), typeof(string), typeof(ImageView), string.Empty, propertyChanged: (bindable, oldValue, newValue) =>
{
var imageView = (ImageView)bindable;
if (newValue is Selector selector)
{
imageView.ResourceUrlSelector = selector;
}
else
{
imageView.resourceUrlSelector?.Reset(imageView);
imageView.SetResourceUrl((string)newValue);
}
},
defaultValueCreator: (BindableProperty.CreateDefaultValueDelegate)((bindable) =>
{
var imageView = (ImageView)bindable;
string ret = "";
PropertyMap imageMap = new PropertyMap();
Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE).Get(imageMap);
imageMap.Find(ImageVisualProperty.URL)?.Get(out ret);
return ret;
}));
/// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty ImageProperty = BindableProperty.Create(nameof(ImageView.Image), typeof(PropertyMap), typeof(ImageView), null, propertyChanged: (BindableProperty.BindingPropertyChangedDelegate)((bindable, oldValue, newValue) =>
{
var imageView = (ImageView)bindable;
if (newValue != null)
{
PropertyMap map = (PropertyMap)newValue;
if (imageView.IsCreateByXaml)
{
string url = "", alphaMaskURL = "", auxiliaryImageURL = "";
string resource = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
PropertyValue urlValue = map.Find(NDalic.ImageVisualUrl);
bool ret = false;
if (urlValue != null) ret = urlValue.Get(out url);
PropertyMap mmap = new PropertyMap();
if (ret && url.StartsWith("*Resource*"))
{
url = url.Replace("*Resource*", resource);
mmap.Insert(NDalic.ImageVisualUrl, new PropertyValue(url));
}
ret = false;
PropertyValue alphaMaskUrlValue = map.Find(NDalic.ImageVisualAlphaMaskUrl);
if (alphaMaskUrlValue != null) ret = alphaMaskUrlValue.Get(out alphaMaskURL);
if (ret && alphaMaskURL.StartsWith("*Resource*"))
{
alphaMaskURL = alphaMaskURL.Replace("*Resource*", resource);
mmap.Insert(NDalic.ImageVisualUrl, new PropertyValue(alphaMaskURL));
}
ret = false;
PropertyValue auxiliaryImageURLValue = map.Find(NDalic.ImageVisualAuxiliaryImageUrl);
if (auxiliaryImageURLValue != null) ret = auxiliaryImageURLValue.Get(out auxiliaryImageURL);
if (ret && auxiliaryImageURL.StartsWith("*Resource*"))
{
auxiliaryImageURL = auxiliaryImageURL.Replace("*Resource*", resource);
mmap.Insert(NDalic.ImageVisualAuxiliaryImageUrl, new PropertyValue(auxiliaryImageURL));
}
map.Merge(mmap);
}
if (imageView._border == null)
{
Tizen.NUI.Object.SetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE, new Tizen.NUI.PropertyValue(map));
}
}
}),
defaultValueCreator: (BindableProperty.CreateDefaultValueDelegate)((bindable) =>
{
var imageView = (ImageView)bindable;
if (imageView._border == null)
{
PropertyMap temp = new PropertyMap();
Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE).Get(temp);
return temp;
}
else
{
return null;
}
}));
/// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty PreMultipliedAlphaProperty = BindableProperty.Create(nameof(PreMultipliedAlpha), typeof(bool), typeof(ImageView), false, propertyChanged: (BindableProperty.BindingPropertyChangedDelegate)((bindable, oldValue, newValue) =>
{
var imageView = (ImageView)bindable;
if (newValue != null)
{
Tizen.NUI.Object.SetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.PreMultipliedAlpha, new Tizen.NUI.PropertyValue((bool)newValue));
}
}),
defaultValueCreator: (BindableProperty.CreateDefaultValueDelegate)((bindable) =>
{
var imageView = (ImageView)bindable;
bool temp = false;
Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.PreMultipliedAlpha).Get(out temp);
return temp;
}));
/// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty PixelAreaProperty = BindableProperty.Create(nameof(PixelArea), typeof(RelativeVector4), typeof(ImageView), null, propertyChanged: (BindableProperty.BindingPropertyChangedDelegate)((bindable, oldValue, newValue) =>
{
var imageView = (ImageView)bindable;
if (newValue != null)
{
Tizen.NUI.Object.SetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.PixelArea, new Tizen.NUI.PropertyValue((RelativeVector4)newValue));
}
}),
defaultValueCreator: (BindableProperty.CreateDefaultValueDelegate)((bindable) =>
{
var imageView = (ImageView)bindable;
Vector4 temp = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.PixelArea).Get(temp);
RelativeVector4 relativeTemp = new RelativeVector4(temp.X, temp.Y, temp.Z, temp.W);
return relativeTemp;
}));
/// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty BorderProperty = BindableProperty.Create(nameof(Border), typeof(Rectangle), typeof(ImageView), null, propertyChanged: (bindable, oldValue, newValue) =>
{
var imageView = (ImageView)bindable;
imageView.borderSelector?.Reset(imageView);
if (newValue is Selector selector)
{
if (selector.HasAll()) imageView.SetBorder(selector.All);
else imageView.borderSelector = new TriggerableSelector(imageView, selector, imageView.SetBorder, true);
}
else
{
imageView.SetBorder((Rectangle)newValue);
}
},
defaultValueCreator: (bindable) =>
{
var imageView = (ImageView)bindable;
return imageView._border;
});
/// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty BorderOnlyProperty = BindableProperty.Create(nameof(BorderOnly), typeof(bool), typeof(ImageView), false, propertyChanged: (bindable, oldValue, newValue) =>
{
var imageView = (ImageView)bindable;
if (newValue != null)
{
imageView.UpdateImage(NpatchImageVisualProperty.BorderOnly, new PropertyValue((bool)newValue));
}
},
defaultValueCreator: (BindableProperty.CreateDefaultValueDelegate)((bindable) =>
{
var imageView = (ImageView)bindable;
bool ret = false;
PropertyMap imageMap = new PropertyMap();
Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE).Get(imageMap);
imageMap.Find(ImageVisualProperty.BorderOnly)?.Get(out ret);
return ret;
}));
/// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty SynchronosLoadingProperty = BindableProperty.Create(nameof(SynchronousLoading), typeof(bool), typeof(ImageView), false, propertyChanged: (bindable, oldValue, newValue) =>
{
var imageView = (ImageView)bindable;
if (newValue != null)
{
imageView._synchronousLoading = (bool)newValue;
imageView.UpdateImage(NpatchImageVisualProperty.SynchronousLoading, new PropertyValue((bool)newValue));
}
},
defaultValueCreator: (bindable) =>
{
var imageView = (ImageView)bindable;
return imageView._synchronousLoading;
});
/// This will be public opened in tizen_7.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty SynchronousLoadingProperty = BindableProperty.Create(nameof(SynchronousLoading), typeof(bool), typeof(ImageView), false, propertyChanged: (bindable, oldValue, newValue) =>
{
var imageView = (ImageView)bindable;
if (newValue != null)
{
imageView._synchronousLoading = (bool)newValue;
imageView.UpdateImage(NpatchImageVisualProperty.SynchronousLoading, new PropertyValue((bool)newValue));
}
},
defaultValueCreator: (bindable) =>
{
var imageView = (ImageView)bindable;
return imageView._synchronousLoading;
});
/// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty OrientationCorrectionProperty = BindableProperty.Create(nameof(OrientationCorrection), typeof(bool), typeof(ImageView), false, propertyChanged: (bindable, oldValue, newValue) =>
{
var imageView = (ImageView)bindable;
if (newValue != null)
{
imageView.UpdateImage(ImageVisualProperty.OrientationCorrection, new PropertyValue((bool)newValue));
}
},
defaultValueCreator: (BindableProperty.CreateDefaultValueDelegate)((bindable) =>
{
var imageView = (ImageView)bindable;
bool ret = false;
PropertyMap imageMap = new PropertyMap();
Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE).Get(imageMap);
imageMap?.Find(ImageVisualProperty.OrientationCorrection)?.Get(out ret);
return ret;
}));
private EventHandler _resourceReadyEventHandler;
private ResourceReadyEventCallbackType _resourceReadyEventCallback;
private EventHandler _resourceLoadedEventHandler;
private _resourceLoadedCallbackType _resourceLoadedCallback;
private Rectangle _border;
private string _resourceUrl = "";
private bool _synchronousLoading = false;
private string _alphaMaskUrl = null;
private int _desired_width = -1;
private int _desired_height = -1;
private bool _cropToMask = false;
private VisualFittingModeType _fittingMode = VisualFittingModeType.Fill;
private TriggerableSelector resourceUrlSelector;
private TriggerableSelector borderSelector;
///
/// Creates an initialized ImageView.
///
/// 3
public ImageView() : this(Interop.ImageView.New(), true)
{
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
/// 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)
{
}
///
/// Creates an initialized ImageView with setting the status of shown or hidden.
///
/// false : Not displayed (hidden), true : displayed (shown)
/// 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);
}
///
/// Creates an initialized ImageView from a URL to an image resource.
/// If the string is empty, ImageView will not display anything.
///
/// The URL of the image resource to display.
/// 3
public ImageView(string url) : this(Interop.ImageView.New(url), true)
{
ResourceUrl = url;
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Creates an initialized ImageView from a URL to an image resource with setting shown or hidden.
///
/// The URL of the image resource to display.
/// false : Not displayed (hidden), true : displayed (shown)
/// 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)
{
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);
}
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void ResourceReadyEventCallbackType(IntPtr data);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void _resourceLoadedCallbackType(IntPtr view);
///
/// An event for ResourceReady signal which can be used to subscribe or unsubscribe the event handler.
/// This signal is emitted after all resources required by a control are loaded and ready.
/// Most resources are only loaded when the control is placed on the stage.
///
/// 3
public event EventHandler ResourceReady
{
add
{
if (_resourceReadyEventHandler == null)
{
_resourceReadyEventCallback = OnResourceReady;
ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
resourceReadySignal?.Connect(_resourceReadyEventCallback);
resourceReadySignal?.Dispose();
}
_resourceReadyEventHandler += value;
}
remove
{
_resourceReadyEventHandler -= value;
ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
if (_resourceReadyEventHandler == null && resourceReadySignal?.Empty() == false)
{
resourceReadySignal?.Disconnect(_resourceReadyEventCallback);
}
resourceReadySignal?.Dispose();
}
}
internal event EventHandler ResourceLoaded
{
add
{
if (_resourceLoadedEventHandler == null)
{
_resourceLoadedCallback = OnResourceLoaded;
ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
resourceReadySignal?.Connect(_resourceLoadedCallback);
resourceReadySignal?.Dispose();
}
_resourceLoadedEventHandler += value;
}
remove
{
_resourceLoadedEventHandler -= value;
ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
if (_resourceLoadedEventHandler == null && resourceReadySignal?.Empty() == false)
{
resourceReadySignal?.Disconnect(_resourceLoadedCallback);
}
resourceReadySignal?.Dispose();
}
}
///
/// Enumeration for LoadingStatus of image.
///
/// 5
public enum LoadingStatusType
{
///
/// Loading preparing status.
///
/// 5
Preparing,
///
/// Loading ready status.
///
/// 5
Ready,
///
/// Loading failed status.
///
/// 5
Failed
}
///
/// 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.
///
/// 3
public string ResourceUrl
{
get
{
return (string)GetValue(ResourceUrlProperty);
}
set
{
SetValue(ResourceUrlProperty, value);
NotifyPropertyChanged();
}
}
///
/// This will be deprecated, please use Image instead.
/// ImageView ImageMap, type PropertyMap: string if it is a URL, map otherwise.
///
/// 3
[Obsolete("Please do not use! This will be deprecated! Please use Image property instead!")]
[EditorBrowsable(EditorBrowsableState.Never)]
public PropertyMap ImageMap
{
get
{
if (_border == null)
{
PropertyMap returnValue = new PropertyMap();
PropertyValue image = GetProperty(ImageView.Property.IMAGE);
image?.Get(returnValue);
image?.Dispose();
return returnValue;
}
else
{
return null;
}
}
set
{
if (_border == null)
{
PropertyValue setValue = new Tizen.NUI.PropertyValue(value);
SetProperty(ImageView.Property.IMAGE, setValue);
NotifyPropertyChanged();
setValue?.Dispose();
}
}
}
///
/// ImageView Image, type PropertyMap: string if it is a URL, map otherwise.
///
///
/// This PropertyMap use a .
/// See for a detailed description.
/// you can also use .
/// See for a detailed description.
///
///
/// The following example demonstrates how to use the Image property.
///
/// 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;
///
///
/// 4
public PropertyMap Image
{
get
{
if (_border == null)
{
return (PropertyMap)GetValue(ImageProperty);
}
else
{
return null;
}
}
set
{
if (_border == null)
{
SetValue(ImageProperty, value);
NotifyPropertyChanged();
}
}
}
///
/// ImageView PreMultipliedAlpha, type Boolean.
/// Image must be initialized.
///
/// 3
public bool PreMultipliedAlpha
{
get
{
return (bool)GetValue(PreMultipliedAlphaProperty);
}
set
{
SetValue(PreMultipliedAlphaProperty, value);
NotifyPropertyChanged();
}
}
///
/// ImageView PixelArea, type Vector4 (Animatable property).
/// Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0].
///
///
/// The property cascade chaining set is possible. For example, this (imageView.PixelArea.X = 0.1f;) is possible.
///
/// 3
public RelativeVector4 PixelArea
{
get
{
RelativeVector4 temp = (RelativeVector4)GetValue(PixelAreaProperty);
return new RelativeVector4(OnPixelAreaChanged, temp.X, temp.Y, temp.Z, temp.W);
}
set
{
SetValue(PixelAreaProperty, value);
NotifyPropertyChanged();
}
}
///
/// The border of the image in the order: left, right, bottom, top.
/// If set, ImageMap will be ignored.
/// For N-Patch images only.
/// Optional.
///
///
/// The property cascade chaining set is possible. For example, this (imageView.Border.X = 1;) is possible.
///
/// 3
public Rectangle Border
{
get
{
Rectangle temp = (Rectangle)GetValue(BorderProperty);
if (null == temp)
{
return null;
}
else
{
return new Rectangle(OnBorderChanged, temp.X, temp.Y, temp.Width, temp.Height);
}
}
set
{
SetValue(BorderProperty, value);
NotifyPropertyChanged();
}
}
///
/// Gets or sets whether to draw the borders only (if true).
/// If not specified, the default is false.
/// For N-Patch images only.
/// Optional.
///
/// 3
public bool BorderOnly
{
get
{
return (bool)GetValue(BorderOnlyProperty);
}
set
{
SetValue(BorderOnlyProperty, value);
NotifyPropertyChanged();
}
}
///
/// Gets or sets whether to synchronous loading the resourceurl of image.
///
/// 3
[Obsolete("Deprecated since API level 9 and will be removed in API level 11. Please use SynchronousLoading instead!")]
public bool SynchronosLoading
{
get
{
return SynchronousLoading;
}
set
{
SynchronousLoading = value;
}
}
///
/// Gets or sets whether the image of the ResourceUrl property will be loaded synchronously.
///
///
/// Changing this property make this ImageView load image synchronously at the next loading
/// by following operation: , ,
/// and by some properties those cause reloading: , and etc.
///
/// 9
public bool SynchronousLoading
{
get
{
return (bool)GetValue(SynchronousLoadingProperty);
}
set
{
SetValue(SynchronousLoadingProperty, value);
NotifyPropertyChanged();
}
}
///
/// Gets or sets whether to automatically correct the orientation of an image.
///
/// 5
public bool OrientationCorrection
{
get
{
return (bool)GetValue(OrientationCorrectionProperty);
}
set
{
SetValue(OrientationCorrectionProperty, value);
NotifyPropertyChanged();
}
}
///
/// Gets the loading state of the visual resource.
///
/// 5
public ImageView.LoadingStatusType LoadingStatus
{
get
{
return (ImageView.LoadingStatusType)Interop.View.GetVisualResourceStatus(SwigCPtr, (int)Property.IMAGE);
}
}
///
/// Downcasts a handle to imageView handle.
///
/// Thrown when handle is null.
/// Please do not use! this will be deprecated!
/// Instead please use as keyword.
/// 3
[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 (null == handle)
{
throw new ArgumentNullException(nameof(handle));
}
ImageView ret = Registry.GetManagedBaseHandleFromNativePtr(handle) as ImageView;
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return ret;
}
///
/// Sets this ImageView from the given URL.
/// If the URL is empty, ImageView will not display anything.
///
/// The URL to the image resource to display.
/// Thrown when url is null.
/// 3
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;
}
///
/// Queries if all resources required by a control are loaded and ready.
/// Most resources are only loaded when the control is placed on the stage.
/// True if the resources are loaded and ready, false otherwise.
///
/// 3
public new bool IsResourceReady()
{
bool ret = Interop.View.IsResourceReady(SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending)
throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return ret;
}
///
/// Forcefully reloads the image. All the visuals using this image will reload to the latest image.
///
/// 5
public void Reload()
{
PropertyValue attributes = new PropertyValue(0);
this.DoAction(ImageView.Property.IMAGE, ActionReload, attributes);
attributes?.Dispose();
}
///
/// Plays the animated GIF. This is also the default playback mode.
///
/// 5
public void Play()
{
PropertyValue attributes = new PropertyValue(0);
this.DoAction(ImageView.Property.IMAGE, ActionPlay, attributes);
attributes?.Dispose();
}
///
/// Pauses the animated GIF.
///
/// 5
public void Pause()
{
PropertyValue attributes = new PropertyValue(0);
this.DoAction(ImageView.Property.IMAGE, ActionPause, attributes);
attributes?.Dispose();
}
///
/// Stops the animated GIF.
///
/// 5
public void Stop()
{
PropertyValue attributes = new PropertyValue(0);
this.DoAction(ImageView.Property.IMAGE, ActionStop, attributes);
attributes?.Dispose();
}
///
/// Gets or sets the URL of the alpha mask.
/// Optional.
///
/// 6
[EditorBrowsable(EditorBrowsableState.Never)]
public string AlphaMaskURL
{
get
{
string ret = "";
PropertyMap imageMap = new PropertyMap();
PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
image?.Get(imageMap);
PropertyValue maskUrl = imageMap?.Find(ImageVisualProperty.AlphaMaskURL);
maskUrl?.Get(out ret);
_alphaMaskUrl = ret;
imageMap?.Dispose();
image?.Dispose();
maskUrl?.Dispose();
return ret;
}
set
{
if (value == null)
{
value = "";
}
_alphaMaskUrl = value;
PropertyValue setValue = new PropertyValue(value);
UpdateImage(ImageVisualProperty.AlphaMaskURL, setValue);
setValue?.Dispose();
}
}
///
/// Whether to crop image to mask or scale mask to fit image.
///
/// 6
public bool CropToMask
{
get
{
bool ret = _cropToMask;
PropertyMap imageMap = new PropertyMap();
PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
image?.Get(imageMap);
PropertyValue cropUrl = imageMap?.Find(ImageVisualProperty.CropToMask);
cropUrl?.Get(out ret);
_cropToMask = ret;
imageMap?.Dispose();
image?.Dispose();
cropUrl?.Dispose();
return ret;
}
set
{
_cropToMask = value;
PropertyValue setValue = new PropertyValue(value);
UpdateImage(ImageVisualProperty.CropToMask, setValue);
setValue.Dispose();
}
}
///
/// Actions property value for Reload image.
///
private int ActionReload { get; set; } = Interop.ImageView.ImageVisualActionReloadGet();
///
/// Actions property value to Play animated images.
/// This property can be redefined by child class if it use different value.
///
[EditorBrowsable(EditorBrowsableState.Never)]
protected int ActionPlay { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet();
///
/// Actions property value to Pause animated images.
/// This property can be redefined by child class if it use different value.
///
[EditorBrowsable(EditorBrowsableState.Never)]
protected int ActionPause { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet();
///
/// Actions property value to Stop animated images.
/// This property can be redefined by child class if it use different value.
///
[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();
}
///
/// Gets or sets fitting options used when resizing images to fit.
/// If not supplied, the default is FittingModeType.Fill.
/// For normal quad images only.
/// Optional.
///
/// 6
[EditorBrowsable(EditorBrowsableState.Never)]
public FittingModeType FittingMode
{
get
{
int ret = (int)_fittingMode;
PropertyMap imageMap = new PropertyMap();
PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
image?.Get(imageMap);
PropertyValue fittingMode = imageMap?.Find(Visual.Property.VisualFittingMode);
fittingMode?.Get(out ret);
_fittingMode = (VisualFittingModeType)ret;
imageMap?.Dispose();
image?.Dispose();
fittingMode?.Dispose();
return ConvertVisualFittingModetoFittingMode((VisualFittingModeType)ret);
}
set
{
VisualFittingModeType ret = ConvertFittingModetoVisualFittingMode(value);
PropertyValue setValue = new PropertyValue((int)ret);
if(_fittingMode != ret)
{
_fittingMode = ret;
UpdateImage(Visual.Property.VisualFittingMode, setValue);
}
setValue?.Dispose();
}
}
///
/// Gets or sets the desired image width.
/// If not specified, the actual image width is used.
/// For normal quad images only.
/// Optional.
///
/// 6
[EditorBrowsable(EditorBrowsableState.Never)]
public int DesiredWidth
{
get
{
PropertyMap imageMap = new PropertyMap();
PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
image?.Get(imageMap);
PropertyValue desireWidth = imageMap?.Find(ImageVisualProperty.DesiredWidth);
desireWidth?.Get(out _desired_width);
imageMap?.Dispose();
image?.Dispose();
desireWidth?.Dispose();
return _desired_width;
}
set
{
if (_desired_width != value)
{
_desired_width = value;
UpdateImage(0, null);
}
}
}
///
/// Gets or sets the desired image height.
/// If not specified, the actual image height is used.
/// For normal quad images only.
/// Optional.
///
/// 6
[EditorBrowsable(EditorBrowsableState.Never)]
public int DesiredHeight
{
get
{
PropertyMap imageMap = new PropertyMap();
PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
image?.Get(imageMap);
PropertyValue desireheight = imageMap?.Find(ImageVisualProperty.DesiredHeight);
desireheight?.Get(out _desired_height);
imageMap?.Dispose();
image?.Dispose();
desireheight?.Dispose();
return _desired_height;
}
set
{
if (_desired_height != value)
{
_desired_height = value;
UpdateImage(0, null);
}
}
}
///
/// Gets or sets ReleasePolicy for image.
/// If not supplied, the default is ReleasePolicyType.Detached.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public ReleasePolicyType ReleasePolicy
{
get
{
int ret = (int)ReleasePolicyType.Detached;
PropertyMap imageMap = new PropertyMap();
PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
image?.Get(imageMap);
PropertyValue releasePoli = imageMap?.Find(ImageVisualProperty.ReleasePolicy);
releasePoli?.Get(out ret);
imageMap?.Dispose();
image?.Dispose();
releasePoli?.Dispose();
return (ReleasePolicyType)ret;
}
set
{
PropertyValue setValue = new PropertyValue((int)value);
UpdateImage(ImageVisualProperty.ReleasePolicy, setValue);
setValue?.Dispose();
}
}
///
/// Gets or sets the wrap mode for the u coordinate.
/// It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.
/// If not specified, the default is WrapModeType.Default(CLAMP).
/// For normal quad images only.
/// Optional.
///
/// 6
[EditorBrowsable(EditorBrowsableState.Never)]
public WrapModeType WrapModeU
{
get
{
int ret = (int)WrapModeType.Default;
PropertyMap imageMap = new PropertyMap();
PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
image?.Get(imageMap);
PropertyValue warpModeU = imageMap?.Find(ImageVisualProperty.WrapModeU);
warpModeU?.Get(out ret);
imageMap?.Dispose();
image?.Dispose();
warpModeU?.Dispose();
return (WrapModeType)ret;
}
set
{
PropertyValue setValue = new PropertyValue((int)value);
UpdateImage(ImageVisualProperty.WrapModeU, setValue);
setValue?.Dispose();
}
}
///
/// Gets or sets the wrap mode for the v coordinate.
/// It decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.
/// 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.
/// If not specified, the default is WrapModeType.Default(CLAMP).
/// For normal quad images only.
/// Optional.
///
/// 6
[EditorBrowsable(EditorBrowsableState.Never)]
public WrapModeType WrapModeV
{
get
{
int ret = (int)WrapModeType.Default;
PropertyMap imageMap = new PropertyMap();
PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
image?.Get(imageMap);
PropertyValue wrapModeV = imageMap?.Find(ImageVisualProperty.WrapModeV);
wrapModeV?.Get(out ret);
imageMap?.Dispose();
image?.Dispose();
wrapModeV?.Dispose();
return (WrapModeType)ret;
}
set
{
PropertyValue setValue = new PropertyValue((int)value);
UpdateImage(ImageVisualProperty.WrapModeV, setValue);
setValue?.Dispose();
}
}
///
/// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
///
///
/// 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).
///
/// 9
public bool AdjustViewSize { get; set; } = false;
internal Selector ResourceUrlSelector
{
get => GetSelector(resourceUrlSelector, ImageView.ResourceUrlProperty);
set
{
resourceUrlSelector?.Reset(this);
if (value == null) return;
if (value.HasAll()) SetResourceUrl(value.All);
else resourceUrlSelector = new TriggerableSelector(this, value, SetResourceUrl, true);
}
}
///
/// Get attributes, it is abstract function and must be override.
///
[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;
}
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();
UpdateImage(0, null);
}
internal override void ApplyBorderline()
{
base.ApplyBorderline();
// Apply borderline to IMAGE.
if (backgroundExtraData != null)
{
var borderlineColor = backgroundExtraData.BorderlineColor == null ? new PropertyValue(Color.Black) : new PropertyValue(backgroundExtraData.BorderlineColor);
// Apply to the image visual
PropertyMap imageMap = new PropertyMap();
PropertyValue imageValue = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
if (imageValue.Get(imageMap) && !imageMap.Empty())
{
imageMap[Visual.Property.BorderlineWidth] = new PropertyValue(backgroundExtraData.BorderlineWidth);
imageMap[Visual.Property.BorderlineColor] = borderlineColor;
imageMap[Visual.Property.BorderlineOffset] = new PropertyValue(backgroundExtraData.BorderlineOffset);
var temp = new PropertyValue(imageMap);
Tizen.NUI.Object.SetProperty(SwigCPtr, ImageView.Property.IMAGE, temp);
temp.Dispose();
}
imageMap.Dispose();
imageValue.Dispose();
borderlineColor.Dispose();
}
UpdateImage(0, null);
}
internal ResourceLoadingStatusType GetResourceStatus()
{
return (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
}
///
/// you can override it to clean-up your own resources.
///
/// DisposeTypes
/// 3
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);
}
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);
}
_resourceUrl = value;
UpdateImage(ImageVisualProperty.URL, new PropertyValue(value));
}
private void SetBorder(Rectangle value)
{
if (value == null)
{
return;
}
_border = new Rectangle(value);
UpdateImage(NpatchImageVisualProperty.Border, new PropertyValue(_border));
}
private void UpdateImageMap(PropertyMap fromMap)
{
PropertyMap imageMap = new PropertyMap();
PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE);
image?.Get(imageMap);
imageMap?.Merge(fromMap);
PropertyValue setValue = new PropertyValue(imageMap);
SetProperty(ImageView.Property.IMAGE, setValue);
imageMap?.Dispose();
image?.Dispose();
setValue?.Dispose();
}
private void UpdateImage(int key, PropertyValue value)
{
PropertyMap imageMap = new PropertyMap();
if (_alphaMaskUrl != null)
{
PropertyValue alphaMaskUrl = new PropertyValue(_alphaMaskUrl);
imageMap?.Insert(ImageVisualProperty.AlphaMaskURL, alphaMaskUrl);
alphaMaskUrl?.Dispose();
}
if(key != ImageVisualProperty.CropToMask)
{
PropertyValue cropToMask = new PropertyValue(_cropToMask);
imageMap?.Insert(ImageVisualProperty.CropToMask, cropToMask);
cropToMask?.Dispose();
}
if (string.IsNullOrEmpty(_resourceUrl))
{
PropertyValue resourceUrl = new PropertyValue(_resourceUrl);
imageMap?.Insert(ImageVisualProperty.URL, resourceUrl);
PropertyValue setValue = new PropertyValue(imageMap);
SetProperty(ImageView.Property.IMAGE, setValue);
resourceUrl?.Dispose();
setValue?.Dispose();
return;
}
if (_border == null)
{
PropertyValue image = new PropertyValue((int)Visual.Type.Image);
imageMap?.Insert(Visual.Property.Type, image);
image?.Dispose();
}
else
{
PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch);
imageMap?.Insert(Visual.Property.Type, nPatch);
nPatch?.Dispose();
PropertyValue border = new PropertyValue(_border);
imageMap?.Insert(NpatchImageVisualProperty.Border, border);
border?.Dispose();
}
if(key != Visual.Property.VisualFittingMode && _fittingMode != VisualFittingModeType.Fill)
{
PropertyValue fittingMode = new PropertyValue((int)_fittingMode);
imageMap?.Insert(Visual.Property.VisualFittingMode, fittingMode);
fittingMode?.Dispose();
}
PropertyValue synchronousLoading = new PropertyValue(_synchronousLoading);
imageMap?.Insert(NpatchImageVisualProperty.SynchronousLoading, synchronousLoading);
synchronousLoading?.Dispose();
if (backgroundExtraData != null && backgroundExtraData.CornerRadius != null)
{
using (var cornerRadius = new PropertyValue(backgroundExtraData.CornerRadius))
using (var cornerRadiusPolicy = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy))
{
imageMap.Insert(Visual.Property.CornerRadius, cornerRadius);
imageMap.Insert(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))
{
imageMap.Insert(Visual.Property.BorderlineWidth, borderlineWidth);
imageMap.Insert(Visual.Property.BorderlineColor, borderlineColor);
imageMap.Insert(Visual.Property.BorderlineOffset, borderlineOffset);
}
}
if (value != null)
{
imageMap?.Insert(key, value);
}
// 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);
imageMap?.Insert(ImageVisualProperty.DesiredWidth, returnWidth);
returnWidth?.Dispose();
PropertyValue returnHeight = new PropertyValue(adjustedDesiredHeight);
imageMap?.Insert(ImageVisualProperty.DesiredHeight, returnHeight);
returnHeight?.Dispose();
PropertyValue scaleToFit = new PropertyValue((int)FittingModeType.ScaleToFill);
imageMap?.Insert(ImageVisualProperty.FittingMode, scaleToFit);
scaleToFit?.Dispose();
}
else
{
Tizen.Log.Fatal("NUI", "[ERROR] Can't use DesiredSize when ImageLoading is failed.");
}
imageSize?.Dispose();
}
}
UpdateImageMap(imageMap);
imageMap?.Dispose();
imageMap = null;
}
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);
}
}
///
/// Event arguments of resource ready.
///
/// 3
public class ResourceReadyEventArgs : EventArgs
{
private View _view;
///
/// The view whose resource is ready.
///
/// 3
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
{
///
/// For Normal Image.
///
Normal = 0,
///
/// For normal image, with synchronous loading and orientation correction property
///
Specific = 1,
///
/// For nine-patch image
///
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
{
///
/// 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.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public bool AdjustViewSize
{
get
{
return (Owner as ImageView)?.AdjustViewSize ?? false;
}
set
{
if (Owner is ImageView imageView)
{
imageView.AdjustViewSize = value;
}
}
}
///
[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));
}
}
}
}