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>
32 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
39 #if defined(DEBUG_ENABLED)
40 // debugging support, very useful when new features are added or bugs are hunted down
41 // currently not called from code so compiler will optimize these away, kept here for future debugging
43 #define FLEX_CONTAINER_TAG "DALI Toolkit::FlexContainer "
44 #define FC_LOG(fmt, args,...) Debug::LogMessage(Debug::DebugInfo, FLEX_CONTAINER_TAG fmt, ## args)
45 // #define FLEX_CONTAINER_DEBUG 1
47 #if defined(FLEX_CONTAINER_DEBUG)
48 void PrintNodes( Toolkit::Internal::FlexContainer::FlexItemNodeContainer itemNodes )
50 // Print the style property and layout of all the children
51 for( unsigned int i = 0; i < itemNodes.size(); ++i )
53 FC_LOG( "Item %d style: \n", i );
54 YGNodePrint( itemNodes[i].node, (YGPrintOptions)( YGPrintOptionsStyle | YGPrintOptionsChildren ) );
56 FC_LOG( "Item %d layout: \n", i );
57 YGNodePrint( itemNodes[i].node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsChildren ) );
62 #endif // defined(FLEX_CONTAINER_DEBUG)
63 #endif // defined(DEBUG_ENABLED)
83 return Toolkit::FlexContainer::New();
86 // Setup properties, signals and actions using the type-registry.
87 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::FlexContainer, Toolkit::Control, Create );
89 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "contentDirection", INTEGER, CONTENT_DIRECTION )
90 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexDirection", INTEGER, FLEX_DIRECTION )
91 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexWrap", INTEGER, FLEX_WRAP )
92 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "justifyContent", INTEGER, JUSTIFY_CONTENT )
93 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignItems", INTEGER, ALIGN_ITEMS )
94 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignContent", INTEGER, ALIGN_CONTENT )
95 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flex", FLOAT, FLEX )
96 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignSelf", INTEGER, ALIGN_SELF )
97 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexMargin", VECTOR4, FLEX_MARGIN )
99 DALI_TYPE_REGISTRATION_END()
101 const Scripting::StringEnum ALIGN_SELF_STRING_TABLE[] =
103 { "auto", Toolkit::FlexContainer::ALIGN_AUTO },
104 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
105 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
106 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
107 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
109 const unsigned int ALIGN_SELF_STRING_TABLE_COUNT = sizeof( ALIGN_SELF_STRING_TABLE ) / sizeof( ALIGN_SELF_STRING_TABLE[0] );
111 const Scripting::StringEnum CONTENT_DIRECTION_STRING_TABLE[] =
113 { "inherit", Toolkit::FlexContainer::INHERIT },
114 { "LTR", Toolkit::FlexContainer::LTR },
115 { "RTL", Toolkit::FlexContainer::RTL }
117 const unsigned int CONTENT_DIRECTION_STRING_TABLE_COUNT = sizeof( CONTENT_DIRECTION_STRING_TABLE ) / sizeof( CONTENT_DIRECTION_STRING_TABLE[0] );
119 const Scripting::StringEnum FLEX_DIRECTION_STRING_TABLE[] =
121 { "column", Toolkit::FlexContainer::COLUMN },
122 { "columnReverse", Toolkit::FlexContainer::COLUMN_REVERSE },
123 { "row", Toolkit::FlexContainer::ROW },
124 { "rowReverse", Toolkit::FlexContainer::ROW_REVERSE }
126 const unsigned int FLEX_DIRECTION_STRING_TABLE_COUNT = sizeof( FLEX_DIRECTION_STRING_TABLE ) / sizeof( FLEX_DIRECTION_STRING_TABLE[0] );
128 const Scripting::StringEnum FLEX_WRAP_STRING_TABLE[] =
130 { "noWrap", Toolkit::FlexContainer::NO_WRAP },
131 { "wrap", Toolkit::FlexContainer::WRAP }
133 const unsigned int FLEX_WRAP_STRING_TABLE_COUNT = sizeof( FLEX_WRAP_STRING_TABLE ) / sizeof( FLEX_WRAP_STRING_TABLE[0] );
135 const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
137 { "flexStart", Toolkit::FlexContainer::JUSTIFY_FLEX_START },
138 { "center", Toolkit::FlexContainer::JUSTIFY_CENTER },
139 { "flexEnd", Toolkit::FlexContainer::JUSTIFY_FLEX_END },
140 { "spaceBetween", Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN },
141 { "spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND }
143 const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof( JUSTIFY_CONTENT_STRING_TABLE ) / sizeof( JUSTIFY_CONTENT_STRING_TABLE[0] );
145 const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
147 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
148 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
149 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
150 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
152 const unsigned int ALIGN_ITEMS_STRING_TABLE_COUNT = sizeof( ALIGN_ITEMS_STRING_TABLE ) / sizeof( ALIGN_ITEMS_STRING_TABLE[0] );
154 const Scripting::StringEnum ALIGN_CONTENT_STRING_TABLE[] =
156 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
157 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
158 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
159 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
161 const unsigned int ALIGN_CONTENT_STRING_TABLE_COUNT = sizeof( ALIGN_CONTENT_STRING_TABLE ) / sizeof( ALIGN_CONTENT_STRING_TABLE[0] );
163 } // Unnamed namespace
165 Toolkit::FlexContainer FlexContainer::New()
167 // Create the implementation, temporarily owned by this handle on stack
168 IntrusivePtr< FlexContainer > impl = new FlexContainer();
170 // Pass ownership to CustomActor handle
171 Toolkit::FlexContainer handle( *impl );
173 // Second-phase init of the implementation
174 // This can only be done after the CustomActor connection has been made...
180 FlexContainer::~FlexContainer()
182 YGNodeFree( mRootNode.node );
184 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
186 YGNodeFree( mChildrenNodes[i].node );
189 mChildrenNodes.clear();
192 void FlexContainer::SetContentDirection( Toolkit::FlexContainer::ContentDirection contentDirection)
194 if( mContentDirection != contentDirection )
196 Dali::CustomActor ownerActor(GetOwner());
198 if( Toolkit::FlexContainer::INHERIT != contentDirection )
200 mContentDirection = contentDirection;
202 ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, false );
204 if( Toolkit::FlexContainer::LTR == contentDirection )
206 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT);
210 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT);
215 ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, true );
217 Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( ownerActor.GetParent().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
219 if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
221 mContentDirection = Toolkit::FlexContainer::RTL;
225 mContentDirection = Toolkit::FlexContainer::LTR;
233 Toolkit::FlexContainer::ContentDirection FlexContainer::GetContentDirection()
235 return mContentDirection;
238 void FlexContainer::SetFlexDirection( Toolkit::FlexContainer::FlexDirection flexDirection )
240 if( mFlexDirection != flexDirection )
242 mFlexDirection = flexDirection;
243 YGNodeStyleSetFlexDirection( mRootNode.node, static_cast<YGFlexDirection>( flexDirection ) );
249 Toolkit::FlexContainer::FlexDirection FlexContainer::GetFlexDirection()
251 return mFlexDirection;
254 void FlexContainer::SetFlexWrap( Toolkit::FlexContainer::WrapType flexWrap )
256 if( mFlexWrap != flexWrap )
258 mFlexWrap = flexWrap;
259 YGNodeStyleSetFlexWrap( mRootNode.node, static_cast<YGWrap>( flexWrap ) );
265 Toolkit::FlexContainer::WrapType FlexContainer::GetFlexWrap()
270 void FlexContainer::SetJustifyContent( Toolkit::FlexContainer::Justification justifyContent )
272 if( mJustifyContent != justifyContent )
274 mJustifyContent = justifyContent;
275 YGNodeStyleSetJustifyContent( mRootNode.node, static_cast<YGJustify>( justifyContent ) );
281 Toolkit::FlexContainer::Justification FlexContainer::GetJustifyContent()
283 return mJustifyContent;
286 void FlexContainer::SetAlignItems( Toolkit::FlexContainer::Alignment alignItems )
288 if( mAlignItems != alignItems )
290 mAlignItems = alignItems;
291 YGNodeStyleSetAlignItems( mRootNode.node, static_cast<YGAlign>( alignItems ) );
297 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignItems()
302 void FlexContainer::SetAlignContent( Toolkit::FlexContainer::Alignment alignContent )
304 if( mAlignContent != alignContent )
306 mAlignContent = alignContent;
307 YGNodeStyleSetAlignContent( mRootNode.node, static_cast<YGAlign>( alignContent ) );
313 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignContent()
315 return mAlignContent;
318 void FlexContainer::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
320 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
324 FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
327 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
329 Toolkit::FlexContainer::ContentDirection contentDirection( Toolkit::FlexContainer::INHERIT );
331 if( value.GetType() == Property::INTEGER )
333 flexContainerImpl.SetContentDirection( static_cast<Toolkit::FlexContainer::ContentDirection>( value.Get< int >() ) );
335 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::ContentDirection >( value.Get< std::string >().c_str(),
336 CONTENT_DIRECTION_STRING_TABLE,
337 CONTENT_DIRECTION_STRING_TABLE_COUNT,
340 flexContainerImpl.SetContentDirection(contentDirection);
344 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
346 Toolkit::FlexContainer::FlexDirection flexDirection( Toolkit::FlexContainer::COLUMN );
348 if( value.GetType() == Property::INTEGER )
350 flexContainerImpl.SetFlexDirection( static_cast<Toolkit::FlexContainer::FlexDirection>( value.Get< int >() ) );
352 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::FlexDirection >( value.Get< std::string >().c_str(),
353 FLEX_DIRECTION_STRING_TABLE,
354 FLEX_DIRECTION_STRING_TABLE_COUNT,
357 flexContainerImpl.SetFlexDirection(flexDirection);
361 case Toolkit::FlexContainer::Property::FLEX_WRAP:
363 Toolkit::FlexContainer::WrapType flexWrap( Toolkit::FlexContainer::NO_WRAP );
365 if( value.GetType() == Property::INTEGER )
367 flexContainerImpl.SetFlexWrap( static_cast<Toolkit::FlexContainer::WrapType>( value.Get< int >() ) );
369 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::WrapType >( value.Get< std::string >().c_str(),
370 FLEX_WRAP_STRING_TABLE,
371 FLEX_WRAP_STRING_TABLE_COUNT,
374 flexContainerImpl.SetFlexWrap(flexWrap);
378 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
380 Toolkit::FlexContainer::Justification justifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START );
382 if( value.GetType() == Property::INTEGER )
384 flexContainerImpl.SetJustifyContent( static_cast<Toolkit::FlexContainer::Justification>( value.Get< int >() ) );
386 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Justification >( value.Get< std::string >().c_str(),
387 JUSTIFY_CONTENT_STRING_TABLE,
388 JUSTIFY_CONTENT_STRING_TABLE_COUNT,
391 flexContainerImpl.SetJustifyContent(justifyContent);
395 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
397 Toolkit::FlexContainer::Alignment alignItems( Toolkit::FlexContainer::ALIGN_STRETCH );
399 if( value.GetType() == Property::INTEGER )
401 flexContainerImpl.SetAlignItems( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
403 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
404 ALIGN_ITEMS_STRING_TABLE,
405 ALIGN_ITEMS_STRING_TABLE_COUNT,
408 flexContainerImpl.SetAlignItems(alignItems);
412 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
414 Toolkit::FlexContainer::Alignment alignContent( Toolkit::FlexContainer::ALIGN_FLEX_START );
416 if( value.GetType() == Property::INTEGER )
418 flexContainerImpl.SetAlignContent( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
420 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
421 ALIGN_CONTENT_STRING_TABLE,
422 ALIGN_CONTENT_STRING_TABLE_COUNT,
425 flexContainerImpl.SetAlignContent(alignContent);
433 Property::Value FlexContainer::GetProperty( BaseObject* object, Property::Index index )
435 Property::Value value;
437 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
441 FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
444 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
446 value = flexContainerImpl.GetContentDirection();
449 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
451 value = flexContainerImpl.GetFlexDirection();
454 case Toolkit::FlexContainer::Property::FLEX_WRAP:
456 value = flexContainerImpl.GetFlexWrap();
459 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
461 value = flexContainerImpl.GetJustifyContent();
464 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
466 value = flexContainerImpl.GetAlignItems();
469 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
471 value = flexContainerImpl.GetAlignContent();
480 void FlexContainer::OnChildAdd( Actor& child )
482 // Create a new node for the child.
483 FlexItemNode childNode;
484 childNode.actor = child;
485 childNode.node = YGNodeNew();
487 mChildrenNodes.push_back( childNode );
488 YGNodeInsertChild( mRootNode.node, childNode.node, mChildrenNodes.size() - 1 );
490 Control::OnChildAdd( child );
493 void FlexContainer::OnChildRemove( Actor& child )
495 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
497 if( mChildrenNodes[i].actor.GetHandle() == child )
499 YGNodeRemoveChild( mRootNode.node, mChildrenNodes[i].node );
500 YGNodeFree( mChildrenNodes[i].node );
502 mChildrenNodes.erase( mChildrenNodes.begin() + i );
504 // Relayout the container only if instances were found
510 Control::OnChildRemove( child );
513 void FlexContainer::OnRelayout( const Vector2& size, RelayoutContainer& container )
515 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
517 Actor child = mChildrenNodes[i].actor.GetHandle();
520 // Anchor actor to top left of the container
521 if( child.GetProperty( Actor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
523 child.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
525 child.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
527 float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
528 float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
530 if( negotiatedWidth > 0 )
532 YGNodeStyleSetWidth( mChildrenNodes[i].node, negotiatedWidth );
534 if( negotiatedHeight > 0 )
536 YGNodeStyleSetHeight( mChildrenNodes[i].node, negotiatedHeight );
541 // Relayout the container
543 #if defined(FLEX_CONTAINER_DEBUG)
544 PrintNodes( mChildrenNodes );
547 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
549 Actor child = mChildrenNodes[i].actor.GetHandle();
552 if( child.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
554 // Only Set to USE_ASSIGNED_SIZE if the child actor is flexible.
556 if( child.GetResizePolicy( Dimension::WIDTH ) != ResizePolicy::USE_ASSIGNED_SIZE )
558 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
560 if( child.GetResizePolicy( Dimension::HEIGHT ) != ResizePolicy::USE_ASSIGNED_SIZE )
562 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
565 container.Add( child, Vector2(YGNodeLayoutGetWidth(mChildrenNodes[i].node), YGNodeLayoutGetHeight(mChildrenNodes[i].node) ) );
570 bool FlexContainer::RelayoutDependentOnChildren( Dimension::Type dimension )
575 void FlexContainer::OnSizeSet( const Vector3& size )
580 YGNodeStyleSetWidth( mRootNode.node, size.x );
581 YGNodeStyleSetHeight( mRootNode.node, size.y );
586 Control::OnSizeSet( size );
589 void FlexContainer::OnLayoutDirectionChanged( Dali::Actor actor, Dali::LayoutDirection::Type type )
591 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(actor);
592 Toolkit::FlexContainer::ContentDirection direction;
594 if( type == Dali::LayoutDirection::RIGHT_TO_LEFT )
596 direction = Toolkit::FlexContainer::RTL;
600 direction = Toolkit::FlexContainer::LTR;
603 Toolkit::Internal::FlexContainer &flexContainerImpl = GetImpl( flexContainer );
605 if( flexContainerImpl.mContentDirection != direction )
607 Dali::CustomActor ownerActor(flexContainerImpl.GetOwner());
608 flexContainerImpl.mContentDirection = direction;
610 flexContainerImpl.RelayoutRequest();
614 void FlexContainer::ComputeLayout()
618 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
620 YGNodeRef childNode = mChildrenNodes[i].node;
621 Actor childActor = mChildrenNodes[i].actor.GetHandle();
623 // Intialize the style of the child.
624 YGNodeStyleSetMinWidth( childNode, childActor.GetProperty< Vector2 >( Actor::Property::MINIMUM_SIZE ).x );
625 YGNodeStyleSetMinHeight( childNode, childActor.GetProperty< Vector2 >( Actor::Property::MINIMUM_SIZE ).y );
626 YGNodeStyleSetMaxWidth( childNode, childActor.GetProperty< Vector2 >( Actor::Property::MAXIMUM_SIZE ).x );
627 YGNodeStyleSetMaxHeight( childNode, childActor.GetProperty< Vector2 >( Actor::Property::MAXIMUM_SIZE ).y );
629 // Check child properties on the child for how to layout it.
630 // These properties should be dynamically registered to the child which
631 // would be added to FlexContainer.
633 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
635 YGNodeStyleSetFlex( childNode, childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX ).Get<float>() );
638 Toolkit::FlexContainer::Alignment alignSelf( Toolkit::FlexContainer::ALIGN_AUTO );
639 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF ) != Property::NONE )
641 Property::Value alignSelfPropertyValue = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF );
642 if( alignSelfPropertyValue.GetType() == Property::INTEGER )
644 alignSelf = static_cast<Toolkit::FlexContainer::Alignment>( alignSelfPropertyValue.Get< int >() );
646 else if( alignSelfPropertyValue.GetType() == Property::STRING )
648 std::string value = alignSelfPropertyValue.Get<std::string>();
649 Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.c_str(),
650 ALIGN_SELF_STRING_TABLE,
651 ALIGN_SELF_STRING_TABLE_COUNT,
654 YGNodeStyleSetAlignSelf( childNode, static_cast<YGAlign>(alignSelf) );
657 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ) != Property::NONE )
659 Vector4 flexMargin = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ).Get<Vector4>();
660 YGNodeStyleSetMargin( childNode, YGEdgeLeft, flexMargin.x );
661 YGNodeStyleSetMargin( childNode, YGEdgeTop, flexMargin.y );
662 YGNodeStyleSetMargin( childNode, YGEdgeRight, flexMargin.z );
663 YGNodeStyleSetMargin( childNode, YGEdgeBottom, flexMargin.w );
667 // Calculate the layout
668 YGDirection nodeLayoutDirection = YGDirectionInherit;
669 switch( mContentDirection )
671 case Dali::Toolkit::FlexContainer::LTR:
673 nodeLayoutDirection = YGDirectionLTR;
677 case Dali::Toolkit::FlexContainer::RTL:
679 nodeLayoutDirection = YGDirectionRTL;
683 case Dali::Toolkit::FlexContainer::INHERIT:
685 nodeLayoutDirection = YGDirectionInherit;
690 #if defined(FLEX_CONTAINER_DEBUG)
691 YGNodePrint( mRootNode.node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren ) );
693 YGNodeCalculateLayout( mRootNode.node, Self().GetProperty< Vector2 >( Actor::Property::MAXIMUM_SIZE ).x, Self().GetProperty< Vector2 >( Actor::Property::MAXIMUM_SIZE ).y, nodeLayoutDirection );
694 #if defined(FLEX_CONTAINER_DEBUG)
695 YGNodePrint( mRootNode.node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren ) );
700 void FlexContainer::RelayoutChildren()
704 // Set size and position of children according to the layout calculation
705 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
707 Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
710 child.SetProperty( Actor::Property::POSITION_X, YGNodeLayoutGetLeft( mChildrenNodes[i].node ) );
711 child.SetProperty( Actor::Property::POSITION_Y, YGNodeLayoutGetTop( mChildrenNodes[i].node ) );
716 Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
718 Actor nextFocusableActor;
720 // First check whether there is any items in the container
721 if( mChildrenNodes.size() > 0 )
723 if ( !currentFocusedActor || currentFocusedActor == Self() )
725 // Nothing is currently focused, so the first child in the container should be focused.
726 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
730 // Check whether the current focused actor is within flex container
731 int currentFocusedActorIndex = -1;
732 for( unsigned int index = 0; index < mChildrenNodes.size(); index++ )
734 if( currentFocusedActor == mChildrenNodes[index].actor.GetHandle() )
736 currentFocusedActorIndex = index;
741 if( currentFocusedActorIndex > -1 )
743 int previousCheckedActorIndex = -1;
744 int nextFocusedActorIndex = currentFocusedActorIndex;
747 case Toolkit::Control::KeyboardFocus::LEFT:
748 case Toolkit::Control::KeyboardFocus::UP:
750 // Search the next focusable actor in the backward direction
753 nextFocusedActorIndex--;
754 if( nextFocusedActorIndex < 0 )
756 nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
758 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
760 previousCheckedActorIndex = nextFocusedActorIndex;
766 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) );
769 case Toolkit::Control::KeyboardFocus::RIGHT:
770 case Toolkit::Control::KeyboardFocus::DOWN:
772 // Search the next focusable actor in the forward direction
775 nextFocusedActorIndex++;
776 if( nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1) )
778 nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
780 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
782 previousCheckedActorIndex = nextFocusedActorIndex;
788 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) );
797 if( nextFocusedActorIndex != currentFocusedActorIndex )
799 nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
803 // No focusble child in the container
804 nextFocusableActor = Actor();
809 // The current focused actor is not within flex container, so the first child in the container should be focused.
810 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
815 return nextFocusableActor;
818 FlexContainer::FlexContainer()
819 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
820 mContentDirection( Toolkit::FlexContainer::INHERIT ),
821 mFlexDirection( Toolkit::FlexContainer::COLUMN ),
822 mFlexWrap( Toolkit::FlexContainer::NO_WRAP ),
823 mJustifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START ),
824 mAlignItems( Toolkit::FlexContainer::ALIGN_STRETCH ),
825 mAlignContent( Toolkit::FlexContainer::ALIGN_FLEX_START )
827 SetKeyboardNavigationSupport( true );
830 void FlexContainer::OnInitialize()
832 // Initialize the node for the flex container itself
833 Dali::Actor self = Self();
834 self.LayoutDirectionChangedSignal().Connect( this, &FlexContainer::OnLayoutDirectionChanged );
836 mRootNode.actor = self;
837 mRootNode.node = YGNodeNew();
838 YGNodeSetContext( mRootNode.node, &mChildrenNodes );
841 YGNodeStyleSetFlexDirection( mRootNode.node, static_cast<YGFlexDirection>( mFlexDirection ) );
842 YGNodeStyleSetFlexWrap( mRootNode.node, static_cast<YGWrap>( mFlexWrap ) );
843 YGNodeStyleSetJustifyContent( mRootNode.node, static_cast<YGJustify>( mJustifyContent ) );
844 YGNodeStyleSetAlignItems( mRootNode.node, static_cast<YGAlign>( mAlignItems ) );
845 YGNodeStyleSetAlignContent( mRootNode.node, static_cast<YGAlign>( mAlignContent ) );
847 // Make self as keyboard focusable and focus group
848 self.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE, true );
849 SetAsKeyboardFocusGroup( true );
851 DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) {
852 return std::unique_ptr< Dali::Accessibility::Accessible >(
853 new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) );
857 } // namespace Internal
859 } // namespace Toolkit