Fix layout group crash
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / devel-api / layouting / layout-group-impl.cpp
index 844e35a..d9ff6ff 100644 (file)
  */
 
 // CLASS HEADER
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+
+// EXTERNAL INCLUDES
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/object/handle-devel.h>
-#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
 #include <dali-toolkit/internal/layouting/layout-group-data-impl.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
 
-
 namespace
 {
-const char* MARGIN_SPECIFICATION_NAME( "marginSpec" );
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_LAYOUT" );
+#endif
 }
 
 namespace Dali
@@ -44,9 +50,11 @@ LayoutGroup::LayoutGroup()
 
 LayoutGroup::~LayoutGroup()
 {
+  // An object with a unique_ptr to an opaque structure must define it's destructor in the translation unit
+  // where the opaque structure is defined. It cannot use the default method in the header file.
 }
 
-Toolkit::LayoutGroup::LayoutId LayoutGroup::Add( LayoutBase& child )
+Toolkit::LayoutGroup::LayoutId LayoutGroup::Add( LayoutItem& child )
 {
   LayoutParent* oldParent = child.GetParent();
   if( oldParent )
@@ -65,10 +73,10 @@ Toolkit::LayoutGroup::LayoutId LayoutGroup::Add( LayoutBase& child )
 
   auto owner = child.GetOwner();
 
-  // If the owner does not have any LayoutBase child properties, add them
-  if( ! DevelHandle::DoesCustomPropertyExist( owner, Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION ) )
+  // If the owner does not have any LayoutItem child properties, add them
+  if( ! DevelHandle::DoesCustomPropertyExist( owner, Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ) )
   {
-    // Set default properties for LayoutGroup and LayoutBase.
+    // Set default properties for LayoutGroup and LayoutItem.
     // Deriving classes can override OnChildAdd() to add their own default properties
     GenerateDefaultChildPropertyValues( owner );
   }
@@ -98,7 +106,7 @@ void LayoutGroup::Remove( Toolkit::LayoutGroup::LayoutId childId )
   RequestLayout();
 }
 
