From: Anton Obzhirov Date: Tue, 26 Jun 2018 10:18:26 +0000 (+0100) Subject: Simplify and improve FlexLayout::OnChildMeasure. X-Git-Tag: dali_1.3.31~9 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=cf09a1ce17613ce4ce4b538d9a2cc4896ab1bc0c;hp=-c Simplify and improve FlexLayout::OnChildMeasure. Also FlexLayout::OnChildMeasure now uses LayoutGroup::GetChildMeasureSpec to get measure spec for its children which is in line with other layouts. Change-Id: I71a05e092e2ba524d1a1eb5ac3b0cd78fcac4797 --- cf09a1ce17613ce4ce4b538d9a2cc4896ab1bc0c diff --git a/automated-tests/src/dali-toolkit/utc-Dali-FlexLayout.cpp b/automated-tests/src/dali-toolkit/utc-Dali-FlexLayout.cpp index 8317361..b839043 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-FlexLayout.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-FlexLayout.cpp @@ -716,3 +716,93 @@ int UtcDaliLayouting_FlexLayout08(void) END_TEST; } + +int UtcDaliLayouting_FlexLayout_NestedFlexboxWithSpec(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliLayouting_FlexLayout_NestedFlexboxWithSpec Test nested flex box with wrap content/match parent"); + + Stage stage = Stage::GetCurrent(); + + auto flexbox1 = Control::New(); + auto flexLayout1 = FlexLayout::New(); + DevelControl::SetLayout( flexbox1, flexLayout1 ); + flexbox1.SetName( "Flexbox1"); + flexbox1.SetParentOrigin( ParentOrigin::CENTER ); + flexbox1.SetAnchorPoint( AnchorPoint::CENTER ); + + auto flexbox2 = Control::New(); + auto flexLayout2 = FlexLayout::New(); + DevelControl::SetLayout( flexbox2, flexLayout2 ); + flexbox2.SetParentOrigin( ParentOrigin::CENTER ); + flexbox2.SetAnchorPoint( AnchorPoint::CENTER ); + flexbox2.SetName( "Flexbox2"); + flexbox2.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + flexbox2.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + + std::vector< Control > controls; + controls.push_back( CreateLeafControl( 100, 100 ) ); + flexbox2.Add( controls[0] ); + flexbox1.Add( flexbox2 ); + stage.Add( flexbox1 ); + + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // Test flexbox2 is sized to wrap its content + DALI_TEST_EQUALS( flexbox1.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox2.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox1.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox2.GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + flexbox2.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT ); + flexbox2.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // Test flexbox2 width is sized to match parent + DALI_TEST_EQUALS( flexbox1.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox2.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox1.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox2.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + flexbox2.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + flexbox2.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::MATCH_PARENT ); + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // Test flexbox2 height is sized to match parent + DALI_TEST_EQUALS( flexbox1.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox2.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox1.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox2.GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + flexbox2.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT ); + flexbox2.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::MATCH_PARENT ); + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // Test flexbox2 is sized to match its parent + DALI_TEST_EQUALS( flexbox1.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox2.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox1.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( flexbox2.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + END_TEST; +} diff --git a/dali-toolkit/internal/layouting/flex-layout-impl.cpp b/dali-toolkit/internal/layouting/flex-layout-impl.cpp index 648a7f6..bf5d084 100644 --- a/dali-toolkit/internal/layouting/flex-layout-impl.cpp +++ b/dali-toolkit/internal/layouting/flex-layout-impl.cpp @@ -286,84 +286,33 @@ YGSize FlexLayout::OnChildMeasure( YGNodeRef node, YGMeasureMode widthMode, float innerHeight, YGMeasureMode heightMode ) { - // TODO: this function should try to get use of LayoutGroup::GetChildMeasureSpec - // or LayoutGroup::MeasureChild somehow since it is fixed now LayoutItem* childLayout = static_cast(node->getContext()); auto childOwner = childLayout->GetOwner(); auto desiredWidth = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ); auto desiredHeight = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION ); - - MeasureSpec::Mode measureWidthMode = MeasureSpec::Mode::AT_MOST; - MeasureSpec::Mode measureHeightMode = MeasureSpec::Mode::AT_MOST; - if( desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT ) - { - if( innerWidth != YGUndefined) - { - desiredWidth = innerWidth; - } - measureWidthMode = MeasureSpec::Mode::EXACTLY; - } - - if( desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT ) - { - if( innerHeight != YGUndefined) - { - desiredHeight = innerHeight; - } - measureHeightMode = MeasureSpec::Mode::EXACTLY; - } - - if( desiredWidth == Toolkit::ChildLayoutData::WRAP_CONTENT ) + auto parentWidthMeasureSpec = MeasureSpec( 0 ); + if ( innerWidth != YGUndefined ) { - measureWidthMode = MeasureSpec::Mode::UNSPECIFIED; + parentWidthMeasureSpec = MeasureSpec( innerWidth, static_cast(widthMode) ); } - - if( desiredHeight == Toolkit::ChildLayoutData::WRAP_CONTENT ) + auto parentHeightMeasureSpec = MeasureSpec( 0 ); + if ( innerHeight != YGUndefined ) { - measureHeightMode = MeasureSpec::Mode::UNSPECIFIED; + parentHeightMeasureSpec = MeasureSpec( innerHeight, static_cast(heightMode) ); } + auto childWidthMeasureSpec = LayoutGroup::GetChildMeasureSpec( parentWidthMeasureSpec, 0, desiredWidth); + auto childHeightMeasureSpec = LayoutGroup::GetChildMeasureSpec( parentHeightMeasureSpec, 0, desiredHeight); - MeasureSpec widthMeasureSpec = MeasureSpec( desiredWidth, measureWidthMode ); - MeasureSpec heightMeasureSpec = MeasureSpec( desiredHeight, measureHeightMode ); - if( measureWidthMode == MeasureSpec::Mode::UNSPECIFIED || - measureHeightMode == MeasureSpec::Mode::UNSPECIFIED ) + // Force to fill parent if a child wants to match parent even if GetChildMeasureSpec sets otherwise + if( desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT && innerWidth != YGUndefined ) { - // A measure just to get the size if the wrapped content - childLayout->Measure( widthMeasureSpec, heightMeasureSpec ); - desiredWidth = childLayout->GetMeasuredWidth(); - desiredHeight = childLayout->GetMeasuredHeight(); - // Remove padding here since the second measure will add it back - Extents padding = childLayout->GetPadding(); - desiredWidth = desiredWidth - padding.end - padding.start; - desiredHeight = desiredHeight - padding.bottom - padding.top; + childWidthMeasureSpec = MeasureSpec( innerWidth, MeasureSpec::Mode::EXACTLY ); } - - // Safety check to avoid going out of boundary - if( (innerWidth != YGUndefined && innerWidth != 0) && innerWidth < desiredWidth ) + if( desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT && innerHeight != YGUndefined ) { - desiredWidth = innerWidth; + childHeightMeasureSpec = MeasureSpec( innerHeight, MeasureSpec::Mode::EXACTLY ); } - if( (innerHeight != YGUndefined && innerHeight != 0) && innerHeight < desiredHeight ) - { - desiredHeight = innerHeight; - } - - // Measure for Yoga - MeasureSpec::Mode ygWidthMode = static_cast(widthMode); - if( measureWidthMode == MeasureSpec::Mode::EXACTLY ) - { - ygWidthMode = MeasureSpec::Mode::EXACTLY; - } - - MeasureSpec::Mode ygHeightMode = static_cast(heightMode); - if( measureHeightMode == MeasureSpec::Mode::EXACTLY ) - { - ygHeightMode = MeasureSpec::Mode::EXACTLY; - } - - MeasureSpec ygWidthMeasureSpec = MeasureSpec( desiredWidth, ygWidthMode ); - MeasureSpec ygHeightMeasureSpec = MeasureSpec( desiredHeight, ygHeightMode ); #if defined(DEBUG_ENABLED) auto actor = Actor::DownCast(childOwner); std::ostringstream oss; @@ -372,30 +321,23 @@ YGSize FlexLayout::OnChildMeasure( YGNodeRef node, { oss << "Actor Id:" << actor.GetId() << " Name:" << actor.GetName() << " "; } - oss << "innerWidth:" << ((innerWidth == YGUndefined) ? "YGUndefined " : "") << innerWidth << - " innerHeight:" << ((innerHeight == YGUndefined) ? "YGUndefined " : "") << innerHeight << + oss << "innerWidth:" << ( ( innerWidth == YGUndefined ) ? "YGUndefined " : "" ) << innerWidth << + " innerHeight:" << ( ( innerHeight == YGUndefined ) ? "YGUndefined " : "" ) << innerHeight << " desiredWidth:" << desiredWidth << " desiredHeight:" << desiredHeight << - " widthMeasureSpec:" << widthMeasureSpec << " heightMeasureSpec:" << heightMeasureSpec << - " ygWidthMeasureSpec:" << ygWidthMeasureSpec << " ygHeightMeasureSpec:" << ygHeightMeasureSpec << std::endl; + " childWidthMeasureSpec:" << childWidthMeasureSpec << " childHeightMeasureSpec:" << childHeightMeasureSpec << std::endl; DALI_LOG_INFO( gLogFilter, Debug::Concise, oss.str().c_str() ); #endif - if( measureWidthMode == MeasureSpec::Mode::UNSPECIFIED || - measureHeightMode == MeasureSpec::Mode::UNSPECIFIED ) - { - if( ygWidthMeasureSpec == widthMeasureSpec && ygHeightMeasureSpec == heightMeasureSpec ) - { - return YGSize{ - .width = childLayout->GetMeasuredWidth(), - .height = childLayout->GetMeasuredHeight(), - }; - } - } + childLayout->Measure( childWidthMeasureSpec, childHeightMeasureSpec ); + + // Remove padding here since Yoga doesn't consider it as a part of the node size + Extents padding = childLayout->GetPadding(); + auto measuredWidth = childLayout->GetMeasuredWidth() - padding.end - padding.start; + auto measuredHeight = childLayout->GetMeasuredHeight() - padding.bottom - padding.top; - childLayout->Measure( ygWidthMeasureSpec, ygHeightMeasureSpec ); return YGSize{ - .width = childLayout->GetMeasuredWidth(), - .height = childLayout->GetMeasuredHeight(), + .width = measuredWidth, + .height = measuredHeight, }; }