Controls are LayoutGroups instead of LayoutItems 93/187193/11
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Mon, 20 Aug 2018 16:28:20 +0000 (17:28 +0100)
committerAgnelo Vaz <agnelo.vaz@samsung.com>
Thu, 23 Aug 2018 18:50:54 +0000 (19:50 +0100)
LayoutGroup measures and layouts it's children.
Children are currently positioned by their AnchorPoint and Position.
Children are not positioned in relation to each other so may overlap.

Change-Id: I786736a13f5f0b00c15fec461b5a20883da9f346

automated-tests/src/dali-toolkit/utc-Dali-Layouting.cpp
dali-toolkit/devel-api/layouting/layout-group-impl.cpp
dali-toolkit/devel-api/layouting/layout-group-impl.h
dali-toolkit/devel-api/layouting/layout-group.cpp
dali-toolkit/devel-api/layouting/layout-group.h
dali-toolkit/devel-api/layouting/layout-item-impl.cpp
dali-toolkit/internal/layouting/absolute-layout-impl.cpp
dali-toolkit/internal/layouting/layout-controller-impl.cpp

index 29e3726..8fabd35 100644 (file)
@@ -35,6 +35,9 @@
 using namespace Dali;
 using namespace Toolkit;
 
 using namespace Dali;
 using namespace Toolkit;
 
+namespace
+{
+
 void TestLayoutItemOrder( std::vector< Control >& controls, LayoutGroup& layoutGroup )
 {
   for( auto&& iter : controls )
 void TestLayoutItemOrder( std::vector< Control >& controls, LayoutGroup& layoutGroup )
 {
   for( auto&& iter : controls )
@@ -44,6 +47,19 @@ void TestLayoutItemOrder( std::vector< Control >& controls, LayoutGroup& layoutG
   }
 }
 
   }
 }
 
+// Turns the given control into a Root layout control and adds it to the stage.
+void SetupRootLayoutControl( Control& rootControl )
+{
+  rootControl = Control::New();
+  auto absoluteLayout = AbsoluteLayout::New();
+  DevelControl::SetLayout( rootControl, absoluteLayout );
+  rootControl.SetName( "RootAbsoluteLayout" );
+  Stage stage = Stage::GetCurrent();
+  stage.Add( rootControl );
+}
+
+} // unnamed namespace
+
 void utc_dali_toolkit_layouting_startup(void)
 {
   test_return_value = TET_UNDEF;
 void utc_dali_toolkit_layouting_startup(void)
 {
   test_return_value = TET_UNDEF;
@@ -623,6 +639,7 @@ int UtcDaliLayouting_HboxLayout08(void)
 
   Control control1 = CreateLeafControl( 40, 40 );
   rootControl.Add( control1 );
 
   Control control1 = CreateLeafControl( 40, 40 );
   rootControl.Add( control1 );
+
   auto hbox = Control::New();
   auto hboxLayout = LinearLayout::New();
   hboxLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL );
   auto hbox = Control::New();
   auto hboxLayout = LinearLayout::New();
   hboxLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL );
@@ -641,7 +658,9 @@ int UtcDaliLayouting_HboxLayout08(void)
   DALI_TEST_EQUALS( hboxLayout.IsLayoutAnimated(), false, TEST_LOCATION );
   DALI_TEST_EQUALS( DevelControl::GetLayout( control2 ).IsLayoutAnimated(), false, TEST_LOCATION );
 
   DALI_TEST_EQUALS( hboxLayout.IsLayoutAnimated(), false, TEST_LOCATION );
   DALI_TEST_EQUALS( DevelControl::GetLayout( control2 ).IsLayoutAnimated(), false, TEST_LOCATION );
 
+  tet_infoline(" Set hBoxLayout to animate");
   hboxLayout.SetAnimateLayout( true );
   hboxLayout.SetAnimateLayout( true );
