Add weight support for LinearLayout. 01/187601/8
authorAnton Obzhirov <a.obzhirov@samsung.com>
Thu, 23 Aug 2018 09:35:00 +0000 (10:35 +0100)
committerAnton Obzhirov <a.obzhirov@samsung.com>
Mon, 3 Sep 2018 15:10:00 +0000 (16:10 +0100)
Change-Id: Ibb97ee80b4346b9cca842043951dab42b3470a52

automated-tests/src/dali-toolkit/utc-Dali-Layouting.cpp
dali-toolkit/devel-api/layouting/linear-layout.h
dali-toolkit/internal/layouting/linear-layout-impl.cpp
dali-toolkit/internal/layouting/linear-layout-impl.h

index 9206215..f93257a 100644 (file)
@@ -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<Control> 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 120.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 240.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 360.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 120.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 120.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 120.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 40.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 290.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 190.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 40.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 330.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 230.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 110.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 330.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 440.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 110.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 220.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 110.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 40.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 180.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 120.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 240.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 360.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 120.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 120.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 120.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 10.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 70.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 150.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 250.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Control> 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 400.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 600.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 450.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 500.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 400.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 175.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 525.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 700.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 175.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 175.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 180.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 80.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 400.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 600.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 480.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 480.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 480.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 10.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 150.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 250.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 80.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 10.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 50.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 50.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( 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<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( 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";
index 07924db..b70303a 100644 (file)
@@ -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.
    *
index c85c5fe..fdba7e6 100644 (file)
@@ -21,6 +21,7 @@
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/common/extents.h>
 #include <dali/public-api/actors/actor.h>
+#include <dali/devel-api/object/handle-devel.h>
 
 //INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/layouting/layout-item.h>
@@ -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; i<GetChildCount(); ++i )
+
+  // 1st phase:
+  // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
+  // to accumulate total used space in mTotalLength based on measured sizes and margins.
+  // Weighted children are not measured at this phase.
+  // Available space for weighted children will be calculated in the phase 2 based on mTotalLength value.
+  for( unsigned int i = 0; i < GetChildCount(); ++i )
   {
     auto childLayout = GetChildAt( i );
     if( childLayout )
     {
       auto childOwner = childLayout->GetOwner();
       auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
-
-      MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec );
-      auto childWidth = childLayout->GetMeasuredWidth();
+      auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
+      auto childWeight = childOwner.GetProperty<float>( 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<GetChildCount()-1 ? mCellPadding.width: 0;
+      totalWeight += childWeight;
 
-      if( isExactly )
+      const bool useExcessSpace = desiredWidth == 0 && childWeight > 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<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
+      auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
+      auto childWeight = childOwner.GetProperty<float>( Toolkit::LinearLayout::ChildProperty::WEIGHT );
+      auto childMargin = childLayout->GetMargin();
+
+      LayoutLength childWidth = 0;
+      if( childWeight > 0 )
+      {
+        int share = static_cast<int>( 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; i<GetChildCount(); ++i )
+
+  // 1st phase:
+  // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
+  // to accumulate total used space in mTotalLength based on measured sizes and margins.
+  // Weighted children are not measured at this phase.
+  // Available space for weighted children will be calculated in the phase 2 based on mTotalLength value.
+  for( unsigned int i = 0; i < GetChildCount(); ++i )
   {
     auto childLayout = GetChildAt( i );
     if( childLayout )
     {
       auto childOwner = childLayout->GetOwner();
       auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
-
-      MeasureChildWithMargins( childLayout, widthMeasureSpec, 0, heightMeasureSpec, 0 );
-      auto childHeight = childLayout->GetMeasuredHeight();
+      auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
+      auto childWeight = childOwner.GetProperty<float>( Toolkit::LinearLayout::ChildProperty::WEIGHT );
       auto childMargin = childLayout->GetMargin();
-      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);
+      totalWeight += childWeight;
+
+      bool useExcessSpace = desiredHeight == 0 && childWeight > 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<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
+      auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
+      auto childWeight = childOwner.GetProperty<float>( Toolkit::LinearLayout::ChildProperty::WEIGHT );
+      auto childMargin = childLayout->GetMargin();
+
+      LayoutLength childHeight = 0;
+      if( childWeight > 0 )
+      {
+        int share = static_cast<int>( 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;
index 23f3184..5f39ad2 100644 (file)
@@ -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;