X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Fdevel-api%2Flayouting%2Flayout-group-impl.cpp;h=a27f060b40fa76e6cc7c73b9324fec5ef08230bb;hb=34bb584d815970cb12b0678cf68915338800ebb4;hp=21fb3910a12e7c43a9384b11bbcf6329ffa500d9;hpb=20b42a9bcaba6b874f2271f03a56da6f884c4053;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/devel-api/layouting/layout-group-impl.cpp b/dali-toolkit/devel-api/layouting/layout-group-impl.cpp index 21fb391..a27f060 100644 --- a/dali-toolkit/devel-api/layouting/layout-group-impl.cpp +++ b/dali-toolkit/devel-api/layouting/layout-group-impl.cpp @@ -15,18 +15,25 @@ */ // CLASS HEADER +#include + +// EXTERNAL INCLUDES #include #include #include -#include +#include + +// INTERNAL INCLUDES #include #include #include - +#include namespace { -const char* MARGIN_SPECIFICATION_NAME( "marginSpec" ); +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_LAYOUT" ); +#endif } namespace Dali @@ -42,10 +49,17 @@ 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 // where the opaque structure is defined. It cannot use the default method in the header file. + RemoveAll(); } Toolkit::LayoutGroup::LayoutId LayoutGroup::Add( LayoutItem& child ) @@ -65,6 +79,8 @@ Toolkit::LayoutGroup::LayoutId LayoutGroup::Add( LayoutItem& child ) childLayout.child = &child; mImpl->mChildren.emplace_back( childLayout ); + child.SetParent( this ); + auto owner = child.GetOwner(); // If the owner does not have any LayoutItem child properties, add them @@ -92,7 +108,7 @@ void LayoutGroup::Remove( Toolkit::LayoutGroup::LayoutId childId ) { if( iter->layoutId == childId ) { - OnChildRemove( *iter->child.Get() ); + RemoveChild( *iter->child.Get() ); mImpl->mChildren.erase(iter); break; } @@ -106,7 +122,7 @@ void LayoutGroup::Remove( LayoutItem& child ) { if( iter->child.Get() == &child ) { - OnChildRemove( *iter->child.Get() ); + RemoveChild( *iter->child.Get() ); mImpl->mChildren.erase(iter); break; } @@ -114,11 +130,54 @@ void LayoutGroup::Remove( LayoutItem& child ) RequestLayout(); } +Toolkit::LayoutGroup::LayoutId LayoutGroup::Insert( LayoutItem& target, LayoutItem& child ) +{ + LayoutParent* oldParent = child.GetParent(); + if( oldParent ) + { + LayoutGroupPtr parentGroup( dynamic_cast< LayoutGroup* >( oldParent ) ); + if( parentGroup ) + { + parentGroup->Remove( child ); + } + } + + // Find target position + std::vector< Impl::ChildLayout >::iterator position; + for( auto iter = mImpl->mChildren.begin(); iter != mImpl->mChildren.end(); ++iter ) + { + if( iter->child.Get() == &target ) + { + position = iter; + break; + } + } + + Impl::ChildLayout childLayout; + childLayout.layoutId = mImpl->mNextLayoutId++; + childLayout.child = &child; + mImpl->mChildren.insert( position, childLayout ); + + child.SetParent( this ); + + auto owner = child.GetOwner(); + + // Inform deriving classes that this child has been added + OnChildAdd( *childLayout.child.Get() ); + + // Now listen to future changes to the child properties. + DevelHandle::PropertySetSignal(owner).Connect( this, &LayoutGroup::OnSetChildProperties ); + + RequestLayout(); + + return childLayout.layoutId; +} + 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() ); + RemoveChild( *iter->child.Get() ); iter = mImpl->mChildren.erase(iter); } } @@ -176,10 +235,22 @@ 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_STREAM( gLogFilter, Debug::Verbose, "LayoutGroup::OnSetChildProperties property(" << handle.GetPropertyName(index) << ")\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->RequestLayout(); + break; + } + } } } @@ -189,7 +260,6 @@ void LayoutGroup::GenerateDefaultChildPropertyValues( Handle child ) Toolkit::ChildLayoutData::WRAP_CONTENT ); 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) @@ -207,11 +277,27 @@ void LayoutGroup::MeasureChild( LayoutItemPtr child, MeasureSpec parentWidthMeasureSpec, MeasureSpec parentHeightMeasureSpec ) { + DALI_LOG_TRACE_METHOD( gLogFilter ); + auto childOwner = child->GetOwner(); + + auto control = Toolkit::Control::DownCast( childOwner ); + +#if defined( DEBUG_ENABLED ) + if ( control ) + { + 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 + + + // Get last stored width and height specifications for the child auto desiredWidth = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ); auto desiredHeight = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChild desiredWidth(%d) desiredHeight(%d)\n", desiredWidth, desiredHeight ); - auto padding = GetPadding(); + auto padding = GetPadding(); // Padding of this layout's owner, not of the child being measured. const MeasureSpec childWidthMeasureSpec = GetChildMeasureSpec( parentWidthMeasureSpec, padding.start + padding.end, @@ -230,17 +316,19 @@ void LayoutGroup::MeasureChildWithMargins( LayoutItemPtr child, auto childOwner = child->GetOwner(); auto desiredWidth = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ); auto desiredHeight = childOwner.GetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION ); - auto desiredMargin = childOwner.GetProperty( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION ); - auto padding = GetPadding(); + + 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 + + LayoutLength( padding.start + padding.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 + + LayoutLength( padding.top + padding.bottom )+ heightUsed, desiredHeight ); child->Measure( childWidthMeasureSpec, childHeightMeasureSpec ); @@ -255,9 +343,9 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec( auto specMode = measureSpec.GetMode(); LayoutLength specSize = measureSpec.GetSize(); - auto size = std::max( LayoutLength(0), specSize - padding ); + LayoutLength size = std::max( LayoutLength(0), specSize - padding ); // reduce available size by the owners padding - MeasureSpec::IntType resultSize = 0; + LayoutLength resultSize = 0; MeasureSpec::Mode resultMode = MeasureSpec::Mode::UNSPECIFIED; switch( specMode ) @@ -265,15 +353,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; @@ -281,6 +373,7 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec( } else { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::GetChildMeasureSpec childDimension UNSPECIFIED\n"); resultSize = childDimension; resultMode = MeasureSpec::Mode::EXACTLY; } @@ -291,6 +384,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. @@ -308,7 +402,7 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec( else { // Child wants a specific size... so be it - resultSize = childDimension; + resultSize = childDimension + padding; resultMode = MeasureSpec::Mode::EXACTLY; } @@ -318,6 +412,8 @@ 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 @@ -334,13 +430,15 @@ MeasureSpec LayoutGroup::GetChildMeasureSpec( else { // Child wants a specific size... let him have it - resultSize = childDimension; + resultSize = childDimension + padding; resultMode = MeasureSpec::Mode::EXACTLY; } break; } } + DALI_LOG_STREAM( gLogFilter, Debug::Verbose, "LayoutGroup::GetChildMeasureSpec resultSize(" << resultSize << ")\n" ); + //noinspection ResourceType return MeasureSpec( resultSize, resultMode ); } @@ -355,43 +453,97 @@ void LayoutGroup::OnInitialize() // Take ownership of existing children for( unsigned int childIndex = 0 ; childIndex < control.GetChildCount(); ++childIndex ) { - ChildAddedToOwner( control.GetChildAt( childIndex ) ); + ChildAddedToOwnerImpl( control.GetChildAt( childIndex ) ); } DevelActor::ChildAddedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildAddedToOwner ); DevelActor::ChildRemovedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildRemovedFromOwner ); DevelHandle::PropertySetSignal( control ).Connect( mSlotDelegate, &LayoutGroup::OnOwnerPropertySet ); - } -} - -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() ) + if( control.GetParent() ) { - ChildPropertyRegistration( typeInfo.GetName(), MARGIN_SPECIFICATION_NAME, Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION, Property::EXTENTS ); + auto parent = Toolkit::Control::DownCast( control.GetParent() ); + if( parent ) + { + auto parentLayout = Toolkit::LayoutGroup::DownCast( DevelControl::GetLayout( parent ) ); + if( parentLayout ) + { + Internal::LayoutGroup& parentLayoutImpl = GetImplementation( parentLayout ); + + unsigned int count = parent.GetChildCount(); + unsigned int index = static_cast< unsigned int >( control.GetProperty< int >( DevelActor::Property::SIBLING_ORDER ) ); + + // Find insertion position + while( ++index < count ) + { + auto sibling = Toolkit::Control::DownCast( parent.GetChildAt( index ) ); + if( sibling ) + { + auto siblingLayout = DevelControl::GetLayout( sibling ); + if( siblingLayout ) + { + Internal::LayoutItem& siblingLayoutImpl = GetImplementation( siblingLayout ); + parentLayoutImpl.Insert( siblingLayoutImpl, *this ); + break; + } + } + } + + if( index >= count ) + { + parentLayoutImpl.Add( *this ); + } + } + } } + + RequestLayout( Dali::Toolkit::LayoutTransitionData::Type::ON_OWNER_SET ); } +} +void LayoutGroup::OnRegisterChildProperties( const std::string& containerType ) +{ DoRegisterChildProperties( containerType ); } void LayoutGroup::OnUnparent() { + // Remove children RemoveAll(); + + auto control = Toolkit::Control::DownCast( GetOwner() ); + if( control ) + { + DevelActor::ChildAddedSignal( control ).Disconnect( mSlotDelegate, &LayoutGroup::ChildAddedToOwner ); + DevelActor::ChildRemovedSignal( control ).Disconnect( mSlotDelegate, &LayoutGroup::ChildRemovedFromOwner ); + DevelHandle::PropertySetSignal( control ).Disconnect( mSlotDelegate, &LayoutGroup::OnOwnerPropertySet ); + } +} + +void LayoutGroup::RemoveChild( LayoutItem& item ) +{ + item.SetParent( nullptr ); + OnChildRemove( item ); } void LayoutGroup::ChildAddedToOwner( Actor child ) { + ChildAddedToOwnerImpl( child ); + RequestLayout( Dali::Toolkit::LayoutTransitionData::Type::ON_CHILD_ADD, child, Actor() ); +} + +void LayoutGroup::ChildAddedToOwnerImpl( Actor child ) +{ LayoutItemPtr childLayout; Toolkit::Control control = Toolkit::Control::DownCast( child ); +#if defined(DEBUG_ENABLED) + auto parent = Toolkit::Control::DownCast( GetOwner() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner child control(%s) owner control(%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 { Internal::Control& childControlImpl = GetImplementation( control ); @@ -400,17 +552,51 @@ void LayoutGroup::ChildAddedToOwner( Actor child ) if( ! childLayout ) { - // 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 the child doesn't already have a layout, then create a LayoutItem or LayoutGroup for it. + // If control behaviour flag set to Layout then set a LayoutGroup. + if( DevelControl::IsLayoutingRequired( control ) ) + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner Creating default LayoutGroup for control:%s\n", + control?control.GetName().c_str():"Invalid" ); + childLayout = LayoutGroup::New( control ); + } + else + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner Creating default LayoutItem for control:%s\n", + control?control.GetName().c_str():"Invalid" ); + childLayout = LayoutItem::New( control ); + childLayout->SetAnimateLayout( IsLayoutAnimated() ); // forces animation inheritance. + } + + DALI_LOG_STREAM( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner child control:" << control.GetName() << + " desiredWidth: " << control.GetNaturalSize().width << + " desiredHeight:" << control.GetNaturalSize().height ); - auto desiredSize = control.GetNaturalSize(); childControlDataImpl.SetLayout( *childLayout.Get() ); - // HBoxLayout will apply default layout data for this object - child.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, LayoutLength::IntType( desiredSize.width ) ); - child.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, LayoutLength::IntType( desiredSize.height ) ); - child.SetProperty( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION, Extents() ); + Vector3 size = child.GetTargetSize(); + // If the size of the control is set explicitly make sure that the control size + // stays the same after the layout except it is over written with match parent specs. + if ( size.x != 0 ) + { + childLayout->SetMinimumWidth( size.x ); + } + + if ( size.y != 0 ) + { + childLayout->SetMinimumHeight( size.y ); + } + // Default layout data will be generated by Add(). + } + else + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner child(%s) already has a Layout\n", control.GetName().c_str() ); + LayoutGroupPtr layoutGroup( dynamic_cast< LayoutGroup* >( childLayout.Get() ) ); + if( !layoutGroup ) + { + // Set only in case of leaf children + childLayout->SetAnimateLayout( IsLayoutAnimated() ); + } } Add( *childLayout.Get() ); @@ -428,19 +614,217 @@ void LayoutGroup::ChildRemovedFromOwner( Actor child ) if( childLayout ) { Remove( *childLayout.Get() ); + RequestLayout( Dali::Toolkit::LayoutTransitionData::Type::ON_CHILD_REMOVE, 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(); } } +void LayoutGroup::OnAnimationStateChanged( bool animateLayout ) +{ + // Change children's animation state + for( auto&& child : mImpl->mChildren ) + { + LayoutGroupPtr parentGroup( dynamic_cast< LayoutGroup* >( child.child.Get() ) ); + if( ! parentGroup ) + { + // Change state only in case of leaf children + child.child->SetAnimateLayout( animateLayout ); + } + } +} + +void LayoutGroup::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec ) +{ + auto childCount = GetChildCount(); + + DALI_LOG_STREAM( gLogFilter, Debug::Verbose, + "LayoutGroup::OnMeasure Actor Id:" << Actor::DownCast(GetOwner()).GetId() << + " Owner:" << Actor::DownCast(GetOwner()).GetName() << + " Child Count:" << childCount << + " MeasureSpecs( width:"< 0 ) + { + for( unsigned int i=0; iGetOwner()); + + // If child control has children check if a ResizePolicy is set on it. A LayoutItem could be a legacy container. + // A legacy container would need it's ResizePolicy to be applied as a MeasureSpec. + + // Check below will be true for legacy containers and controls with layout required set. + // Other layouts will have their own OnMeasure (a checked requirement) hence not execute LayoutGroup::OnMeasure. + // Controls which have set layout required will not be legacy controls hence should not have a ResizePolicy set. + // Only need to map the resize policy the first time as the Layouting system will then set it to FIXED. + if( childControl.GetChildCount() > 0 && ! mImpl->mResizePolicyMapped ) + { + // First pass, Static mappings that are not dependant on parent + SizeNegotiationMapper::SetLayoutParametersUsingResizePolicy( childControl, childLayout, Dimension::WIDTH ); + SizeNegotiationMapper::SetLayoutParametersUsingResizePolicy( childControl, childLayout, Dimension::HEIGHT ); + mImpl->mResizePolicyMapped = true; + } + + // Second pass, if any mappings were not possible due to parent size dependancies then calculate an exact desired size for child + if( true == childLayout->IsResizePolicyRequired() ) // No need to test child count as this flag would only be set if control had children. + { + // Get last stored width and height specifications for the child + LayoutLength desiredWidth = childControl.GetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ); + LayoutLength desiredHeight = childControl.GetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION ); + + DALI_LOG_INFO( gLogFilter, Debug::General, "LayoutGroup::MeasureChild Initial desired size pre ResizePolicy(%f,%f)\n", desiredWidth.AsInteger(), desiredHeight.AsInteger() ); + + childLayout->SetResizePolicyRequired( false ); // clear flag incase in case of changes before next Measure + SizeNegotiationMapper::GetSizeofChildForParentDependentResizePolicy( childControl, widthMeasureSpec, heightMeasureSpec, desiredWidth, desiredHeight ); + + // Parent dependant ResizePolicies become exact sizes so are now set on the child before it's measured. + childControl.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, desiredWidth.AsInteger() ); + childControl.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, desiredHeight.AsInteger() ); + + DALI_LOG_INFO( gLogFilter, Debug::General, " LayoutGroup::OnMeasure ResizePolicy Required resulting size(%f,%f)\n", desiredWidth.AsInteger(), desiredHeight.AsInteger() ); + } + + // Get size of child + MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec ); + LayoutLength childWidth = childLayout->GetMeasuredWidth(); + LayoutLength childHeight = childLayout->GetMeasuredHeight(); + + Extents childMargin = childLayout->GetMargin(); + DALI_LOG_STREAM( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure child " << childControl.GetName().c_str() << " width[" << childWidth << "] height[" << childHeight << "]\n" ); + + layoutWidth = std::max( layoutWidth, childWidth + childMargin.start + childMargin.end ); + layoutHeight = std::max( layoutHeight, childHeight + childMargin.top + childMargin.bottom ); + DALI_LOG_STREAM( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure calculated child width[" << layoutWidth << "] height[" << layoutHeight << "]\n" ); + } + else + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure Not a layout\n" ); + } + } + + 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_STREAM( gLogFilter, Debug::General, "LayoutGroup::OnMeasure Measured size(" << layoutWidth << "," << layoutHeight << ") for : " << Actor::DownCast(GetOwner()).GetName() << " \n" ); + SetMeasuredDimensions( MeasuredSize( layoutWidth ), MeasuredSize( layoutHeight ) ); +} + +void LayoutGroup::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom ) +{ + auto count = GetChildCount(); + + DALI_LOG_STREAM( gLogFilter, Debug::Verbose, "LayoutGroup OnLayout owner:" << ( ( Toolkit::Control::DownCast(GetOwner())) ? Toolkit::Control::DownCast(GetOwner()).GetName() : "invalid" ) << " childCount:" << count ); + + for( unsigned int childIndex = 0; childIndex < count; childIndex++) + { + LayoutItemPtr childLayout = GetChildAt( childIndex ); + if( childLayout != nullptr ) + { + + auto childOwner = childLayout->GetOwner(); + LayoutLength childWidth = childLayout->GetMeasuredWidth(); + LayoutLength childHeight = childLayout->GetMeasuredHeight(); + Extents childMargin = childLayout->GetMargin(); + auto control = Toolkit::Control::DownCast( childOwner ); + Extents padding = GetPadding(); + + auto childPosition = control.GetProperty< Vector3 >( Actor::Property::POSITION ); + auto anchorPoint = control.GetProperty< Vector3 >( Actor::Property::ANCHOR_POINT ); + + DALI_LOG_STREAM( gLogFilter, Debug::General, "LayoutGroup::OnLayout child[" << control.GetName() << + "] position(" << childPosition << ") child width[" << childWidth << "] height[" << childHeight << "]\n" ); + + // 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