Include required header files directly rather than through dali.h
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / table-view / table-view-impl.cpp
1 /*
2  * Copyright (c) 2014 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/table-view/table-view-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <sstream>
23 #include <dali/public-api/adaptor-framework/physical-keyboard.h>
24 #include <dali/public-api/animation/constraint.h>
25 #include <dali/public-api/animation/time-period.h>
26 #include <dali/public-api/object/ref-object.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/public-api/scripting/scripting.h>
29 #include <dali/integration-api/debug.h>
30
31 // INTERNAL INCLUDES
32 #include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
33
34 using namespace Dali;
35 using namespace std;
36
37 namespace
38 {
39 const float DEFAULT_CONSTRAINT_DURATION = 0.0f;
40
41 /**
42  * Constraint that sets a child property relative to parents Width or Height
43  */
44 struct RelativeToWidthOrHeight
45 {
46   /**
47    * Constraint that is relative (%) to parent width/height and applies a
48    * unit based padding before the relative calculation.
49    * @param scale of parent minus padding between 0 and 1
50    * @param padding in world coordinate units
51    * @param fixed part in world coordinate units
52    */
53   RelativeToWidthOrHeight( float scale, float padding, float fixed )
54   : mScaleFactor( scale ),
55     mPadding( padding ),
56     mFixed( fixed )
57   {
58   }
59
60   inline float operator()( const float& parentWidthOrHeight )
61   {
62     return mFixed  + ( parentWidthOrHeight - mPadding  ) * mScaleFactor;
63   }
64
65   float operator()( const float& current,
66                     const PropertyInput& parentWidthOrHeight )
67   {
68     return operator()( parentWidthOrHeight.GetFloat() );
69   }
70
71   float mScaleFactor;
72   float mPadding;
73   float mFixed;
74 };
75
76 #if defined(DEBUG_ENABLED)
77 // debugging support, very useful when new features are added or bugs are hunted down
78 // currently not called from code so compiler will optimize these away, kept here for future debugging
79
80 #define TABLEVIEW_TAG "DALI Toolkit::TableView "
81 #define TV_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
82
83 void PrintArray( Array2d<Dali::Toolkit::Internal::TableView::CellData>& array )
84 {
85   TV_LOG( "Array2d<CellData> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
86   // print values
87   for( unsigned int i = 0; i < array.GetRows(); ++i )
88   {
89     for( unsigned int j = 0; j < array.GetColumns(); ++j )
90     {
91       Dali::Toolkit::Internal::TableView::CellData data = array[i][j];
92       char actor = ' ';
93       if( data.actor )
94       {
95         actor = 'A';
96       }
97       TV_LOG("Array[%d,%d]=%c %d,%d,%d,%d  ", i, j, actor,
98           data.position.rowIndex, data.position.columnIndex,
99           data.position.rowSpan, data.position.columnSpan );
100     }
101     TV_LOG( "\n" );
102   }
103 }
104
105 // debugging support, very useful when new features are added or bugs are hunted down
106 // currently not called from code so compiler will optimize these away, kept here for future debugging
107 void PrintArray( Array2d<Size>& array )
108 {
109   TV_LOG( "Array2d<Size> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
110   // print values
111   for( unsigned int i = 0; i < array.GetRows(); ++i )
112   {
113     for( unsigned int j = 0; j < array.GetColumns(); ++j )
114     {
115       TV_LOG( "Array[%d,%d]=%.2f,%.2f ", i, j, array[i][j].width, array[i][j].height );
116     }
117     TV_LOG( "\n" );
118   }
119 }
120 // debugging support, very useful when new features are added or bugs are hunted down
121 // currently not called from code so compiler will optimize these away, kept here for future debugging
122 void PrintVector( vector<float>& array )
123 {
124   TV_LOG( "vector, size [%d]\n", array.size() );
125   // print values
126   for( unsigned int i = 0; i < array.size(); ++i )
127   {
128     TV_LOG( "vector[%d]=%.2f ", i, array[i] );
129   }
130   TV_LOG( "\n" );
131 }
132 #endif // defined(DEBUG_ENABLED)
133
134 } // namespace
135
136 namespace Dali
137 {
138
139 namespace Toolkit
140 {
141
142 const Property::Index TableView::PROPERTY_ROWS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX );
143 const Property::Index TableView::PROPERTY_COLUMNS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 1 );
144 const Property::Index TableView::PROPERTY_CELL_PADDING( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 2 );
145 const Property::Index TableView::PROPERTY_LAYOUT_ANIMATION_DURATION( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 3 );
146 const Property::Index TableView::PROPERTY_LAYOUT_ROWS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 4 );
147 const Property::Index TableView::PROPERTY_LAYOUT_COLUMNS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 5 );
148
149 namespace Internal
150 {
151
152 namespace
153 {
154
155 const Scripting::StringEnum< Toolkit::TableView::LayoutPolicy > LAYOUT_POLICY_STRING_TABLE[] =
156 {
157  { "fixed",    Toolkit::TableView::Fixed    },
158  { "relative", Toolkit::TableView::Relative },
159  { "fill",     Toolkit::TableView::Fill }
160 };
161
162 const unsigned int LAYOUT_POLICY_STRING_TABLE_COUNT = sizeof(LAYOUT_POLICY_STRING_TABLE) / sizeof( LAYOUT_POLICY_STRING_TABLE[0] );
163
164 // Type registration
165 BaseHandle Create()
166 {
167   return Toolkit::TableView::New(0, 0);
168 }
169 TypeRegistration mType( typeid(Toolkit::TableView), typeid(Toolkit::Control), Create );
170
171 PropertyRegistration property1( mType, "rows", Toolkit::TableView::PROPERTY_ROWS, Property::UNSIGNED_INTEGER, &TableView::SetProperty, &TableView::GetProperty );
172 PropertyRegistration property2( mType, "columns", Toolkit::TableView::PROPERTY_COLUMNS, Property::UNSIGNED_INTEGER, &TableView::SetProperty, &TableView::GetProperty );
173 PropertyRegistration property3( mType, "cell-padding", Toolkit::TableView::PROPERTY_CELL_PADDING, Property::VECTOR2, &TableView::SetProperty, &TableView::GetProperty );
174 PropertyRegistration property4( mType, "layout-animation-duration", Toolkit::TableView::PROPERTY_LAYOUT_ANIMATION_DURATION, Property::FLOAT, &TableView::SetProperty, &TableView::GetProperty );
175 PropertyRegistration property5( mType, "layout-rows", Toolkit::TableView::PROPERTY_LAYOUT_ROWS, Property::MAP, &TableView::SetProperty, &TableView::GetProperty );
176 PropertyRegistration property6( mType, "layout-columns", Toolkit::TableView::PROPERTY_LAYOUT_COLUMNS, Property::MAP, &TableView::SetProperty, &TableView::GetProperty );
177
178 } // namespace
179
180 Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns )
181 {
182   // Create the implementation, temporarily owned by this handle on stack
183   IntrusivePtr< TableView > impl = new TableView( initialRows, initialColumns );
184
185   // Pass ownership to CustomActor handle
186   Toolkit::TableView handle( *impl );
187
188   // Second-phase init of the implementation
189   // This can only be done after the CustomActor connection has been made...
190   impl->Initialize();
191
192   return handle;
193 }
194
195 bool TableView::AddChild( Actor child, Toolkit::TableView::CellPosition position )
196 {
197   // check that the child is valid
198   DALI_ASSERT_ALWAYS( child );
199
200   // if child is already parented, we adopt it
201   if( child.GetParent() )
202   {
203     child.GetParent().Remove( child );
204   }
205   // check if we need to expand our data array
206   if( position.rowIndex >= mCellData.GetRows() )
207   {
208     // only adding new rows
209     ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
210   }
211   if( position.columnIndex >= mCellData.GetColumns() )
212   {
213     // only adding new columns
214     ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
215   }
216   // check if there already is something in this cell
217   if( mCellData[ position.rowIndex ][ position.columnIndex ].actor )
218   {
219     return false; // cannot share a cell, it would complicate all logic and not bring much benefit
220   }
221   RelayoutingLock lock( *this );
222   // adopt the child
223   Self().Add( child );
224
225   // put the actor to the main cell
226   CellData data;
227   data.actor = child;
228   data.position = position;
229   mCellData[ position.rowIndex ][ position.columnIndex ] = data;
230   // if child spans multiple rows of columns
231   bool spanned = false;
232   if( position.rowSpan > 1 )
233   {
234     // span might go outside table
235     if( position.rowIndex + position.rowSpan > mCellData.GetRows() )
236     {
237       // increase table size for the full span, only increasing rows
238       ResizeContainers( position.rowIndex + position.rowSpan, mCellData.GetColumns() );
239     }
240     spanned = true;
241   }
242   if( position.columnSpan > 1 )
243   {
244     // span might go outside table
245     if( position.columnIndex + position.columnSpan > mCellData.GetColumns() )
246     {
247       // increase table size for the full span, only increasing columns
248       ResizeContainers( mCellData.GetRows(), position.columnIndex + position.columnSpan );
249     }
250     spanned = true;
251   }
252   // if it spanned multiple rows, put the cellinfo in all of those
253   if( spanned )
254   {
255     for( unsigned int row = position.rowIndex; row < ( position.rowIndex + position.rowSpan ); ++row )
256     {
257       // store same information to all cells, this way we can identify
258       // if a cell is the prime location of an actor or a spanned one
259       for( unsigned int column = position.columnIndex; column < ( position.columnIndex + position.columnSpan ); ++column )
260       {
261         // store same information to all cells, this way we can identify
262         // if a cell is the prime location of an actor or a spanned one
263         mCellData[ row ][ column ] = data;
264       }
265     }
266   }
267   // relayout the whole table
268   RelayoutRequest();
269   return true; // addition successful
270 }
271
272 Actor TableView::GetChildAt( Toolkit::TableView::CellPosition position )
273 {
274   // check if we have this row and column in the table
275   if( ( position.columnIndex >= mCellData.GetColumns() )||
276       ( position.rowIndex >= mCellData.GetRows() ) )
277   {
278     // return an empty handle
279     return Actor();
280   }
281   // return the child handle
282   return mCellData[ position.rowIndex ][ position.columnIndex ].actor;
283 }
284
285 Actor TableView::RemoveChildAt( Toolkit::TableView::CellPosition position )
286 {
287   // get the child handle
288   Actor child = GetChildAt( position );
289   // if no real actor there, nothing else to be done
290   if( child )
291   {
292     RelayoutingLock lock( *this );
293     // Remove the child, this will trigger a call to OnControlChildRemove
294     Self().Remove( child );
295
296     // relayout the table only if instances were found
297     if( RemoveAllInstances( child ) )
298     {
299       RelayoutRequest();
300     }
301   }
302   // return the child back to caller
303   return child;
304 }
305
306 bool TableView::FindChildPosition( Actor child, Toolkit::TableView::CellPosition& position )
307 {
308   // only find valid child actors
309   if( child )
310   {
311     // walk through the layout data
312     const unsigned int rowCount = mCellData.GetRows();
313     const unsigned int columnCount = mCellData.GetColumns();
314     for( unsigned int row = 0; row < rowCount; ++row )
315     {
316       for( unsigned int column = 0; column < columnCount; ++column )
317       {
318         if( mCellData[ row ][ column ].actor == child )
319         {
320           position = mCellData[ row ][ column ].position;
321           return true;
322         }
323       }
324     }
325   }
326   return false;
327 }
328
329 void TableView::InsertRow( unsigned int rowIndex )
330 {
331   RelayoutingLock lock( *this );
332   mCellData.InsertRow( rowIndex );
333   // need to update the cellinfos for the items that moved
334   const unsigned int rowCount = mCellData.GetRows();
335   const unsigned int columnCount = mCellData.GetColumns();
336   for( unsigned int row = 0; row < rowCount; ++row )
337   {
338     for( unsigned int column = 0; column < columnCount; ++column )
339     {
340       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
341       // if cell is spanning and above and spans to inserted row
342       if( ( position.rowSpan > 1 )&&( position.rowIndex <= rowIndex )&&
343           ( position.rowIndex + position.rowSpan > rowIndex ) )
344       {
345         // increase span by one
346         position.rowSpan++;
347         // copy cell to occupy the new column
348         mCellData[ rowIndex ][ column ] = mCellData[ row ][ column ];
349       }
350       // if below of inserted row, increase row index
351       else if( row > rowIndex )
352       {
353         // increase index by one
354         position.rowIndex++;
355       }
356     }
357   }
358   mRelativeSizes.InsertRow( rowIndex );
359   // inserting a row requires adjusting the height vectors
360   mFixedHeights.insert( mFixedHeights.begin() + rowIndex, 0 );
361   mRelativeHeights.insert( mRelativeHeights.begin() + rowIndex, 0 );
362   RelayoutRequest();
363 }
364
365 void TableView::DeleteRow( unsigned int rowIndex )
366 {
367   vector< Actor > ignored;
368   DeleteRow( rowIndex, ignored );
369 }
370
371 void TableView::DeleteRow( unsigned int rowIndex, vector<Actor>& removed )
372 {
373   RelayoutingLock lock( *this );
374   vector< CellData > lost;
375   mCellData.DeleteRow( rowIndex, lost );
376   // need to update the cellinfos for the items that moved
377   const unsigned int rowCount = mCellData.GetRows();
378   const unsigned int columnCount = mCellData.GetColumns();
379   for( unsigned int row = 0; row < rowCount; ++row )
380   {
381     for( unsigned int column = 0; column < columnCount; ++column )
382     {
383       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
384       // if cell is spanning and above and spans to deleted row
385       if( ( position.rowSpan > 1 )&&( position.rowIndex <= rowIndex )&&
386           ( position.rowIndex + position.rowSpan > rowIndex ) )
387       {
388         // decrease span by one
389         if( position.rowSpan > 1 )
390         {
391           position.rowSpan--;
392         }
393       }
394       // if below of or at the inserted row, decrease row index
395       else if( row >= rowIndex )
396       {
397         // decrease index by one
398         if( position.rowIndex > 1 )
399         {
400           position.rowIndex--;
401         }
402       }
403     }
404   }
405   // 1 row removed, 0 columns
406   RemoveAndGetLostActors( lost, removed, 1u, 0u );
407   // resize the data structures
408   mRelativeSizes.DeleteRow( rowIndex );
409   // deleting a row requires adjusting the height vectors
410   mFixedHeights.erase( mFixedHeights.begin() + rowIndex );
411   mRelativeHeights.erase( mRelativeHeights.begin() + rowIndex );
412   RelayoutRequest();
413 }
414
415 void TableView::InsertColumn( unsigned int columnIndex )
416 {
417   RelayoutingLock lock( *this );
418   mCellData.InsertColumn( columnIndex );
419   // need to update the cellinfos for the items that moved
420   const unsigned int rowCount = mCellData.GetRows();
421   const unsigned int columnCount = mCellData.GetColumns();
422   for( unsigned int row = 0; row < rowCount; ++row )
423   {
424     for( unsigned int column = 0; column < columnCount; ++column )
425     {
426       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
427       // if cell is spanning and left side and spans to inserted column
428       if( ( position.columnSpan > 1 )&&( position.columnIndex <= columnIndex )&&
429           ( position.columnIndex + position.columnSpan > columnIndex ) )
430       {
431         // increase span by one
432         position.columnSpan++;
433         // copy cell to occupy the new column
434         mCellData[ row ][ columnIndex ] = mCellData[ row ][ column ];
435       }
436       // if on the right side of inserted column, increase column index
437       else if( column > columnIndex )
438       {
439         // increase index by one
440         position.columnIndex++;
441       }
442     }
443   }
444   // relative sizes gets recalculated on Relayout
445   mRelativeSizes.InsertColumn( columnIndex );
446   // inserting a column requires adjusting the width vectors
447   mFixedWidths.insert( mFixedWidths.begin() + columnIndex, 0 );
448   mRelativeWidths.insert( mRelativeWidths.begin() + columnIndex, 0 );
449   RelayoutRequest();
450 }
451
452 void TableView::DeleteColumn( unsigned int columnIndex )
453 {
454   vector< Actor > ignored;
455   DeleteColumn( columnIndex, ignored );
456 }
457
458 void TableView::DeleteColumn( unsigned int columnIndex, vector<Actor>& removed )
459 {
460   RelayoutingLock lock( *this );
461   vector< CellData > lost;
462   mCellData.DeleteColumn( columnIndex, lost );
463   // need to update the cellinfos for the items that moved
464   const unsigned int rowCount = mCellData.GetRows();
465   const unsigned int columnCount = mCellData.GetColumns();
466   for( unsigned int row = 0; row < rowCount; ++row )
467   {
468     for( unsigned int column = 0; column < columnCount; ++column )
469     {
470       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
471       // if cell is spanning and left side and spans to inserted column
472       if( ( position.columnSpan > 1 )&&( position.columnIndex <= columnIndex )&&
473           ( position.columnIndex + position.columnSpan > columnIndex ) )
474       {
475         // decrease span by one
476         if( position.columnSpan > 1 )
477         {
478           position.columnSpan--;
479         }
480       }
481       // if on the right side of or at the inserted column, decrease column index
482       else if( column >= columnIndex )
483       {
484         // decrease index by one
485         if( position.columnIndex > 0 )
486         {
487           position.columnIndex--;
488         }
489       }
490     }
491   }
492   // 0 rows, 1 column removed
493   RemoveAndGetLostActors( lost, removed, 0u, 1u );
494   // resize the data structures
495   mRelativeSizes.DeleteColumn( columnIndex );
496   // deleting a column requires adjusting the width vectors
497   mFixedWidths.erase( mFixedWidths.begin() + columnIndex );
498   mRelativeWidths.erase( mRelativeWidths.begin() + columnIndex );
499   // relayout
500   RelayoutRequest();
501 }
502
503 void TableView::Resize( unsigned int rows, unsigned int columns )
504 {
505   vector< Actor > ignored;
506   Resize( rows, columns, ignored );
507 }
508
509 void TableView::Resize( unsigned int rows, unsigned int columns, vector<Actor>& removed )
510 {
511   RelayoutingLock lock( *this );
512   unsigned int oldRows = GetRows();
513   unsigned int oldColumns = GetColumns();
514   // resize data array
515   vector< CellData > lost;
516   ResizeContainers( rows, columns, lost );
517   // calculate if we lost rows or columns
518   unsigned int rowsRemoved = 0;
519   unsigned int newRows = GetRows();
520   if( oldRows < newRows )
521   {
522     rowsRemoved = newRows - oldRows;
523   }
524   unsigned int columnsRemoved = 0;
525   unsigned int newColumns = GetColumns();
526   if( oldColumns < newColumns )
527   {
528     rowsRemoved = newColumns - oldColumns;
529   }
530   RemoveAndGetLostActors( lost, removed, rowsRemoved, columnsRemoved );
531   // finally relayout once all actors are removed
532   RelayoutRequest();
533 }
534
535 void TableView::SetCellPadding( Size padding )
536 {
537   // if padding really changed
538   if( padding != mPadding )
539   {
540     mPadding = padding;
541     // do a relayout
542     RelayoutRequest();
543   }
544 }
545
546 Size TableView::GetCellPadding()
547 {
548   return mPadding;
549 }
550
551 void TableView::SetFixedHeight( unsigned int rowIndex, float height )
552 {
553   DALI_ASSERT_ALWAYS( rowIndex < mFixedHeights.size() );
554   // add the fixed height to the array of fixed heights
555   mFixedHeights[ rowIndex ] = height;
556   // remove the relative height of the same row
557   mRelativeHeights[ rowIndex ] = 0.f;
558   // relayout all cells, no lock needed as nothing added or removed
559   RelayoutRequest();
560 }
561
562 float TableView::GetFixedHeight( unsigned int rowIndex ) const
563 {
564   DALI_ASSERT_ALWAYS( rowIndex < mFixedHeights.size() );
565
566   return mFixedHeights[ rowIndex ];
567 }
568
569 void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage )
570 {
571   DALI_ASSERT_ALWAYS( rowIndex < mRelativeHeights.size() );
572   // add the relative height to the array of relative heights
573   mRelativeHeights[ rowIndex ] = heightPercentage;
574   // remove the fixed height of the same row
575   mFixedHeights[ rowIndex ] = 0.f;
576   // relayout all cells, no lock needed as nothing added or removed
577   RelayoutRequest();
578 }
579
580 float TableView::GetRelativeHeight( unsigned int rowIndex ) const
581 {
582   DALI_ASSERT_ALWAYS( rowIndex < mRelativeHeights.size() );
583
584   return mRelativeHeights[ rowIndex ];
585 }
586
587 void TableView::SetFixedWidth( unsigned int columnIndex, float width )
588 {
589   DALI_ASSERT_ALWAYS( columnIndex < mFixedWidths.size() );
590   // add the fixed width to the array of fixed column widths
591   mFixedWidths[ columnIndex ] = width;
592   // remove the relative width of the same column
593   mRelativeWidths[ columnIndex ] = 0.f;
594   // relayout all cells, no lock needed as nothing added or removed
595   RelayoutRequest();
596 }
597
598 float TableView::GetFixedWidth( unsigned int columnIndex ) const
599 {
600   DALI_ASSERT_ALWAYS( columnIndex < mFixedWidths.size() );
601
602   return mFixedWidths[ columnIndex ];
603 }
604
605 void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentage )
606 {
607   DALI_ASSERT_ALWAYS( columnIndex < mRelativeWidths.size() );
608   // add the relative widths to the array of relative widths
609   mRelativeWidths[ columnIndex ] = widthPercentage;
610   // remove the fixed width of the same column
611   mFixedWidths[ columnIndex ] = 0.f;
612   // relayout all cells, no lock needed as nothing added or removed
613   RelayoutRequest();
614 }
615
616 float TableView::GetRelativeWidth( unsigned int columnIndex ) const
617 {
618   DALI_ASSERT_ALWAYS( columnIndex < mRelativeWidths.size() );
619
620   return mRelativeWidths[ columnIndex ];
621 }
622
623 void TableView::SetLayoutAnimationDuration( float duration )
624 {
625   mConstraintDuration = duration;
626 }
627
628 float TableView::GetLayoutAnimationDuration()
629 {
630   return mConstraintDuration;
631 }
632
633 void TableView::OnRelaidOut( Vector2 size, ActorSizeContainer& container )
634 {
635   float fixedHeightsTotal = 0.0f;
636   float fixedWidthsTotal = 0.0f;
637
638   // 1. update the relative sizes and calculate total fixed height and width
639   UpdateRelativeSizes( fixedHeightsTotal, fixedWidthsTotal );
640
641   // 2. go through the layout data and create constraints
642   float cumulatedFixedHeight = 0.0f;
643   float cumulatedRelativeHeight = 0.0f;
644
645   // iterate the table
646   const unsigned int rowCount = mCellData.GetRows();
647   const unsigned int columnCount = mCellData.GetColumns();
648   // float versions of the count + 1 to keep precision
649   const float maxRowPlusOne( rowCount + 1 );
650   const float maxColumnPlusOne( columnCount + 1 );
651   for( unsigned int row = 0; row < rowCount; ++row )
652   {
653     // reset widths at the start of each row
654     float cumulatedFixedWidth = 0.0f;
655     float cumulatedRelativeWidth = 0.0f;
656     for( unsigned int column = 0; column < columnCount; ++column )
657     {
658       // check if this cell has an actor
659       Actor actor = mCellData[ row ][ column ].actor;
660       const Toolkit::TableView::CellPosition position = mCellData[ row ][ column ].position;
661       // if there is an actor and this is the main cell of the actor
662       // an actor can be in multiple cells if its row or columnspan is more than 1
663       // we however must only lay out each actor only once
664       if( ( actor )&&( position.rowIndex == row )&&( position.columnIndex == column ) )
665       {
666         // anchor actor correctly
667         actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
668         actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
669         // remove old constraints
670         actor.RemoveConstraints();
671
672         // 1. set position
673         // get the row and column indices
674         float rowPos( position.rowIndex );
675         float colPos( position.columnIndex );
676         // constrain the actor position to be relative to the width and height of table
677         // minus the padding of course (padding is all around cells)
678         Vector2 relativePosition( cumulatedRelativeWidth, cumulatedRelativeHeight );
679         // fixed height rows and fixed width cells are considered as padding so
680         // they are removed from the total size for relative
681         // for position only consider cumulated fixed rows and columns from top and left
682         Vector2 positionPadding( maxColumnPlusOne * mPadding.width + fixedWidthsTotal,
683                                  maxRowPlusOne * mPadding.height + fixedHeightsTotal );
684         Vector2 fixedPosition( ( colPos + 1.0f ) * mPadding.width + cumulatedFixedWidth,
685                                  ( rowPos + 1.0f ) * mPadding.height + cumulatedFixedHeight );
686
687         Constraint widthConstraint = Constraint::New<float>( Actor::POSITION_X,
688                                                              ParentSource( Actor::SIZE_WIDTH ),
689                                                              RelativeToWidthOrHeight( relativePosition.x, positionPadding.x, fixedPosition.x ) );
690
691         Constraint heightConstraint = Constraint::New<float>( Actor::POSITION_Y,
692                                                               ParentSource( Actor::SIZE_HEIGHT ),
693                                                               RelativeToWidthOrHeight( relativePosition.y, positionPadding.y, fixedPosition.y ) );
694
695         widthConstraint.SetApplyTime( mConstraintDuration );
696         heightConstraint.SetApplyTime( mConstraintDuration );
697
698         // bake constrained position value if constraint is removed
699         widthConstraint.SetRemoveAction( Constraint::Bake );
700         heightConstraint.SetRemoveAction( Constraint::Bake );
701
702         actor.ApplyConstraint( widthConstraint );
703         actor.ApplyConstraint( heightConstraint );
704
705         // 2. set size
706         // constrain the actor size to be relative to the size of table
707         // get the relative size for this cell
708         Vector2 relativeSize( mRelativeSizes[ row ][ column ] );
709         Vector2 fixedSize( mFixedWidths[ column ], mFixedHeights[ row ] );
710         // if we span multiple cells, need to sum them all up, both fixed and relative parts
711         if( position.rowSpan > 1 )
712         {
713           for( unsigned int i = 1; i < position.rowSpan; ++i )
714           {
715             // accumulate the height only
716             relativeSize.height += mRelativeSizes[ row + i ][ column ].height;
717             fixedSize.height += mFixedHeights[ row + i ];
718           }
719         }
720         if( position.columnSpan > 1 )
721         {
722           for( unsigned int i = 1; i < position.columnSpan; ++i )
723           {
724             // accumulate the width only
725             relativeSize.width += mRelativeSizes[ row ][ column + i ].width;
726             fixedSize.width += mFixedWidths[ column + i ];
727           }
728         }
729         // minus the padding from size (padding is all around cells)
730         // if item spans multiple columns or rows then less padding is added (default span is 1)
731         // fixed height rows and fixed width cells are considered as padding so they are removed
732         // from the total available size for relative cells
733         Vector2 sizePadding( maxColumnPlusOne * mPadding.width + fixedWidthsTotal,
734                              maxRowPlusOne * mPadding.height + fixedHeightsTotal );
735         // and added to the fixed size multiplied by the span of rows and columns
736         fixedSize.width += ( position.columnSpan - 1.0f ) * mPadding.width;
737         fixedSize.height += ( position.rowSpan - 1.0f ) * mPadding.height;
738
739         RelativeToWidthOrHeight relativeWidthFunctor( relativeSize.x, sizePadding.x, fixedSize.x );
740         RelativeToWidthOrHeight relativeHeightFunctor( relativeSize.y, sizePadding.y, fixedSize.y );
741
742         widthConstraint = Constraint::New<float>( Actor::SIZE_WIDTH,
743                                                   ParentSource( Actor::SIZE_WIDTH ),
744                                                   relativeWidthFunctor );
745
746         heightConstraint = Constraint::New<float>( Actor::SIZE_HEIGHT,
747                                                    ParentSource( Actor::SIZE_HEIGHT ),
748                                                    relativeHeightFunctor );
749
750         widthConstraint.SetApplyTime( mConstraintDuration );
751         heightConstraint.SetApplyTime( mConstraintDuration );
752
753         // bake constrained size value if constraint is removed
754         widthConstraint.SetRemoveAction( Constraint::Bake );
755         heightConstraint.SetRemoveAction( Constraint::Bake );
756
757         actor.ApplyConstraint( widthConstraint );
758         actor.ApplyConstraint( heightConstraint );
759
760         // Relayout Children
761         Relayout ( actor, Vector2( relativeWidthFunctor( size.width ), relativeHeightFunctor( size.height ) ), container );
762       }
763       // for position we need to keep track of current fixed width and relative width
764       // increase for next column
765       cumulatedFixedWidth += mFixedWidths[ column ];
766       cumulatedRelativeWidth += mRelativeSizes[ row ][ column ].width;
767     }
768     // for position we need to keep track of current fixed height and relative height
769     // increase for next row
770     cumulatedFixedHeight += mFixedHeights[ row ];
771     cumulatedRelativeHeight += mRelativeSizes[ row ][ 0 ].height; // all columns share same height
772   }
773 }
774
775 unsigned int TableView::GetRows()
776 {
777   return mCellData.GetRows();
778 }
779
780 unsigned int TableView::GetColumns()
781 {
782   return mCellData.GetColumns();
783 }
784
785 void TableView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
786 {
787   Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
788
789   if( tableView )
790   {
791     TableView& tableViewImpl( GetImpl( tableView ) );
792     switch( index )
793     {
794       case Toolkit::TableView::PROPERTY_ROWS:
795       {
796         if( value.Get<unsigned int>() != tableViewImpl.GetRows() )
797         {
798           tableViewImpl.Resize( value.Get<unsigned int>(), tableViewImpl.GetColumns() );
799         }
800         break;
801       }
802       case Toolkit::TableView::PROPERTY_COLUMNS:
803       {
804         if( value.Get<unsigned int>() != tableViewImpl.GetColumns() )
805         {
806           tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<unsigned int>() );
807         }
808         break;
809       }
810       case Toolkit::TableView::PROPERTY_CELL_PADDING:
811       {
812         tableViewImpl.SetCellPadding( value.Get<Vector2>() );
813         break;
814       }
815       case Toolkit::TableView::PROPERTY_LAYOUT_ANIMATION_DURATION:
816       {
817         tableViewImpl.SetLayoutAnimationDuration( value.Get<float>() );
818         break;
819       }
820       case Toolkit::TableView::PROPERTY_LAYOUT_ROWS:
821       {
822         SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, value );
823         break;
824       }
825       case Toolkit::TableView::PROPERTY_LAYOUT_COLUMNS:
826       {
827         SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, value );
828         break;
829       }
830     }
831   }
832 }
833
834 Property::Value TableView::GetProperty( BaseObject* object, Property::Index index )
835 {
836   Property::Value value;
837
838   Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
839
840   if( tableView )
841   {
842     TableView& tableViewImpl( GetImpl( tableView ) );
843     switch( index )
844     {
845       case Toolkit::TableView::PROPERTY_ROWS:
846       {
847         value = tableViewImpl.GetRows();
848         break;
849       }
850       case Toolkit::TableView::PROPERTY_COLUMNS:
851       {
852         value = tableViewImpl.GetColumns();
853         break;
854       }
855       case Toolkit::TableView::PROPERTY_CELL_PADDING:
856       {
857         value = tableViewImpl.GetCellPadding();
858         break;
859       }
860       case Toolkit::TableView::PROPERTY_LAYOUT_ANIMATION_DURATION:
861       {
862         value = tableViewImpl.GetLayoutAnimationDuration();
863         break;
864       }
865       case Toolkit::TableView::PROPERTY_LAYOUT_ROWS:
866       {
867         value = tableViewImpl.GetRowHeightsPropertyValue();
868         break;
869       }
870       case Toolkit::TableView::PROPERTY_LAYOUT_COLUMNS:
871       {
872         value = tableViewImpl.GetColumnWidthsPropertyValue();
873         break;
874       }
875     }
876   }
877
878   return value;
879 }
880
881 void TableView::OnControlChildAdd( Actor& child )
882 {
883   if( mLayoutingChild )
884   {
885     // we're in the middle of laying out children so no point doing anything here
886     return;
887   }
888
889   Toolkit::TableView::CellPosition cellPosition;
890   if( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
891   {
892     cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
893   }
894   if( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
895   {
896     cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
897   }
898   if( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) != Property::INVALID_INDEX )
899   {
900     Vector2 indices = child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) ).Get<Vector2 >();
901     cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
902     cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
903
904     AddChild( child, cellPosition );
905     // donot continue
906     return;
907   }
908
909   // check if we're already laying out this child somewhere on the table
910   // walk through the layout data
911   const unsigned int rowCount = mCellData.GetRows();
912   const unsigned int columnCount = mCellData.GetColumns();
913   // child not yet laid out, find the first free slot
914   for( unsigned int row = 0; row < rowCount; ++row )
915   {
916     for( unsigned int column = 0; column < columnCount; ++column )
917     {
918       // no actor means free cell
919       if( !(mCellData[ row ][ column ].actor) )
920       {
921         // put the actor in the cell
922         CellData data;
923         data.actor = child;
924         data.position.columnIndex = column;
925         data.position.rowIndex = row;
926         mCellData[ row ][ column ] = data;
927         RelayoutRequest();
928         // don' continue
929         return;
930       }
931     }
932   }
933   // still here, no room for the poor child so increase the array. Need a new row
934   ResizeContainers( rowCount + 1, columnCount );
935   // put the actor to the first cell of the new row
936   CellData data;
937   data.actor = child;
938   data.position.rowIndex = rowCount;
939   data.position.columnIndex = 0;
940   mCellData[ rowCount ][ 0 ] = data;
941   // finally relayout the table
942   RelayoutRequest();
943 }
944
945 void TableView::OnControlChildRemove( Actor& child )
946 {
947   // dont process if we're in the middle of bigger operation like delete row, column or resize
948   if( !mLayoutingChild )
949   {
950     // relayout the table only if instances were found
951     if( RemoveAllInstances( child ) )
952     {
953       RelayoutRequest();
954     }
955   }
956 }
957
958 TableView::TableView( unsigned int initialRows, unsigned int initialColumns )
959 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
960   mCellData( initialRows, initialColumns ),
961   mLayoutingChild( false ),
962   mConstraintDuration( DEFAULT_CONSTRAINT_DURATION )
963 {
964   SetKeyboardNavigationSupport( true );
965   ResizeContainers( initialRows, initialColumns );
966 }
967
968 void TableView::OnInitialize()
969 {
970   // Make self as keyboard focusable and focus group
971   Actor self = Self();
972   self.SetKeyboardFocusable(true);
973   SetAsKeyboardFocusGroup(true);
974 }
975
976 void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
977 {
978   vector<CellData> ignored;
979   ResizeContainers( rows, columns, ignored );
980 }
981
982 void TableView::ResizeContainers( unsigned int rows, unsigned int columns, vector<CellData>& removed )
983 {
984   mCellData.Resize( rows, columns, removed );
985   // we dont care if these go smaller, data will be regenerated or is not needed anymore
986   mRelativeSizes.Resize( rows, columns );
987   mFixedHeights.resize( rows );
988   mRelativeHeights.resize( rows );
989   mFixedWidths.resize( columns );
990   mRelativeWidths.resize( columns );
991 }
992
993 void TableView::RemoveAndGetLostActors( const vector<CellData>& lost, vector<Actor>& removed,
994                                         unsigned int rowsRemoved, unsigned int columnsRemoved )
995 {
996   // iterate through all lost cells
997   vector< CellData >::const_iterator iter = lost.begin();
998   for( ; iter != lost.end(); ++iter )
999   {
1000     // if it is a valid actor
1001     if( (*iter).actor )
1002     {
1003       // is this actor still somewhere else in the table
1004       Toolkit::TableView::CellPosition position;
1005       if( FindChildPosition( (*iter).actor, position ) )
1006       {
1007         // it must be spanning multiple cells, position contains the top left most one
1008         // check if position is left of the removed location
1009         if( position.columnIndex < (*iter).position.columnIndex )
1010         {
1011           // if column span is greater than 1
1012           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan > 1 )
1013           {
1014             // decrease column span
1015             mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan -= columnsRemoved;
1016           }
1017         }
1018         // check if position is left of the removed location
1019         if( position.rowIndex < (*iter).position.rowIndex )
1020         {
1021           // if row span is greater than 1
1022           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan > 1 )
1023           {
1024             // decrease row span
1025             mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan -= rowsRemoved;
1026           }
1027         }
1028       }
1029       else
1030       {
1031         // this actor is gone for good
1032         // add actor to removed container
1033         removed.push_back( (*iter).actor );
1034         // we dont want the child actor anymore
1035         Self().Remove( (*iter).actor );
1036       }
1037     }
1038   }
1039 }
1040
1041 bool TableView::RemoveAllInstances( Actor child )
1042 {
1043   bool found = false;
1044   // walk through the layout data
1045   const unsigned int rowCount = mCellData.GetRows();
1046   const unsigned int columnCount = mCellData.GetColumns();
1047   for( unsigned int row = 0; row < rowCount; ++row )
1048   {
1049     for( unsigned int column = 0; column < columnCount; ++column )
1050     {
1051       if( mCellData[ row ][ column ].actor == child )
1052       {
1053         // clear the cell, NOTE that the cell might be spanning multiple cells
1054         mCellData[ row ][ column ] = CellData();
1055         found = true;
1056       }
1057     }
1058   }
1059   return found;
1060 }
1061
1062 void TableView::UpdateRelativeSizes( float& fixedHeightsTotal, float& fixedWidthsTotal )
1063 {
1064   // 1. check all the fixed heights and widths to know how much size they take in total
1065   // as well as the relative heights and widths to know how much is left for the 'fill' cells
1066   unsigned int fixedRowCount = 0;
1067   unsigned int relativeRowCount = 0;
1068   float relativeHeightsTotal = 0.0f;
1069   const unsigned int rowCount = mCellData.GetRows();
1070   for( unsigned int row = 0; row < rowCount; ++row )
1071   {
1072     if( mFixedHeights[ row ] > 0.0f )
1073     {
1074       ++fixedRowCount;
1075       fixedHeightsTotal += mFixedHeights[ row ];
1076     }
1077     if( mRelativeHeights[ row ] > 0.0f )
1078     {
1079       ++relativeRowCount;
1080       relativeHeightsTotal += mRelativeHeights[ row ];
1081     }
1082   }
1083   unsigned int fixedColumnCount = 0;
1084   unsigned int relativeColumnCount = 0;
1085   const unsigned int columnCount = mCellData.GetColumns();
1086   float relativeWidthsTotal = 0.0f;
1087   for( unsigned int column = 0; column < columnCount; ++column )
1088   {
1089     if( mFixedWidths[ column ] > 0.0f )
1090     {
1091       ++fixedColumnCount;
1092       fixedWidthsTotal += mFixedWidths[ column ];
1093     }
1094     if( mRelativeWidths[ column ] > 0.0f )
1095     {
1096       ++relativeColumnCount;
1097       relativeWidthsTotal += mRelativeWidths[ column ];
1098     }
1099   }
1100
1101   // 2. cap the relative width and height totals to 100%
1102   if( relativeHeightsTotal > 1.0f )
1103   {
1104     relativeHeightsTotal = 1.0f;
1105   }
1106   if( relativeWidthsTotal > 1.0f )
1107   {
1108     relativeWidthsTotal = 1.0f;
1109   }
1110
1111   // 3. create a table of relative sizes so we can lookup for cells that span multiple rows & colums
1112   const float fillRowCount( rowCount - relativeRowCount - fixedRowCount );
1113   const float fillColumnCount( columnCount - relativeColumnCount - fixedColumnCount );
1114
1115   // walk through the data containers
1116   for( unsigned int row = 0; row < rowCount; ++row )
1117   {
1118     float relativeHeight = 0.0f;
1119     // if we have a fixed height, relative height is 0
1120     if( mFixedHeights[ row ] > 0.0f )
1121     {
1122       relativeHeight = 0.0f;
1123     }
1124     // else if we're given a specific row height %, use that
1125     else if( mRelativeHeights[ row ] > 0.0f )
1126     {
1127       relativeHeight = mRelativeHeights[ row ];
1128     }
1129     // else if there are fill rows
1130     else if( fillRowCount > 0 )
1131     {
1132       // this is a 'fill' row. it gets the remainder of the 100% divided evenly between 'fill' rows
1133       relativeHeight = (1.0f - relativeHeightsTotal ) / fillRowCount;
1134     }
1135     for( unsigned int column = 0; column < columnCount; ++column )
1136     {
1137       float relativeWidth = 0.0f;
1138       // if we have a fixed width, relative width is 0
1139       if( mFixedWidths[ column ] > 0.0f )
1140       {
1141         relativeWidth = 0.0f;
1142       }
1143       // else if we're given a specific column width %, use that
1144       else if( mRelativeWidths[ column ] > 0.0f )
1145       {
1146         relativeWidth = mRelativeWidths[ column ];
1147       }
1148       // else if there are fill columns
1149       else if( fillColumnCount > 0 )
1150       {
1151         // this is a 'fill' column. it gets the remainder of the 100% divided evenly between 'fill' columns
1152         relativeWidth = (1.0f - relativeWidthsTotal ) / fillColumnCount;
1153       }
1154       // store the value
1155       mRelativeSizes[ row ][ column ] = Size( relativeWidth, relativeHeight );
1156     }
1157   }
1158 }
1159
1160 void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
1161                                          void(TableView::*funcFixed)(unsigned int, float),
1162                                          void(TableView::*funcRelative)(unsigned int, float),
1163                                          const Property::Value& value )
1164 {
1165   if( Property::MAP == value.GetType() )
1166   {
1167     Property::Map map = value.Get<Property::Map>();
1168     unsigned int rowIndex(0);
1169     for ( unsigned int i = 0, count = map.Count(); i < count; ++i )
1170     {
1171       Property::Value& item = map.GetValue(i);
1172
1173       if( istringstream(map.GetKey(i)) >> rowIndex  // the key is a number
1174           && Property::MAP == item.GetType())
1175       {
1176         if( item.HasKey( "policy" ) && item.HasKey( "value" ) )
1177         {
1178           Toolkit::TableView::LayoutPolicy policy = Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( item.GetValue("policy").Get<string>(), LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT );
1179           if( policy == Toolkit::TableView::Fixed )
1180           {
1181             (tableViewImpl.*funcFixed)( rowIndex, item.GetValue("value").Get<float>() );
1182           }
1183           else if( policy == Toolkit::TableView::Relative )
1184           {
1185             (tableViewImpl.*funcRelative)( rowIndex, item.GetValue("value").Get<float>() );
1186           }
1187         }
1188       }
1189     }
1190   }
1191 }
1192
1193 Property::Value TableView::GetRowHeightsPropertyValue()
1194 {
1195   Property::Map map;
1196   GetMapPropertyValue( mFixedHeights, mRelativeHeights, map);
1197   return Property::Value(map);
1198 }
1199
1200 Property::Value TableView::GetColumnWidthsPropertyValue()
1201 {
1202   Property::Map map;
1203   GetMapPropertyValue( mFixedWidths, mRelativeWidths, map);
1204   return Property::Value(map);
1205 }
1206
1207 void TableView::GetMapPropertyValue( const std::vector<float>& fixedSize, const std::vector<float>& relativeSize, Property::Map& map )
1208 {
1209   string fixedPolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::Fixed, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
1210   string relativePolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::Relative, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
1211   Property::StringValuePair fixedPolicyPair( "policy", fixedPolicy );
1212   Property::StringValuePair relativePolicyPair( "policy", relativePolicy );
1213
1214   size_t count = fixedSize.size();
1215   for( size_t index = 0; index < count; index++ )
1216   {
1217     if( ! EqualsZero( fixedSize[index] ) )
1218     {
1219       Property::StringValuePair valuePair( "value", fixedSize[index] );
1220       Property::Map item;
1221       item[ fixedPolicyPair.first ] = fixedPolicyPair.second;
1222       item[ valuePair.first ] = valuePair.second;
1223
1224       map[ static_cast<std::ostringstream*>( &(std::ostringstream() << index ) )->str() ] = item;
1225     }
1226     else if( ! EqualsZero( relativeSize[index] ) )
1227     {
1228       Property::StringValuePair valuePair( "value", relativeSize[index] );
1229       Property::Map item;
1230       item[ relativePolicyPair.first ] = relativePolicyPair.second;
1231       item[ valuePair.first ] = valuePair.second;
1232
1233       map[ static_cast<std::ostringstream*>( &(std::ostringstream() << index ) )->str() ] = item;
1234     }
1235   }
1236 }
1237
1238 TableView::~TableView()
1239 {
1240   // nothing to do
1241 }
1242
1243 Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1244 {
1245   Actor nextFocusableActor;
1246
1247   if ( !currentFocusedActor )
1248   {
1249     // Nothing is currently focused, so the child in the first cell should be focused.
1250     nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1251   }
1252   else
1253   {
1254     Toolkit::TableView::CellPosition position;
1255     if( FindChildPosition( currentFocusedActor, position ) )
1256     {
1257       // The current focused actor is a child of TableView
1258       bool focusLost = false;
1259       int currentRow = position.rowIndex;
1260       int currentColumn = position.columnIndex;
1261       int numberOfColumns = GetColumns();
1262       int numberOfRows = GetRows();
1263
1264       switch ( direction )
1265       {
1266         case Toolkit::Control::Left:
1267         {
1268           if(--currentColumn < 0)
1269           {
1270             currentColumn = numberOfColumns - 1;
1271             if(--currentRow < 0)
1272             {
1273               currentRow = loopEnabled ? numberOfRows - 1 : 0;
1274               focusLost = (currentRow == 0);
1275             }
1276           }
1277           break;
1278         }
1279         case Toolkit::Control::Right:
1280         {
1281           if(++currentColumn > numberOfColumns - 1)
1282           {
1283             currentColumn = 0;
1284             if(++currentRow > numberOfRows - 1)
1285             {
1286               currentRow = loopEnabled ? 0 : numberOfRows - 1;
1287               focusLost = (currentRow == numberOfRows - 1);
1288             }
1289           }
1290           break;
1291         }
1292         case Toolkit::Control::Up:
1293         {
1294           if(--currentRow < 0)
1295           {
1296             currentRow = loopEnabled ? numberOfRows - 1 : 0;
1297             focusLost = (currentRow == 0);
1298           }
1299           break;
1300         }
1301         case Toolkit::Control::Down:
1302         {
1303           if(++currentRow > numberOfRows - 1)
1304           {
1305             currentRow = loopEnabled ? 0 : numberOfRows - 1;
1306             focusLost = (currentRow == numberOfRows - 1);
1307           }
1308           break;
1309         }
1310       }
1311
1312       // Move the focus if we haven't lost it.
1313       if(!focusLost)
1314       {
1315         nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1316       }
1317     }
1318     else
1319     {
1320       // The current focused actor is not within table view, so the child in the first cell should be focused.
1321       nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1322     }
1323   }
1324
1325   return nextFocusableActor;
1326 }
1327
1328 } // namespace Internal
1329
1330 } // namespace Toolkit
1331
1332 } // namespace Dali