From: David Steele Date: Wed, 5 Sep 2018 10:04:28 +0000 (+0000) Subject: Merge "Actor's position and size is not updated after DevelControl::SetLayout." into... X-Git-Tag: dali_1.3.40~2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=636f1454804a1566e47c968e7810c7080fc7b180;hp=5840e42e5cbccf50ba4629146a19441cee45482c Merge "Actor's position and size is not updated after DevelControl::SetLayout." into devel/master --- diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Layouting.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Layouting.cpp index 27222a9..28ada5a 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Layouting.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Layouting.cpp @@ -944,6 +944,454 @@ int UtcDaliLayouting_HboxLayout09(void) END_TEST; } +int UtcDaliLayouting_HboxLayout_Weight(void) +{ + ToolkitTestApplication application; + tet_infoline( " UtcDaliLayouting_HboxLayout_Weight - Test LinearLayout weight horizontally" ); + + Stage stage = Stage::GetCurrent(); + auto hbox = Control::New(); + auto hboxLayout = LinearLayout::New(); + DevelControl::SetLayout( hbox, hboxLayout ); + hbox.SetName( "HBox" ); + + std::vector controls; + controls.push_back( CreateLeafControl( 40, 40 ) ); + controls.push_back( CreateLeafControl( 60, 40 ) ); + controls.push_back( CreateLeafControl( 80, 40 ) ); + controls.push_back( CreateLeafControl( 100, 40 ) ); + + // Set weight for each leaf to use quarter of available space + // 480 * 0.25, 480 * 0.25, 480 * 0.25, 480 * 0.25, + // width spec has to be set to 0 so not to consume any extra space. + for( auto&& iter : controls ) + { + iter.SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.25f ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 0 ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + hbox.Add( iter ); + } + + hbox.SetParentOrigin( ParentOrigin::CENTER ); + hbox.SetAnchorPoint( AnchorPoint::CENTER ); + stage.Add( hbox ); + + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 120.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 240.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 360.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 120.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 120.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 120.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 120.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // Set weight for 3, 4 leafs to use all remaining available space after 1, 2 content sized leafs. + // 40, 60, (480 - 40 - 60) * 0.5, (480 - 40 - 60) * 0.5 + controls[0].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[0].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[1].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[1].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[2].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.5f ); + controls[3].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.5f ); + + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 40.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 100.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 290.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 190.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 190.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // Add intrinsic width for 3rd leaf so now we should get + // 40, 60, (480 - 40 - 60 - 80) * 0.5 + 80, (480 - 40 - 60 - 80) * 0.5 + controls[2].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 80 ); + + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 40.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 100.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 330.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 230.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 150.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + controls[0].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 0 ); + controls[0].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.25f ); + controls[1].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 0 ); + controls[1].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.5f ); + controls[2].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 0 ); + controls[2].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.25f ); + controls[3].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 40 ); + controls[3].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 110.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 330.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 440.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 110.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 220.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 110.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // WRAP_CONTENT doesn't affect weight + controls[0].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[0].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[1].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[1].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[2].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[2].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[3].SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[3].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 1 ); + + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 40.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 100.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 180.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 80.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 300.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // MATCH_PARENT doesn't affect weight + for( auto&& iter : controls ) + { + iter.SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.25f ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT ); + iter.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[1].GetProperty( Actor::Property::POSITION ), Vector3( 120.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 240.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 360.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 120.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 120.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 120.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 120.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + const Extents CONTROL_MARGIN = Extents( 10, 10, 0, 0 ); + for( auto&& iter : controls ) + { + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + iter.SetProperty( Toolkit::Control::Property::MARGIN, CONTROL_MARGIN ); + } + + controls[0].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[1].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[2].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[3].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 1 ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 10.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 70.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 150.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 250.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 80.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 220.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliLayouting_VboxLayout_Weight(void) +{ + ToolkitTestApplication application; + tet_infoline( " UtcDaliLayouting_VboxLayout_Weight - Test LinearLayout weight vertically" ); + + Stage stage = Stage::GetCurrent(); + auto vbox = Control::New(); + auto vboxLayout = LinearLayout::New(); + vboxLayout.SetOrientation( Dali::Toolkit::LinearLayout::Orientation::VERTICAL ); + DevelControl::SetLayout( vbox, vboxLayout ); + vbox.SetName( "VBox" ); + + std::vector controls; + controls.push_back( CreateLeafControl( 40, 40 ) ); + controls.push_back( CreateLeafControl( 60, 60 ) ); + controls.push_back( CreateLeafControl( 80, 80 ) ); + controls.push_back( CreateLeafControl( 100, 100 ) ); + + // Set weight for each leaf to use quarter of available space + // 800 * 0.25, 800 * 0.25, 800 * 0.25, 800 * 0.25, + // width spec has to be set to 0 so not to consume any extra space. + for( auto&& iter : controls ) + { + iter.SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.25f ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, 0 ); + vbox.Add( iter ); + } + + vbox.SetParentOrigin( ParentOrigin::CENTER ); + vbox.SetAnchorPoint( AnchorPoint::CENTER ); + stage.Add( vbox ); + + // 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[1].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 400.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 600.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 80.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // Set weight for 3, 4 leafs to use all remaining available space after 1, 2 content sized leafs. + // 40, 60, (800 - 40 - 60) * 0.5, (800 - 40 - 60) * 0.5 + controls[0].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[0].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[1].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[1].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[2].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.5f ); + controls[3].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.5f ); + + // 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[1].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 450.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 80.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // Add intrinsic width for 3rd leaf so now we should get + // 40, 60, (800 - 40 - 60 - 100) * 0.5 + 100, (800 - 40 - 60 - 100) * 0.5 + controls[2].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, 100 ); + + // 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[1].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 500.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 80.0f, 400.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 300.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + controls[0].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, 0 ); + controls[0].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.25f ); + controls[1].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, 0 ); + controls[1].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.5f ); + controls[2].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, 0 ); + controls[2].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.25f ); + controls[3].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, 100 ); + controls[3].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + + // 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[1].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 175.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 525.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 700.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 175.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 80.0f, 175.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // WRAP_CONTENT doesn't affect weight + controls[0].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[0].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[1].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[1].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[2].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[2].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[3].SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + controls[3].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 1 ); + + // 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[1].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 180.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 80.0f, 80.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 620.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // MATCH_PARENT doesn't affect weight + for( auto&& iter : controls ) + { + iter.SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.25f ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT ); + iter.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[1].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 400.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 600.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + const Extents CONTROL_MARGIN = Extents( 0, 0, 10, 10 ); + for( auto&& iter : controls ) + { + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + iter.SetProperty( Toolkit::Control::Property::MARGIN, CONTROL_MARGIN ); + } + + controls[0].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[1].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[2].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0 ); + controls[3].SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 1 ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 10.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 150.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 250.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[2].GetProperty( Actor::Property::SIZE ), Vector3( 80.0f, 80.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[3].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 540.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliLayouting_NestedLinearLayout_Weight(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliLayouting_NestedLinearLayout_Weight - test weighted children with wrapped parent"); + + Stage stage = Stage::GetCurrent(); + auto rootControl = Control::New(); + rootControl.SetName( "AbsoluteLayout"); + auto rootLayout = AbsoluteLayout::New(); + DevelControl::SetLayout( rootControl, rootLayout ); + rootControl.SetAnchorPoint( AnchorPoint::CENTER ); + rootControl.SetParentOrigin( ParentOrigin::CENTER ); + stage.Add( rootControl ); + + auto hbox = Control::New(); + auto hboxLayout = LinearLayout::New(); + DevelControl::SetLayout( hbox, hboxLayout ); + hbox.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + hbox.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + + std::vector< Control > controls; + controls.push_back( CreateLeafControl( 40, 40 ) ); + controls.push_back( CreateLeafControl( 60, 60 ) ); + + // set equal share of wrapped content width (40 + 60 = 100) for both children 100 * 0.5, 100 * 0.5 + for( auto&& iter : controls ) + { + iter.SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.5f ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 0 ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + hbox.Add( iter ); + } + + hbox.SetParentOrigin( ParentOrigin::CENTER ); + hbox.SetAnchorPoint( AnchorPoint::CENTER ); + rootControl.Add( hbox ); + + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( hbox.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( hbox.GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 10.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 50.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 50.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 50.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + hboxLayout.SetOrientation(Dali::Toolkit::LinearLayout::Orientation::VERTICAL); + + // set equal share of wrapped content height (40 + 60 = 100) for both children 100 * 0.5, 100 * 0.5 + for( auto&& iter : controls ) + { + iter.SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.5f ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT ); + iter.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, 0 ); + } + + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( hbox.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( hbox.GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 40.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 60.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + END_TEST; +} + + namespace { const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/broken.png"; diff --git a/dali-toolkit/devel-api/layouting/linear-layout.h b/dali-toolkit/devel-api/layouting/linear-layout.h index 07924db..b70303a 100644 --- a/dali-toolkit/devel-api/layouting/linear-layout.h +++ b/dali-toolkit/devel-api/layouting/linear-layout.h @@ -72,6 +72,14 @@ public: }; }; + struct ChildProperty + { + enum + { + WEIGHT = CHILD_PROPERTY_START_INDEX, ///< name "weight", The proportion of the free space in the container the linear item will receive after all other non weighted items measured and all items specification width & height added. Type FLOAT + }; + }; + /** * @brief Creates an uninitialized LinearLayout handle. * diff --git a/dali-toolkit/internal/layouting/linear-layout-impl.cpp b/dali-toolkit/internal/layouting/linear-layout-impl.cpp index c85c5fe..fdba7e6 100644 --- a/dali-toolkit/internal/layouting/linear-layout-impl.cpp +++ b/dali-toolkit/internal/layouting/linear-layout-impl.cpp @@ -21,6 +21,7 @@ #include #include #include +#include //INTERNAL INCLUDES #include @@ -63,6 +64,31 @@ LinearLayout::~LinearLayout() { } +void LinearLayout::DoRegisterChildProperties( const std::string& containerType ) +{ + auto typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( containerType ); + if( typeInfo ) + { + Property::IndexContainer indices; + typeInfo.GetChildPropertyIndices( indices ); + + if( std::find( indices.Begin(), indices.End(), Toolkit::LinearLayout::ChildProperty::WEIGHT ) == + indices.End() ) + { + ChildPropertyRegistration( typeInfo.GetName(), "weight", Toolkit::LinearLayout::ChildProperty::WEIGHT, Property::FLOAT ); + } + } +} + +void LinearLayout::OnChildAdd( LayoutItem& child ) +{ + auto owner = child.GetOwner(); + if( !DevelHandle::DoesCustomPropertyExist( owner, Toolkit::LinearLayout::ChildProperty::WEIGHT ) ) + { + owner.SetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT, 0.0f ); + } +} + void LinearLayout::SetCellPadding( LayoutSize size ) { if ( mCellPadding != size ) @@ -159,11 +185,14 @@ void LinearLayout::MeasureHorizontal( MeasureSpec widthMeasureSpec, MeasureSpec { auto widthMode = widthMeasureSpec.GetMode(); auto heightMode = heightMeasureSpec.GetMode(); - bool isExactly = (widthMode == MeasureSpec::Mode::EXACTLY); + bool isExactly = ( widthMode == MeasureSpec::Mode::EXACTLY ); bool matchHeight = false; bool allFillParent = true; LayoutLength maxHeight = 0; LayoutLength alternativeMaxHeight = 0; + LayoutLength weightedMaxHeight = 0; + float totalWeight = 0; + int usedExcessSpace = 0; struct { MeasuredSize::State widthState; @@ -174,32 +203,64 @@ void LinearLayout::MeasureHorizontal( MeasureSpec widthMeasureSpec, MeasureSpec mTotalLength = 0; // measure children, and determine if further resolution is required - for( unsigned int i=0; iGetOwner(); auto desiredHeight = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION ); - - MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec ); - auto childWidth = childLayout->GetMeasuredWidth(); + auto desiredWidth = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ); + auto childWeight = childOwner.GetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT ); auto childMargin = childLayout->GetMargin(); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LinearLayout::OnMeasure childWidth(%d)\n", MeasureSpec::IntType( childWidth ) ); - - auto length = childWidth + LayoutLength::IntType(childMargin.start + childMargin.end); - - auto cellPadding = i 0; + if( isExactly && useExcessSpace ) { - mTotalLength += length; + mTotalLength += childMargin.start + childMargin.end; } else { - auto totalLength = mTotalLength; - mTotalLength = std::max( totalLength, totalLength + length + cellPadding ); + LayoutLength childWidth = 0; + if( useExcessSpace ) + { + // The widthMode is either UNSPECIFIED or AT_MOST, and + // this child is only laid out using excess space. Measure + // using WRAP_CONTENT so that we can find out the view's + // optimal width. + auto padding = GetPadding(); + const MeasureSpec childWidthMeasureSpec = GetChildMeasureSpec( widthMeasureSpec, padding.start + padding.end, Toolkit::ChildLayoutData::WRAP_CONTENT ); + const MeasureSpec childHeightMeasureSpec = GetChildMeasureSpec( heightMeasureSpec, padding.top + padding.bottom, desiredHeight ); + childLayout->Measure( childWidthMeasureSpec, childHeightMeasureSpec ); + childWidth = childLayout->GetMeasuredWidth(); + usedExcessSpace += childWidth; + } + else + { + MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec ); + childWidth = childLayout->GetMeasuredWidth(); + } + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LinearLayout::OnMeasure childWidth(%d)\n", MeasureSpec::IntType( childWidth ) ); + auto length = childWidth + LayoutLength::IntType( childMargin.start + childMargin.end ); + auto cellPadding = i < GetChildCount() - 1 ? mCellPadding.width : 0; + if( isExactly ) + { + mTotalLength += length; + } + else + { + auto totalLength = mTotalLength; + mTotalLength = std::max( totalLength, totalLength + length + cellPadding ); + } } bool matchHeightLocally = false; @@ -224,7 +285,18 @@ void LinearLayout::MeasureHorizontal( MeasureSpec widthMeasureSpec, MeasureSpec maxHeight = std::max( maxHeight, childHeight ); allFillParent = ( allFillParent && desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT ); - alternativeMaxHeight = std::max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight ); + if( childWeight > 0 ) + { + /* + * Heights of weighted Views are bogus if we end up + * remeasuring, so keep them separate. + */ + weightedMaxHeight = std::max( weightedMaxHeight, matchHeightLocally ? marginHeight : childHeight ); + } + else + { + alternativeMaxHeight = std::max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight ); + } } } @@ -235,6 +307,88 @@ void LinearLayout::MeasureHorizontal( MeasureSpec widthMeasureSpec, MeasureSpec MeasuredSize widthSizeAndState = ResolveSizeAndState( widthSize, widthMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK); widthSize = widthSizeAndState.GetSize(); + // Expand children with weight to take up available space + // 2nd phase: + // We cycle through weighted children now (children with weight > 0). + // The children are measured with exact size equal to their share of the available space based on their weights. + // mTotalLength is updated to include weighted children measured sizes. + int remainingExcess = widthSize - mTotalLength + usedExcessSpace; + if( remainingExcess != 0 && totalWeight > 0 ) + { + float remainingWeightSum = totalWeight; + maxHeight = 0; + mTotalLength = 0; + + for( unsigned int i = 0; i < GetChildCount(); ++i ) + { + auto childLayout = GetChildAt( i ); + auto childOwner = childLayout->GetOwner(); + auto desiredWidth = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ); + auto desiredHeight = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION ); + auto childWeight = childOwner.GetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT ); + auto childMargin = childLayout->GetMargin(); + + LayoutLength childWidth = 0; + if( childWeight > 0 ) + { + int share = static_cast( childWeight * remainingExcess / remainingWeightSum ); + remainingExcess -= share; + remainingWeightSum -= childWeight; + + // Always lay out weighted elements with intrinsic size regardless of the parent spec. + // for consistency between specs. + if( desiredWidth == 0 ) + { + // This child needs to be laid out from scratch using + // only its share of excess space. + childWidth = share; + } + else + { + // This child had some intrinsic width to which we + // need to add its share of excess space. + childWidth = childLayout->GetMeasuredWidth() + share; + } + + const MeasureSpec childWidthMeasureSpec = MeasureSpec( childWidth, MeasureSpec::Mode::EXACTLY ); + const MeasureSpec childHeightMeasureSpec = GetChildMeasureSpec( heightMeasureSpec, padding.top + padding.bottom, desiredHeight ); + childLayout->Measure( childWidthMeasureSpec, childHeightMeasureSpec ); + + // Child may now not fit in horizontal dimension. + if( childLayout->GetMeasuredWidthAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL ) + { + childState.widthState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL; + } + } + + auto length = childLayout->GetMeasuredWidth() + LayoutLength::IntType( childMargin.start + childMargin.end ); + auto cellPadding = i < GetChildCount() - 1 ? mCellPadding.width : 0; + if( isExactly ) + { + mTotalLength += length; + } + else + { + auto totalLength = mTotalLength; + mTotalLength = std::max( totalLength, totalLength + length + cellPadding ); + } + + bool matchHeightLocally = heightMode != MeasureSpec::Mode::EXACTLY && desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT; + auto marginHeight = LayoutLength( childMargin.top + childMargin.bottom ); + auto childHeight = childLayout->GetMeasuredHeight() + marginHeight; + + maxHeight = std::max( maxHeight, childHeight ); + alternativeMaxHeight = std::max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight ); + allFillParent = (allFillParent && desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT); + + mTotalLength += padding.start + padding.end; + } + } + else + { + alternativeMaxHeight = std::max( alternativeMaxHeight, weightedMaxHeight ); + } + if( !allFillParent && heightMode != MeasureSpec::Mode::EXACTLY ) { maxHeight = alternativeMaxHeight; @@ -385,12 +539,16 @@ void LinearLayout::LayoutHorizontal( LayoutLength left, LayoutLength top, Layout void LinearLayout::MeasureVertical( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec ) { auto widthMode = widthMeasureSpec.GetMode(); + auto heightMode = heightMeasureSpec.GetMode(); + bool isExactly = ( heightMode == MeasureSpec::Mode::EXACTLY ); bool matchWidth = false; bool allFillParent = true; LayoutLength maxWidth = 0; LayoutLength alternativeMaxWidth = 0; - + LayoutLength weightedMaxWidth = 0; + float totalWeight = 0; + int usedExcessSpace = 0; struct { MeasuredSize::State widthState; @@ -401,22 +559,62 @@ void LinearLayout::MeasureVertical( MeasureSpec widthMeasureSpec, MeasureSpec he mTotalLength = 0; // measure children, and determine if further resolution is required - for( unsigned int i=0; iGetOwner(); auto desiredWidth = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ); - - MeasureChildWithMargins( childLayout, widthMeasureSpec, 0, heightMeasureSpec, 0 ); - auto childHeight = childLayout->GetMeasuredHeight(); + auto desiredHeight = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION ); + auto childWeight = childOwner.GetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT ); auto childMargin = childLayout->GetMargin(); - auto length = childHeight + LayoutLength::IntType(childMargin.top + childMargin.bottom ); - auto cellPadding = i 0; + + if( isExactly && useExcessSpace ) + { + LayoutLength totalLength = mTotalLength; + mTotalLength = std::max( totalLength, totalLength + childMargin.top + childMargin.bottom ); + } + else + { + LayoutLength childHeight = 0; + if( useExcessSpace ) + { + // The heightMode is either UNSPECIFIED or AT_MOST, and + // this child is only laid out using excess space. Measure + // using WRAP_CONTENT so that we can find out the view's + // optimal height. We'll restore the original height of 0 + // after measurement. + auto padding = GetPadding(); + const MeasureSpec childWidthMeasureSpec = GetChildMeasureSpec( widthMeasureSpec, padding.start + padding.end, desiredWidth ); + const MeasureSpec childHeightMeasureSpec = GetChildMeasureSpec( heightMeasureSpec, padding.top + padding.bottom, Toolkit::ChildLayoutData::WRAP_CONTENT ); + childLayout->Measure( childWidthMeasureSpec, childHeightMeasureSpec ); + childHeight = childLayout->GetMeasuredHeight(); + usedExcessSpace += childHeight; + } + else + { + MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec ); + childHeight = childLayout->GetMeasuredHeight(); + } + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LinearLayout::MeasureVertical childHeight(%d)\n", MeasureSpec::IntType( childHeight ) ); + + auto length = childHeight + LayoutLength::IntType( childMargin.top + childMargin.bottom ); + auto cellPadding = i < GetChildCount() - 1 ? mCellPadding.height : 0; + auto totalLength = mTotalLength; + mTotalLength = std::max( totalLength, totalLength + length + cellPadding ); + } bool matchWidthLocally = false; if( widthMode != MeasureSpec::Mode::EXACTLY && desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT ) @@ -441,9 +639,21 @@ void LinearLayout::MeasureVertical( MeasureSpec widthMeasureSpec, MeasureSpec he maxWidth = std::max( maxWidth, childWidth ); allFillParent = ( allFillParent && desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT ); - alternativeMaxWidth = std::max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth ); + if( childWeight > 0 ) + { + /* + * Widths of weighted Views are bogus if we end up + * remeasuring, so keep them separate. + */ + weightedMaxWidth = std::max( weightedMaxWidth, matchWidthLocally ? marginWidth : childWidth ); + } + else + { + alternativeMaxWidth = std::max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth ); + } } } + Extents padding = GetPadding(); mTotalLength += padding.top + padding.bottom; auto heightSize = mTotalLength; @@ -451,6 +661,92 @@ void LinearLayout::MeasureVertical( MeasureSpec widthMeasureSpec, MeasureSpec he MeasuredSize heightSizeAndState = ResolveSizeAndState( heightSize, heightMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK); heightSize = heightSizeAndState.GetSize(); + // Either expand children with weight to take up available space or + // shrink them if they extend beyond our current bounds. If we skipped + // measurement on any children, we need to measure them now. + + // 2nd phase: + // We cycle through weighted children now (children with weight > 0). + // The children are measured with exact size equal to their share of the available space based on their weights. + // mTotalLength is updated to include weighted children measured sizes. + int remainingExcess = heightSize - mTotalLength + usedExcessSpace; + if( remainingExcess != 0 && totalWeight > 0.0f ) + { + float remainingWeightSum = totalWeight; + + mTotalLength = 0; + + for( unsigned int i = 0; i < GetChildCount(); ++i ) + { + auto childLayout = GetChildAt( i ); + auto childOwner = childLayout->GetOwner(); + auto desiredWidth = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ); + auto desiredHeight = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION ); + auto childWeight = childOwner.GetProperty( Toolkit::LinearLayout::ChildProperty::WEIGHT ); + auto childMargin = childLayout->GetMargin(); + + LayoutLength childHeight = 0; + if( childWeight > 0 ) + { + int share = static_cast( childWeight * remainingExcess / remainingWeightSum ); + remainingExcess -= share; + remainingWeightSum -= childWeight; + + // Always lay out weighted elements with intrinsic size regardless of the parent spec + // for consistency between specs. + if( desiredHeight == 0 ) + { + // This child needs to be laid out from scratch using + // only its share of excess space. + childHeight = share; + } + else + { + // This child had some intrinsic width to which we + // need to add its share of excess space. + childHeight = childLayout->GetMeasuredHeight() + share; + } + + const MeasureSpec childWidthMeasureSpec = GetChildMeasureSpec( widthMeasureSpec, padding.start + padding.end, desiredWidth ); + const MeasureSpec childHeightMeasureSpec = MeasureSpec( childHeight, MeasureSpec::Mode::EXACTLY ); + childLayout->Measure( childWidthMeasureSpec, childHeightMeasureSpec ); + + // Child may now not fit in vertical dimension. + if( childLayout->GetMeasuredHeightAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL ) + { + childState.heightState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL; + } + } + + bool matchWidthLocally = false; + if( widthMode != MeasureSpec::Mode::EXACTLY && desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT ) + { + // Will have to re-measure at least this child when we know exact height. + matchWidth = true; + matchWidthLocally = true; + } + + auto marginWidth = LayoutLength( childMargin.start + childMargin.end ); + auto childWidth = childLayout->GetMeasuredWidth() + marginWidth; + maxWidth = std::max( maxWidth, childWidth ); + allFillParent = allFillParent && desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT; + alternativeMaxWidth = std::max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth ); + + childHeight = childLayout->GetMeasuredHeight(); + auto length = childHeight + LayoutLength::IntType( childMargin.top + childMargin.bottom ); + auto cellPadding = i < GetChildCount() - 1 ? mCellPadding.height : 0; + auto totalLength = mTotalLength; + mTotalLength = std::max( totalLength, totalLength + length + cellPadding ); + } + + // Add in our padding + mTotalLength += padding.top + padding.bottom; + } + else + { + alternativeMaxWidth = std::max( alternativeMaxWidth, weightedMaxWidth ); + } + if( !allFillParent && widthMode != MeasureSpec::Mode::EXACTLY ) { maxWidth = alternativeMaxWidth; diff --git a/dali-toolkit/internal/layouting/linear-layout-impl.h b/dali-toolkit/internal/layouting/linear-layout-impl.h index 23f3184..5f39ad2 100644 --- a/dali-toolkit/internal/layouting/linear-layout-impl.h +++ b/dali-toolkit/internal/layouting/linear-layout-impl.h @@ -95,6 +95,16 @@ protected: virtual ~LinearLayout(); /** + * @copydoc LayoutItem::DoRegisterChildProperties() + */ + virtual void DoRegisterChildProperties( const std::string& containerType ) override; + + /** + * @copydoc LayoutItem::OnChildAdd + */ + virtual void OnChildAdd( LayoutItem& child ) override; + + /** * @copydoc LayoutItem::OnMeasure */ virtual void OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec ) override;