Changed all property & signal names to lowerCamelCase
[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/object/ref-object.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/devel-api/object/type-registry-helper.h>
26 #include <dali/devel-api/scripting/scripting.h>
27 #include <dali/public-api/size-negotiation/relayout-container.h>
28 #include <dali/integration-api/debug.h>
29
30 using namespace Dali;
31
32 namespace
33 {
34 /*
35  * Custom properties for where to put the actor.
36  *
37  * When an actor is add to the tableView through Actor::Add() instead of TableView::AddChild,
38  * the following custom properties of the actor are checked to decide the actor position inside the table
39  *
40  * These non-animatable properties should be registered to the child which would be added to the table
41  */
42 const char * const CELL_INDEX_PROPERTY_NAME("cellIndex");
43 const char * const ROW_SPAN_PROPERTY_NAME("rowSpan");
44 const char * const COLUMN_SPAN_PROPERTY_NAME("columnSpan");
45 const char * const CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME("cellHorizontalAlignment");
46 const char * const CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME("cellVerticalAlignment");
47
48 /**
49  * @brief Should the tableview fit around the given actor
50  *
51  * @param[in] actor The child actor to test against
52  * @param[dimension] The dimension to test against
53  */
54 bool FitToChild( Actor actor, Dimension::Type dimension )
55 {
56   return actor.GetResizePolicy( dimension ) != ResizePolicy::FILL_TO_PARENT && actor.GetRelayoutSize( dimension ) > 0.0f;
57 }
58
59 #if defined(DEBUG_ENABLED)
60 // debugging support, very useful when new features are added or bugs are hunted down
61 // currently not called from code so compiler will optimize these away, kept here for future debugging
62
63 #define TABLEVIEW_TAG "DALI Toolkit::TableView "
64 #define TV_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
65 //#define TABLEVIEW_DEBUG 1
66
67 #if defined(TABLEVIEW_DEBUG)
68 void PrintArray( Array2d<Dali::Toolkit::Internal::TableView::CellData>& array )
69 {
70   TV_LOG( "Array2d<CellData> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
71   // print values
72   for( unsigned int i = 0; i < array.GetRows(); ++i )
73   {
74     for( unsigned int j = 0; j < array.GetColumns(); ++j )
75     {
76       Dali::Toolkit::Internal::TableView::CellData data = array[i][j];
77       char actor = ' ';
78       std::string actorName;
79       if( data.actor )
80       {
81         actor = 'A';
82         actorName = data.actor.GetName();
83       }
84       TV_LOG("Array[%d,%d]=%c %s %d,%d,%d,%d  ", i, j, actor, actorName.c_str(),
85           data.position.rowIndex, data.position.columnIndex,
86           data.position.rowSpan, data.position.columnSpan );
87     }
88     TV_LOG( "\n" );
89   }
90 }
91
92 // debugging support, very useful when new features are added or bugs are hunted down
93 // currently not called from code so compiler will optimize these away, kept here for future debugging
94 void PrintArray( Array2d<Size>& array )
95 {
96   TV_LOG( "Array2d<Size> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
97   // print values
98   for( unsigned int i = 0; i < array.GetRows(); ++i )
99   {
100     for( unsigned int j = 0; j < array.GetColumns(); ++j )
101     {
102       TV_LOG( "Array[%d,%d]=%.2f,%.2f ", i, j, array[i][j].width, array[i][j].height );
103     }
104     TV_LOG( "\n" );
105   }
106 }
107 // debugging support, very useful when new features are added or bugs are hunted down
108 // currently not called from code so compiler will optimize these away, kept here for future debugging
109 void PrintVector( std::vector<float>& array )
110 {
111   TV_LOG( "vector, size [%d]\n", array.size() );
112   // print values
113   for( unsigned int i = 0; i < array.size(); ++i )
114   {
115     TV_LOG( "vector[%d]=%.2f ", i, array[i] );
116   }
117   TV_LOG( "\n" );
118 }
119 #endif // defined(TABLEVIEW_DEBUG)
120 #endif // defined(DEBUG_ENABLED)
121
122 } // namespace
123
124 namespace Dali
125 {
126
127 namespace Toolkit
128 {
129
130 namespace Internal
131 {
132
133 namespace
134 {
135
136 // Type registration
137 BaseHandle Create()
138 {
139   return Toolkit::TableView::New( 0, 0 );
140 }
141
142 // Setup properties, signals and actions using the type-registry.
143 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TableView, Toolkit::Control, Create );
144
145 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "rows",           INTEGER, ROWS           )
146 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "columns",        INTEGER, COLUMNS        )
147 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "cellPadding",    VECTOR2, CELL_PADDING   )
148 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutRows",     MAP,     LAYOUT_ROWS    )
149 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutColumns",  MAP,     LAYOUT_COLUMNS )
150
151 DALI_TYPE_REGISTRATION_END()
152
153 const Scripting::StringEnum LAYOUT_POLICY_STRING_TABLE[] =
154 {
155  { "fixed",    Toolkit::TableView::FIXED    },
156  { "relative", Toolkit::TableView::RELATIVE },
157  { "fill",     Toolkit::TableView::FILL     },
158  { "fit",      Toolkit::TableView::FIT      }
159 };
160 const unsigned int LAYOUT_POLICY_STRING_TABLE_COUNT = sizeof(LAYOUT_POLICY_STRING_TABLE) / sizeof( LAYOUT_POLICY_STRING_TABLE[0] );
161
162 const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
163 {
164   {"left",   HorizontalAlignment::LEFT},
165   {"center", HorizontalAlignment::CENTER},
166   {"right",  HorizontalAlignment::RIGHT}
167 };
168 const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof(HORIZONTAL_ALIGNMENT_STRING_TABLE) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] );
169
170 const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] =
171 {
172   {"top",    VerticalAlignment::TOP},
173   {"center", VerticalAlignment::CENTER},
174   {"bottom", VerticalAlignment::BOTTOM}
175 };
176 const unsigned int VERTICAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof(VERTICAL_ALIGNMENT_STRING_TABLE) / sizeof( VERTICAL_ALIGNMENT_STRING_TABLE[0] );
177
178 } // Unnamed namespace
179
180 Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns )
181 {
182   // Create the implementation, temporarily owned by this handle on stack
183   IntrusivePtr< TableView > impl = new TableView( initialRows, initialColumns );
184
185   // Pass ownership to CustomActor handle
186   Toolkit::TableView handle( *impl );
187
188   // Second-phase init of the implementation
189   // This can only be done after the CustomActor connection has been made...
190   impl->Initialize();
191
192   return handle;
193 }
194
195 bool TableView::AddChild( Actor& child, const Toolkit::TableView::CellPosition& position )
196 {
197   // check that the child is valid
198   DALI_ASSERT_ALWAYS( child );
199
200   // if child is already parented, we adopt it
201   child.Unparent();
202
203   // check if we need to expand our data array
204   if( position.rowIndex >= mCellData.GetRows() )
205   {
206     // only adding new rows
207     ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
208   }
209
210   if( position.columnIndex >= mCellData.GetColumns() )
211   {
212     // only adding new columns
213     ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
214   }
215
216   // check if there already is something in this cell
217   if( mCellData[ position.rowIndex ][ position.columnIndex ].actor )
218   {
219     return false; // cannot share a cell, it would complicate all logic and not bring much benefit
220   }
221
222   RelayoutingLock lock( *this );
223   // adopt the child
224   Self().Add( child );
225
226   // if child spans multiple rows of columns
227   if( ( position.rowSpan > 1 ) && ( position.rowIndex + position.rowSpan > mCellData.GetRows() ) )
228   {
229     // increase table size for the full span, only increasing rows
230     ResizeContainers( position.rowIndex + position.rowSpan, mCellData.GetColumns() );
231   }
232
233   if( ( position.columnSpan > 1 ) && ( position.columnIndex + position.columnSpan > mCellData.GetColumns() ) )
234   {
235     // increase table size for the full span, only increasing columns
236     ResizeContainers( mCellData.GetRows(), position.columnIndex + position.columnSpan );
237   }
238
239   // Fill in all cells that need the data
240   CellData data;
241   data.actor = child;
242   data.position = position;
243
244   for( unsigned int row = position.rowIndex; row < ( position.rowIndex + position.rowSpan ); ++row )
245   {
246     // store same information to all cells, this way we can identify
247     // if a cell is the prime location of an actor or a spanned one
248     for( unsigned int column = position.columnIndex; column < ( position.columnIndex + position.columnSpan ); ++column )
249     {
250       // store same information to all cells, this way we can identify
251       // if a cell is the prime location of an actor or a spanned one
252       mCellData[ row ][ column ] = data;
253     }
254   }
255
256   // Relayout the whole table
257   if( mRowData[position.rowIndex].sizePolicy == Toolkit::TableView::FIT && position.rowSpan == 1 )
258   {
259     mRowDirty = true;
260   }
261   if( mColumnData[position.columnIndex].sizePolicy == Toolkit::TableView::FIT && position.columnSpan == 1 )
262   {
263     mColumnDirty = true;
264   }
265
266   RelayoutRequest();
267
268   return true;    // Addition successful
269 }
270
271 Actor TableView::GetChildAt( const Toolkit::TableView::CellPosition& position )
272 {
273   if( ( position.rowIndex < mCellData.GetRows() ) && ( position.columnIndex < mCellData.GetColumns() ) )
274   {
275     return mCellData[ position.rowIndex ][ position.columnIndex ].actor;
276   }
277
278   // Return an empty handle
279   return Actor();
280 }
281
282 Actor TableView::RemoveChildAt( const Toolkit::TableView::CellPosition& position )
283 {
284   // get the child handle
285   Actor child = GetChildAt( position );
286   // if no real actor there, nothing else to be done
287   if( child )
288   {
289     RelayoutingLock lock( *this );
290     // Remove the child, this will trigger a call to OnControlChildRemove
291     Self().Remove( child );
292
293     // relayout the table only if instances were found
294     if( RemoveAllInstances( child ) )
295     {
296       if( mRowData[position.rowIndex].sizePolicy == Toolkit::TableView::FIT )
297       {
298         mRowDirty = true;
299       }
300       if( mColumnData[position.columnIndex].sizePolicy == Toolkit::TableView::FIT )
301       {
302         mColumnDirty = true;
303       }
304       RelayoutRequest();
305     }
306   }
307   // return the child back to caller
308   return child;
309 }
310
311 bool TableView::FindChildPosition( const Actor& child, Toolkit::TableView::CellPosition& positionOut )
312 {
313   // Only find valid child actors
314   if( child )
315   {
316     // Walk through the layout data
317     const unsigned int rowCount = mCellData.GetRows();
318     const unsigned int columnCount = mCellData.GetColumns();
319
320     for( unsigned int row = 0; row < rowCount; ++row )
321     {
322       for( unsigned int column = 0; column < columnCount; ++column )
323       {
324         if( mCellData[ row ][ column ].actor == child )
325         {
326           positionOut = mCellData[ row ][ column ].position;
327           return true;
328         }
329       }
330     }
331   }
332
333   return false;
334 }
335
336 void TableView::InsertRow( unsigned int rowIndex )
337 {
338   RelayoutingLock lock( *this );
339
340   mCellData.InsertRow( rowIndex );
341
342   // Need to update the cell infos for the items that moved
343   const unsigned int rowCount = mCellData.GetRows();
344   const unsigned int columnCount = mCellData.GetColumns();
345
346   for( unsigned int row = 0; row < rowCount; ++row )
347   {
348     for( unsigned int column = 0; column < columnCount; ++column )
349     {
350       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
351
352       // If cell is spanning and above and spans to inserted row
353       if( ( position.rowSpan > 1 ) && ( position.rowIndex <= rowIndex ) &&
354           ( position.rowIndex + position.rowSpan > rowIndex ) )
355       {
356         // Increment span
357         position.rowSpan++;
358
359         // Copy cell to occupy the new column
360         mCellData[ rowIndex ][ column ] = mCellData[ row ][ column ];
361       }
362       else if( row > rowIndex )   // If below of inserted row, increase row index
363       {
364         // Increment index
365         position.rowIndex++;
366       }
367     }
368   }
369
370   // Expand row data array
371   mRowData.Insert( mRowData.Begin() + rowIndex, RowColumnData() );
372
373   // Sizes may have changed, so relayout
374   mRowDirty = true;
375   RelayoutRequest();
376 }
377
378 void TableView::DeleteRow( unsigned int rowIndex )
379 {
380   std::vector< Actor > ignored;
381   DeleteRow( rowIndex, ignored );
382 }
383
384 void TableView::DeleteRow( unsigned int rowIndex, std::vector<Actor>& removed )
385 {
386   RelayoutingLock lock( *this );
387
388   // Delete the row
389   std::vector< CellData > lost;
390   mCellData.DeleteRow( rowIndex, lost );
391
392   // Need to update the cell infos for the items that moved
393   const unsigned int rowCount = mCellData.GetRows();
394   const unsigned int columnCount = mCellData.GetColumns();
395
396   for( unsigned int row = 0; row < rowCount; ++row )
397   {
398     for( unsigned int column = 0; column < columnCount; ++column )
399     {
400       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
401
402       // If cell is spanning and above and spans to deleted row
403       if( ( position.rowSpan > 1 ) && ( position.rowIndex <= rowIndex ) &&
404           ( position.rowIndex + position.rowSpan > rowIndex ) )
405       {
406         // Decrement span
407         if( position.rowSpan > 1 )
408         {
409           position.rowSpan--;
410         }
411       }
412       else if( row >= rowIndex )    // If below of or at the inserted row, decrease row index
413       {
414         // Decrement index
415         if( position.rowIndex > 1 )
416         {
417           position.rowIndex--;
418         }
419       }
420     }
421   }
422
423   // 1 row removed, 0 columns
424   RemoveAndGetLostActors( lost, removed, 1u, 0u );
425
426   // Contract row data array
427   mRowData.Erase( mRowData.Begin() + rowIndex );
428
429   // Sizes may have changed, so relayout
430   mRowDirty = true;
431   // it is possible that the deletion of row leads to remove of child which might further lead to the change of FIT column
432   mColumnDirty = true;
433
434   RelayoutRequest();
435 }
436
437 void TableView::InsertColumn( unsigned int columnIndex )
438 {
439   RelayoutingLock lock( *this );
440
441   // Insert the new column
442   mCellData.InsertColumn( columnIndex );
443
444   // Need to update the cell infos for the items that moved
445   const unsigned int rowCount = mCellData.GetRows();
446   const unsigned int columnCount = mCellData.GetColumns();
447
448   for( unsigned int row = 0; row < rowCount; ++row )
449   {
450     for( unsigned int column = 0; column < columnCount; ++column )
451     {
452       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
453
454       // If cell is spanning and left side and spans to inserted column
455       if( ( position.columnSpan > 1 ) && ( position.columnIndex <= columnIndex ) &&
456           ( position.columnIndex + position.columnSpan > columnIndex ) )
457       {
458         // Increment span
459         position.columnSpan++;
460
461         // Copy cell to occupy the new column
462         mCellData[ row ][ columnIndex ] = mCellData[ row ][ column ];
463       }
464       else if( column > columnIndex )   // If on the right side of inserted column, increase column index
465       {
466         // Increment index
467         position.columnIndex++;
468       }
469     }
470   }
471
472   // Expand column data array
473   mColumnData.Insert( mColumnData.Begin() + columnIndex, RowColumnData() );
474
475   // Sizes may have changed so relayout
476   mColumnDirty = true;
477   RelayoutRequest();
478 }
479
480 void TableView::DeleteColumn( unsigned int columnIndex )
481 {
482   std::vector< Actor > ignored;
483   DeleteColumn( columnIndex, ignored );
484 }
485
486 void TableView::DeleteColumn( unsigned int columnIndex, std::vector<Actor>& removed )
487 {
488   RelayoutingLock lock( *this );
489
490   // Remove the column
491   std::vector< CellData > lost;
492   mCellData.DeleteColumn( columnIndex, lost );
493
494   // Need to update the cell infos for the items that moved
495   const unsigned int rowCount = mCellData.GetRows();
496   const unsigned int columnCount = mCellData.GetColumns();
497
498   for( unsigned int row = 0; row < rowCount; ++row )
499   {
500     for( unsigned int column = 0; column < columnCount; ++column )
501     {
502       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
503
504       // If cell is spanning and left side and spans to inserted column
505       if( ( position.columnSpan > 1 ) && ( position.columnIndex <= columnIndex ) &&
506           ( position.columnIndex + position.columnSpan > columnIndex ) )
507       {
508         // Decrement span
509         if( position.columnSpan > 1 )
510         {
511           position.columnSpan--;
512         }
513       }
514       else if( column >= columnIndex )    // If on the right side of or at the inserted column, decrease column index
515       {
516         // Decrement index
517         if( position.columnIndex > 0 )
518         {
519           position.columnIndex--;
520         }
521       }
522     }
523   }
524
525   // 0 rows, 1 column removed
526   RemoveAndGetLostActors( lost, removed, 0u, 1u );
527
528   // Contract column data array
529   mColumnData.Erase( mColumnData.Begin() + columnIndex );
530
531   // Size may have changed so relayout
532   mColumnDirty = true;
533   // it is possible that the deletion of column leads to remove of child which might further lead to the change of FIT row
534   mRowDirty = true;
535
536   RelayoutRequest();
537 }
538
539 void TableView::Resize( unsigned int rows, unsigned int columns )
540 {
541   std::vector< Actor > ignored;
542   Resize( rows, columns, ignored );
543 }
544
545 void TableView::Resize( unsigned int rows, unsigned int columns, std::vector<Actor>& removed )
546 {
547   RelayoutingLock lock( *this );
548
549   unsigned int oldRows = GetRows();
550   unsigned int oldColumns = GetColumns();
551
552   // Resize data array
553   std::vector< CellData > lost;
554   ResizeContainers( rows, columns, lost );
555
556   // Calculate if we lost rows
557   unsigned int rowsRemoved = 0;
558   unsigned int newRows = GetRows();
559
560   if( oldRows < newRows )
561   {
562     rowsRemoved = newRows - oldRows;
563   }
564
565   // Calculate if we lost columns
566   unsigned int columnsRemoved = 0;
567   unsigned int newColumns = GetColumns();
568   if( oldColumns < newColumns )
569   {
570     rowsRemoved = newColumns - oldColumns;
571   }
572
573   RemoveAndGetLostActors( lost, removed, rowsRemoved, columnsRemoved );
574
575   // Sizes may have changed so request a relayout
576   mRowDirty = true;
577   mColumnDirty = true;
578   RelayoutRequest();
579 }
580
581 void TableView::SetCellPadding( Size padding )
582 {
583   // If padding really changed
584   if( padding != mPadding )
585   {
586     mPadding = padding;
587
588     RelayoutRequest();
589   }
590 }
591
592 Size TableView::GetCellPadding()
593 {
594   return mPadding;
595 }
596
597 void TableView::SetFitHeight( unsigned int rowIndex )
598 {
599   DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
600
601   if( mRowData[ rowIndex ].sizePolicy != Toolkit::TableView::FIT )
602   {
603     mRowData[ rowIndex ].sizePolicy = Toolkit::TableView::FIT;
604
605     mRowDirty = true;
606     RelayoutRequest();
607   }
608 }
609
610 bool TableView::IsFitHeight( unsigned int rowIndex ) const
611 {
612   DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
613
614   return mRowData[ rowIndex ].sizePolicy == Toolkit::TableView::FIT;
615 }
616
617 void TableView::SetFitWidth( unsigned int columnIndex )
618 {
619   DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
620
621   if( mColumnData[ columnIndex ].sizePolicy != Toolkit::TableView::FIT )
622   {
623     mColumnData[ columnIndex ].sizePolicy = Toolkit::TableView::FIT;
624
625     mColumnDirty = true;
626     RelayoutRequest();
627   }
628 }
629
630 bool TableView::IsFitWidth( unsigned int columnIndex ) const
631 {
632   DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
633
634   return mColumnData[ columnIndex ].sizePolicy == Toolkit::TableView::FIT;
635 }
636
637 void TableView::SetFixedHeight( unsigned int rowIndex, float height )
638 {
639   DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
640
641   RowColumnData& data = mRowData[ rowIndex ];
642   data.size = height;
643   data.sizePolicy = Toolkit::TableView::FIXED;
644
645   mRowDirty = true;
646   RelayoutRequest();
647 }
648
649 float TableView::GetFixedHeight( unsigned int rowIndex ) const
650 {
651   DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
652
653   return mRowData[ rowIndex ].size;
654 }
655
656 void TableView::SetFixedWidth( unsigned int columnIndex, float width )
657 {
658   DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
659
660   RowColumnData& data = mColumnData[ columnIndex ];
661   data.size = width;
662   data.sizePolicy = Toolkit::TableView::FIXED;
663
664   mColumnDirty = true;
665   RelayoutRequest();
666 }
667
668 float TableView::GetFixedWidth( unsigned int columnIndex ) const
669 {
670   DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
671
672   return mColumnData[ columnIndex ].size;
673 }
674
675 void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage )
676 {
677   DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
678
679   RowColumnData& data = mRowData[ rowIndex ];
680   data.fillRatio = heightPercentage;
681   data.sizePolicy = Toolkit::TableView::RELATIVE;
682
683   mRowDirty = true;
684   RelayoutRequest();
685 }
686
687 float TableView::GetRelativeHeight( unsigned int rowIndex ) const
688 {
689   DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
690
691   return mRowData[ rowIndex ].fillRatio;
692 }
693
694 void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentage )
695 {
696   DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
697
698   RowColumnData& data = mColumnData[ columnIndex ];
699   data.fillRatio = widthPercentage;
700   data.sizePolicy = Toolkit::TableView::RELATIVE;
701
702   mColumnDirty = true;
703   RelayoutRequest();
704 }
705
706 float TableView::GetRelativeWidth( unsigned int columnIndex ) const
707 {
708   DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
709
710   return mColumnData[ columnIndex ].fillRatio;
711 }
712
713 void TableView::OnCalculateRelayoutSize( Dimension::Type dimension )
714 {
715   if( (dimension & Dimension::WIDTH) && mColumnDirty )
716   {
717     /*
718      * FIXED and FIT have size in pixel
719      * Nothing to do with FIXED, as its value is assigned by user and will not get changed
720      *
721      * Need to update the size for FIT column here
722      */
723     CalculateFitSizes( mColumnData, Dimension::WIDTH );
724
725     /* RELATIVE and FILL have size in ratio
726      * Their size in pixel is not available until we get the negotiated size for the whole table
727      * Nothing to do with RELATIVE, as its ratio is assigned by user and will not get changed
728      *
729      * Need to update the ratio for FILL column here
730      */
731     CalculateFillSizes( mColumnData );
732
733     mFixedTotals.width = CalculateTotalFixedSize( mColumnData );
734   }
735
736   if( (dimension & Dimension::HEIGHT) && mRowDirty )
737   {
738     // refer to the comment above
739     CalculateFitSizes( mRowData, Dimension::HEIGHT );
740
741     // refer to the comment above
742     CalculateFillSizes( mRowData );
743
744     mFixedTotals.height = CalculateTotalFixedSize( mRowData );
745   }
746 }
747
748 void TableView::OnLayoutNegotiated( float size, Dimension::Type dimension )
749 {
750   // Update the column sizes
751   if( (dimension & Dimension::WIDTH) && mColumnDirty )
752   {
753     float remainingSize = size - mFixedTotals.width;
754     if( remainingSize < 0.0f )
755     {
756       remainingSize = 0.0f;
757     }
758
759     // update every column position in ColumnData array
760     float cumulatedWidth = 0.0f;
761     for( unsigned int column = 0, columnCount = mCellData.GetColumns(); column < columnCount; ++column )
762     {
763       if( mColumnData[ column ].sizePolicy == Toolkit::TableView::FILL ||  mColumnData[ column ].sizePolicy == Toolkit::TableView::RELATIVE)
764       {
765         mColumnData[ column ].size = mColumnData[ column ].fillRatio * remainingSize;
766       }
767
768       cumulatedWidth += mColumnData[ column ].size;
769       mColumnData[column].position = cumulatedWidth;
770     }
771
772     mColumnDirty = false;
773   }
774
775   // Update the row sizes
776   if( (dimension & Dimension::HEIGHT) && mRowDirty )
777   {
778     float remainingSize = size - mFixedTotals.height;
779     if( remainingSize < 0.0f )
780     {
781       remainingSize = 0.0f;
782     }
783
784     // update every row position in RowData array
785     float cumulatedHeight = 0.0f;
786     for( unsigned int row = 0, rowCount = mCellData.GetRows(); row < rowCount; ++row )
787     {
788       if( mRowData[ row ].sizePolicy == Toolkit::TableView::FILL ||  mRowData[ row ].sizePolicy == Toolkit::TableView::RELATIVE)
789       {
790         mRowData[ row ].size = mRowData[ row ].fillRatio * remainingSize;
791       }
792
793       cumulatedHeight += mRowData[ row ].size;
794       mRowData[row].position = cumulatedHeight;
795     }
796
797     mRowDirty = false;
798   }
799 }
800
801 void TableView::OnSizeSet( const Vector3& size )
802 {
803   // If this table view is size negotiated by another actor or control, then the
804   // rows and columns must be recalculated or the new size will not take effect.
805   mRowDirty = mColumnDirty = true;
806   RelayoutRequest();
807 }
808
809 void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
810 {
811   // Go through the layout data
812   for( unsigned int row = 0, rowCount = mCellData.GetRows(); row < rowCount; ++row )
813   {
814     for( unsigned int column = 0, columnCount = mCellData.GetColumns(); column < columnCount; ++column )
815     {
816       CellData& cellData= mCellData[ row ][ column ];
817       Actor& actor = cellData.actor;
818       const Toolkit::TableView::CellPosition position = cellData.position;
819
820       // If there is an actor and this is the main cell of the actor.
821       // An actor can be in multiple cells if its row or column span is more than 1.
822       // We however must lay out each actor only once.
823       if( actor &&  position.rowIndex == row && position.columnIndex == column )
824       {
825         // Anchor actor to top left of the cell
826         actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
827         actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
828
829         Padding padding;
830         actor.GetPadding( padding );
831
832         float left = column > 0 ? mColumnData[column-1].position : 0.f;
833         float right = mColumnData[column+position.columnSpan-1].position;
834         float top = row > 0 ? mRowData[row-1].position : 0.f;
835         float bottom = mRowData[row+position.rowSpan-1].position;
836
837         if( cellData.horizontalAlignment == HorizontalAlignment::LEFT )
838         {
839           actor.SetX( left + mPadding.width + padding.left );
840         }
841         else if( cellData.horizontalAlignment ==  HorizontalAlignment::RIGHT )
842         {
843           actor.SetX( right - mPadding.width - padding.right - actor.GetRelayoutSize( Dimension::WIDTH ) );
844         }
845         else //if( cellData.horizontalAlignment ==  HorizontalAlignment::CENTER )
846         {
847           actor.SetX( (left + right + padding.left - padding.right - actor.GetRelayoutSize( Dimension::WIDTH )) * 0.5f );
848         }
849
850         if( cellData.verticalAlignment == VerticalAlignment::TOP )
851         {
852           actor.SetY( top + mPadding.height + padding.top );
853         }
854         else if( cellData.verticalAlignment == VerticalAlignment::BOTTOM )
855         {
856           actor.SetY( bottom - mPadding.height - padding.bottom -  actor.GetRelayoutSize( Dimension::HEIGHT ) );
857         }
858         else //if( cellData.verticalAlignment = VerticalAlignment::CENTER )
859         {
860           actor.SetY( (top + bottom + padding.top - padding.bottom - actor.GetRelayoutSize( Dimension::HEIGHT )) * 0.5f );
861         }
862       }
863     }
864   }
865 }
866
867 unsigned int TableView::GetRows()
868 {
869   return mCellData.GetRows();
870 }
871
872 unsigned int TableView::GetColumns()
873 {
874   return mCellData.GetColumns();
875 }
876
877 void TableView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
878 {
879   Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
880
881   if( tableView )
882   {
883     TableView& tableViewImpl( GetImpl( tableView ) );
884     switch( index )
885     {
886       case Toolkit::TableView::Property::ROWS:
887       {
888         int rows = 0;
889         if( value.Get( rows ) && rows >= 0 )
890         {
891           if( static_cast<unsigned int>(rows) != tableViewImpl.GetRows() )
892           {
893             tableViewImpl.Resize( rows, tableViewImpl.GetColumns() );
894           }
895         }
896         break;
897       }
898       case Toolkit::TableView::Property::COLUMNS:
899       {
900         int columns = 0;
901         if( value.Get( columns ) && columns >= 0 )
902         {
903           if( static_cast<unsigned int>( columns ) != tableViewImpl.GetColumns() )
904           {
905             tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<int>() );
906           }
907         }
908         break;
909       }
910       case Toolkit::TableView::Property::CELL_PADDING:
911       {
912         tableViewImpl.SetCellPadding( value.Get<Vector2>() );
913         break;
914       }
915       case Toolkit::TableView::Property::LAYOUT_ROWS:
916       {
917         SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, &TableView::SetFitHeight, value );
918         break;
919       }
920       case Toolkit::TableView::Property::LAYOUT_COLUMNS:
921       {
922         SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, &TableView::SetFitWidth, value );
923         break;
924       }
925     }
926   }
927 }
928
929 Property::Value TableView::GetProperty( BaseObject* object, Property::Index index )
930 {
931   Property::Value value;
932
933   Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
934
935   if( tableView )
936   {
937     TableView& tableViewImpl( GetImpl( tableView ) );
938     switch( index )
939     {
940       case Toolkit::TableView::Property::ROWS:
941       {
942         value = static_cast<int>( tableViewImpl.GetRows() );
943         break;
944       }
945       case Toolkit::TableView::Property::COLUMNS:
946       {
947         value = static_cast<int>( tableViewImpl.GetColumns() );
948         break;
949       }
950       case Toolkit::TableView::Property::CELL_PADDING:
951       {
952         value = tableViewImpl.GetCellPadding();
953         break;
954       }
955       case Toolkit::TableView::Property::LAYOUT_ROWS:
956       {
957         value = tableViewImpl.GetRowHeightsPropertyValue();
958         break;
959       }
960       case Toolkit::TableView::Property::LAYOUT_COLUMNS:
961       {
962         value = tableViewImpl.GetColumnWidthsPropertyValue();
963         break;
964       }
965     }
966   }
967
968   return value;
969 }
970
971 void TableView::OnControlChildAdd( Actor& child )
972 {
973   if( mLayoutingChild )
974   {
975     // we're in the middle of laying out children so no point doing anything here
976     return;
977   }
978
979   // Test properties on actor
980   HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT;
981   VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP;
982   if( child.GetPropertyIndex( CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME ) != Property::INVALID_INDEX )
983   {
984     std::string value = child.GetProperty( child.GetPropertyIndex(CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME) ).Get<std::string >();
985     Scripting::GetEnumeration< HorizontalAlignment::Type >( value.c_str(),
986                                                             HORIZONTAL_ALIGNMENT_STRING_TABLE,
987                                                             HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
988                                                             horizontalAlignment );
989   }
990   if( child.GetPropertyIndex( CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME ) != Property::INVALID_INDEX )
991   {
992     std::string value = child.GetProperty( child.GetPropertyIndex(CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME) ).Get<std::string >();
993     Scripting::GetEnumeration< VerticalAlignment::Type >( value.c_str(),
994                                                           VERTICAL_ALIGNMENT_STRING_TABLE,
995                                                           VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
996                                                           verticalAlignment );
997   }
998
999
1000   Toolkit::TableView::CellPosition cellPosition;
1001   if( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
1002   {
1003     cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
1004   }
1005
1006   if( child.GetPropertyIndex(COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
1007   {
1008     cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
1009   }
1010
1011   if( child.GetPropertyIndex(CELL_INDEX_PROPERTY_NAME) != Property::INVALID_INDEX )
1012   {
1013     Vector2 indices = child.GetProperty( child.GetPropertyIndex(CELL_INDEX_PROPERTY_NAME) ).Get<Vector2 >();
1014     cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
1015     cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
1016
1017     AddChild( child, cellPosition );
1018     SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment);
1019
1020     // Do not continue
1021     return;
1022   }
1023
1024   // Find the first available cell to store the actor in
1025   const unsigned int rowCount = mCellData.GetRows();
1026   const unsigned int columnCount = mCellData.GetColumns();
1027   for( unsigned int row = 0; row < rowCount; ++row )
1028   {
1029     for( unsigned int column = 0; column < columnCount; ++column )
1030     {
1031       if( !(mCellData[ row ][ column ].actor) )
1032       {
1033         // Put the actor in the cell
1034         CellData data;
1035         data.actor = child;
1036         data.position.columnIndex = column;
1037         data.position.rowIndex = row;
1038         data.horizontalAlignment = horizontalAlignment;
1039         data.verticalAlignment = verticalAlignment;
1040         mCellData[ row ][ column ] = data;
1041
1042         // Don't continue
1043         RelayoutRequest();
1044         return;
1045       }
1046     }
1047   }
1048
1049   // No empty cells, so increase size of the table
1050   unsigned int newColumnCount = ( columnCount > 0 ) ? columnCount : 1;
1051   ResizeContainers( rowCount + 1, newColumnCount );
1052
1053   // Put the actor in the first cell of the new row
1054   CellData data;
1055   data.actor = child;
1056   data.position.rowIndex = rowCount;
1057   data.position.columnIndex = 0;
1058   data.horizontalAlignment = horizontalAlignment;
1059   data.verticalAlignment = verticalAlignment;
1060   mCellData[ rowCount ][ 0 ] = data;
1061   RelayoutRequest();
1062 }
1063
1064 void TableView::OnControlChildRemove( Actor& child )
1065 {
1066   // dont process if we're in the middle of bigger operation like delete row, column or resize
1067   if( !mLayoutingChild )
1068   {
1069     // relayout the table only if instances were found
1070     if( RemoveAllInstances( child ) )
1071     {
1072       RelayoutRequest();
1073     }
1074   }
1075 }
1076
1077 TableView::TableView( unsigned int initialRows, unsigned int initialColumns )
1078 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
1079   mCellData( initialRows, initialColumns ),
1080   mLayoutingChild( false ),
1081   mRowDirty( true ),     // Force recalculation first time
1082   mColumnDirty( true )
1083 {
1084   SetKeyboardNavigationSupport( true );
1085   ResizeContainers( initialRows, initialColumns );
1086 }
1087
1088 void TableView::OnInitialize()
1089 {
1090   // Make self as keyboard focusable and focus group
1091   Actor self = Self();
1092   self.SetKeyboardFocusable(true);
1093   SetAsKeyboardFocusGroup(true);
1094 }
1095
1096 void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
1097 {
1098   std::vector<CellData> ignored;
1099   ResizeContainers( rows, columns, ignored );
1100 }
1101
1102 void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& removed )
1103 {
1104   // Resize cell data
1105   mCellData.Resize( rows, columns, removed );
1106
1107   // We don't care if these go smaller, data will be regenerated or is not needed anymore
1108   mRowData.Resize( rows );
1109   mColumnData.Resize( columns );
1110 }
1111
1112 void TableView::RemoveAndGetLostActors( const std::vector<CellData>& lost, std::vector<Actor>& removed,
1113                                         unsigned int rowsRemoved, unsigned int columnsRemoved )
1114 {
1115   // iterate through all lost cells
1116   std::vector< CellData >::const_iterator iter = lost.begin();
1117   for( ; iter != lost.end(); ++iter )
1118   {
1119     // if it is a valid actor
1120     if( (*iter).actor )
1121     {
1122       // is this actor still somewhere else in the table
1123       Toolkit::TableView::CellPosition position;
1124       if( FindChildPosition( (*iter).actor, position ) )
1125       {
1126         // it must be spanning multiple cells, position contains the top left most one
1127         // check if position is left of the removed location
1128         if( position.columnIndex < (*iter).position.columnIndex )
1129         {
1130           // if column span is greater than 1
1131           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan > 1 )
1132           {
1133             // decrease column span
1134             mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan -= columnsRemoved;
1135           }
1136         }
1137         // check if position is left of the removed location
1138         if( position.rowIndex < (*iter).position.rowIndex )
1139         {
1140           // if row span is greater than 1
1141           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan > 1 )
1142           {
1143             // decrease row span
1144             mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan -= rowsRemoved;
1145           }
1146         }
1147       }
1148       else
1149       {
1150         // this actor is gone for good
1151         // add actor to removed container
1152         removed.push_back( (*iter).actor );
1153         // we dont want the child actor anymore
1154         Self().Remove( (*iter).actor );
1155       }
1156     }
1157   }
1158 }
1159
1160 bool TableView::RemoveAllInstances( const Actor& child )
1161 {
1162   bool found = false;
1163   // walk through the layout data
1164   const unsigned int rowCount = mCellData.GetRows();
1165   const unsigned int columnCount = mCellData.GetColumns();
1166   for( unsigned int row = 0; row < rowCount; ++row )
1167   {
1168     for( unsigned int column = 0; column < columnCount; ++column )
1169     {
1170       if( mCellData[ row ][ column ].actor == child )
1171       {
1172         // clear the cell, NOTE that the cell might be spanning multiple cells
1173         mCellData[ row ][ column ] = CellData();
1174         found = true;
1175       }
1176     }
1177   }
1178   return found;
1179 }
1180
1181 void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
1182                                          void(TableView::*funcFixed)(unsigned int, float),
1183                                          void(TableView::*funcRelative)(unsigned int, float),
1184                                          void(TableView::*funcFit)(unsigned int),
1185                                          const Property::Value& value )
1186 {
1187   Property::Map* map = value.GetMap();
1188   if( map )
1189   {
1190     unsigned int index(0);
1191     for ( unsigned int i = 0, count = map->Count(); i < count; ++i )
1192     {
1193       Property::Value& item = map->GetValue(i);
1194       Property::Map* childMap = item.GetMap();
1195
1196       std::istringstream( map->GetKey(i) ) >> index;
1197       if( childMap )
1198       {
1199         Property::Value* policy = childMap->Find( "policy" );
1200         Property::Value* value = childMap->Find( "value" );
1201         if( policy && value )
1202         {
1203           std::string policyValue;
1204           policy->Get( policyValue );
1205           Toolkit::TableView::LayoutPolicy policy;
1206           if( Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( policyValue.c_str(),
1207                                                                              LAYOUT_POLICY_STRING_TABLE,
1208                                                                              LAYOUT_POLICY_STRING_TABLE_COUNT,
1209                                                                              policy ) )
1210           {
1211             if( policy == Toolkit::TableView::FIXED  )
1212             {
1213               (tableViewImpl.*funcFixed)( index, value->Get<float>() );
1214             }
1215             else if( policy == Toolkit::TableView::RELATIVE )
1216             {
1217               (tableViewImpl.*funcRelative)( index, value->Get<float>() );
1218             }
1219             else if( policy == Toolkit::TableView::FIT )
1220             {
1221               (tableViewImpl.*funcFit)( index );
1222             }
1223             // do nothing for FILL policy
1224           }
1225         }
1226       }
1227     }
1228   }
1229 }
1230
1231 Property::Value TableView::GetRowHeightsPropertyValue()
1232 {
1233   Property::Map map;
1234   GetMapPropertyValue( mRowData, map);
1235   return Property::Value(map);
1236 }
1237
1238 Property::Value TableView::GetColumnWidthsPropertyValue()
1239 {
1240   Property::Map map;
1241   GetMapPropertyValue( mColumnData, map);
1242   return Property::Value(map);
1243 }
1244
1245 void TableView::GetMapPropertyValue( const RowColumnArray& data, Property::Map& map )
1246 {
1247   const char* fixedPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIXED,
1248                                                                                                LAYOUT_POLICY_STRING_TABLE,
1249                                                                                                LAYOUT_POLICY_STRING_TABLE_COUNT );
1250   const char* relativePolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::RELATIVE,
1251                                                                                                   LAYOUT_POLICY_STRING_TABLE,
1252                                                                                                   LAYOUT_POLICY_STRING_TABLE_COUNT );
1253   const char* fillPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FILL,
1254                                                                                               LAYOUT_POLICY_STRING_TABLE,
1255                                                                                               LAYOUT_POLICY_STRING_TABLE_COUNT );
1256   const char* fitPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIT,
1257                                                                                              LAYOUT_POLICY_STRING_TABLE,
1258                                                                                              LAYOUT_POLICY_STRING_TABLE_COUNT );
1259
1260   const RowColumnArray::SizeType count = data.Size();
1261   for( RowColumnArray::SizeType i = 0; i < count; i++ )
1262   {
1263     const RowColumnData& dataInstance = data[ i ];
1264
1265     Property::Map item;
1266     switch( dataInstance.sizePolicy )
1267     {
1268       case Toolkit::TableView::FIXED:
1269       {
1270         item[ "policy" ] = fixedPolicy;
1271         item[ "value" ] = dataInstance.size;
1272         break;
1273       }
1274       case Toolkit::TableView::RELATIVE:
1275       {
1276         item[ "policy" ] = relativePolicy;
1277         item[ "value" ] = dataInstance.fillRatio;
1278         break;
1279       }
1280       case Toolkit::TableView::FIT:
1281       {
1282         item[ "policy" ] = fitPolicy;
1283         item[ "value" ] = 0.f;
1284         break;
1285       }
1286       case Toolkit::TableView::FILL:
1287       default:
1288       {
1289         item[ "policy" ] = fillPolicy;
1290         item[ "value" ] = 0.f;
1291         break;
1292       }
1293     }
1294     std::ostringstream ss;
1295     ss << i;
1296     map[ ss.str() ] = item;
1297   }
1298 }
1299
1300 TableView::~TableView()
1301 {
1302   // nothing to do
1303 }
1304
1305 Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
1306 {
1307   Actor nextFocusableActor;
1308
1309   if ( !currentFocusedActor )
1310   {
1311     // Nothing is currently focused, so the child in the first cell should be focused.
1312     nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1313   }
1314   else
1315   {
1316     Toolkit::TableView::CellPosition position;
1317     if( FindChildPosition( currentFocusedActor, position ) )
1318     {
1319       // The current focused actor is a child of TableView
1320       bool focusLost = false;
1321       int currentRow = position.rowIndex;
1322       int currentColumn = position.columnIndex;
1323       int numberOfColumns = GetColumns();
1324       int numberOfRows = GetRows();
1325
1326       switch ( direction )
1327       {
1328         case Toolkit::Control::KeyboardFocus::LEFT:
1329         {
1330           if(--currentColumn < 0)
1331           {
1332             currentColumn = numberOfColumns - 1;
1333             if(--currentRow < 0)
1334             {
1335               currentRow = loopEnabled ? numberOfRows - 1 : 0;
1336               focusLost = (currentRow == 0);
1337             }
1338           }
1339           break;
1340         }
1341         case Toolkit::Control::KeyboardFocus::RIGHT:
1342         {
1343           if(++currentColumn > numberOfColumns - 1)
1344           {
1345             currentColumn = 0;
1346             if(++currentRow > numberOfRows - 1)
1347             {
1348               currentRow = loopEnabled ? 0 : numberOfRows - 1;
1349               focusLost = (currentRow == numberOfRows - 1);
1350             }
1351           }
1352           break;
1353         }
1354         case Toolkit::Control::KeyboardFocus::UP:
1355         {
1356           if(--currentRow < 0)
1357           {
1358             currentRow = loopEnabled ? numberOfRows - 1 : 0;
1359             focusLost = (currentRow == 0);
1360           }
1361           break;
1362         }
1363         case Toolkit::Control::KeyboardFocus::DOWN:
1364
1365         {
1366           if(++currentRow > numberOfRows - 1)
1367           {
1368             currentRow = loopEnabled ? 0 : numberOfRows - 1;
1369             focusLost = (currentRow == numberOfRows - 1);
1370           }
1371           break;
1372         }
1373       }
1374
1375       // Move the focus if we haven't lost it.
1376       if(!focusLost)
1377       {
1378         nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1379       }
1380     }
1381     else
1382     {
1383       // The current focused actor is not within table view, so the child in the first cell should be focused.
1384       nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1385     }
1386   }
1387
1388   return nextFocusableActor;
1389 }
1390
1391 Vector3 TableView::GetNaturalSize()
1392 {
1393   // Natural size is the size of all fixed cell widths or heights. This ignores cells with relative heights.
1394   return Vector3( mFixedTotals.width, mFixedTotals.height, 1.0f );
1395 }
1396
1397 float TableView::CalculateChildSize( const Actor& child, Dimension::Type dimension )
1398 {
1399   Toolkit::TableView::CellPosition position;
1400   if( FindChildPosition( child, position) )
1401   {
1402     switch( dimension )
1403     {
1404       case Dimension::WIDTH:
1405       {
1406         float cellSize = 0.0f;
1407         cellSize = mColumnData[position.columnIndex+position.columnSpan-1].position
1408                  - (position.columnIndex > 0 ? mColumnData[position.columnIndex-1].position : 0.f)
1409                  - mPadding.width * 2.0f;
1410
1411         if( cellSize < 0.0f )
1412         {
1413           cellSize = 0.0f;
1414         }
1415
1416         return cellSize;
1417       }
1418
1419       case Dimension::HEIGHT:
1420       {
1421         float cellSize = 0.0f;
1422
1423         cellSize = mRowData[position.rowIndex+position.rowSpan-1].position
1424                  - (position.rowIndex > 0 ? mRowData[position.rowIndex-1].position : 0.f)
1425                  - mPadding.height * 2.0f;
1426
1427         if( cellSize < 0.0f )
1428         {
1429           cellSize = 0.0f;
1430         }
1431
1432         return cellSize;
1433       }
1434       default:
1435       {
1436         return 0.0f;
1437       }
1438     }
1439   }
1440
1441   return 0.0f;    // Child not found
1442 }
1443
1444 bool TableView::RelayoutDependentOnChildren( Dimension::Type dimension )
1445 {
1446   if ( Control::RelayoutDependentOnChildren( dimension ) )
1447   {
1448     return true;
1449   }
1450
1451   return FindFit( mRowData ) || FindFit( mColumnData );
1452 }
1453
1454 void TableView::SetCellAlignment( Toolkit::TableView::CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical )
1455 {
1456   // Check if we need to expand our data array
1457   if( position.rowIndex >= mCellData.GetRows() )
1458   {
1459     // Only adding new rows
1460     ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
1461   }
1462
1463   if( position.columnIndex >= mCellData.GetColumns() )
1464   {
1465     // Only adding new columns
1466     ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
1467   }
1468
1469   // Set the alignment of the cell
1470   CellData& data = mCellData[ position.rowIndex ][ position.columnIndex ];
1471   data.horizontalAlignment = horizontal;
1472   data.verticalAlignment = vertical;
1473 }
1474
1475 void TableView::CalculateFillSizes( RowColumnArray& data )
1476 {
1477   // First pass: Count number of fill entries and calculate used relative space
1478   Dali::Vector< RowColumnData* > fillData;
1479   float relativeTotal = 0.0f;
1480
1481   const unsigned int dataCount = data.Size();
1482
1483   for( unsigned int i = 0; i < dataCount; ++i )
1484   {
1485     RowColumnData& dataInstance = data[ i ];
1486
1487     if( dataInstance.sizePolicy == Toolkit::TableView::RELATIVE )
1488     {
1489       relativeTotal += dataInstance.fillRatio;
1490     }
1491     else if(dataInstance.sizePolicy == Toolkit::TableView::FILL)
1492     {
1493       fillData.PushBack( &dataInstance );
1494     }
1495   }
1496
1497   // Second pass: Distribute remaining relative space
1498   const unsigned int fillCount = fillData.Size();
1499   if( fillCount > 0 )
1500   {
1501     if( relativeTotal > 1.0f )
1502     {
1503       relativeTotal = 1.0f;
1504     }
1505
1506     const float evenFillRatio = (1.0f - relativeTotal ) / fillCount;
1507
1508     for( unsigned int i = 0; i < fillCount; ++i )
1509     {
1510       fillData[ i ]->fillRatio = evenFillRatio;
1511     }
1512   }
1513 }
1514
1515 float TableView::CalculateTotalFixedSize( const RowColumnArray& data )
1516 {
1517   float totalSize = 0.0f;
1518
1519   const unsigned int dataCount = data.Size();
1520
1521   for( unsigned int i = 0; i < dataCount; ++i )
1522   {
1523     const RowColumnData& dataInstance = data[ i ];
1524
1525     switch( dataInstance.sizePolicy )
1526     {
1527       // we have absolute size to FIXED and FIT column/row and relative size for RELATIVE and FILL column/row
1528       case Toolkit::TableView::FIXED:
1529       case Toolkit::TableView::FIT:
1530       {
1531         totalSize += dataInstance.size;
1532         break;
1533       }
1534
1535       default:
1536       {
1537         break;
1538       }
1539     }
1540   }
1541
1542   return totalSize;
1543 }
1544
1545 Vector2 TableView::GetCellPadding( Dimension::Type dimension )
1546 {
1547   switch( dimension )
1548   {
1549     case Dimension::WIDTH:
1550     {
1551       return Vector2( mPadding.x, mPadding.x );
1552     }
1553     case Dimension::HEIGHT:
1554     {
1555       return Vector2( mPadding.y, mPadding.y );
1556     }
1557     default:
1558     {
1559       break;
1560     }
1561   }
1562
1563   return Vector2();
1564 }
1565
1566 void TableView::CalculateFitSizes( RowColumnArray& data, Dimension::Type dimension )
1567 {
1568   Vector2 cellPadding = GetCellPadding( dimension );
1569
1570   const unsigned int dataCount = data.Size();
1571
1572   for( unsigned int i = 0; i < dataCount; ++i )
1573   {
1574     RowColumnData& dataInstance = data[ i ];
1575
1576     if( dataInstance.sizePolicy == Toolkit::TableView::FIT )
1577     {
1578       // Find the size of the biggest actor in the row or column
1579       float maxActorHeight = 0.0f;
1580
1581       unsigned int fitCount = ( dimension == Dimension::WIDTH ) ? mCellData.GetRows() : mCellData.GetColumns();
1582
1583       for( unsigned int j = 0; j < fitCount; ++j )
1584       {
1585         unsigned int row = ( dimension == Dimension::WIDTH ) ? j : i;
1586         unsigned int column = ( dimension == Dimension::WIDTH ) ? i : j;
1587         DALI_ASSERT_DEBUG( row < mCellData.GetRows() );
1588         DALI_ASSERT_DEBUG( column < mCellData.GetColumns() );
1589
1590         const CellData& cellData = mCellData[ row ][ column ];
1591         const Actor& actor = cellData.actor;
1592         if( actor )
1593         {
1594           if( FitToChild( actor, dimension ) && ( dimension == Dimension::WIDTH ) ? ( cellData.position.columnSpan == 1 ) : ( cellData.position.rowSpan == 1 )  )
1595           {
1596             maxActorHeight = std::max( maxActorHeight, actor.GetRelayoutSize( dimension ) + cellPadding.x + cellPadding.y );
1597           }
1598         }
1599       }
1600
1601       dataInstance.size = maxActorHeight;
1602     }
1603   }
1604 }
1605
1606 bool TableView::FindFit( const RowColumnArray& data )
1607 {
1608   for( unsigned int i = 0, count = data.Size(); i < count; ++i )
1609   {
1610     if( data[ i ].sizePolicy == Toolkit::TableView::FIT )
1611     {
1612       return true;
1613     }
1614   }
1615
1616   return false;
1617 }
1618
1619 } // namespace Internal
1620
1621 } // namespace Toolkit
1622
1623 } // namespace Dali