2 * Copyright (c) 2021 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>
22 #include <dali/devel-api/actors/actor-devel.h>
23 #include <dali/devel-api/scripting/scripting.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/object/ref-object.h>
26 #include <dali/public-api/object/type-registry-helper.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/public-api/size-negotiation/relayout-container.h>
32 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
38 #if defined(DEBUG_ENABLED)
39 // debugging support, very useful when new features are added or bugs are hunted down
40 // currently not called from code so compiler will optimize these away, kept here for future debugging
42 #define FLEX_CONTAINER_TAG "DALI Toolkit::FlexContainer "
43 #define FC_LOG(fmt, args, ...) Debug::LogMessage(Debug::DebugInfo, FLEX_CONTAINER_TAG fmt, ##args)
44 // #define FLEX_CONTAINER_DEBUG 1
46 #if defined(FLEX_CONTAINER_DEBUG)
47 void PrintNodes(Toolkit::Internal::FlexContainer::FlexItemNodeContainer itemNodes)
49 // Print the style property and layout of all the children
50 for(unsigned int i = 0; i < itemNodes.size(); ++i)
52 FC_LOG("Item %d style: \n", i);
53 YGNodePrint(itemNodes[i].node, (YGPrintOptions)(YGPrintOptionsStyle | YGPrintOptionsChildren));
55 FC_LOG("Item %d layout: \n", i);
56 YGNodePrint(itemNodes[i].node, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren));
61 #endif // defined(FLEX_CONTAINER_DEBUG)
62 #endif // defined(DEBUG_ENABLED)
77 return Toolkit::FlexContainer::New();
80 // Setup properties, signals and actions using the type-registry.
81 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::FlexContainer, Toolkit::Control, Create);
83 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "contentDirection", INTEGER, CONTENT_DIRECTION)
84 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "flexDirection", INTEGER, FLEX_DIRECTION)
85 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "flexWrap", INTEGER, FLEX_WRAP)
86 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "justifyContent", INTEGER, JUSTIFY_CONTENT)
87 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "alignItems", INTEGER, ALIGN_ITEMS)
88 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "alignContent", INTEGER, ALIGN_CONTENT)
89 DALI_CHILD_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "flex", FLOAT, FLEX)
90 DALI_CHILD_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "alignSelf", INTEGER, ALIGN_SELF)
91 DALI_CHILD_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "flexMargin", VECTOR4, FLEX_MARGIN)
93 DALI_TYPE_REGISTRATION_END()
95 const Scripting::StringEnum ALIGN_SELF_STRING_TABLE[] =
97 {"auto", Toolkit::FlexContainer::ALIGN_AUTO},
98 {"flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START},
99 {"center", Toolkit::FlexContainer::ALIGN_CENTER},
100 {"flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END},
101 {"stretch", Toolkit::FlexContainer::ALIGN_STRETCH}};
102 const unsigned int ALIGN_SELF_STRING_TABLE_COUNT = sizeof(ALIGN_SELF_STRING_TABLE) / sizeof(ALIGN_SELF_STRING_TABLE[0]);
104 const Scripting::StringEnum CONTENT_DIRECTION_STRING_TABLE[] =
106 {"inherit", Toolkit::FlexContainer::INHERIT},
107 {"LTR", Toolkit::FlexContainer::LTR},
108 {"RTL", Toolkit::FlexContainer::RTL}};
109 const unsigned int CONTENT_DIRECTION_STRING_TABLE_COUNT = sizeof(CONTENT_DIRECTION_STRING_TABLE) / sizeof(CONTENT_DIRECTION_STRING_TABLE[0]);
111 const Scripting::StringEnum FLEX_DIRECTION_STRING_TABLE[] =
113 {"column", Toolkit::FlexContainer::COLUMN},
114 {"columnReverse", Toolkit::FlexContainer::COLUMN_REVERSE},
115 {"row", Toolkit::FlexContainer::ROW},
116 {"rowReverse", Toolkit::FlexContainer::ROW_REVERSE}};
117 const unsigned int FLEX_DIRECTION_STRING_TABLE_COUNT = sizeof(FLEX_DIRECTION_STRING_TABLE) / sizeof(FLEX_DIRECTION_STRING_TABLE[0]);
119 const Scripting::StringEnum FLEX_WRAP_STRING_TABLE[] =
121 {"noWrap", Toolkit::FlexContainer::NO_WRAP},
122 {"wrap", Toolkit::FlexContainer::WRAP}};
123 const unsigned int FLEX_WRAP_STRING_TABLE_COUNT = sizeof(FLEX_WRAP_STRING_TABLE) / sizeof(FLEX_WRAP_STRING_TABLE[0]);
125 const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
127 {"flexStart", Toolkit::FlexContainer::JUSTIFY_FLEX_START},
128 {"center", Toolkit::FlexContainer::JUSTIFY_CENTER},
129 {"flexEnd", Toolkit::FlexContainer::JUSTIFY_FLEX_END},
130 {"spaceBetween", Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN},
131 {"spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND}};
132 const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof(JUSTIFY_CONTENT_STRING_TABLE) / sizeof(JUSTIFY_CONTENT_STRING_TABLE[0]);
134 const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
136 {"flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START},
137 {"center", Toolkit::FlexContainer::ALIGN_CENTER},
138 {"flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END},
139 {"stretch", Toolkit::FlexContainer::ALIGN_STRETCH}};
140 const unsigned int ALIGN_ITEMS_STRING_TABLE_COUNT = sizeof(ALIGN_ITEMS_STRING_TABLE) / sizeof(ALIGN_ITEMS_STRING_TABLE[0]);
142 const Scripting::StringEnum ALIGN_CONTENT_STRING_TABLE[] =
144 {"flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START},
145 {"center", Toolkit::FlexContainer::ALIGN_CENTER},
146 {"flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END},
147 {"stretch", Toolkit::FlexContainer::ALIGN_STRETCH}};
148 const unsigned int ALIGN_CONTENT_STRING_TABLE_COUNT = sizeof(ALIGN_CONTENT_STRING_TABLE) / sizeof(ALIGN_CONTENT_STRING_TABLE[0]);
150 } // Unnamed namespace
152 Toolkit::FlexContainer FlexContainer::New()
154 // Create the implementation, temporarily owned by this handle on stack
155 IntrusivePtr<FlexContainer> impl = new FlexContainer();
157 // Pass ownership to CustomActor handle
158 Toolkit::FlexContainer handle(*impl);
160 // Second-phase init of the implementation
161 // This can only be done after the CustomActor connection has been made...
167 FlexContainer::~FlexContainer()
169 YGNodeFree(mRootNode.node);
171 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
173 YGNodeFree(mChildrenNodes[i].node);
176 mChildrenNodes.clear();
179 void FlexContainer::SetContentDirection(Toolkit::FlexContainer::ContentDirection contentDirection)
181 if(mContentDirection != contentDirection)
183 Dali::CustomActor ownerActor(GetOwner());
185 if(Toolkit::FlexContainer::INHERIT != contentDirection)
187 mContentDirection = contentDirection;
189 ownerActor.SetProperty(Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, false);
191 if(Toolkit::FlexContainer::LTR == contentDirection)
193 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT);
197 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT);
202 ownerActor.SetProperty(Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, true);
204 Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(ownerActor.GetParent().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
206 if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
208 mContentDirection = Toolkit::FlexContainer::RTL;
212 mContentDirection = Toolkit::FlexContainer::LTR;
220 Toolkit::FlexContainer::ContentDirection FlexContainer::GetContentDirection()
222 return mContentDirection;
225 void FlexContainer::SetFlexDirection(Toolkit::FlexContainer::FlexDirection flexDirection)
227 if(mFlexDirection != flexDirection)
229 mFlexDirection = flexDirection;
230 YGNodeStyleSetFlexDirection(mRootNode.node, static_cast<YGFlexDirection>(flexDirection));
236 Toolkit::FlexContainer::FlexDirection FlexContainer::GetFlexDirection()
238 return mFlexDirection;
241 void FlexContainer::SetFlexWrap(Toolkit::FlexContainer::WrapType flexWrap)
243 if(mFlexWrap != flexWrap)
245 mFlexWrap = flexWrap;
246 YGNodeStyleSetFlexWrap(mRootNode.node, static_cast<YGWrap>(flexWrap));
252 Toolkit::FlexContainer::WrapType FlexContainer::GetFlexWrap()
257 void FlexContainer::SetJustifyContent(Toolkit::FlexContainer::Justification justifyContent)
259 if(mJustifyContent != justifyContent)
261 mJustifyContent = justifyContent;
262 YGNodeStyleSetJustifyContent(mRootNode.node, static_cast<YGJustify>(justifyContent));
268 Toolkit::FlexContainer::Justification FlexContainer::GetJustifyContent()
270 return mJustifyContent;
273 void FlexContainer::SetAlignItems(Toolkit::FlexContainer::Alignment alignItems)
275 if(mAlignItems != alignItems)
277 mAlignItems = alignItems;
278 YGNodeStyleSetAlignItems(mRootNode.node, static_cast<YGAlign>(alignItems));
284 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignItems()
289 void FlexContainer::SetAlignContent(Toolkit::FlexContainer::Alignment alignContent)
291 if(mAlignContent != alignContent)
293 mAlignContent = alignContent;
294 YGNodeStyleSetAlignContent(mRootNode.node, static_cast<YGAlign>(alignContent));
300 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignContent()
302 return mAlignContent;
305 void FlexContainer::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
307 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(Dali::BaseHandle(object));
311 FlexContainer& flexContainerImpl(GetImpl(flexContainer));
314 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
316 Toolkit::FlexContainer::ContentDirection contentDirection(Toolkit::FlexContainer::INHERIT);
318 if(value.GetType() == Property::INTEGER)
320 flexContainerImpl.SetContentDirection(static_cast<Toolkit::FlexContainer::ContentDirection>(value.Get<int>()));
322 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::ContentDirection>(value.Get<std::string>().c_str(),
323 CONTENT_DIRECTION_STRING_TABLE,
324 CONTENT_DIRECTION_STRING_TABLE_COUNT,
327 flexContainerImpl.SetContentDirection(contentDirection);
331 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
333 Toolkit::FlexContainer::FlexDirection flexDirection(Toolkit::FlexContainer::COLUMN);
335 if(value.GetType() == Property::INTEGER)
337 flexContainerImpl.SetFlexDirection(static_cast<Toolkit::FlexContainer::FlexDirection>(value.Get<int>()));
339 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::FlexDirection>(value.Get<std::string>().c_str(),
340 FLEX_DIRECTION_STRING_TABLE,
341 FLEX_DIRECTION_STRING_TABLE_COUNT,
344 flexContainerImpl.SetFlexDirection(flexDirection);
348 case Toolkit::FlexContainer::Property::FLEX_WRAP:
350 Toolkit::FlexContainer::WrapType flexWrap(Toolkit::FlexContainer::NO_WRAP);
352 if(value.GetType() == Property::INTEGER)
354 flexContainerImpl.SetFlexWrap(static_cast<Toolkit::FlexContainer::WrapType>(value.Get<int>()));
356 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::WrapType>(value.Get<std::string>().c_str(),
357 FLEX_WRAP_STRING_TABLE,
358 FLEX_WRAP_STRING_TABLE_COUNT,
361 flexContainerImpl.SetFlexWrap(flexWrap);
365 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
367 Toolkit::FlexContainer::Justification justifyContent(Toolkit::FlexContainer::JUSTIFY_FLEX_START);
369 if(value.GetType() == Property::INTEGER)
371 flexContainerImpl.SetJustifyContent(static_cast<Toolkit::FlexContainer::Justification>(value.Get<int>()));
373 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::Justification>(value.Get<std::string>().c_str(),
374 JUSTIFY_CONTENT_STRING_TABLE,
375 JUSTIFY_CONTENT_STRING_TABLE_COUNT,
378 flexContainerImpl.SetJustifyContent(justifyContent);
382 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
384 Toolkit::FlexContainer::Alignment alignItems(Toolkit::FlexContainer::ALIGN_STRETCH);
386 if(value.GetType() == Property::INTEGER)
388 flexContainerImpl.SetAlignItems(static_cast<Toolkit::FlexContainer::Alignment>(value.Get<int>()));
390 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::Alignment>(value.Get<std::string>().c_str(),
391 ALIGN_ITEMS_STRING_TABLE,
392 ALIGN_ITEMS_STRING_TABLE_COUNT,
395 flexContainerImpl.SetAlignItems(alignItems);
399 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
401 Toolkit::FlexContainer::Alignment alignContent(Toolkit::FlexContainer::ALIGN_FLEX_START);
403 if(value.GetType() == Property::INTEGER)
405 flexContainerImpl.SetAlignContent(static_cast<Toolkit::FlexContainer::Alignment>(value.Get<int>()));
407 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::Alignment>(value.Get<std::string>().c_str(),
408 ALIGN_CONTENT_STRING_TABLE,
409 ALIGN_CONTENT_STRING_TABLE_COUNT,
412 flexContainerImpl.SetAlignContent(alignContent);
420 Property::Value FlexContainer::GetProperty(BaseObject* object, Property::Index index)
422 Property::Value value;
424 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(Dali::BaseHandle(object));
428 FlexContainer& flexContainerImpl(GetImpl(flexContainer));
431 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
433 value = flexContainerImpl.GetContentDirection();
436 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
438 value = flexContainerImpl.GetFlexDirection();
441 case Toolkit::FlexContainer::Property::FLEX_WRAP:
443 value = flexContainerImpl.GetFlexWrap();
446 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
448 value = flexContainerImpl.GetJustifyContent();
451 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
453 value = flexContainerImpl.GetAlignItems();
456 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
458 value = flexContainerImpl.GetAlignContent();
467 void FlexContainer::OnChildAdd(Actor& child)
469 // Create a new node for the child.
470 FlexItemNode childNode;
471 childNode.actor = child;
472 childNode.node = YGNodeNew();
474 mChildrenNodes.push_back(childNode);
475 YGNodeInsertChild(mRootNode.node, childNode.node, mChildrenNodes.size() - 1);
477 Control::OnChildAdd(child);
480 void FlexContainer::OnChildRemove(Actor& child)
482 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
484 if(mChildrenNodes[i].actor.GetHandle() == child)
486 YGNodeRemoveChild(mRootNode.node, mChildrenNodes[i].node);
487 YGNodeFree(mChildrenNodes[i].node);
489 mChildrenNodes.erase(mChildrenNodes.begin() + i);
491 // Relayout the container only if instances were found
497 Control::OnChildRemove(child);
500 void FlexContainer::OnRelayout(const Vector2& size, RelayoutContainer& container)
502 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
504 Actor child = mChildrenNodes[i].actor.GetHandle();
507 // Anchor actor to top left of the container
508 if(child.GetProperty(Actor::Property::POSITION_USES_ANCHOR_POINT).Get<bool>())
510 child.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
512 child.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
514 float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
515 float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
517 if(negotiatedWidth > 0)
519 YGNodeStyleSetWidth(mChildrenNodes[i].node, negotiatedWidth);
521 if(negotiatedHeight > 0)
523 YGNodeStyleSetHeight(mChildrenNodes[i].node, negotiatedHeight);
528 // Relayout the container
530 #if defined(FLEX_CONTAINER_DEBUG)
531 PrintNodes(mChildrenNodes);
534 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
536 Actor child = mChildrenNodes[i].actor.GetHandle();
539 if(child.GetPropertyType(Toolkit::FlexContainer::ChildProperty::FLEX) != Property::NONE)
541 // Only Set to USE_ASSIGNED_SIZE if the child actor is flexible.
543 if(child.GetResizePolicy(Dimension::WIDTH) != ResizePolicy::USE_ASSIGNED_SIZE)
545 child.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH);
547 if(child.GetResizePolicy(Dimension::HEIGHT) != ResizePolicy::USE_ASSIGNED_SIZE)
549 child.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT);
552 container.Add(child, Vector2(YGNodeLayoutGetWidth(mChildrenNodes[i].node), YGNodeLayoutGetHeight(mChildrenNodes[i].node)));
557 bool FlexContainer::RelayoutDependentOnChildren(Dimension::Type dimension)
562 void FlexContainer::OnSizeSet(const Vector3& size)
567 YGNodeStyleSetWidth(mRootNode.node, size.x);
568 YGNodeStyleSetHeight(mRootNode.node, size.y);
573 Control::OnSizeSet(size);
576 void FlexContainer::OnLayoutDirectionChanged(Dali::Actor actor, Dali::LayoutDirection::Type type)
578 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(actor);
579 Toolkit::FlexContainer::ContentDirection direction;
581 if(type == Dali::LayoutDirection::RIGHT_TO_LEFT)
583 direction = Toolkit::FlexContainer::RTL;
587 direction = Toolkit::FlexContainer::LTR;
590 Toolkit::Internal::FlexContainer& flexContainerImpl = GetImpl(flexContainer);
592 if(flexContainerImpl.mContentDirection != direction)
594 Dali::CustomActor ownerActor(flexContainerImpl.GetOwner());
595 flexContainerImpl.mContentDirection = direction;
597 flexContainerImpl.RelayoutRequest();
601 void FlexContainer::ComputeLayout()
605 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
607 YGNodeRef childNode = mChildrenNodes[i].node;
608 Actor childActor = mChildrenNodes[i].actor.GetHandle();
610 // Intialize the style of the child.
611 YGNodeStyleSetMinWidth(childNode, childActor.GetProperty<Vector2>(Actor::Property::MINIMUM_SIZE).x);
612 YGNodeStyleSetMinHeight(childNode, childActor.GetProperty<Vector2>(Actor::Property::MINIMUM_SIZE).y);
613 YGNodeStyleSetMaxWidth(childNode, childActor.GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE).x);
614 YGNodeStyleSetMaxHeight(childNode, childActor.GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE).y);
616 // Check child properties on the child for how to layout it.
617 // These properties should be dynamically registered to the child which
618 // would be added to FlexContainer.
620 if(childActor.GetPropertyType(Toolkit::FlexContainer::ChildProperty::FLEX) != Property::NONE)
622 YGNodeStyleSetFlex(childNode, childActor.GetProperty(Toolkit::FlexContainer::ChildProperty::FLEX).Get<float>());
625 Toolkit::FlexContainer::Alignment alignSelf(Toolkit::FlexContainer::ALIGN_AUTO);
626 if(childActor.GetPropertyType(Toolkit::FlexContainer::ChildProperty::ALIGN_SELF) != Property::NONE)
628 Property::Value alignSelfPropertyValue = childActor.GetProperty(Toolkit::FlexContainer::ChildProperty::ALIGN_SELF);
629 if(alignSelfPropertyValue.GetType() == Property::INTEGER)
631 alignSelf = static_cast<Toolkit::FlexContainer::Alignment>(alignSelfPropertyValue.Get<int>());
633 else if(alignSelfPropertyValue.GetType() == Property::STRING)
635 std::string value = alignSelfPropertyValue.Get<std::string>();
636 Scripting::GetEnumeration<Toolkit::FlexContainer::Alignment>(value.c_str(),
637 ALIGN_SELF_STRING_TABLE,
638 ALIGN_SELF_STRING_TABLE_COUNT,
641 YGNodeStyleSetAlignSelf(childNode, static_cast<YGAlign>(alignSelf));
644 if(childActor.GetPropertyType(Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN) != Property::NONE)
646 Vector4 flexMargin = childActor.GetProperty(Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN).Get<Vector4>();
647 YGNodeStyleSetMargin(childNode, YGEdgeLeft, flexMargin.x);
648 YGNodeStyleSetMargin(childNode, YGEdgeTop, flexMargin.y);
649 YGNodeStyleSetMargin(childNode, YGEdgeRight, flexMargin.z);
650 YGNodeStyleSetMargin(childNode, YGEdgeBottom, flexMargin.w);
654 // Calculate the layout
655 YGDirection nodeLayoutDirection = YGDirectionInherit;
656 switch(mContentDirection)
658 case Dali::Toolkit::FlexContainer::LTR:
660 nodeLayoutDirection = YGDirectionLTR;
664 case Dali::Toolkit::FlexContainer::RTL:
666 nodeLayoutDirection = YGDirectionRTL;
670 case Dali::Toolkit::FlexContainer::INHERIT:
672 nodeLayoutDirection = YGDirectionInherit;
677 #if defined(FLEX_CONTAINER_DEBUG)
678 YGNodePrint(mRootNode.node, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren));
680 YGNodeCalculateLayout(mRootNode.node, Self().GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE).x, Self().GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE).y, nodeLayoutDirection);
681 #if defined(FLEX_CONTAINER_DEBUG)
682 YGNodePrint(mRootNode.node, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren));
687 void FlexContainer::RelayoutChildren()
691 // Set size and position of children according to the layout calculation
692 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
694 Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
697 child.SetProperty(Actor::Property::POSITION_X, YGNodeLayoutGetLeft(mChildrenNodes[i].node));
698 child.SetProperty(Actor::Property::POSITION_Y, YGNodeLayoutGetTop(mChildrenNodes[i].node));
703 Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
705 Actor nextFocusableActor;
707 // First check whether there is any items in the container
708 if(mChildrenNodes.size() > 0)
710 if(!currentFocusedActor || currentFocusedActor == Self())
712 // Nothing is currently focused, so the first child in the container should be focused.
713 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
717 // Check whether the current focused actor is within flex container
718 int currentFocusedActorIndex = -1;
719 for(unsigned int index = 0; index < mChildrenNodes.size(); index++)
721 if(currentFocusedActor == mChildrenNodes[index].actor.GetHandle())
723 currentFocusedActorIndex = index;
728 if(currentFocusedActorIndex > -1)
730 int previousCheckedActorIndex = -1;
731 int nextFocusedActorIndex = currentFocusedActorIndex;
734 case Toolkit::Control::KeyboardFocus::LEFT:
735 case Toolkit::Control::KeyboardFocus::UP:
737 // Search the next focusable actor in the backward direction
740 nextFocusedActorIndex--;
741 if(nextFocusedActorIndex < 0)
743 nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
745 if(nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex)
747 previousCheckedActorIndex = nextFocusedActorIndex;
753 } while(!mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE));
756 case Toolkit::Control::KeyboardFocus::RIGHT:
757 case Toolkit::Control::KeyboardFocus::DOWN:
759 // Search the next focusable actor in the forward direction
762 nextFocusedActorIndex++;
763 if(nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1))
765 nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
767 if(nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex)
769 previousCheckedActorIndex = nextFocusedActorIndex;
775 } while(!mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE));
784 if(nextFocusedActorIndex != currentFocusedActorIndex)
786 nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
790 // No focusble child in the container
791 nextFocusableActor = Actor();
796 // The current focused actor is not within flex container, so the first child in the container should be focused.
797 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
802 return nextFocusableActor;
805 FlexContainer::FlexContainer()
806 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
807 mContentDirection(Toolkit::FlexContainer::INHERIT),
808 mFlexDirection(Toolkit::FlexContainer::COLUMN),
809 mFlexWrap(Toolkit::FlexContainer::NO_WRAP),
810 mJustifyContent(Toolkit::FlexContainer::JUSTIFY_FLEX_START),
811 mAlignItems(Toolkit::FlexContainer::ALIGN_STRETCH),
812 mAlignContent(Toolkit::FlexContainer::ALIGN_FLEX_START)
814 SetKeyboardNavigationSupport(true);
817 void FlexContainer::OnInitialize()
819 // Initialize the node for the flex container itself
820 Dali::Actor self = Self();
821 self.LayoutDirectionChangedSignal().Connect(this, &FlexContainer::OnLayoutDirectionChanged);
823 mRootNode.actor = self;
824 mRootNode.node = YGNodeNew();
825 YGNodeSetContext(mRootNode.node, &mChildrenNodes);
828 YGNodeStyleSetFlexDirection(mRootNode.node, static_cast<YGFlexDirection>(mFlexDirection));
829 YGNodeStyleSetFlexWrap(mRootNode.node, static_cast<YGWrap>(mFlexWrap));
830 YGNodeStyleSetJustifyContent(mRootNode.node, static_cast<YGJustify>(mJustifyContent));
831 YGNodeStyleSetAlignItems(mRootNode.node, static_cast<YGAlign>(mAlignItems));
832 YGNodeStyleSetAlignContent(mRootNode.node, static_cast<YGAlign>(mAlignContent));
834 // Make self as keyboard focusable and focus group
835 self.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
836 SetAsKeyboardFocusGroup(true);
838 DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
839 return std::unique_ptr<Dali::Accessibility::Accessible>(
840 new Control::Impl::AccessibleImpl(actor, Dali::Accessibility::Role::FILLER));
844 } // namespace Internal
846 } // namespace Toolkit