2 * Copyright(c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20 using System.ComponentModel;
21 using Tizen.NUI.Binding;
23 namespace Tizen.NUI.BaseComponents
27 /// ImageView is a class for displaying an image resource.<br />
28 /// An instance of ImageView can be created using a URL or an image instance.<br />
30 /// <since_tizen> 3 </since_tizen>
31 public partial class ImageView : View
33 static ImageView() { }
35 private EventHandler<ResourceReadyEventArgs> _resourceReadyEventHandler;
36 private ResourceReadyEventCallbackType _resourceReadyEventCallback;
37 private EventHandler<ResourceLoadedEventArgs> _resourceLoadedEventHandler;
38 private _resourceLoadedCallbackType _resourceLoadedCallback;
41 /// Convert non-null string that some keyword change as application specific directory.
43 /// <param name="value">Inputed and replaced after this function finished</param>
44 /// <returns>Replaced url</returns>
45 private static string ConvertResourceUrl(ref string value)
48 if (value.StartsWith("*Resource*"))
50 string resource = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
51 value = value.Replace("*Resource*", resource);
56 // Collection of image-sensitive properties.
57 private static readonly List<int> cachedImagePropertyKeyList = new List<int> {
59 ImageVisualProperty.URL,
60 ImageVisualProperty.AlphaMaskURL,
61 ImageVisualProperty.CropToMask,
62 Visual.Property.VisualFittingMode,
63 ImageVisualProperty.DesiredWidth,
64 ImageVisualProperty.DesiredHeight,
65 ImageVisualProperty.ReleasePolicy,
66 ImageVisualProperty.WrapModeU,
67 ImageVisualProperty.WrapModeV,
68 ImageVisualProperty.SynchronousLoading,
69 Visual.Property.PremultipliedAlpha,
70 ImageVisualProperty.OrientationCorrection,
71 NpatchImageVisualProperty.Border,
72 NpatchImageVisualProperty.BorderOnly,
74 internal PropertyMap cachedImagePropertyMap;
75 internal bool imagePropertyUpdatedFlag = false;
77 private bool imagePropertyUpdateProcessAttachedFlag = false;
78 private Rectangle _border;
79 private string _resourceUrl = "";
80 private int _desired_width = -1;
81 private int _desired_height = -1;
82 private TriggerableSelector<string> resourceUrlSelector;
83 private TriggerableSelector<Rectangle> borderSelector;
85 private RelativeVector4 internalPixelArea;
88 /// Creates an initialized ImageView.
90 /// <since_tizen> 3 </since_tizen>
91 public ImageView() : this(Interop.ImageView.New(), true)
93 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
96 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
97 [EditorBrowsable(EditorBrowsableState.Never)]
98 public ImageView(ViewStyle viewStyle) : this(Interop.ImageView.New(), true, viewStyle)
103 /// Creates an initialized ImageView with setting the status of shown or hidden.
105 /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
106 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
107 [EditorBrowsable(EditorBrowsableState.Never)]
108 public ImageView(bool shown) : this(Interop.ImageView.New(), true)
110 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
115 /// Creates an initialized ImageView from a URL to an image resource.<br />
116 /// If the string is empty, ImageView will not display anything.<br />
118 /// <param name="url">The URL of the image resource to display.</param>
119 /// <since_tizen> 3 </since_tizen>
120 public ImageView(string url) : this(Interop.ImageView.New(ConvertResourceUrl(ref url)), true)
123 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
128 /// Creates an initialized ImageView from a URL to an image resource with setting shown or hidden.
130 /// <param name="url">The URL of the image resource to display.</param>
131 /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
132 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
133 [EditorBrowsable(EditorBrowsableState.Never)]
134 public ImageView(string url, bool shown) : this(Interop.ImageView.New(ConvertResourceUrl(ref url)), true)
137 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
141 internal ImageView(string url, Uint16Pair size, bool shown = true) : this(Interop.ImageView.New(ConvertResourceUrl(ref url), Uint16Pair.getCPtr(size)), true)
144 _desired_width = size?.GetWidth() ?? -1;
145 _desired_height = size?.GetHeight() ?? -1;
146 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
154 internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, ViewStyle viewStyle, bool shown = true) : base(cPtr, cMemoryOwn, viewStyle)
162 internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, bool shown = true) : base(cPtr, cMemoryOwn, null)
170 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
171 private delegate void ResourceReadyEventCallbackType(IntPtr data);
172 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
173 private delegate void _resourceLoadedCallbackType(IntPtr view);
176 /// An event for ResourceReady signal which can be used to subscribe or unsubscribe the event handler.<br />
177 /// This signal is emitted after all resources required by a control are loaded and ready.<br />
178 /// Most resources are only loaded when the control is placed on the stage.<br />
180 /// <since_tizen> 3 </since_tizen>
181 public event EventHandler<ResourceReadyEventArgs> ResourceReady
185 if (_resourceReadyEventHandler == null)
187 _resourceReadyEventCallback = OnResourceReady;
188 ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
189 resourceReadySignal?.Connect(_resourceReadyEventCallback);
190 resourceReadySignal?.Dispose();
193 _resourceReadyEventHandler += value;
198 _resourceReadyEventHandler -= value;
200 ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
201 if (_resourceReadyEventHandler == null && resourceReadySignal?.Empty() == false)
203 resourceReadySignal?.Disconnect(_resourceReadyEventCallback);
205 resourceReadySignal?.Dispose();
209 internal event EventHandler<ResourceLoadedEventArgs> ResourceLoaded
213 if (_resourceLoadedEventHandler == null)
215 _resourceLoadedCallback = OnResourceLoaded;
216 ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
217 resourceReadySignal?.Connect(_resourceLoadedCallback);
218 resourceReadySignal?.Dispose();
221 _resourceLoadedEventHandler += value;
225 _resourceLoadedEventHandler -= value;
226 ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
227 if (_resourceLoadedEventHandler == null && resourceReadySignal?.Empty() == false)
229 resourceReadySignal?.Disconnect(_resourceLoadedCallback);
231 resourceReadySignal?.Dispose();
236 /// Enumeration for LoadingStatus of image.
238 /// <since_tizen> 5 </since_tizen>
239 public enum LoadingStatusType
242 /// Loading preparing status.
244 /// <since_tizen> 5 </since_tizen>
247 /// Loading ready status.
249 /// <since_tizen> 5 </since_tizen>
252 /// Loading failed status.
254 /// <since_tizen> 5 </since_tizen>
259 /// Enumeration for MaskingMode of image.
261 [EditorBrowsable(EditorBrowsableState.Never)]
262 public enum MaskingModeType
265 /// Applies alpha masking on rendering time.
267 [EditorBrowsable(EditorBrowsableState.Never)]
270 /// Applies alpha masking on loading time.
272 [EditorBrowsable(EditorBrowsableState.Never)]
277 /// ImageView ResourceUrl, type string.
278 /// This is one of mandatory property. Even if not set or null set, it sets empty string ("") internally.
279 /// When it is set as null, it gives empty string ("") to be read.
281 /// <since_tizen> 3 </since_tizen>
282 public string ResourceUrl
286 return (string)GetValue(ResourceUrlProperty);
290 SetValue(ResourceUrlProperty, value);
291 NotifyPropertyChanged();
296 /// This will be deprecated, Use Image instead. <br />
297 /// ImageView ImageMap, type PropertyMap: string if it is a URL, map otherwise.
299 /// <since_tizen> 3 </since_tizen>
300 [Obsolete("Do not use this, that will be deprecated. Use Image property instead.")]
301 [EditorBrowsable(EditorBrowsableState.Never)]
302 public PropertyMap ImageMap
306 return GetValue(ImageMapProperty) as PropertyMap;
310 SetValue(ImageMapProperty, value);
311 NotifyPropertyChanged();
314 private PropertyMap InternalImageMap
320 // Sync as current properties
323 // Get current properties force.
324 PropertyMap returnValue = new PropertyMap();
325 PropertyValue image = GetProperty(ImageView.Property.IMAGE);
326 image?.Get(returnValue);
329 // Update cached property map
330 if(returnValue != null)
332 MergeCachedImageVisualProperty(returnValue);
345 PropertyValue setValue = new Tizen.NUI.PropertyValue(value);
346 SetProperty(ImageView.Property.IMAGE, setValue);
348 // Image properties are changed hardly. We should ignore lazy UpdateImage
349 imagePropertyUpdatedFlag = false;
350 cachedImagePropertyMap?.Dispose();
351 cachedImagePropertyMap = null;
352 MergeCachedImageVisualProperty(value);
354 NotifyPropertyChanged();
361 /// ImageView Image, type PropertyMap: string if it is a URL, map otherwise.
364 /// This PropertyMap use a <see cref="ImageVisualProperty"/>. <br />
365 /// See <see cref="ImageVisualProperty"/> for a detailed description. <br />
366 /// you can also use <see cref="Visual.Property"/>. <br />
367 /// See <see cref="Visual.Property"/> for a detailed description. <br />
370 /// The following example demonstrates how to use the Image property.
372 /// PropertyMap map = new PropertyMap();
373 /// map.Insert(Visual.Property.Type, new PropertyValue((int)Visual.Type.Image));
374 /// map.Insert(ImageVisualProperty.AlphaMaskURL, new PropertyValue(url));
375 /// map.Insert(ImageVisualProperty.FittingMode, new PropertyValue((int)FittingModeType.ScaleToFill);
376 /// imageview.Image = map;
379 /// <since_tizen> 4 </since_tizen>
380 public PropertyMap Image
386 return (PropertyMap)GetValue(ImageProperty);
397 SetValue(ImageProperty, value);
398 NotifyPropertyChanged();
404 /// ImageView PreMultipliedAlpha, type Boolean.<br />
405 /// Image must be initialized.<br />
407 /// <since_tizen> 3 </since_tizen>
408 public bool PreMultipliedAlpha
412 return (bool)GetValue(PreMultipliedAlphaProperty);
416 SetValue(PreMultipliedAlphaProperty, value);
417 NotifyPropertyChanged();
422 /// ImageView PixelArea, type Vector4 (Animatable property).<br />
423 /// Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0].<br />
426 /// The property cascade chaining set is possible. For example, this (imageView.PixelArea.X = 0.1f;) is possible.
428 /// <since_tizen> 3 </since_tizen>
429 public RelativeVector4 PixelArea
433 return (RelativeVector4)GetValue(PixelAreaProperty);
437 SetValue(PixelAreaProperty, value);
438 NotifyPropertyChanged();
443 /// The border of the image in the order: left, right, bottom, top.<br />
444 /// If set, ImageMap will be ignored.<br />
445 /// For N-Patch images only.<br />
449 /// The property cascade chaining set is possible. For example, this (imageView.Border.X = 1;) is possible.
451 /// <since_tizen> 3 </since_tizen>
452 public Rectangle Border
456 Rectangle temp = (Rectangle)GetValue(BorderProperty);
463 return new Rectangle(OnBorderChanged, temp.X, temp.Y, temp.Width, temp.Height);
468 SetValue(BorderProperty, value);
469 NotifyPropertyChanged();
474 /// Gets or sets whether to draw the borders only (if true).<br />
475 /// If not specified, the default is false.<br />
476 /// For N-Patch images only.<br />
479 /// <since_tizen> 3 </since_tizen>
480 public bool BorderOnly
484 return (bool)GetValue(BorderOnlyProperty);
488 SetValue(BorderOnlyProperty, value);
489 NotifyPropertyChanged();
494 /// Gets or sets whether to synchronous loading the resourceurl of image.<br />
496 /// <since_tizen> 3 </since_tizen>
497 [Obsolete("This has been deprecated since API9 and will be removed in API11. Use SynchronousLoading instead.")]
498 public bool SynchronosLoading
502 return SynchronousLoading;
506 SynchronousLoading = value;
511 /// Gets or sets whether the image of the ResourceUrl property will be loaded synchronously.<br />
514 /// Changing this property make this ImageView load image synchronously at the next loading
515 /// by following operation: <see cref="Reload"/>, <see cref="SetImage(string)"/>,
516 /// and by some properties those cause reloading: <see cref="ResourceUrl"/>, <see cref="PreMultipliedAlpha"/> and etc.
518 /// <since_tizen> 9 </since_tizen>
519 public bool SynchronousLoading
523 return (bool)GetValue(SynchronousLoadingProperty);
527 SetValue(SynchronousLoadingProperty, value);
528 NotifyPropertyChanged();
533 /// Gets or sets whether to automatically correct the orientation of an image.<br />
535 /// <since_tizen> 5 </since_tizen>
536 public bool OrientationCorrection
540 return (bool)GetValue(OrientationCorrectionProperty);
544 SetValue(OrientationCorrectionProperty, value);
545 NotifyPropertyChanged();
550 /// Gets or sets whether to apply mask on GPU or not.<br />
552 [EditorBrowsable(EditorBrowsableState.Never)]
553 public MaskingModeType MaskingMode
557 return (MaskingModeType)GetValue(MaskingModeProperty);
561 SetValue(MaskingModeProperty, value);
562 NotifyPropertyChanged();
566 private MaskingModeType InternalMaskingMode
570 int ret = (int)MaskingModeType.MaskingOnLoading;
572 PropertyValue maskingMode = GetCachedImageVisualProperty(ImageVisualProperty.MaskingMode);
573 maskingMode?.Get(out ret);
574 maskingMode?.Dispose();
576 return (MaskingModeType)ret;
580 MaskingModeType ret = value;
581 PropertyValue setValue = new PropertyValue((int)ret);
582 UpdateImage(ImageVisualProperty.MaskingMode, setValue);
588 /// Gets the loading state of the visual resource.
590 /// <since_tizen> 5 </since_tizen>
591 public ImageView.LoadingStatusType LoadingStatus
595 return (ImageView.LoadingStatusType)Interop.View.GetVisualResourceStatus(SwigCPtr, (int)Property.IMAGE);
600 /// Downcasts a handle to imageView handle.
602 /// <exception cref="ArgumentNullException"> Thrown when handle is null. </exception>
603 /// Do not use this, that will be deprecated. Use as keyword instead.
604 /// <since_tizen> 3 </since_tizen>
605 [Obsolete("Do not use this, that will be deprecated. Use as keyword instead. " +
607 "BaseHandle handle = new ImageView(imagePath); " +
608 "ImageView image = handle as ImageView")]
609 [EditorBrowsable(EditorBrowsableState.Never)]
610 public static ImageView DownCast(BaseHandle handle)
614 throw new ArgumentNullException(nameof(handle));
616 ImageView ret = Registry.GetManagedBaseHandleFromNativePtr(handle) as ImageView;
617 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
622 /// Sets this ImageView from the given URL.<br />
623 /// If the URL is empty, ImageView will not display anything.<br />
625 /// <param name="url">The URL to the image resource to display.</param>
626 /// <exception cref="ArgumentNullException"> Thrown when url is null. </exception>
627 /// <since_tizen> 3 </since_tizen>
628 public void SetImage(string url)
632 throw new ArgumentNullException(nameof(url));
635 if (url.Contains(".json"))
637 Tizen.Log.Fatal("NUI", "[ERROR] Do not set lottie file in ImageView! This is temporary checking, will be removed soon!");
641 Interop.ImageView.SetImage(SwigCPtr, ConvertResourceUrl(ref url));
642 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
648 /// Queries if all resources required by a control are loaded and ready.<br />
649 /// Most resources are only loaded when the control is placed on the stage.<br />
650 /// True if the resources are loaded and ready, false otherwise.<br />
652 /// <since_tizen> 3 </since_tizen>
653 public new bool IsResourceReady()
655 bool ret = Interop.View.IsResourceReady(SwigCPtr);
656 if (NDalicPINVOKE.SWIGPendingException.Pending)
657 throw NDalicPINVOKE.SWIGPendingException.Retrieve();
662 /// Forcefully reloads the image. All the visuals using this image will reload to the latest image.
664 /// <since_tizen> 5 </since_tizen>
667 // Sync as current properties
671 Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionReload);
675 /// Plays the animated GIF. This is also the default playback mode.
677 /// <since_tizen> 5 </since_tizen>
680 // Sync as current properties
684 Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionPlay);
688 /// Pauses the animated GIF.
690 /// <since_tizen> 5 </since_tizen>
693 // Sync as current properties
697 Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionPause);
701 /// Stops the animated GIF.
703 /// <since_tizen> 5 </since_tizen>
706 // Sync as current properties
711 Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionStop);
715 /// Gets or sets the URL of the alpha mask.<br />
718 /// <since_tizen> 6</since_tizen>
719 [EditorBrowsable(EditorBrowsableState.Never)]
720 public string AlphaMaskURL
724 return GetValue(AlphaMaskURLProperty) as string;
728 SetValue(AlphaMaskURLProperty, value);
729 NotifyPropertyChanged();
733 private string InternalAlphaMaskURL
739 PropertyValue maskUrl = GetCachedImageVisualProperty(ImageVisualProperty.AlphaMaskURL);
740 maskUrl?.Get(out ret);
747 PropertyValue setValue = new PropertyValue(value ?? "");
748 UpdateImage(ImageVisualProperty.AlphaMaskURL, setValue);
749 // When we never set CropToMask property before, we should set default value as true.
750 using(PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask))
752 if(cropToMask == null)
754 using PropertyValue setCropValue = new PropertyValue(true);
755 UpdateImage(ImageVisualProperty.CropToMask, setCropValue);
764 /// Whether to crop image to mask or scale mask to fit image.
766 /// <since_tizen> 6 </since_tizen>
767 public bool CropToMask
771 return (bool)GetValue(CropToMaskProperty);
775 SetValue(CropToMaskProperty, value);
776 NotifyPropertyChanged();
779 private bool InternalCropToMask
785 PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask);
786 cropToMask?.Get(out ret);
787 cropToMask?.Dispose();
793 PropertyValue setValue = new PropertyValue(value);
794 UpdateImage(ImageVisualProperty.CropToMask, setValue);
800 /// Actions property value for Reload image.
802 private int ActionReload { get; set; } = Interop.ImageView.ImageVisualActionReloadGet();
805 /// Actions property value to Play animated images.
806 /// This property can be redefined by child class if it use different value.
808 [EditorBrowsable(EditorBrowsableState.Never)]
809 protected int ActionPlay { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet();
812 /// Actions property value to Pause animated images.
813 /// This property can be redefined by child class if it use different value.
815 [EditorBrowsable(EditorBrowsableState.Never)]
816 protected int ActionPause { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet();
819 /// Actions property value to Stop animated images.
820 /// This property can be redefined by child class if it use different value.
822 [EditorBrowsable(EditorBrowsableState.Never)]
823 protected int ActionStop { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionStopGet();
825 internal VisualFittingModeType ConvertFittingModetoVisualFittingMode(FittingModeType value)
829 case FittingModeType.ShrinkToFit:
830 return VisualFittingModeType.FitKeepAspectRatio;
831 case FittingModeType.ScaleToFill:
832 return VisualFittingModeType.OverFitKeepAspectRatio;
833 case FittingModeType.Center:
834 return VisualFittingModeType.Center;
835 case FittingModeType.Fill:
836 return VisualFittingModeType.Fill;
837 case FittingModeType.FitHeight:
838 return VisualFittingModeType.FitHeight;
839 case FittingModeType.FitWidth:
840 return VisualFittingModeType.FitWidth;
842 return VisualFittingModeType.Fill;
846 internal FittingModeType ConvertVisualFittingModetoFittingMode(VisualFittingModeType value)
850 case VisualFittingModeType.FitKeepAspectRatio:
851 return FittingModeType.ShrinkToFit;
852 case VisualFittingModeType.OverFitKeepAspectRatio:
853 return FittingModeType.ScaleToFill;
854 case VisualFittingModeType.Center:
855 return FittingModeType.Center;
856 case VisualFittingModeType.Fill:
857 return FittingModeType.Fill;
858 case VisualFittingModeType.FitHeight:
859 return FittingModeType.FitHeight;
860 case VisualFittingModeType.FitWidth:
861 return FittingModeType.FitWidth;
863 return FittingModeType.ShrinkToFit;
867 internal override LayoutItem CreateDefaultLayout()
869 return new ImageLayout();
873 /// Gets or sets fitting options used when resizing images to fit.<br />
874 /// If not supplied, the default is FittingModeType.Fill.<br />
875 /// For normal quad images only.<br />
878 /// <since_tizen> 6 </since_tizen>
879 [EditorBrowsable(EditorBrowsableState.Never)]
880 public FittingModeType FittingMode
884 return (FittingModeType)GetValue(FittingModeProperty);
888 SetValue(FittingModeProperty, value);
889 NotifyPropertyChanged();
893 private FittingModeType InternalFittingMode
897 int ret = (int)VisualFittingModeType.Fill;
899 PropertyValue fittingMode = GetCachedImageVisualProperty(Visual.Property.VisualFittingMode);
900 fittingMode?.Get(out ret);
901 fittingMode?.Dispose();
903 return ConvertVisualFittingModetoFittingMode((VisualFittingModeType)ret);
907 VisualFittingModeType ret = ConvertFittingModetoVisualFittingMode(value);
908 PropertyValue setValue = new PropertyValue((int)ret);
909 UpdateImage(Visual.Property.VisualFittingMode, setValue);
915 /// Gets or sets the desired image width.<br />
916 /// If not specified, the actual image width is used.<br />
917 /// For normal quad images only.<br />
920 /// <since_tizen> 6 </since_tizen>
921 [EditorBrowsable(EditorBrowsableState.Never)]
922 public int DesiredWidth
926 return (int)GetValue(DesiredWidthProperty);
930 SetValue(DesiredWidthProperty, value);
931 NotifyPropertyChanged();
934 private int InternalDesiredWidth
938 // Sync as current properties only if both _desired_width and _desired_height are setuped.
939 if(_desired_width != -1 && _desired_height != -1)
943 PropertyValue desirewidth = GetCachedImageVisualProperty(ImageVisualProperty.DesiredWidth);
944 desirewidth?.Get(out _desired_width);
945 desirewidth?.Dispose();
947 return _desired_width;
951 if (_desired_width != value)
953 _desired_width = value;
954 PropertyValue setValue = new PropertyValue(value);
955 UpdateImage(ImageVisualProperty.DesiredWidth, setValue);
962 /// Gets or sets the desired image height.<br />
963 /// If not specified, the actual image height is used.<br />
964 /// For normal quad images only.<br />
967 /// <since_tizen> 6 </since_tizen>
968 [EditorBrowsable(EditorBrowsableState.Never)]
969 public int DesiredHeight
973 return (int)GetValue(DesiredHeightProperty);
977 SetValue(DesiredHeightProperty, value);
978 NotifyPropertyChanged();
981 private int InternalDesiredHeight
985 // Sync as current properties only if both _desired_width and _desired_height are setuped.
986 if(_desired_width != -1 && _desired_height != -1)
990 PropertyValue desireheight = GetCachedImageVisualProperty(ImageVisualProperty.DesiredHeight);
991 desireheight?.Get(out _desired_height);
992 desireheight?.Dispose();
994 return _desired_height;
998 if (_desired_height != value)
1000 _desired_height = value;
1001 PropertyValue setValue = new PropertyValue(value);
1002 UpdateImage(ImageVisualProperty.DesiredHeight, setValue);
1003 setValue?.Dispose();
1009 /// Gets or sets ReleasePolicy for image.<br />
1010 /// If not supplied, the default is ReleasePolicyType.Detached.<br />
1012 [EditorBrowsable(EditorBrowsableState.Never)]
1013 public ReleasePolicyType ReleasePolicy
1017 return (ReleasePolicyType)GetValue(ReleasePolicyProperty);
1021 SetValue(ReleasePolicyProperty, value);
1022 NotifyPropertyChanged();
1026 private ReleasePolicyType InternalReleasePolicy
1030 int ret = (int)ReleasePolicyType.Detached;
1032 PropertyValue releasePoli = GetCachedImageVisualProperty(ImageVisualProperty.ReleasePolicy);
1033 releasePoli?.Get(out ret);
1034 releasePoli?.Dispose();
1036 return (ReleasePolicyType)ret;
1040 PropertyValue setValue = new PropertyValue((int)value);
1041 UpdateImage(ImageVisualProperty.ReleasePolicy, setValue);
1042 setValue?.Dispose();
1047 /// Gets or sets the wrap mode for the u coordinate.<br />
1048 /// It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.<br />
1049 /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
1050 /// For normal quad images only.<br />
1053 /// <since_tizen> 6 </since_tizen>
1054 [EditorBrowsable(EditorBrowsableState.Never)]
1055 public WrapModeType WrapModeU
1059 return (WrapModeType)GetValue(WrapModeUProperty);
1063 SetValue(WrapModeUProperty, value);
1064 NotifyPropertyChanged();
1068 private WrapModeType InternalWrapModeU
1072 int ret = (int)WrapModeType.Default;
1074 PropertyValue wrapModeU = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeU);
1075 wrapModeU?.Get(out ret);
1076 wrapModeU?.Dispose();
1078 return (WrapModeType)ret;
1082 PropertyValue setValue = new PropertyValue((int)value);
1083 UpdateImage(ImageVisualProperty.WrapModeU, setValue);
1084 setValue?.Dispose();
1089 /// Gets or sets the wrap mode for the v coordinate.<br />
1090 /// It decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.<br />
1091 /// 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 />
1092 /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
1093 /// For normal quad images only.
1096 /// <since_tizen> 6 </since_tizen>
1097 [EditorBrowsable(EditorBrowsableState.Never)]
1098 public WrapModeType WrapModeV
1102 return (WrapModeType)GetValue(WrapModeVProperty);
1106 SetValue(WrapModeVProperty, value);
1107 NotifyPropertyChanged();
1111 private WrapModeType InternalWrapModeV
1115 int ret = (int)WrapModeType.Default;
1117 PropertyValue wrapModeV = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeV);
1118 wrapModeV?.Get(out ret);
1119 wrapModeV?.Dispose();
1121 return (WrapModeType)ret;
1125 PropertyValue setValue = new PropertyValue((int)value);
1126 UpdateImage(ImageVisualProperty.WrapModeV, setValue);
1127 setValue?.Dispose();
1132 /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
1135 /// This is false by default.
1136 /// If this is set to be true, then the width or height value, which is not set by user explicitly, can be changed automatically
1137 /// to preserve the aspect ratio of the image resource.
1138 /// AdjustViewSize works only if ImageView is added to a View having Layout.
1139 /// e.g. If the image resource size is (100, 100), then the ImageView requests size (100, 100) to its parent layout by default.
1140 /// If the ImageView's HeightSpecification is 50 and AdjustViewSize is true, then the ImageView requests size (50, 50) instead of (100, 50).
1142 /// <since_tizen> 9 </since_tizen>
1143 public bool AdjustViewSize
1147 return (bool)GetValue(AdjustViewSizeProperty);
1151 SetValue(AdjustViewSizeProperty, value);
1152 NotifyPropertyChanged();
1155 private bool adjustViewSize = false;
1158 /// ImageView PlaceHolderUrl, type string.
1159 /// This is one of mandatory property. Even if not set or null set, it sets empty string ("") internally.
1160 /// When it is set as null, it gives empty string ("") to be read.
1162 /// <since_tizen> 11 </since_tizen>
1163 [EditorBrowsable(EditorBrowsableState.Never)]
1164 public string PlaceHolderUrl
1168 return (string)GetValue(PlaceHolderUrlProperty);
1172 SetValue(PlaceHolderUrlProperty, value);
1173 NotifyPropertyChanged();
1178 /// Gets or sets whether the image use TransitionEffect or not<br />
1180 /// <since_tizen> 11 </since_tizen>
1181 [EditorBrowsable(EditorBrowsableState.Never)]
1182 public bool TransitionEffect
1186 return (bool)GetValue(TransitionEffectProperty);
1190 SetValue(TransitionEffectProperty, value);
1191 NotifyPropertyChanged();
1195 internal Selector<string> ResourceUrlSelector
1197 get => GetSelector<string>(resourceUrlSelector, ImageView.ResourceUrlProperty);
1200 resourceUrlSelector?.Reset(this);
1201 if (value == null) return;
1203 if (value.HasAll()) SetResourceUrl(value.All);
1204 else resourceUrlSelector = new TriggerableSelector<string>(this, value, SetResourceUrl, true);
1209 /// Get attributes, it is abstract function and must be override.
1211 [EditorBrowsable(EditorBrowsableState.Never)]
1212 protected override ViewStyle CreateViewStyle()
1214 return new ImageViewStyle();
1217 internal void SetImage(string url, Uint16Pair size)
1219 if (url.Contains(".json"))
1221 Tizen.Log.Fatal("NUI", "[ERROR] Do not set lottie file in ImageView! This is temporary checking, will be removed soon!");
1225 Interop.ImageView.SetImage(SwigCPtr, ConvertResourceUrl(ref url), Uint16Pair.getCPtr(size));
1226 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1229 _desired_width = size?.GetWidth() ?? -1;
1230 _desired_height = size?.GetHeight() ?? -1;
1233 internal ViewResourceReadySignal ResourceReadySignal(View view)
1235 ViewResourceReadySignal ret = new ViewResourceReadySignal(Interop.View.ResourceReadySignal(View.getCPtr(view)), false);
1236 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1240 internal override void ApplyCornerRadius()
1242 base.ApplyCornerRadius();
1244 if (backgroundExtraData == null) return;
1247 // Update corner radius properties to image by ActionUpdateProperty
1248 if (backgroundExtraData.CornerRadius != null)
1250 Interop.View.InternalUpdateVisualPropertyVector4(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.CornerRadius, Vector4.getCPtr(backgroundExtraData.CornerRadius));
1252 Interop.View.InternalUpdateVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.CornerRadiusPolicy, (int)backgroundExtraData.CornerRadiusPolicy);
1255 internal override void ApplyBorderline()
1257 base.ApplyBorderline();
1259 if (backgroundExtraData == null) return;
1262 // Update borderline properties to image by ActionUpdateProperty
1263 Interop.View.InternalUpdateVisualPropertyFloat(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.BorderlineWidth, backgroundExtraData.BorderlineWidth);
1264 Interop.View.InternalUpdateVisualPropertyVector4(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.BorderlineColor, Vector4.getCPtr(backgroundExtraData.BorderlineColor ?? Color.Black));
1265 Interop.View.InternalUpdateVisualPropertyFloat(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.BorderlineOffset, backgroundExtraData.BorderlineOffset);
1268 internal ResourceLoadingStatusType GetResourceStatus()
1270 return (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
1274 /// you can override it to clean-up your own resources.
1276 /// <param name="type">DisposeTypes</param>
1277 /// <since_tizen> 3 </since_tizen>
1278 protected override void Dispose(DisposeTypes type)
1285 internalPixelArea?.Dispose();
1287 if (type == DisposeTypes.Explicit)
1290 //Release your own managed resources here.
1291 //You should release all of your own disposable objects here.
1294 borderSelector?.Reset(this);
1295 resourceUrlSelector?.Reset(this);
1296 imagePropertyUpdatedFlag = false;
1297 if (imagePropertyUpdateProcessAttachedFlag)
1299 ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
1300 imagePropertyUpdateProcessAttachedFlag = false;
1302 cachedImagePropertyMap?.Dispose();
1303 cachedImagePropertyMap = null;
1309 /// This will not be public opened.
1310 [EditorBrowsable(EditorBrowsableState.Never)]
1311 protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
1313 Interop.ImageView.DeleteImageView(swigCPtr);
1316 // Callback for View ResourceReady signal
1317 private void OnResourceReady(IntPtr data)
1319 if(!CheckResourceReady())
1324 ResourceReadyEventArgs e = new ResourceReadyEventArgs();
1327 e.View = Registry.GetManagedBaseHandleFromNativePtr(data) as View;
1330 if (_resourceReadyEventHandler != null)
1332 _resourceReadyEventHandler(this, e);
1336 private void SetResourceUrl(string value)
1338 if(_resourceUrl != ConvertResourceUrl(ref value))
1340 _resourceUrl = value;
1341 if(string.IsNullOrEmpty(_resourceUrl))
1343 // Special case. If we set ResourceUrl as empty, Unregist visual.
1348 using(PropertyValue setValue = new PropertyValue(value))
1350 UpdateImage(ImageVisualProperty.URL, setValue);
1352 // Special case. If we set GeneratedUrl, Create ImageVisual synchronously.
1353 if(value.StartsWith("dali://") || value.StartsWith("enbuf://"))
1361 private void SetBorder(Rectangle value)
1367 if(_border != value)
1369 _border = new Rectangle(value);
1370 UpdateImage(NpatchImageVisualProperty.Border, new PropertyValue(_border));
1375 /// Unregist image visual directly. After this operation, we cannot get any properties from Image property.
1377 private void RemoveImage()
1379 // If previous resourceUrl was already empty, we don't need to do anything. just ignore.
1380 // Unregist and detach process only if previous resourceUrl was not empty
1381 string currentResourceUrl = "";
1382 PropertyValue currentResourceUrlValue = GetCachedImageVisualProperty(ImageVisualProperty.URL);
1383 if((currentResourceUrlValue?.Get(out currentResourceUrl) ?? false) && !string.IsNullOrEmpty(currentResourceUrl))
1385 PropertyValue emptyValue = new PropertyValue();
1387 // Remove current registed Image.
1388 SetProperty(ImageView.Property.IMAGE, emptyValue);
1390 // Image visual is not exist anymore. We should ignore lazy UpdateImage
1391 imagePropertyUpdatedFlag = false;
1392 if(imagePropertyUpdateProcessAttachedFlag)
1394 ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
1395 imagePropertyUpdateProcessAttachedFlag = false;
1397 // Update resourceUrl as empty value
1398 cachedImagePropertyMap[ImageVisualProperty.URL] = emptyValue;
1400 emptyValue?.Dispose();
1402 currentResourceUrlValue?.Dispose();
1406 /// Lazy call to UpdateImage.
1407 /// Collect Properties need to be update, and set properties that starts the Processing.
1409 [EditorBrowsable(EditorBrowsableState.Never)]
1410 protected virtual void UpdateImage(int key, PropertyValue value)
1412 // Update image property map value as inputed value.
1415 if (cachedImagePropertyMap == null)
1417 cachedImagePropertyMap = new PropertyMap();
1420 // To optimization, we don't check URL duplicate case. We already checked before.
1421 if (key != ImageVisualProperty.URL)
1423 using (PropertyValue oldValue = GetCachedImageVisualProperty(key))
1425 if (oldValue != null && oldValue.EqualTo(value))
1427 // Ignore UpdateImage query when we try to update equality value.
1432 imagePropertyUpdatedFlag = true;
1433 cachedImagePropertyMap[key] = value;
1435 // Lazy update only if _resourceUrl is not empty and ProcessAttachedFlag is false.
1436 if (!string.IsNullOrEmpty(_resourceUrl) && !imagePropertyUpdateProcessAttachedFlag)
1438 imagePropertyUpdateProcessAttachedFlag = true;
1439 ProcessorController.Instance.ProcessorOnceEvent += UpdateImage;
1440 // Call process hardly.
1441 ProcessorController.Instance.Awake();
1447 /// Callback function to Lazy UpdateImage.
1449 private void UpdateImage(object source, EventArgs e)
1452 imagePropertyUpdateProcessAttachedFlag = false;
1456 /// Update image-relative properties synchronously.
1457 /// After call this API, All image properties updated.
1460 /// Current version ImageView property update asynchronously.
1461 /// If you want to guarantee that ImageView property setuped,
1462 /// Please call this ImageView.UpdateImage() API.
1464 [EditorBrowsable(EditorBrowsableState.Never)]
1465 protected virtual void UpdateImage()
1467 if(!imagePropertyUpdatedFlag) return;
1469 imagePropertyUpdatedFlag = false;
1471 if(cachedImagePropertyMap == null)
1473 cachedImagePropertyMap = new PropertyMap();
1476 // Checkup the cached visual type is AnimatedImage.
1477 // It is trick to know that this code is running on AnimatedImageView.UpdateImage() / LottieAnimationView.UpdateImage() or not.
1478 int visualType = (int)Visual.Type.Invalid;
1479 if(!((GetCachedImageVisualProperty(Visual.Property.Type)?.Get(out visualType) ?? false) && (visualType == (int)Visual.Type.AnimatedImage || visualType == (int)Visual.Type.AnimatedVectorImage)))
1481 // If ResourceUrl is not setuped, don't set property. fast return.
1482 if(string.IsNullOrEmpty(_resourceUrl))
1486 if (_border == null)
1488 PropertyValue image = new PropertyValue((int)Visual.Type.Image);
1489 cachedImagePropertyMap[Visual.Property.Type] = image;
1494 PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch);
1495 cachedImagePropertyMap[Visual.Property.Type] = nPatch;
1497 PropertyValue border = new PropertyValue(_border);
1498 cachedImagePropertyMap[NpatchImageVisualProperty.Border] = border;
1503 if (backgroundExtraData != null && backgroundExtraData.CornerRadius != null)
1505 using (var cornerRadius = new PropertyValue(backgroundExtraData.CornerRadius))
1506 using (var cornerRadiusPolicy = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy))
1508 cachedImagePropertyMap[Visual.Property.CornerRadius] = cornerRadius;
1509 cachedImagePropertyMap[Visual.Property.CornerRadiusPolicy] = new PropertyValue((int)(backgroundExtraData.CornerRadiusPolicy));
1513 if (backgroundExtraData != null && backgroundExtraData.BorderlineWidth > 0.0f)
1515 using (var borderlineWidth = new PropertyValue(backgroundExtraData.BorderlineWidth))
1516 using (var borderlineColor = new PropertyValue(backgroundExtraData.BorderlineColor))
1517 using (var borderlineOffset = new PropertyValue(backgroundExtraData.BorderlineOffset))
1519 cachedImagePropertyMap[Visual.Property.BorderlineWidth] = borderlineWidth;
1520 cachedImagePropertyMap[Visual.Property.BorderlineColor] = borderlineColor;
1521 cachedImagePropertyMap[Visual.Property.BorderlineOffset] = borderlineOffset;
1525 // Do Fitting Buffer when desired dimension is set
1526 if (_desired_width != -1 && _desired_height != -1)
1528 if (_resourceUrl != null)
1530 Size2D imageSize = ImageLoader.GetOriginalImageSize(_resourceUrl, true);
1531 if( imageSize.Height > 0 && imageSize.Width > 0 && _desired_width > 0 && _desired_height > 0 )
1533 int adjustedDesiredWidth, adjustedDesiredHeight;
1534 float aspectOfDesiredSize = (float)_desired_height / (float)_desired_width;
1535 float aspectOfImageSize = (float)imageSize.Height / (float)imageSize.Width;
1536 if (aspectOfImageSize > aspectOfDesiredSize)
1538 adjustedDesiredWidth = _desired_width;
1539 adjustedDesiredHeight = imageSize.Height * _desired_width / imageSize.Width;
1543 adjustedDesiredWidth = imageSize.Width * _desired_height / imageSize.Height;
1544 adjustedDesiredHeight = _desired_height;
1547 PropertyValue returnWidth = new PropertyValue(adjustedDesiredWidth);
1548 cachedImagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth;
1549 returnWidth?.Dispose();
1550 PropertyValue returnHeight = new PropertyValue(adjustedDesiredHeight);
1551 cachedImagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight;
1552 returnHeight?.Dispose();
1553 PropertyValue scaleToFit = new PropertyValue((int)FittingModeType.ScaleToFill);
1554 cachedImagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit;
1555 scaleToFit?.Dispose();
1559 Tizen.Log.Fatal("NUI", "[ERROR] Can't use DesiredSize when ImageLoading is failed.");
1561 imageSize?.Dispose();
1569 /// Merge our collected properties, and set IMAGE property internally.
1571 private void UpdateImageMap()
1573 // Note : We can't use ImageView.Image property here. Because That property call UpdateImage internally.
1574 using(PropertyMap imageMap = new PropertyMap())
1576 using(PropertyValue returnValue = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE))
1578 returnValue?.Get(imageMap);
1580 if(cachedImagePropertyMap != null)
1582 imageMap?.Merge(cachedImagePropertyMap);
1584 using(PropertyValue setValue = new PropertyValue(imageMap))
1586 SetProperty(ImageView.Property.IMAGE, setValue);
1589 // Update cached image property.
1590 MergeCachedImageVisualProperty(imageMap);
1595 /// Get image visual property by key.
1596 /// If we found value in local Cached result, return that.
1597 /// Else, get synced native map and return that.
1598 /// If there is no matched value, return null.
1600 [EditorBrowsable(EditorBrowsableState.Never)]
1601 protected virtual PropertyValue GetImageVisualProperty(int key)
1603 PropertyValue ret = GetCachedImageVisualProperty(key);
1606 // If we cannot find result form cached map, Get value from native engine.
1607 ret = Image?.Find(key);
1613 /// Get image visual property from NUI cached image map by key.
1614 /// If there is no matched value, return null.
1616 [EditorBrowsable(EditorBrowsableState.Never)]
1617 protected virtual PropertyValue GetCachedImageVisualProperty(int key)
1619 return cachedImagePropertyMap?.Find(key);
1623 /// Update NUI cached image visual property map by inputed property map.
1626 /// For performance issue, we will collect only "cachedImagePropertyKeyList" hold.
1628 [EditorBrowsable(EditorBrowsableState.Never)]
1629 protected virtual void MergeCachedImageVisualProperty(PropertyMap map)
1631 if(map == null) return;
1632 if(cachedImagePropertyMap == null)
1634 cachedImagePropertyMap = new PropertyMap();
1636 foreach(var key in cachedImagePropertyKeyList)
1638 PropertyValue value = map.Find(key);
1641 // Update-or-Insert new value
1642 cachedImagePropertyMap[key] = value;
1648 /// GetNaturalSize() should be guaranteed that ResourceUrl property setuped.
1649 /// So before get base.GetNaturalSize(), we should synchronous image properties
1651 internal override Vector3 GetNaturalSize()
1653 // Sync as current properties
1655 return base.GetNaturalSize();
1658 [EditorBrowsable(EditorBrowsableState.Never)]
1659 protected override bool CheckResourceReady()
1661 // If we have some properties to be updated, this signal is old thing.
1662 // We need to ignore current signal, and wait next.
1663 return !(imagePropertyUpdateProcessAttachedFlag && imagePropertyUpdatedFlag);
1666 private void OnResourceLoaded(IntPtr view)
1668 if(!CheckResourceReady())
1672 ResourceLoadedEventArgs e = new ResourceLoadedEventArgs();
1673 e.Status = (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
1675 if (_resourceLoadedEventHandler != null)
1677 _resourceLoadedEventHandler(this, e);
1682 /// Event arguments of resource ready.
1684 /// <since_tizen> 3 </since_tizen>
1685 public class ResourceReadyEventArgs : EventArgs
1690 /// The view whose resource is ready.
1692 /// <since_tizen> 3 </since_tizen>
1706 internal class ResourceLoadedEventArgs : EventArgs
1708 private ResourceLoadingStatusType status = ResourceLoadingStatusType.Invalid;
1709 public ResourceLoadingStatusType Status
1722 internal new class Property
1724 internal static readonly int IMAGE = Interop.ImageView.ImageGet();
1725 internal static readonly int PreMultipliedAlpha = Interop.ImageView.PreMultipliedAlphaGet();
1726 internal static readonly int PixelArea = Interop.ImageView.PixelAreaGet();
1727 internal static readonly int PlaceHolderUrl = Interop.ImageView.PlaceHolderImageGet();
1728 internal static readonly int TransitionEffect = Interop.ImageView.TransitionEffectGet();
1731 private enum ImageType
1734 /// For Normal Image.
1739 /// For normal image, with synchronous loading and orientation correction property
1744 /// For nine-patch image
1749 private void OnBorderChanged(int x, int y, int width, int height)
1751 Border = new Rectangle(x, y, width, height);
1753 private void OnPixelAreaChanged(float x, float y, float z, float w)
1755 PixelArea = new RelativeVector4(x, y, z, w);
1758 private class ImageLayout : LayoutItem
1761 /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
1762 /// 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.
1764 [EditorBrowsable(EditorBrowsableState.Never)]
1765 public bool AdjustViewSize
1769 return (Owner as ImageView)?.AdjustViewSize ?? false;
1773 if (Owner is ImageView imageView)
1775 imageView.AdjustViewSize = value;
1781 [EditorBrowsable(EditorBrowsableState.Never)]
1782 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
1784 // To not change the view size by DALi
1785 Owner.WidthResizePolicy = ResizePolicyType.Fixed;
1786 Owner.HeightResizePolicy = ResizePolicyType.Fixed;
1788 float specWidth = widthMeasureSpec.Size.AsDecimal();
1789 float specHeight = heightMeasureSpec.Size.AsDecimal();
1790 float naturalWidth = Owner.NaturalSize.Width;
1791 float naturalHeight = Owner.NaturalSize.Height;
1792 float minWidth = Owner.MinimumSize.Width;
1793 float maxWidth = Owner.MaximumSize.Width;
1794 float minHeight = Owner.MinimumSize.Height;
1795 float maxHeight = Owner.MaximumSize.Height;
1796 float aspectRatio = (naturalWidth > 0) ? (naturalHeight / naturalWidth) : 0;
1798 // Assume that the new width and height are given from the view's suggested size by default.
1799 float newWidth = Math.Min(Math.Max(naturalWidth, minWidth), (maxWidth < 0 ? Int32.MaxValue : maxWidth));
1800 float newHeight = Math.Min(Math.Max(naturalHeight, minHeight), (maxHeight < 0 ? Int32.MaxValue : maxHeight));
1802 // The width and height measure specs are going to be used to set measured size.
1803 // Mark that the measure specs are changed by default to update measure specs later.
1804 bool widthSpecChanged = true;
1805 bool heightSpecChanged = true;
1807 if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
1809 newWidth = specWidth;
1810 widthSpecChanged = false;
1812 if (heightMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
1814 if ((AdjustViewSize) && (aspectRatio > 0))
1816 newHeight = newWidth * aspectRatio;
1821 if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
1823 newHeight = specHeight;
1824 heightSpecChanged = false;
1826 if (widthMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
1828 if ((AdjustViewSize) && (aspectRatio > 0))
1830 newWidth = newHeight / aspectRatio;
1835 if (widthSpecChanged)
1837 widthMeasureSpec = new MeasureSpecification(new LayoutLength(newWidth), MeasureSpecification.ModeType.Exactly);
1840 if (heightSpecChanged)
1842 heightMeasureSpec = new MeasureSpecification(new LayoutLength(newHeight), MeasureSpecification.ModeType.Exactly);
1845 MeasuredSize.StateType childWidthState = MeasuredSize.StateType.MeasuredSizeOK;
1846 MeasuredSize.StateType childHeightState = MeasuredSize.StateType.MeasuredSizeOK;
1848 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(newWidth), widthMeasureSpec, childWidthState),
1849 ResolveSizeAndState(new LayoutLength(newHeight), heightMeasureSpec, childHeightState));