[dali_1.1.36] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / flex-container / flex-container-impl.cpp
1 /*
2  * Copyright (c) 2016 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/scripting/scripting.h>
27 #include <dali/public-api/size-negotiation/relayout-container.h>
28 #include <dali/integration-api/debug.h>
29
30 using namespace Dali;
31
32 namespace
33 {
34
35 #if defined(DEBUG_ENABLED)
36 // debugging support, very useful when new features are added or bugs are hunted down
37 // currently not called from code so compiler will optimize these away, kept here for future debugging
38
39 #define FLEX_CONTAINER_TAG "DALI Toolkit::FlexContainer "
40 #define FC_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, FLEX_CONTAINER_TAG fmt, ## args)
41 //#define FLEX_CONTAINER_DEBUG 1
42
43 #if defined(FLEX_CONTAINER_DEBUG)
44 void PrintNode( Toolkit::Internal::FlexContainer::FlexItemNodeContainer itemNodes )
45 {
46   // Print the style property and layout of all the children
47   for( unsigned int i = 0; i < itemNodes.size(); ++i )
48   {
49     FC_LOG( "Item %d style: \n", i );
50     print_css_node( itemNodes[i].node, (css_print_options_t)( CSS_PRINT_STYLE | CSS_PRINT_CHILDREN ) );
51     FC_LOG( "Item %d layout: \n", i );
52     print_css_node( itemNodes[i].node, (css_print_options_t)( CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN ) );
53     FC_LOG( "\n" );
54   }
55 }
56
57 #endif // defined(FLEX_CONTAINER_DEBUG)
58 #endif // defined(DEBUG_ENABLED)
59
60
61 } // namespace
62
63 namespace Dali
64 {
65
66 namespace Toolkit
67 {
68
69 namespace Internal
70 {
71
72 namespace
73 {
74
75 // Type registration
76 BaseHandle Create()
77 {
78   return Toolkit::FlexContainer::New();
79 }
80
81 // Setup properties, signals and actions using the type-registry.
82 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::FlexContainer, Toolkit::Control, Create );
83
84 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "contentDirection",  INTEGER,  CONTENT_DIRECTION )
85 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "flexDirection",     INTEGER,  FLEX_DIRECTION    )
86 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "flexWrap",          INTEGER,  FLEX_WRAP         )
87 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "justifyContent",    INTEGER,  JUSTIFY_CONTENT   )
88 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "alignItems",        INTEGER,  ALIGN_ITEMS       )
89 DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "alignContent",      INTEGER,  ALIGN_CONTENT     )
90 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer,  "flex",              FLOAT,    FLEX              )
91 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer,  "alignSelf",         INTEGER,  ALIGN_SELF        )
92 DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer,  "flexMargin",        VECTOR4,  FLEX_MARGIN       )
93
94 DALI_TYPE_REGISTRATION_END()
95
96 const Scripting::StringEnum ALIGN_SELF_STRING_TABLE[] =
97 {
98   { "auto",        Toolkit::FlexContainer::ALIGN_AUTO        },
99   { "flexStart",   Toolkit::FlexContainer::ALIGN_FLEX_START  },
100   { "center",      Toolkit::FlexContainer::ALIGN_CENTER      },
101   { "flexEnd",     Toolkit::FlexContainer::ALIGN_FLEX_END    },
102   { "stretch",     Toolkit::FlexContainer::ALIGN_STRETCH     }
103 };
104 const unsigned int ALIGN_SELF_STRING_TABLE_COUNT = sizeof( ALIGN_SELF_STRING_TABLE ) / sizeof( ALIGN_SELF_STRING_TABLE[0] );
105
106 const Scripting::StringEnum CONTENT_DIRECTION_STRING_TABLE[] =
107 {
108   { "inherit",     Toolkit::FlexContainer::INHERIT           },
109   { "LTR",         Toolkit::FlexContainer::LTR               },
110   { "RTL",         Toolkit::FlexContainer::RTL               }
111 };
112 const unsigned int CONTENT_DIRECTION_STRING_TABLE_COUNT = sizeof( CONTENT_DIRECTION_STRING_TABLE ) / sizeof( CONTENT_DIRECTION_STRING_TABLE[0] );
113
114 const Scripting::StringEnum FLEX_DIRECTION_STRING_TABLE[] =
115 {
116   { "column",          Toolkit::FlexContainer::COLUMN          },
117   { "columnReverse",   Toolkit::FlexContainer::COLUMN_REVERSE  },
118   { "row",             Toolkit::FlexContainer::ROW             },
119   { "rowReverse",      Toolkit::FlexContainer::ROW_REVERSE     }
120 };
121 const unsigned int FLEX_DIRECTION_STRING_TABLE_COUNT = sizeof( FLEX_DIRECTION_STRING_TABLE ) / sizeof( FLEX_DIRECTION_STRING_TABLE[0] );
122
123 const Scripting::StringEnum FLEX_WRAP_STRING_TABLE[] =
124 {
125   { "noWrap",          Toolkit::FlexContainer::NO_WRAP         },
126   { "wrap",            Toolkit::FlexContainer::WRAP            }
127 };
128 const unsigned int FLEX_WRAP_STRING_TABLE_COUNT = sizeof( FLEX_WRAP_STRING_TABLE ) / sizeof( FLEX_WRAP_STRING_TABLE[0] );
129
130 const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
131 {
132   { "flexStart",       Toolkit::FlexContainer::JUSTIFY_FLEX_START     },
133   { "center",          Toolkit::FlexContainer::JUSTIFY_CENTER         },
134   { "flexEnd",         Toolkit::FlexContainer::JUSTIFY_FLEX_END       },
135   { "spaceBetween",    Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN  },
136   { "spaceAround",     Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND   }
137 };
138 const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof( JUSTIFY_CONTENT_STRING_TABLE ) / sizeof( JUSTIFY_CONTENT_STRING_TABLE[0] );
139
140 const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
141 {
142   { "flexStart",   Toolkit::FlexContainer::ALIGN_FLEX_START  },
143   { "center",      Toolkit::FlexContainer::ALIGN_CENTER      },
144   { "flexEnd",     Toolkit::FlexContainer::ALIGN_FLEX_END    },
145   { "stretch",     Toolkit::FlexContainer::ALIGN_STRETCH     }
146 };
147 const unsigned int ALIGN_ITEMS_STRING_TABLE_COUNT = sizeof( ALIGN_ITEMS_STRING_TABLE ) / sizeof( ALIGN_ITEMS_STRING_TABLE[0] );
148
149 const Scripting::StringEnum ALIGN_CONTENT_STRING_TABLE[] =
150 {
151   { "flexStart",   Toolkit::FlexContainer::ALIGN_FLEX_START  },
152   { "center",      Toolkit::FlexContainer::ALIGN_CENTER      },
153   { "flexEnd",     Toolkit::FlexContainer::ALIGN_FLEX_END    },
154   { "stretch",     Toolkit::FlexContainer::ALIGN_STRETCH     }
155 };
156 const unsigned int ALIGN_CONTENT_STRING_TABLE_COUNT = sizeof( ALIGN_CONTENT_STRING_TABLE ) / sizeof( ALIGN_CONTENT_STRING_TABLE[0] );
157
158 /**
159  * The function used by the layout algorithm to be get the style properties
160  * and layout information of the child at the given index.
161  */
162 css_node_t* GetChildNodeAtIndex( void *childrenNodes, int i )
163 {
164   FlexContainer::FlexItemNodeContainer childrenNodeContainer = *( static_cast<FlexContainer::FlexItemNodeContainer*>( childrenNodes ) );
165   return childrenNodeContainer[i].node;
166 }
167
168 /**
169  * The function used by the layout algorithm to check whether the node is dirty
170  * for relayout.
171  */
172 bool IsNodeDirty( void *itemNodes )
173 {
174   // We only calculate the layout when the child is added or removed, or when
175   // style properties are changed. So should always return true here.
176   return true;
177 }
178
179 } // Unnamed namespace
180
181 Toolkit::FlexContainer FlexContainer::New()
182 {
183   // Create the implementation, temporarily owned by this handle on stack
184   IntrusivePtr< FlexContainer > impl = new FlexContainer();
185
186   // Pass ownership to CustomActor handle
187   Toolkit::FlexContainer handle( *impl );
188
189   // Second-phase init of the implementation
190   // This can only be done after the CustomActor connection has been made...
191   impl->Initialize();
192
193   return handle;
194 }
195
196 FlexContainer::~FlexContainer()
197 {
198   free_css_node( mRootNode.node );
199
200   for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
201   {
202     free_css_node( mChildrenNodes[i].node );
203   }
204
205   mChildrenNodes.clear();
206 }
207
208 void FlexContainer::SetContentDirection( Toolkit::FlexContainer::ContentDirection contentDirection )
209 {
210   if( mContentDirection != contentDirection )
211   {
212     mContentDirection = contentDirection;
213     mRootNode.node->style.direction = static_cast<css_direction_t>( mContentDirection );
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     mRootNode.node->style.flex_direction = static_cast<css_flex_direction_t>( mFlexDirection );
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     mRootNode.node->style.flex_wrap = static_cast<css_wrap_type_t>( mFlexWrap );
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     mRootNode.node->style.justify_content = static_cast<css_justify_t>( mJustifyContent );
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     mRootNode.node->style.align_items = static_cast<css_align_t>( mAlignItems );
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     mRootNode.node->style.align_content = static_cast<css_align_t>( mAlignContent );
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   Control::OnChildAdd( child );
469
470   // Anchor actor to top left of the container
471   child.SetAnchorPoint( AnchorPoint::TOP_LEFT );
472   child.SetParentOrigin( ParentOrigin::TOP_LEFT );
473
474   // Create a new node for the child.
475   FlexItemNode childNode;
476   childNode.actor = child;
477   childNode.node = new_css_node();
478   childNode.node->get_child = GetChildNodeAtIndex;
479   childNode.node->is_dirty = IsNodeDirty;
480   mChildrenNodes.push_back(childNode);
481 }
482
483 void FlexContainer::OnChildRemove( Actor& child )
484 {
485   for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
486   {
487     if( mChildrenNodes[i].actor.GetHandle() == child )
488     {
489       free_css_node( mChildrenNodes[i].node );
490       mChildrenNodes.erase( mChildrenNodes.begin() + i );
491
492       // Relayout the container only if instances were found
493       RelayoutRequest();
494       break;
495     }
496   }
497
498   Control::OnChildRemove( child );
499 }
500
501 void FlexContainer::OnRelayout( const Vector2& size, RelayoutContainer& container )
502 {
503   for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
504   {
505     Actor child = mChildrenNodes[i].actor.GetHandle();
506     if( child )
507     {
508       float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
509       float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
510
511       if( negotiatedWidth > 0 )
512       {
513         mChildrenNodes[i].node->style.dimensions[CSS_WIDTH] = negotiatedWidth;
514       }
515       if( negotiatedHeight > 0 )
516       {
517         mChildrenNodes[i].node->style.dimensions[CSS_HEIGHT] = negotiatedHeight;
518       }
519     }
520   }
521
522   // Relayout the container
523   RelayoutChildren();
524
525   for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
526   {
527     Actor child = mChildrenNodes[i].actor.GetHandle();
528     if( child )
529     {
530       if( child.GetResizePolicy( Dimension::WIDTH ) != ResizePolicy::USE_ASSIGNED_SIZE )
531       {
532         child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
533       }
534       if( child.GetResizePolicy( Dimension::HEIGHT ) != ResizePolicy::USE_ASSIGNED_SIZE )
535       {
536         child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
537       }
538
539       container.Add( child, Vector2(mChildrenNodes[i].node->layout.dimensions[CSS_WIDTH], mChildrenNodes[i].node->layout.dimensions[CSS_HEIGHT] ) );
540     }
541   }
542 }
543
544 bool FlexContainer::RelayoutDependentOnChildren( Dimension::Type dimension )
545 {
546   return true;
547 }
548
549 void FlexContainer::OnSizeSet( const Vector3& size )
550 {
551   if( mRootNode.node )
552   {
553     Actor self = Self();
554
555     mRootNode.node->style.dimensions[CSS_WIDTH] = size.x;
556     mRootNode.node->style.dimensions[CSS_HEIGHT] = size.y;
557
558     RelayoutRequest();
559   }
560 }
561
562 void FlexContainer::OnSizeAnimation( Animation& animation, const Vector3& targetSize )
563 {
564   // @todo Animate the children to their target size and position
565 }
566
567 void FlexContainer::ComputeLayout()
568 {
569   if( mRootNode.node )
570   {
571     mRootNode.node->children_count = mChildrenNodes.size();
572
573     // Intialize the layout.
574     mRootNode.node->layout.position[CSS_LEFT] = 0;
575     mRootNode.node->layout.position[CSS_TOP] = 0;
576     mRootNode.node->layout.position[CSS_BOTTOM] = 0;
577     mRootNode.node->layout.position[CSS_RIGHT] = 0;
578     mRootNode.node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
579     mRootNode.node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
580
581     for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
582     {
583       css_node_t* childNode = mChildrenNodes[i].node;
584       Actor childActor = mChildrenNodes[i].actor.GetHandle();
585
586       childNode->layout.position[CSS_LEFT] = 0;
587       childNode->layout.position[CSS_TOP] = 0;
588       childNode->layout.position[CSS_BOTTOM] = 0;
589       childNode->layout.position[CSS_RIGHT] = 0;
590       childNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
591       childNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
592
593       // Intialize the style of the child.
594       childNode->style.minDimensions[CSS_WIDTH] = childActor.GetMinimumSize().x;
595       childNode->style.minDimensions[CSS_HEIGHT] = childActor.GetMinimumSize().y;
596       childNode->style.maxDimensions[CSS_WIDTH] = childActor.GetMaximumSize().x;
597       childNode->style.maxDimensions[CSS_HEIGHT] = childActor.GetMaximumSize().y;
598
599       // Check child properties on the child for how to layout it.
600       // These properties should be dynamically registered to the child which
601       // would be added to FlexContainer.
602
603       if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
604       {
605         childNode->style.flex = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX ).Get<float>();
606       }
607
608       Toolkit::FlexContainer::Alignment alignSelf( Toolkit::FlexContainer::ALIGN_AUTO );
609       if( childActor.GetPropertyType( Toolkit::FlexContainer::FlexContainer::ChildProperty::ALIGN_SELF ) != Property::NONE )
610       {
611         Property::Value alignSelfPropertyValue = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF );
612         if( alignSelfPropertyValue.GetType() == Property::INTEGER )
613         {
614           alignSelf = static_cast<Toolkit::FlexContainer::Alignment>( alignSelfPropertyValue.Get< int >() );
615         }
616         else if( alignSelfPropertyValue.GetType() == Property::STRING )
617         {
618           std::string value = alignSelfPropertyValue.Get<std::string>();
619           Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.c_str(),
620                                                                           ALIGN_SELF_STRING_TABLE,
621                                                                           ALIGN_SELF_STRING_TABLE_COUNT,
622                                                                           alignSelf );
623         }
624       }
625       childNode->style.align_self = static_cast<css_align_t>(alignSelf);
626
627       if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ) != Property::NONE )
628       {
629         Vector4 flexMargin = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ).Get<Vector4>();
630         childNode->style.margin[CSS_LEFT] = flexMargin.x;
631         childNode->style.margin[CSS_TOP] = flexMargin.y;
632         childNode->style.margin[CSS_RIGHT] = flexMargin.z;
633         childNode->style.margin[CSS_BOTTOM] = flexMargin.w;
634       }
635     }
636
637     // Calculate the layout
638     layoutNode( mRootNode.node, Self().GetMaximumSize().x, Self().GetMaximumSize().y, mRootNode.node->style.direction );
639   }
640 }
641
642 void FlexContainer::RelayoutChildren()
643 {
644   ComputeLayout();
645
646   // Set size and position of children according to the layout calculation
647   for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
648   {
649     Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
650     if( child )
651     {
652       child.SetX( mChildrenNodes[i].node->layout.position[CSS_LEFT] );
653       child.SetY( mChildrenNodes[i].node->layout.position[CSS_TOP] );
654     }
655   }
656 }
657
658 Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
659 {
660   Actor nextFocusableActor;
661
662   // First check whether there is any items in the container
663   if( mChildrenNodes.size() > 0 )
664   {
665     if ( !currentFocusedActor || currentFocusedActor == Self() )
666     {
667       // Nothing is currently focused, so the first child in the container should be focused.
668       nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
669     }
670     else
671     {
672       // Check whether the current focused actor is within flex container
673       int currentFocusedActorIndex = -1;
674       for( unsigned int index = 0; index < mChildrenNodes.size(); index++ )
675       {
676         if( currentFocusedActor == mChildrenNodes[index].actor.GetHandle() )
677         {
678           currentFocusedActorIndex = index;
679           break;
680         }
681       }
682
683       if( currentFocusedActorIndex > -1 )
684       {
685         int previousCheckedActorIndex = -1;
686         int nextFocusedActorIndex = currentFocusedActorIndex;
687         switch ( direction )
688         {
689           case Toolkit::Control::KeyboardFocus::LEFT:
690           case Toolkit::Control::KeyboardFocus::UP:
691           {
692             // Search the next focusable actor in the backward direction
693             do
694             {
695               nextFocusedActorIndex--;
696               if( nextFocusedActorIndex < 0 )
697               {
698                 nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
699               }
700               if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
701               {
702                 previousCheckedActorIndex = nextFocusedActorIndex;
703               }
704               else
705               {
706                 break;
707               }
708             } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
709             break;
710           }
711           case Toolkit::Control::KeyboardFocus::RIGHT:
712           case Toolkit::Control::KeyboardFocus::DOWN:
713           {
714             // Search the next focusable actor in the forward direction
715             do
716             {
717               nextFocusedActorIndex++;
718               if( nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1) )
719               {
720                 nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
721               }
722               if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
723               {
724                 previousCheckedActorIndex = nextFocusedActorIndex;
725               }
726               else
727               {
728                 break;
729               }
730             } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
731             break;
732           }
733         }
734
735         if( nextFocusedActorIndex != currentFocusedActorIndex )
736         {
737           nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
738         }
739         else
740         {
741           // No focusble child in the container
742           nextFocusableActor = Actor();
743         }
744       }
745       else
746       {
747         // The current focused actor is not within flex container, so the first child in the container should be focused.
748         nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
749       }
750     }
751   }
752
753   return nextFocusableActor;
754 }
755
756 FlexContainer::FlexContainer()
757 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
758   mContentDirection( Toolkit::FlexContainer::INHERIT ),
759   mFlexDirection( Toolkit::FlexContainer::COLUMN ),
760   mFlexWrap( Toolkit::FlexContainer::NO_WRAP ),
761   mJustifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START ),
762   mAlignItems( Toolkit::FlexContainer::ALIGN_STRETCH ),
763   mAlignContent( Toolkit::FlexContainer::ALIGN_FLEX_START )
764 {
765   SetKeyboardNavigationSupport( true );
766 }
767
768 void FlexContainer::OnInitialize()
769 {
770   // Initialize the node for the flex container itself
771   Dali::Actor self = Self();
772   mRootNode.actor = self;
773   mRootNode.node = new_css_node();
774   mRootNode.node->context = &mChildrenNodes;
775
776   // Set default style
777   mRootNode.node->style.direction = static_cast<css_direction_t>( mContentDirection );
778   mRootNode.node->style.flex_direction = static_cast<css_flex_direction_t>( mFlexDirection );
779   mRootNode.node->style.flex_wrap = static_cast<css_wrap_type_t>( mFlexWrap );
780   mRootNode.node->style.justify_content = static_cast<css_justify_t>( mJustifyContent );
781   mRootNode.node->style.align_items = static_cast<css_align_t>( mAlignItems );
782   mRootNode.node->style.align_content = static_cast<css_align_t>( mAlignContent );
783
784   // Set callbacks.
785   mRootNode.node->get_child = GetChildNodeAtIndex;
786   mRootNode.node->is_dirty = IsNodeDirty;
787
788   // Make self as keyboard focusable and focus group
789   self.SetKeyboardFocusable( true );
790   SetAsKeyboardFocusGroup( true );
791 }
792
793 } // namespace Internal
794
795 } // namespace Toolkit
796
797 } // namespace Dali