+  tet_infoline(" Set absoluteLayout not to animate");
   absoluteLayout.SetAnimateLayout( false );
 
   DALI_TEST_EQUALS( absoluteLayout.IsLayoutAnimated(), false, TEST_LOCATION );
   absoluteLayout.SetAnimateLayout( false );
 
   DALI_TEST_EQUALS( absoluteLayout.IsLayoutAnimated(), false, TEST_LOCATION );
@@ -2028,3 +2047,235 @@ int UtcDaliLayouting_SetLayoutOrder02(void)
 
   END_TEST;
 }
 
   END_TEST;
 }
+
+int UtcDaliLayouting_LayoutGroup01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliLayouting_LayoutGroup01 - Test adding a control to a layout then adding a TextLabel to that control");
+
+  Control rootControl;
+  SetupRootLayoutControl( rootControl );
+
+  // Create a parent layout
+  auto hbox = Control::New();
+  auto hboxLayout = LinearLayout::New();
+  hbox.SetName( "HBox");
+  rootControl.Add( hbox );
+  DevelControl::SetLayout( hbox, hboxLayout );
+  hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+  hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+  hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT );  // LinearLayout will eventually do this internally.
+
+  tet_infoline("Add a control without SetLayout being called");
+
+  auto control = Control::New();
+  control.SetName("Control1");
+  hbox.Add( control );
+  control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+  control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+
+  tet_infoline("Add a Textlabel to the control");
+  auto textLabel = TextLabel::New("Test text");
+  textLabel.SetName("TextLabel");
+  control.Add( textLabel );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Test text is it's natural size");
+  DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 230.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  tet_infoline("Test control is width of it's parent and height of it's child");
+  DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 600.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliLayouting_LayoutGroup02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliLayouting_LayoutGroup02 - Test control is the size of it's largest child");
+
+  Control rootControl;
+  SetupRootLayoutControl( rootControl );
+
+  // Create a parent layout
+  auto hbox = Control::New();
+  auto hboxLayout = LinearLayout::New();
+  hbox.SetName( "HBox");
+  rootControl.Add( hbox );
+  DevelControl::SetLayout( hbox, hboxLayout );
+  hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+  hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+  hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT );  // LinearLayout will eventually do this internally.
+
+  tet_infoline("Add a control without SetLayout being called");
+
+  auto control = Control::New();
+  control.SetName("Control1");
+  hbox.Add( control );
+  control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+
+  tet_infoline("Add a Textlabel to the control");
+  auto textLabel = TextLabel::New("Test text");
+  textLabel.SetName("TextLabel");
+  control.Add( textLabel );
+
+  tet_infoline("Add another  Textlabel to the control");
+  auto largeTextLabel = TextLabel::New("Test large text");
+  largeTextLabel.SetName("TextLabel-Large");
+  control.Add( largeTextLabel );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Test text is it's natural size");
+  DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 230.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  tet_infoline("Test text is centered in the control, the control is the size of the largest child");
+  DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  tet_infoline("Test large text is it's natural size");
+  DALI_TEST_EQUALS( largeTextLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 382.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  tet_infoline("Test text is aligned to start as is the size of the control");
+  DALI_TEST_EQUALS( largeTextLabel.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  tet_infoline("Test control is width of it's parent and height of it's largest child");
+  DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 382.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliLayouting_LayoutGroup03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliLayouting_LayoutGroup03 - Test control witha LayoutGroup as a leaf");
+
+  Control rootControl;
+  SetupRootLayoutControl( rootControl );
+
+  // Create a parent layout
+  auto hbox = Control::New();
+  auto hboxLayout = LinearLayout::New();
+  hbox.SetName( "HBox");
+  rootControl.Add( hbox );
+  DevelControl::SetLayout( hbox, hboxLayout );
+  hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+  hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+  hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT );  // LinearLayout will eventually do this internally.
+
+  tet_infoline("Add a control without SetLayout being called");
+
+  auto control = Control::New();
+  control.SetName("Control1");
+  hbox.Add( control );
+  control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+  control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  100 );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Test control is width of it's parent and exact given height");
+  DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 600.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliLayouting_LayoutGroupWithPadding01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliLayouting_LayoutGroupWithPadding01 - Test adding a control to a layout that has padding");
+
+  Control rootControl;
+  SetupRootLayoutControl( rootControl );
+
+  // Create a parent layout
+  auto hbox = Control::New();
+  auto hboxLayout = LinearLayout::New();
+  hbox.SetName( "HBox");
+  rootControl.Add( hbox );
+  DevelControl::SetLayout( hbox, hboxLayout );
+  hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+  hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+  hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT );  // LinearLayout will eventually do this internally.
+
+  tet_infoline("Add a control without SetLayout being called");
+
+  auto control = Control::New();
+  control.SetName("Control1");
+  hbox.Add( control );
+  control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+
+  const Extents CONTROL_PADDING = Extents(5, 10, 20, 2 );
+  tet_printf( "Adding Padding to control");
+  control.SetProperty( Toolkit::Control::Property::PADDING, CONTROL_PADDING );
+
+  tet_infoline("Add a Textlabel to the control");
+  auto textLabel = TextLabel::New("Test text");
+  textLabel.SetName("TextLabel");
+  control.Add( textLabel );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Test text is it's natural size");
+  DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 230.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  tet_infoline("Test control is size of it's child and control it's own padding");
+  DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 245.0f, 86.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliLayouting_LayoutGroupWithChildMargin01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliLayouting_LayoutGroupWithChildMargin01 - Test adding a control with padding to a layout that has padding");
+
+  Control rootControl;
+  SetupRootLayoutControl( rootControl );
+
+  // Create a parent layout
+  auto hbox = Control::New();
+  auto hboxLayout = LinearLayout::New();
+  hbox.SetName( "HBox");
+  rootControl.Add( hbox );
+  DevelControl::SetLayout( hbox, hboxLayout );
+  hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+  hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+  hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT );  // LinearLayout will eventually do this internally.
+
+  tet_infoline("Add a control without SetLayout being called");
+
+  auto control = Control::New();
+  control.SetName("Control1");
+  hbox.Add( control );
+  control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+
+  const Extents CONTROL_PADDING = Extents(5, 10, 20, 2 );
+  tet_printf( "Adding Padding to control");
+  control.SetProperty( Toolkit::Control::Property::PADDING, CONTROL_PADDING );
+
+  tet_infoline("Add a Textlabel to the control");
+  auto textLabel = TextLabel::New("Test text");
+  const Extents CHILD_MARGIN = Extents( 10, 0, 5, 0 );
+  textLabel.SetProperty( Toolkit::Control::Property::MARGIN, CHILD_MARGIN );
+  textLabel.SetName("TextLabel");
+  control.Add( textLabel );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Test text is it's natural size");
+  DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 230.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  tet_infoline("Test control is width of it's parent and height of it's child");
+  DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 255.0f, 91.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
\ No newline at end of file
index 69d268d..9f54f56 100644 (file)
@@ -48,6 +48,12 @@ LayoutGroup::LayoutGroup()
 {
 }
 
 {
 }
 
