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