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