+LayoutGroupPtr LayoutGroup::New( Handle& owner )
+{
+  LayoutGroupPtr layoutPtr = new LayoutGroup();
+  return layoutPtr;
+}
+
 LayoutGroup::~LayoutGroup()
 {
   // An object with a unique_ptr to an opaque structure must define it's destructor in the translation unit
 LayoutGroup::~LayoutGroup()
 {
   // An object with a unique_ptr to an opaque structure must define it's destructor in the translation unit
@@ -333,7 +339,8 @@ void LayoutGroup::MeasureChild( LayoutItemPtr child,
 #if defined( DEBUG_ENABLED )
   if ( control )
   {
 #if defined( DEBUG_ENABLED )
   if ( control )
   {
-    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChild natural size(%f, %f)\n",  control.GetNaturalSize().width, control.GetNaturalSize().height );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChild(%s) natural size(%f, %f)\n",
+                   control.GetName().c_str(), control.GetNaturalSize().width, control.GetNaturalSize().height );
   }
 #endif
 
   }
 #endif
 
@@ -568,7 +575,10 @@ void LayoutGroup::ChildAddedToOwner( Actor child )
   LayoutItemPtr childLayout;
   Toolkit::Control control = Toolkit::Control::DownCast( child );
 
   LayoutItemPtr childLayout;
   Toolkit::Control control = Toolkit::Control::DownCast( child );
 
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner control(%s)\n", control?control.GetName().c_str():"Invalid" );
+#if defined(DEBUG_ENABLED)
+  auto parent = Toolkit::Control::DownCast( GetOwner() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner control(%s) owner(%s)\n", control?control.GetName().c_str():"Invalid", parent?parent.GetName().c_str():"Invalid" );
+#endif
 
   if( control ) // Can only support adding Controls, not Actors to layout
   {
 
   if( control ) // Can only support adding Controls, not Actors to layout
   {
@@ -579,7 +589,7 @@ void LayoutGroup::ChildAddedToOwner( Actor child )
     if( ! childLayout )
     {
       // If the child doesn't already have a layout, then create a LayoutItem for it.
     if( ! childLayout )
     {
       // If the child doesn't already have a layout, then create a LayoutItem for it.
-      childLayout = LayoutItem::New( control );
+      childLayout = LayoutGroup::New( control );
       childLayout->SetAnimateLayout( IsLayoutAnimated() ); // @todo this essentially forces animation inheritance. Bad?
 #if defined(DEBUG_ENABLED)
       auto desiredSize = control.GetNaturalSize();
       childLayout->SetAnimateLayout( IsLayoutAnimated() ); // @todo this essentially forces animation inheritance. Bad?
 #if defined(DEBUG_ENABLED)
       auto desiredSize = control.GetNaturalSize();
@@ -688,7 +698,7 @@ void LayoutGroup::OnAnimationStateChanged( bool animateLayout )
   for( auto&& child : mImpl->mChildren )
   {
     LayoutGroupPtr parentGroup( dynamic_cast< LayoutGroup* >( child.child.Get() ) );
   for( auto&& child : mImpl->mChildren )
   {
     LayoutGroupPtr parentGroup( dynamic_cast< LayoutGroup* >( child.child.Get() ) );
-    if( !parentGroup )
+    if( parentGroup && ( 0 == parentGroup->GetChildCount() ) ) // A leaf LayoutGroup will have no children.
     {
       // Change state only in case of leaf children
       child.child->SetAnimateLayout( animateLayout );
     {
       // Change state only in case of leaf children
       child.child->SetAnimateLayout( animateLayout );
@@ -696,6 +706,146 @@ void LayoutGroup::OnAnimationStateChanged( bool animateLayout )
   }
 }
 
   }
 }
 
+void LayoutGroup::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
+{
+  DALI_LOG_STREAM( gLogFilter, Debug::Verbose,
+                  "LayoutGroup::OnMeasure Actor Id:" <<  Actor::DownCast(GetOwner()).GetId() <<
+                  " Owner:" <<  Actor::DownCast(GetOwner()).GetName() <<
+                  " MeasureSpecs( width:"<<widthMeasureSpec<<", height:"<<heightMeasureSpec );
+
+  auto childCount = GetChildCount();
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure child count(%u)\n", childCount);
+
+  auto widthMode = widthMeasureSpec.GetMode();
+  auto heightMode = heightMeasureSpec.GetMode();
+  LayoutLength widthSpecSize = widthMeasureSpec.GetSize();
+  LayoutLength heightSpecSize = heightMeasureSpec.GetSize();
+
+  bool exactWidth ( false );
+  bool exactHeight ( false );
+
+  // Default Layouting behaviour if not overridden
+  // EXACT, width and height as provided.
+  // MATCH_PARENT, width and hewidthSpecSizeight that of parent
+
+  // WRAP_CONTENT, take width of widest child and height size of longest child (within given limit)
+  // UNSPECIFIED, take width of widest child and height size of longest child.
+
+  LayoutLength layoutWidth( 0 );
+  LayoutLength layoutHeight( 0 );
+
+  // If LayoutGroup has children then measure children to get max dimensions
+  if ( childCount > 0 )
+  {
+    for( unsigned int i=0; i<childCount; ++i )
+    {
+      auto childLayout = GetChildAt( i );
+      if( childLayout )
+      {
+        auto childOwner = childLayout->GetOwner();
+
+        // Get size of child
+        MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec );
+        auto childWidth = childLayout->GetMeasuredWidth();
+        auto childHeight = childLayout->GetMeasuredHeight();
+        auto childMargin = childLayout->GetMargin();
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure child width[%d] height(%d)\n", childWidth.mValue, childHeight.mValue );
+
+        layoutWidth = std::max( layoutWidth, childWidth + childMargin.start + childMargin.end );
+        layoutHeight = std::max( layoutHeight, childHeight + childMargin.top + childMargin.bottom );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure calculated child width[%d] calculated height(%d)\n", layoutWidth.mValue, layoutHeight.mValue );
+      }
+    }
+
+    Extents padding = GetPadding();
+    layoutWidth += padding.start + padding.end;
+    layoutHeight += padding.top + padding.bottom;
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure Getting default size as a leaf\n" );
+    // LayoutGroup does not contain any children so must be a leaf
+    layoutWidth = GetDefaultSize( GetSuggestedMinimumWidth(), widthMeasureSpec );
+    layoutHeight = GetDefaultSize( GetSuggestedMinimumHeight(), heightMeasureSpec );
+  }
+
+  // Can't exceed specified width
+  if( widthMode == MeasureSpec::Mode::EXACTLY )
+  {
+    exactWidth = true;
+  }
+  else if ( widthMode == MeasureSpec::Mode::AT_MOST )
+  {
+    layoutWidth = std::min( layoutWidth, widthSpecSize );
+  }
+
+  // Can't exceed specified height
+  if( heightMode == MeasureSpec::Mode::EXACTLY )
+  {
+    exactHeight = true;
+  }
+  else if ( heightMode == MeasureSpec::Mode::AT_MOST )
+  {
+    layoutHeight = std::min( layoutHeight, heightSpecSize );
+  }
+
+  layoutWidth = std::max( layoutWidth, GetSuggestedMinimumWidth() );
+  layoutHeight = std::max( layoutHeight, GetSuggestedMinimumHeight() );
+
+  if( exactWidth )
+  {
+    layoutWidth = widthSpecSize;
+  }
+
+  if( exactHeight )
+  {
+    layoutHeight = heightSpecSize;
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure Measured size(%d,%d) for : %s \n", layoutWidth.mValue, layoutHeight.mValue, Actor::DownCast(GetOwner()).GetName().c_str() );
+  SetMeasuredDimensions( MeasuredSize( layoutWidth ), MeasuredSize( layoutHeight ) );
+}
+
+void LayoutGroup::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnLayout\n");
+
+  auto count = GetChildCount();
+
+  for( unsigned int childIndex = 0; childIndex < count; childIndex++)
+  {
+    LayoutItemPtr childLayout = GetChildAt( childIndex );
+    if( childLayout != nullptr )
+    {
+
+      auto childOwner = childLayout->GetOwner();
+      auto childWidth = childLayout->GetMeasuredWidth();
+      auto childHeight = childLayout->GetMeasuredHeight();
+      auto childMargin = childLayout->GetMargin();
+      auto control = Toolkit::Control::DownCast( childOwner );
+      Extents padding = GetPadding();
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnLayout child width[%d] height(%d)\n", childWidth.mValue, childHeight.mValue );
+
+      auto childPosition = control.GetProperty< Vector3 >( Actor::Property::POSITION );
+      auto anchorPoint = control.GetProperty< Vector3 >( Actor::Property::ANCHOR_POINT );
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnLayout child[%s] position(%f,%f)\n", control.GetName().c_str(), childPosition.x, childPosition.y );
+
+      // Margin and Padding only supported when child anchor point is TOP_LEFT.
+      int paddingAndMarginOffsetX = ( AnchorPoint::TOP_LEFT == anchorPoint ) ? ( padding.top + childMargin.top ) : 0;
+      int paddingAndMarginOffsetY = ( AnchorPoint::TOP_LEFT == anchorPoint ) ? ( padding.start + childMargin.start ) : 0;
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnLayout paddingMargin offset(%d,%d)\n", paddingAndMarginOffsetX, paddingAndMarginOffsetY );
+
+      LayoutLength childLeft = childPosition.x + paddingAndMarginOffsetX;
+      LayoutLength childTop = childPosition.y + paddingAndMarginOffsetY;
+
+      childLayout->Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
+    }
+  }
+}
+
+
 } // namespace Internal
 } // namespace Toolkit
 } // namespace Dali
 } // namespace Internal
 } // namespace Toolkit
 } // namespace Dali
