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 PrintNode( 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 print_css_node( itemNodes[i].node, (css_print_options_t)( CSS_PRINT_STYLE | CSS_PRINT_CHILDREN ) );
52 FC_LOG( "Item %d layout: \n", i );
53 print_css_node( itemNodes[i].node, (css_print_options_t)( CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN ) );
58 #endif // defined(FLEX_CONTAINER_DEBUG)
59 #endif // defined(DEBUG_ENABLED)
79 return Toolkit::FlexContainer::New();
82 // Setup properties, signals and actions using the type-registry.
83 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::FlexContainer, Toolkit::Control, Create );
85 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "contentDirection", INTEGER, CONTENT_DIRECTION )
86 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexDirection", INTEGER, FLEX_DIRECTION )
87 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexWrap", INTEGER, FLEX_WRAP )
88 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "justifyContent", INTEGER, JUSTIFY_CONTENT )
89 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignItems", INTEGER, ALIGN_ITEMS )
90 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignContent", INTEGER, ALIGN_CONTENT )
91 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flex", FLOAT, FLEX )
92 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignSelf", INTEGER, ALIGN_SELF )
93 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexMargin", VECTOR4, FLEX_MARGIN )
95 DALI_TYPE_REGISTRATION_END()
97 const Scripting::StringEnum ALIGN_SELF_STRING_TABLE[] =
99 { "auto", Toolkit::FlexContainer::ALIGN_AUTO },
100 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
101 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
102 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
103 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
105 const unsigned int ALIGN_SELF_STRING_TABLE_COUNT = sizeof( ALIGN_SELF_STRING_TABLE ) / sizeof( ALIGN_SELF_STRING_TABLE[0] );
107 const Scripting::StringEnum CONTENT_DIRECTION_STRING_TABLE[] =
109 { "inherit", Toolkit::FlexContainer::INHERIT },
110 { "LTR", Toolkit::FlexContainer::LTR },
111 { "RTL", Toolkit::FlexContainer::RTL }
113 const unsigned int CONTENT_DIRECTION_STRING_TABLE_COUNT = sizeof( CONTENT_DIRECTION_STRING_TABLE ) / sizeof( CONTENT_DIRECTION_STRING_TABLE[0] );
115 const Scripting::StringEnum FLEX_DIRECTION_STRING_TABLE[] =
117 { "column", Toolkit::FlexContainer::COLUMN },
118 { "columnReverse", Toolkit::FlexContainer::COLUMN_REVERSE },
119 { "row", Toolkit::FlexContainer::ROW },
120 { "rowReverse", Toolkit::FlexContainer::ROW_REVERSE }
122 const unsigned int FLEX_DIRECTION_STRING_TABLE_COUNT = sizeof( FLEX_DIRECTION_STRING_TABLE ) / sizeof( FLEX_DIRECTION_STRING_TABLE[0] );
124 const Scripting::StringEnum FLEX_WRAP_STRING_TABLE[] =
126 { "noWrap", Toolkit::FlexContainer::NO_WRAP },
127 { "wrap", Toolkit::FlexContainer::WRAP }
129 const unsigned int FLEX_WRAP_STRING_TABLE_COUNT = sizeof( FLEX_WRAP_STRING_TABLE ) / sizeof( FLEX_WRAP_STRING_TABLE[0] );
131 const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
133 { "flexStart", Toolkit::FlexContainer::JUSTIFY_FLEX_START },
134 { "center", Toolkit::FlexContainer::JUSTIFY_CENTER },
135 { "flexEnd", Toolkit::FlexContainer::JUSTIFY_FLEX_END },
136 { "spaceBetween", Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN },
137 { "spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND }
139 const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof( JUSTIFY_CONTENT_STRING_TABLE ) / sizeof( JUSTIFY_CONTENT_STRING_TABLE[0] );
141 const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
143 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
144 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
145 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
146 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
148 const unsigned int ALIGN_ITEMS_STRING_TABLE_COUNT = sizeof( ALIGN_ITEMS_STRING_TABLE ) / sizeof( ALIGN_ITEMS_STRING_TABLE[0] );
150 const Scripting::StringEnum ALIGN_CONTENT_STRING_TABLE[] =
152 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
153 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
154 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
155 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
157 const unsigned int ALIGN_CONTENT_STRING_TABLE_COUNT = sizeof( ALIGN_CONTENT_STRING_TABLE ) / sizeof( ALIGN_CONTENT_STRING_TABLE[0] );
160 * The function used by the layout algorithm to be get the style properties
161 * and layout information of the child at the given index.
163 css_node_t* GetChildNodeAtIndex( void *childrenNodes, int i )
165 FlexContainer::FlexItemNodeContainer childrenNodeContainer = *( static_cast<FlexContainer::FlexItemNodeContainer*>( childrenNodes ) );
166 return childrenNodeContainer[i].node;
170 * The function used by the layout algorithm to check whether the node is dirty
173 bool IsNodeDirty( void *itemNodes )
175 // We only calculate the layout when the child is added or removed, or when
176 // style properties are changed. So should always return true here.
179 } // Unnamed namespace
181 Toolkit::FlexContainer FlexContainer::New()
183 // Create the implementation, temporarily owned by this handle on stack
184 IntrusivePtr< FlexContainer > impl = new FlexContainer();
186 // Pass ownership to CustomActor handle
187 Toolkit::FlexContainer handle( *impl );
189 // Second-phase init of the implementation
190 // This can only be done after the CustomActor connection has been made...
196 FlexContainer::~FlexContainer()
198 free_css_node( mRootNode.node );
200 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
202 free_css_node( mChildrenNodes[i].node );
205 mChildrenNodes.clear();
208 void FlexContainer::SetContentDirection( Toolkit::FlexContainer::ContentDirection contentDirection)
210 if( mContentDirection != contentDirection )
212 Dali::CustomActor ownerActor(GetOwner());
214 if( Toolkit::FlexContainer::INHERIT != contentDirection )
216 mContentDirection = contentDirection;
218 ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, false );
220 if( Toolkit::FlexContainer::LTR == contentDirection )
222 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT);
226 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT);
231 ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, true );
233 Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( ownerActor.GetParent().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
235 if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
237 mContentDirection = Toolkit::FlexContainer::RTL;
241 mContentDirection = Toolkit::FlexContainer::LTR;
249 Toolkit::FlexContainer::ContentDirection FlexContainer::GetContentDirection()
251 return mContentDirection;
254 void FlexContainer::SetFlexDirection( Toolkit::FlexContainer::FlexDirection flexDirection )
256 if( mFlexDirection != flexDirection )
258 mFlexDirection = flexDirection;
259 mRootNode.node->style.flex_direction = static_cast<css_flex_direction_t>( mFlexDirection );
265 Toolkit::FlexContainer::FlexDirection FlexContainer::GetFlexDirection()
267 return mFlexDirection;
270 void FlexContainer::SetFlexWrap( Toolkit::FlexContainer::WrapType flexWrap )
272 if( mFlexWrap != flexWrap )
274 mFlexWrap = flexWrap;
275 mRootNode.node->style.flex_wrap = static_cast<css_wrap_type_t>( mFlexWrap );
281 Toolkit::FlexContainer::WrapType FlexContainer::GetFlexWrap()
286 void FlexContainer::SetJustifyContent( Toolkit::FlexContainer::Justification justifyContent )
288 if( mJustifyContent != justifyContent )
290 mJustifyContent = justifyContent;
291 mRootNode.node->style.justify_content = static_cast<css_justify_t>( mJustifyContent );
297 Toolkit::FlexContainer::Justification FlexContainer::GetJustifyContent()
299 return mJustifyContent;
302 void FlexContainer::SetAlignItems( Toolkit::FlexContainer::Alignment alignItems )
304 if( mAlignItems != alignItems )
306 mAlignItems = alignItems;
307 mRootNode.node->style.align_items = static_cast<css_align_t>( mAlignItems );
313 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignItems()
318 void FlexContainer::SetAlignContent( Toolkit::FlexContainer::Alignment alignContent )
320 if( mAlignContent != alignContent )
322 mAlignContent = alignContent;
323 mRootNode.node->style.align_content = static_cast<css_align_t>( mAlignContent );
329 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignContent()
331 return mAlignContent;
334 void FlexContainer::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
336 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
340 FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
343 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
345 Toolkit::FlexContainer::ContentDirection contentDirection( Toolkit::FlexContainer::INHERIT );
347 if( value.GetType() == Property::INTEGER )
349 flexContainerImpl.SetContentDirection( static_cast<Toolkit::FlexContainer::ContentDirection>( value.Get< int >() ) );
351 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::ContentDirection >( value.Get< std::string >().c_str(),
352 CONTENT_DIRECTION_STRING_TABLE,
353 CONTENT_DIRECTION_STRING_TABLE_COUNT,
356 flexContainerImpl.SetContentDirection(contentDirection);
360 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
362 Toolkit::FlexContainer::FlexDirection flexDirection( Toolkit::FlexContainer::COLUMN );
364 if( value.GetType() == Property::INTEGER )
366 flexContainerImpl.SetFlexDirection( static_cast<Toolkit::FlexContainer::FlexDirection>( value.Get< int >() ) );
368 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::FlexDirection >( value.Get< std::string >().c_str(),
369 FLEX_DIRECTION_STRING_TABLE,
370 FLEX_DIRECTION_STRING_TABLE_COUNT,
373 flexContainerImpl.SetFlexDirection(flexDirection);
377 case Toolkit::FlexContainer::Property::FLEX_WRAP:
379 Toolkit::FlexContainer::WrapType flexWrap( Toolkit::FlexContainer::NO_WRAP );
381 if( value.GetType() == Property::INTEGER )
383 flexContainerImpl.SetFlexWrap( static_cast<Toolkit::FlexContainer::WrapType>( value.Get< int >() ) );
385 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::WrapType >( value.Get< std::string >().c_str(),
386 FLEX_WRAP_STRING_TABLE,
387 FLEX_WRAP_STRING_TABLE_COUNT,
390 flexContainerImpl.SetFlexWrap(flexWrap);
394 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
396 Toolkit::FlexContainer::Justification justifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START );
398 if( value.GetType() == Property::INTEGER )
400 flexContainerImpl.SetJustifyContent( static_cast<Toolkit::FlexContainer::Justification>( value.Get< int >() ) );
402 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Justification >( value.Get< std::string >().c_str(),
403 JUSTIFY_CONTENT_STRING_TABLE,
404 JUSTIFY_CONTENT_STRING_TABLE_COUNT,
407 flexContainerImpl.SetJustifyContent(justifyContent);
411 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
413 Toolkit::FlexContainer::Alignment alignItems( Toolkit::FlexContainer::ALIGN_STRETCH );
415 if( value.GetType() == Property::INTEGER )
417 flexContainerImpl.SetAlignItems( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
419 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
420 ALIGN_ITEMS_STRING_TABLE,
421 ALIGN_ITEMS_STRING_TABLE_COUNT,
424 flexContainerImpl.SetAlignItems(alignItems);
428 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
430 Toolkit::FlexContainer::Alignment alignContent( Toolkit::FlexContainer::ALIGN_FLEX_START );
432 if( value.GetType() == Property::INTEGER )
434 flexContainerImpl.SetAlignContent( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
436 else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
437 ALIGN_CONTENT_STRING_TABLE,
438 ALIGN_CONTENT_STRING_TABLE_COUNT,
441 flexContainerImpl.SetAlignContent(alignContent);
449 Property::Value FlexContainer::GetProperty( BaseObject* object, Property::Index index )
451 Property::Value value;
453 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
457 FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
460 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
462 value = flexContainerImpl.GetContentDirection();
465 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
467 value = flexContainerImpl.GetFlexDirection();
470 case Toolkit::FlexContainer::Property::FLEX_WRAP:
472 value = flexContainerImpl.GetFlexWrap();
475 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
477 value = flexContainerImpl.GetJustifyContent();
480 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
482 value = flexContainerImpl.GetAlignItems();
485 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
487 value = flexContainerImpl.GetAlignContent();
496 void FlexContainer::OnChildAdd( Actor& child )
498 // Create a new node for the child.
499 FlexItemNode childNode;
500 childNode.actor = child;
501 childNode.node = new_css_node();
502 childNode.node->get_child = GetChildNodeAtIndex;
503 childNode.node->is_dirty = IsNodeDirty;
504 mChildrenNodes.push_back(childNode);
506 Control::OnChildAdd( child );
509 void FlexContainer::OnChildRemove( Actor& child )
511 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
513 if( mChildrenNodes[i].actor.GetHandle() == child )
515 free_css_node( mChildrenNodes[i].node );
516 mChildrenNodes.erase( mChildrenNodes.begin() + i );
518 // Relayout the container only if instances were found
524 Control::OnChildRemove( child );
527 void FlexContainer::OnRelayout( const Vector2& size, RelayoutContainer& container )
529 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
531 Actor child = mChildrenNodes[i].actor.GetHandle();
534 // Anchor actor to top left of the container
535 if( child.GetProperty( DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
537 child.SetAnchorPoint( AnchorPoint::TOP_LEFT );
539 child.SetParentOrigin( ParentOrigin::TOP_LEFT );
541 float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
542 float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
544 if( negotiatedWidth > 0 )
546 mChildrenNodes[i].node->style.dimensions[CSS_WIDTH] = negotiatedWidth;
548 if( negotiatedHeight > 0 )
550 mChildrenNodes[i].node->style.dimensions[CSS_HEIGHT] = negotiatedHeight;
555 // Relayout the container
558 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
560 Actor child = mChildrenNodes[i].actor.GetHandle();
563 if( child.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
565 // Only Set to USE_ASSIGNED_SIZE if the child actor is flexible.
567 if( child.GetResizePolicy( Dimension::WIDTH ) != ResizePolicy::USE_ASSIGNED_SIZE )
569 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
571 if( child.GetResizePolicy( Dimension::HEIGHT ) != ResizePolicy::USE_ASSIGNED_SIZE )
573 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
577 container.Add( child, Vector2(mChildrenNodes[i].node->layout.dimensions[CSS_WIDTH], mChildrenNodes[i].node->layout.dimensions[CSS_HEIGHT] ) );
582 bool FlexContainer::RelayoutDependentOnChildren( Dimension::Type dimension )
587 void FlexContainer::OnSizeSet( const Vector3& size )
593 mRootNode.node->style.dimensions[CSS_WIDTH] = size.x;
594 mRootNode.node->style.dimensions[CSS_HEIGHT] = size.y;
599 Control::OnSizeSet( size );
602 void FlexContainer::OnLayoutDirectionChanged( Dali::Actor actor, Dali::LayoutDirection::Type type )
604 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(actor);
605 Toolkit::FlexContainer::ContentDirection direction;
607 if( type == Dali::LayoutDirection::RIGHT_TO_LEFT )
609 direction = Toolkit::FlexContainer::RTL;
613 direction = Toolkit::FlexContainer::LTR;
616 Toolkit::Internal::FlexContainer &flexContainerImpl = GetImpl( flexContainer );
618 if( flexContainerImpl.mContentDirection != direction )
620 Dali::CustomActor ownerActor(flexContainerImpl.GetOwner());
621 flexContainerImpl.mContentDirection = direction;
623 flexContainerImpl.RelayoutRequest();
627 void FlexContainer::ComputeLayout()
631 mRootNode.node->children_count = mChildrenNodes.size();
633 // Intialize the layout.
634 mRootNode.node->layout.position[CSS_LEFT] = 0;
635 mRootNode.node->layout.position[CSS_TOP] = 0;
636 mRootNode.node->layout.position[CSS_BOTTOM] = 0;
637 mRootNode.node->layout.position[CSS_RIGHT] = 0;
638 mRootNode.node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
639 mRootNode.node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
641 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
643 css_node_t* childNode = mChildrenNodes[i].node;
644 Actor childActor = mChildrenNodes[i].actor.GetHandle();
646 childNode->layout.position[CSS_LEFT] = 0;
647 childNode->layout.position[CSS_TOP] = 0;
648 childNode->layout.position[CSS_BOTTOM] = 0;
649 childNode->layout.position[CSS_RIGHT] = 0;
650 childNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
651 childNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
653 // Intialize the style of the child.
654 childNode->style.minDimensions[CSS_WIDTH] = childActor.GetMinimumSize().x;
655 childNode->style.minDimensions[CSS_HEIGHT] = childActor.GetMinimumSize().y;
656 childNode->style.maxDimensions[CSS_WIDTH] = childActor.GetMaximumSize().x;
657 childNode->style.maxDimensions[CSS_HEIGHT] = childActor.GetMaximumSize().y;
659 // Check child properties on the child for how to layout it.
660 // These properties should be dynamically registered to the child which
661 // would be added to FlexContainer.
663 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
665 childNode->style.flex = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX ).Get<float>();
668 Toolkit::FlexContainer::Alignment alignSelf( Toolkit::FlexContainer::ALIGN_AUTO );
669 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF ) != Property::NONE )
671 Property::Value alignSelfPropertyValue = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF );
672 if( alignSelfPropertyValue.GetType() == Property::INTEGER )
674 alignSelf = static_cast<Toolkit::FlexContainer::Alignment>( alignSelfPropertyValue.Get< int >() );
676 else if( alignSelfPropertyValue.GetType() == Property::STRING )
678 std::string value = alignSelfPropertyValue.Get<std::string>();
679 Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.c_str(),
680 ALIGN_SELF_STRING_TABLE,
681 ALIGN_SELF_STRING_TABLE_COUNT,
685 childNode->style.align_self = static_cast<css_align_t>(alignSelf);
687 if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ) != Property::NONE )
689 Vector4 flexMargin = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ).Get<Vector4>();
690 childNode->style.margin[CSS_LEFT] = flexMargin.x;
691 childNode->style.margin[CSS_TOP] = flexMargin.y;
692 childNode->style.margin[CSS_RIGHT] = flexMargin.z;
693 childNode->style.margin[CSS_BOTTOM] = flexMargin.w;
697 // Calculate the layout
698 css_direction_t nodeLayoutDirection = CSS_DIRECTION_INHERIT;
699 switch( mContentDirection )
701 case Dali::Toolkit::FlexContainer::LTR:
703 nodeLayoutDirection = CSS_DIRECTION_LTR;
707 case Dali::Toolkit::FlexContainer::RTL:
709 nodeLayoutDirection = CSS_DIRECTION_RTL;
713 case Dali::Toolkit::FlexContainer::INHERIT:
715 nodeLayoutDirection = CSS_DIRECTION_INHERIT;
720 layoutNode( mRootNode.node, Self().GetMaximumSize().x, Self().GetMaximumSize().y, nodeLayoutDirection);
724 void FlexContainer::RelayoutChildren()
728 // Set size and position of children according to the layout calculation
729 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
731 Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
734 child.SetX( mChildrenNodes[i].node->layout.position[CSS_LEFT] );
735 child.SetY( mChildrenNodes[i].node->layout.position[CSS_TOP] );
740 Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
742 Actor nextFocusableActor;
744 // First check whether there is any items in the container
745 if( mChildrenNodes.size() > 0 )
747 if ( !currentFocusedActor || currentFocusedActor == Self() )
749 // Nothing is currently focused, so the first child in the container should be focused.
750 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
754 // Check whether the current focused actor is within flex container
755 int currentFocusedActorIndex = -1;
756 for( unsigned int index = 0; index < mChildrenNodes.size(); index++ )
758 if( currentFocusedActor == mChildrenNodes[index].actor.GetHandle() )
760 currentFocusedActorIndex = index;
765 if( currentFocusedActorIndex > -1 )
767 int previousCheckedActorIndex = -1;
768 int nextFocusedActorIndex = currentFocusedActorIndex;
771 case Toolkit::Control::KeyboardFocus::LEFT:
772 case Toolkit::Control::KeyboardFocus::UP:
774 // Search the next focusable actor in the backward direction
777 nextFocusedActorIndex--;
778 if( nextFocusedActorIndex < 0 )
780 nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
782 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
784 previousCheckedActorIndex = nextFocusedActorIndex;
790 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
793 case Toolkit::Control::KeyboardFocus::RIGHT:
794 case Toolkit::Control::KeyboardFocus::DOWN:
796 // Search the next focusable actor in the forward direction
799 nextFocusedActorIndex++;
800 if( nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1) )
802 nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
804 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
806 previousCheckedActorIndex = nextFocusedActorIndex;
812 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
821 if( nextFocusedActorIndex != currentFocusedActorIndex )
823 nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
827 // No focusble child in the container
828 nextFocusableActor = Actor();
833 // The current focused actor is not within flex container, so the first child in the container should be focused.
834 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
839 return nextFocusableActor;
842 FlexContainer::FlexContainer()
843 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
844 mContentDirection( Toolkit::FlexContainer::INHERIT ),
845 mFlexDirection( Toolkit::FlexContainer::COLUMN ),
846 mFlexWrap( Toolkit::FlexContainer::NO_WRAP ),
847 mJustifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START ),
848 mAlignItems( Toolkit::FlexContainer::ALIGN_STRETCH ),
849 mAlignContent( Toolkit::FlexContainer::ALIGN_FLEX_START )
851 SetKeyboardNavigationSupport( true );
854 void FlexContainer::OnInitialize()
856 // Initialize the node for the flex container itself
857 Dali::Actor self = Self();
858 self.LayoutDirectionChangedSignal().Connect( this, &FlexContainer::OnLayoutDirectionChanged );
860 mRootNode.actor = self;
861 mRootNode.node = new_css_node();
862 mRootNode.node->context = &mChildrenNodes;
865 mRootNode.node->style.direction = static_cast<css_direction_t>( mContentDirection );
866 mRootNode.node->style.flex_direction = static_cast<css_flex_direction_t>( mFlexDirection );
867 mRootNode.node->style.flex_wrap = static_cast<css_wrap_type_t>( mFlexWrap );
868 mRootNode.node->style.justify_content = static_cast<css_justify_t>( mJustifyContent );
869 mRootNode.node->style.align_items = static_cast<css_align_t>( mAlignItems );
870 mRootNode.node->style.align_content = static_cast<css_align_t>( mAlignContent );
873 mRootNode.node->get_child = GetChildNodeAtIndex;
874 mRootNode.node->is_dirty = IsNodeDirty;
876 // Make self as keyboard focusable and focus group
877 self.SetKeyboardFocusable( true );
878 SetAsKeyboardFocusGroup( true );
881 } // namespace Internal
883 } // namespace Toolkit