Merge "Fix for selection handles." into devel/master
[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("cell-index");
43 const char * const ROW_SPAN_PROPERTY_NAME("row-span");
44 const char * const COLUMN_SPAN_PROPERTY_NAME("column-span");
45 const char * const CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME("cell-horizontal-alignment");
46 const char * const CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME("cell-vertical-alignment");
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",           UNSIGNED_INTEGER, ROWS           )
146 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "columns",        UNSIGNED_INTEGER, COLUMNS        )
147 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "cell-padding",   VECTOR2,          CELL_PADDING   )
148 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layout-rows",    MAP,              LAYOUT_ROWS    )
149 DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layout-columns", 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::OnRelayout( const Vector2& size, RelayoutContainer& container )
802 {
803   // Go through the layout data
804   for( unsigned int row = 0, rowCount = mCellData.GetRows(); row < rowCount; ++row )
805   {
806     for( unsigned int column = 0, columnCount = mCellData.GetColumns(); column < columnCount; ++column )
807     {
808       CellData& cellData= mCellData[ row ][ column ];
809       Actor& actor = cellData.actor;
810       const Toolkit::TableView::CellPosition position = cellData.position;
811
812       // If there is an actor and this is the main cell of the actor.
813       // An actor can be in multiple cells if its row or column span is more than 1.
814       // We however must lay out each actor only once.
815       if( actor &&  position.rowIndex == row && position.columnIndex == column )
816       {
817         // Anchor actor to top left of the cell
818         actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
819         actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
820
821         Padding padding;
822         actor.GetPadding( padding );
823
824         float left = column > 0 ? mColumnData[column-1].position : 0.f;
825         float right = mColumnData[column+position.columnSpan-1].position;
826         float top = row > 0 ? mRowData[row-1].position : 0.f;
827         float bottom = mRowData[row+position.rowSpan-1].position;
828
829         if( cellData.horizontalAlignment == HorizontalAlignment::LEFT )
830         {
831           actor.SetX( left + mPadding.width + padding.left );
832         }
833         else if( cellData.horizontalAlignment ==  HorizontalAlignment::RIGHT )
834         {
835           actor.SetX( right - mPadding.width - padding.right - actor.GetRelayoutSize( Dimension::WIDTH ) );
836         }
837         else //if( cellData.horizontalAlignment ==  HorizontalAlignment::CENTER )
838         {
839           actor.SetX( (left + right + padding.left - padding.right - actor.GetRelayoutSize( Dimension::WIDTH )) * 0.5f );
840         }
841
842         if( cellData.verticalAlignment == VerticalAlignment::TOP )
843         {
844           actor.SetY( top + mPadding.height + padding.top );
845         }
846         else if( cellData.verticalAlignment == VerticalAlignment::BOTTOM )
847         {
848           actor.SetY( bottom - mPadding.height - padding.bottom -  actor.GetRelayoutSize( Dimension::HEIGHT ) );
849         }
850         else //if( cellData.verticalAlignment = VerticalAlignment::CENTER )
851         {
852           actor.SetY( (top + bottom + padding.top - padding.bottom - actor.GetRelayoutSize( Dimension::HEIGHT )) * 0.5f );
853         }
854       }
855     }
856   }
857 }
858
859 unsigned int TableView::GetRows()
860 {
861   return mCellData.GetRows();
862 }
863
864 unsigned int TableView::GetColumns()
865 {
866   return mCellData.GetColumns();
867 }
868
869 void TableView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
870 {
871   Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
872
873   if( tableView )
874   {
875     TableView& tableViewImpl( GetImpl( tableView ) );
876     switch( index )
877     {
878       case Toolkit::TableView::Property::ROWS:
879       {
880         if( value.Get<unsigned int>() != tableViewImpl.GetRows() )
881         {
882           tableViewImpl.Resize( value.Get<unsigned int>(), tableViewImpl.GetColumns() );
883         }
884         break;
885       }
886       case Toolkit::TableView::Property::COLUMNS:
887       {
888         if( value.Get<unsigned int>() != tableViewImpl.GetColumns() )
889         {
890           tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<unsigned int>() );
891         }
892         break;
893       }
894       case Toolkit::TableView::Property::CELL_PADDING:
895       {
896         tableViewImpl.SetCellPadding( value.Get<Vector2>() );
897         break;
898       }
899       case Toolkit::TableView::Property::LAYOUT_ROWS:
900       {
901         SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, &TableView::SetFitHeight, value );
902         break;
903       }
904       case Toolkit::TableView::Property::LAYOUT_COLUMNS:
905       {
906         SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, &TableView::SetFitWidth, value );
907         break;
908       }
909     }
910   }
911 }
912
913 Property::Value TableView::GetProperty( BaseObject* object, Property::Index index )
914 {
915   Property::Value value;
916
917   Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
918
919   if( tableView )
920   {
921     TableView& tableViewImpl( GetImpl( tableView ) );
922     switch( index )
923     {
924       case Toolkit::TableView::Property::ROWS:
925       {
926         value = tableViewImpl.GetRows();
927         break;
928       }
929       case Toolkit::TableView::Property::COLUMNS:
930       {
931         value = tableViewImpl.GetColumns();
932         break;
933       }
934       case Toolkit::TableView::Property::CELL_PADDING:
935       {
936         value = tableViewImpl.GetCellPadding();
937         break;
938       }
939       case Toolkit::TableView::Property::LAYOUT_ROWS:
940       {
941         value = tableViewImpl.GetRowHeightsPropertyValue();
942         break;
943       }
944       case Toolkit::TableView::Property::LAYOUT_COLUMNS:
945       {
946         value = tableViewImpl.GetColumnWidthsPropertyValue();
947         break;
948       }
949     }
950   }
951
952   return value;
953 }
954
955 void TableView::OnControlChildAdd( Actor& child )
956 {
957   if( mLayoutingChild )
958   {
959     // we're in the middle of laying out children so no point doing anything here
960     return;
961   }
962
963   // Test properties on actor
964   HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT;
965   VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP;
966   if( child.GetPropertyIndex( CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME ) != Property::INVALID_INDEX )
967   {
968     std::string value = child.GetProperty( child.GetPropertyIndex(CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME) ).Get<std::string >();
969     Scripting::GetEnumeration< HorizontalAlignment::Type >( value.c_str(),
970                                                             HORIZONTAL_ALIGNMENT_STRING_TABLE,
971                                                             HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
972                                                             horizontalAlignment );
973   }
974   if( child.GetPropertyIndex( CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME ) != Property::INVALID_INDEX )
975   {
976     std::string value = child.GetProperty( child.GetPropertyIndex(CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME) ).Get<std::string >();
977     Scripting::GetEnumeration< VerticalAlignment::Type >( value.c_str(),
978                                                           VERTICAL_ALIGNMENT_STRING_TABLE,
979                                                           VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
980                                                           verticalAlignment );
981   }
982
983
984   Toolkit::TableView::CellPosition cellPosition;
985   if( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
986   {
987     cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
988   }
989
990   if( child.GetPropertyIndex(COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
991   {
992     cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
993   }
994
995   if( child.GetPropertyIndex(CELL_INDEX_PROPERTY_NAME) != Property::INVALID_INDEX )
996   {
997     Vector2 indices = child.GetProperty( child.GetPropertyIndex(CELL_INDEX_PROPERTY_NAME) ).Get<Vector2 >();
998     cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
999     cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
1000
1001     AddChild( child, cellPosition );
1002     SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment);
1003
1004     // Do not continue
1005     return;
1006   }
1007
1008   // Find the first available cell to store the actor in
1009   const unsigned int rowCount = mCellData.GetRows();
1010   const unsigned int columnCount = mCellData.GetColumns();
1011   for( unsigned int row = 0; row < rowCount; ++row )
1012   {
1013     for( unsigned int column = 0; column < columnCount; ++column )
1014     {
1015       if( !(mCellData[ row ][ column ].actor) )
1016       {
1017         // Put the actor in the cell
1018         CellData data;
1019         data.actor = child;
1020         data.position.columnIndex = column;
1021         data.position.rowIndex = row;
1022         data.horizontalAlignment = horizontalAlignment;
1023         data.verticalAlignment = verticalAlignment;
1024         mCellData[ row ][ column ] = data;
1025
1026         // Don't continue
1027         RelayoutRequest();
1028         return;
1029       }
1030     }
1031   }
1032
1033   // No empty cells, so increase size of the table
1034   unsigned int newColumnCount = ( columnCount > 0 ) ? columnCount : 1;
1035   ResizeContainers( rowCount + 1, newColumnCount );
1036
1037   // Put the actor in the first cell of the new row
1038   CellData data;
1039   data.actor = child;
1040   data.position.rowIndex = rowCount;
1041   data.position.columnIndex = 0;
1042   data.horizontalAlignment = horizontalAlignment;
1043   data.verticalAlignment = verticalAlignment;
1044   mCellData[ rowCount ][ 0 ] = data;
1045   RelayoutRequest();
1046 }
1047
1048 void TableView::OnControlChildRemove( Actor& child )
1049 {
1050   // dont process if we're in the middle of bigger operation like delete row, column or resize
1051   if( !mLayoutingChild )
1052   {
1053     // relayout the table only if instances were found
1054     if( RemoveAllInstances( child ) )
1055     {
1056       RelayoutRequest();
1057     }
1058   }
1059 }
1060
1061 TableView::TableView( unsigned int initialRows, unsigned int initialColumns )
1062 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
1063   mCellData( initialRows, initialColumns ),
1064   mLayoutingChild( false ),
1065   mRowDirty( true ),     // Force recalculation first time
1066   mColumnDirty( true )
1067 {
1068   SetKeyboardNavigationSupport( true );
1069   ResizeContainers( initialRows, initialColumns );
1070 }
1071
1072 void TableView::OnInitialize()
1073 {
1074   // Make self as keyboard focusable and focus group
1075   Actor self = Self();
1076   self.SetKeyboardFocusable(true);
1077   SetAsKeyboardFocusGroup(true);
1078 }
1079
1080 void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
1081 {
1082   std::vector<CellData> ignored;
1083   ResizeContainers( rows, columns, ignored );
1084 }
1085
1086 void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& removed )
1087 {
1088   // Resize cell data
1089   mCellData.Resize( rows, columns, removed );
1090
1091   // We don't care if these go smaller, data will be regenerated or is not needed anymore
1092   mRowData.Resize( rows );
1093   mColumnData.Resize( columns );
1094 }
1095
1096 void TableView::RemoveAndGetLostActors( const std::vector<CellData>& lost, std::vector<Actor>& removed,
1097                                         unsigned int rowsRemoved, unsigned int columnsRemoved )
1098 {
1099   // iterate through all lost cells
1100   std::vector< CellData >::const_iterator iter = lost.begin();
1101   for( ; iter != lost.end(); ++iter )
1102   {
1103     // if it is a valid actor
1104     if( (*iter).actor )
1105     {
1106       // is this actor still somewhere else in the table
1107       Toolkit::TableView::CellPosition position;
1108       if( FindChildPosition( (*iter).actor, position ) )
1109       {
1110         // it must be spanning multiple cells, position contains the top left most one
1111         // check if position is left of the removed location
1112         if( position.columnIndex < (*iter).position.columnIndex )
1113         {
1114           // if column span is greater than 1
1115           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan > 1 )
1116           {
1117             // decrease column span
1118             mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan -= columnsRemoved;
1119           }
1120         }
1121         // check if position is left of the removed location
1122         if( position.rowIndex < (*iter).position.rowIndex )
1123         {
1124           // if row span is greater than 1
1125           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan > 1 )
1126           {
1127             // decrease row span
1128             mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan -= rowsRemoved;
1129           }
1130         }
1131       }
1132       else
1133       {
1134         // this actor is gone for good
1135         // add actor to removed container
1136         removed.push_back( (*iter).actor );
1137         // we dont want the child actor anymore
1138         Self().Remove( (*iter).actor );
1139       }
1140     }
1141   }
1142 }
1143
1144 bool TableView::RemoveAllInstances( const Actor& child )
1145 {
1146   bool found = false;
1147   // walk through the layout data
1148   const unsigned int rowCount = mCellData.GetRows();
1149   const unsigned int columnCount = mCellData.GetColumns();
1150   for( unsigned int row = 0; row < rowCount; ++row )
1151   {
1152     for( unsigned int column = 0; column < columnCount; ++column )
1153     {
1154       if( mCellData[ row ][ column ].actor == child )
1155       {
1156         // clear the cell, NOTE that the cell might be spanning multiple cells
1157         mCellData[ row ][ column ] = CellData();
1158         found = true;
1159       }
1160     }
1161   }
1162   return found;
1163 }
1164
1165 void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
1166                                          void(TableView::*funcFixed)(unsigned int, float),
1167                                          void(TableView::*funcRelative)(unsigned int, float),
1168                                          void(TableView::*funcFit)(unsigned int),
1169                                          const Property::Value& value )
1170 {
1171   Property::Map* map = value.GetMap();
1172   if( map )
1173   {
1174     unsigned int index(0);
1175     for ( unsigned int i = 0, count = map->Count(); i < count; ++i )
1176     {
1177       Property::Value& item = map->GetValue(i);
1178       Property::Map* childMap = item.GetMap();
1179
1180       std::istringstream( map->GetKey(i) ) >> index;
1181       if( childMap )
1182       {
1183         Property::Value* policy = childMap->Find( "policy" );
1184         Property::Value* value = childMap->Find( "value" );
1185         if( policy && value )
1186         {
1187           std::string policyValue;
1188           policy->Get( policyValue );
1189           Toolkit::TableView::LayoutPolicy policy;
1190           if( Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( policyValue.c_str(),
1191                                                                              LAYOUT_POLICY_STRING_TABLE,
1192                                                                              LAYOUT_POLICY_STRING_TABLE_COUNT,
1193                                                                              policy ) )
1194           {
1195             if( policy == Toolkit::TableView::FIXED  )
1196             {
1197               (tableViewImpl.*funcFixed)( index, value->Get<float>() );
1198             }
1199             else if( policy == Toolkit::TableView::RELATIVE )
1200             {
1201               (tableViewImpl.*funcRelative)( index, value->Get<float>() );
1202             }
1203             else if( policy == Toolkit::TableView::FIT )
1204             {
1205               (tableViewImpl.*funcFit)( index );
1206             }
1207             // do nothing for FILL policy
1208           }
1209         }
1210       }
1211     }
1212   }
1213 }
1214
1215 Property::Value TableView::GetRowHeightsPropertyValue()
1216 {
1217   Property::Map map;
1218   GetMapPropertyValue( mRowData, map);
1219   return Property::Value(map);
1220 }
1221
1222 Property::Value TableView::GetColumnWidthsPropertyValue()
1223 {
1224   Property::Map map;
1225   GetMapPropertyValue( mColumnData, map);
1226   return Property::Value(map);
1227 }
1228
1229 void TableView::GetMapPropertyValue( const RowColumnArray& data, Property::Map& map )
1230 {
1231   const char* fixedPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIXED,
1232                                                                                                LAYOUT_POLICY_STRING_TABLE,
1233                                                                                                LAYOUT_POLICY_STRING_TABLE_COUNT );
1234   const char* relativePolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::RELATIVE,
1235                                                                                                   LAYOUT_POLICY_STRING_TABLE,
1236                                                                                                   LAYOUT_POLICY_STRING_TABLE_COUNT );
1237   const char* fillPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FILL,
1238                                                                                               LAYOUT_POLICY_STRING_TABLE,
1239                                                                                               LAYOUT_POLICY_STRING_TABLE_COUNT );
1240   const char* fitPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIT,
1241                                                                                              LAYOUT_POLICY_STRING_TABLE,
1242                                                                                              LAYOUT_POLICY_STRING_TABLE_COUNT );
1243
1244   const RowColumnArray::SizeType count = data.Size();
1245   for( RowColumnArray::SizeType i = 0; i < count; i++ )
1246   {
1247     const RowColumnData& dataInstance = data[ i ];
1248
1249     Property::Map item;
1250     switch( dataInstance.sizePolicy )
1251     {
1252       case Toolkit::TableView::FIXED:
1253       {
1254         item[ "policy" ] = fixedPolicy;
1255         item[ "value" ] = dataInstance.size;
1256         break;
1257       }
1258       case Toolkit::TableView::RELATIVE:
1259       {
1260         item[ "policy" ] = relativePolicy;
1261         item[ "value" ] = dataInstance.fillRatio;
1262         break;
1263       }
1264       case Toolkit::TableView::FIT:
1265       {
1266         item[ "policy" ] = fitPolicy;
1267         item[ "value" ] = 0.f;
1268         break;
1269       }
1270       case Toolkit::TableView::FILL:
1271       default:
1272       {
1273         item[ "policy" ] = fillPolicy;
1274         item[ "value" ] = 0.f;
1275         break;
1276       }
1277     }
1278     std::ostringstream ss;
1279     ss << i;
1280     map[ ss.str() ] = item;
1281   }
1282 }
1283
1284 TableView::~TableView()
1285 {
1286   // nothing to do
1287 }
1288
1289 Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
1290 {
1291   Actor nextFocusableActor;
1292
1293   if ( !currentFocusedActor )
1294   {
1295     // Nothing is currently focused, so the child in the first cell should be focused.
1296     nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1297   }
1298   else
1299   {
1300     Toolkit::TableView::CellPosition position;
1301     if( FindChildPosition( currentFocusedActor, position ) )
1302     {
1303       // The current focused actor is a child of TableView
1304       bool focusLost = false;
1305       int currentRow = position.rowIndex;
1306       int currentColumn = position.columnIndex;
1307       int numberOfColumns = GetColumns();
1308       int numberOfRows = GetRows();
1309
1310       switch ( direction )
1311       {
1312         case Toolkit::Control::KeyboardFocus::LEFT:
1313         {
1314           if(--currentColumn < 0)
1315           {
1316             currentColumn = numberOfColumns - 1;
1317             if(--currentRow < 0)
1318             {
1319               currentRow = loopEnabled ? numberOfRows - 1 : 0;
1320               focusLost = (currentRow == 0);
1321             }
1322           }
1323           break;
1324         }
1325         case Toolkit::Control::KeyboardFocus::RIGHT:
1326         {
1327           if(++currentColumn > numberOfColumns - 1)
1328           {
1329             currentColumn = 0;
1330             if(++currentRow > numberOfRows - 1)
1331             {
1332               currentRow = loopEnabled ? 0 : numberOfRows - 1;
1333               focusLost = (currentRow == numberOfRows - 1);
1334             }
1335           }
1336           break;
1337         }
1338         case Toolkit::Control::KeyboardFocus::UP:
1339         {
1340           if(--currentRow < 0)
1341           {
1342             currentRow = loopEnabled ? numberOfRows - 1 : 0;
1343             focusLost = (currentRow == 0);
1344           }
1345           break;
1346         }
1347         case Toolkit::Control::KeyboardFocus::DOWN:
1348
1349         {
1350           if(++currentRow > numberOfRows - 1)
1351           {
1352             currentRow = loopEnabled ? 0 : numberOfRows - 1;
1353             focusLost = (currentRow == numberOfRows - 1);
1354           }
1355           break;
1356         }
1357       }
1358
1359       // Move the focus if we haven't lost it.
1360       if(!focusLost)
1361       {
1362         nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1363       }
1364     }
1365     else
1366     {
1367       // The current focused actor is not within table view, so the child in the first cell should be focused.
1368       nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1369     }
1370   }
1371
1372   return nextFocusableActor;
1373 }
1374
1375 Vector3 TableView::GetNaturalSize()
1376 {
1377   // Natural size is the size of all fixed cell widths or heights. This ignores cells with relative heights.
1378   return Vector3( mFixedTotals.width, mFixedTotals.height, 1.0f );
1379 }
1380
1381 float TableView::CalculateChildSize( const Actor& child, Dimension::Type dimension )
1382 {
1383   Toolkit::TableView::CellPosition position;
1384   if( FindChildPosition( child, position) )
1385   {
1386     switch( dimension )
1387     {
1388       case Dimension::WIDTH:
1389       {
1390         float cellSize = 0.0f;
1391         cellSize = mColumnData[position.columnIndex+position.columnSpan-1].position
1392                  - (position.columnIndex > 0 ? mColumnData[position.columnIndex-1].position : 0.f)
1393                  - mPadding.width * 2.0f;
1394
1395         if( cellSize < 0.0f )
1396         {
1397           cellSize = 0.0f;
1398         }
1399
1400         return cellSize;
1401       }
1402
1403       case Dimension::HEIGHT:
1404       {
1405         float cellSize = 0.0f;
1406
1407         cellSize = mRowData[position.rowIndex+position.rowSpan-1].position
1408                  - (position.rowIndex > 0 ? mRowData[position.rowIndex-1].position : 0.f)
1409                  - mPadding.height * 2.0f;
1410
1411         if( cellSize < 0.0f )
1412         {
1413           cellSize = 0.0f;
1414         }
1415
1416         return cellSize;
1417       }
1418       default:
1419       {
1420         return 0.0f;
1421       }
1422     }
1423   }
1424
1425   return 0.0f;    // Child not found
1426 }
1427
1428 bool TableView::RelayoutDependentOnChildren( Dimension::Type dimension )
1429 {
1430   if ( Control::RelayoutDependentOnChildren( dimension ) )
1431   {
1432     return true;
1433   }
1434
1435   return FindFit( mRowData ) || FindFit( mColumnData );
1436 }
1437
1438 void TableView::SetCellAlignment( Toolkit::TableView::CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical )
1439 {
1440   // Check if we need to expand our data array
1441   if( position.rowIndex >= mCellData.GetRows() )
1442   {
1443     // Only adding new rows
1444     ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
1445   }
1446
1447   if( position.columnIndex >= mCellData.GetColumns() )
1448   {
1449     // Only adding new columns
1450     ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
1451   }
1452
1453   // Set the alignment of the cell
1454   CellData& data = mCellData[ position.rowIndex ][ position.columnIndex ];
1455   data.horizontalAlignment = horizontal;
1456   data.verticalAlignment = vertical;
1457 }
1458
1459 void TableView::CalculateFillSizes( RowColumnArray& data )
1460 {
1461   // First pass: Count number of fill entries and calculate used relative space
1462   Dali::Vector< RowColumnData* > fillData;
1463   float relativeTotal = 0.0f;
1464
1465   const unsigned int dataCount = data.Size();
1466
1467   for( unsigned int i = 0; i < dataCount; ++i )
1468   {
1469     RowColumnData& dataInstance = data[ i ];
1470
1471     if( dataInstance.sizePolicy == Toolkit::TableView::RELATIVE )
1472     {
1473       relativeTotal += dataInstance.fillRatio;
1474     }
1475     else if(dataInstance.sizePolicy == Toolkit::TableView::FILL)
1476     {
1477       fillData.PushBack( &dataInstance );
1478     }
1479   }
1480
1481   // Second pass: Distribute remaining relative space
1482   const unsigned int fillCount = fillData.Size();
1483   if( fillCount > 0 )
1484   {
1485     if( relativeTotal > 1.0f )
1486     {
1487       relativeTotal = 1.0f;
1488     }
1489
1490     const float evenFillRatio = (1.0f - relativeTotal ) / fillCount;
1491
1492     for( unsigned int i = 0; i < fillCount; ++i )
1493     {
1494       fillData[ i ]->fillRatio = evenFillRatio;
1495     }
1496   }
1497 }
1498
1499 float TableView::CalculateTotalFixedSize( const RowColumnArray& data )
1500 {
1501   float totalSize = 0.0f;
1502
1503   const unsigned int dataCount = data.Size();
1504
1505   for( unsigned int i = 0; i < dataCount; ++i )
1506   {
1507     const RowColumnData& dataInstance = data[ i ];
1508
1509     switch( dataInstance.sizePolicy )
1510     {
1511       // we have absolute size to FIXED and FIT column/row and relative size for RELATIVE and FILL column/row
1512       case Toolkit::TableView::FIXED:
1513       case Toolkit::TableView::FIT:
1514       {
1515         totalSize += dataInstance.size;
1516         break;
1517       }
1518
1519       default:
1520       {
1521         break;
1522       }
1523     }
1524   }
1525
1526   return totalSize;
1527 }
1528
1529 Vector2 TableView::GetCellPadding( Dimension::Type dimension )
1530 {
1531   switch( dimension )
1532   {
1533     case Dimension::WIDTH:
1534     {
1535       return Vector2( mPadding.x, mPadding.x );
1536     }
1537     case Dimension::HEIGHT:
1538     {
1539       return Vector2( mPadding.y, mPadding.y );
1540     }
1541     default:
1542     {
1543       break;
1544     }
1545   }
1546
1547   return Vector2();
1548 }
1549
1550 void TableView::CalculateFitSizes( RowColumnArray& data, Dimension::Type dimension )
1551 {
1552   Vector2 cellPadding = GetCellPadding( dimension );
1553
1554   const unsigned int dataCount = data.Size();
1555
1556   for( unsigned int i = 0; i < dataCount; ++i )
1557   {
1558     RowColumnData& dataInstance = data[ i ];
1559
1560     if( dataInstance.sizePolicy == Toolkit::TableView::FIT )
1561     {
1562       // Find the size of the biggest actor in the row or column
1563       float maxActorHeight = 0.0f;
1564
1565       unsigned int fitCount = ( dimension == Dimension::WIDTH ) ? mCellData.GetRows() : mCellData.GetColumns();
1566
1567       for( unsigned int j = 0; j < fitCount; ++j )
1568       {
1569         unsigned int row = ( dimension == Dimension::WIDTH ) ? j : i;
1570         unsigned int column = ( dimension == Dimension::WIDTH ) ? i : j;
1571         DALI_ASSERT_DEBUG( row < mCellData.GetRows() );
1572         DALI_ASSERT_DEBUG( column < mCellData.GetColumns() );
1573
1574         const CellData& cellData = mCellData[ row ][ column ];
1575         const Actor& actor = cellData.actor;
1576         if( actor )
1577         {
1578           if( FitToChild( actor, dimension ) && ( dimension == Dimension::WIDTH ) ? ( cellData.position.columnSpan == 1 ) : ( cellData.position.rowSpan == 1 )  )
1579           {
1580             maxActorHeight = std::max( maxActorHeight, actor.GetRelayoutSize( dimension ) + cellPadding.x + cellPadding.y );
1581           }
1582         }
1583       }
1584
1585       dataInstance.size = maxActorHeight;
1586     }
1587   }
1588 }
1589
1590 bool TableView::FindFit( const RowColumnArray& data )
1591 {
1592   for( unsigned int i = 0, count = data.Size(); i < count; ++i )
1593   {
1594     if( data[ i ].sizePolicy == Toolkit::TableView::FIT )
1595     {
1596       return true;
1597     }
1598   }
1599
1600   return false;
1601 }
1602
1603 } // namespace Internal
1604
1605 } // namespace Toolkit
1606
1607 } // namespace Dali