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;
40 // Collection of image-sensitive properties.
41 private static readonly List<int> cachedImagePropertyKeyList = new List<int> {
43 ImageVisualProperty.URL,
44 ImageVisualProperty.AlphaMaskURL,
45 ImageVisualProperty.CropToMask,
46 Visual.Property.VisualFittingMode,
47 ImageVisualProperty.DesiredWidth,
48 ImageVisualProperty.DesiredHeight,
49 ImageVisualProperty.ReleasePolicy,
50 ImageVisualProperty.WrapModeU,
51 ImageVisualProperty.WrapModeV,
52 ImageVisualProperty.SynchronousLoading,
53 Visual.Property.PremultipliedAlpha,
54 ImageVisualProperty.OrientationCorrection,
55 NpatchImageVisualProperty.Border,
56 NpatchImageVisualProperty.BorderOnly,
58 internal PropertyMap cachedImagePropertyMap;
59 internal bool imagePropertyUpdatedFlag = false;
61 private bool imagePropertyUpdateProcessAttachedFlag = false;
62 private Rectangle _border;
63 private string _resourceUrl = "";
64 private int _desired_width = -1;
65 private int _desired_height = -1;
66 private TriggerableSelector<string> resourceUrlSelector;
67 private TriggerableSelector<Rectangle> borderSelector;
69 private RelativeVector4 internalPixelArea;
72 /// Creates an initialized ImageView.
74 /// <since_tizen> 3 </since_tizen>
75 public ImageView() : this(Interop.ImageView.New(), true)
77 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
80 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
81 [EditorBrowsable(EditorBrowsableState.Never)]
82 public ImageView(ViewStyle viewStyle) : this(Interop.ImageView.New(), true, viewStyle)
87 /// Creates an initialized ImageView with setting the status of shown or hidden.
89 /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
90 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
91 [EditorBrowsable(EditorBrowsableState.Never)]
92 public ImageView(bool shown) : this(Interop.ImageView.New(), true)
94 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
99 /// Creates an initialized ImageView from a URL to an image resource.<br />
100 /// If the string is empty, ImageView will not display anything.<br />
102 /// <param name="url">The URL of the image resource to display.</param>
103 /// <since_tizen> 3 </since_tizen>
104 public ImageView(string url) : this(Interop.ImageView.New(url), true)
107 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
112 /// Creates an initialized ImageView from a URL to an image resource with setting shown or hidden.
114 /// <param name="url">The URL of the image resource to display.</param>
115 /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
116 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
117 [EditorBrowsable(EditorBrowsableState.Never)]
118 public ImageView(string url, bool shown) : this(Interop.ImageView.New(url), true)
121 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
125 internal ImageView(string url, Uint16Pair size, bool shown = true) : this(Interop.ImageView.New(url, Uint16Pair.getCPtr(size)), true)
128 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
136 internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, ViewStyle viewStyle, bool shown = true) : base(cPtr, cMemoryOwn, viewStyle)
144 internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, bool shown = true) : base(cPtr, cMemoryOwn, null)
152 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
153 private delegate void ResourceReadyEventCallbackType(IntPtr data);
154 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
155 private delegate void _resourceLoadedCallbackType(IntPtr view);
158 /// An event for ResourceReady signal which can be used to subscribe or unsubscribe the event handler.<br />
159 /// This signal is emitted after all resources required by a control are loaded and ready.<br />
160 /// Most resources are only loaded when the control is placed on the stage.<br />
162 /// <since_tizen> 3 </since_tizen>
163 public event EventHandler<ResourceReadyEventArgs> ResourceReady
167 if (_resourceReadyEventHandler == null)
169 _resourceReadyEventCallback = OnResourceReady;
170 ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
171 resourceReadySignal?.Connect(_resourceReadyEventCallback);
172 resourceReadySignal?.Dispose();
175 _resourceReadyEventHandler += value;
180 _resourceReadyEventHandler -= value;
182 ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
183 if (_resourceReadyEventHandler == null && resourceReadySignal?.Empty() == false)
185 resourceReadySignal?.Disconnect(_resourceReadyEventCallback);
187 resourceReadySignal?.Dispose();
191 internal event EventHandler<ResourceLoadedEventArgs> ResourceLoaded
195 if (_resourceLoadedEventHandler == null)
197 _resourceLoadedCallback = OnResourceLoaded;
198 ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
199 resourceReadySignal?.Connect(_resourceLoadedCallback);
200 resourceReadySignal?.Dispose();
203 _resourceLoadedEventHandler += value;
207 _resourceLoadedEventHandler -= value;
208 ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
209 if (_resourceLoadedEventHandler == null && resourceReadySignal?.Empty() == false)
211 resourceReadySignal?.Disconnect(_resourceLoadedCallback);
213 resourceReadySignal?.Dispose();
218 /// Enumeration for LoadingStatus of image.
220 /// <since_tizen> 5 </since_tizen>
221 public enum LoadingStatusType
224 /// Loading preparing status.
226 /// <since_tizen> 5 </since_tizen>
229 /// Loading ready status.
231 /// <since_tizen> 5 </since_tizen>
234 /// Loading failed status.
236 /// <since_tizen> 5 </since_tizen>
241 /// Enumeration for MaskingMode of image.
243 [EditorBrowsable(EditorBrowsableState.Never)]
244 public enum MaskingModeType
247 /// Applies alpha masking on rendering time.
249 [EditorBrowsable(EditorBrowsableState.Never)]
252 /// Applies alpha masking on loading time.
254 [EditorBrowsable(EditorBrowsableState.Never)]
259 /// ImageView ResourceUrl, type string.
260 /// This is one of mandatory property. Even if not set or null set, it sets empty string ("") internally.
261 /// When it is set as null, it gives empty string ("") to be read.
263 /// <since_tizen> 3 </since_tizen>
264 public string ResourceUrl
268 return (string)GetValue(ResourceUrlProperty);
272 SetValue(ResourceUrlProperty, value);
273 NotifyPropertyChanged();
278 /// This will be deprecated, Use Image instead. <br />
279 /// ImageView ImageMap, type PropertyMap: string if it is a URL, map otherwise.
281 /// <since_tizen> 3 </since_tizen>
282 [Obsolete("Do not use this, that will be deprecated. Use Image property instead.")]
283 [EditorBrowsable(EditorBrowsableState.Never)]
284 public PropertyMap ImageMap
288 return GetValue(ImageMapProperty) as PropertyMap;
292 SetValue(ImageMapProperty, value);
293 NotifyPropertyChanged();
296 private PropertyMap InternalImageMap
302 // Sync as current properties
305 // Get current properties force.
306 PropertyMap returnValue = new PropertyMap();
307 PropertyValue image = GetProperty(ImageView.Property.IMAGE);
308 image?.Get(returnValue);
311 // Update cached property map
312 if(returnValue != null)
314 MergeCachedImageVisualProperty(returnValue);
327 PropertyValue setValue = new Tizen.NUI.PropertyValue(value);
328 SetProperty(ImageView.Property.IMAGE, setValue);
330 // Image properties are changed hardly. We should ignore lazy UpdateImage
331 imagePropertyUpdatedFlag = false;
332 cachedImagePropertyMap?.Dispose();
333 cachedImagePropertyMap = null;
334 MergeCachedImageVisualProperty(value);
336 NotifyPropertyChanged();
343 /// ImageView Image, type PropertyMap: string if it is a URL, map otherwise.
346 /// This PropertyMap use a <see cref="ImageVisualProperty"/>. <br />
347 /// See <see cref="ImageVisualProperty"/> for a detailed description. <br />
348 /// you can also use <see cref="Visual.Property"/>. <br />
349 /// See <see cref="Visual.Property"/> for a detailed description. <br />
352 /// The following example demonstrates how to use the Image property.
354 /// PropertyMap map = new PropertyMap();
355 /// map.Insert(Visual.Property.Type, new PropertyValue((int)Visual.Type.Image));
356 /// map.Insert(ImageVisualProperty.AlphaMaskURL, new PropertyValue(url));
357 /// map.Insert(ImageVisualProperty.FittingMode, new PropertyValue((int)FittingModeType.ScaleToFill);
358 /// imageview.Image = map;
361 /// <since_tizen> 4 </since_tizen>
362 public PropertyMap Image
368 return (PropertyMap)GetValue(ImageProperty);
379 SetValue(ImageProperty, value);
380 NotifyPropertyChanged();
386 /// ImageView PreMultipliedAlpha, type Boolean.<br />
387 /// Image must be initialized.<br />
389 /// <since_tizen> 3 </since_tizen>
390 public bool PreMultipliedAlpha
394 return (bool)GetValue(PreMultipliedAlphaProperty);
398 SetValue(PreMultipliedAlphaProperty, value);
399 NotifyPropertyChanged();
404 /// ImageView PixelArea, type Vector4 (Animatable property).<br />
405 /// Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0].<br />
408 /// The property cascade chaining set is possible. For example, this (imageView.PixelArea.X = 0.1f;) is possible.
410 /// <since_tizen> 3 </since_tizen>
411 public RelativeVector4 PixelArea
415 return (RelativeVector4)GetValue(PixelAreaProperty);
419 SetValue(PixelAreaProperty, value);
420 NotifyPropertyChanged();
425 /// The border of the image in the order: left, right, bottom, top.<br />
426 /// If set, ImageMap will be ignored.<br />
427 /// For N-Patch images only.<br />
431 /// The property cascade chaining set is possible. For example, this (imageView.Border.X = 1;) is possible.
433 /// <since_tizen> 3 </since_tizen>
434 public Rectangle Border
438 Rectangle temp = (Rectangle)GetValue(BorderProperty);
445 return new Rectangle(OnBorderChanged, temp.X, temp.Y, temp.Width, temp.Height);
450 SetValue(BorderProperty, value);
451 NotifyPropertyChanged();
456 /// Gets or sets whether to draw the borders only (if true).<br />
457 /// If not specified, the default is false.<br />
458 /// For N-Patch images only.<br />
461 /// <since_tizen> 3 </since_tizen>
462 public bool BorderOnly
466 return (bool)GetValue(BorderOnlyProperty);
470 SetValue(BorderOnlyProperty, value);
471 NotifyPropertyChanged();
476 /// Gets or sets whether to synchronous loading the resourceurl of image.<br />
478 /// <since_tizen> 3 </since_tizen>
479 [Obsolete("This has been deprecated since API9 and will be removed in API11. Use SynchronousLoading instead.")]
480 public bool SynchronosLoading
484 return SynchronousLoading;
488 SynchronousLoading = value;
493 /// Gets or sets whether the image of the ResourceUrl property will be loaded synchronously.<br />
496 /// Changing this property make this ImageView load image synchronously at the next loading
497 /// by following operation: <see cref="Reload"/>, <see cref="SetImage(string)"/>,
498 /// and by some properties those cause reloading: <see cref="ResourceUrl"/>, <see cref="PreMultipliedAlpha"/> and etc.
500 /// <since_tizen> 9 </since_tizen>
501 public bool SynchronousLoading
505 return (bool)GetValue(SynchronousLoadingProperty);
509 SetValue(SynchronousLoadingProperty, value);
510 NotifyPropertyChanged();
515 /// Gets or sets whether to automatically correct the orientation of an image.<br />
517 /// <since_tizen> 5 </since_tizen>
518 public bool OrientationCorrection
522 return (bool)GetValue(OrientationCorrectionProperty);
526 SetValue(OrientationCorrectionProperty, value);
527 NotifyPropertyChanged();
532 /// Gets or sets whether to apply mask on GPU or not.<br />
534 [EditorBrowsable(EditorBrowsableState.Never)]
535 public MaskingModeType MaskingMode
539 return (MaskingModeType)GetValue(MaskingModeProperty);
543 SetValue(MaskingModeProperty, value);
544 NotifyPropertyChanged();
548 private MaskingModeType InternalMaskingMode
552 int ret = (int)MaskingModeType.MaskingOnLoading;
554 PropertyValue maskingMode = GetCachedImageVisualProperty(ImageVisualProperty.MaskingMode);
555 maskingMode?.Get(out ret);
556 maskingMode?.Dispose();
558 return (MaskingModeType)ret;
562 MaskingModeType ret = value;
563 PropertyValue setValue = new PropertyValue((int)ret);
564 UpdateImage(ImageVisualProperty.MaskingMode, setValue);
570 /// Gets the loading state of the visual resource.
572 /// <since_tizen> 5 </since_tizen>
573 public ImageView.LoadingStatusType LoadingStatus
577 return (ImageView.LoadingStatusType)Interop.View.GetVisualResourceStatus(SwigCPtr, (int)Property.IMAGE);
582 /// Downcasts a handle to imageView handle.
584 /// <exception cref="ArgumentNullException"> Thrown when handle is null. </exception>
585 /// Do not use this, that will be deprecated. Use as keyword instead.
586 /// <since_tizen> 3 </since_tizen>
587 [Obsolete("Do not use this, that will be deprecated. Use as keyword instead. " +
589 "BaseHandle handle = new ImageView(imagePath); " +
590 "ImageView image = handle as ImageView")]
591 [EditorBrowsable(EditorBrowsableState.Never)]
592 public static ImageView DownCast(BaseHandle handle)
596 throw new ArgumentNullException(nameof(handle));
598 ImageView ret = Registry.GetManagedBaseHandleFromNativePtr(handle) as ImageView;
599 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
604 /// Sets this ImageView from the given URL.<br />
605 /// If the URL is empty, ImageView will not display anything.<br />
607 /// <param name="url">The URL to the image resource to display.</param>
608 /// <exception cref="ArgumentNullException"> Thrown when url is null. </exception>
609 /// <since_tizen> 3 </since_tizen>
610 public void SetImage(string url)
614 throw new ArgumentNullException(nameof(url));
617 if (url.Contains(".json"))
619 Tizen.Log.Fatal("NUI", "[ERROR] Do not set lottie file in ImageView! This is temporary checking, will be removed soon!");
623 Interop.ImageView.SetImage(SwigCPtr, url);
624 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
630 /// Queries if all resources required by a control are loaded and ready.<br />
631 /// Most resources are only loaded when the control is placed on the stage.<br />
632 /// True if the resources are loaded and ready, false otherwise.<br />
634 /// <since_tizen> 3 </since_tizen>
635 public new bool IsResourceReady()
637 bool ret = Interop.View.IsResourceReady(SwigCPtr);
638 if (NDalicPINVOKE.SWIGPendingException.Pending)
639 throw NDalicPINVOKE.SWIGPendingException.Retrieve();
644 /// Forcefully reloads the image. All the visuals using this image will reload to the latest image.
646 /// <since_tizen> 5 </since_tizen>
649 // Sync as current properties
653 Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionReload);
657 /// Plays the animated GIF. This is also the default playback mode.
659 /// <since_tizen> 5 </since_tizen>
662 // Sync as current properties
666 Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionPlay);
670 /// Pauses the animated GIF.
672 /// <since_tizen> 5 </since_tizen>
675 // Sync as current properties
679 Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionPause);
683 /// Stops the animated GIF.
685 /// <since_tizen> 5 </since_tizen>
688 // Sync as current properties
693 Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionStop);
697 /// Gets or sets the URL of the alpha mask.<br />
700 /// <since_tizen> 6</since_tizen>
701 [EditorBrowsable(EditorBrowsableState.Never)]
702 public string AlphaMaskURL
706 return GetValue(AlphaMaskURLProperty) as string;
710 SetValue(AlphaMaskURLProperty, value);
711 NotifyPropertyChanged();
715 private string InternalAlphaMaskURL
721 PropertyValue maskUrl = GetCachedImageVisualProperty(ImageVisualProperty.AlphaMaskURL);
722 maskUrl?.Get(out ret);
729 PropertyValue setValue = new PropertyValue(value ?? "");
730 UpdateImage(ImageVisualProperty.AlphaMaskURL, setValue);
731 // When we never set CropToMask property before, we should set default value as true.
732 using(PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask))
734 if(cropToMask == null)
736 using PropertyValue setCropValue = new PropertyValue(true);
737 UpdateImage(ImageVisualProperty.CropToMask, setCropValue);
746 /// Whether to crop image to mask or scale mask to fit image.
748 /// <since_tizen> 6 </since_tizen>
749 public bool CropToMask
753 return (bool)GetValue(CropToMaskProperty);
757 SetValue(CropToMaskProperty, value);
758 NotifyPropertyChanged();
761 private bool InternalCropToMask
767 PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask);
768 cropToMask?.Get(out ret);
769 cropToMask?.Dispose();
775 PropertyValue setValue = new PropertyValue(value);
776 UpdateImage(ImageVisualProperty.CropToMask, setValue);
782 /// Actions property value for Reload image.
784 private int ActionReload { get; set; } = Interop.ImageView.ImageVisualActionReloadGet();
787 /// Actions property value to Play animated images.
788 /// This property can be redefined by child class if it use different value.
790 [EditorBrowsable(EditorBrowsableState.Never)]
791 protected int ActionPlay { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet();
794 /// Actions property value to Pause animated images.
795 /// This property can be redefined by child class if it use different value.
797 [EditorBrowsable(EditorBrowsableState.Never)]
798 protected int ActionPause { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet();
801 /// Actions property value to Stop animated images.
802 /// This property can be redefined by child class if it use different value.
804 [EditorBrowsable(EditorBrowsableState.Never)]
805 protected int ActionStop { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionStopGet();
807 internal VisualFittingModeType ConvertFittingModetoVisualFittingMode(FittingModeType value)
811 case FittingModeType.ShrinkToFit:
812 return VisualFittingModeType.FitKeepAspectRatio;
813 case FittingModeType.ScaleToFill:
814 return VisualFittingModeType.OverFitKeepAspectRatio;
815 case FittingModeType.Center:
816 return VisualFittingModeType.Center;
817 case FittingModeType.Fill:
818 return VisualFittingModeType.Fill;
819 case FittingModeType.FitHeight:
820 return VisualFittingModeType.FitHeight;
821 case FittingModeType.FitWidth:
822 return VisualFittingModeType.FitWidth;
824 return VisualFittingModeType.Fill;
828 internal FittingModeType ConvertVisualFittingModetoFittingMode(VisualFittingModeType value)
832 case VisualFittingModeType.FitKeepAspectRatio:
833 return FittingModeType.ShrinkToFit;
834 case VisualFittingModeType.OverFitKeepAspectRatio:
835 return FittingModeType.ScaleToFill;
836 case VisualFittingModeType.Center:
837 return FittingModeType.Center;
838 case VisualFittingModeType.Fill:
839 return FittingModeType.Fill;
840 case VisualFittingModeType.FitHeight:
841 return FittingModeType.FitHeight;
842 case VisualFittingModeType.FitWidth:
843 return FittingModeType.FitWidth;
845 return FittingModeType.ShrinkToFit;
849 internal override LayoutItem CreateDefaultLayout()
851 return new ImageLayout();
855 /// Gets or sets fitting options used when resizing images to fit.<br />
856 /// If not supplied, the default is FittingModeType.Fill.<br />
857 /// For normal quad images only.<br />
860 /// <since_tizen> 6 </since_tizen>
861 [EditorBrowsable(EditorBrowsableState.Never)]
862 public FittingModeType FittingMode
866 return (FittingModeType)GetValue(FittingModeProperty);
870 SetValue(FittingModeProperty, value);
871 NotifyPropertyChanged();
875 private FittingModeType InternalFittingMode
879 int ret = (int)VisualFittingModeType.Fill;
881 PropertyValue fittingMode = GetCachedImageVisualProperty(Visual.Property.VisualFittingMode);
882 fittingMode?.Get(out ret);
883 fittingMode?.Dispose();
885 return ConvertVisualFittingModetoFittingMode((VisualFittingModeType)ret);
889 VisualFittingModeType ret = ConvertFittingModetoVisualFittingMode(value);
890 PropertyValue setValue = new PropertyValue((int)ret);
891 UpdateImage(Visual.Property.VisualFittingMode, setValue);
897 /// Gets or sets the desired image width.<br />
898 /// If not specified, the actual image width is used.<br />
899 /// For normal quad images only.<br />
902 /// <since_tizen> 6 </since_tizen>
903 [EditorBrowsable(EditorBrowsableState.Never)]
904 public int DesiredWidth
908 return (int)GetValue(DesiredWidthProperty);
912 SetValue(DesiredWidthProperty, value);
913 NotifyPropertyChanged();
916 private int InternalDesiredWidth
920 // Sync as current properties only if both _desired_width and _desired_height are setuped.
921 if(_desired_width != -1 && _desired_height != -1)
925 PropertyValue desirewidth = GetCachedImageVisualProperty(ImageVisualProperty.DesiredWidth);
926 desirewidth?.Get(out _desired_width);
927 desirewidth?.Dispose();
929 return _desired_width;
933 if (_desired_width != value)
935 _desired_width = value;
936 PropertyValue setValue = new PropertyValue(value);
937 UpdateImage(ImageVisualProperty.DesiredWidth, setValue);
944 /// Gets or sets the desired image height.<br />
945 /// If not specified, the actual image height is used.<br />
946 /// For normal quad images only.<br />
949 /// <since_tizen> 6 </since_tizen>
950 [EditorBrowsable(EditorBrowsableState.Never)]
951 public int DesiredHeight
955 return (int)GetValue(DesiredHeightProperty);
959 SetValue(DesiredHeightProperty, value);
960 NotifyPropertyChanged();
963 private int InternalDesiredHeight
967 // Sync as current properties only if both _desired_width and _desired_height are setuped.
968 if(_desired_width != -1 && _desired_height != -1)
972 PropertyValue desireheight = GetCachedImageVisualProperty(ImageVisualProperty.DesiredHeight);
973 desireheight?.Get(out _desired_height);
974 desireheight?.Dispose();
976 return _desired_height;
980 if (_desired_height != value)
982 _desired_height = value;
983 PropertyValue setValue = new PropertyValue(value);
984 UpdateImage(ImageVisualProperty.DesiredHeight, setValue);
991 /// Gets or sets ReleasePolicy for image.<br />
992 /// If not supplied, the default is ReleasePolicyType.Detached.<br />
994 [EditorBrowsable(EditorBrowsableState.Never)]
995 public ReleasePolicyType ReleasePolicy
999 return (ReleasePolicyType)GetValue(ReleasePolicyProperty);
1003 SetValue(ReleasePolicyProperty, value);
1004 NotifyPropertyChanged();
1008 private ReleasePolicyType InternalReleasePolicy
1012 int ret = (int)ReleasePolicyType.Detached;
1014 PropertyValue releasePoli = GetCachedImageVisualProperty(ImageVisualProperty.ReleasePolicy);
1015 releasePoli?.Get(out ret);
1016 releasePoli?.Dispose();
1018 return (ReleasePolicyType)ret;
1022 PropertyValue setValue = new PropertyValue((int)value);
1023 UpdateImage(ImageVisualProperty.ReleasePolicy, setValue);
1024 setValue?.Dispose();
1029 /// Gets or sets the wrap mode for the u coordinate.<br />
1030 /// It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.<br />
1031 /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
1032 /// For normal quad images only.<br />
1035 /// <since_tizen> 6 </since_tizen>
1036 [EditorBrowsable(EditorBrowsableState.Never)]
1037 public WrapModeType WrapModeU
1041 return (WrapModeType)GetValue(WrapModeUProperty);
1045 SetValue(WrapModeUProperty, value);
1046 NotifyPropertyChanged();
1050 private WrapModeType InternalWrapModeU
1054 int ret = (int)WrapModeType.Default;
1056 PropertyValue wrapModeU = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeU);
1057 wrapModeU?.Get(out ret);
1058 wrapModeU?.Dispose();
1060 return (WrapModeType)ret;
1064 PropertyValue setValue = new PropertyValue((int)value);
1065 UpdateImage(ImageVisualProperty.WrapModeU, setValue);
1066 setValue?.Dispose();
1071 /// Gets or sets the wrap mode for the v coordinate.<br />
1072 /// It decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.<br />
1073 /// 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 />
1074 /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
1075 /// For normal quad images only.
1078 /// <since_tizen> 6 </since_tizen>
1079 [EditorBrowsable(EditorBrowsableState.Never)]
1080 public WrapModeType WrapModeV
1084 return (WrapModeType)GetValue(WrapModeVProperty);
1088 SetValue(WrapModeVProperty, value);
1089 NotifyPropertyChanged();
1093 private WrapModeType InternalWrapModeV
1097 int ret = (int)WrapModeType.Default;
1099 PropertyValue wrapModeV = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeV);
1100 wrapModeV?.Get(out ret);
1101 wrapModeV?.Dispose();
1103 return (WrapModeType)ret;
1107 PropertyValue setValue = new PropertyValue((int)value);
1108 UpdateImage(ImageVisualProperty.WrapModeV, setValue);
1109 setValue?.Dispose();
1114 /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
1117 /// This is false by default.
1118 /// If this is set to be true, then the width or height value, which is not set by user explicitly, can be changed automatically
1119 /// to preserve the aspect ratio of the image resource.
1120 /// AdjustViewSize works only if ImageView is added to a View having Layout.
1121 /// e.g. If the image resource size is (100, 100), then the ImageView requests size (100, 100) to its parent layout by default.
1122 /// If the ImageView's HeightSpecification is 50 and AdjustViewSize is true, then the ImageView requests size (50, 50) instead of (100, 50).
1124 /// <since_tizen> 9 </since_tizen>
1125 public bool AdjustViewSize
1129 return (bool)GetValue(AdjustViewSizeProperty);
1133 SetValue(AdjustViewSizeProperty, value);
1134 NotifyPropertyChanged();
1137 private bool adjustViewSize = false;
1139 internal Selector<string> ResourceUrlSelector
1141 get => GetSelector<string>(resourceUrlSelector, ImageView.ResourceUrlProperty);
1144 resourceUrlSelector?.Reset(this);
1145 if (value == null) return;
1147 if (value.HasAll()) SetResourceUrl(value.All);
1148 else resourceUrlSelector = new TriggerableSelector<string>(this, value, SetResourceUrl, true);
1153 /// Get attributes, it is abstract function and must be override.
1155 [EditorBrowsable(EditorBrowsableState.Never)]
1156 protected override ViewStyle CreateViewStyle()
1158 return new ImageViewStyle();
1161 internal void SetImage(string url, Uint16Pair size)
1163 if (url.Contains(".json"))
1165 Tizen.Log.Fatal("NUI", "[ERROR] Do not set lottie file in ImageView! This is temporary checking, will be removed soon!");
1169 Interop.ImageView.SetImage(SwigCPtr, url, Uint16Pair.getCPtr(size));
1170 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1175 internal ViewResourceReadySignal ResourceReadySignal(View view)
1177 ViewResourceReadySignal ret = new ViewResourceReadySignal(Interop.View.ResourceReadySignal(View.getCPtr(view)), false);
1178 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1182 internal override void ApplyCornerRadius()
1184 base.ApplyCornerRadius();
1186 if (backgroundExtraData == null) return;
1189 // Update corner radius properties to image by ActionUpdateProperty
1190 if (backgroundExtraData.CornerRadius != null)
1192 Interop.View.InternalUpdateVisualPropertyVector4(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.CornerRadius, Vector4.getCPtr(backgroundExtraData.CornerRadius));
1194 Interop.View.InternalUpdateVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.CornerRadiusPolicy, (int)backgroundExtraData.CornerRadiusPolicy);
1197 internal override void ApplyBorderline()
1199 base.ApplyBorderline();
1201 if (backgroundExtraData == null) return;
1204 // Update borderline properties to image by ActionUpdateProperty
1205 Interop.View.InternalUpdateVisualPropertyFloat(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.BorderlineWidth, backgroundExtraData.BorderlineWidth);
1206 Interop.View.InternalUpdateVisualPropertyVector4(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.BorderlineColor, Vector4.getCPtr(backgroundExtraData.BorderlineColor ?? Color.Black));
1207 Interop.View.InternalUpdateVisualPropertyFloat(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.BorderlineOffset, backgroundExtraData.BorderlineOffset);
1210 internal ResourceLoadingStatusType GetResourceStatus()
1212 return (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
1216 /// you can override it to clean-up your own resources.
1218 /// <param name="type">DisposeTypes</param>
1219 /// <since_tizen> 3 </since_tizen>
1220 protected override void Dispose(DisposeTypes type)
1227 internalPixelArea?.Dispose();
1229 if (type == DisposeTypes.Explicit)
1232 //Release your own managed resources here.
1233 //You should release all of your own disposable objects here.
1236 borderSelector?.Reset(this);
1237 resourceUrlSelector?.Reset(this);
1238 imagePropertyUpdatedFlag = false;
1239 if (imagePropertyUpdateProcessAttachedFlag)
1241 ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
1242 imagePropertyUpdateProcessAttachedFlag = false;
1244 cachedImagePropertyMap?.Dispose();
1245 cachedImagePropertyMap = null;
1251 /// This will not be public opened.
1252 [EditorBrowsable(EditorBrowsableState.Never)]
1253 protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
1255 Interop.ImageView.DeleteImageView(swigCPtr);
1258 // Callback for View ResourceReady signal
1259 private void OnResourceReady(IntPtr data)
1261 if(!CheckResourceReady())
1266 ResourceReadyEventArgs e = new ResourceReadyEventArgs();
1269 e.View = Registry.GetManagedBaseHandleFromNativePtr(data) as View;
1272 if (_resourceReadyEventHandler != null)
1274 _resourceReadyEventHandler(this, e);
1278 private void SetResourceUrl(string value)
1280 value = (value == null ? "" : value);
1281 if (value.StartsWith("*Resource*"))
1283 string resource = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
1284 value = value.Replace("*Resource*", resource);
1286 if(_resourceUrl != value)
1288 _resourceUrl = value;
1289 if(string.IsNullOrEmpty(_resourceUrl))
1291 // Special case. If we set ResourceUrl as empty, Unregist visual.
1296 using(PropertyValue setValue = new PropertyValue(value))
1298 UpdateImage(ImageVisualProperty.URL, setValue);
1300 // Special case. If we set GeneratedUrl, Create ImageVisual synchronously.
1301 if(value.StartsWith("dali://") || value.StartsWith("enbuf://"))
1309 private void SetBorder(Rectangle value)
1315 if(_border != value)
1317 _border = new Rectangle(value);
1318 UpdateImage(NpatchImageVisualProperty.Border, new PropertyValue(_border));
1323 /// Unregist image visual directly. After this operation, we cannot get any properties from Image property.
1325 private void RemoveImage()
1327 // If previous resourceUrl was already empty, we don't need to do anything. just ignore.
1328 // Unregist and detach process only if previous resourceUrl was not empty
1329 string currentResourceUrl = "";
1330 PropertyValue currentResourceUrlValue = GetCachedImageVisualProperty(ImageVisualProperty.URL);
1331 if((currentResourceUrlValue?.Get(out currentResourceUrl) ?? false) && !string.IsNullOrEmpty(currentResourceUrl))
1333 PropertyValue emptyValue = new PropertyValue();
1335 // Remove current registed Image.
1336 SetProperty(ImageView.Property.IMAGE, emptyValue);
1338 // Image visual is not exist anymore. We should ignore lazy UpdateImage
1339 imagePropertyUpdatedFlag = false;
1340 if(imagePropertyUpdateProcessAttachedFlag)
1342 ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
1343 imagePropertyUpdateProcessAttachedFlag = false;
1345 // Update resourceUrl as empty value
1346 cachedImagePropertyMap[ImageVisualProperty.URL] = emptyValue;
1348 emptyValue?.Dispose();
1350 currentResourceUrlValue?.Dispose();
1354 /// Lazy call to UpdateImage.
1355 /// Collect Properties need to be update, and set properties that starts the Processing.
1357 [EditorBrowsable(EditorBrowsableState.Never)]
1358 protected virtual void UpdateImage(int key, PropertyValue value)
1360 // Update image property map value as inputed value.
1363 if (cachedImagePropertyMap == null)
1365 cachedImagePropertyMap = new PropertyMap();
1368 // To optimization, we don't check URL duplicate case. We already checked before.
1369 if (key != ImageVisualProperty.URL)
1371 using (PropertyValue oldValue = GetCachedImageVisualProperty(key))
1373 if (oldValue != null && oldValue.EqualTo(value))
1375 // Ignore UpdateImage query when we try to update equality value.
1380 imagePropertyUpdatedFlag = true;
1381 cachedImagePropertyMap[key] = value;
1383 // Lazy update only if _resourceUrl is not empty and ProcessAttachedFlag is false.
1384 if (!string.IsNullOrEmpty(_resourceUrl) && !imagePropertyUpdateProcessAttachedFlag)
1386 imagePropertyUpdateProcessAttachedFlag = true;
1387 ProcessorController.Instance.ProcessorOnceEvent += UpdateImage;
1388 // Call process hardly.
1389 ProcessorController.Instance.Awake();
1395 /// Callback function to Lazy UpdateImage.
1397 private void UpdateImage(object source, EventArgs e)
1400 imagePropertyUpdateProcessAttachedFlag = false;
1404 /// Update image-relative properties synchronously.
1405 /// After call this API, All image properties updated.
1408 /// Current version ImageView property update asynchronously.
1409 /// If you want to guarantee that ImageView property setuped,
1410 /// Please call this ImageView.UpdateImage() API.
1412 [EditorBrowsable(EditorBrowsableState.Never)]
1413 protected virtual void UpdateImage()
1415 if(!imagePropertyUpdatedFlag) return;
1417 imagePropertyUpdatedFlag = false;
1419 if(cachedImagePropertyMap == null)
1421 cachedImagePropertyMap = new PropertyMap();
1424 // Checkup the cached visual type is AnimatedImage.
1425 // It is trick to know that this code is running on AnimatedImageView.UpdateImage() / LottieAnimationView.UpdateImage() or not.
1426 int visualType = (int)Visual.Type.Invalid;
1427 if(!((GetCachedImageVisualProperty(Visual.Property.Type)?.Get(out visualType) ?? false) && (visualType == (int)Visual.Type.AnimatedImage || visualType == (int)Visual.Type.AnimatedVectorImage)))
1429 // If ResourceUrl is not setuped, don't set property. fast return.
1430 if(string.IsNullOrEmpty(_resourceUrl))
1434 if (_border == null)
1436 PropertyValue image = new PropertyValue((int)Visual.Type.Image);
1437 cachedImagePropertyMap[Visual.Property.Type] = image;
1442 PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch);
1443 cachedImagePropertyMap[Visual.Property.Type] = nPatch;
1445 PropertyValue border = new PropertyValue(_border);
1446 cachedImagePropertyMap[NpatchImageVisualProperty.Border] = border;
1451 if (backgroundExtraData != null && backgroundExtraData.CornerRadius != null)
1453 using (var cornerRadius = new PropertyValue(backgroundExtraData.CornerRadius))
1454 using (var cornerRadiusPolicy = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy))
1456 cachedImagePropertyMap[Visual.Property.CornerRadius] = cornerRadius;
1457 cachedImagePropertyMap[Visual.Property.CornerRadiusPolicy] = new PropertyValue((int)(backgroundExtraData.CornerRadiusPolicy));
1461 if (backgroundExtraData != null && backgroundExtraData.BorderlineWidth > 0.0f)
1463 using (var borderlineWidth = new PropertyValue(backgroundExtraData.BorderlineWidth))
1464 using (var borderlineColor = new PropertyValue(backgroundExtraData.BorderlineColor))
1465 using (var borderlineOffset = new PropertyValue(backgroundExtraData.BorderlineOffset))
1467 cachedImagePropertyMap[Visual.Property.BorderlineWidth] = borderlineWidth;
1468 cachedImagePropertyMap[Visual.Property.BorderlineColor] = borderlineColor;
1469 cachedImagePropertyMap[Visual.Property.BorderlineOffset] = borderlineOffset;
1473 // Do Fitting Buffer when desired dimension is set
1474 if (_desired_width != -1 && _desired_height != -1)
1476 if (_resourceUrl != null)
1478 Size2D imageSize = ImageLoader.GetOriginalImageSize(_resourceUrl, true);
1479 if( imageSize.Height > 0 && imageSize.Width > 0 && _desired_width > 0 && _desired_height > 0 )
1481 int adjustedDesiredWidth, adjustedDesiredHeight;
1482 float aspectOfDesiredSize = (float)_desired_height / (float)_desired_width;
1483 float aspectOfImageSize = (float)imageSize.Height / (float)imageSize.Width;
1484 if (aspectOfImageSize > aspectOfDesiredSize)
1486 adjustedDesiredWidth = _desired_width;
1487 adjustedDesiredHeight = imageSize.Height * _desired_width / imageSize.Width;
1491 adjustedDesiredWidth = imageSize.Width * _desired_height / imageSize.Height;
1492 adjustedDesiredHeight = _desired_height;
1495 PropertyValue returnWidth = new PropertyValue(adjustedDesiredWidth);
1496 cachedImagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth;
1497 returnWidth?.Dispose();
1498 PropertyValue returnHeight = new PropertyValue(adjustedDesiredHeight);
1499 cachedImagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight;
1500 returnHeight?.Dispose();
1501 PropertyValue scaleToFit = new PropertyValue((int)FittingModeType.ScaleToFill);
1502 cachedImagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit;
1503 scaleToFit?.Dispose();
1507 Tizen.Log.Fatal("NUI", "[ERROR] Can't use DesiredSize when ImageLoading is failed.");
1509 imageSize?.Dispose();
1517 /// Merge our collected properties, and set IMAGE property internally.
1519 private void UpdateImageMap()
1521 // Note : We can't use ImageView.Image property here. Because That property call UpdateImage internally.
1522 using(PropertyMap imageMap = new PropertyMap())
1524 using(PropertyValue returnValue = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE))
1526 returnValue?.Get(imageMap);
1528 if(cachedImagePropertyMap != null)
1530 imageMap?.Merge(cachedImagePropertyMap);
1532 using(PropertyValue setValue = new PropertyValue(imageMap))
1534 SetProperty(ImageView.Property.IMAGE, setValue);
1537 // Update cached image property.
1538 MergeCachedImageVisualProperty(imageMap);
1543 /// Get image visual property by key.
1544 /// If we found value in local Cached result, return that.
1545 /// Else, get synced native map and return that.
1546 /// If there is no matched value, return null.
1548 [EditorBrowsable(EditorBrowsableState.Never)]
1549 protected virtual PropertyValue GetImageVisualProperty(int key)
1551 PropertyValue ret = GetCachedImageVisualProperty(key);
1554 // If we cannot find result form cached map, Get value from native engine.
1555 ret = Image?.Find(key);
1561 /// Get image visual property from NUI cached image map by key.
1562 /// If there is no matched value, return null.
1564 [EditorBrowsable(EditorBrowsableState.Never)]
1565 protected virtual PropertyValue GetCachedImageVisualProperty(int key)
1567 return cachedImagePropertyMap?.Find(key);
1571 /// Update NUI cached image visual property map by inputed property map.
1574 /// For performance issue, we will collect only "cachedImagePropertyKeyList" hold.
1576 [EditorBrowsable(EditorBrowsableState.Never)]
1577 protected virtual void MergeCachedImageVisualProperty(PropertyMap map)
1579 if(map == null) return;
1580 if(cachedImagePropertyMap == null)
1582 cachedImagePropertyMap = new PropertyMap();
1584 foreach(var key in cachedImagePropertyKeyList)
1586 PropertyValue value = map.Find(key);
1589 // Update-or-Insert new value
1590 cachedImagePropertyMap[key] = value;
1596 /// GetNaturalSize() should be guaranteed that ResourceUrl property setuped.
1597 /// So before get base.GetNaturalSize(), we should synchronous image properties
1599 internal override Vector3 GetNaturalSize()
1601 // Sync as current properties
1603 return base.GetNaturalSize();
1606 [EditorBrowsable(EditorBrowsableState.Never)]
1607 protected override bool CheckResourceReady()
1609 // If we have some properties to be updated, this signal is old thing.
1610 // We need to ignore current signal, and wait next.
1611 return !(imagePropertyUpdateProcessAttachedFlag && imagePropertyUpdatedFlag);
1614 private void OnResourceLoaded(IntPtr view)
1616 if(!CheckResourceReady())
1620 ResourceLoadedEventArgs e = new ResourceLoadedEventArgs();
1621 e.Status = (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
1623 if (_resourceLoadedEventHandler != null)
1625 _resourceLoadedEventHandler(this, e);
1630 /// Event arguments of resource ready.
1632 /// <since_tizen> 3 </since_tizen>
1633 public class ResourceReadyEventArgs : EventArgs
1638 /// The view whose resource is ready.
1640 /// <since_tizen> 3 </since_tizen>
1654 internal class ResourceLoadedEventArgs : EventArgs
1656 private ResourceLoadingStatusType status = ResourceLoadingStatusType.Invalid;
1657 public ResourceLoadingStatusType Status
1670 internal new class Property
1672 internal static readonly int IMAGE = Interop.ImageView.ImageGet();
1673 internal static readonly int PreMultipliedAlpha = Interop.ImageView.PreMultipliedAlphaGet();
1674 internal static readonly int PixelArea = Interop.ImageView.PixelAreaGet();
1677 private enum ImageType
1680 /// For Normal Image.
1685 /// For normal image, with synchronous loading and orientation correction property
1690 /// For nine-patch image
1695 private void OnBorderChanged(int x, int y, int width, int height)
1697 Border = new Rectangle(x, y, width, height);
1699 private void OnPixelAreaChanged(float x, float y, float z, float w)
1701 PixelArea = new RelativeVector4(x, y, z, w);
1704 private class ImageLayout : LayoutItem
1707 /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
1708 /// 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.
1710 [EditorBrowsable(EditorBrowsableState.Never)]
1711 public bool AdjustViewSize
1715 return (Owner as ImageView)?.AdjustViewSize ?? false;
1719 if (Owner is ImageView imageView)
1721 imageView.AdjustViewSize = value;
1727 [EditorBrowsable(EditorBrowsableState.Never)]
1728 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
1730 // To not change the view size by DALi
1731 Owner.WidthResizePolicy = ResizePolicyType.Fixed;
1732 Owner.HeightResizePolicy = ResizePolicyType.Fixed;
1734 float specWidth = widthMeasureSpec.Size.AsDecimal();
1735 float specHeight = heightMeasureSpec.Size.AsDecimal();
1736 float naturalWidth = Owner.NaturalSize.Width;
1737 float naturalHeight = Owner.NaturalSize.Height;
1738 float minWidth = Owner.MinimumSize.Width;
1739 float maxWidth = Owner.MaximumSize.Width;
1740 float minHeight = Owner.MinimumSize.Height;
1741 float maxHeight = Owner.MaximumSize.Height;
1742 float aspectRatio = (naturalWidth > 0) ? (naturalHeight / naturalWidth) : 0;
1744 // Assume that the new width and height are given from the view's suggested size by default.
1745 float newWidth = Math.Min(Math.Max(naturalWidth, minWidth), (maxWidth < 0 ? Int32.MaxValue : maxWidth));
1746 float newHeight = Math.Min(Math.Max(naturalHeight, minHeight), (maxHeight < 0 ? Int32.MaxValue : maxHeight));
1748 // The width and height measure specs are going to be used to set measured size.
1749 // Mark that the measure specs are changed by default to update measure specs later.
1750 bool widthSpecChanged = true;
1751 bool heightSpecChanged = true;
1753 if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
1755 newWidth = specWidth;
1756 widthSpecChanged = false;
1758 if (heightMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
1760 if ((AdjustViewSize) && (aspectRatio > 0))
1762 newHeight = newWidth * aspectRatio;
1767 if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
1769 newHeight = specHeight;
1770 heightSpecChanged = false;
1772 if (widthMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
1774 if ((AdjustViewSize) && (aspectRatio > 0))
1776 newWidth = newHeight / aspectRatio;
1781 if (widthSpecChanged)
1783 widthMeasureSpec = new MeasureSpecification(new LayoutLength(newWidth), MeasureSpecification.ModeType.Exactly);
1786 if (heightSpecChanged)
1788 heightMeasureSpec = new MeasureSpecification(new LayoutLength(newHeight), MeasureSpecification.ModeType.Exactly);
1791 MeasuredSize.StateType childWidthState = MeasuredSize.StateType.MeasuredSizeOK;
1792 MeasuredSize.StateType childHeightState = MeasuredSize.StateType.MeasuredSizeOK;
1794 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(newWidth), widthMeasureSpec, childWidthState),
1795 ResolveSizeAndState(new LayoutLength(newHeight), heightMeasureSpec, childHeightState));