[dali_1.0.33] Merge branch 'tizen'
[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/public-api/object/type-registry-helper.h>
26 #include <dali/public-api/scripting/scripting.h>
27 #include <dali/integration-api/debug.h>
28
29 using namespace Dali;
30
31 namespace
32 {
33 const float DEFAULT_CONSTRAINT_DURATION = 0.0f;
34
35 /**
36  * sets a child property relative to parents size and applies a unit based padding before the relative calculation.
37  * @param[in] scale of parent minus padding between 0 and 1
38  * @param[in] padding in world coordinate units
39  * @param[in] fixed part in world coordinate units
40  * @param[in] size of the parent
41  * @return The relative size with padding.
42  */
43 Vector2 RelativeToSize( const Vector2& scale, const Vector2& padding, const Vector2& fixed, const Vector2& parentSize)
44 {
45   return fixed + ( parentSize - padding ) * scale;
46 }
47
48 #if defined(DEBUG_ENABLED)
49 // debugging support, very useful when new features are added or bugs are hunted down
50 // currently not called from code so compiler will optimize these away, kept here for future debugging
51
52 #define TABLEVIEW_TAG "DALI Toolkit::TableView "
53 #define TV_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
54
55 void PrintArray( Array2d<Dali::Toolkit::Internal::TableView::CellData>& array )
56 {
57   TV_LOG( "Array2d<CellData> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
58   // print values
59   for( unsigned int i = 0; i < array.GetRows(); ++i )
60   {
61     for( unsigned int j = 0; j < array.GetColumns(); ++j )
62     {
63       Dali::Toolkit::Internal::TableView::CellData data = array[i][j];
64       char actor = ' ';
65       if( data.actor )
66       {
67         actor = 'A';
68       }
69       TV_LOG("Array[%d,%d]=%c %d,%d,%d,%d  ", i, j, actor,
70           data.position.rowIndex, data.position.columnIndex,
71           data.position.rowSpan, data.position.columnSpan );
72     }
73     TV_LOG( "\n" );
74   }
75 }
76
77 // debugging support, very useful when new features are added or bugs are hunted down
78 // currently not called from code so compiler will optimize these away, kept here for future debugging
79 void PrintArray( Array2d<Size>& array )
80 {
81   TV_LOG( "Array2d<Size> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
82   // print values
83   for( unsigned int i = 0; i < array.GetRows(); ++i )
84   {
85     for( unsigned int j = 0; j < array.GetColumns(); ++j )
86     {
87       TV_LOG( "Array[%d,%d]=%.2f,%.2f ", i, j, array[i][j].width, array[i][j].height );
88     }
89     TV_LOG( "\n" );
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 PrintVector( std::vector<float>& array )
95 {
96   TV_LOG( "vector, size [%d]\n", array.size() );
97   // print values
98   for( unsigned int i = 0; i < array.size(); ++i )
99   {
100     TV_LOG( "vector[%d]=%.2f ", i, array[i] );
101   }
102   TV_LOG( "\n" );
103 }
104 #endif // defined(DEBUG_ENABLED)
105
106 } // namespace
107
108 namespace Dali
109 {
110
111 namespace Toolkit
112 {
113
114 namespace Internal
115 {
116
117 namespace
118 {
119
120 // Type registration
121 BaseHandle Create()
122 {
123   return Toolkit::TableView::New( 0, 0 );
124 }
125
126 // Setup properties, signals and actions using the type-registry.
127 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TableView, Toolkit::Control, Create );
128
129 DALI_PROPERTY_REGISTRATION( TableView, "rows",           UNSIGNED_INTEGER, ROWS           )
130 DALI_PROPERTY_REGISTRATION( TableView, "columns",        UNSIGNED_INTEGER, COLUMNS        )
131 DALI_PROPERTY_REGISTRATION( TableView, "cell-padding",   VECTOR2,          CELL_PADDING   )
132 DALI_PROPERTY_REGISTRATION( TableView, "layout-rows",    MAP,              LAYOUT_ROWS    )
133 DALI_PROPERTY_REGISTRATION( TableView, "layout-columns", MAP,              LAYOUT_COLUMNS )
134
135 DALI_TYPE_REGISTRATION_END()
136
137 const Scripting::StringEnum< Toolkit::TableView::LayoutPolicy > LAYOUT_POLICY_STRING_TABLE[] =
138 {
139  { "fixed",    Toolkit::TableView::Fixed    },
140  { "relative", Toolkit::TableView::Relative },
141  { "fill",     Toolkit::TableView::Fill     }
142 };
143
144 const unsigned int LAYOUT_POLICY_STRING_TABLE_COUNT = sizeof(LAYOUT_POLICY_STRING_TABLE) / sizeof( LAYOUT_POLICY_STRING_TABLE[0] );
145
146 } // Unnamed namespace
147
148 Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns )
149 {
150   // Create the implementation, temporarily owned by this handle on stack
151   IntrusivePtr< TableView > impl = new TableView( initialRows, initialColumns );
152
153   // Pass ownership to CustomActor handle
154   Toolkit::TableView handle( *impl );
155
156   // Second-phase init of the implementation
157   // This can only be done after the CustomActor connection has been made...
158   impl->Initialize();
159
160   return handle;
161 }
162
163 bool TableView::AddChild( Actor child, Toolkit::TableView::CellPosition position )
164 {
165   // check that the child is valid
166   DALI_ASSERT_ALWAYS( child );
167
168   // if child is already parented, we adopt it
169   if( child.GetParent() )
170   {
171     child.GetParent().Remove( child );
172   }
173   // check if we need to expand our data array
174   if( position.rowIndex >= mCellData.GetRows() )
175   {
176     // only adding new rows
177     ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
178   }
179   if( position.columnIndex >= mCellData.GetColumns() )
180   {
181     // only adding new columns
182     ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
183   }
184   // check if there already is something in this cell
185   if( mCellData[ position.rowIndex ][ position.columnIndex ].actor )
186   {
187     return false; // cannot share a cell, it would complicate all logic and not bring much benefit
188   }
189   RelayoutingLock lock( *this );
190   // adopt the child
191   Self().Add( child );
192
193   // put the actor to the main cell
194   CellData data;
195   data.actor = child;
196   data.position = position;
197   mCellData[ position.rowIndex ][ position.columnIndex ] = data;
198   // if child spans multiple rows of columns
199   bool spanned = false;
200   if( position.rowSpan > 1 )
201   {
202     // span might go outside table
203     if( position.rowIndex + position.rowSpan > mCellData.GetRows() )
204     {
205       // increase table size for the full span, only increasing rows
206       ResizeContainers( position.rowIndex + position.rowSpan, mCellData.GetColumns() );
207     }
208     spanned = true;
209   }
210   if( position.columnSpan > 1 )
211   {
212     // span might go outside table
213     if( position.columnIndex + position.columnSpan > mCellData.GetColumns() )
214     {
215       // increase table size for the full span, only increasing columns
216       ResizeContainers( mCellData.GetRows(), position.columnIndex + position.columnSpan );
217     }
218     spanned = true;
219   }
220   // if it spanned multiple rows, put the cellinfo in all of those
221   if( spanned )
222   {
223     for( unsigned int row = position.rowIndex; row < ( position.rowIndex + position.rowSpan ); ++row )
224     {
225       // store same information to all cells, this way we can identify
226       // if a cell is the prime location of an actor or a spanned one
227       for( unsigned int column = position.columnIndex; column < ( position.columnIndex + position.columnSpan ); ++column )
228       {
229         // store same information to all cells, this way we can identify
230         // if a cell is the prime location of an actor or a spanned one
231         mCellData[ row ][ column ] = data;
232       }
233     }
234   }
235   // relayout the whole table
236   RelayoutRequest();
237   return true; // addition successful
238 }
239
240 Actor TableView::GetChildAt( Toolkit::TableView::CellPosition position )
241 {
242   // check if we have this row and column in the table
243   if( ( position.columnIndex >= mCellData.GetColumns() )||
244       ( position.rowIndex >= mCellData.GetRows() ) )
245   {
246     // return an empty handle
247     return Actor();
248   }
249   // return the child handle
250   return mCellData[ position.rowIndex ][ position.columnIndex ].actor;
251 }
252
253 Actor TableView::RemoveChildAt( Toolkit::TableView::CellPosition position )
254 {
255   // get the child handle
256   Actor child = GetChildAt( position );
257   // if no real actor there, nothing else to be done
258   if( child )
259   {
260     RelayoutingLock lock( *this );
261     // Remove the child, this will trigger a call to OnControlChildRemove
262     Self().Remove( child );
263
264     // relayout the table only if instances were found
265     if( RemoveAllInstances( child ) )
266     {
267       RelayoutRequest();
268     }
269   }
270   // return the child back to caller
271   return child;
272 }
273
274 bool TableView::FindChildPosition( Actor child, Toolkit::TableView::CellPosition& position )
275 {
276   // only find valid child actors
277   if( child )
278   {
279     // walk through the layout data
280     const unsigned int rowCount = mCellData.GetRows();
281     const unsigned int columnCount = mCellData.GetColumns();
282     for( unsigned int row = 0; row < rowCount; ++row )
283     {
284       for( unsigned int column = 0; column < columnCount; ++column )
285       {
286         if( mCellData[ row ][ column ].actor == child )
287         {
288           position = mCellData[ row ][ column ].position;
289           return true;
290         }
291       }
292     }
293   }
294   return false;
295 }
296
297 void TableView::InsertRow( unsigned int rowIndex )
298 {
299   RelayoutingLock lock( *this );
300   mCellData.InsertRow( rowIndex );
301   // need to update the cellinfos for the items that moved
302   const unsigned int rowCount = mCellData.GetRows();
303   const unsigned int columnCount = mCellData.GetColumns();
304   for( unsigned int row = 0; row < rowCount; ++row )
305   {
306     for( unsigned int column = 0; column < columnCount; ++column )
307     {
308       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
309       // if cell is spanning and above and spans to inserted row
310       if( ( position.rowSpan > 1 )&&( position.rowIndex <= rowIndex )&&
311           ( position.rowIndex + position.rowSpan > rowIndex ) )
312       {
313         // increase span by one
314         position.rowSpan++;
315         // copy cell to occupy the new column
316         mCellData[ rowIndex ][ column ] = mCellData[ row ][ column ];
317       }
318       // if below of inserted row, increase row index
319       else if( row > rowIndex )
320       {
321         // increase index by one
322         position.rowIndex++;
323       }
324     }
325   }
326   mRelativeSizes.InsertRow( rowIndex );
327   // inserting a row requires adjusting the height vectors
328   mFixedHeights.insert( mFixedHeights.begin() + rowIndex, 0 );
329   mRelativeHeights.insert( mRelativeHeights.begin() + rowIndex, 0 );
330   RelayoutRequest();
331 }
332
333 void TableView::DeleteRow( unsigned int rowIndex )
334 {
335   std::vector< Actor > ignored;
336   DeleteRow( rowIndex, ignored );
337 }
338
339 void TableView::DeleteRow( unsigned int rowIndex, std::vector<Actor>& removed )
340 {
341   RelayoutingLock lock( *this );
342   std::vector< CellData > lost;
343   mCellData.DeleteRow( rowIndex, lost );
344   // need to update the cellinfos for the items that moved
345   const unsigned int rowCount = mCellData.GetRows();
346   const unsigned int columnCount = mCellData.GetColumns();
347   for( unsigned int row = 0; row < rowCount; ++row )
348   {
349     for( unsigned int column = 0; column < columnCount; ++column )
350     {
351       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
352       // if cell is spanning and above and spans to deleted row
353       if( ( position.rowSpan > 1 )&&( position.rowIndex <= rowIndex )&&
354           ( position.rowIndex + position.rowSpan > rowIndex ) )
355       {
356         // decrease span by one
357         if( position.rowSpan > 1 )
358         {
359           position.rowSpan--;
360         }
361       }
362       // if below of or at the inserted row, decrease row index
363       else if( row >= rowIndex )
364       {
365         // decrease index by one
366         if( position.rowIndex > 1 )
367         {
368           position.rowIndex--;
369         }
370       }
371     }
372   }
373   // 1 row removed, 0 columns
374   RemoveAndGetLostActors( lost, removed, 1u, 0u );
375   // resize the data structures
376   mRelativeSizes.DeleteRow( rowIndex );
377   // deleting a row requires adjusting the height vectors
378   mFixedHeights.erase( mFixedHeights.begin() + rowIndex );
379   mRelativeHeights.erase( mRelativeHeights.begin() + rowIndex );
380   RelayoutRequest();
381 }
382
383 void TableView::InsertColumn( unsigned int columnIndex )
384 {
385   RelayoutingLock lock( *this );
386   mCellData.InsertColumn( columnIndex );
387   // need to update the cellinfos for the items that moved
388   const unsigned int rowCount = mCellData.GetRows();
389   const unsigned int columnCount = mCellData.GetColumns();
390   for( unsigned int row = 0; row < rowCount; ++row )
391   {
392     for( unsigned int column = 0; column < columnCount; ++column )
393     {
394       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
395       // if cell is spanning and left side and spans to inserted column
396       if( ( position.columnSpan > 1 )&&( position.columnIndex <= columnIndex )&&
397           ( position.columnIndex + position.columnSpan > columnIndex ) )
398       {
399         // increase span by one
400         position.columnSpan++;
401         // copy cell to occupy the new column
402         mCellData[ row ][ columnIndex ] = mCellData[ row ][ column ];
403       }
404       // if on the right side of inserted column, increase column index
405       else if( column > columnIndex )
406       {
407         // increase index by one
408         position.columnIndex++;
409       }
410     }
411   }
412   // relative sizes gets recalculated on Relayout
413   mRelativeSizes.InsertColumn( columnIndex );
414   // inserting a column requires adjusting the width vectors
415   mFixedWidths.insert( mFixedWidths.begin() + columnIndex, 0 );
416   mRelativeWidths.insert( mRelativeWidths.begin() + columnIndex, 0 );
417   RelayoutRequest();
418 }
419
420 void TableView::DeleteColumn( unsigned int columnIndex )
421 {
422   std::vector< Actor > ignored;
423   DeleteColumn( columnIndex, ignored );
424 }
425
426 void TableView::DeleteColumn( unsigned int columnIndex, std::vector<Actor>& removed )
427 {
428   RelayoutingLock lock( *this );
429   std::vector< CellData > lost;
430   mCellData.DeleteColumn( columnIndex, lost );
431   // need to update the cellinfos for the items that moved
432   const unsigned int rowCount = mCellData.GetRows();
433   const unsigned int columnCount = mCellData.GetColumns();
434   for( unsigned int row = 0; row < rowCount; ++row )
435   {
436     for( unsigned int column = 0; column < columnCount; ++column )
437     {
438       Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
439       // if cell is spanning and left side and spans to inserted column
440       if( ( position.columnSpan > 1 )&&( position.columnIndex <= columnIndex )&&
441           ( position.columnIndex + position.columnSpan > columnIndex ) )
442       {
443         // decrease span by one
444         if( position.columnSpan > 1 )
445         {
446           position.columnSpan--;
447         }
448       }
449       // if on the right side of or at the inserted column, decrease column index
450       else if( column >= columnIndex )
451       {
452         // decrease index by one
453         if( position.columnIndex > 0 )
454         {
455           position.columnIndex--;
456         }
457       }
458     }
459   }
460   // 0 rows, 1 column removed
461   RemoveAndGetLostActors( lost, removed, 0u, 1u );
462   // resize the data structures
463   mRelativeSizes.DeleteColumn( columnIndex );
464   // deleting a column requires adjusting the width vectors
465   mFixedWidths.erase( mFixedWidths.begin() + columnIndex );
466   mRelativeWidths.erase( mRelativeWidths.begin() + columnIndex );
467   // relayout
468   RelayoutRequest();
469 }
470
471 void TableView::Resize( unsigned int rows, unsigned int columns )
472 {
473   std::vector< Actor > ignored;
474   Resize( rows, columns, ignored );
475 }
476
477 void TableView::Resize( unsigned int rows, unsigned int columns, std::vector<Actor>& removed )
478 {
479   RelayoutingLock lock( *this );
480   unsigned int oldRows = GetRows();
481   unsigned int oldColumns = GetColumns();
482   // resize data array
483   std::vector< CellData > lost;
484   ResizeContainers( rows, columns, lost );
485   // calculate if we lost rows or columns
486   unsigned int rowsRemoved = 0;
487   unsigned int newRows = GetRows();
488   if( oldRows < newRows )
489   {
490     rowsRemoved = newRows - oldRows;
491   }
492   unsigned int columnsRemoved = 0;
493   unsigned int newColumns = GetColumns();
494   if( oldColumns < newColumns )
495   {
496     rowsRemoved = newColumns - oldColumns;
497   }
498   RemoveAndGetLostActors( lost, removed, rowsRemoved, columnsRemoved );
499   // finally relayout once all actors are removed
500   RelayoutRequest();
501 }
502
503 void TableView::SetCellPadding( Size padding )
504 {
505   // if padding really changed
506   if( padding != mPadding )
507   {
508     mPadding = padding;
509     // do a relayout
510     RelayoutRequest();
511   }
512 }
513
514 Size TableView::GetCellPadding()
515 {
516   return mPadding;
517 }
518
519 void TableView::SetFixedHeight( unsigned int rowIndex, float height )
520 {
521   DALI_ASSERT_ALWAYS( rowIndex < mFixedHeights.size() );
522   // add the fixed height to the array of fixed heights
523   mFixedHeights[ rowIndex ] = height;
524   // remove the relative height of the same row
525   mRelativeHeights[ rowIndex ] = 0.f;
526   // relayout all cells, no lock needed as nothing added or removed
527   RelayoutRequest();
528 }
529
530 float TableView::GetFixedHeight( unsigned int rowIndex ) const
531 {
532   DALI_ASSERT_ALWAYS( rowIndex < mFixedHeights.size() );
533
534   return mFixedHeights[ rowIndex ];
535 }
536
537 void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage )
538 {
539   DALI_ASSERT_ALWAYS( rowIndex < mRelativeHeights.size() );
540   // add the relative height to the array of relative heights
541   mRelativeHeights[ rowIndex ] = heightPercentage;
542   // remove the fixed height of the same row
543   mFixedHeights[ rowIndex ] = 0.f;
544   // relayout all cells, no lock needed as nothing added or removed
545   RelayoutRequest();
546 }
547
548 float TableView::GetRelativeHeight( unsigned int rowIndex ) const
549 {
550   DALI_ASSERT_ALWAYS( rowIndex < mRelativeHeights.size() );
551
552   return mRelativeHeights[ rowIndex ];
553 }
554
555 void TableView::SetFixedWidth( unsigned int columnIndex, float width )
556 {
557   DALI_ASSERT_ALWAYS( columnIndex < mFixedWidths.size() );
558   // add the fixed width to the array of fixed column widths
559   mFixedWidths[ columnIndex ] = width;
560   // remove the relative width of the same column
561   mRelativeWidths[ columnIndex ] = 0.f;
562   // relayout all cells, no lock needed as nothing added or removed
563   RelayoutRequest();
564 }
565
566 float TableView::GetFixedWidth( unsigned int columnIndex ) const
567 {
568   DALI_ASSERT_ALWAYS( columnIndex < mFixedWidths.size() );
569
570   return mFixedWidths[ columnIndex ];
571 }
572
573 void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentage )
574 {
575   DALI_ASSERT_ALWAYS( columnIndex < mRelativeWidths.size() );
576   // add the relative widths to the array of relative widths
577   mRelativeWidths[ columnIndex ] = widthPercentage;
578   // remove the fixed width of the same column
579   mFixedWidths[ columnIndex ] = 0.f;
580   // relayout all cells, no lock needed as nothing added or removed
581   RelayoutRequest();
582 }
583
584 float TableView::GetRelativeWidth( unsigned int columnIndex ) const
585 {
586   DALI_ASSERT_ALWAYS( columnIndex < mRelativeWidths.size() );
587
588   return mRelativeWidths[ columnIndex ];
589 }
590
591 void TableView::OnRelayout( const Vector2& size, ActorSizeContainer& container )
592 {
593   float fixedHeightsTotal = 0.0f;
594   float fixedWidthsTotal = 0.0f;
595
596   // 1. update the relative sizes and calculate total fixed height and width
597   UpdateRelativeSizes( fixedHeightsTotal, fixedWidthsTotal );
598
599   // 2. go through the layout data and create constraints
600   float cumulatedFixedHeight = 0.0f;
601   float cumulatedRelativeHeight = 0.0f;
602
603   // iterate the table
604   const unsigned int rowCount = mCellData.GetRows();
605   const unsigned int columnCount = mCellData.GetColumns();
606   // float versions of the count + 1 to keep precision
607   const float maxRowPlusOne( rowCount + 1 );
608   const float maxColumnPlusOne( columnCount + 1 );
609   for( unsigned int row = 0; row < rowCount; ++row )
610   {
611     // reset widths at the start of each row
612     float cumulatedFixedWidth = 0.0f;
613     float cumulatedRelativeWidth = 0.0f;
614     for( unsigned int column = 0; column < columnCount; ++column )
615     {
616       // check if this cell has an actor
617       Actor actor = mCellData[ row ][ column ].actor;
618       const Toolkit::TableView::CellPosition position = mCellData[ row ][ column ].position;
619       // if there is an actor and this is the main cell of the actor
620       // an actor can be in multiple cells if its row or columnspan is more than 1
621       // we however must only lay out each actor only once
622       if( ( actor )&&( position.rowIndex == row )&&( position.columnIndex == column ) )
623       {
624         // anchor actor correctly
625         actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
626         actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
627         // remove old constraints
628         actor.RemoveConstraints();
629
630         // 1. set position
631         // get the row and column indices
632         float rowPos( position.rowIndex );
633         float colPos( position.columnIndex );
634         // constrain the actor position to be relative to the width and height of table
635         // minus the padding of course (padding is all around cells)
636         Vector2 relativePosition( cumulatedRelativeWidth, cumulatedRelativeHeight );
637         // fixed height rows and fixed width cells are considered as padding so
638         // they are removed from the total size for relative
639         // for position only consider cumulated fixed rows and columns from top and left
640         Vector2 positionPadding( maxColumnPlusOne * mPadding.width + fixedWidthsTotal,
641                                  maxRowPlusOne * mPadding.height + fixedHeightsTotal );
642         Vector2 fixedPosition( ( colPos + 1.0f ) * mPadding.width + cumulatedFixedWidth,
643                                  ( rowPos + 1.0f ) * mPadding.height + cumulatedFixedHeight );
644
645         Vector3 actorPosition( RelativeToSize( relativePosition, positionPadding, fixedPosition, size ) );
646         actor.SetPosition( actorPosition );
647
648         // 2. set size
649         // constrain the actor size to be relative to the size of table
650         // get the relative size for this cell
651         Vector2 relativeSize( mRelativeSizes[ row ][ column ] );
652         Vector2 fixedSize( mFixedWidths[ column ], mFixedHeights[ row ] );
653         // if we span multiple cells, need to sum them all up, both fixed and relative parts
654         if( position.rowSpan > 1 )
655         {
656           for( unsigned int i = 1; i < position.rowSpan; ++i )
657           {
658             // accumulate the height only
659             relativeSize.height += mRelativeSizes[ row + i ][ column ].height;
660             fixedSize.height += mFixedHeights[ row + i ];
661           }
662         }
663         if( position.columnSpan > 1 )
664         {
665           for( unsigned int i = 1; i < position.columnSpan; ++i )
666           {
667             // accumulate the width only
668             relativeSize.width += mRelativeSizes[ row ][ column + i ].width;
669             fixedSize.width += mFixedWidths[ column + i ];
670           }
671         }
672         // minus the padding from size (padding is all around cells)
673         // if item spans multiple columns or rows then less padding is added (default span is 1)
674         // fixed height rows and fixed width cells are considered as padding so they are removed
675         // from the total available size for relative cells
676         Vector2 sizePadding( maxColumnPlusOne * mPadding.width + fixedWidthsTotal,
677                              maxRowPlusOne * mPadding.height + fixedHeightsTotal );
678         // and added to the fixed size multiplied by the span of rows and columns
679         fixedSize.width += ( position.columnSpan - 1.0f ) * mPadding.width;
680         fixedSize.height += ( position.rowSpan - 1.0f ) * mPadding.height;
681
682         Vector2 actorSize( RelativeToSize( relativeSize, sizePadding, fixedSize, size ) );
683         actor.SetSize(actorSize.x, actorSize.y);
684
685         // Relayout Children
686         Relayout ( actor, actorSize, container );
687       }
688       // for position we need to keep track of current fixed width and relative width
689       // increase for next column
690       cumulatedFixedWidth += mFixedWidths[ column ];
691       cumulatedRelativeWidth += mRelativeSizes[ row ][ column ].width;
692     }
693     // for position we need to keep track of current fixed height and relative height
694     // increase for next row
695     cumulatedFixedHeight += mFixedHeights[ row ];
696     cumulatedRelativeHeight += mRelativeSizes[ row ][ 0 ].height; // all columns share same height
697   }
698 }
699
700 unsigned int TableView::GetRows()
701 {
702   return mCellData.GetRows();
703 }
704
705 unsigned int TableView::GetColumns()
706 {
707   return mCellData.GetColumns();
708 }
709
710 void TableView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
711 {
712   Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
713
714   if( tableView )
715   {
716     TableView& tableViewImpl( GetImpl( tableView ) );
717     switch( index )
718     {
719       case Toolkit::TableView::Property::ROWS:
720       {
721         if( value.Get<unsigned int>() != tableViewImpl.GetRows() )
722         {
723           tableViewImpl.Resize( value.Get<unsigned int>(), tableViewImpl.GetColumns() );
724         }
725         break;
726       }
727       case Toolkit::TableView::Property::COLUMNS:
728       {
729         if( value.Get<unsigned int>() != tableViewImpl.GetColumns() )
730         {
731           tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<unsigned int>() );
732         }
733         break;
734       }
735       case Toolkit::TableView::Property::CELL_PADDING:
736       {
737         tableViewImpl.SetCellPadding( value.Get<Vector2>() );
738         break;
739       }
740       case Toolkit::TableView::Property::LAYOUT_ROWS:
741       {
742         SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, value );
743         break;
744       }
745       case Toolkit::TableView::Property::LAYOUT_COLUMNS:
746       {
747         SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, value );
748         break;
749       }
750     }
751   }
752 }
753
754 Property::Value TableView::GetProperty( BaseObject* object, Property::Index index )
755 {
756   Property::Value value;
757
758   Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
759
760   if( tableView )
761   {
762     TableView& tableViewImpl( GetImpl( tableView ) );
763     switch( index )
764     {
765       case Toolkit::TableView::Property::ROWS:
766       {
767         value = tableViewImpl.GetRows();
768         break;
769       }
770       case Toolkit::TableView::Property::COLUMNS:
771       {
772         value = tableViewImpl.GetColumns();
773         break;
774       }
775       case Toolkit::TableView::Property::CELL_PADDING:
776       {
777         value = tableViewImpl.GetCellPadding();
778         break;
779       }
780       case Toolkit::TableView::Property::LAYOUT_ROWS:
781       {
782         value = tableViewImpl.GetRowHeightsPropertyValue();
783         break;
784       }
785       case Toolkit::TableView::Property::LAYOUT_COLUMNS:
786       {
787         value = tableViewImpl.GetColumnWidthsPropertyValue();
788         break;
789       }
790     }
791   }
792
793   return value;
794 }
795
796 void TableView::OnControlChildAdd( Actor& child )
797 {
798   if( mLayoutingChild )
799   {
800     // we're in the middle of laying out children so no point doing anything here
801     return;
802   }
803
804   Toolkit::TableView::CellPosition cellPosition;
805   if( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
806   {
807     cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
808   }
809   if( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
810   {
811     cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
812   }
813   if( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) != Property::INVALID_INDEX )
814   {
815     Vector2 indices = child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) ).Get<Vector2 >();
816     cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
817     cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
818
819     AddChild( child, cellPosition );
820     // donot continue
821     return;
822   }
823
824   // check if we're already laying out this child somewhere on the table
825   // walk through the layout data
826   const unsigned int rowCount = mCellData.GetRows();
827   const unsigned int columnCount = mCellData.GetColumns();
828   // child not yet laid out, find the first free slot
829   for( unsigned int row = 0; row < rowCount; ++row )
830   {
831     for( unsigned int column = 0; column < columnCount; ++column )
832     {
833       // no actor means free cell
834       if( !(mCellData[ row ][ column ].actor) )
835       {
836         // put the actor in the cell
837         CellData data;
838         data.actor = child;
839         data.position.columnIndex = column;
840         data.position.rowIndex = row;
841         mCellData[ row ][ column ] = data;
842         RelayoutRequest();
843         // don' continue
844         return;
845       }
846     }
847   }
848   // still here, no room for the poor child so increase the array. Need a new row
849   ResizeContainers( rowCount + 1, columnCount );
850   // put the actor to the first cell of the new row
851   CellData data;
852   data.actor = child;
853   data.position.rowIndex = rowCount;
854   data.position.columnIndex = 0;
855   mCellData[ rowCount ][ 0 ] = data;
856   // finally relayout the table
857   RelayoutRequest();
858 }
859
860 void TableView::OnControlChildRemove( Actor& child )
861 {
862   // dont process if we're in the middle of bigger operation like delete row, column or resize
863   if( !mLayoutingChild )
864   {
865     // relayout the table only if instances were found
866     if( RemoveAllInstances( child ) )
867     {
868       RelayoutRequest();
869     }
870   }
871 }
872
873 TableView::TableView( unsigned int initialRows, unsigned int initialColumns )
874 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
875   mCellData( initialRows, initialColumns ),
876   mLayoutingChild( false )
877 {
878   SetKeyboardNavigationSupport( true );
879   ResizeContainers( initialRows, initialColumns );
880 }
881
882 void TableView::OnInitialize()
883 {
884   // Make self as keyboard focusable and focus group
885   Actor self = Self();
886   self.SetKeyboardFocusable(true);
887   SetAsKeyboardFocusGroup(true);
888 }
889
890 void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
891 {
892   std::vector<CellData> ignored;
893   ResizeContainers( rows, columns, ignored );
894 }
895
896 void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& removed )
897 {
898   mCellData.Resize( rows, columns, removed );
899   // we dont care if these go smaller, data will be regenerated or is not needed anymore
900   mRelativeSizes.Resize( rows, columns );
901   mFixedHeights.resize( rows );
902   mRelativeHeights.resize( rows );
903   mFixedWidths.resize( columns );
904   mRelativeWidths.resize( columns );
905 }
906
907 void TableView::RemoveAndGetLostActors( const std::vector<CellData>& lost, std::vector<Actor>& removed,
908                                         unsigned int rowsRemoved, unsigned int columnsRemoved )
909 {
910   // iterate through all lost cells
911   std::vector< CellData >::const_iterator iter = lost.begin();
912   for( ; iter != lost.end(); ++iter )
913   {
914     // if it is a valid actor
915     if( (*iter).actor )
916     {
917       // is this actor still somewhere else in the table
918       Toolkit::TableView::CellPosition position;
919       if( FindChildPosition( (*iter).actor, position ) )
920       {
921         // it must be spanning multiple cells, position contains the top left most one
922         // check if position is left of the removed location
923         if( position.columnIndex < (*iter).position.columnIndex )
924         {
925           // if column span is greater than 1
926           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan > 1 )
927           {
928             // decrease column span
929             mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan -= columnsRemoved;
930           }
931         }
932         // check if position is left of the removed location
933         if( position.rowIndex < (*iter).position.rowIndex )
934         {
935           // if row span is greater than 1
936           if( mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan > 1 )
937           {
938             // decrease row span
939             mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan -= rowsRemoved;
940           }
941         }
942       }
943       else
944       {
945         // this actor is gone for good
946         // add actor to removed container
947         removed.push_back( (*iter).actor );
948         // we dont want the child actor anymore
949         Self().Remove( (*iter).actor );
950       }
951     }
952   }
953 }
954
955 bool TableView::RemoveAllInstances( Actor child )
956 {
957   bool found = false;
958   // walk through the layout data
959   const unsigned int rowCount = mCellData.GetRows();
960   const unsigned int columnCount = mCellData.GetColumns();
961   for( unsigned int row = 0; row < rowCount; ++row )
962   {
963     for( unsigned int column = 0; column < columnCount; ++column )
964     {
965       if( mCellData[ row ][ column ].actor == child )
966       {
967         // clear the cell, NOTE that the cell might be spanning multiple cells
968         mCellData[ row ][ column ] = CellData();
969         found = true;
970       }
971     }
972   }
973   return found;
974 }
975
976 void TableView::UpdateRelativeSizes( float& fixedHeightsTotal, float& fixedWidthsTotal )
977 {
978   // 1. check all the fixed heights and widths to know how much size they take in total
979   // as well as the relative heights and widths to know how much is left for the 'fill' cells
980   unsigned int fixedRowCount = 0;
981   unsigned int relativeRowCount = 0;
982   float relativeHeightsTotal = 0.0f;
983   const unsigned int rowCount = mCellData.GetRows();
984   for( unsigned int row = 0; row < rowCount; ++row )
985   {
986     if( mFixedHeights[ row ] > 0.0f )
987     {
988       ++fixedRowCount;
989       fixedHeightsTotal += mFixedHeights[ row ];
990     }
991     if( mRelativeHeights[ row ] > 0.0f )
992     {
993       ++relativeRowCount;
994       relativeHeightsTotal += mRelativeHeights[ row ];
995     }
996   }
997   unsigned int fixedColumnCount = 0;
998   unsigned int relativeColumnCount = 0;
999   const unsigned int columnCount = mCellData.GetColumns();
1000   float relativeWidthsTotal = 0.0f;
1001   for( unsigned int column = 0; column < columnCount; ++column )
1002   {
1003     if( mFixedWidths[ column ] > 0.0f )
1004     {
1005       ++fixedColumnCount;
1006       fixedWidthsTotal += mFixedWidths[ column ];
1007     }
1008     if( mRelativeWidths[ column ] > 0.0f )
1009     {
1010       ++relativeColumnCount;
1011       relativeWidthsTotal += mRelativeWidths[ column ];
1012     }
1013   }
1014
1015   // 2. cap the relative width and height totals to 100%
1016   if( relativeHeightsTotal > 1.0f )
1017   {
1018     relativeHeightsTotal = 1.0f;
1019   }
1020   if( relativeWidthsTotal > 1.0f )
1021   {
1022     relativeWidthsTotal = 1.0f;
1023   }
1024
1025   // 3. create a table of relative sizes so we can lookup for cells that span multiple rows & colums
1026   const float fillRowCount( rowCount - relativeRowCount - fixedRowCount );
1027   const float fillColumnCount( columnCount - relativeColumnCount - fixedColumnCount );
1028
1029   // walk through the data containers
1030   for( unsigned int row = 0; row < rowCount; ++row )
1031   {
1032     float relativeHeight = 0.0f;
1033     // if we have a fixed height, relative height is 0
1034     if( mFixedHeights[ row ] > 0.0f )
1035     {
1036       relativeHeight = 0.0f;
1037     }
1038     // else if we're given a specific row height %, use that
1039     else if( mRelativeHeights[ row ] > 0.0f )
1040     {
1041       relativeHeight = mRelativeHeights[ row ];
1042     }
1043     // else if there are fill rows
1044     else if( fillRowCount > 0 )
1045     {
1046       // this is a 'fill' row. it gets the remainder of the 100% divided evenly between 'fill' rows
1047       relativeHeight = (1.0f - relativeHeightsTotal ) / fillRowCount;
1048     }
1049     for( unsigned int column = 0; column < columnCount; ++column )
1050     {
1051       float relativeWidth = 0.0f;
1052       // if we have a fixed width, relative width is 0
1053       if( mFixedWidths[ column ] > 0.0f )
1054       {
1055         relativeWidth = 0.0f;
1056       }
1057       // else if we're given a specific column width %, use that
1058       else if( mRelativeWidths[ column ] > 0.0f )
1059       {
1060         relativeWidth = mRelativeWidths[ column ];
1061       }
1062       // else if there are fill columns
1063       else if( fillColumnCount > 0 )
1064       {
1065         // this is a 'fill' column. it gets the remainder of the 100% divided evenly between 'fill' columns
1066         relativeWidth = (1.0f - relativeWidthsTotal ) / fillColumnCount;
1067       }
1068       // store the value
1069       mRelativeSizes[ row ][ column ] = Size( relativeWidth, relativeHeight );
1070     }
1071   }
1072 }
1073
1074 void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
1075                                          void(TableView::*funcFixed)(unsigned int, float),
1076                                          void(TableView::*funcRelative)(unsigned int, float),
1077                                          const Property::Value& value )
1078 {
1079   if( Property::MAP == value.GetType() )
1080   {
1081     Property::Map map = value.Get<Property::Map>();
1082     unsigned int rowIndex(0);
1083     for ( unsigned int i = 0, count = map.Count(); i < count; ++i )
1084     {
1085       Property::Value& item = map.GetValue(i);
1086
1087       if( std::istringstream(map.GetKey(i)) >> rowIndex  // the key is a number
1088           && Property::MAP == item.GetType())
1089       {
1090         if( item.HasKey( "policy" ) && item.HasKey( "value" ) )
1091         {
1092           Toolkit::TableView::LayoutPolicy policy = Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( item.GetValue("policy").Get<std::string>().c_str(), LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT );
1093           if( policy == Toolkit::TableView::Fixed )
1094           {
1095             (tableViewImpl.*funcFixed)( rowIndex, item.GetValue("value").Get<float>() );
1096           }
1097           else if( policy == Toolkit::TableView::Relative )
1098           {
1099             (tableViewImpl.*funcRelative)( rowIndex, item.GetValue("value").Get<float>() );
1100           }
1101         }
1102       }
1103     }
1104   }
1105 }
1106
1107 Property::Value TableView::GetRowHeightsPropertyValue()
1108 {
1109   Property::Map map;
1110   GetMapPropertyValue( mFixedHeights, mRelativeHeights, map);
1111   return Property::Value(map);
1112 }
1113
1114 Property::Value TableView::GetColumnWidthsPropertyValue()
1115 {
1116   Property::Map map;
1117   GetMapPropertyValue( mFixedWidths, mRelativeWidths, map);
1118   return Property::Value(map);
1119 }
1120
1121 void TableView::GetMapPropertyValue( const std::vector<float>& fixedSize, const std::vector<float>& relativeSize, Property::Map& map )
1122 {
1123   std::string fixedPolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::Fixed, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
1124   std::string relativePolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::Relative, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
1125
1126   size_t count = fixedSize.size();
1127   for( size_t index = 0; index < count; index++ )
1128   {
1129     if( ! EqualsZero( fixedSize[index] ) )
1130     {
1131       Property::Map item;
1132       item[ "policy" ] = fixedPolicy;
1133       item[ "value" ] = fixedSize[index];
1134
1135       map[ static_cast<std::ostringstream*>( &(std::ostringstream() << index ) )->str() ] = item;
1136     }
1137     else if( ! EqualsZero( relativeSize[index] ) )
1138     {
1139       Property::Map item;
1140       item[ "policy" ] = relativePolicy;
1141       item[ "value" ] = relativeSize[index];
1142
1143       map[ static_cast<std::ostringstream*>( &(std::ostringstream() << index ) )->str() ] = item;
1144     }
1145   }
1146 }
1147
1148 TableView::~TableView()
1149 {
1150   // nothing to do
1151 }
1152
1153 Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1154 {
1155   Actor nextFocusableActor;
1156
1157   if ( !currentFocusedActor )
1158   {
1159     // Nothing is currently focused, so the child in the first cell should be focused.
1160     nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1161   }
1162   else
1163   {
1164     Toolkit::TableView::CellPosition position;
1165     if( FindChildPosition( currentFocusedActor, position ) )
1166     {
1167       // The current focused actor is a child of TableView
1168       bool focusLost = false;
1169       int currentRow = position.rowIndex;
1170       int currentColumn = position.columnIndex;
1171       int numberOfColumns = GetColumns();
1172       int numberOfRows = GetRows();
1173
1174       switch ( direction )
1175       {
1176         case Toolkit::Control::Left:
1177         {
1178           if(--currentColumn < 0)
1179           {
1180             currentColumn = numberOfColumns - 1;
1181             if(--currentRow < 0)
1182             {
1183               currentRow = loopEnabled ? numberOfRows - 1 : 0;
1184               focusLost = (currentRow == 0);
1185             }
1186           }
1187           break;
1188         }
1189         case Toolkit::Control::Right:
1190         {
1191           if(++currentColumn > numberOfColumns - 1)
1192           {
1193             currentColumn = 0;
1194             if(++currentRow > numberOfRows - 1)
1195             {
1196               currentRow = loopEnabled ? 0 : numberOfRows - 1;
1197               focusLost = (currentRow == numberOfRows - 1);
1198             }
1199           }
1200           break;
1201         }
1202         case Toolkit::Control::Up:
1203         {
1204           if(--currentRow < 0)
1205           {
1206             currentRow = loopEnabled ? numberOfRows - 1 : 0;
1207             focusLost = (currentRow == 0);
1208           }
1209           break;
1210         }
1211         case Toolkit::Control::Down:
1212
1213         {
1214           if(++currentRow > numberOfRows - 1)
1215           {
1216             currentRow = loopEnabled ? 0 : numberOfRows - 1;
1217             focusLost = (currentRow == numberOfRows - 1);
1218           }
1219           break;
1220         }
1221       }
1222
1223       // Move the focus if we haven't lost it.
1224       if(!focusLost)
1225       {
1226         nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1227       }
1228     }
1229     else
1230     {
1231       // The current focused actor is not within table view, so the child in the first cell should be focused.
1232       nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1233     }
1234   }
1235
1236   return nextFocusableActor;
1237 }
1238
1239 } // namespace Internal
1240
1241 } // namespace Toolkit
1242
1243 } // namespace Dali