[NUI] Fix CustomView.GetNaturalSize() to return Size2D set by user
authorJaehyun Cho <jae_hyun.cho@samsung.com>
Wed, 20 Apr 2022 02:35:49 +0000 (11:35 +0900)
committerJaehyun Cho <jaehyun0cho@gmail.com>
Thu, 21 Apr 2022 10:39:37 +0000 (19:39 +0900)
Originally, CustomView.GetNaturalSize() returned size set by user
explicitly.

It was changed by https://github.com/Samsung/TizenFX/pull/2515.
By the above PR, CustomView.GetNaturalSize() returned Size2D which can
be set by both user and Layout.

Since the current CustomView.GetNaturalSize() cannot distinguish the
size set by user from the size set by Layout, the size set by Layout
previously can be preserved incorrectly and the size is not updated
incorrectly.

To resolve the above issue, CustomView.GetNaturalSize() returns Size2D
set by user explicitly to make Layout preserve the size only set by user
explicitly.

e.g. problem case
var window = NUIApplication.GetDefaultWindow();

var parent = new Control()
{
    Layout = new AbsoluteLayout(),
    WidthSpecification = LayoutParamPolicies.MatchParent,
    HeightSpecification = LayoutParamPolicies.WrapContent,
    BackgroundColor = Color.Red,
};
window.Add(parent);

var child = new Control()
{
    WidthSpecification = LayoutParamPolicies.MatchParent,
    HeightSpecification = 200,
    BackgroundColor = Color.Blue,
};
parent.Add(child);

var timer = new Timer(1000);
timer.Tick += (object sender, Timer.TickEventArgs args) =>
{
    child.HeightSpecification = 100;
    return false;
};
timer.Start();

src/Tizen.NUI/src/public/BaseComponents/CustomView.cs
src/Tizen.NUI/src/public/BaseComponents/ViewBindableProperty.cs

index c322b64..3d8ef74 100755 (executable)
@@ -320,7 +320,7 @@ namespace Tizen.NUI.BaseComponents
         [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1721: Property names should not match get methods")]
         public new virtual Size2D GetNaturalSize()
         {
-            return (Size2D)GetValue(Size2DProperty);
+            return GetUserSize2D();
         }
 
         /// <summary>
index 755671d..6cc36f7 100755 (executable)
@@ -27,6 +27,9 @@ namespace Tizen.NUI.BaseComponents
     /// <since_tizen> 3 </since_tizen>
     public partial class View
     {
+        private float userSizeWidth = 0.0f;
+        private float userSizeHeight = 0.0f;
+
         /// <summary>
         /// StyleNameProperty (DALi json)
         /// </summary>
@@ -696,6 +699,13 @@ namespace Tizen.NUI.BaseComponents
                 var view = (View)bindable;
                 if (newValue != null)
                 {
+                    // Size property setter is only used by user.
+                    // Framework code uses SetSize() instead of Size property setter.
+                    // Size set by user is returned by GetUserSize2D() for SuggestedMinimumWidth/Height.
+                    // SuggestedMinimumWidth/Height is used by Layout calculation.
+                    view.userSizeWidth = ((Size2D)newValue).Width;
+                    view.userSizeHeight = ((Size2D)newValue).Height;
+
                     view.SetSize(((Size2D)newValue).Width, ((Size2D)newValue).Height, 0);
 
                     view.widthPolicy = ((Size2D)newValue).Width;
@@ -926,6 +936,12 @@ namespace Tizen.NUI.BaseComponents
             var view = (View)bindable;
             if (newValue != null)
             {
+                // Size property setter is only used by user.
+                // Framework code uses SetSize() instead of Size property setter.
+                // Size set by user is returned by GetUserSize2D() for SuggestedMinimumWidth/Height.
+                // SuggestedMinimumWidth/Height is used by Layout calculation.
+                view.userSizeWidth = (float)newValue;
+
                 Tizen.NUI.Object.SetProperty((System.Runtime.InteropServices.HandleRef)view.SwigCPtr, View.Property.SizeWidth, new Tizen.NUI.PropertyValue((float)newValue));
                 view.WidthSpecification = (int)System.Math.Ceiling((float)newValue);
             }
@@ -947,6 +963,12 @@ namespace Tizen.NUI.BaseComponents
             var view = (View)bindable;
             if (newValue != null)
             {
+                // Size property setter is only used by user.
+                // Framework code uses SetSize() instead of Size property setter.
+                // Size set by user is returned by GetUserSize2D() for SuggestedMinimumWidth/Height.
+                // SuggestedMinimumWidth/Height is used by Layout calculation.
+                view.userSizeHeight = (float)newValue;
+
                 Tizen.NUI.Object.SetProperty((System.Runtime.InteropServices.HandleRef)view.SwigCPtr, View.Property.SizeHeight, new Tizen.NUI.PropertyValue((float)newValue));
                 view.HeightSpecification = (int)System.Math.Ceiling((float)newValue);
             }
@@ -1579,6 +1601,13 @@ namespace Tizen.NUI.BaseComponents
                 var view = (View)bindable;
                 if (newValue != null)
                 {
+                    // Size property setter is only used by user.
+                    // Framework code uses SetSize() instead of Size property setter.
+                    // Size set by user is returned by GetUserSize2D() for SuggestedMinimumWidth/Height.
+                    // SuggestedMinimumWidth/Height is used by Layout calculation.
+                    view.userSizeWidth = ((Size)newValue).Width;
+                    view.userSizeHeight = ((Size)newValue).Height;
+
                     // Set Specification so when layouts measure this View it matches the value set here.
                     // All Views are currently Layouts.
                     view.WidthSpecification = (int)System.Math.Ceiling(((Size)newValue).Width);
@@ -2431,6 +2460,14 @@ namespace Tizen.NUI.BaseComponents
             return instance.InternalTouchAreaOffset;
         });
 
+        /// <summary>
+        /// Gets View's Size2D set by user.
+        /// </summary>
+        internal Size2D GetUserSize2D()
+        {
+            return new Size2D((int)userSizeWidth, (int)userSizeHeight);
+        }
+
         private void SetBackgroundImage(string value)
         {
             if (string.IsNullOrEmpty(value))