2 * Copyright (c) 2016 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/devel-api/object/type-registry-helper.h>
26 #include <dali/devel-api/scripting/scripting.h>
27 #include <dali/public-api/size-negotiation/relayout-container.h>
28 #include <dali/integration-api/debug.h>
35 * Custom properties for how to lay out the actor.
37 * When an actor is add to the flex container, the following custom properties of the actor
38 * are checked to decide how to lay out the actor inside the flex container.
40 * These non-animatable properties should be registered to the child which would be added
41 * to the flex container, and once added their values can not be changed.
43 const char * const FLEX_PROPERTY_NAME("flex");
44 const char * const ALIGN_SELF_PROPERTY_NAME("alignSelf");
45 const char * const FLEX_PADDING_PROPERTY_NAME("flexPadding");
46 const char * const FLEX_BORDER_PROPERTY_NAME("flexBorder");
47 const char * const FLEX_MARGIN_PROPERTY_NAME("flexMargin");
49 #if defined(DEBUG_ENABLED)
50 // debugging support, very useful when new features are added or bugs are hunted down
51 // currently not called from code so compiler will optimize these away, kept here for future debugging
53 #define FLEX_CONTAINER_TAG "DALI Toolkit::FlexContainer "
54 #define FC_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, FLEX_CONTAINER_TAG fmt, ## args)
55 //#define FLEX_CONTAINER_DEBUG 1
57 #if defined(FLEX_CONTAINER_DEBUG)
58 void PrintNode( Toolkit::Internal::FlexContainer::FlexItemNodeContainer itemNodes )
60 // Print the style property and layout of all the children
61 for( unsigned int i = 0; i < itemNodes.size(); ++i )
63 FC_LOG( "Item %d style: \n", i );
64 print_css_node( itemNodes[i].node, (css_print_options_t)( CSS_PRINT_STYLE | CSS_PRINT_CHILDREN ) );
65 FC_LOG( "Item %d layout: \n", i );
66 print_css_node( itemNodes[i].node, (css_print_options_t)( CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN ) );
71 #endif // defined(FLEX_CONTAINER_DEBUG)
72 #endif // defined(DEBUG_ENABLED)
92 return Toolkit::FlexContainer::New();
95 // Setup properties, signals and actions using the type-registry.
96 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::FlexContainer, Toolkit::Control, Create );
98 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "contentDirection", INTEGER, CONTENT_DIRECTION )
99 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexDirection", INTEGER, FLEX_DIRECTION )
100 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexWrap", INTEGER, FLEX_WRAP )
101 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "justifyContent", INTEGER, JUSTIFY_CONTENT )
102 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignItems", INTEGER, ALIGN_ITEMS )
103 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignContent", INTEGER, ALIGN_CONTENT )
105 DALI_TYPE_REGISTRATION_END()
107 const Scripting::StringEnum ALIGN_SELF_STRING_TABLE[] =
109 { "auto", Toolkit::FlexContainer::ALIGN_AUTO },
110 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
111 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
112 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
113 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
115 const unsigned int ALIGN_SELF_STRING_TABLE_COUNT = sizeof( ALIGN_SELF_STRING_TABLE ) / sizeof( ALIGN_SELF_STRING_TABLE[0] );
117 const Scripting::StringEnum CONTENT_DIRECTION_STRING_TABLE[] =
119 { "inherit", Toolkit::FlexContainer::INHERIT },
120 { "LTR", Toolkit::FlexContainer::LTR },
121 { "RTL", Toolkit::FlexContainer::RTL }
123 const unsigned int CONTENT_DIRECTION_STRING_TABLE_COUNT = sizeof( CONTENT_DIRECTION_STRING_TABLE ) / sizeof( CONTENT_DIRECTION_STRING_TABLE[0] );
125 const Scripting::StringEnum FLEX_DIRECTION_STRING_TABLE[] =
127 { "column", Toolkit::FlexContainer::COLUMN },
128 { "columnReverse", Toolkit::FlexContainer::COLUMN_REVERSE },
129 { "row", Toolkit::FlexContainer::ROW },
130 { "rowReverse", Toolkit::FlexContainer::ROW_REVERSE }
132 const unsigned int FLEX_DIRECTION_STRING_TABLE_COUNT = sizeof( FLEX_DIRECTION_STRING_TABLE ) / sizeof( FLEX_DIRECTION_STRING_TABLE[0] );
134 const Scripting::StringEnum FLEX_WRAP_STRING_TABLE[] =
136 { "noWrap", Toolkit::FlexContainer::NO_WRAP },
137 { "wrap", Toolkit::FlexContainer::WRAP }
139 const unsigned int FLEX_WRAP_STRING_TABLE_COUNT = sizeof( FLEX_WRAP_STRING_TABLE ) / sizeof( FLEX_WRAP_STRING_TABLE[0] );
141 const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
143 { "flexStart", Toolkit::FlexContainer::JUSTIFY_FLEX_START },
144 { "center", Toolkit::FlexContainer::JUSTIFY_CENTER },
145 { "flexEnd", Toolkit::FlexContainer::JUSTIFY_FLEX_END },
146 { "spaceBetween", Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN },
147 { "spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND }
149 const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof( JUSTIFY_CONTENT_STRING_TABLE ) / sizeof( JUSTIFY_CONTENT_STRING_TABLE[0] );
151 const Scripting::StringEnum ALIGN_ITEMS_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_ITEMS_STRING_TABLE_COUNT = sizeof( ALIGN_ITEMS_STRING_TABLE ) / sizeof( ALIGN_ITEMS_STRING_TABLE[0] );
160 const Scripting::StringEnum ALIGN_CONTENT_STRING_TABLE[] =
162 { "flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START },
163 { "center", Toolkit::FlexContainer::ALIGN_CENTER },
164 { "flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END },
165 { "stretch", Toolkit::FlexContainer::ALIGN_STRETCH }
167 const unsigned int ALIGN_CONTENT_STRING_TABLE_COUNT = sizeof( ALIGN_CONTENT_STRING_TABLE ) / sizeof( ALIGN_CONTENT_STRING_TABLE[0] );
170 * The function used by the layout algorithm to be get the style properties
171 * and layout information of the child at the given index.
173 css_node_t* GetChildNodeAtIndex( void *childrenNodes, int i )
175 FlexContainer::FlexItemNodeContainer childrenNodeContainer = *( static_cast<FlexContainer::FlexItemNodeContainer*>( childrenNodes ) );
176 return childrenNodeContainer[i].node;
180 * The function used by the layout algorithm to check whether the node is dirty
183 bool IsNodeDirty( void *itemNodes )
185 // We only calculate the layout when the child is added or removed, or when
186 // style properties are changed. So should always return true here.
190 } // Unnamed namespace
192 Toolkit::FlexContainer FlexContainer::New()
194 // Create the implementation, temporarily owned by this handle on stack
195 IntrusivePtr< FlexContainer > impl = new FlexContainer();
197 // Pass ownership to CustomActor handle
198 Toolkit::FlexContainer handle( *impl );
200 // Second-phase init of the implementation
201 // This can only be done after the CustomActor connection has been made...
207 FlexContainer::~FlexContainer()
209 free_css_node( mRootNode.node );
211 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
213 free_css_node( mChildrenNodes[i].node );
216 mChildrenNodes.clear();
219 void FlexContainer::SetContentDirection( Toolkit::FlexContainer::ContentDirection contentDirection )
221 if( mContentDirection != contentDirection )
223 mContentDirection = contentDirection;
224 mRootNode.node->style.direction = static_cast<css_direction_t>( mContentDirection );
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 mRootNode.node->style.flex_direction = static_cast<css_flex_direction_t>( mFlexDirection );
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 mRootNode.node->style.flex_wrap = static_cast<css_wrap_type_t>( mFlexWrap );
262 Toolkit::FlexContainer::WrapType FlexContainer::GetFlexWrap()
267 void FlexContainer::SetJustifyContent( Toolkit::FlexContainer::Justification justifyContent )
269 if( mJustifyContent != justifyContent )
271 mJustifyContent = justifyContent;
272 mRootNode.node->style.justify_content = static_cast<css_justify_t>( mJustifyContent );
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 mRootNode.node->style.align_items = static_cast<css_align_t>( mAlignItems );
294 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignItems()
299 void FlexContainer::SetAlignContent( Toolkit::FlexContainer::Alignment alignContent )
301 if( mAlignContent != alignContent )
303 mAlignContent = alignContent;
304 mRootNode.node->style.align_content = static_cast<css_align_t>( mAlignContent );
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 Control::OnChildAdd( child );
481 // Anchor actor to top left of the container
482 child.SetAnchorPoint( AnchorPoint::TOP_LEFT );
483 child.SetParentOrigin( ParentOrigin::TOP_LEFT );
485 // Create a new node for the child.
486 FlexItemNode childNode;
487 childNode.actor = child;
488 childNode.node = new_css_node();
489 childNode.node->get_child = GetChildNodeAtIndex;
490 childNode.node->is_dirty = IsNodeDirty;
491 mChildrenNodes.push_back(childNode);
494 void FlexContainer::OnChildRemove( Actor& child )
496 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
498 if( mChildrenNodes[i].actor.GetHandle() == child )
500 free_css_node( mChildrenNodes[i].node );
501 mChildrenNodes.erase( mChildrenNodes.begin() + i );
503 // Relayout the container only if instances were found
509 Control::OnChildRemove( child );
512 void FlexContainer::OnRelayout( const Vector2& size, RelayoutContainer& container )
514 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
516 Actor child = mChildrenNodes[i].actor.GetHandle();
519 float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
520 float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
522 if( negotiatedWidth > 0 )
524 mChildrenNodes[i].node->style.dimensions[CSS_WIDTH] = negotiatedWidth;
526 if( negotiatedHeight > 0 )
528 mChildrenNodes[i].node->style.dimensions[CSS_HEIGHT] = negotiatedHeight;
533 // Relayout the container
536 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
538 Actor child = mChildrenNodes[i].actor.GetHandle();
541 if( child.GetResizePolicy( Dimension::WIDTH ) != ResizePolicy::USE_ASSIGNED_SIZE )
543 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
545 if( child.GetResizePolicy( Dimension::HEIGHT ) != ResizePolicy::USE_ASSIGNED_SIZE )
547 child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
550 container.Add( child, Vector2(mChildrenNodes[i].node->layout.dimensions[CSS_WIDTH], mChildrenNodes[i].node->layout.dimensions[CSS_HEIGHT] ) );
555 bool FlexContainer::RelayoutDependentOnChildren( Dimension::Type dimension )
560 void FlexContainer::OnSizeSet( const Vector3& size )
566 mRootNode.node->style.dimensions[CSS_WIDTH] = size.x;
567 mRootNode.node->style.dimensions[CSS_HEIGHT] = size.y;
573 void FlexContainer::OnSizeAnimation( Animation& animation, const Vector3& targetSize )
575 // @todo Animate the children to their target size and position
578 void FlexContainer::ComputeLayout()
582 mRootNode.node->children_count = mChildrenNodes.size();
584 // Intialize the layout.
585 mRootNode.node->layout.position[CSS_LEFT] = 0;
586 mRootNode.node->layout.position[CSS_TOP] = 0;
587 mRootNode.node->layout.position[CSS_BOTTOM] = 0;
588 mRootNode.node->layout.position[CSS_RIGHT] = 0;
589 mRootNode.node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
590 mRootNode.node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
592 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
594 css_node_t* childNode = mChildrenNodes[i].node;
595 Actor childActor = mChildrenNodes[i].actor.GetHandle();
597 childNode->layout.position[CSS_LEFT] = 0;
598 childNode->layout.position[CSS_TOP] = 0;
599 childNode->layout.position[CSS_BOTTOM] = 0;
600 childNode->layout.position[CSS_RIGHT] = 0;
601 childNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
602 childNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
604 // Intialize the style of the child.
605 childNode->style.minDimensions[CSS_WIDTH] = childActor.GetMinimumSize().x;
606 childNode->style.minDimensions[CSS_HEIGHT] = childActor.GetMinimumSize().y;
607 childNode->style.maxDimensions[CSS_WIDTH] = childActor.GetMaximumSize().x;
608 childNode->style.maxDimensions[CSS_HEIGHT] = childActor.GetMaximumSize().y;
610 // Test custom properties on the child
611 if( childActor.GetPropertyIndex( FLEX_PROPERTY_NAME ) != Property::INVALID_INDEX )
613 childNode->style.flex = childActor.GetProperty( childActor.GetPropertyIndex(FLEX_PROPERTY_NAME) ).Get<float>();
616 Property::Index alignSelfPropertyIndex = childActor.GetPropertyIndex( ALIGN_SELF_PROPERTY_NAME );
617 if( alignSelfPropertyIndex != Property::INVALID_INDEX )
619 Property::Value alignSelfPropertyValue = childActor.GetProperty( alignSelfPropertyIndex );
621 Toolkit::FlexContainer::Alignment alignSelf( Toolkit::FlexContainer::ALIGN_AUTO );
622 if( alignSelfPropertyValue.GetType() == Property::INTEGER )
624 alignSelf = static_cast<Toolkit::FlexContainer::Alignment>( alignSelfPropertyValue.Get< int >() );
626 else if( alignSelfPropertyValue.GetType() == Property::STRING )
628 std::string value = alignSelfPropertyValue.Get<std::string>();
629 Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.c_str(),
630 ALIGN_SELF_STRING_TABLE,
631 ALIGN_SELF_STRING_TABLE_COUNT,
634 childNode->style.align_self = static_cast<css_align_t>(alignSelf);
637 if( childActor.GetPropertyIndex( FLEX_PADDING_PROPERTY_NAME ) != Property::INVALID_INDEX )
639 Vector4 flexPadding = childActor.GetProperty( childActor.GetPropertyIndex(FLEX_PADDING_PROPERTY_NAME) ).Get<Vector4>();
640 childNode->style.padding[CSS_LEFT] = flexPadding.x;
641 childNode->style.padding[CSS_TOP] = flexPadding.y;
642 childNode->style.padding[CSS_RIGHT] = flexPadding.z;
643 childNode->style.padding[CSS_BOTTOM] = flexPadding.w;
646 if( childActor.GetPropertyIndex( FLEX_BORDER_PROPERTY_NAME ) != Property::INVALID_INDEX )
648 Vector4 flexBorder = childActor.GetProperty( childActor.GetPropertyIndex(FLEX_BORDER_PROPERTY_NAME) ).Get<Vector4>();
649 childNode->style.border[CSS_LEFT] = flexBorder.x;
650 childNode->style.border[CSS_TOP] = flexBorder.y;
651 childNode->style.border[CSS_RIGHT] = flexBorder.z;
652 childNode->style.border[CSS_BOTTOM] = flexBorder.w;
655 if( childActor.GetPropertyIndex( FLEX_MARGIN_PROPERTY_NAME ) != Property::INVALID_INDEX )
657 Vector4 flexMargin = childActor.GetProperty( childActor.GetPropertyIndex(FLEX_MARGIN_PROPERTY_NAME) ).Get<Vector4>();
658 childNode->style.margin[CSS_LEFT] = flexMargin.x;
659 childNode->style.margin[CSS_TOP] = flexMargin.y;
660 childNode->style.margin[CSS_RIGHT] = flexMargin.z;
661 childNode->style.margin[CSS_BOTTOM] = flexMargin.w;
665 // Calculate the layout
666 layoutNode( mRootNode.node, Self().GetMaximumSize().x, Self().GetMaximumSize().y, mRootNode.node->style.direction );
670 void FlexContainer::RelayoutChildren()
674 // Set size and position of children according to the layout calculation
675 for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
677 Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
680 child.SetX( mChildrenNodes[i].node->layout.position[CSS_LEFT] );
681 child.SetY( mChildrenNodes[i].node->layout.position[CSS_TOP] );
686 Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
688 Actor nextFocusableActor;
690 // First check whether there is any items in the container
691 if( mChildrenNodes.size() > 0 )
693 if ( !currentFocusedActor || currentFocusedActor == Self() )
695 // Nothing is currently focused, so the first child in the container should be focused.
696 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
700 // Check whether the current focused actor is within flex container
701 int currentFocusedActorIndex = -1;
702 for( unsigned int index = 0; index < mChildrenNodes.size(); index++ )
704 if( currentFocusedActor == mChildrenNodes[index].actor.GetHandle() )
706 currentFocusedActorIndex = index;
711 if( currentFocusedActorIndex > -1 )
713 int previousCheckedActorIndex = -1;
714 int nextFocusedActorIndex = currentFocusedActorIndex;
717 case Toolkit::Control::KeyboardFocus::LEFT:
718 case Toolkit::Control::KeyboardFocus::UP:
720 // Search the next focusable actor in the backward direction
723 nextFocusedActorIndex--;
724 if( nextFocusedActorIndex < 0 )
726 nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
728 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
730 previousCheckedActorIndex = nextFocusedActorIndex;
736 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
739 case Toolkit::Control::KeyboardFocus::RIGHT:
740 case Toolkit::Control::KeyboardFocus::DOWN:
742 // Search the next focusable actor in the forward direction
745 nextFocusedActorIndex++;
746 if( nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1) )
748 nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
750 if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
752 previousCheckedActorIndex = nextFocusedActorIndex;
758 } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
763 if( nextFocusedActorIndex != currentFocusedActorIndex )
765 nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
769 // No focusble child in the container
770 nextFocusableActor = Actor();
775 // The current focused actor is not within flex container, so the first child in the container should be focused.
776 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
781 return nextFocusableActor;
784 FlexContainer::FlexContainer()
785 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
786 mContentDirection( Toolkit::FlexContainer::INHERIT ),
787 mFlexDirection( Toolkit::FlexContainer::COLUMN ),
788 mFlexWrap( Toolkit::FlexContainer::NO_WRAP ),
789 mJustifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START ),
790 mAlignItems( Toolkit::FlexContainer::ALIGN_STRETCH ),
791 mAlignContent( Toolkit::FlexContainer::ALIGN_FLEX_START )
793 SetKeyboardNavigationSupport( true );
796 void FlexContainer::OnInitialize()
798 // Initialize the node for the flex container itself
799 Dali::Actor self = Self();
800 mRootNode.actor = self;
801 mRootNode.node = new_css_node();
802 mRootNode.node->context = &mChildrenNodes;
805 mRootNode.node->style.direction = static_cast<css_direction_t>( mContentDirection );
806 mRootNode.node->style.flex_direction = static_cast<css_flex_direction_t>( mFlexDirection );
807 mRootNode.node->style.flex_wrap = static_cast<css_wrap_type_t>( mFlexWrap );
808 mRootNode.node->style.justify_content = static_cast<css_justify_t>( mJustifyContent );
809 mRootNode.node->style.align_items = static_cast<css_align_t>( mAlignItems );
810 mRootNode.node->style.align_content = static_cast<css_align_t>( mAlignContent );
813 mRootNode.node->get_child = GetChildNodeAtIndex;
814 mRootNode.node->is_dirty = IsNodeDirty;
816 // Make self as keyboard focusable and focus group
817 self.SetKeyboardFocusable( true );
818 SetAsKeyboardFocusGroup( true );
821 } // namespace Internal
823 } // namespace Toolkit