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