2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/controls/flex-container/flex-container-impl.h>
23 #include <dali/public-api/object/ref-object.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/object/type-registry-helper.h>
26 #include <dali/devel-api/actors/actor-devel.h>
27 #include <dali/devel-api/scripting/scripting.h>
28 #include <dali/public-api/size-negotiation/relayout-container.h>
29 #include <dali/integration-api/debug.h>
36 #if defined(DEBUG_ENABLED)
37 // debugging support, very useful when new features are added or bugs are hunted down
38 // currently not called from code so compiler will optimize these away, kept here for future debugging
40 #define FLEX_CONTAINER_TAG "DALI Toolkit::FlexContainer "
41 #define FC_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, FLEX_CONTAINER_TAG fmt, ## args)
42 // #define FLEX_CONTAINER_DEBUG 1
44 #if defined(FLEX_CONTAINER_DEBUG)
45 void PrintNodes( Toolkit::Internal::FlexContainer::FlexItemNodeContainer itemNodes )
47 // Print the style property and layout of all the children
48 for( unsigned int i = 0; i < itemNodes.size(); ++i )
50 FC_LOG( "Item %d style: \n", i );
51 YGNodePrint( itemNodes[i].node, (YGPrintOptions)( YGPrintOptionsStyle | YGPrintOptionsChildren ) );
53 FC_LOG( "Item %d layout: \n", i );
54 YGNodePrint( itemNodes[i].node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsChildren ) );
59 #endif // defined(FLEX_CONTAINER_DEBUG)
60 #endif // defined(DEBUG_ENABLED)
80 return Toolkit::FlexContainer::New();
83 // Setup properties, signals and actions using the type-registry.
84 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::FlexContainer, Toolkit::Control, Create );
86 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "contentDirection", INTEGER, CONTENT_DIRECTION )
87 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexDirection", INTEGER, FLEX_DIRECTION )
88 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexWrap", INTEGER, FLEX_WRAP )
89 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "justifyContent", INTEGER, JUSTIFY_CONTENT )
90 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignItems", INTEGER, ALIGN_ITEMS )
91 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignContent", INTEGER, ALIGN_CONTENT )
92 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flex", FLOAT, FLEX )
93 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignSelf", INTEGER, ALIGN_SELF )
94 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexMargin", VECTOR4, FLEX_MARGIN )
96 DALI_TYPE_REGISTRATION_END()
98 const Scripting::StringEnum ALIGN_SELF_STRING_TABLE[] =
100 { "auto", Toolkit::FlexContainer::ALIGN_AUTO },
101 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
102 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
103 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
104 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
106 const unsigned int ALIGN_SELF_STRING_TABLE_COUNT = sizeof( ALIGN_SELF_STRING_TABLE ) / sizeof( ALIGN_SELF_STRING_TABLE[0] );
108 const Scripting::StringEnum CONTENT_DIRECTION_STRING_TABLE[] =
110 { "inherit", Toolkit::FlexContainer::INHERIT },
111 { "LTR", Toolkit::FlexContainer::LTR },
112 { "RTL", Toolkit::FlexContainer::RTL }
114 const unsigned int CONTENT_DIRECTION_STRING_TABLE_COUNT = sizeof( CONTENT_DIRECTION_STRING_TABLE ) / sizeof( CONTENT_DIRECTION_STRING_TABLE[0] );
116 const Scripting::StringEnum FLEX_DIRECTION_STRING_TABLE[] =
118 { "column", Toolkit::FlexContainer::COLUMN },
119 { "columnReverse", Toolkit::FlexContainer::COLUMN_REVERSE },
120 { "row", Toolkit::FlexContainer::ROW },
121 { "rowReverse", Toolkit::FlexContainer::ROW_REVERSE }
123 const unsigned int FLEX_DIRECTION_STRING_TABLE_COUNT = sizeof( FLEX_DIRECTION_STRING_TABLE ) / sizeof( FLEX_DIRECTION_STRING_TABLE[0] );
125 const Scripting::StringEnum FLEX_WRAP_STRING_TABLE[] =
127 { "noWrap", Toolkit::FlexContainer::NO_WRAP },
128 { "wrap", Toolkit::FlexContainer::WRAP }
130 const unsigned int FLEX_WRAP_STRING_TABLE_COUNT = sizeof( FLEX_WRAP_STRING_TABLE ) / sizeof( FLEX_WRAP_STRING_TABLE[0] );
132 const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
134 { "flexStart", Toolkit::FlexContainer::JUSTIFY_FLEX_START },
135 { "center", Toolkit::FlexContainer::JUSTIFY_CENTER },
136 { "flexEnd", Toolkit::FlexContainer::JUSTIFY_FLEX_END },
137 { "spaceBetween", Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN },
138 { "spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND }
140 const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof( JUSTIFY_CONTENT_STRING_TABLE ) / sizeof( JUSTIFY_CONTENT_STRING_TABLE[0] );
142 const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
144 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
145 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
146 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
147 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
149 const unsigned int ALIGN_ITEMS_STRING_TABLE_COUNT = sizeof( ALIGN_ITEMS_STRING_TABLE ) / sizeof( ALIGN_ITEMS_STRING_TABLE[0] );
151 const Scripting::StringEnum ALIGN_CONTENT_STRING_TABLE[] =
153 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
154 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
155 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
156 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
158 const unsigned int ALIGN_CONTENT_STRING_TABLE_COUNT = sizeof( ALIGN_CONTENT_STRING_TABLE ) / sizeof( ALIGN_CONTENT_STRING_TABLE[0] );
160 } // Unnamed namespace
162 Toolkit::FlexContainer FlexContainer::New()
164 // Create the implementation, temporarily owned by this handle on stack
165 IntrusivePtr< FlexContainer > impl = new FlexContainer();
167 // Pass ownership to CustomActor handle
168 Toolkit::FlexContainer handle( *impl );
170 // Second-phase init of the implementation
171 // This can only be done after the CustomActor connection has been made...
177 FlexContainer::~FlexContainer()
179 YGNodeFree( mRootNode.node );
181 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
183 YGNodeFree( mChildrenNodes[i].node );
186 mChildrenNodes.clear();
189 void FlexContainer::SetContentDirection( Toolkit::FlexContainer::ContentDirection contentDirection)
191 if( mContentDirection != contentDirection )
193 Dali::CustomActor ownerActor(GetOwner());
195 if( Toolkit::FlexContainer::INHERIT != contentDirection )
197 mContentDirection = contentDirection;
199 ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, false );
201 if( Toolkit::FlexContainer::LTR == contentDirection )
203 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT);
207 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT);
212 ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, true );
214 Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( ownerActor.GetParent().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
216 if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
218 mContentDirection = Toolkit::FlexContainer::RTL;
222 mContentDirection = Toolkit::FlexContainer::LTR;
230 Toolkit::FlexContainer::ContentDirection FlexContainer::GetContentDirection()
232 return mContentDirection;
235 void FlexContainer::SetFlexDirection( Toolkit::FlexContainer::FlexDirection flexDirection )
237 if( mFlexDirection != flexDirection )
239 mFlexDirection = flexDirection;
240 YGNodeStyleSetFlexDirection( mRootNode.node, static_cast<YGFlexDirection>( flexDirection ) );
246 Toolkit::FlexContainer::FlexDirection FlexContainer::GetFlexDirection()
248 return mFlexDirection;
251 void FlexContainer::SetFlexWrap( Toolkit::FlexContainer::WrapType flexWrap )
253 if( mFlexWrap != flexWrap )
255 mFlexWrap = flexWrap;
256 YGNodeStyleSetFlexWrap( mRootNode.node, static_cast<YGWrap>( flexWrap ) );
262 Toolkit::FlexContainer::WrapType FlexContainer::GetFlexWrap()
267 void FlexContainer::SetJustifyContent( Toolkit::FlexContainer::Justification justifyContent )
269 if( mJustifyContent != justifyContent )
271 mJustifyContent = justifyContent;
272 YGNodeStyleSetJustifyContent( mRootNode.node, static_cast<YGJustify>( justifyContent ) );
278 Toolkit::FlexContainer::Justification FlexContainer::GetJustifyContent()
280 return mJustifyContent;
283 void FlexContainer::SetAlignItems( Toolkit::FlexContainer::Alignment alignItems )
285 if( mAlignItems != alignItems )
287 mAlignItems = alignItems;
288 YGNodeStyleSetAlignItems( mRootNode.node, static_cast<YGAlign>( alignItems ) );
294 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignItems()
299 void FlexContainer::SetAlignContent( Toolkit::FlexContainer::Alignment alignContent )
301 if( mAlignContent != alignContent )
303 mAlignContent = alignContent;
304 YGNodeStyleSetAlignContent( mRootNode.node, static_cast<YGAlign>( alignContent ) );
310 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignContent()
312 return mAlignContent;
315 void FlexContainer::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
317 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
321 FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
324 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
326 Toolkit::FlexContainer::ContentDirection contentDirection( Toolkit::FlexContainer::INHERIT );
328 if( value.GetType() == Property::INTEGER )
330 flexContainerImpl.SetContentDirection( static_cast<Toolkit::FlexContainer::ContentDirection>( value.Get< int >() ) );
332 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::ContentDirection >( value.Get< std::string >().c_str(),
333 CONTENT_DIRECTION_STRING_TABLE,
334 CONTENT_DIRECTION_STRING_TABLE_COUNT,
337 flexContainerImpl.SetContentDirection(contentDirection);
341 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
343 Toolkit::FlexContainer::FlexDirection flexDirection( Toolkit::FlexContainer::COLUMN );
345 if( value.GetType() == Property::INTEGER )
347 flexContainerImpl.SetFlexDirection( static_cast<Toolkit::FlexContainer::FlexDirection>( value.Get< int >() ) );
349 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::FlexDirection >( value.Get< std::string >().c_str(),
350 FLEX_DIRECTION_STRING_TABLE,
351 FLEX_DIRECTION_STRING_TABLE_COUNT,
354 flexContainerImpl.SetFlexDirection(flexDirection);
358 case Toolkit::FlexContainer::Property::FLEX_WRAP:
360 Toolkit::FlexContainer::WrapType flexWrap( Toolkit::FlexContainer::NO_WRAP );
362 if( value.GetType() == Property::INTEGER )
364 flexContainerImpl.SetFlexWrap( static_cast<Toolkit::FlexContainer::WrapType>( value.Get< int >() ) );
366 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::WrapType >( value.Get< std::string >().c_str(),
367 FLEX_WRAP_STRING_TABLE,
368 FLEX_WRAP_STRING_TABLE_COUNT,
371 flexContainerImpl.SetFlexWrap(flexWrap);
375 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
377 Toolkit::FlexContainer::Justification justifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START );
379 if( value.GetType() == Property::INTEGER )
381 flexContainerImpl.SetJustifyContent( static_cast<Toolkit::FlexContainer::Justification>( value.Get< int >() ) );
383 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Justification >( value.Get< std::string >().c_str(),
384 JUSTIFY_CONTENT_STRING_TABLE,
385 JUSTIFY_CONTENT_STRING_TABLE_COUNT,
388 flexContainerImpl.SetJustifyContent(justifyContent);
392 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
394 Toolkit::FlexContainer::Alignment alignItems( Toolkit::FlexContainer::ALIGN_STRETCH );
396 if( value.GetType() == Property::INTEGER )
398 flexContainerImpl.SetAlignItems( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
400 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
401 ALIGN_ITEMS_STRING_TABLE,
402 ALIGN_ITEMS_STRING_TABLE_COUNT,
405 flexContainerImpl.SetAlignItems(alignItems);
409 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
411 Toolkit::FlexContainer::Alignment alignContent( Toolkit::FlexContainer::ALIGN_FLEX_START );
413 if( value.GetType() == Property::INTEGER )
415 flexContainerImpl.SetAlignContent( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
417 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
418 ALIGN_CONTENT_STRING_TABLE,
419 ALIGN_CONTENT_STRING_TABLE_COUNT,
422 flexContainerImpl.SetAlignContent(alignContent);
430 Property::Value FlexContainer::GetProperty( BaseObject* object, Property::Index index )
432 Property::Value value;
434 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
438 FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
441 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
443 value = flexContainerImpl.GetContentDirection();
446 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
448 value = flexContainerImpl.GetFlexDirection();
451 case Toolkit::FlexContainer::Property::FLEX_WRAP:
453 value = flexContainerImpl.GetFlexWrap();
456 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
458 value = flexContainerImpl.GetJustifyContent();
461 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
463 value = flexContainerImpl.GetAlignItems();
466 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
468 value = flexContainerImpl.GetAlignContent();
477 void FlexContainer::OnChildAdd( Actor& child )
479 // Create a new node for the child.
480 FlexItemNode childNode;
481 childNode.actor = child;
482 childNode.node = YGNodeNew();
484 mChildrenNodes.push_back( childNode );
485 YGNodeInsertChild( mRootNode.node, childNode.node, mChildrenNodes.size() - 1 );
487 Control::OnChildAdd( child );
490 void FlexContainer::OnChildRemove( Actor& child )
492 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
494 if( mChildrenNodes[i].actor.GetHandle() == child )
496 YGNodeRemoveChild( mRootNode.node, mChildrenNodes[i].node );
497 YGNodeFree( mChildrenNodes[i].node );
499 mChildrenNodes.erase( mChildrenNodes.begin() + i );
501 // Relayout the container only if instances were found
507 Control::OnChildRemove( child );
510 void FlexContainer::OnRelayout( const Vector2& size, RelayoutContainer& container )
512 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
514 Actor child = mChildrenNodes[i].actor.GetHandle();
517 // Anchor actor to top left of the container
518 if( child.GetProperty( DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
520 child.SetAnchorPoint( AnchorPoint::TOP_LEFT );
522 child.SetParentOrigin( ParentOrigin::TOP_LEFT );
524 float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
525 float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
527 if( negotiatedWidth > 0 )
529 YGNodeStyleSetWidth( mChildrenNodes[i].node, negotiatedWidth );
531 if( negotiatedHeight > 0 )
533 YGNodeStyleSetHeight( mChildrenNodes[i].node, negotiatedHeight );
538 // Relayout the container
540 #if defined(FLEX_CONTAINER_DEBUG)
541 PrintNodes( mChildrenNodes );
544 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
546 Actor child = mChildrenNodes[i].actor.GetHandle();
549 if( child.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
551 // Only Set to USE_ASSIGNED_SIZE if the child actor is flexible.
553 if( child.GetResizePolicy( Dimension::WIDTH ) != ResizePolicy::USE_ASSIGNED_SIZE )
555 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
557 if( child.GetResizePolicy( Dimension::HEIGHT ) != ResizePolicy::USE_ASSIGNED_SIZE )
559 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
562 container.Add( child, Vector2(YGNodeLayoutGetWidth(mChildrenNodes[i].node), YGNodeLayoutGetHeight(mChildrenNodes[i].node) ) );
567 bool FlexContainer::RelayoutDependentOnChildren( Dimension::Type dimension )
572 void FlexContainer::OnSizeSet( const Vector3& size )
577 YGNodeStyleSetWidth( mRootNode.node, size.x );
578 YGNodeStyleSetHeight( mRootNode.node, size.y );
583 Control::OnSizeSet( size );
586 void FlexContainer::OnLayoutDirectionChanged( Dali::Actor actor, Dali::LayoutDirection::Type type )
588 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(actor);
589 Toolkit::FlexContainer::ContentDirection direction;
591 if( type == Dali::LayoutDirection::RIGHT_TO_LEFT )
593 direction = Toolkit::FlexContainer::RTL;
597 direction = Toolkit::FlexContainer::LTR;
600 Toolkit::Internal::FlexContainer &flexContainerImpl = GetImpl( flexContainer );
602 if( flexContainerImpl.mContentDirection != direction )
604 Dali::CustomActor ownerActor(flexContainerImpl.GetOwner());
605 flexContainerImpl.mContentDirection = direction;
607 flexContainerImpl.RelayoutRequest();
611 void FlexContainer::ComputeLayout()
615 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
617 YGNodeRef childNode = mChildrenNodes[i].node;
618 Actor childActor = mChildrenNodes[i].actor.GetHandle();
620 // Intialize the style of the child.
621 YGNodeStyleSetMinWidth( childNode, childActor.GetMinimumSize().x );
622 YGNodeStyleSetMinHeight( childNode, childActor.GetMinimumSize().y );
623 YGNodeStyleSetMaxWidth( childNode, childActor.GetMaximumSize().x );
624 YGNodeStyleSetMaxHeight( childNode, childActor.GetMaximumSize().y );
626 // Check child properties on the child for how to layout it.
627 // These properties should be dynamically registered to the child which
628 // would be added to FlexContainer.
630 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
632 YGNodeStyleSetFlex( childNode, childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX ).Get<float>() );
635 Toolkit::FlexContainer::Alignment alignSelf( Toolkit::FlexContainer::ALIGN_AUTO );
636 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF ) != Property::NONE )
638 Property::Value alignSelfPropertyValue = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF );
639 if( alignSelfPropertyValue.GetType() == Property::INTEGER )
641 alignSelf = static_cast<Toolkit::FlexContainer::Alignment>( alignSelfPropertyValue.Get< int >() );
643 else if( alignSelfPropertyValue.GetType() == Property::STRING )
645 std::string value = alignSelfPropertyValue.Get<std::string>();
646 Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.c_str(),
647 ALIGN_SELF_STRING_TABLE,
648 ALIGN_SELF_STRING_TABLE_COUNT,
651 YGNodeStyleSetAlignSelf( childNode, static_cast<YGAlign>(alignSelf) );
654 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ) != Property::NONE )
656 Vector4 flexMargin = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ).Get<Vector4>();
657 YGNodeStyleSetMargin( childNode, YGEdgeLeft, flexMargin.x );
658 YGNodeStyleSetMargin( childNode, YGEdgeTop, flexMargin.y );
659 YGNodeStyleSetMargin( childNode, YGEdgeRight, flexMargin.z );
660 YGNodeStyleSetMargin( childNode, YGEdgeBottom, flexMargin.w );
664 // Calculate the layout
665 YGDirection nodeLayoutDirection = YGDirectionInherit;
666 switch( mContentDirection )
668 case Dali::Toolkit::FlexContainer::LTR:
670 nodeLayoutDirection = YGDirectionLTR;
674 case Dali::Toolkit::FlexContainer::RTL:
676 nodeLayoutDirection = YGDirectionRTL;
680 case Dali::Toolkit::FlexContainer::INHERIT:
682 nodeLayoutDirection = YGDirectionInherit;
687 #if defined(FLEX_CONTAINER_DEBUG)
688 YGNodePrint( mRootNode.node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren ) );
690 YGNodeCalculateLayout( mRootNode.node, Self().GetMaximumSize().x, Self().GetMaximumSize().y, nodeLayoutDirection );
691 #if defined(FLEX_CONTAINER_DEBUG)
692 YGNodePrint( mRootNode.node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren ) );
697 void FlexContainer::RelayoutChildren()
701 // Set size and position of children according to the layout calculation
702 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
704 Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
707 child.SetX( YGNodeLayoutGetLeft( mChildrenNodes[i].node ) );
708 child.SetY( YGNodeLayoutGetTop( mChildrenNodes[i].node ) );
713 Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
715 Actor nextFocusableActor;
717 // First check whether there is any items in the container
718 if( mChildrenNodes.size() > 0 )
720 if ( !currentFocusedActor || currentFocusedActor == Self() )
722 // Nothing is currently focused, so the first child in the container should be focused.
723 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
727 // Check whether the current focused actor is within flex container
728 int currentFocusedActorIndex = -1;
729 for( unsigned int index = 0; index < mChildrenNodes.size(); index++ )
731 if( currentFocusedActor == mChildrenNodes[index].actor.GetHandle() )
733 currentFocusedActorIndex = index;
738 if( currentFocusedActorIndex > -1 )
740 int previousCheckedActorIndex = -1;
741 int nextFocusedActorIndex = currentFocusedActorIndex;
744 case Toolkit::Control::KeyboardFocus::LEFT:
745 case Toolkit::Control::KeyboardFocus::UP:
747 // Search the next focusable actor in the backward direction
750 nextFocusedActorIndex--;
751 if( nextFocusedActorIndex < 0 )
753 nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
755 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
757 previousCheckedActorIndex = nextFocusedActorIndex;
763 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
766 case Toolkit::Control::KeyboardFocus::RIGHT:
767 case Toolkit::Control::KeyboardFocus::DOWN:
769 // Search the next focusable actor in the forward direction
772 nextFocusedActorIndex++;
773 if( nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1) )
775 nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
777 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
779 previousCheckedActorIndex = nextFocusedActorIndex;
785 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
794 if( nextFocusedActorIndex != currentFocusedActorIndex )
796 nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
800 // No focusble child in the container
801 nextFocusableActor = Actor();
806 // The current focused actor is not within flex container, so the first child in the container should be focused.
807 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
812 return nextFocusableActor;
815 FlexContainer::FlexContainer()
816 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
817 mContentDirection( Toolkit::FlexContainer::INHERIT ),
818 mFlexDirection( Toolkit::FlexContainer::COLUMN ),
819 mFlexWrap( Toolkit::FlexContainer::NO_WRAP ),
820 mJustifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START ),
821 mAlignItems( Toolkit::FlexContainer::ALIGN_STRETCH ),
822 mAlignContent( Toolkit::FlexContainer::ALIGN_FLEX_START )
824 SetKeyboardNavigationSupport( true );
827 void FlexContainer::OnInitialize()
829 // Initialize the node for the flex container itself
830 Dali::Actor self = Self();
831 self.LayoutDirectionChangedSignal().Connect( this, &FlexContainer::OnLayoutDirectionChanged );
833 mRootNode.actor = self;
834 mRootNode.node = YGNodeNew();
835 YGNodeSetContext( mRootNode.node, &mChildrenNodes );
838 YGNodeStyleSetFlexDirection( mRootNode.node, static_cast<YGFlexDirection>( mFlexDirection ) );
839 YGNodeStyleSetFlexWrap( mRootNode.node, static_cast<YGWrap>( mFlexWrap ) );
840 YGNodeStyleSetJustifyContent( mRootNode.node, static_cast<YGJustify>( mJustifyContent ) );
841 YGNodeStyleSetAlignItems( mRootNode.node, static_cast<YGAlign>( mAlignItems ) );
842 YGNodeStyleSetAlignContent( mRootNode.node, static_cast<YGAlign>( mAlignContent ) );
844 // Make self as keyboard focusable and focus group
845 self.SetKeyboardFocusable( true );
846 SetAsKeyboardFocusGroup( true );
849 } // namespace Internal
851 } // namespace Toolkit