index 3039125..ee73c88 100644 (file)
@@ -65,6 +65,14 @@ public:
    */
   LayoutGroup();
 
    */
   LayoutGroup();
 
+  /**
+   * @brief Construct
+   *
+   * @param[in] owner The owner (container view / child view / visual ) of this layout
+   * @return a new LayoutGroup object
+   */
+  static LayoutGroupPtr New( Handle& owner );
+
 protected:
   /**
    * Virtual destructor may only be called by Unreference()
 protected:
   /**
    * Virtual destructor may only be called by Unreference()
@@ -248,6 +256,15 @@ protected:
                                         LayoutLength widthUsed,
                                         MeasureSpec parentHeightMeasureSpec,
                                         LayoutLength heightUsed );
                                         LayoutLength widthUsed,
                                         MeasureSpec parentHeightMeasureSpec,
                                         LayoutLength heightUsed );
+  /**
+   * @copydoc LayoutItem::OnMeasure
+   */
+  virtual void OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec ) override;
+
+  /**
+   * @copydoc LayoutItem::OnLayout
+   */
+  virtual void OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom ) override;
 
 private:
   /**
 
 private:
   /**
index b13da31..50ed913 100644 (file)
@@ -27,6 +27,12 @@ LayoutGroup::LayoutGroup()
 {
 }
 
 {
 }
 
+LayoutGroup LayoutGroup::New( Handle& handle )
+{
+  Internal::LayoutGroupPtr layout = Internal::LayoutGroup::New( handle );
+  return LayoutGroup( layout.Get() );
+}
+
 LayoutGroup LayoutGroup::DownCast( BaseHandle handle )
 {
   return LayoutGroup( dynamic_cast< Dali::Toolkit::Internal::LayoutGroup* >( handle.GetObjectPtr() ) );
 LayoutGroup LayoutGroup::DownCast( BaseHandle handle )
 {
   return LayoutGroup( dynamic_cast< Dali::Toolkit::Internal::LayoutGroup* >( handle.GetObjectPtr() ) );
index 1d9ad5d..9d0e684 100644 (file)
@@ -80,6 +80,13 @@ public:
   ~LayoutGroup() = default;
 
   /**
   ~LayoutGroup() = default;
 
   /**
+   * @brief Create an initialized LayoutGroup
+   *
+   * @param[in] handle A handle to the object that this layout for, e.g. a Control or a Visual::Base
+   */
+  static LayoutGroup New( Handle& handle );
+
+  /**
    * @brief Copy constructor
    */
   LayoutGroup(const LayoutGroup& copy) = default;
    * @brief Copy constructor
    */
   LayoutGroup(const LayoutGroup& copy) = default;
