2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/controls/table-view/table-view-impl.h>
23 #include <dali/public-api/object/ref-object.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/scripting/scripting.h>
26 #include <dali/integration-api/debug.h>
32 const float DEFAULT_CONSTRAINT_DURATION = 0.0f;
35 * sets a child property relative to parents size and applies a unit based padding before the relative calculation.
36 * @param[in] scale of parent minus padding between 0 and 1
37 * @param[in] padding in world coordinate units
38 * @param[in] fixed part in world coordinate units
39 * @param[in] size of the parent
40 * @return The relative size with padding.
42 Vector2 RelativeToSize( const Vector2& scale, const Vector2& padding, const Vector2& fixed, const Vector2& parentSize)
44 return fixed + ( parentSize - padding ) * scale;
47 #if defined(DEBUG_ENABLED)
48 // debugging support, very useful when new features are added or bugs are hunted down
49 // currently not called from code so compiler will optimize these away, kept here for future debugging
51 #define TABLEVIEW_TAG "DALI Toolkit::TableView "
52 #define TV_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
54 void PrintArray( Array2d<Dali::Toolkit::Internal::TableView::CellData>& array )
56 TV_LOG( "Array2d<CellData> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
58 for( unsigned int i = 0; i < array.GetRows(); ++i )
60 for( unsigned int j = 0; j < array.GetColumns(); ++j )
62 Dali::Toolkit::Internal::TableView::CellData data = array[i][j];
68 TV_LOG("Array[%d,%d]=%c %d,%d,%d,%d ", i, j, actor,
69 data.position.rowIndex, data.position.columnIndex,
70 data.position.rowSpan, data.position.columnSpan );
76 // debugging support, very useful when new features are added or bugs are hunted down
77 // currently not called from code so compiler will optimize these away, kept here for future debugging
78 void PrintArray( Array2d<Size>& array )
80 TV_LOG( "Array2d<Size> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
82 for( unsigned int i = 0; i < array.GetRows(); ++i )
84 for( unsigned int j = 0; j < array.GetColumns(); ++j )
86 TV_LOG( "Array[%d,%d]=%.2f,%.2f ", i, j, array[i][j].width, array[i][j].height );
91 // debugging support, very useful when new features are added or bugs are hunted down
92 // currently not called from code so compiler will optimize these away, kept here for future debugging
93 void PrintVector( std::vector<float>& array )
95 TV_LOG( "vector, size [%d]\n", array.size() );
97 for( unsigned int i = 0; i < array.size(); ++i )
99 TV_LOG( "vector[%d]=%.2f ", i, array[i] );
103 #endif // defined(DEBUG_ENABLED)
113 const Property::Index TableView::PROPERTY_ROWS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX );
114 const Property::Index TableView::PROPERTY_COLUMNS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 1 );
115 const Property::Index TableView::PROPERTY_CELL_PADDING( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 2 );
116 const Property::Index TableView::PROPERTY_LAYOUT_ROWS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 3 );
117 const Property::Index TableView::PROPERTY_LAYOUT_COLUMNS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 4 );
125 const Scripting::StringEnum< Toolkit::TableView::LayoutPolicy > LAYOUT_POLICY_STRING_TABLE[] =
127 { "fixed", Toolkit::TableView::Fixed },
128 { "relative", Toolkit::TableView::Relative },
129 { "fill", Toolkit::TableView::Fill }
132 const unsigned int LAYOUT_POLICY_STRING_TABLE_COUNT = sizeof(LAYOUT_POLICY_STRING_TABLE) / sizeof( LAYOUT_POLICY_STRING_TABLE[0] );
137 return Toolkit::TableView::New(0, 0);
139 TypeRegistration mType( typeid(Toolkit::TableView), typeid(Toolkit::Control), Create );
141 PropertyRegistration property1( mType, "rows", Toolkit::TableView::PROPERTY_ROWS, Property::UNSIGNED_INTEGER, &TableView::SetProperty, &TableView::GetProperty );
142 PropertyRegistration property2( mType, "columns", Toolkit::TableView::PROPERTY_COLUMNS, Property::UNSIGNED_INTEGER, &TableView::SetProperty, &TableView::GetProperty );
143 PropertyRegistration property3( mType, "cell-padding", Toolkit::TableView::PROPERTY_CELL_PADDING, Property::VECTOR2, &TableView::SetProperty, &TableView::GetProperty );
144 PropertyRegistration property4( mType, "layout-rows", Toolkit::TableView::PROPERTY_LAYOUT_ROWS, Property::MAP, &TableView::SetProperty, &TableView::GetProperty );
145 PropertyRegistration property5( mType, "layout-columns", Toolkit::TableView::PROPERTY_LAYOUT_COLUMNS, Property::MAP, &TableView::SetProperty, &TableView::GetProperty );
149 Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns )
151 // Create the implementation, temporarily owned by this handle on stack
152 IntrusivePtr< TableView > impl = new TableView( initialRows, initialColumns );
154 // Pass ownership to CustomActor handle
155 Toolkit::TableView handle( *impl );
157 // Second-phase init of the implementation
158 // This can only be done after the CustomActor connection has been made...
164 bool TableView::AddChild( Actor child, Toolkit::TableView::CellPosition position )
166 // check that the child is valid
167 DALI_ASSERT_ALWAYS( child );
169 // if child is already parented, we adopt it
170 if( child.GetParent() )
172 child.GetParent().Remove( child );
174 // check if we need to expand our data array
175 if( position.rowIndex >= mCellData.GetRows() )
177 // only adding new rows
178 ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
180 if( position.columnIndex >= mCellData.GetColumns() )
182 // only adding new columns
183 ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
185 // check if there already is something in this cell
186 if( mCellData[ position.rowIndex ][ position.columnIndex ].actor )
188 return false; // cannot share a cell, it would complicate all logic and not bring much benefit
190 RelayoutingLock lock( *this );
194 // put the actor to the main cell
197 data.position = position;
198 mCellData[ position.rowIndex ][ position.columnIndex ] = data;
199 // if child spans multiple rows of columns
200 bool spanned = false;
201 if( position.rowSpan > 1 )
203 // span might go outside table
204 if( position.rowIndex + position.rowSpan > mCellData.GetRows() )
206 // increase table size for the full span, only increasing rows
207 ResizeContainers( position.rowIndex + position.rowSpan, mCellData.GetColumns() );
211 if( position.columnSpan > 1 )
213 // span might go outside table
214 if( position.columnIndex + position.columnSpan > mCellData.GetColumns() )
216 // increase table size for the full span, only increasing columns
217 ResizeContainers( mCellData.GetRows(), position.columnIndex + position.columnSpan );
221 // if it spanned multiple rows, put the cellinfo in all of those
224 for( unsigned int row = position.rowIndex; row < ( position.rowIndex + position.rowSpan ); ++row )
226 // store same information to all cells, this way we can identify
227 // if a cell is the prime location of an actor or a spanned one
228 for( unsigned int column = position.columnIndex; column < ( position.columnIndex + position.columnSpan ); ++column )
230 // store same information to all cells, this way we can identify
231 // if a cell is the prime location of an actor or a spanned one
232 mCellData[ row ][ column ] = data;
236 // relayout the whole table
238 return true; // addition successful
241 Actor TableView::GetChildAt( Toolkit::TableView::CellPosition position )
243 // check if we have this row and column in the table
244 if( ( position.columnIndex >= mCellData.GetColumns() )||
245 ( position.rowIndex >= mCellData.GetRows() ) )
247 // return an empty handle
250 // return the child handle
251 return mCellData[ position.rowIndex ][ position.columnIndex ].actor;
254 Actor TableView::RemoveChildAt( Toolkit::TableView::CellPosition position )
256 // get the child handle
257 Actor child = GetChildAt( position );
258 // if no real actor there, nothing else to be done
261 RelayoutingLock lock( *this );
262 // Remove the child, this will trigger a call to OnControlChildRemove
263 Self().Remove( child );
265 // relayout the table only if instances were found
266 if( RemoveAllInstances( child ) )
271 // return the child back to caller
275 bool TableView::FindChildPosition( Actor child, Toolkit::TableView::CellPosition& position )
277 // only find valid child actors
280 // walk through the layout data
281 const unsigned int rowCount = mCellData.GetRows();
282 const unsigned int columnCount = mCellData.GetColumns();
283 for( unsigned int row = 0; row < rowCount; ++row )
285 for( unsigned int column = 0; column < columnCount; ++column )
287 if( mCellData[ row ][ column ].actor == child )
289 position = mCellData[ row ][ column ].position;
298 void TableView::InsertRow( unsigned int rowIndex )
300 RelayoutingLock lock( *this );
301 mCellData.InsertRow( rowIndex );
302 // need to update the cellinfos for the items that moved
303 const unsigned int rowCount = mCellData.GetRows();
304 const unsigned int columnCount = mCellData.GetColumns();
305 for( unsigned int row = 0; row < rowCount; ++row )
307 for( unsigned int column = 0; column < columnCount; ++column )
309 Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
310 // if cell is spanning and above and spans to inserted row
311 if( ( position.rowSpan > 1 )&&( position.rowIndex <= rowIndex )&&
312 ( position.rowIndex + position.rowSpan > rowIndex ) )
314 // increase span by one
316 // copy cell to occupy the new column
317 mCellData[ rowIndex ][ column ] = mCellData[ row ][ column ];
319 // if below of inserted row, increase row index
320 else if( row > rowIndex )
322 // increase index by one
327 mRelativeSizes.InsertRow( rowIndex );
328 // inserting a row requires adjusting the height vectors
329 mFixedHeights.insert( mFixedHeights.begin() + rowIndex, 0 );
330 mRelativeHeights.insert( mRelativeHeights.begin() + rowIndex, 0 );
334 void TableView::DeleteRow( unsigned int rowIndex )
336 std::vector< Actor > ignored;
337 DeleteRow( rowIndex, ignored );
340 void TableView::DeleteRow( unsigned int rowIndex, std::vector<Actor>& removed )
342 RelayoutingLock lock( *this );
343 std::vector< CellData > lost;
344 mCellData.DeleteRow( rowIndex, lost );
345 // need to update the cellinfos for the items that moved
346 const unsigned int rowCount = mCellData.GetRows();
347 const unsigned int columnCount = mCellData.GetColumns();
348 for( unsigned int row = 0; row < rowCount; ++row )
350 for( unsigned int column = 0; column < columnCount; ++column )
352 Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
353 // if cell is spanning and above and spans to deleted row
354 if( ( position.rowSpan > 1 )&&( position.rowIndex <= rowIndex )&&
355 ( position.rowIndex + position.rowSpan > rowIndex ) )
357 // decrease span by one
358 if( position.rowSpan > 1 )
363 // if below of or at the inserted row, decrease row index
364 else if( row >= rowIndex )
366 // decrease index by one
367 if( position.rowIndex > 1 )
374 // 1 row removed, 0 columns
375 RemoveAndGetLostActors( lost, removed, 1u, 0u );
376 // resize the data structures
377 mRelativeSizes.DeleteRow( rowIndex );
378 // deleting a row requires adjusting the height vectors
379 mFixedHeights.erase( mFixedHeights.begin() + rowIndex );
380 mRelativeHeights.erase( mRelativeHeights.begin() + rowIndex );
384 void TableView::InsertColumn( unsigned int columnIndex )
386 RelayoutingLock lock( *this );
387 mCellData.InsertColumn( columnIndex );
388 // need to update the cellinfos for the items that moved
389 const unsigned int rowCount = mCellData.GetRows();
390 const unsigned int columnCount = mCellData.GetColumns();
391 for( unsigned int row = 0; row < rowCount; ++row )
393 for( unsigned int column = 0; column < columnCount; ++column )
395 Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
396 // if cell is spanning and left side and spans to inserted column
397 if( ( position.columnSpan > 1 )&&( position.columnIndex <= columnIndex )&&
398 ( position.columnIndex + position.columnSpan > columnIndex ) )
400 // increase span by one
401 position.columnSpan++;
402 // copy cell to occupy the new column
403 mCellData[ row ][ columnIndex ] = mCellData[ row ][ column ];
405 // if on the right side of inserted column, increase column index
406 else if( column > columnIndex )
408 // increase index by one
409 position.columnIndex++;
413 // relative sizes gets recalculated on Relayout
414 mRelativeSizes.InsertColumn( columnIndex );
415 // inserting a column requires adjusting the width vectors
416 mFixedWidths.insert( mFixedWidths.begin() + columnIndex, 0 );
417 mRelativeWidths.insert( mRelativeWidths.begin() + columnIndex, 0 );
421 void TableView::DeleteColumn( unsigned int columnIndex )
423 std::vector< Actor > ignored;
424 DeleteColumn( columnIndex, ignored );
427 void TableView::DeleteColumn( unsigned int columnIndex, std::vector<Actor>& removed )
429 RelayoutingLock lock( *this );
430 std::vector< CellData > lost;
431 mCellData.DeleteColumn( columnIndex, lost );
432 // need to update the cellinfos for the items that moved
433 const unsigned int rowCount = mCellData.GetRows();
434 const unsigned int columnCount = mCellData.GetColumns();
435 for( unsigned int row = 0; row < rowCount; ++row )
437 for( unsigned int column = 0; column < columnCount; ++column )
439 Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
440 // if cell is spanning and left side and spans to inserted column
441 if( ( position.columnSpan > 1 )&&( position.columnIndex <= columnIndex )&&
442 ( position.columnIndex + position.columnSpan > columnIndex ) )
444 // decrease span by one
445 if( position.columnSpan > 1 )
447 position.columnSpan--;
450 // if on the right side of or at the inserted column, decrease column index
451 else if( column >= columnIndex )
453 // decrease index by one
454 if( position.columnIndex > 0 )
456 position.columnIndex--;
461 // 0 rows, 1 column removed
462 RemoveAndGetLostActors( lost, removed, 0u, 1u );
463 // resize the data structures
464 mRelativeSizes.DeleteColumn( columnIndex );
465 // deleting a column requires adjusting the width vectors
466 mFixedWidths.erase( mFixedWidths.begin() + columnIndex );
467 mRelativeWidths.erase( mRelativeWidths.begin() + columnIndex );
472 void TableView::Resize( unsigned int rows, unsigned int columns )
474 std::vector< Actor > ignored;
475 Resize( rows, columns, ignored );
478 void TableView::Resize( unsigned int rows, unsigned int columns, std::vector<Actor>& removed )
480 RelayoutingLock lock( *this );
481 unsigned int oldRows = GetRows();
482 unsigned int oldColumns = GetColumns();
484 std::vector< CellData > lost;
485 ResizeContainers( rows, columns, lost );
486 // calculate if we lost rows or columns
487 unsigned int rowsRemoved = 0;
488 unsigned int newRows = GetRows();
489 if( oldRows < newRows )
491 rowsRemoved = newRows - oldRows;
493 unsigned int columnsRemoved = 0;
494 unsigned int newColumns = GetColumns();
495 if( oldColumns < newColumns )
497 rowsRemoved = newColumns - oldColumns;
499 RemoveAndGetLostActors( lost, removed, rowsRemoved, columnsRemoved );
500 // finally relayout once all actors are removed
504 void TableView::SetCellPadding( Size padding )
506 // if padding really changed
507 if( padding != mPadding )
515 Size TableView::GetCellPadding()
520 void TableView::SetFixedHeight( unsigned int rowIndex, float height )
522 DALI_ASSERT_ALWAYS( rowIndex < mFixedHeights.size() );
523 // add the fixed height to the array of fixed heights
524 mFixedHeights[ rowIndex ] = height;
525 // remove the relative height of the same row
526 mRelativeHeights[ rowIndex ] = 0.f;
527 // relayout all cells, no lock needed as nothing added or removed
531 float TableView::GetFixedHeight( unsigned int rowIndex ) const
533 DALI_ASSERT_ALWAYS( rowIndex < mFixedHeights.size() );
535 return mFixedHeights[ rowIndex ];
538 void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage )
540 DALI_ASSERT_ALWAYS( rowIndex < mRelativeHeights.size() );
541 // add the relative height to the array of relative heights
542 mRelativeHeights[ rowIndex ] = heightPercentage;
543 // remove the fixed height of the same row
544 mFixedHeights[ rowIndex ] = 0.f;
545 // relayout all cells, no lock needed as nothing added or removed
549 float TableView::GetRelativeHeight( unsigned int rowIndex ) const
551 DALI_ASSERT_ALWAYS( rowIndex < mRelativeHeights.size() );
553 return mRelativeHeights[ rowIndex ];
556 void TableView::SetFixedWidth( unsigned int columnIndex, float width )
558 DALI_ASSERT_ALWAYS( columnIndex < mFixedWidths.size() );
559 // add the fixed width to the array of fixed column widths
560 mFixedWidths[ columnIndex ] = width;
561 // remove the relative width of the same column
562 mRelativeWidths[ columnIndex ] = 0.f;
563 // relayout all cells, no lock needed as nothing added or removed
567 float TableView::GetFixedWidth( unsigned int columnIndex ) const
569 DALI_ASSERT_ALWAYS( columnIndex < mFixedWidths.size() );
571 return mFixedWidths[ columnIndex ];
574 void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentage )
576 DALI_ASSERT_ALWAYS( columnIndex < mRelativeWidths.size() );
577 // add the relative widths to the array of relative widths
578 mRelativeWidths[ columnIndex ] = widthPercentage;
579 // remove the fixed width of the same column
580 mFixedWidths[ columnIndex ] = 0.f;
581 // relayout all cells, no lock needed as nothing added or removed
585 float TableView::GetRelativeWidth( unsigned int columnIndex ) const
587 DALI_ASSERT_ALWAYS( columnIndex < mRelativeWidths.size() );
589 return mRelativeWidths[ columnIndex ];
592 void TableView::OnRelayout( const Vector2& size, ActorSizeContainer& container )
594 float fixedHeightsTotal = 0.0f;
595 float fixedWidthsTotal = 0.0f;
597 // 1. update the relative sizes and calculate total fixed height and width
598 UpdateRelativeSizes( fixedHeightsTotal, fixedWidthsTotal );
600 // 2. go through the layout data and create constraints
601 float cumulatedFixedHeight = 0.0f;
602 float cumulatedRelativeHeight = 0.0f;
605 const unsigned int rowCount = mCellData.GetRows();
606 const unsigned int columnCount = mCellData.GetColumns();
607 // float versions of the count + 1 to keep precision
608 const float maxRowPlusOne( rowCount + 1 );
609 const float maxColumnPlusOne( columnCount + 1 );
610 for( unsigned int row = 0; row < rowCount; ++row )
612 // reset widths at the start of each row
613 float cumulatedFixedWidth = 0.0f;
614 float cumulatedRelativeWidth = 0.0f;
615 for( unsigned int column = 0; column < columnCount; ++column )
617 // check if this cell has an actor
618 Actor actor = mCellData[ row ][ column ].actor;
619 const Toolkit::TableView::CellPosition position = mCellData[ row ][ column ].position;
620 // if there is an actor and this is the main cell of the actor
621 // an actor can be in multiple cells if its row or columnspan is more than 1
622 // we however must only lay out each actor only once
623 if( ( actor )&&( position.rowIndex == row )&&( position.columnIndex == column ) )
625 // anchor actor correctly
626 actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
627 actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
628 // remove old constraints
629 actor.RemoveConstraints();
632 // get the row and column indices
633 float rowPos( position.rowIndex );
634 float colPos( position.columnIndex );
635 // constrain the actor position to be relative to the width and height of table
636 // minus the padding of course (padding is all around cells)
637 Vector2 relativePosition( cumulatedRelativeWidth, cumulatedRelativeHeight );
638 // fixed height rows and fixed width cells are considered as padding so
639 // they are removed from the total size for relative
640 // for position only consider cumulated fixed rows and columns from top and left
641 Vector2 positionPadding( maxColumnPlusOne * mPadding.width + fixedWidthsTotal,
642 maxRowPlusOne * mPadding.height + fixedHeightsTotal );
643 Vector2 fixedPosition( ( colPos + 1.0f ) * mPadding.width + cumulatedFixedWidth,
644 ( rowPos + 1.0f ) * mPadding.height + cumulatedFixedHeight );
646 Vector3 actorPosition( RelativeToSize( relativePosition, positionPadding, fixedPosition, size ) );
647 actor.SetPosition( actorPosition );
650 // constrain the actor size to be relative to the size of table
651 // get the relative size for this cell
652 Vector2 relativeSize( mRelativeSizes[ row ][ column ] );
653 Vector2 fixedSize( mFixedWidths[ column ], mFixedHeights[ row ] );
654 // if we span multiple cells, need to sum them all up, both fixed and relative parts
655 if( position.rowSpan > 1 )
657 for( unsigned int i = 1; i < position.rowSpan; ++i )
659 // accumulate the height only
660 relativeSize.height += mRelativeSizes[ row + i ][ column ].height;
661 fixedSize.height += mFixedHeights[ row + i ];
664 if( position.columnSpan > 1 )
666 for( unsigned int i = 1; i < position.columnSpan; ++i )
668 // accumulate the width only
669 relativeSize.width += mRelativeSizes[ row ][ column + i ].width;
670 fixedSize.width += mFixedWidths[ column + i ];
673 // minus the padding from size (padding is all around cells)
674 // if item spans multiple columns or rows then less padding is added (default span is 1)
675 // fixed height rows and fixed width cells are considered as padding so they are removed
676 // from the total available size for relative cells
677 Vector2 sizePadding( maxColumnPlusOne * mPadding.width + fixedWidthsTotal,
678 maxRowPlusOne * mPadding.height + fixedHeightsTotal );
679 // and added to the fixed size multiplied by the span of rows and columns
680 fixedSize.width += ( position.columnSpan - 1.0f ) * mPadding.width;
681 fixedSize.height += ( position.rowSpan - 1.0f ) * mPadding.height;
683 Vector2 actorSize( RelativeToSize( relativeSize, sizePadding, fixedSize, size ) );
684 actor.SetSize(actorSize.x, actorSize.y);
687 Relayout ( actor, actorSize, container );
689 // for position we need to keep track of current fixed width and relative width
690 // increase for next column
691 cumulatedFixedWidth += mFixedWidths[ column ];
692 cumulatedRelativeWidth += mRelativeSizes[ row ][ column ].width;
694 // for position we need to keep track of current fixed height and relative height
695 // increase for next row
696 cumulatedFixedHeight += mFixedHeights[ row ];
697 cumulatedRelativeHeight += mRelativeSizes[ row ][ 0 ].height; // all columns share same height
701 unsigned int TableView::GetRows()
703 return mCellData.GetRows();
706 unsigned int TableView::GetColumns()
708 return mCellData.GetColumns();
711 void TableView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
713 Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
717 TableView& tableViewImpl( GetImpl( tableView ) );
720 case Toolkit::TableView::PROPERTY_ROWS:
722 if( value.Get<unsigned int>() != tableViewImpl.GetRows() )
724 tableViewImpl.Resize( value.Get<unsigned int>(), tableViewImpl.GetColumns() );
728 case Toolkit::TableView::PROPERTY_COLUMNS:
730 if( value.Get<unsigned int>() != tableViewImpl.GetColumns() )
732 tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<unsigned int>() );
736 case Toolkit::TableView::PROPERTY_CELL_PADDING:
738 tableViewImpl.SetCellPadding( value.Get<Vector2>() );
741 case Toolkit::TableView::PROPERTY_LAYOUT_ROWS:
743 SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, value );
746 case Toolkit::TableView::PROPERTY_LAYOUT_COLUMNS:
748 SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, value );
755 Property::Value TableView::GetProperty( BaseObject* object, Property::Index index )
757 Property::Value value;
759 Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
763 TableView& tableViewImpl( GetImpl( tableView ) );
766 case Toolkit::TableView::PROPERTY_ROWS:
768 value = tableViewImpl.GetRows();
771 case Toolkit::TableView::PROPERTY_COLUMNS:
773 value = tableViewImpl.GetColumns();
776 case Toolkit::TableView::PROPERTY_CELL_PADDING:
778 value = tableViewImpl.GetCellPadding();
781 case Toolkit::TableView::PROPERTY_LAYOUT_ROWS:
783 value = tableViewImpl.GetRowHeightsPropertyValue();
786 case Toolkit::TableView::PROPERTY_LAYOUT_COLUMNS:
788 value = tableViewImpl.GetColumnWidthsPropertyValue();
797 void TableView::OnControlChildAdd( Actor& child )
799 if( mLayoutingChild )
801 // we're in the middle of laying out children so no point doing anything here
805 Toolkit::TableView::CellPosition cellPosition;
806 if( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
808 cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
810 if( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
812 cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
814 if( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) != Property::INVALID_INDEX )
816 Vector2 indices = child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) ).Get<Vector2 >();
817 cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
818 cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
820 AddChild( child, cellPosition );
825 // check if we're already laying out this child somewhere on the table
826 // walk through the layout data
827 const unsigned int rowCount = mCellData.GetRows();
828 const unsigned int columnCount = mCellData.GetColumns();
829 // child not yet laid out, find the first free slot
830 for( unsigned int row = 0; row < rowCount; ++row )
832 for( unsigned int column = 0; column < columnCount; ++column )
834 // no actor means free cell
835 if( !(mCellData[ row ][ column ].actor) )
837 // put the actor in the cell
840 data.position.columnIndex = column;
841 data.position.rowIndex = row;
842 mCellData[ row ][ column ] = data;
849 // still here, no room for the poor child so increase the array. Need a new row
850 ResizeContainers( rowCount + 1, columnCount );
851 // put the actor to the first cell of the new row
854 data.position.rowIndex = rowCount;
855 data.position.columnIndex = 0;
856 mCellData[ rowCount ][ 0 ] = data;
857 // finally relayout the table
861 void TableView::OnControlChildRemove( Actor& child )
863 // dont process if we're in the middle of bigger operation like delete row, column or resize
864 if( !mLayoutingChild )
866 // relayout the table only if instances were found
867 if( RemoveAllInstances( child ) )
874 TableView::TableView( unsigned int initialRows, unsigned int initialColumns )
875 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
876 mCellData( initialRows, initialColumns ),
877 mLayoutingChild( false )
879 SetKeyboardNavigationSupport( true );
880 ResizeContainers( initialRows, initialColumns );
883 void TableView::OnInitialize()
885 // Make self as keyboard focusable and focus group
887 self.SetKeyboardFocusable(true);
888 SetAsKeyboardFocusGroup(true);
891 void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
893 std::vector<CellData> ignored;
894 ResizeContainers( rows, columns, ignored );
897 void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& removed )
899 mCellData.Resize( rows, columns, removed );
900 // we dont care if these go smaller, data will be regenerated or is not needed anymore
901 mRelativeSizes.Resize( rows, columns );
902 mFixedHeights.resize( rows );
903 mRelativeHeights.resize( rows );
904 mFixedWidths.resize( columns );
905 mRelativeWidths.resize( columns );
908 void TableView::RemoveAndGetLostActors( const std::vector<CellData>& lost, std::vector<Actor>& removed,
909 unsigned int rowsRemoved, unsigned int columnsRemoved )
911 // iterate through all lost cells
912 std::vector< CellData >::const_iterator iter = lost.begin();
913 for( ; iter != lost.end(); ++iter )
915 // if it is a valid actor
918 // is this actor still somewhere else in the table
919 Toolkit::TableView::CellPosition position;
920 if( FindChildPosition( (*iter).actor, position ) )
922 // it must be spanning multiple cells, position contains the top left most one
923 // check if position is left of the removed location
924 if( position.columnIndex < (*iter).position.columnIndex )
926 // if column span is greater than 1
927 if( mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan > 1 )
929 // decrease column span
930 mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan -= columnsRemoved;
933 // check if position is left of the removed location
934 if( position.rowIndex < (*iter).position.rowIndex )
936 // if row span is greater than 1
937 if( mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan > 1 )
940 mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan -= rowsRemoved;
946 // this actor is gone for good
947 // add actor to removed container
948 removed.push_back( (*iter).actor );
949 // we dont want the child actor anymore
950 Self().Remove( (*iter).actor );
956 bool TableView::RemoveAllInstances( Actor child )
959 // walk through the layout data
960 const unsigned int rowCount = mCellData.GetRows();
961 const unsigned int columnCount = mCellData.GetColumns();
962 for( unsigned int row = 0; row < rowCount; ++row )
964 for( unsigned int column = 0; column < columnCount; ++column )
966 if( mCellData[ row ][ column ].actor == child )
968 // clear the cell, NOTE that the cell might be spanning multiple cells
969 mCellData[ row ][ column ] = CellData();
977 void TableView::UpdateRelativeSizes( float& fixedHeightsTotal, float& fixedWidthsTotal )
979 // 1. check all the fixed heights and widths to know how much size they take in total
980 // as well as the relative heights and widths to know how much is left for the 'fill' cells
981 unsigned int fixedRowCount = 0;
982 unsigned int relativeRowCount = 0;
983 float relativeHeightsTotal = 0.0f;
984 const unsigned int rowCount = mCellData.GetRows();
985 for( unsigned int row = 0; row < rowCount; ++row )
987 if( mFixedHeights[ row ] > 0.0f )
990 fixedHeightsTotal += mFixedHeights[ row ];
992 if( mRelativeHeights[ row ] > 0.0f )
995 relativeHeightsTotal += mRelativeHeights[ row ];
998 unsigned int fixedColumnCount = 0;
999 unsigned int relativeColumnCount = 0;
1000 const unsigned int columnCount = mCellData.GetColumns();
1001 float relativeWidthsTotal = 0.0f;
1002 for( unsigned int column = 0; column < columnCount; ++column )
1004 if( mFixedWidths[ column ] > 0.0f )
1007 fixedWidthsTotal += mFixedWidths[ column ];
1009 if( mRelativeWidths[ column ] > 0.0f )
1011 ++relativeColumnCount;
1012 relativeWidthsTotal += mRelativeWidths[ column ];
1016 // 2. cap the relative width and height totals to 100%
1017 if( relativeHeightsTotal > 1.0f )
1019 relativeHeightsTotal = 1.0f;
1021 if( relativeWidthsTotal > 1.0f )
1023 relativeWidthsTotal = 1.0f;
1026 // 3. create a table of relative sizes so we can lookup for cells that span multiple rows & colums
1027 const float fillRowCount( rowCount - relativeRowCount - fixedRowCount );
1028 const float fillColumnCount( columnCount - relativeColumnCount - fixedColumnCount );
1030 // walk through the data containers
1031 for( unsigned int row = 0; row < rowCount; ++row )
1033 float relativeHeight = 0.0f;
1034 // if we have a fixed height, relative height is 0
1035 if( mFixedHeights[ row ] > 0.0f )
1037 relativeHeight = 0.0f;
1039 // else if we're given a specific row height %, use that
1040 else if( mRelativeHeights[ row ] > 0.0f )
1042 relativeHeight = mRelativeHeights[ row ];
1044 // else if there are fill rows
1045 else if( fillRowCount > 0 )
1047 // this is a 'fill' row. it gets the remainder of the 100% divided evenly between 'fill' rows
1048 relativeHeight = (1.0f - relativeHeightsTotal ) / fillRowCount;
1050 for( unsigned int column = 0; column < columnCount; ++column )
1052 float relativeWidth = 0.0f;
1053 // if we have a fixed width, relative width is 0
1054 if( mFixedWidths[ column ] > 0.0f )
1056 relativeWidth = 0.0f;
1058 // else if we're given a specific column width %, use that
1059 else if( mRelativeWidths[ column ] > 0.0f )
1061 relativeWidth = mRelativeWidths[ column ];
1063 // else if there are fill columns
1064 else if( fillColumnCount > 0 )
1066 // this is a 'fill' column. it gets the remainder of the 100% divided evenly between 'fill' columns
1067 relativeWidth = (1.0f - relativeWidthsTotal ) / fillColumnCount;
1070 mRelativeSizes[ row ][ column ] = Size( relativeWidth, relativeHeight );
1075 void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
1076 void(TableView::*funcFixed)(unsigned int, float),
1077 void(TableView::*funcRelative)(unsigned int, float),
1078 const Property::Value& value )
1080 if( Property::MAP == value.GetType() )
1082 Property::Map map = value.Get<Property::Map>();
1083 unsigned int rowIndex(0);
1084 for ( unsigned int i = 0, count = map.Count(); i < count; ++i )
1086 Property::Value& item = map.GetValue(i);
1088 if( std::istringstream(map.GetKey(i)) >> rowIndex // the key is a number
1089 && Property::MAP == item.GetType())
1091 if( item.HasKey( "policy" ) && item.HasKey( "value" ) )
1093 Toolkit::TableView::LayoutPolicy policy = Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( item.GetValue("policy").Get<std::string>(), LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT );
1094 if( policy == Toolkit::TableView::Fixed )
1096 (tableViewImpl.*funcFixed)( rowIndex, item.GetValue("value").Get<float>() );
1098 else if( policy == Toolkit::TableView::Relative )
1100 (tableViewImpl.*funcRelative)( rowIndex, item.GetValue("value").Get<float>() );
1108 Property::Value TableView::GetRowHeightsPropertyValue()
1111 GetMapPropertyValue( mFixedHeights, mRelativeHeights, map);
1112 return Property::Value(map);
1115 Property::Value TableView::GetColumnWidthsPropertyValue()
1118 GetMapPropertyValue( mFixedWidths, mRelativeWidths, map);
1119 return Property::Value(map);
1122 void TableView::GetMapPropertyValue( const std::vector<float>& fixedSize, const std::vector<float>& relativeSize, Property::Map& map )
1124 std::string fixedPolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::Fixed, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
1125 std::string relativePolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::Relative, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
1127 size_t count = fixedSize.size();
1128 for( size_t index = 0; index < count; index++ )
1130 if( ! EqualsZero( fixedSize[index] ) )
1133 item[ "policy" ] = fixedPolicy;
1134 item[ "value" ] = fixedSize[index];
1136 map[ static_cast<std::ostringstream*>( &(std::ostringstream() << index ) )->str() ] = item;
1138 else if( ! EqualsZero( relativeSize[index] ) )
1141 item[ "policy" ] = relativePolicy;
1142 item[ "value" ] = relativeSize[index];
1144 map[ static_cast<std::ostringstream*>( &(std::ostringstream() << index ) )->str() ] = item;
1149 TableView::~TableView()
1154 Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1156 Actor nextFocusableActor;
1158 if ( !currentFocusedActor )
1160 // Nothing is currently focused, so the child in the first cell should be focused.
1161 nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1165 Toolkit::TableView::CellPosition position;
1166 if( FindChildPosition( currentFocusedActor, position ) )
1168 // The current focused actor is a child of TableView
1169 bool focusLost = false;
1170 int currentRow = position.rowIndex;
1171 int currentColumn = position.columnIndex;
1172 int numberOfColumns = GetColumns();
1173 int numberOfRows = GetRows();
1175 switch ( direction )
1177 case Toolkit::Control::Left:
1179 if(--currentColumn < 0)
1181 currentColumn = numberOfColumns - 1;
1182 if(--currentRow < 0)
1184 currentRow = loopEnabled ? numberOfRows - 1 : 0;
1185 focusLost = (currentRow == 0);
1190 case Toolkit::Control::Right:
1192 if(++currentColumn > numberOfColumns - 1)
1195 if(++currentRow > numberOfRows - 1)
1197 currentRow = loopEnabled ? 0 : numberOfRows - 1;
1198 focusLost = (currentRow == numberOfRows - 1);
1203 case Toolkit::Control::Up:
1205 if(--currentRow < 0)
1207 currentRow = loopEnabled ? numberOfRows - 1 : 0;
1208 focusLost = (currentRow == 0);
1212 case Toolkit::Control::Down:
1214 if(++currentRow > numberOfRows - 1)
1216 currentRow = loopEnabled ? 0 : numberOfRows - 1;
1217 focusLost = (currentRow == numberOfRows - 1);
1223 // Move the focus if we haven't lost it.
1226 nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
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));
1236 return nextFocusableActor;
1239 } // namespace Internal
1241 } // namespace Toolkit