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