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