index a0350e3..ecf86b3 100644 (file)
@@ -95,6 +95,16 @@ void LayoutItem::Unparent()
 
 void LayoutItem::SetAnimateLayout( bool animateLayout )
 {
 
 void LayoutItem::SetAnimateLayout( bool animateLayout )
 {
+  DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetAnimateLayout animateLayout(%s)\n", (animateLayout)?"true":"false" );
+
+  auto owner = GetOwner();
+  auto actor = Actor::DownCast(owner);
+
+  if( actor )
+  {
+      DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetAnimateLayout animateLayout(%s) owner(%s)\n", (animateLayout)?"true":"false", actor.GetName().c_str() );
+  }
+
   mImpl->mAnimated = animateLayout;
 
   OnAnimationStateChanged( animateLayout );
   mImpl->mAnimated = animateLayout;
 
   OnAnimationStateChanged( animateLayout );
@@ -170,7 +180,7 @@ void LayoutItem::Measure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasur
 
     // flag not set, setMeasuredDimension() was not invoked, we raise an exception to warn the developer
     DALI_ASSERT_ALWAYS( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET ) &&
 
     // flag not set, setMeasuredDimension() was not invoked, we raise an exception to warn the developer
     DALI_ASSERT_ALWAYS( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET ) &&
-                        "Layout's OnMeasure() did not set the measured dimension by calling setMeasuredDimension()" );
+                        "Layout's OnMeasure() mension()" );
     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
   }
 
     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
   }
 
