Promote Control::Impl::AccessibleImpl to DevelControl
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / flex-container / flex-container-impl.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/flex-container/flex-container-impl.h>
20
21 // EXTERNAL INCLUDES
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>
29 #include <sstream>
30
31 #include <dali-toolkit/devel-api/controls/control-devel.h>
32
33 using namespace Dali;
34
35 namespace
36 {
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
40
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
44
45 #if defined(FLEX_CONTAINER_DEBUG)
46 void PrintNodes(Toolkit::Internal::FlexContainer::FlexItemNodeContainer itemNodes)
47 {
48   // Print the style property and layout of all the children
49   for(unsigned int i = 0; i < itemNodes.size(); ++i)
50   {
51     FC_LOG("Item %d style: \n", i);
52     YGNodePrint(itemNodes[i].node, (YGPrintOptions)(YGPrintOptionsStyle | YGPrintOptionsChildren));
53     FC_LOG("\n");
54     FC_LOG("Item %d layout: \n", i);
55     YGNodePrint(itemNodes[i].node, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren));
56     FC_LOG("\n");
57   }
58 }
59
60 #endif // defined(FLEX_CONTAINER_DEBUG)
61 #endif // defined(DEBUG_ENABLED)
62
63 } // namespace
64
65 namespace Dali
66 {
67 namespace Toolkit
68 {
69 namespace Internal
70 {
71 namespace
72 {
73 // Type registration
74 BaseHandle Create()
75 {
76   return Toolkit::FlexContainer::New();
77 }
78
79 // Setup properties, signals and actions using the type-registry.
80 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::FlexContainer, Toolkit::Control, Create);
81
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)
91
92 DALI_TYPE_REGISTRATION_END()
93
94 const Scripting::StringEnum ALIGN_SELF_STRING_TABLE[] =
95   {
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]);
102
103 const Scripting::StringEnum CONTENT_DIRECTION_STRING_TABLE[] =
104   {
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]);
109
110 const Scripting::StringEnum FLEX_DIRECTION_STRING_TABLE[] =
111   {
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]);
117
118 const Scripting::StringEnum FLEX_WRAP_STRING_TABLE[] =
119   {
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]);
123
124 const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
125   {
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]);
132
133 const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
134   {
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]);
140
141 const Scripting::StringEnum ALIGN_CONTENT_STRING_TABLE[] =
142   {
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]);
148
149 } // Unnamed namespace
150
151 Toolkit::FlexContainer FlexContainer::New()
152 {
153   // Create the implementation, temporarily owned by this handle on stack
154   IntrusivePtr<FlexContainer> impl = new FlexContainer();
155
156   // Pass ownership to CustomActor handle
157   Toolkit::FlexContainer handle(*impl);
158
159   // Second-phase init of the implementation
160   // This can only be done after the CustomActor connection has been made...
161   impl->Initialize();
162
163   return handle;
164 }
165
166 FlexContainer::~FlexContainer()
167 {
168   YGNodeFree(mRootNode.node);
169
170   for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
171   {
172     YGNodeFree(mChildrenNodes[i].node);
173   }
174
175   mChildrenNodes.clear();
176 }
177
178 void FlexContainer::SetContentDirection(Toolkit::FlexContainer::ContentDirection contentDirection)
179 {
180   if(mContentDirection != contentDirection)
181   {
182     Dali::CustomActor ownerActor(GetOwner());
183
184     if(Toolkit::FlexContainer::INHERIT != contentDirection)
185     {
186       mContentDirection = contentDirection;
187
188       ownerActor.SetProperty(Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, false);
189
190       if(Toolkit::FlexContainer::LTR == contentDirection)
191       {
192         ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT);
193       }
194       else
195       {
196         ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT);
197       }
198     }
199     else
200     {
201       ownerActor.SetProperty(Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, true);
202
203       Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(ownerActor.GetParent().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
204
205       if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
206       {
207         mContentDirection = Toolkit::FlexContainer::RTL;
208       }
209       else
210       {
211         mContentDirection = Toolkit::FlexContainer::LTR;
212       }
213     }
214
215     RelayoutRequest();
216   }
217 }
218
219 Toolkit::FlexContainer::ContentDirection FlexContainer::GetContentDirection()
220 {
221   return mContentDirection;
222 }
223
224 void FlexContainer::SetFlexDirection(Toolkit::FlexContainer::FlexDirection flexDirection)
225 {
226   if(mFlexDirection != flexDirection)
227   {
228     mFlexDirection = flexDirection;
229     YGNodeStyleSetFlexDirection(mRootNode.node, static_cast<YGFlexDirection>(flexDirection));
230
231     RelayoutRequest();
232   }
233 }
234
235 Toolkit::FlexContainer::FlexDirection FlexContainer::GetFlexDirection()
236 {
237   return mFlexDirection;
238 }
239
240 void FlexContainer::SetFlexWrap(Toolkit::FlexContainer::WrapType flexWrap)
241 {
242   if(mFlexWrap != flexWrap)
243   {
244     mFlexWrap = flexWrap;
245     YGNodeStyleSetFlexWrap(mRootNode.node, static_cast<YGWrap>(flexWrap));
246
247     RelayoutRequest();
248   }
249 }
250
251 Toolkit::FlexContainer::WrapType FlexContainer::GetFlexWrap()
252 {
253   return mFlexWrap;
254 }
255
256 void FlexContainer::SetJustifyContent(Toolkit::FlexContainer::Justification justifyContent)
257 {
258   if(mJustifyContent != justifyContent)
259   {
260     mJustifyContent = justifyContent;
261     YGNodeStyleSetJustifyContent(mRootNode.node, static_cast<YGJustify>(justifyContent));
262
263     RelayoutRequest();
264   }
265 }
266
267 Toolkit::FlexContainer::Justification FlexContainer::GetJustifyContent()
268 {
269   return mJustifyContent;
270 }
271
272 void FlexContainer::SetAlignItems(Toolkit::FlexContainer::Alignment alignItems)
273 {
274   if(mAlignItems != alignItems)
275   {
276     mAlignItems = alignItems;
277     YGNodeStyleSetAlignItems(mRootNode.node, static_cast<YGAlign>(alignItems));
278
279     RelayoutRequest();
280   }
281 }
282
283 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignItems()
284 {
285   return mAlignItems;
286 }
287
288 void FlexContainer::SetAlignContent(Toolkit::FlexContainer::Alignment alignContent)
289 {
290   if(mAlignContent != alignContent)
291   {
292     mAlignContent = alignContent;
293     YGNodeStyleSetAlignContent(mRootNode.node, static_cast<YGAlign>(alignContent));
294
295     RelayoutRequest();
296   }
297 }
298
299 Toolkit::FlexContainer::Alignment FlexContainer::GetAlignContent()
300 {
301   return mAlignContent;
302 }
303
304 void FlexContainer::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
305 {
306   Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(Dali::BaseHandle(object));
307
308   if(flexContainer)
309   {
310     FlexContainer& flexContainerImpl(GetImpl(flexContainer));
311     switch(index)
312     {
313       case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
314       {
315         Toolkit::FlexContainer::ContentDirection contentDirection(Toolkit::FlexContainer::INHERIT);
316
317         if(value.GetType() == Property::INTEGER)
318         {
319           flexContainerImpl.SetContentDirection(static_cast<Toolkit::FlexContainer::ContentDirection>(value.Get<int>()));
320         }
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,
324                                                                                     contentDirection))
325         {
326           flexContainerImpl.SetContentDirection(contentDirection);
327         }
328         break;
329       }
330       case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
331       {
332         Toolkit::FlexContainer::FlexDirection flexDirection(Toolkit::FlexContainer::COLUMN);
333
334         if(value.GetType() == Property::INTEGER)
335         {
336           flexContainerImpl.SetFlexDirection(static_cast<Toolkit::FlexContainer::FlexDirection>(value.Get<int>()));
337         }
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,
341                                                                                  flexDirection))
342         {
343           flexContainerImpl.SetFlexDirection(flexDirection);
344         }
345         break;
346       }
347       case Toolkit::FlexContainer::Property::FLEX_WRAP:
348       {
349         Toolkit::FlexContainer::WrapType flexWrap(Toolkit::FlexContainer::NO_WRAP);
350
351         if(value.GetType() == Property::INTEGER)
352         {
353           flexContainerImpl.SetFlexWrap(static_cast<Toolkit::FlexContainer::WrapType>(value.Get<int>()));
354         }
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,
358                                                                             flexWrap))
359         {
360           flexContainerImpl.SetFlexWrap(flexWrap);
361         }
362         break;
363       }
364       case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
365       {
366         Toolkit::FlexContainer::Justification justifyContent(Toolkit::FlexContainer::JUSTIFY_FLEX_START);
367
368         if(value.GetType() == Property::INTEGER)
369         {
370           flexContainerImpl.SetJustifyContent(static_cast<Toolkit::FlexContainer::Justification>(value.Get<int>()));
371         }
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,
375                                                                                  justifyContent))
376         {
377           flexContainerImpl.SetJustifyContent(justifyContent);
378         }
379         break;
380       }
381       case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
382       {
383         Toolkit::FlexContainer::Alignment alignItems(Toolkit::FlexContainer::ALIGN_STRETCH);
384
385         if(value.GetType() == Property::INTEGER)
386         {
387           flexContainerImpl.SetAlignItems(static_cast<Toolkit::FlexContainer::Alignment>(value.Get<int>()));
388         }
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,
392                                                                              alignItems))
393         {
394           flexContainerImpl.SetAlignItems(alignItems);
395         }
396         break;
397       }
398       case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
399       {
400         Toolkit::FlexContainer::Alignment alignContent(Toolkit::FlexContainer::ALIGN_FLEX_START);
401
402         if(value.GetType() == Property::INTEGER)
403         {
404           flexContainerImpl.SetAlignContent(static_cast<Toolkit::FlexContainer::Alignment>(value.Get<int>()));
405         }
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,
409                                                                              alignContent))
410         {
411           flexContainerImpl.SetAlignContent(alignContent);
412         }
413         break;
414       }
415     }
416   }
417 }
418
419 Property::Value FlexContainer::GetProperty(BaseObject* object, Property::Index index)
420 {
421   Property::Value value;
422
423   Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(Dali::BaseHandle(object));
424
425   if(flexContainer)
426   {
427     FlexContainer& flexContainerImpl(GetImpl(flexContainer));
428     switch(index)
429     {
430       case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
431       {
432         value = flexContainerImpl.GetContentDirection();
433         break;
434       }
435       case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
436       {
437         value = flexContainerImpl.GetFlexDirection();
438         break;
439       }
440       case Toolkit::FlexContainer::Property::FLEX_WRAP:
441       {
442         value = flexContainerImpl.GetFlexWrap();
443         break;
444       }
445       case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
446       {
447         value = flexContainerImpl.GetJustifyContent();
448         break;
449       }
450       case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
451       {
452         value = flexContainerImpl.GetAlignItems();
453         break;
454       }
455       case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
456       {
457         value = flexContainerImpl.GetAlignContent();
458         break;
459       }
460     }
461   }
462
463   return value;
464 }
465
466 void FlexContainer::OnChildAdd(Actor& child)
467 {
468   // Create a new node for the child.
469   FlexItemNode childNode;
470   childNode.actor = child;
471   childNode.node  = YGNodeNew();
472
473   mChildrenNodes.push_back(childNode);
474   YGNodeInsertChild(mRootNode.node, childNode.node, mChildrenNodes.size() - 1);
475
476   Control::OnChildAdd(child);
477 }
478
479 void FlexContainer::OnChildRemove(Actor& child)
480 {
481   for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
482   {
483     if(mChildrenNodes[i].actor.GetHandle() == child)
484     {
485       YGNodeRemoveChild(mRootNode.node, mChildrenNodes[i].node);
486       YGNodeFree(mChildrenNodes[i].node);
487
488       mChildrenNodes.erase(mChildrenNodes.begin() + i);
489
490       // Relayout the container only if instances were found
491       RelayoutRequest();
492       break;
493     }
494   }
495
496   Control::OnChildRemove(child);
497 }
498
499 void FlexContainer::OnRelayout(const Vector2& size, RelayoutContainer& container)
500 {
501   for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
502   {
503     Actor child = mChildrenNodes[i].actor.GetHandle();
504     if(child)
505     {
506       // Anchor actor to top left of the container
507       if(child.GetProperty(Actor::Property::POSITION_USES_ANCHOR_POINT).Get<bool>())
508       {
509         child.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
510       }
511       child.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
512
513       float negotiatedWidth  = child.GetRelayoutSize(Dimension::WIDTH);
514       float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
515
516       if(negotiatedWidth > 0)
517       {
518         YGNodeStyleSetWidth(mChildrenNodes[i].node, negotiatedWidth);
519       }
520       if(negotiatedHeight > 0)
521       {
522         YGNodeStyleSetHeight(mChildrenNodes[i].node, negotiatedHeight);
523       }
524     }
525   }
526
527   // Relayout the container
528   RelayoutChildren();
529 #if defined(FLEX_CONTAINER_DEBUG)
530   PrintNodes(mChildrenNodes);
531 #endif
532
533   for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
534   {
535     Actor child = mChildrenNodes[i].actor.GetHandle();
536     if(child)
537     {
538       if(child.GetPropertyType(Toolkit::FlexContainer::ChildProperty::FLEX) != Property::NONE)
539       {
540         // Only Set to USE_ASSIGNED_SIZE if the child actor is flexible.
541
542         if(child.GetResizePolicy(Dimension::WIDTH) != ResizePolicy::USE_ASSIGNED_SIZE)
543         {
544           child.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH);
545         }
546         if(child.GetResizePolicy(Dimension::HEIGHT) != ResizePolicy::USE_ASSIGNED_SIZE)
547         {
548           child.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT);
549         }
550       }
551       container.Add(child, Vector2(YGNodeLayoutGetWidth(mChildrenNodes[i].node), YGNodeLayoutGetHeight(mChildrenNodes[i].node)));
552     }
553   }
554 }
555
556 bool FlexContainer::RelayoutDependentOnChildren(Dimension::Type dimension)
557 {
558   return true;
559 }
560
561 void FlexContainer::OnSizeSet(const Vector3& size)
562 {
563   if(mRootNode.node)
564   {
565     Actor self = Self();
566     YGNodeStyleSetWidth(mRootNode.node, size.x);
567     YGNodeStyleSetHeight(mRootNode.node, size.y);
568
569     RelayoutRequest();
570   }
571
572   Control::OnSizeSet(size);
573 }
574
575 void FlexContainer::OnLayoutDirectionChanged(Dali::Actor actor, Dali::LayoutDirection::Type type)
576 {
577   Toolkit::FlexContainer                   flexContainer = Toolkit::FlexContainer::DownCast(actor);
578   Toolkit::FlexContainer::ContentDirection direction;
579
580   if(type == Dali::LayoutDirection::RIGHT_TO_LEFT)
581   {
582     direction = Toolkit::FlexContainer::RTL;
583   }
584   else
585   {
586     direction = Toolkit::FlexContainer::LTR;
587   }
588
589   Toolkit::Internal::FlexContainer& flexContainerImpl = GetImpl(flexContainer);
590
591   if(flexContainerImpl.mContentDirection != direction)
592   {
593     Dali::CustomActor ownerActor(flexContainerImpl.GetOwner());
594     flexContainerImpl.mContentDirection = direction;
595
596     flexContainerImpl.RelayoutRequest();
597   }
598 }
599
600 void FlexContainer::ComputeLayout()
601 {
602   if(mRootNode.node)
603   {
604     for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
605     {
606       YGNodeRef childNode  = mChildrenNodes[i].node;
607       Actor     childActor = mChildrenNodes[i].actor.GetHandle();
608
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);
614
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.
618
619       if(childActor.GetPropertyType(Toolkit::FlexContainer::ChildProperty::FLEX) != Property::NONE)
620       {
621         YGNodeStyleSetFlex(childNode, childActor.GetProperty(Toolkit::FlexContainer::ChildProperty::FLEX).Get<float>());
622       }
623
624       Toolkit::FlexContainer::Alignment alignSelf(Toolkit::FlexContainer::ALIGN_AUTO);
625       if(childActor.GetPropertyType(Toolkit::FlexContainer::ChildProperty::ALIGN_SELF) != Property::NONE)
626       {
627         Property::Value alignSelfPropertyValue = childActor.GetProperty(Toolkit::FlexContainer::ChildProperty::ALIGN_SELF);
628         if(alignSelfPropertyValue.GetType() == Property::INTEGER)
629         {
630           alignSelf = static_cast<Toolkit::FlexContainer::Alignment>(alignSelfPropertyValue.Get<int>());
631         }
632         else if(alignSelfPropertyValue.GetType() == Property::STRING)
633         {
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,
638                                                                        alignSelf);
639         }
640         YGNodeStyleSetAlignSelf(childNode, static_cast<YGAlign>(alignSelf));
641       }
642
643       if(childActor.GetPropertyType(Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN) != Property::NONE)
644       {
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);
650       }
651     }
652
653     // Calculate the layout
654     YGDirection nodeLayoutDirection = YGDirectionInherit;
655     switch(mContentDirection)
656     {
657       case Dali::Toolkit::FlexContainer::LTR:
658       {
659         nodeLayoutDirection = YGDirectionLTR;
660         break;
661       }
662
663       case Dali::Toolkit::FlexContainer::RTL:
664       {
665         nodeLayoutDirection = YGDirectionRTL;
666         break;
667       }
668
669       case Dali::Toolkit::FlexContainer::INHERIT:
670       {
671         nodeLayoutDirection = YGDirectionInherit;
672         break;
673       }
674     }
675
676 #if defined(FLEX_CONTAINER_DEBUG)
677     YGNodePrint(mRootNode.node, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren));
678 #endif
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));
682 #endif
683   }
684 }
685
686 void FlexContainer::RelayoutChildren()
687 {
688   ComputeLayout();
689
690   // Set size and position of children according to the layout calculation
691   for(unsigned int i = 0; i < mChildrenNodes.size(); i++)
692   {
693     Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
694     if(child)
695     {
696       child.SetProperty(Actor::Property::POSITION_X, YGNodeLayoutGetLeft(mChildrenNodes[i].node));
697       child.SetProperty(Actor::Property::POSITION_Y, YGNodeLayoutGetTop(mChildrenNodes[i].node));
698     }
699   }
700 }
701
702 Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
703 {
704   Actor nextFocusableActor;
705
706   // First check whether there is any items in the container
707   if(mChildrenNodes.size() > 0)
708   {
709     if(!currentFocusedActor || currentFocusedActor == Self())
710     {
711       // Nothing is currently focused, so the first child in the container should be focused.
712       nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
713     }
714     else
715     {
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++)
719       {
720         if(currentFocusedActor == mChildrenNodes[index].actor.GetHandle())
721         {
722           currentFocusedActorIndex = index;
723           break;
724         }
725       }
726
727       if(currentFocusedActorIndex > -1)
728       {
729         int previousCheckedActorIndex = -1;
730         int nextFocusedActorIndex     = currentFocusedActorIndex;
731         switch(direction)
732         {
733           case Toolkit::Control::KeyboardFocus::LEFT:
734           case Toolkit::Control::KeyboardFocus::UP:
735           {
736             // Search the next focusable actor in the backward direction
737             do
738             {
739               nextFocusedActorIndex--;
740               if(nextFocusedActorIndex < 0)
741               {
742                 nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
743               }
744               if(nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex)
745               {
746                 previousCheckedActorIndex = nextFocusedActorIndex;
747               }
748               else
749               {
750                 break;
751               }
752             } while(!mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE));
753             break;
754           }
755           case Toolkit::Control::KeyboardFocus::RIGHT:
756           case Toolkit::Control::KeyboardFocus::DOWN:
757           {
758             // Search the next focusable actor in the forward direction
759             do
760             {
761               nextFocusedActorIndex++;
762               if(nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1))
763               {
764                 nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
765               }
766               if(nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex)
767               {
768                 previousCheckedActorIndex = nextFocusedActorIndex;
769               }
770               else
771               {
772                 break;
773               }
774             } while(!mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE));
775             break;
776           }
777           default:
778           {
779             break;
780           }
781         }
782
783         if(nextFocusedActorIndex != currentFocusedActorIndex)
784         {
785           nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
786         }
787         else
788         {
789           // No focusble child in the container
790           nextFocusableActor = Actor();
791         }
792       }
793       else
794       {
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();
797       }
798     }
799   }
800
801   return nextFocusableActor;
802 }
803
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)
812 {
813   SetKeyboardNavigationSupport(true);
814 }
815
816 void FlexContainer::OnInitialize()
817 {
818   // Initialize the node for the flex container itself
819   Dali::Actor self = Self();
820   self.LayoutDirectionChangedSignal().Connect(this, &FlexContainer::OnLayoutDirectionChanged);
821
822   mRootNode.actor = self;
823   mRootNode.node  = YGNodeNew();
824   YGNodeSetContext(mRootNode.node, &mChildrenNodes);
825
826   // Set default style
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));
832
833   // Make self as keyboard focusable and focus group
834   self.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
835   SetAsKeyboardFocusGroup(true);
836
837   DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
838     return std::unique_ptr<Dali::Accessibility::Accessible>(
839       new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::FILLER));
840   });
841 }
842
843 } // namespace Internal
844
845 } // namespace Toolkit
846
847 } // namespace Dali