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 },
139 { "spaceEvenly", Toolkit::FlexContainer::JUSTIFY_SPACE_EVENLY }
141 const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof( JUSTIFY_CONTENT_STRING_TABLE ) / sizeof( JUSTIFY_CONTENT_STRING_TABLE[0] );
143 const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
145 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
146 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
147 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
148 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
150 const unsigned int ALIGN_ITEMS_STRING_TABLE_COUNT = sizeof( ALIGN_ITEMS_STRING_TABLE ) / sizeof( ALIGN_ITEMS_STRING_TABLE[0] );
152 const Scripting::StringEnum ALIGN_CONTENT_STRING_TABLE[] =
154 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
155 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
156 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
157 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
159 const unsigned int ALIGN_CONTENT_STRING_TABLE_COUNT = sizeof( ALIGN_CONTENT_STRING_TABLE ) / sizeof( ALIGN_CONTENT_STRING_TABLE[0] );
161 } // Unnamed namespace
163 Toolkit::FlexContainer FlexContainer::New()
165 // Create the implementation, temporarily owned by this handle on stack
166 IntrusivePtr< FlexContainer > impl = new FlexContainer();
168 // Pass ownership to CustomActor handle
169 Toolkit::FlexContainer handle( *impl );
171 // Second-phase init of the implementation
172 // This can only be done after the CustomActor connection has been made...
178 FlexContainer::~FlexContainer()
180 YGNodeFree( mRootNode.node );
182 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
184 YGNodeFree( mChildrenNodes[i].node );
187 mChildrenNodes.clear();
190 void FlexContainer::SetContentDirection( Toolkit::FlexContainer::ContentDirection contentDirection)
192 if( mContentDirection != contentDirection )
194 Dali::CustomActor ownerActor(GetOwner());
196 if( Toolkit::FlexContainer::INHERIT != contentDirection )
198 mContentDirection = contentDirection;
200 ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, false );
202 if( Toolkit::FlexContainer::LTR == contentDirection )
204 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT);
208 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT);
213 ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, true );
215 Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( ownerActor.GetParent().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
217 if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
219 mContentDirection = Toolkit::FlexContainer::RTL;
223 mContentDirection = Toolkit::FlexContainer::LTR;
231 Toolkit::FlexContainer::ContentDirection FlexContainer::GetContentDirection()
233 return mContentDirection;
236 void FlexContainer::SetFlexDirection( Toolkit::FlexContainer::FlexDirection flexDirection )
238 if( mFlexDirection != flexDirection )
240 mFlexDirection = flexDirection;
241 YGNodeStyleSetFlexDirection( mRootNode.node, static_cast<YGFlexDirection>( flexDirection ) );
247 Toolkit::FlexContainer::FlexDirection FlexContainer::GetFlexDirection()
249 return mFlexDirection;
252 void FlexContainer::SetFlexWrap( Toolkit::FlexContainer::WrapType flexWrap )
254 if( mFlexWrap != flexWrap )
256 mFlexWrap = flexWrap;
257 YGNodeStyleSetFlexWrap( mRootNode.node, static_cast<YGWrap>( flexWrap ) );
263 Toolkit::FlexContainer::WrapType FlexContainer::GetFlexWrap()
268 void FlexContainer::SetJustifyContent( Toolkit::FlexContainer::Justification justifyContent )
270 if( mJustifyContent != justifyContent )
272 mJustifyContent = justifyContent;
273 YGNodeStyleSetJustifyContent( mRootNode.node, static_cast<YGJustify>( justifyContent ) );
279 Toolkit::FlexContainer::Justification FlexContainer::GetJustifyContent()
281 return mJustifyContent;
284 void FlexContainer::SetAlignItems( Toolkit::FlexContainer::Alignment alignItems )
286 if( mAlignItems != alignItems )
288 mAlignItems = alignItems;
289 YGNodeStyleSetAlignItems( mRootNode.node, static_cast<YGAlign>( alignItems ) );
295 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignItems()
300 void FlexContainer::SetAlignContent( Toolkit::FlexContainer::Alignment alignContent )
302 if( mAlignContent != alignContent )
304 mAlignContent = alignContent;
305 YGNodeStyleSetAlignContent( mRootNode.node, static_cast<YGAlign>( alignContent ) );
311 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignContent()
313 return mAlignContent;
316 void FlexContainer::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
318 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
322 FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
325 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
327 Toolkit::FlexContainer::ContentDirection contentDirection( Toolkit::FlexContainer::INHERIT );
329 if( value.GetType() == Property::INTEGER )
331 flexContainerImpl.SetContentDirection( static_cast<Toolkit::FlexContainer::ContentDirection>( value.Get< int >() ) );
333 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::ContentDirection >( value.Get< std::string >().c_str(),
334 CONTENT_DIRECTION_STRING_TABLE,
335 CONTENT_DIRECTION_STRING_TABLE_COUNT,
338 flexContainerImpl.SetContentDirection(contentDirection);
342 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
344 Toolkit::FlexContainer::FlexDirection flexDirection( Toolkit::FlexContainer::COLUMN );
346 if( value.GetType() == Property::INTEGER )
348 flexContainerImpl.SetFlexDirection( static_cast<Toolkit::FlexContainer::FlexDirection>( value.Get< int >() ) );
350 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::FlexDirection >( value.Get< std::string >().c_str(),
351 FLEX_DIRECTION_STRING_TABLE,
352 FLEX_DIRECTION_STRING_TABLE_COUNT,
355 flexContainerImpl.SetFlexDirection(flexDirection);
359 case Toolkit::FlexContainer::Property::FLEX_WRAP:
361 Toolkit::FlexContainer::WrapType flexWrap( Toolkit::FlexContainer::NO_WRAP );
363 if( value.GetType() == Property::INTEGER )
365 flexContainerImpl.SetFlexWrap( static_cast<Toolkit::FlexContainer::WrapType>( value.Get< int >() ) );
367 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::WrapType >( value.Get< std::string >().c_str(),
368 FLEX_WRAP_STRING_TABLE,
369 FLEX_WRAP_STRING_TABLE_COUNT,
372 flexContainerImpl.SetFlexWrap(flexWrap);
376 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
378 Toolkit::FlexContainer::Justification justifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START );
380 if( value.GetType() == Property::INTEGER )
382 flexContainerImpl.SetJustifyContent( static_cast<Toolkit::FlexContainer::Justification>( value.Get< int >() ) );
384 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Justification >( value.Get< std::string >().c_str(),
385 JUSTIFY_CONTENT_STRING_TABLE,
386 JUSTIFY_CONTENT_STRING_TABLE_COUNT,
389 flexContainerImpl.SetJustifyContent(justifyContent);
393 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
395 Toolkit::FlexContainer::Alignment alignItems( Toolkit::FlexContainer::ALIGN_STRETCH );
397 if( value.GetType() == Property::INTEGER )
399 flexContainerImpl.SetAlignItems( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
401 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
402 ALIGN_ITEMS_STRING_TABLE,
403 ALIGN_ITEMS_STRING_TABLE_COUNT,
406 flexContainerImpl.SetAlignItems(alignItems);
410 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
412 Toolkit::FlexContainer::Alignment alignContent( Toolkit::FlexContainer::ALIGN_FLEX_START );
414 if( value.GetType() == Property::INTEGER )
416 flexContainerImpl.SetAlignContent( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
418 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
419 ALIGN_CONTENT_STRING_TABLE,
420 ALIGN_CONTENT_STRING_TABLE_COUNT,
423 flexContainerImpl.SetAlignContent(alignContent);
431 Property::Value FlexContainer::GetProperty( BaseObject* object, Property::Index index )
433 Property::Value value;
435 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
439 FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
442 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
444 value = flexContainerImpl.GetContentDirection();
447 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
449 value = flexContainerImpl.GetFlexDirection();
452 case Toolkit::FlexContainer::Property::FLEX_WRAP:
454 value = flexContainerImpl.GetFlexWrap();
457 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
459 value = flexContainerImpl.GetJustifyContent();
462 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
464 value = flexContainerImpl.GetAlignItems();
467 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
469 value = flexContainerImpl.GetAlignContent();
478 void FlexContainer::OnChildAdd( Actor& child )
480 // Create a new node for the child.
481 FlexItemNode childNode;
482 childNode.actor = child;
483 childNode.node = YGNodeNew();
485 mChildrenNodes.push_back( childNode );
486 YGNodeInsertChild( mRootNode.node, childNode.node, mChildrenNodes.size() - 1 );
488 Control::OnChildAdd( child );
491 void FlexContainer::OnChildRemove( Actor& child )
493 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
495 if( mChildrenNodes[i].actor.GetHandle() == child )
497 YGNodeRemoveChild( mRootNode.node, mChildrenNodes[i].node );
498 YGNodeFree( mChildrenNodes[i].node );
500 mChildrenNodes.erase( mChildrenNodes.begin() + i );
502 // Relayout the container only if instances were found
508 Control::OnChildRemove( child );
511 void FlexContainer::OnRelayout( const Vector2& size, RelayoutContainer& container )
513 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
515 Actor child = mChildrenNodes[i].actor.GetHandle();
518 // Anchor actor to top left of the container
519 if( child.GetProperty( Actor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
521 child.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
523 child.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
525 float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
526 float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
528 if( negotiatedWidth > 0 )
530 YGNodeStyleSetWidth( mChildrenNodes[i].node, negotiatedWidth );
532 if( negotiatedHeight > 0 )
534 YGNodeStyleSetHeight( mChildrenNodes[i].node, negotiatedHeight );
539 // Relayout the container
541 #if defined(FLEX_CONTAINER_DEBUG)
542 PrintNodes( mChildrenNodes );
545 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
547 Actor child = mChildrenNodes[i].actor.GetHandle();
550 if( child.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
552 // Only Set to USE_ASSIGNED_SIZE if the child actor is flexible.
554 if( child.GetResizePolicy( Dimension::WIDTH ) != ResizePolicy::USE_ASSIGNED_SIZE )
556 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
558 if( child.GetResizePolicy( Dimension::HEIGHT ) != ResizePolicy::USE_ASSIGNED_SIZE )
560 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
563 container.Add( child, Vector2(YGNodeLayoutGetWidth(mChildrenNodes[i].node), YGNodeLayoutGetHeight(mChildrenNodes[i].node) ) );
568 bool FlexContainer::RelayoutDependentOnChildren( Dimension::Type dimension )
573 void FlexContainer::OnSizeSet( const Vector3& size )
578 YGNodeStyleSetWidth( mRootNode.node, size.x );
579 YGNodeStyleSetHeight( mRootNode.node, size.y );
584 Control::OnSizeSet( size );
587 void FlexContainer::OnLayoutDirectionChanged( Dali::Actor actor, Dali::LayoutDirection::Type type )
589 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(actor);
590 Toolkit::FlexContainer::ContentDirection direction;
592 if( type == Dali::LayoutDirection::RIGHT_TO_LEFT )
594 direction = Toolkit::FlexContainer::RTL;
598 direction = Toolkit::FlexContainer::LTR;
601 Toolkit::Internal::FlexContainer &flexContainerImpl = GetImpl( flexContainer );
603 if( flexContainerImpl.mContentDirection != direction )
605 Dali::CustomActor ownerActor(flexContainerImpl.GetOwner());
606 flexContainerImpl.mContentDirection = direction;
608 flexContainerImpl.RelayoutRequest();
612 void FlexContainer::ComputeLayout()
616 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
618 YGNodeRef childNode = mChildrenNodes[i].node;
619 Actor childActor = mChildrenNodes[i].actor.GetHandle();
621 // Intialize the style of the child.
622 YGNodeStyleSetMinWidth( childNode, childActor.GetProperty< Vector2 >( Actor::Property::MINIMUM_SIZE ).x );
623 YGNodeStyleSetMinHeight( childNode, childActor.GetProperty< Vector2 >( Actor::Property::MINIMUM_SIZE ).y );
624 YGNodeStyleSetMaxWidth( childNode, childActor.GetProperty< Vector2 >( Actor::Property::MAXIMUM_SIZE ).x );
625 YGNodeStyleSetMaxHeight( childNode, childActor.GetProperty< Vector2 >( Actor::Property::MAXIMUM_SIZE ).y );
627 // Check child properties on the child for how to layout it.
628 // These properties should be dynamically registered to the child which
629 // would be added to FlexContainer.
631 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
633 YGNodeStyleSetFlex( childNode, childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX ).Get<float>() );
636 Toolkit::FlexContainer::Alignment alignSelf( Toolkit::FlexContainer::ALIGN_AUTO );
637 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF ) != Property::NONE )
639 Property::Value alignSelfPropertyValue = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF );
640 if( alignSelfPropertyValue.GetType() == Property::INTEGER )
642 alignSelf = static_cast<Toolkit::FlexContainer::Alignment>( alignSelfPropertyValue.Get< int >() );
644 else if( alignSelfPropertyValue.GetType() == Property::STRING )
646 std::string value = alignSelfPropertyValue.Get<std::string>();
647 Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.c_str(),
648 ALIGN_SELF_STRING_TABLE,
649 ALIGN_SELF_STRING_TABLE_COUNT,
652 YGNodeStyleSetAlignSelf( childNode, static_cast<YGAlign>(alignSelf) );
655 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ) != Property::NONE )
657 Vector4 flexMargin = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ).Get<Vector4>();
658 YGNodeStyleSetMargin( childNode, YGEdgeLeft, flexMargin.x );
659 YGNodeStyleSetMargin( childNode, YGEdgeTop, flexMargin.y );
660 YGNodeStyleSetMargin( childNode, YGEdgeRight, flexMargin.z );
661 YGNodeStyleSetMargin( childNode, YGEdgeBottom, flexMargin.w );
665 // Calculate the layout
666 YGDirection nodeLayoutDirection = YGDirectionInherit;
667 switch( mContentDirection )
669 case Dali::Toolkit::FlexContainer::LTR:
671 nodeLayoutDirection = YGDirectionLTR;
675 case Dali::Toolkit::FlexContainer::RTL:
677 nodeLayoutDirection = YGDirectionRTL;
681 case Dali::Toolkit::FlexContainer::INHERIT:
683 nodeLayoutDirection = YGDirectionInherit;
688 #if defined(FLEX_CONTAINER_DEBUG)
689 YGNodePrint( mRootNode.node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren ) );
691 YGNodeCalculateLayout( mRootNode.node, Self().GetProperty< Vector2 >( Actor::Property::MAXIMUM_SIZE ).x, Self().GetProperty< Vector2 >( Actor::Property::MAXIMUM_SIZE ).y, nodeLayoutDirection );
692 #if defined(FLEX_CONTAINER_DEBUG)
693 YGNodePrint( mRootNode.node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren ) );
698 void FlexContainer::RelayoutChildren()
702 // Set size and position of children according to the layout calculation
703 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
705 Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
708 child.SetProperty( Actor::Property::POSITION_X, YGNodeLayoutGetLeft( mChildrenNodes[i].node ) );
709 child.SetProperty( Actor::Property::POSITION_Y, YGNodeLayoutGetTop( mChildrenNodes[i].node ) );
714 Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
716 Actor nextFocusableActor;
718 // First check whether there is any items in the container
719 if( mChildrenNodes.size() > 0 )
721 if ( !currentFocusedActor || currentFocusedActor == Self() )
723 // Nothing is currently focused, so the first child in the container should be focused.
724 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
728 // Check whether the current focused actor is within flex container
729 int currentFocusedActorIndex = -1;
730 for( unsigned int index = 0; index < mChildrenNodes.size(); index++ )
732 if( currentFocusedActor == mChildrenNodes[index].actor.GetHandle() )
734 currentFocusedActorIndex = index;
739 if( currentFocusedActorIndex > -1 )
741 int previousCheckedActorIndex = -1;
742 int nextFocusedActorIndex = currentFocusedActorIndex;
745 case Toolkit::Control::KeyboardFocus::LEFT:
746 case Toolkit::Control::KeyboardFocus::UP:
748 // Search the next focusable actor in the backward direction
751 nextFocusedActorIndex--;
752 if( nextFocusedActorIndex < 0 )
754 nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
756 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
758 previousCheckedActorIndex = nextFocusedActorIndex;
764 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) );
767 case Toolkit::Control::KeyboardFocus::RIGHT:
768 case Toolkit::Control::KeyboardFocus::DOWN:
770 // Search the next focusable actor in the forward direction
773 nextFocusedActorIndex++;
774 if( nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1) )
776 nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
778 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
780 previousCheckedActorIndex = nextFocusedActorIndex;
786 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) );
795 if( nextFocusedActorIndex != currentFocusedActorIndex )
797 nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
801 // No focusble child in the container
802 nextFocusableActor = Actor();
807 // The current focused actor is not within flex container, so the first child in the container should be focused.
808 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
813 return nextFocusableActor;
816 FlexContainer::FlexContainer()
817 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
818 mContentDirection( Toolkit::FlexContainer::INHERIT ),
819 mFlexDirection( Toolkit::FlexContainer::COLUMN ),
820 mFlexWrap( Toolkit::FlexContainer::NO_WRAP ),
821 mJustifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START ),
822 mAlignItems( Toolkit::FlexContainer::ALIGN_STRETCH ),
823 mAlignContent( Toolkit::FlexContainer::ALIGN_FLEX_START )
825 SetKeyboardNavigationSupport( true );
828 void FlexContainer::OnInitialize()
830 // Initialize the node for the flex container itself
831 Dali::Actor self = Self();
832 self.LayoutDirectionChangedSignal().Connect( this, &FlexContainer::OnLayoutDirectionChanged );
834 mRootNode.actor = self;
835 mRootNode.node = YGNodeNew();
836 YGNodeSetContext( mRootNode.node, &mChildrenNodes );
839 YGNodeStyleSetFlexDirection( mRootNode.node, static_cast<YGFlexDirection>( mFlexDirection ) );
840 YGNodeStyleSetFlexWrap( mRootNode.node, static_cast<YGWrap>( mFlexWrap ) );
841 YGNodeStyleSetJustifyContent( mRootNode.node, static_cast<YGJustify>( mJustifyContent ) );
842 YGNodeStyleSetAlignItems( mRootNode.node, static_cast<YGAlign>( mAlignItems ) );
843 YGNodeStyleSetAlignContent( mRootNode.node, static_cast<YGAlign>( mAlignContent ) );
845 // Make self as keyboard focusable and focus group
846 self.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE, true );
847 SetAsKeyboardFocusGroup( true );
850 } // namespace Internal
852 } // namespace Toolkit