-void LayoutGroup::Remove( LayoutBase& child )
+void LayoutGroup::Remove( LayoutItem& child )
 {
   for( auto iter = mImpl->mChildren.begin() ; iter != mImpl->mChildren.end() ; ++iter )
   {
@@ -114,7 +122,7 @@ void LayoutGroup::Remove( LayoutBase& child )
 
 void LayoutGroup::RemoveAll()
 {
-  for( auto iter = mImpl->mChildren.begin() ; iter != mImpl->mChildren.end() ; ++iter )
+  for( auto iter = mImpl->mChildren.begin() ; iter != mImpl->mChildren.end() ; )
   {
     OnChildRemove( *iter->child.Get() );
     iter = mImpl->mChildren.erase(iter);
@@ -126,13 +134,13 @@ unsigned int LayoutGroup::GetChildCount() const
   return mImpl->mChildren.size();
 }
 
-LayoutBasePtr LayoutGroup::GetChildAt( unsigned int index ) const
+LayoutItemPtr LayoutGroup::GetChildAt( unsigned int index ) const
 {
   DALI_ASSERT_ALWAYS( index < mImpl->mChildren.size() );
   return mImpl->mChildren[ index ].child;
 }
 
-LayoutBasePtr LayoutGroup::GetChild( Toolkit::LayoutGroup::LayoutId childId ) const
+LayoutItemPtr LayoutGroup::GetChild( Toolkit::LayoutGroup::LayoutId childId ) const
 {
   for( auto&& childLayout : mImpl->mChildren )
   {
@@ -144,7 +152,7 @@ LayoutBasePtr LayoutGroup::GetChild( Toolkit::LayoutGroup::LayoutId childId ) co
   return NULL;
 }
 
-Toolkit::LayoutGroup::LayoutId LayoutGroup::GetChildId( LayoutBase& child ) const
+Toolkit::LayoutGroup::LayoutId LayoutGroup::GetChildId( LayoutItem& child ) const
 {
   for( auto&& childLayout : mImpl->mChildren )
   {
@@ -156,11 +164,11 @@ Toolkit::LayoutGroup::LayoutId LayoutGroup::GetChildId( LayoutBase& child ) cons
   return Toolkit::LayoutGroup::UNKNOWN_ID;
 }
 
-void LayoutGroup::OnChildAdd( LayoutBase& child )
+void LayoutGroup::OnChildAdd( LayoutItem& child )
 {
 }
 
-void LayoutGroup::OnChildRemove( LayoutBase& child )
+void LayoutGroup::OnChildRemove( LayoutItem& child )
 {
 }
 
@@ -174,20 +182,32 @@ void LayoutGroup::DoRegisterChildProperties( const std::string& containerType )
 
 void LayoutGroup::OnSetChildProperties( Handle& handle, Property::Index index, Property::Value value )
 {
-  if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnSetChildProperties\n");
+
+  if ( ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) &&
+         ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
+       ||
+       ( index == Toolkit::Control::Property::MARGIN || index == Toolkit::Control::Property::PADDING ) )
   {
     // If any child properties are set, must perform relayout
     RequestLayout();
+    for( auto&& child : mImpl->mChildren )
+    {
+      if( child.child->GetOwner() == handle )
+      {
+        child.child->SetLayoutRequested();
+        break;
+      }
+    }
   }
 }
 
 void LayoutGroup::GenerateDefaultChildPropertyValues( Handle child )
 {
-  child.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION,
+  child.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION,
                      Toolkit::ChildLayoutData::WRAP_CONTENT );
-  child.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION,
+  child.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,
                      Toolkit::ChildLayoutData::WRAP_CONTENT );
-  child.SetProperty( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION, Extents() );
 }
 
 void LayoutGroup::MeasureChildren( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
@@ -201,15 +221,29 @@ void LayoutGroup::MeasureChildren( MeasureSpec widthMeasureSpec, MeasureSpec hei
   }
 }
 
-void LayoutGroup::MeasureChild( LayoutBasePtr child,
+void LayoutGroup::MeasureChild( LayoutItemPtr child,
                                 MeasureSpec parentWidthMeasureSpec,
                                 MeasureSpec parentHeightMeasureSpec )
 {
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+
   auto childOwner = child->GetOwner();
-  auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION );
-  auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION );
 
-  auto padding = GetPadding();
+  auto control = Toolkit::Control::DownCast( childOwner );
+
+#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 );
+  }
+#endif
+
+  // Get last stored width and height specifications for the child
+  auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
+  auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChild desiredWidth(%d) desiredHeight(%d)\n", desiredWidth, desiredHeight );
+
+  auto padding = GetPadding(); // Padding of this layout's owner, not of the child being measured.
 
   const MeasureSpec childWidthMeasureSpec = GetChildMeasureSpec( parentWidthMeasureSpec,
                                                                  padding.start + padding.end,
@@ -221,24 +255,26 @@ void LayoutGroup::MeasureChild( LayoutBasePtr child,
   child->Measure( childWidthMeasureSpec, childHeightMeasureSpec );
 }
 
-void LayoutGroup::MeasureChildWithMargins( LayoutBasePtr child,
+void LayoutGroup::MeasureChildWithMargins( LayoutItemPtr child,
                                            MeasureSpec parentWidthMeasureSpec, LayoutLength widthUsed,
                                            MeasureSpec parentHeightMeasureSpec, LayoutLength heightUsed)
 {
   auto childOwner = child->GetOwner();
-  auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION );
-  auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION );
-  auto desiredMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
-  auto padding = GetPadding();
+  auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
+  auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
+
+  auto padding = GetPadding(); // Padding of this layout's owner, not of the child being measured.
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChildWithMargins desiredWidth(%d)\n",  desiredWidth );
 
   MeasureSpec childWidthMeasureSpec = GetChildMeasureSpec( parentWidthMeasureSpec,
                                                            padding.start + padding.end +
-                                                           desiredMargin.start + desiredMargin.end +
                                                            widthUsed, desiredWidth );
 
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChildWithMargins desiredHeight(%d)\n",  desiredHeight );
+
   MeasureSpec childHeightMeasureSpec = GetChildMeasureSpec( parentHeightMeasureSpec,
                                                             padding.top + padding.bottom +
-                                                            desiredMargin.top + desiredMargin.end +
                                                             heightUsed, desiredHeight );
 
   child->Measure( childWidthMeasureSpec, childHeightMeasureSpec );
@@ -253,7 +289,7 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec(
   auto specMode = measureSpec.GetMode();
   LayoutLength specSize = measureSpec.GetSize();
 
-  auto size = std::max( LayoutLength(0), specSize - padding );
+  auto size = std::max( LayoutLength(0), specSize - padding ); // reduce available size by the owners padding
 
   MeasureSpec::IntType resultSize = 0;
   MeasureSpec::Mode resultMode = MeasureSpec::Mode::UNSPECIFIED;
@@ -263,15 +299,19 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec(
     // Parent has imposed an exact size on us
     case MeasureSpec::Mode::EXACTLY:
     {
-
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::GetChildMeasureSpec MeasureSpec::Mode::EXACTLY\n");
       if (childDimension == Toolkit::ChildLayoutData::MATCH_PARENT)
       {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::GetChildMeasureSpec childDimension MATCH_PARENT\n");
+
         // Child wants to be our size. So be it.
         resultSize = size;
         resultMode = MeasureSpec::Mode::EXACTLY;
       }
       else if (childDimension == Toolkit::ChildLayoutData::WRAP_CONTENT)
       {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::GetChildMeasureSpec childDimension WRAP_CONTENT\n");
+
         // Child wants to determine its own size. It can't be
         // bigger than us.
         resultSize = size;
@@ -279,6 +319,7 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec(
       }
       else
       {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::GetChildMeasureSpec childDimension UNSPECIFIED\n");
         resultSize = childDimension;
         resultMode = MeasureSpec::Mode::EXACTLY;
       }
@@ -289,6 +330,7 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec(
       // Parent has imposed a maximum size on us
     case MeasureSpec::Mode::AT_MOST:
     {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::GetChildMeasureSpec MeasureSpec::Mode::AT_MOST\n");
       if (childDimension == Toolkit::ChildLayoutData::MATCH_PARENT)
       {
         // Child wants to be our size, but our size is not fixed.
@@ -306,7 +348,7 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec(
       else
       {
         // Child wants a specific size... so be it
-        resultSize = childDimension;
+        resultSize = childDimension + padding;
         resultMode = MeasureSpec::Mode::EXACTLY;
       }
 
@@ -316,29 +358,34 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec(
       // Parent asked to see how big we want to be
     case MeasureSpec::Mode::UNSPECIFIED:
     {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::GetChildMeasureSpec MeasureSpec::Mode::UNSPECIFIED\n");
+
       if (childDimension == Toolkit::ChildLayoutData::MATCH_PARENT)
       {
         // Child wants to be our size... find out how big it should be
-        resultSize = LayoutBase::Impl::sUseZeroUnspecifiedMeasureSpec ? LayoutLength(0) : size;
+        resultSize = LayoutItem::Impl::sUseZeroUnspecifiedMeasureSpec ? LayoutLength(0) : size;
         resultMode = MeasureSpec::Mode::UNSPECIFIED;
       }
       else if (childDimension == Toolkit::ChildLayoutData::WRAP_CONTENT)
       {
         // Child wants to determine its own size.... find out how big
         // it should be
-        resultSize = LayoutBase::Impl::sUseZeroUnspecifiedMeasureSpec ? LayoutLength(0) : size;
+        resultSize = LayoutItem::Impl::sUseZeroUnspecifiedMeasureSpec ? LayoutLength(0) : size;
         resultMode = MeasureSpec::Mode::UNSPECIFIED;
       }
       else
       {
         // Child wants a specific size... let him have it
-        resultSize = childDimension;
+        resultSize = childDimension + padding;
         resultMode = MeasureSpec::Mode::EXACTLY;
       }
       break;
     }
   }
 
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::GetChildMeasureSpec resultSize(%u)\n", resultSize );
+
+
   //noinspection ResourceType
   return MeasureSpec( resultSize, resultMode );
 }
@@ -364,19 +411,6 @@ void LayoutGroup::OnInitialize()
 
 void LayoutGroup::OnRegisterChildProperties( const std::string& containerType )
 {
-  auto typeInfo = TypeRegistry::Get().GetTypeInfo( containerType );
-  if( typeInfo )
-  {
-    Property::IndexContainer indices;
-    typeInfo.GetChildPropertyIndices( indices );
-
-    if( std::find( indices.Begin(), indices.End(), Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION ) ==
-        indices.End() )
-    {
-      ChildPropertyRegistration( typeInfo.GetName(), MARGIN_SPECIFICATION_NAME, Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION, Property::EXTENTS );
-    }
-  }
-
   DoRegisterChildProperties( containerType );
 }
 
@@ -387,8 +421,9 @@ void LayoutGroup::OnUnparent()
 
 void LayoutGroup::ChildAddedToOwner( Actor child )
 {
-  LayoutBasePtr childLayout;
+  LayoutItemPtr childLayout;
   Toolkit::Control control = Toolkit::Control::DownCast( child );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner(%s)\n", control.GetName().c_str() );
 
   if( control ) // Can only support adding Controls, not Actors to layout
   {
@@ -398,17 +433,16 @@ void LayoutGroup::ChildAddedToOwner( Actor child )
 
     if( ! childLayout )
     {
-      // If the child doesn't already have a layout, then create a LayoutBase for it.
-      childLayout = LayoutBase::New( control );
+      // If the child doesn't already have a layout, then create a LayoutItem for it.
+      childLayout = LayoutItem::New( control );
       childLayout->SetAnimateLayout( IsLayoutAnimated() ); // @todo this essentially forces animation inheritance. Bad?
-
+#if defined(DEBUG_ENABLED)
       auto desiredSize = control.GetNaturalSize();
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner desiredSize(%f,%f) (naturalSize)\n", desiredSize.width, desiredSize.height );
+#endif
       childControlDataImpl.SetLayout( *childLayout.Get() );
 
-      // HBoxLayout will apply default layout data for this object
-      child.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, LayoutLength::IntType( desiredSize.width ) );
-      child.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, LayoutLength::IntType( desiredSize.height ) );
-      child.SetProperty( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION, Extents() );
+      // Default layout data will be generated by Add().
     }
 
     Add( *childLayout.Get() );
@@ -432,14 +466,20 @@ void LayoutGroup::ChildRemovedFromOwner( Actor child )
 
 void LayoutGroup::OnOwnerPropertySet( Handle& handle, Property::Index index, Property::Value value )
 {
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutGroup::OnOwnerPropertySet\n");
   auto actor = Actor::DownCast( handle );
-  if( actor && index == Actor::Property::LAYOUT_DIRECTION )
+  if( actor &&
+      (
+        index == Actor::Property::LAYOUT_DIRECTION  ||
+        index == Toolkit::Control::Property::PADDING  ||
+        index == Toolkit::Control::Property::MARGIN
+      )
+    )
   {
     RequestLayout();
   }
 }
 
-
 } // namespace Internal
 } // namespace Toolkit
 } // namespace Dali