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