X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Fdevel-api%2Flayouting%2Flayout-group-impl.cpp;h=9f54f5672bcb2cdc9413a1ca3f1ede5980f49d37;hp=9df05c6cd009cc882de98037263235b9bdbe99a2;hb=56a9f0862566dfb88e0f0266c211ca9766e9bf49;hpb=e8ea0328f92e38164592f09b9c978258622c0939 diff --git a/dali-toolkit/devel-api/layouting/layout-group-impl.cpp b/dali-toolkit/devel-api/layouting/layout-group-impl.cpp index 9df05c6..9f54f56 100644 --- a/dali-toolkit/devel-api/layouting/layout-group-impl.cpp +++ b/dali-toolkit/devel-api/layouting/layout-group-impl.cpp @@ -31,7 +31,7 @@ namespace { #if defined(DEBUG_ENABLED) -Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_LAYOUT" ); +Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_LAYOUT" ); #endif } @@ -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 @@ -71,6 +77,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 @@ -98,7 +106,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; } @@ -112,7 +120,7 @@ void LayoutGroup::Remove( LayoutItem& child ) { if( iter->child.Get() == &child ) { - OnChildRemove( *iter->child.Get() ); + RemoveChild( *iter->child.Get() ); mImpl->mChildren.erase(iter); break; } @@ -120,11 +128,109 @@ void LayoutGroup::Remove( LayoutItem& child ) RequestLayout(); } -void LayoutGroup::RemoveAll() +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; +} + +Toolkit::LayoutGroup::LayoutId LayoutGroup::Move( LayoutItem& target, LayoutItem& child ) +{ + // Remove child from the previous position for( auto iter = mImpl->mChildren.begin() ; iter != mImpl->mChildren.end() ; ++iter ) { - OnChildRemove( *iter->child.Get() ); + if( iter->child.Get() == &child ) + { + mImpl->mChildren.erase( iter ); + break; + } + } + + // 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 ); + + RequestLayout(); + + return childLayout.layoutId; +} + +Toolkit::LayoutGroup::LayoutId LayoutGroup::MoveBack( LayoutItem& child ) +{ + // Remove child from the previous position + for( auto iter = mImpl->mChildren.begin() ; iter != mImpl->mChildren.end() ; ++iter ) + { + if( iter->child.Get() == &child ) + { + mImpl->mChildren.erase( iter ); + break; + } + } + + Impl::ChildLayout childLayout; + childLayout.layoutId = mImpl->mNextLayoutId++; + childLayout.child = &child; + mImpl->mChildren.emplace_back( childLayout ); + + RequestLayout(); + + return childLayout.layoutId; +} + +void LayoutGroup::RemoveAll() +{ + for( auto iter = mImpl->mChildren.begin() ; iter != mImpl->mChildren.end() ; ) + { + RemoveChild( *iter->child.Get() ); iter = mImpl->mChildren.erase(iter); } } @@ -182,7 +288,7 @@ void LayoutGroup::DoRegisterChildProperties( const std::string& containerType ) void LayoutGroup::OnSetChildProperties( Handle& handle, Property::Index index, Property::Value value ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnSetChildProperties"); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnSetChildProperties property(%s)\n", handle.GetPropertyName(index).c_str()); if ( ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) ) @@ -190,7 +296,14 @@ void LayoutGroup::OnSetChildProperties( Handle& handle, Property::Index index, P ( 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; + } + } } } @@ -226,36 +339,15 @@ void LayoutGroup::MeasureChild( LayoutItemPtr child, #if defined( DEBUG_ENABLED ) if ( control ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChildWithMargins naturalSizewidth(%f)\n", control.GetNaturalSize().width ); + 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 ); - - // The size of the control could have changed due to padding being altered, the XXX_SPECIFICATIONs will not have been updated. - // So GetNaturalSize is called, if the control's natural size includes padding then th size will be updated. - if ( control ) - { - auto desiredSize = control.GetNaturalSize(); // Get's child control's size which could include new padding values. - - // Check if WIDTH_SPECIFICATION was a size value, if so then get update to child controls's width. - if ( desiredWidth > 0 ) - { - desiredWidth = desiredSize.width; - childOwner.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, LayoutLength::IntType( desiredWidth ) ); - } - - // Check if HEIGHT_SPECIFICATION was a size value, if so then get update to child controls's height. - if ( desiredHeight > 0) - { - desiredHeight = desiredSize.height; - childOwner.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, LayoutLength::IntType( desiredHeight ) ); - } - } - - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChild desiredWidth(%d)\n", desiredWidth ); + 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. @@ -279,7 +371,6 @@ void LayoutGroup::MeasureChildWithMargins( LayoutItemPtr child, 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, @@ -420,7 +511,45 @@ void LayoutGroup::OnInitialize() DevelActor::ChildAddedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildAddedToOwner ); DevelActor::ChildRemovedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildRemovedFromOwner ); + DevelActor::ChildOrderChangedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildOrderChanged ); DevelHandle::PropertySetSignal( control ).Connect( mSlotDelegate, &LayoutGroup::OnOwnerPropertySet ); + + if( control.GetParent() ) + { + 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 ); + } + } + } + } } } @@ -431,14 +560,25 @@ void LayoutGroup::OnRegisterChildProperties( const std::string& containerType ) void LayoutGroup::OnUnparent() { + // Remove children RemoveAll(); } +void LayoutGroup::RemoveChild( LayoutItem& item ) +{ + item.SetParent( nullptr ); + OnChildRemove( item ); +} + void LayoutGroup::ChildAddedToOwner( Actor child ) { LayoutItemPtr childLayout; Toolkit::Control control = Toolkit::Control::DownCast( child ); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner(%s)\n", control.GetName().c_str() ); + +#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 { @@ -449,17 +589,36 @@ 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 = LayoutGroup::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() ); - // 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 ) ); + 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 + { + LayoutGroupPtr layoutGroup( dynamic_cast< LayoutGroup* >( childLayout.Get() ) ); + if( !layoutGroup ) + { + // Set only in case of leaf children + childLayout->SetAnimateLayout( IsLayoutAnimated() ); + } } Add( *childLayout.Get() ); @@ -481,6 +640,42 @@ void LayoutGroup::ChildRemovedFromOwner( Actor child ) } } +void LayoutGroup::ChildOrderChanged( Actor child ) +{ + Toolkit::Control childControl = Toolkit::Control::DownCast( child ); + if( childControl ) + { + Internal::Control& childControlImpl = GetImplementation( childControl ); + Internal::Control::Impl& childControlDataImpl = Internal::Control::Impl::Get( childControlImpl ); + + auto childLayout = childControlDataImpl.GetLayout(); + if( childLayout ) + { + Toolkit::Control control = Toolkit::Control::DownCast( GetOwner() ); + unsigned int count = control.GetChildCount(); + unsigned int index = static_cast< unsigned int >( childControl.GetProperty< int >( DevelActor::Property::SIBLING_ORDER ) ); + + // Find insertion position + while( ++index < count ) + { + auto sibling = Toolkit::Control::DownCast( control.GetChildAt( index ) ); + if( sibling ) + { + auto siblingLayout = DevelControl::GetLayout( sibling ); + if( siblingLayout ) + { + Internal::LayoutItem& siblingLayoutImpl = GetImplementation( siblingLayout ); + Move( siblingLayoutImpl, *childLayout ); + return; + } + } + } + + MoveBack( *childLayout ); + } + } +} + void LayoutGroup::OnOwnerPropertySet( Handle& handle, Property::Index index, Property::Value value ) { DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutGroup::OnOwnerPropertySet\n"); @@ -497,6 +692,160 @@ void LayoutGroup::OnOwnerPropertySet( Handle& handle, Property::Index index, Pro } } +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 && ( 0 == parentGroup->GetChildCount() ) ) // A leaf LayoutGroup will have no children. + { + // Change state only in case of leaf children + child.child->SetAnimateLayout( 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:"< 0 ) + { + for( unsigned int i=0; iGetOwner(); + + // 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