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