3dc99a5c99d2fbea23f88d4d62bc9be104dafe8e
[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   DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
1118     return std::unique_ptr< Dali::Accessibility::Accessible >(
1119       new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::TABLE ) );
1120   } );
1121 }
1122
1123 void TableView::OnInitialize()
1124 {
1125   // Make self as keyboard focusable and focus group
1126   Actor self = Self();
1127   self.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
1128   SetAsKeyboardFocusGroup(true);
1129 }
1130
1131 void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
1132 {
1133   std::vector<CellData> ignored;
1134   ResizeContainers( rows, columns, ignored );
1135 }
1136
1137 void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& removed )
1138 {
1139   // Resize cell data
1140   mCellData.Resize( rows, columns, removed );
1141
1142   // We don't care if these go smaller, data will be regenerated or is not needed anymore
1143   mRowData.Resize( rows );
1144   mColumnData.Resize( columns );
1145 }
1146
1147 void TableView::RemoveAndGetLostActors( const std::vector<CellData>& lost, std::vector<Actor>& removed,
1148                                         unsigned int rowsRemoved, unsigned int columnsRemoved )
1149 {
1150   // iterate through all lost cells
1151   std::vector< CellData >::const_iterator iter = lost.begin();
1152   for( ; iter != lost.end(); ++iter )
1153   {
1154     // if it is a valid actor
1155     if( (*iter).actor )
1156     {
1157       // is this actor still somewhere else in the table
1158       Toolkit::TableView::CellPosition position;
1159       if( FindChildPosition( (*iter).actor, position ) )
1160       {
1161         // it must be spanning multiple cells, position contains the top left most one
1162         // check if position is left of the removed location
1163         if( position.columnIndex < (*iter).position.columnIndex )
1164         {
1165           // if column span is greater than 1
1166           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan > 1 )
1167           {
1168             // decrease column span
1169             mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan -= columnsRemoved;
1170           }
1171         }
1172         // check if position is left of the removed location
1173         if( position.rowIndex < (*iter).position.rowIndex )
1174         {
1175           // if row span is greater than 1
1176           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan > 1 )
1177           {
1178             // decrease row span
1179             mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan -= rowsRemoved;
1180           }
1181         }
1182       }
1183       else
1184       {
1185         // this actor is gone for good
1186         // add actor to removed container
1187         removed.push_back( (*iter).actor );
1188         // we dont want the child actor anymore
1189         Self().Remove( (*iter).actor );
1190       }
1191     }
1192   }
1193 }
1194
1195 bool TableView::RemoveAllInstances( const Actor& child )
1196 {
1197   bool found = false;
1198   // walk through the layout data
1199   const unsigned int rowCount = mCellData.GetRows();
1200   const unsigned int columnCount = mCellData.GetColumns();
1201   for( unsigned int row = 0; row < rowCount; ++row )
1202   {
1203     for( unsigned int column = 0; column < columnCount; ++column )
1204     {
1205       if( mCellData[ row ][ column ].actor == child )
1206       {
1207         // clear the cell, NOTE that the cell might be spanning multiple cells
1208         mCellData[ row ][ column ] = CellData();
1209         found = true;
1210       }
1211     }
1212   }
1213   return found;
1214 }
1215
1216 void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
1217                                          void(TableView::*funcFixed)(unsigned int, float),
1218                                          void(TableView::*funcRelative)(unsigned int, float),
1219                                          void(TableView::*funcFit)(unsigned int),
1220                                          const Property::Value& value )
1221 {
1222   const Property::Map* map = value.GetMap();
1223   if( map )
1224   {
1225     unsigned int index(0);
1226     for ( unsigned int i = 0, count = map->Count(); i < count; ++i )
1227     {
1228       Property::Value& item = map->GetValue(i);
1229       Property::Map* childMap = item.GetMap();
1230
1231       std::istringstream( map->GetKey(i) ) >> index;
1232       if( childMap )
1233       {
1234         Property::Value* policy = childMap->Find( "policy" );
1235         Property::Value* childMapValue = childMap->Find( "value" );
1236         if( policy && childMapValue )
1237         {
1238           std::string policyValue;
1239           policy->Get( policyValue );
1240           Toolkit::TableView::LayoutPolicy policy;
1241           if( Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( policyValue.c_str(),
1242                                                                              LAYOUT_POLICY_STRING_TABLE,
1243                                                                              LAYOUT_POLICY_STRING_TABLE_COUNT,
1244                                                                              policy ) )
1245           {
1246             if( policy == Toolkit::TableView::FIXED  )
1247             {
1248               (tableViewImpl.*funcFixed)( index, childMapValue->Get<float>() );
1249             }
1250             else if( policy == Toolkit::TableView::RELATIVE )
1251             {
1252               (tableViewImpl.*funcRelative)( index, childMapValue->Get<float>() );
1253             }
1254             else if( policy == Toolkit::TableView::FIT )
1255             {
1256               (tableViewImpl.*funcFit)( index );
1257             }
1258             // do nothing for FILL policy
1259           }
1260         }
1261       }
1262     }
1263   }
1264 }
1265
1266 Property::Value TableView::GetRowHeightsPropertyValue()
1267 {
1268   Property::Map map;
1269   GetMapPropertyValue( mRowData, map);
1270   return Property::Value(map);
1271 }
1272
1273 Property::Value TableView::GetColumnWidthsPropertyValue()
1274 {
1275   Property::Map map;
1276   GetMapPropertyValue( mColumnData, map);
1277   return Property::Value(map);
1278 }
1279
1280 void TableView::GetMapPropertyValue( const RowColumnArray& data, Property::Map& map )
1281 {
1282   const char* fixedPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIXED,
1283                                                                                                LAYOUT_POLICY_STRING_TABLE,
1284                                                                                                LAYOUT_POLICY_STRING_TABLE_COUNT );
1285   const char* relativePolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::RELATIVE,
1286                                                                                                   LAYOUT_POLICY_STRING_TABLE,
1287                                                                                                   LAYOUT_POLICY_STRING_TABLE_COUNT );
1288   const char* fillPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FILL,
1289                                                                                               LAYOUT_POLICY_STRING_TABLE,
1290                                                                                               LAYOUT_POLICY_STRING_TABLE_COUNT );
1291   const char* fitPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIT,
1292                                                                                              LAYOUT_POLICY_STRING_TABLE,
1293                                                                                              LAYOUT_POLICY_STRING_TABLE_COUNT );
1294
1295   const RowColumnArray::SizeType count = data.Size();
1296   for( RowColumnArray::SizeType i = 0; i < count; i++ )
1297   {
1298     const RowColumnData& dataInstance = data[ i ];
1299
1300     Property::Map item;
1301     switch( dataInstance.sizePolicy )
1302     {
1303       case Toolkit::TableView::FIXED:
1304       {
1305         item[ "policy" ] = fixedPolicy;
1306         item[ "value" ] = dataInstance.size;
1307         break;
1308       }
1309       case Toolkit::TableView::RELATIVE:
1310       {
1311         item[ "policy" ] = relativePolicy;
1312         item[ "value" ] = dataInstance.fillRatio;
1313         break;
1314       }
1315       case Toolkit::TableView::FIT:
1316       {
1317         item[ "policy" ] = fitPolicy;
1318         item[ "value" ] = 0.f;
1319         break;
1320       }
1321       case Toolkit::TableView::FILL:
1322       default:
1323       {
1324         item[ "policy" ] = fillPolicy;
1325         item[ "value" ] = 0.f;
1326         break;
1327       }
1328     }
1329     std::ostringstream ss;
1330     ss << i;
1331     map[ ss.str() ] = item;
1332   }
1333 }
1334
1335 TableView::~TableView()
1336 {
1337   // nothing to do
1338 }
1339
1340 Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
1341 {
1342   Actor nextFocusableActor;
1343
1344   if ( !currentFocusedActor )
1345   {
1346     // Nothing is currently focused, so the child in the first cell should be focused.
1347     nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1348   }
1349   else
1350   {
1351     Toolkit::TableView::CellPosition position;
1352     if( FindChildPosition( currentFocusedActor, position ) )
1353     {
1354       // The current focused actor is a child of TableView
1355       bool focusLost = false;
1356       int currentRow = position.rowIndex;
1357       int currentColumn = position.columnIndex;
1358       int numberOfColumns = GetColumns();
1359       int numberOfRows = GetRows();
1360
1361       bool lastCell = false;
1362       Actor nextValidActor;
1363
1364       switch ( direction )
1365       {
1366         case Toolkit::Control::KeyboardFocus::LEFT:
1367         {
1368           do
1369           {
1370             if(--currentColumn < 0)
1371             {
1372               currentColumn = numberOfColumns - 1;
1373               if(--currentRow < 0)
1374               {
1375                 lastCell = true;
1376                 currentRow = loopEnabled ? numberOfRows - 1 : 0;
1377                 focusLost = (currentRow == 0);
1378               }
1379             }
1380             nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1381           } while ( !nextValidActor && !lastCell );
1382           break;
1383         }
1384         case Toolkit::Control::KeyboardFocus::RIGHT:
1385         {
1386           do
1387           {
1388             if(++currentColumn > numberOfColumns - 1)
1389             {
1390               currentColumn = 0;
1391               if(++currentRow > numberOfRows - 1)
1392               {
1393                 lastCell = true;
1394                 currentRow = loopEnabled ? 0 : numberOfRows - 1;
1395                 focusLost = (currentRow == numberOfRows - 1);
1396               }
1397             }
1398             nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1399           } while ( !nextValidActor && !lastCell );
1400           break;
1401         }
1402         case Toolkit::Control::KeyboardFocus::UP:
1403         {
1404           do
1405           {
1406             if(--currentRow < 0)
1407             {
1408               lastCell = true;
1409               currentRow = loopEnabled ? numberOfRows - 1 : 0;
1410               focusLost = (currentRow == 0);
1411             }
1412             nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1413           } while ( !nextValidActor && !lastCell );
1414           break;
1415         }
1416         case Toolkit::Control::KeyboardFocus::DOWN:
1417
1418         {
1419           do
1420           {
1421             if(++currentRow > numberOfRows - 1)
1422             {
1423               lastCell = true;
1424               currentRow = loopEnabled ? 0 : numberOfRows - 1;
1425               focusLost = (currentRow == numberOfRows - 1);
1426             }
1427             nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1428           } while ( !nextValidActor && !lastCell );
1429           break;
1430         }
1431         default:
1432         {
1433           break;
1434         }
1435       }
1436
1437       // Move the focus if we haven't lost it.
1438       if(!focusLost)
1439       {
1440         nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1441
1442         // Save the focused actor in the TableView.
1443         mPreviousFocusedActor = nextFocusableActor;
1444       }
1445     }
1446     else
1447     {
1448       // The current focused actor is not within this TableView.
1449
1450       unsigned int numberOfColumns = GetColumns();
1451       unsigned int numberOfRows = GetRows();
1452
1453       // Check whether the previous focused actor is a focus group (i.e. a layout container)
1454       bool wasFocusedOnLayoutContainer = false;
1455       Actor previousFocusedActor = mPreviousFocusedActor.GetHandle();
1456       if( previousFocusedActor )
1457       {
1458         Toolkit::Control control = Toolkit::Control::DownCast( previousFocusedActor );
1459         if( control )
1460         {
1461           Internal::Control& controlImpl = static_cast<Internal::Control&>(control.GetImplementation());
1462           wasFocusedOnLayoutContainer = controlImpl.IsKeyboardFocusGroup();
1463         }
1464       }
1465
1466       // Check whether the previous focused actor is a layout container and also a child of this TableView
1467       Toolkit::TableView::CellPosition position;
1468       if( wasFocusedOnLayoutContainer && FindChildPosition( previousFocusedActor, position ) )
1469       {
1470         nextFocusableActor = GetNextKeyboardFocusableActor(previousFocusedActor, direction, loopEnabled);
1471       }
1472       else
1473       {
1474         // Otherwise, move the focus to either the first or the last cell according to the given direction.
1475         if(direction == Toolkit::Control::KeyboardFocus::LEFT || direction == Toolkit::Control::KeyboardFocus::UP)
1476         {
1477           nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(numberOfRows - 1, numberOfColumns - 1));
1478         }
1479         else
1480         {
1481           nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1482         }
1483       }
1484     }
1485   }
1486
1487   return nextFocusableActor;
1488 }
1489
1490 Vector3 TableView::GetNaturalSize()
1491 {
1492   // Natural size is the size of all fixed cell widths or heights. This ignores cells with relative heights.
1493   return Vector3( mFixedTotals.width, mFixedTotals.height, 1.0f );
1494 }
1495
1496 float TableView::CalculateChildSize( const Actor& child, Dimension::Type dimension )
1497 {
1498   Toolkit::TableView::CellPosition position;
1499   if( FindChildPosition( child, position) )
1500   {
1501     switch( dimension )
1502     {
1503       case Dimension::WIDTH:
1504       {
1505         float cellSize = 0.0f;
1506         cellSize = mColumnData[position.columnIndex+position.columnSpan-1].position
1507                  - (position.columnIndex > 0 ? mColumnData[position.columnIndex-1].position : 0.f)
1508                  - mPadding.width * 2.0f;
1509
1510         if( cellSize < 0.0f )
1511         {
1512           cellSize = 0.0f;
1513         }
1514
1515         return cellSize;
1516       }
1517
1518       case Dimension::HEIGHT:
1519       {
1520         float cellSize = 0.0f;
1521
1522         cellSize = mRowData[position.rowIndex+position.rowSpan-1].position
1523                  - (position.rowIndex > 0 ? mRowData[position.rowIndex-1].position : 0.f)
1524                  - mPadding.height * 2.0f;
1525
1526         if( cellSize < 0.0f )
1527         {
1528           cellSize = 0.0f;
1529         }
1530
1531         return cellSize;
1532       }
1533       default:
1534       {
1535         return 0.0f;
1536       }
1537     }
1538   }
1539
1540   return 0.0f;    // Child not found
1541 }
1542
1543 bool TableView::RelayoutDependentOnChildren( Dimension::Type dimension )
1544 {
1545   if ( Control::RelayoutDependentOnChildren( dimension ) )
1546   {
1547     return true;
1548   }
1549
1550   return FindFit( mRowData ) || FindFit( mColumnData );
1551 }
1552
1553 void TableView::SetCellAlignment( Toolkit::TableView::CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical )
1554 {
1555   // Check if we need to expand our data array
1556   if( position.rowIndex >= mCellData.GetRows() )
1557   {
1558     // Only adding new rows
1559     ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
1560   }
1561
1562   if( position.columnIndex >= mCellData.GetColumns() )
1563   {
1564     // Only adding new columns
1565     ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
1566   }
1567
1568   // Set the alignment of the cell
1569   CellData& data = mCellData[ position.rowIndex ][ position.columnIndex ];
1570   data.horizontalAlignment = horizontal;
1571   data.verticalAlignment = vertical;
1572 }
1573
1574 void TableView::CalculateFillSizes( RowColumnArray& data )
1575 {
1576   // First pass: Count number of fill entries and calculate used relative space
1577   Dali::Vector< RowColumnData* > fillData;
1578   float relativeTotal = 0.0f;
1579
1580   const unsigned int dataCount = data.Size();
1581
1582   for( unsigned int i = 0; i < dataCount; ++i )
1583   {
1584     RowColumnData& dataInstance = data[ i ];
1585
1586     if( dataInstance.sizePolicy == Toolkit::TableView::RELATIVE )
1587     {
1588       relativeTotal += dataInstance.fillRatio;
1589     }
1590     else if(dataInstance.sizePolicy == Toolkit::TableView::FILL)
1591     {
1592       fillData.PushBack( &dataInstance );
1593     }
1594   }
1595
1596   // Second pass: Distribute remaining relative space
1597   const unsigned int fillCount = fillData.Size();
1598   if( fillCount > 0 )
1599   {
1600     if( relativeTotal > 1.0f )
1601     {
1602       relativeTotal = 1.0f;
1603     }
1604
1605     const float evenFillRatio = (1.0f - relativeTotal ) / fillCount;
1606
1607     for( unsigned int i = 0; i < fillCount; ++i )
1608     {
1609       fillData[ i ]->fillRatio = evenFillRatio;
1610     }
1611   }
1612 }
1613
1614 float TableView::CalculateTotalFixedSize( const RowColumnArray& data )
1615 {
1616   float totalSize = 0.0f;
1617
1618   const unsigned int dataCount = data.Size();
1619
1620   for( unsigned int i = 0; i < dataCount; ++i )
1621   {
1622     const RowColumnData& dataInstance = data[ i ];
1623
1624     switch( dataInstance.sizePolicy )
1625     {
1626       // we have absolute size to FIXED and FIT column/row and relative size for RELATIVE and FILL column/row
1627       case Toolkit::TableView::FIXED:
1628       case Toolkit::TableView::FIT:
1629       {
1630         totalSize += dataInstance.size;
1631         break;
1632       }
1633
1634       default:
1635       {
1636         break;
1637       }
1638     }
1639   }
1640
1641   return totalSize;
1642 }
1643
1644 Vector2 TableView::GetCellPadding( Dimension::Type dimension )
1645 {
1646   switch( dimension )
1647   {
1648     case Dimension::WIDTH:
1649     {
1650       return Vector2( mPadding.x, mPadding.x );
1651     }
1652     case Dimension::HEIGHT:
1653     {
1654       return Vector2( mPadding.y, mPadding.y );
1655     }
1656     default:
1657     {
1658       break;
1659     }
1660   }
1661
1662   return Vector2();
1663 }
1664
1665 void TableView::CalculateFitSizes( RowColumnArray& data, Dimension::Type dimension )
1666 {
1667   Vector2 cellPadding = GetCellPadding( dimension );
1668
1669   const unsigned int dataCount = data.Size();
1670
1671   for( unsigned int i = 0; i < dataCount; ++i )
1672   {
1673     RowColumnData& dataInstance = data[ i ];
1674
1675     if( dataInstance.sizePolicy == Toolkit::TableView::FIT )
1676     {
1677       // Find the size of the biggest actor in the row or column
1678       float maxActorHeight = 0.0f;
1679
1680       unsigned int fitCount = ( dimension == Dimension::WIDTH ) ? mCellData.GetRows() : mCellData.GetColumns();
1681
1682       for( unsigned int j = 0; j < fitCount; ++j )
1683       {
1684         unsigned int row = ( dimension == Dimension::WIDTH ) ? j : i;
1685         unsigned int column = ( dimension == Dimension::WIDTH ) ? i : j;
1686         DALI_ASSERT_DEBUG( row < mCellData.GetRows() );
1687         DALI_ASSERT_DEBUG( column < mCellData.GetColumns() );
1688
1689         const CellData& cellData = mCellData[ row ][ column ];
1690         const Actor& actor = cellData.actor;
1691         if( actor )
1692         {
1693           if( FitToChild( actor, dimension ) && ( dimension == Dimension::WIDTH ) ? ( cellData.position.columnSpan == 1 ) : ( cellData.position.rowSpan == 1 )  )
1694           {
1695             maxActorHeight = std::max( maxActorHeight, actor.GetRelayoutSize( dimension ) + cellPadding.x + cellPadding.y );
1696           }
1697         }
1698       }
1699
1700       dataInstance.size = maxActorHeight;
1701     }
1702   }
1703 }
1704
1705 bool TableView::FindFit( const RowColumnArray& data )
1706 {
1707   for( unsigned int i = 0, count = data.Size(); i < count; ++i )
1708   {
1709     if( data[ i ].sizePolicy == Toolkit::TableView::FIT )
1710     {
1711       return true;
1712     }
1713   }
1714
1715   return false;
1716 }
1717
1718 } // namespace Internal
1719
1720 } // namespace Toolkit
1721
1722 } // namespace Dali