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