@@ -180,6 +190,8 @@ void LayoutItem::Measure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasur
 
 void LayoutItem::Layout( LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b )
 {
 
 void LayoutItem::Layout( LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b )
 {
+  DALI_LOG_TRACE_METHOD( gLayoutFilter );
+
   if( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT ) )
   {
     OnMeasure( mImpl->mOldWidthMeasureSpec, mImpl->mOldHeightMeasureSpec );
   if( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT ) )
   {
     OnMeasure( mImpl->mOldWidthMeasureSpec, mImpl->mOldHeightMeasureSpec );
@@ -227,7 +239,7 @@ Extents LayoutItem::GetPadding() const
   {
     Extents padding = control.GetProperty<Extents>( Toolkit::Control::Property::PADDING );
 
   {
     Extents padding = control.GetProperty<Extents>( Toolkit::Control::Property::PADDING );
 
-    DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutBase::Padding for %s : (%d,%d,%d,%d) \n",
+    DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::Padding for %s : (%d,%d,%d,%d) \n",
                    control.GetName().c_str(),
                    padding.start, padding.end, padding.top, padding.bottom
                  );
                    control.GetName().c_str(),
                    padding.start, padding.end, padding.top, padding.bottom
                  );
@@ -289,6 +301,8 @@ LayoutLength LayoutItem::GetDefaultSize( LayoutLength size, MeasureSpec measureS
 
 void LayoutItem::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
 {
 
 void LayoutItem::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
 {
+  DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::OnMeasure\n");
+
   SetMeasuredDimensions( GetDefaultSize( GetSuggestedMinimumWidth(), widthMeasureSpec ),
                          GetDefaultSize( GetSuggestedMinimumHeight(), heightMeasureSpec ) );
 }
   SetMeasuredDimensions( GetDefaultSize( GetSuggestedMinimumWidth(), widthMeasureSpec ),
                          GetDefaultSize( GetSuggestedMinimumHeight(), heightMeasureSpec ) );
 }
@@ -332,7 +346,7 @@ void LayoutItem::SetLayoutRequested()
 
 void LayoutItem::SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight )
 {
 
 void LayoutItem::SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight )
 {
-  DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutBase::SetMeasuredDimensions width(%d) height(%d) \n",
+  DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetMeasuredDimensions width(%d) height(%d) \n",
                                                  MeasureSpec::IntType( measuredWidth.GetSize() ),
                                                  MeasureSpec::IntType( measuredHeight.GetSize() )
                );
                                                  MeasureSpec::IntType( measuredWidth.GetSize() ),
                                                  MeasureSpec::IntType( measuredHeight.GetSize() )
                );
@@ -450,6 +464,8 @@ bool LayoutItem::SetFrame( LayoutLength left, LayoutLength top, LayoutLength rig
     auto actor = Actor::DownCast(owner);
     if( actor )
     {
     auto actor = Actor::DownCast(owner);
     if( actor )
     {
+      DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame owner(%s) (%d, %d, %d, %d)\n",  actor.GetName().c_str(),
+                                    left.mValue, top.mValue, right.mValue, bottom.mValue );
       if( mImpl->mAnimated )
       {
         auto animation = Animation::New( 0.5f );
       if( mImpl->mAnimated )
       {
         auto animation = Animation::New( 0.5f );
index 3f499ef..14fed57 100644 (file)
@@ -106,7 +106,7 @@ void AbsoluteLayout::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec height
       // Store current width and height needed to contain all children.
       totalWidth = maxPosition.x - minPosition.x;
       totalHeight = maxPosition.y - minPosition.y;
       // Store current width and height needed to contain all children.
       totalWidth = maxPosition.x - minPosition.x;
       totalHeight = maxPosition.y - minPosition.y;
-      DALI_LOG_INFO( gLogFilter, Debug::Concise, "AbsoluteLayout::OnMeasure child width(%f) height(%f) \n", (float)totalWidth, (float)totalHeight  );
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AbsoluteLayout::OnMeasure child width(%f) height(%f) \n", (float)totalWidth, (float)totalHeight  );
 
       if( childLayout->GetMeasuredWidthAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
       {
 
       if( childLayout->GetMeasuredWidthAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
       {
@@ -141,6 +141,7 @@ void AbsoluteLayout::OnLayout( bool changed, LayoutLength left, LayoutLength top
   // Absolute layout positions it's children at their Actor positions.
   // Children could overlap or spill outside the parent, as is the nature of absolute positions.
   auto count = GetChildCount();
   // Absolute layout positions it's children at their Actor positions.
   // Children could overlap or spill outside the parent, as is the nature of absolute positions.
   auto count = GetChildCount();
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "AbsoluteLayout::OnLayout child count(%d)\n", count  );
 
   for( unsigned int i = 0; i < count; i++)
   {
 
   for( unsigned int i = 0; i < count; i++)
   {
index 1f12c3f..0e8d925 100644 (file)
@@ -110,7 +110,7 @@ void LayoutController::MeasureHierarchy( Actor root, MeasureSpec widthSpec, Meas
   Toolkit::Control control = Toolkit::Control::DownCast( root );
   if( control )
   {
   Toolkit::Control control = Toolkit::Control::DownCast( root );
   if( control )
   {
-    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::Measuring leaf\n" );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::Measuring control\n" );
     Internal::Control& controlImpl = GetImplementation( control );
 
     Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
     Internal::Control& controlImpl = GetImplementation( control );
 
     Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
@@ -138,7 +138,7 @@ void LayoutController::PerformLayout( Actor root, int left, int top, int right,
   Toolkit::Control control = Toolkit::Control::DownCast( root );
   if( control )
   {
   Toolkit::Control control = Toolkit::Control::DownCast( root );
   if( control )
   {
-    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayout on leaf\n" );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayout on control[%s]\n", control.GetName().c_str() );
     Internal::Control& controlImpl = GetImplementation( control );
     Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
     LayoutItemPtr layout = controlDataImpl.GetLayout();
     Internal::Control& controlImpl = GetImplementation( control );
     Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
     LayoutItemPtr layout = controlDataImpl.GetLayout();