[NUI] Add AdjustViewSize to ImageView
authorJaehyun Cho <jae_hyun.cho@samsung.com>
Fri, 27 Aug 2021 07:34:26 +0000 (16:34 +0900)
committerSeoyeon2Kim <34738918+Seoyeon2Kim@users.noreply.github.com>
Mon, 13 Sep 2021 07:33:23 +0000 (16:33 +0900)
Up to now, although the position and size of image resource of ImageView
is set by FittingMode, but there is no way to set the size of ImageView
to respect the aspect ratio of its image resource.

If AdjustViewSize is true, then ImageView respects the aspect ratio of
its image resource when it determines its size.

AdjustViewSize works only if the ImageView is added to a View having Layout.
Otherwise, use can set ImageView's size to respect the aspect ratio of its image
resource by using ResizePolicyType.DimensionDependency.

src/Tizen.NUI/src/public/BaseComponents/ImageView.cs
src/Tizen.NUI/src/public/Layouting/LayoutGroup.cs

index 9c9c18b..d23d4fc 100755 (executable)
@@ -353,6 +353,14 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
+        /// <summary>
+        /// Create internal layout of ImageView
+        /// </summary>
+        internal static LayoutItem CreateImageLayout()
+        {
+            return new ImageLayout();
+        }
+
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
         private delegate void ResourceReadyEventCallbackType(IntPtr data);
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
@@ -1119,6 +1127,14 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
+        /// <summary>
+        /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
+        /// If this is set to be true, then the width or height, which is not set by user explicitly, can be adjusted to preserve the aspect ratio of the image resource.
+        /// AdjustViewSize works only if ImageView is added to a View having Layout.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool AdjustViewSize { get; set; } = false;
+
         internal Selector<string> ResourceUrlSelector
         {
             get => GetSelector<string>(resourceUrlSelector, ImageView.ResourceUrlProperty);
@@ -1500,5 +1516,100 @@ namespace Tizen.NUI.BaseComponents
         {
             PixelArea = new RelativeVector4(x, y, z, w);
         }
+
+        private class ImageLayout : LayoutItem
+        {
+            /// <summary>
+            /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
+            /// If this is set to be true, then the width or height, which is not set by user explicitly, can be adjusted to preserve the aspect ratio of the image resource.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            public bool AdjustViewSize
+            {
+                get
+                {
+                    return (Owner as ImageView)?.AdjustViewSize ?? false;
+                }
+                set
+                {
+                    if (Owner is ImageView imageView)
+                    {
+                        imageView.AdjustViewSize = value;
+                    }
+                }
+            }
+
+            /// <inheritdoc/>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
+            {
+                // To not change the view size by DALi
+                Owner.WidthResizePolicy = ResizePolicyType.Fixed;
+                Owner.HeightResizePolicy = ResizePolicyType.Fixed;
+
+                float specWidth = widthMeasureSpec.Size.AsDecimal();
+                float specHeight = heightMeasureSpec.Size.AsDecimal();
+                float naturalWidth = Owner.NaturalSize.Width;
+                float naturalHeight = Owner.NaturalSize.Height;
+                float minWidth = Owner.MinimumSize.Width;
+                float maxWidth = Owner.MaximumSize.Width;
+                float minHeight = Owner.MinimumSize.Height;
+                float maxHeight = Owner.MaximumSize.Height;
+                float aspectRatio = (naturalWidth > 0) ? (naturalHeight / naturalWidth) : 0;
+
+                // Assume that the new width and height are given from the view's suggested size by default.
+                float newWidth = Math.Min(Math.Max(naturalWidth, minWidth), (maxWidth < 0 ? Int32.MaxValue : maxWidth));
+                float newHeight = Math.Min(Math.Max(naturalHeight, minHeight), (maxHeight < 0 ? Int32.MaxValue : maxHeight));
+
+                // The width and height measure specs are going to be used to set measured size.
+                // Mark that the measure specs are changed by default to update measure specs later.
+                bool widthSpecChanged = true;
+                bool heightSpecChanged = true;
+
+                if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
+                {
+                    newWidth = specWidth;
+                    widthSpecChanged = false;
+
+                    if (heightMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
+                    {
+                        if ((AdjustViewSize) && (aspectRatio > 0))
+                        {
+                            newHeight = newWidth * aspectRatio;
+                        }
+                    }
+                }
+
+                if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
+                {
+                    newHeight = specHeight;
+                    heightSpecChanged = false;
+
+                    if (widthMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
+                    {
+                        if ((AdjustViewSize) && (aspectRatio > 0))
+                        {
+                            newWidth = newHeight / aspectRatio;
+                        }
+                    }
+                }
+
+                if (widthSpecChanged)
+                {
+                    widthMeasureSpec = new MeasureSpecification(new LayoutLength(newWidth), MeasureSpecification.ModeType.Exactly);
+                }
+
+                if (heightSpecChanged)
+                {
+                    heightMeasureSpec = new MeasureSpecification(new LayoutLength(newHeight), MeasureSpecification.ModeType.Exactly);
+                }
+
+                MeasuredSize.StateType childWidthState = MeasuredSize.StateType.MeasuredSizeOK;
+                MeasuredSize.StateType childHeightState = MeasuredSize.StateType.MeasuredSizeOK;
+
+                SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(newWidth), widthMeasureSpec, childWidthState),
+                                      ResolveSizeAndState(new LayoutLength(newHeight), heightMeasureSpec, childHeightState));
+            }
+        }
     }
 }
index e32a0f8..327c09d 100755 (executable)
@@ -188,7 +188,18 @@ namespace Tizen.NUI
                 {
                     // If child of this layout is a pure View then assign it a LayoutGroup
                     // If the child is derived from a View then it may be a legacy or existing container hence will do layouting itself.
-                    child.Layout = (child as TextLabel)?.CreateTextLayout() ?? new AbsoluteLayout();
+                    if (child is TextLabel textLabel)
+                    {
+                        child.Layout = textLabel.CreateTextLayout();
+                    }
+                    else if (child is ImageView imageView)
+                    {
+                        child.Layout = ImageView.CreateImageLayout();
+                    }
+                    else
+                    {
+                        child.Layout = new AbsoluteLayout();
+                    }
                 }
             }
             else