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>
31 #include <dali-toolkit/devel-api/controls/control-devel.h>
37 #if defined(DEBUG_ENABLED)
38 // debugging support, very useful when new features are added or bugs are hunted down
39 // currently not called from code so compiler will optimize these away, kept here for future debugging
41 #define FLEX_CONTAINER_TAG "DALI Toolkit::FlexContainer "
42 #define FC_LOG(fmt, args, ...) Debug::LogMessage(Debug::DebugInfo, FLEX_CONTAINER_TAG fmt, ##args)
43 // #define FLEX_CONTAINER_DEBUG 1
45 #if defined(FLEX_CONTAINER_DEBUG)
46 void PrintNodes(Toolkit::Internal::FlexContainer::FlexItemNodeContainer itemNodes)
48 // Print the style property and layout of all the children
49 for(unsigned int i = 0; i < itemNodes.size(); ++i)
51 FC_LOG("Item %d style: \n", i);
52 YGNodePrint(itemNodes[i].node, (YGPrintOptions)(YGPrintOptionsStyle | YGPrintOptionsChildren));
54 FC_LOG("Item %d layout: \n", i);
55 YGNodePrint(itemNodes[i].node, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren));
60 #endif // defined(FLEX_CONTAINER_DEBUG)
61 #endif // defined(DEBUG_ENABLED)
76 return Toolkit::FlexContainer::New();
79 // Setup properties, signals and actions using the type-registry.
80 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::FlexContainer, Toolkit::Control, Create);
82 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "contentDirection", INTEGER, CONTENT_DIRECTION)
83 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "flexDirection", INTEGER, FLEX_DIRECTION)
84 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "flexWrap", INTEGER, FLEX_WRAP)
85 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "justifyContent", INTEGER, JUSTIFY_CONTENT)
86 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "alignItems", INTEGER, ALIGN_ITEMS)
87 DALI_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "alignContent", INTEGER, ALIGN_CONTENT)
88 DALI_CHILD_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "flex", FLOAT, FLEX)
89 DALI_CHILD_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "alignSelf", INTEGER, ALIGN_SELF)
90 DALI_CHILD_PROPERTY_REGISTRATION(Toolkit, FlexContainer, "flexMargin", VECTOR4, FLEX_MARGIN)
92 DALI_TYPE_REGISTRATION_END()
94 const Scripting::StringEnum ALIGN_SELF_STRING_TABLE[] =
96 {"auto", Toolkit::FlexContainer::ALIGN_AUTO},
97 {"flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START},
98 {"center", Toolkit::FlexContainer::ALIGN_CENTER},
99 {"flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END},
100 {"stretch", Toolkit::FlexContainer::ALIGN_STRETCH}};
101 const unsigned int ALIGN_SELF_STRING_TABLE_COUNT = sizeof(ALIGN_SELF_STRING_TABLE) / sizeof(ALIGN_SELF_STRING_TABLE[0]);
103 const Scripting::StringEnum CONTENT_DIRECTION_STRING_TABLE[] =
105 {"inherit", Toolkit::FlexContainer::INHERIT},
106 {"LTR", Toolkit::FlexContainer::LTR},
107 {"RTL", Toolkit::FlexContainer::RTL}};
108 const unsigned int CONTENT_DIRECTION_STRING_TABLE_COUNT = sizeof(CONTENT_DIRECTION_STRING_TABLE) / sizeof(CONTENT_DIRECTION_STRING_TABLE[0]);
110 const Scripting::StringEnum FLEX_DIRECTION_STRING_TABLE[] =
112 {"column", Toolkit::FlexContainer::COLUMN},
113 {"columnReverse", Toolkit::FlexContainer::COLUMN_REVERSE},
114 {"row", Toolkit::FlexContainer::ROW},
115 {"rowReverse", Toolkit::FlexContainer::ROW_REVERSE}};
116 const unsigned int FLEX_DIRECTION_STRING_TABLE_COUNT = sizeof(FLEX_DIRECTION_STRING_TABLE) / sizeof(FLEX_DIRECTION_STRING_TABLE[0]);
118 const Scripting::StringEnum FLEX_WRAP_STRING_TABLE[] =
120 {"noWrap", Toolkit::FlexContainer::NO_WRAP},
121 {"wrap", Toolkit::FlexContainer::WRAP}};
122 const unsigned int FLEX_WRAP_STRING_TABLE_COUNT = sizeof(FLEX_WRAP_STRING_TABLE) / sizeof(FLEX_WRAP_STRING_TABLE[0]);
124 const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
126 {"flexStart", Toolkit::FlexContainer::JUSTIFY_FLEX_START},
127 {"center", Toolkit::FlexContainer::JUSTIFY_CENTER},
128 {"flexEnd", Toolkit::FlexContainer::JUSTIFY_FLEX_END},
129 {"spaceBetween", Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN},
130 {"spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND}};
131 const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof(JUSTIFY_CONTENT_STRING_TABLE) / sizeof(JUSTIFY_CONTENT_STRING_TABLE[0]);
133 const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
135 {"flexStart", Toolkit::FlexContainer::ALIGN_FLEX_START},
136 {"center", Toolkit::FlexContainer::ALIGN_CENTER},
137 {"flexEnd", Toolkit::FlexContainer::ALIGN_FLEX_END},
138 {"stretch", Toolkit::FlexContainer::ALIGN_STRETCH}};
139 const unsigned int ALIGN_ITEMS_STRING_TABLE_COUNT = sizeof(ALIGN_ITEMS_STRING_TABLE) / sizeof(ALIGN_ITEMS_STRING_TABLE[0]);
141 const Scripting::StringEnum ALIGN_CONTENT_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}};
147 const unsigned int ALIGN_CONTENT_STRING_TABLE_COUNT = sizeof(ALIGN_CONTENT_STRING_TABLE) / sizeof(ALIGN_CONTENT_STRING_TABLE[0]);
149 } // Unnamed namespace
151 Toolkit::FlexContainer FlexContainer::New()
153 // Create the implementation, temporarily owned by this handle on stack
154 IntrusivePtr<FlexContainer> impl = new FlexContainer();
156 // Pass ownership to CustomActor handle
157 Toolkit::FlexContainer handle(*impl);
159 // Second-phase init of the implementation
160 // This can only be done after the CustomActor connection has been made...
166 FlexContainer::~FlexContainer()
168 YGNodeFree(mRootNode.node);
170 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
172 YGNodeFree(mChildrenNodes[i].node);
175 mChildrenNodes.clear();
178 void FlexContainer::SetContentDirection(Toolkit::FlexContainer::ContentDirection contentDirection)
180 if(mContentDirection != contentDirection)
182 Dali::CustomActor ownerActor(GetOwner());
184 if(Toolkit::FlexContainer::INHERIT != contentDirection)
186 mContentDirection = contentDirection;
188 ownerActor.SetProperty(Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, false);
190 if(Toolkit::FlexContainer::LTR == contentDirection)
192 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT);
196 ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT);
201 ownerActor.SetProperty(Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, true);
203 Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(ownerActor.GetParent().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
205 if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
207 mContentDirection = Toolkit::FlexContainer::RTL;
211 mContentDirection = Toolkit::FlexContainer::LTR;
219 Toolkit::FlexContainer::ContentDirection FlexContainer::GetContentDirection()
221 return mContentDirection;
224 void FlexContainer::SetFlexDirection(Toolkit::FlexContainer::FlexDirection flexDirection)
226 if(mFlexDirection != flexDirection)
228 mFlexDirection = flexDirection;
229 YGNodeStyleSetFlexDirection(mRootNode.node, static_cast<YGFlexDirection>(flexDirection));
235 Toolkit::FlexContainer::FlexDirection FlexContainer::GetFlexDirection()
237 return mFlexDirection;
240 void FlexContainer::SetFlexWrap(Toolkit::FlexContainer::WrapType flexWrap)
242 if(mFlexWrap != flexWrap)
244 mFlexWrap = flexWrap;
245 YGNodeStyleSetFlexWrap(mRootNode.node, static_cast<YGWrap>(flexWrap));
251 Toolkit::FlexContainer::WrapType FlexContainer::GetFlexWrap()
256 void FlexContainer::SetJustifyContent(Toolkit::FlexContainer::Justification justifyContent)
258 if(mJustifyContent != justifyContent)
260 mJustifyContent = justifyContent;
261 YGNodeStyleSetJustifyContent(mRootNode.node, static_cast<YGJustify>(justifyContent));
267 Toolkit::FlexContainer::Justification FlexContainer::GetJustifyContent()
269 return mJustifyContent;
272 void FlexContainer::SetAlignItems(Toolkit::FlexContainer::Alignment alignItems)
274 if(mAlignItems != alignItems)
276 mAlignItems = alignItems;
277 YGNodeStyleSetAlignItems(mRootNode.node, static_cast<YGAlign>(alignItems));
283 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignItems()
288 void FlexContainer::SetAlignContent(Toolkit::FlexContainer::Alignment alignContent)
290 if(mAlignContent != alignContent)
292 mAlignContent = alignContent;
293 YGNodeStyleSetAlignContent(mRootNode.node, static_cast<YGAlign>(alignContent));
299 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignContent()
301 return mAlignContent;
304 void FlexContainer::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
306 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(Dali::BaseHandle(object));
310 FlexContainer& flexContainerImpl(GetImpl(flexContainer));
313 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
315 Toolkit::FlexContainer::ContentDirection contentDirection(Toolkit::FlexContainer::INHERIT);
317 if(value.GetType() == Property::INTEGER)
319 flexContainerImpl.SetContentDirection(static_cast<Toolkit::FlexContainer::ContentDirection>(value.Get<int>()));
321 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::ContentDirection>(value.Get<std::string>().c_str(),
322 CONTENT_DIRECTION_STRING_TABLE,
323 CONTENT_DIRECTION_STRING_TABLE_COUNT,
326 flexContainerImpl.SetContentDirection(contentDirection);
330 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
332 Toolkit::FlexContainer::FlexDirection flexDirection(Toolkit::FlexContainer::COLUMN);
334 if(value.GetType() == Property::INTEGER)
336 flexContainerImpl.SetFlexDirection(static_cast<Toolkit::FlexContainer::FlexDirection>(value.Get<int>()));
338 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::FlexDirection>(value.Get<std::string>().c_str(),
339 FLEX_DIRECTION_STRING_TABLE,
340 FLEX_DIRECTION_STRING_TABLE_COUNT,
343 flexContainerImpl.SetFlexDirection(flexDirection);
347 case Toolkit::FlexContainer::Property::FLEX_WRAP:
349 Toolkit::FlexContainer::WrapType flexWrap(Toolkit::FlexContainer::NO_WRAP);
351 if(value.GetType() == Property::INTEGER)
353 flexContainerImpl.SetFlexWrap(static_cast<Toolkit::FlexContainer::WrapType>(value.Get<int>()));
355 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::WrapType>(value.Get<std::string>().c_str(),
356 FLEX_WRAP_STRING_TABLE,
357 FLEX_WRAP_STRING_TABLE_COUNT,
360 flexContainerImpl.SetFlexWrap(flexWrap);
364 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
366 Toolkit::FlexContainer::Justification justifyContent(Toolkit::FlexContainer::JUSTIFY_FLEX_START);
368 if(value.GetType() == Property::INTEGER)
370 flexContainerImpl.SetJustifyContent(static_cast<Toolkit::FlexContainer::Justification>(value.Get<int>()));
372 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::Justification>(value.Get<std::string>().c_str(),
373 JUSTIFY_CONTENT_STRING_TABLE,
374 JUSTIFY_CONTENT_STRING_TABLE_COUNT,
377 flexContainerImpl.SetJustifyContent(justifyContent);
381 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
383 Toolkit::FlexContainer::Alignment alignItems(Toolkit::FlexContainer::ALIGN_STRETCH);
385 if(value.GetType() == Property::INTEGER)
387 flexContainerImpl.SetAlignItems(static_cast<Toolkit::FlexContainer::Alignment>(value.Get<int>()));
389 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::Alignment>(value.Get<std::string>().c_str(),
390 ALIGN_ITEMS_STRING_TABLE,
391 ALIGN_ITEMS_STRING_TABLE_COUNT,
394 flexContainerImpl.SetAlignItems(alignItems);
398 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
400 Toolkit::FlexContainer::Alignment alignContent(Toolkit::FlexContainer::ALIGN_FLEX_START);
402 if(value.GetType() == Property::INTEGER)
404 flexContainerImpl.SetAlignContent(static_cast<Toolkit::FlexContainer::Alignment>(value.Get<int>()));
406 else if(Scripting::GetEnumeration<Toolkit::FlexContainer::Alignment>(value.Get<std::string>().c_str(),
407 ALIGN_CONTENT_STRING_TABLE,
408 ALIGN_CONTENT_STRING_TABLE_COUNT,
411 flexContainerImpl.SetAlignContent(alignContent);
419 Property::Value FlexContainer::GetProperty(BaseObject* object, Property::Index index)
421 Property::Value value;
423 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(Dali::BaseHandle(object));
427 FlexContainer& flexContainerImpl(GetImpl(flexContainer));
430 case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
432 value = flexContainerImpl.GetContentDirection();
435 case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
437 value = flexContainerImpl.GetFlexDirection();
440 case Toolkit::FlexContainer::Property::FLEX_WRAP:
442 value = flexContainerImpl.GetFlexWrap();
445 case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
447 value = flexContainerImpl.GetJustifyContent();
450 case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
452 value = flexContainerImpl.GetAlignItems();
455 case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
457 value = flexContainerImpl.GetAlignContent();
466 void FlexContainer::OnChildAdd(Actor& child)
468 // Create a new node for the child.
469 FlexItemNode childNode;
470 childNode.actor = child;
471 childNode.node = YGNodeNew();
473 mChildrenNodes.push_back(childNode);
474 YGNodeInsertChild(mRootNode.node, childNode.node, mChildrenNodes.size() - 1);
476 Control::OnChildAdd(child);
479 void FlexContainer::OnChildRemove(Actor& child)
481 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
483 if(mChildrenNodes[i].actor.GetHandle() == child)
485 YGNodeRemoveChild(mRootNode.node, mChildrenNodes[i].node);
486 YGNodeFree(mChildrenNodes[i].node);
488 mChildrenNodes.erase(mChildrenNodes.begin() + i);
490 // Relayout the container only if instances were found
496 Control::OnChildRemove(child);
499 void FlexContainer::OnRelayout(const Vector2& size, RelayoutContainer& container)
501 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
503 Actor child = mChildrenNodes[i].actor.GetHandle();
506 // Anchor actor to top left of the container
507 if(child.GetProperty(Actor::Property::POSITION_USES_ANCHOR_POINT).Get<bool>())
509 child.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
511 child.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
513 float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
514 float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
516 if(negotiatedWidth > 0)
518 YGNodeStyleSetWidth(mChildrenNodes[i].node, negotiatedWidth);
520 if(negotiatedHeight > 0)
522 YGNodeStyleSetHeight(mChildrenNodes[i].node, negotiatedHeight);
527 // Relayout the container
529 #if defined(FLEX_CONTAINER_DEBUG)
530 PrintNodes(mChildrenNodes);
533 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
535 Actor child = mChildrenNodes[i].actor.GetHandle();
538 if(child.GetPropertyType(Toolkit::FlexContainer::ChildProperty::FLEX) != Property::NONE)
540 // Only Set to USE_ASSIGNED_SIZE if the child actor is flexible.
542 if(child.GetResizePolicy(Dimension::WIDTH) != ResizePolicy::USE_ASSIGNED_SIZE)
544 child.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH);
546 if(child.GetResizePolicy(Dimension::HEIGHT) != ResizePolicy::USE_ASSIGNED_SIZE)
548 child.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT);
551 container.Add(child, Vector2(YGNodeLayoutGetWidth(mChildrenNodes[i].node), YGNodeLayoutGetHeight(mChildrenNodes[i].node)));
556 bool FlexContainer::RelayoutDependentOnChildren(Dimension::Type dimension)
561 void FlexContainer::OnSizeSet(const Vector3& size)
566 YGNodeStyleSetWidth(mRootNode.node, size.x);
567 YGNodeStyleSetHeight(mRootNode.node, size.y);
572 Control::OnSizeSet(size);
575 void FlexContainer::OnLayoutDirectionChanged(Dali::Actor actor, Dali::LayoutDirection::Type type)
577 Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(actor);
578 Toolkit::FlexContainer::ContentDirection direction;
580 if(type == Dali::LayoutDirection::RIGHT_TO_LEFT)
582 direction = Toolkit::FlexContainer::RTL;
586 direction = Toolkit::FlexContainer::LTR;
589 Toolkit::Internal::FlexContainer& flexContainerImpl = GetImpl(flexContainer);
591 if(flexContainerImpl.mContentDirection != direction)
593 Dali::CustomActor ownerActor(flexContainerImpl.GetOwner());
594 flexContainerImpl.mContentDirection = direction;
596 flexContainerImpl.RelayoutRequest();
600 void FlexContainer::ComputeLayout()
604 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
606 YGNodeRef childNode = mChildrenNodes[i].node;
607 Actor childActor = mChildrenNodes[i].actor.GetHandle();
609 // Intialize the style of the child.
610 YGNodeStyleSetMinWidth(childNode, childActor.GetProperty<Vector2>(Actor::Property::MINIMUM_SIZE).x);
611 YGNodeStyleSetMinHeight(childNode, childActor.GetProperty<Vector2>(Actor::Property::MINIMUM_SIZE).y);
612 YGNodeStyleSetMaxWidth(childNode, childActor.GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE).x);
613 YGNodeStyleSetMaxHeight(childNode, childActor.GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE).y);
615 // Check child properties on the child for how to layout it.
616 // These properties should be dynamically registered to the child which
617 // would be added to FlexContainer.
619 if(childActor.GetPropertyType(Toolkit::FlexContainer::ChildProperty::FLEX) != Property::NONE)
621 YGNodeStyleSetFlex(childNode, childActor.GetProperty(Toolkit::FlexContainer::ChildProperty::FLEX).Get<float>());
624 Toolkit::FlexContainer::Alignment alignSelf(Toolkit::FlexContainer::ALIGN_AUTO);
625 if(childActor.GetPropertyType(Toolkit::FlexContainer::ChildProperty::ALIGN_SELF) != Property::NONE)
627 Property::Value alignSelfPropertyValue = childActor.GetProperty(Toolkit::FlexContainer::ChildProperty::ALIGN_SELF);
628 if(alignSelfPropertyValue.GetType() == Property::INTEGER)
630 alignSelf = static_cast<Toolkit::FlexContainer::Alignment>(alignSelfPropertyValue.Get<int>());
632 else if(alignSelfPropertyValue.GetType() == Property::STRING)
634 std::string value = alignSelfPropertyValue.Get<std::string>();
635 Scripting::GetEnumeration<Toolkit::FlexContainer::Alignment>(value.c_str(),
636 ALIGN_SELF_STRING_TABLE,
637 ALIGN_SELF_STRING_TABLE_COUNT,
640 YGNodeStyleSetAlignSelf(childNode, static_cast<YGAlign>(alignSelf));
643 if(childActor.GetPropertyType(Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN) != Property::NONE)
645 Vector4 flexMargin = childActor.GetProperty(Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN).Get<Vector4>();
646 YGNodeStyleSetMargin(childNode, YGEdgeLeft, flexMargin.x);
647 YGNodeStyleSetMargin(childNode, YGEdgeTop, flexMargin.y);
648 YGNodeStyleSetMargin(childNode, YGEdgeRight, flexMargin.z);
649 YGNodeStyleSetMargin(childNode, YGEdgeBottom, flexMargin.w);
653 // Calculate the layout
654 YGDirection nodeLayoutDirection = YGDirectionInherit;
655 switch(mContentDirection)
657 case Dali::Toolkit::FlexContainer::LTR:
659 nodeLayoutDirection = YGDirectionLTR;
663 case Dali::Toolkit::FlexContainer::RTL:
665 nodeLayoutDirection = YGDirectionRTL;
669 case Dali::Toolkit::FlexContainer::INHERIT:
671 nodeLayoutDirection = YGDirectionInherit;
676 #if defined(FLEX_CONTAINER_DEBUG)
677 YGNodePrint(mRootNode.node, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren));
679 YGNodeCalculateLayout(mRootNode.node, Self().GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE).x, Self().GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE).y, nodeLayoutDirection);
680 #if defined(FLEX_CONTAINER_DEBUG)
681 YGNodePrint(mRootNode.node, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren));
686 void FlexContainer::RelayoutChildren()
690 // Set size and position of children according to the layout calculation
691 for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
693 Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
696 child.SetProperty(Actor::Property::POSITION_X, YGNodeLayoutGetLeft(mChildrenNodes[i].node));
697 child.SetProperty(Actor::Property::POSITION_Y, YGNodeLayoutGetTop(mChildrenNodes[i].node));
702 Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
704 Actor nextFocusableActor;
706 // First check whether there is any items in the container
707 if(mChildrenNodes.size() > 0)
709 if(!currentFocusedActor || currentFocusedActor == Self())
711 // Nothing is currently focused, so the first child in the container should be focused.
712 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
716 // Check whether the current focused actor is within flex container
717 int currentFocusedActorIndex = -1;
718 for(unsigned int index = 0; index < mChildrenNodes.size(); index++)
720 if(currentFocusedActor == mChildrenNodes[index].actor.GetHandle())
722 currentFocusedActorIndex = index;
727 if(currentFocusedActorIndex > -1)
729 int previousCheckedActorIndex = -1;
730 int nextFocusedActorIndex = currentFocusedActorIndex;
733 case Toolkit::Control::KeyboardFocus::LEFT:
734 case Toolkit::Control::KeyboardFocus::UP:
736 // Search the next focusable actor in the backward direction
739 nextFocusedActorIndex--;
740 if(nextFocusedActorIndex < 0)
742 nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
744 if(nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex)
746 previousCheckedActorIndex = nextFocusedActorIndex;
752 } while(!mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE));
755 case Toolkit::Control::KeyboardFocus::RIGHT:
756 case Toolkit::Control::KeyboardFocus::DOWN:
758 // Search the next focusable actor in the forward direction
761 nextFocusedActorIndex++;
762 if(nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1))
764 nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
766 if(nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex)
768 previousCheckedActorIndex = nextFocusedActorIndex;
774 } while(!mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE));
783 if(nextFocusedActorIndex != currentFocusedActorIndex)
785 nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
789 // No focusble child in the container
790 nextFocusableActor = Actor();
795 // The current focused actor is not within flex container, so the first child in the container should be focused.
796 nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
801 return nextFocusableActor;
804 FlexContainer::FlexContainer()
805 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
806 mContentDirection(Toolkit::FlexContainer::INHERIT),
807 mFlexDirection(Toolkit::FlexContainer::COLUMN),
808 mFlexWrap(Toolkit::FlexContainer::NO_WRAP),
809 mJustifyContent(Toolkit::FlexContainer::JUSTIFY_FLEX_START),
810 mAlignItems(Toolkit::FlexContainer::ALIGN_STRETCH),
811 mAlignContent(Toolkit::FlexContainer::ALIGN_FLEX_START)
813 SetKeyboardNavigationSupport(true);
816 void FlexContainer::OnInitialize()
818 // Initialize the node for the flex container itself
819 Dali::Actor self = Self();
820 self.LayoutDirectionChangedSignal().Connect(this, &FlexContainer::OnLayoutDirectionChanged);
822 mRootNode.actor = self;
823 mRootNode.node = YGNodeNew();
824 YGNodeSetContext(mRootNode.node, &mChildrenNodes);
827 YGNodeStyleSetFlexDirection(mRootNode.node, static_cast<YGFlexDirection>(mFlexDirection));
828 YGNodeStyleSetFlexWrap(mRootNode.node, static_cast<YGWrap>(mFlexWrap));
829 YGNodeStyleSetJustifyContent(mRootNode.node, static_cast<YGJustify>(mJustifyContent));
830 YGNodeStyleSetAlignItems(mRootNode.node, static_cast<YGAlign>(mAlignItems));
831 YGNodeStyleSetAlignContent(mRootNode.node, static_cast<YGAlign>(mAlignContent));
833 // Make self as keyboard focusable and focus group
834 self.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
835 SetAsKeyboardFocusGroup(true);
837 DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
838 return std::unique_ptr<Dali::Accessibility::Accessible>(
839 new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::FILLER));
843 } // namespace Internal
845 } // namespace Toolkit