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