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/object/type-registry-helper.h>
26 #include <dali/public-api/scripting/scripting.h>
27 #include <dali/public-api/size-negotiation/relayout-container.h>
28 #include <dali/integration-api/debug.h>
36 * @brief Should the tableview fit around the given actor
38 * @param[in] actor The child actor to test against
39 * @param[dimension] The dimnesion to test against
41 bool FitToChild( Actor actor, Dimension dimension )
43 return actor.GetResizePolicy( dimension ) != FILL_TO_PARENT && actor.GetRelayoutSize( dimension ) > 0.0f;
46 #if defined(DEBUG_ENABLED)
47 // debugging support, very useful when new features are added or bugs are hunted down
48 // currently not called from code so compiler will optimize these away, kept here for future debugging
50 #define TABLEVIEW_TAG "DALI Toolkit::TableView "
51 #define TV_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
53 void PrintArray( Array2d<Dali::Toolkit::Internal::TableView::CellData>& array )
55 TV_LOG( "Array2d<CellData> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
57 for( unsigned int i = 0; i < array.GetRows(); ++i )
59 for( unsigned int j = 0; j < array.GetColumns(); ++j )
61 Dali::Toolkit::Internal::TableView::CellData data = array[i][j];
67 TV_LOG("Array[%d,%d]=%c %d,%d,%d,%d ", i, j, actor,
68 data.position.rowIndex, data.position.columnIndex,
69 data.position.rowSpan, data.position.columnSpan );
75 // debugging support, very useful when new features are added or bugs are hunted down
76 // currently not called from code so compiler will optimize these away, kept here for future debugging
77 void PrintArray( Array2d<Size>& array )
79 TV_LOG( "Array2d<Size> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
81 for( unsigned int i = 0; i < array.GetRows(); ++i )
83 for( unsigned int j = 0; j < array.GetColumns(); ++j )
85 TV_LOG( "Array[%d,%d]=%.2f,%.2f ", i, j, array[i][j].width, array[i][j].height );
90 // debugging support, very useful when new features are added or bugs are hunted down
91 // currently not called from code so compiler will optimize these away, kept here for future debugging
92 void PrintVector( std::vector<float>& array )
94 TV_LOG( "vector, size [%d]\n", array.size() );
96 for( unsigned int i = 0; i < array.size(); ++i )
98 TV_LOG( "vector[%d]=%.2f ", i, array[i] );
102 #endif // defined(DEBUG_ENABLED)
121 return Toolkit::TableView::New( 0, 0 );
124 // Setup properties, signals and actions using the type-registry.
125 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TableView, Toolkit::Control, Create );
127 DALI_PROPERTY_REGISTRATION( TableView, "rows", UNSIGNED_INTEGER, ROWS )
128 DALI_PROPERTY_REGISTRATION( TableView, "columns", UNSIGNED_INTEGER, COLUMNS )
129 DALI_PROPERTY_REGISTRATION( TableView, "cell-padding", VECTOR2, CELL_PADDING )
130 DALI_PROPERTY_REGISTRATION( TableView, "layout-rows", MAP, LAYOUT_ROWS )
131 DALI_PROPERTY_REGISTRATION( TableView, "layout-columns", MAP, LAYOUT_COLUMNS )
133 DALI_TYPE_REGISTRATION_END()
135 const Scripting::StringEnum< Toolkit::TableView::LayoutPolicy > LAYOUT_POLICY_STRING_TABLE[] =
137 { "fixed", Toolkit::TableView::FIXED },
138 { "relative", Toolkit::TableView::RELATIVE },
139 { "fill", Toolkit::TableView::FILL }
142 const unsigned int LAYOUT_POLICY_STRING_TABLE_COUNT = sizeof(LAYOUT_POLICY_STRING_TABLE) / sizeof( LAYOUT_POLICY_STRING_TABLE[0] );
144 } // Unnamed namespace
146 Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns )
148 // Create the implementation, temporarily owned by this handle on stack
149 IntrusivePtr< TableView > impl = new TableView( initialRows, initialColumns );
151 // Pass ownership to CustomActor handle
152 Toolkit::TableView handle( *impl );
154 // Second-phase init of the implementation
155 // This can only be done after the CustomActor connection has been made...
161 bool TableView::AddChild( Actor& child, const Toolkit::TableView::CellPosition& position )
163 // check that the child is valid
164 DALI_ASSERT_ALWAYS( child );
166 // if child is already parented, we adopt it
167 if( child.GetParent() )
169 child.GetParent().Remove( child );
172 // check if we need to expand our data array
173 if( position.rowIndex >= mCellData.GetRows() )
175 // only adding new rows
176 ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
179 if( position.columnIndex >= mCellData.GetColumns() )
181 // only adding new columns
182 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
191 RelayoutingLock lock( *this );
195 // put the actor to the main cell
196 CellData& data = mCellData[ position.rowIndex ][ position.columnIndex ];
198 data.position = position;
200 // if child spans multiple rows of columns
201 bool spanned = false;
202 if( position.rowSpan > 1 )
204 // span might go outside table
205 if( position.rowIndex + position.rowSpan > mCellData.GetRows() )
207 // increase table size for the full span, only increasing rows
208 ResizeContainers( position.rowIndex + position.rowSpan, mCellData.GetColumns() );
214 if( position.columnSpan > 1 )
216 // span might go outside table
217 if( position.columnIndex + position.columnSpan > mCellData.GetColumns() )
219 // increase table size for the full span, only increasing columns
220 ResizeContainers( mCellData.GetRows(), position.columnIndex + position.columnSpan );
226 // if it spanned multiple rows, put the cellinfo in all of those
229 for( unsigned int row = position.rowIndex; row < ( position.rowIndex + position.rowSpan ); ++row )
231 // store same information to all cells, this way we can identify
232 // if a cell is the prime location of an actor or a spanned one
233 for( unsigned int column = position.columnIndex; column < ( position.columnIndex + position.columnSpan ); ++column )
235 // store same information to all cells, this way we can identify
236 // if a cell is the prime location of an actor or a spanned one
237 mCellData[ row ][ column ] = data;
242 // Relayout the whole table
245 return true; // Addition successful
248 Actor TableView::GetChildAt( const Toolkit::TableView::CellPosition& position )
250 if( ( position.rowIndex < mCellData.GetRows() ) && ( position.columnIndex < mCellData.GetColumns() ) )
252 return mCellData[ position.rowIndex ][ position.columnIndex ].actor;
255 // Return an empty handle
259 Actor TableView::RemoveChildAt( const Toolkit::TableView::CellPosition& position )
261 // get the child handle
262 Actor child = GetChildAt( position );
263 // if no real actor there, nothing else to be done
266 RelayoutingLock lock( *this );
267 // Remove the child, this will trigger a call to OnControlChildRemove
268 Self().Remove( child );
270 // relayout the table only if instances were found
271 if( RemoveAllInstances( child ) )
276 // return the child back to caller
280 bool TableView::FindChildPosition( const Actor& child, Toolkit::TableView::CellPosition& positionOut )
282 // Only find valid child actors
285 // Walk through the layout data
286 const unsigned int rowCount = mCellData.GetRows();
287 const unsigned int columnCount = mCellData.GetColumns();
289 for( unsigned int row = 0; row < rowCount; ++row )
291 for( unsigned int column = 0; column < columnCount; ++column )
293 if( mCellData[ row ][ column ].actor == child )
295 positionOut = mCellData[ row ][ column ].position;
305 void TableView::InsertRow( unsigned int rowIndex )
307 RelayoutingLock lock( *this );
309 mCellData.InsertRow( rowIndex );
311 // Need to update the cell infos for the items that moved
312 const unsigned int rowCount = mCellData.GetRows();
313 const unsigned int columnCount = mCellData.GetColumns();
315 for( unsigned int row = 0; row < rowCount; ++row )
317 for( unsigned int column = 0; column < columnCount; ++column )
319 Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
321 // If cell is spanning and above and spans to inserted row
322 if( ( position.rowSpan > 1 ) && ( position.rowIndex <= rowIndex ) &&
323 ( position.rowIndex + position.rowSpan > rowIndex ) )
328 // Copy cell to occupy the new column
329 mCellData[ rowIndex ][ column ] = mCellData[ row ][ column ];
331 else if( row > rowIndex ) // If below of inserted row, increase row index
339 // Expand row data array
340 mRowData.Insert( mRowData.Begin() + rowIndex, RowColumnData() );
342 // Sizes may have changed, so relayout
343 mRowColumnDirty = true;
347 void TableView::DeleteRow( unsigned int rowIndex )
349 std::vector< Actor > ignored;
350 DeleteRow( rowIndex, ignored );
353 void TableView::DeleteRow( unsigned int rowIndex, std::vector<Actor>& removed )
355 RelayoutingLock lock( *this );
358 std::vector< CellData > lost;
359 mCellData.DeleteRow( rowIndex, lost );
361 // Need to update the cell infos for the items that moved
362 const unsigned int rowCount = mCellData.GetRows();
363 const unsigned int columnCount = mCellData.GetColumns();
365 for( unsigned int row = 0; row < rowCount; ++row )
367 for( unsigned int column = 0; column < columnCount; ++column )
369 Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
371 // If cell is spanning and above and spans to deleted row
372 if( ( position.rowSpan > 1 ) && ( position.rowIndex <= rowIndex ) &&
373 ( position.rowIndex + position.rowSpan > rowIndex ) )
376 if( position.rowSpan > 1 )
381 else if( row >= rowIndex ) // If below of or at the inserted row, decrease row index
384 if( position.rowIndex > 1 )
392 // 1 row removed, 0 columns
393 RemoveAndGetLostActors( lost, removed, 1u, 0u );
395 // Contract row data array
396 mRowData.Erase( mRowData.Begin() + rowIndex );
398 // Sizes may have changed, so relayout
399 mRowColumnDirty = true;
403 void TableView::InsertColumn( unsigned int columnIndex )
405 RelayoutingLock lock( *this );
407 // Insert the new column
408 mCellData.InsertColumn( columnIndex );
410 // Need to update the cell infos for the items that moved
411 const unsigned int rowCount = mCellData.GetRows();
412 const unsigned int columnCount = mCellData.GetColumns();
414 for( unsigned int row = 0; row < rowCount; ++row )
416 for( unsigned int column = 0; column < columnCount; ++column )
418 Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
420 // If cell is spanning and left side and spans to inserted column
421 if( ( position.columnSpan > 1 ) && ( position.columnIndex <= columnIndex ) &&
422 ( position.columnIndex + position.columnSpan > columnIndex ) )
425 position.columnSpan++;
427 // Copy cell to occupy the new column
428 mCellData[ row ][ columnIndex ] = mCellData[ row ][ column ];
430 else if( column > columnIndex ) // If on the right side of inserted column, increase column index
433 position.columnIndex++;
438 // Expand column data array
439 mColumnData.Insert( mColumnData.Begin() + columnIndex, RowColumnData() );
441 // Sizes may have changed so relayout
442 mRowColumnDirty = true;
446 void TableView::DeleteColumn( unsigned int columnIndex )
448 std::vector< Actor > ignored;
449 DeleteColumn( columnIndex, ignored );
452 void TableView::DeleteColumn( unsigned int columnIndex, std::vector<Actor>& removed )
454 RelayoutingLock lock( *this );
457 std::vector< CellData > lost;
458 mCellData.DeleteColumn( columnIndex, lost );
460 // Need to update the cell infos for the items that moved
461 const unsigned int rowCount = mCellData.GetRows();
462 const unsigned int columnCount = mCellData.GetColumns();
464 for( unsigned int row = 0; row < rowCount; ++row )
466 for( unsigned int column = 0; column < columnCount; ++column )
468 Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
470 // If cell is spanning and left side and spans to inserted column
471 if( ( position.columnSpan > 1 ) && ( position.columnIndex <= columnIndex ) &&
472 ( position.columnIndex + position.columnSpan > columnIndex ) )
475 if( position.columnSpan > 1 )
477 position.columnSpan--;
480 else if( column >= columnIndex ) // If on the right side of or at the inserted column, decrease column index
483 if( position.columnIndex > 0 )
485 position.columnIndex--;
491 // 0 rows, 1 column removed
492 RemoveAndGetLostActors( lost, removed, 0u, 1u );
494 // Contract column data array
495 mColumnData.Erase( mColumnData.Begin() + columnIndex );
497 // Size may have changed so relayout
498 mRowColumnDirty = true;
502 void TableView::Resize( unsigned int rows, unsigned int columns )
504 std::vector< Actor > ignored;
505 Resize( rows, columns, ignored );
508 void TableView::Resize( unsigned int rows, unsigned int columns, std::vector<Actor>& removed )
510 RelayoutingLock lock( *this );
512 unsigned int oldRows = GetRows();
513 unsigned int oldColumns = GetColumns();
516 std::vector< CellData > lost;
517 ResizeContainers( rows, columns, lost );
519 // Calculate if we lost rows
520 unsigned int rowsRemoved = 0;
521 unsigned int newRows = GetRows();
523 if( oldRows < newRows )
525 rowsRemoved = newRows - oldRows;
528 // Calculate if we lost columns
529 unsigned int columnsRemoved = 0;
530 unsigned int newColumns = GetColumns();
531 if( oldColumns < newColumns )
533 rowsRemoved = newColumns - oldColumns;
536 RemoveAndGetLostActors( lost, removed, rowsRemoved, columnsRemoved );
538 // Sizes may have changed so request a relayout
539 mRowColumnDirty = true;
543 void TableView::SetCellPadding( Size padding )
545 // If padding really changed
546 if( padding != mPadding )
554 Size TableView::GetCellPadding()
559 void TableView::SetRowPolicy( unsigned int rowIndex, CellSizePolicy policy )
561 DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
563 if( mRowData[ rowIndex ].sizePolicy != policy )
565 mRowData[ rowIndex ].sizePolicy = policy;
567 mRowColumnDirty = true;
572 TableView::CellSizePolicy TableView::GetRowPolicy( unsigned int rowIndex ) const
574 DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
576 return mRowData[ rowIndex ].sizePolicy;
579 void TableView::SetColumnPolicy( unsigned int columnIndex, CellSizePolicy policy )
581 DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
583 if( mColumnData[ columnIndex ].sizePolicy != policy )
585 mColumnData[ columnIndex ].sizePolicy = policy;
587 mRowColumnDirty = true;
592 TableView::CellSizePolicy TableView::GetColumnPolicy( unsigned int columnIndex ) const
594 DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
596 return mColumnData[ columnIndex ].sizePolicy;
599 void TableView::SetFixedHeight( unsigned int rowIndex, float height )
601 DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
603 RowColumnData& data = mRowData[ rowIndex ];
605 data.sizePolicy = FIXED;
607 mRowColumnDirty = true;
611 float TableView::GetFixedHeight( unsigned int rowIndex ) const
613 DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
615 return mRowData[ rowIndex ].size;
618 void TableView::SetFixedWidth( unsigned int columnIndex, float width )
620 DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
622 RowColumnData& data = mColumnData[ columnIndex ];
624 data.sizePolicy = FIXED;
626 mRowColumnDirty = true;
630 float TableView::GetFixedWidth( unsigned int columnIndex ) const
632 DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
634 return mColumnData[ columnIndex ].size;
637 void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage )
639 DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
641 RowColumnData& data = mRowData[ rowIndex ];
642 data.fillRatio = heightPercentage;
643 data.userFillRatio = true;
644 data.sizePolicy = FILL;
646 mRowColumnDirty = true;
650 float TableView::GetRelativeHeight( unsigned int rowIndex ) const
652 DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
654 return mRowData[ rowIndex ].fillRatio;
657 void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentage )
659 DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
661 RowColumnData& data = mColumnData[ columnIndex ];
662 data.fillRatio = widthPercentage;
663 data.userFillRatio = true;
664 data.sizePolicy = FILL;
666 mRowColumnDirty = true;
670 float TableView::GetRelativeWidth( unsigned int columnIndex ) const
672 DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
674 return mColumnData[ columnIndex ].fillRatio;
677 void TableView::CalculateRowColumnData()
679 // Calculate the relative sizes
680 if( mRowColumnDirty )
682 ComputeRelativeSizes( mRowData );
683 ComputeRelativeSizes( mColumnData );
685 mRowColumnDirty = false;
689 void TableView::OnCalculateRelayoutSize( Dimension dimension )
691 CalculateRowColumnData();
693 if( dimension & WIDTH )
695 CalculateFixedSizes( mColumnData, WIDTH );
696 mFixedTotals.width = CalculateTotalFixedSize( mColumnData );
699 if( dimension & HEIGHT )
701 CalculateFixedSizes( mRowData, HEIGHT );
702 mFixedTotals.height = CalculateTotalFixedSize( mRowData );
706 void TableView::OnLayoutNegotiated( float size, Dimension dimension )
708 CalculateRowColumnData();
710 // Calculate the value of all relative sized rows and columns
711 if( dimension & WIDTH )
713 float remainingSize = size - mFixedTotals.width;
714 if( remainingSize < 0.0f )
716 remainingSize = 0.0f;
719 CalculateRelativeSizes( mColumnData, remainingSize );
722 if( dimension & HEIGHT )
724 float remainingSize = size - mFixedTotals.height;
725 if( remainingSize < 0.0f )
727 remainingSize = 0.0f;
730 CalculateRelativeSizes( mRowData, remainingSize );
734 void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
736 CalculateRowColumnData();
738 // Go through the layout data
739 float cumulatedHeight = 0.0f;
741 const unsigned int rowCount = mCellData.GetRows();
742 const unsigned int columnCount = mCellData.GetColumns();
744 for( unsigned int row = 0; row < rowCount; ++row )
746 float cumulatedWidth = 0.0f;
748 for( unsigned int column = 0; column < columnCount; ++column )
750 Actor& actor = mCellData[ row ][ column ].actor;
751 const Toolkit::TableView::CellPosition position = mCellData[ row ][ column ].position;
753 // If there is an actor and this is the main cell of the actor.
754 // An actor can be in multiple cells if its row or columnspan is more than 1.
755 // We however must lay out each actor only once.
756 if( actor && ( position.rowIndex == row ) && ( position.columnIndex == column ) )
758 // Anchor actor to top left of table view
759 actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
760 actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
763 actor.GetPadding( padding );
765 Vector3 actorPosition( cumulatedWidth + mPadding.width + padding.left, // Left padding
766 cumulatedHeight + mPadding.height + padding.top, // Top padding
768 actor.SetPosition( actorPosition );
771 DALI_ASSERT_DEBUG( column < mColumnData.Size() );
772 cumulatedWidth += mColumnData[ column ].size;
775 DALI_ASSERT_DEBUG( row < mRowData.Size() );
776 cumulatedHeight += mRowData[ row ].size;
780 unsigned int TableView::GetRows()
782 return mCellData.GetRows();
785 unsigned int TableView::GetColumns()
787 return mCellData.GetColumns();
790 void TableView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
792 Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
796 TableView& tableViewImpl( GetImpl( tableView ) );
799 case Toolkit::TableView::Property::ROWS:
801 if( value.Get<unsigned int>() != tableViewImpl.GetRows() )
803 tableViewImpl.Resize( value.Get<unsigned int>(), tableViewImpl.GetColumns() );
807 case Toolkit::TableView::Property::COLUMNS:
809 if( value.Get<unsigned int>() != tableViewImpl.GetColumns() )
811 tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<unsigned int>() );
815 case Toolkit::TableView::Property::CELL_PADDING:
817 tableViewImpl.SetCellPadding( value.Get<Vector2>() );
820 case Toolkit::TableView::Property::LAYOUT_ROWS:
822 SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, value );
825 case Toolkit::TableView::Property::LAYOUT_COLUMNS:
827 SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, value );
834 Property::Value TableView::GetProperty( BaseObject* object, Property::Index index )
836 Property::Value value;
838 Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
842 TableView& tableViewImpl( GetImpl( tableView ) );
845 case Toolkit::TableView::Property::ROWS:
847 value = tableViewImpl.GetRows();
850 case Toolkit::TableView::Property::COLUMNS:
852 value = tableViewImpl.GetColumns();
855 case Toolkit::TableView::Property::CELL_PADDING:
857 value = tableViewImpl.GetCellPadding();
860 case Toolkit::TableView::Property::LAYOUT_ROWS:
862 value = tableViewImpl.GetRowHeightsPropertyValue();
865 case Toolkit::TableView::Property::LAYOUT_COLUMNS:
867 value = tableViewImpl.GetColumnWidthsPropertyValue();
876 void TableView::OnControlChildAdd( Actor& child )
878 if( mLayoutingChild )
880 // we're in the middle of laying out children so no point doing anything here
886 // Test properties on actor
887 Toolkit::TableView::CellPosition cellPosition;
888 if( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
890 cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
893 if( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
895 cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
898 if( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) != Property::INVALID_INDEX )
900 Vector2 indices = child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) ).Get<Vector2 >();
901 cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
902 cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
904 AddChild( child, cellPosition );
910 // Find the first available cell to store the actor in
911 const unsigned int rowCount = mCellData.GetRows();
912 const unsigned int columnCount = mCellData.GetColumns();
913 for( unsigned int row = 0; row < rowCount; ++row )
915 for( unsigned int column = 0; column < columnCount; ++column )
917 if( !(mCellData[ row ][ column ].actor) )
919 // Put the actor in the cell
922 data.position.columnIndex = column;
923 data.position.rowIndex = row;
924 mCellData[ row ][ column ] = data;
932 // No empty cells, so increase size of the table
933 unsigned int newColumnCount = ( columnCount > 0 ) ? columnCount : 1;
934 ResizeContainers( rowCount + 1, newColumnCount );
936 // Put the actor in the first cell of the new row
939 data.position.rowIndex = rowCount;
940 data.position.columnIndex = 0;
941 mCellData[ rowCount ][ 0 ] = data;
944 void TableView::OnControlChildRemove( Actor& child )
946 // dont process if we're in the middle of bigger operation like delete row, column or resize
947 if( !mLayoutingChild )
949 // relayout the table only if instances were found
950 if( RemoveAllInstances( child ) )
957 TableView::TableView( unsigned int initialRows, unsigned int initialColumns )
958 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
959 mCellData( initialRows, initialColumns ),
960 mLayoutingChild( false ),
961 mRowColumnDirty( true ) // Force recalculation first time
963 SetKeyboardNavigationSupport( true );
964 ResizeContainers( initialRows, initialColumns );
967 void TableView::OnInitialize()
969 // Make self as keyboard focusable and focus group
971 self.SetKeyboardFocusable(true);
972 SetAsKeyboardFocusGroup(true);
975 void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
977 std::vector<CellData> ignored;
978 ResizeContainers( rows, columns, ignored );
981 void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& removed )
984 mCellData.Resize( rows, columns, removed );
986 // We don't care if these go smaller, data will be regenerated or is not needed anymore
987 mRowData.Resize( rows );
988 mColumnData.Resize( columns );
991 void TableView::RemoveAndGetLostActors( const std::vector<CellData>& lost, std::vector<Actor>& removed,
992 unsigned int rowsRemoved, unsigned int columnsRemoved )
994 // iterate through all lost cells
995 std::vector< CellData >::const_iterator iter = lost.begin();
996 for( ; iter != lost.end(); ++iter )
998 // if it is a valid actor
1001 // is this actor still somewhere else in the table
1002 Toolkit::TableView::CellPosition position;
1003 if( FindChildPosition( (*iter).actor, position ) )
1005 // it must be spanning multiple cells, position contains the top left most one
1006 // check if position is left of the removed location
1007 if( position.columnIndex < (*iter).position.columnIndex )
1009 // if column span is greater than 1
1010 if( mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan > 1 )
1012 // decrease column span
1013 mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan -= columnsRemoved;
1016 // check if position is left of the removed location
1017 if( position.rowIndex < (*iter).position.rowIndex )
1019 // if row span is greater than 1
1020 if( mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan > 1 )
1022 // decrease row span
1023 mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan -= rowsRemoved;
1029 // this actor is gone for good
1030 // add actor to removed container
1031 removed.push_back( (*iter).actor );
1032 // we dont want the child actor anymore
1033 Self().Remove( (*iter).actor );
1039 bool TableView::RemoveAllInstances( const Actor& child )
1042 // walk through the layout data
1043 const unsigned int rowCount = mCellData.GetRows();
1044 const unsigned int columnCount = mCellData.GetColumns();
1045 for( unsigned int row = 0; row < rowCount; ++row )
1047 for( unsigned int column = 0; column < columnCount; ++column )
1049 if( mCellData[ row ][ column ].actor == child )
1051 // clear the cell, NOTE that the cell might be spanning multiple cells
1052 mCellData[ row ][ column ] = CellData();
1060 void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
1061 void(TableView::*funcFixed)(unsigned int, float),
1062 void(TableView::*funcRelative)(unsigned int, float),
1063 const Property::Value& value )
1065 if( Property::MAP == value.GetType() )
1067 Property::Map map = value.Get<Property::Map>();
1068 unsigned int rowIndex(0);
1069 for ( unsigned int i = 0, count = map.Count(); i < count; ++i )
1071 Property::Value& item = map.GetValue(i);
1073 if( std::istringstream(map.GetKey(i)) >> rowIndex // the key is a number
1074 && Property::MAP == item.GetType())
1076 if( item.HasKey( "policy" ) && item.HasKey( "value" ) )
1078 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 );
1079 if( policy == Toolkit::TableView::FIXED )
1081 (tableViewImpl.*funcFixed)( rowIndex, item.GetValue("value").Get<float>() );
1083 else if( policy == Toolkit::TableView::RELATIVE )
1085 (tableViewImpl.*funcRelative)( rowIndex, item.GetValue("value").Get<float>() );
1093 Property::Value TableView::GetRowHeightsPropertyValue()
1096 GetMapPropertyValue( mRowData, map);
1097 return Property::Value(map);
1100 Property::Value TableView::GetColumnWidthsPropertyValue()
1103 GetMapPropertyValue( mColumnData, map);
1104 return Property::Value(map);
1107 void TableView::GetMapPropertyValue( const RowColumnArray& data, Property::Map& map )
1109 std::string fixedPolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIXED, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
1110 std::string relativePolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::RELATIVE, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
1112 const RowColumnArray::SizeType count = data.Size();
1113 for( RowColumnArray::SizeType i = 0; i < count; i++ )
1115 const RowColumnData& dataInstance = data[ i ];
1117 switch( dataInstance.sizePolicy )
1122 item[ "policy" ] = fixedPolicy;
1123 item[ "value" ] = dataInstance.size;
1125 std::ostringstream ss;
1128 map[ ss.str() ] = item;
1136 item[ "policy" ] = relativePolicy;
1137 item[ "value" ] = dataInstance.fillRatio;
1139 std::ostringstream ss;
1142 map[ ss.str() ] = item;
1155 TableView::~TableView()
1160 Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1162 Actor nextFocusableActor;
1164 if ( !currentFocusedActor )
1166 // Nothing is currently focused, so the child in the first cell should be focused.
1167 nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1171 Toolkit::TableView::CellPosition position;
1172 if( FindChildPosition( currentFocusedActor, position ) )
1174 // The current focused actor is a child of TableView
1175 bool focusLost = false;
1176 int currentRow = position.rowIndex;
1177 int currentColumn = position.columnIndex;
1178 int numberOfColumns = GetColumns();
1179 int numberOfRows = GetRows();
1181 switch ( direction )
1183 case Toolkit::Control::Left:
1185 if(--currentColumn < 0)
1187 currentColumn = numberOfColumns - 1;
1188 if(--currentRow < 0)
1190 currentRow = loopEnabled ? numberOfRows - 1 : 0;
1191 focusLost = (currentRow == 0);
1196 case Toolkit::Control::Right:
1198 if(++currentColumn > numberOfColumns - 1)
1201 if(++currentRow > numberOfRows - 1)
1203 currentRow = loopEnabled ? 0 : numberOfRows - 1;
1204 focusLost = (currentRow == numberOfRows - 1);
1209 case Toolkit::Control::Up:
1211 if(--currentRow < 0)
1213 currentRow = loopEnabled ? numberOfRows - 1 : 0;
1214 focusLost = (currentRow == 0);
1218 case Toolkit::Control::Down:
1221 if(++currentRow > numberOfRows - 1)
1223 currentRow = loopEnabled ? 0 : numberOfRows - 1;
1224 focusLost = (currentRow == numberOfRows - 1);
1230 // Move the focus if we haven't lost it.
1233 nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
1238 // The current focused actor is not within table view, so the child in the first cell should be focused.
1239 nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1243 return nextFocusableActor;
1246 Vector3 TableView::GetNaturalSize()
1248 // Natural size is the size of all fixed cell widths or heights. This ignores cells with relative heights.
1249 return Vector3( mFixedTotals.width, mFixedTotals.height, 1.0f );
1252 float TableView::CalculateChildSize( const Actor& child, Dimension dimension )
1254 CalculateRowColumnData();
1256 const unsigned int rowCount = mCellData.GetRows();
1257 const unsigned int columnCount = mCellData.GetColumns();
1259 for( unsigned int row = 0; row < rowCount; ++row )
1261 for( unsigned int column = 0; column < columnCount; ++column )
1263 // check if this cell has an actor
1264 Actor& actor = mCellData[ row ][ column ].actor;
1266 if( actor && ( actor == child ) )
1268 const Toolkit::TableView::CellPosition position = mCellData[ row ][ column ].position;
1270 // If there is an actor and this is the main cell of the actor.
1271 // An actor can be in multiple cells if its row or columnspan is more than 1.
1272 if ( ( position.rowIndex == row ) && ( position.columnIndex == column ) )
1278 float cellSize = 0.0f;
1280 // Accumulate the width
1281 for( unsigned int i = 0; i < position.columnSpan; ++i )
1283 cellSize += mColumnData[ column + i ].size;
1287 cellSize -= mPadding.width * 2.0f;
1288 if( cellSize < 0.0f )
1298 float cellSize = 0.0f;
1300 // Accumulate the height
1301 for( unsigned int i = 0; i < position.rowSpan; ++i )
1303 cellSize += mRowData[ row + i ].size;
1307 cellSize -= mPadding.width * 2.0f;
1308 if( cellSize < 0.0f )
1326 return 0.0f; // Child not found
1329 bool TableView::RelayoutDependentOnChildren( Dimension dimension )
1331 if ( Control::RelayoutDependentOnChildren( dimension ) )
1336 return FindFit( mRowData ) || FindFit( mColumnData );
1339 void TableView::SetCellAlignment( Toolkit::TableView::CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical )
1341 // Check if we need to expand our data array
1342 if( position.rowIndex >= mCellData.GetRows() )
1344 // Only adding new rows
1345 ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
1348 if( position.columnIndex >= mCellData.GetColumns() )
1350 // Only adding new columns
1351 ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
1354 // Set the alignment of the cell
1355 CellData& data = mCellData[ position.rowIndex ][ position.columnIndex ];
1356 data.horizontalAlignment = horizontal;
1357 data.verticalAlignment = vertical;
1360 void TableView::ComputeRelativeSizes( RowColumnArray& data )
1362 // First pass: Count number of fill entries and calculate used relative space
1363 Dali::Vector< RowColumnData* > fillData;
1364 float relativeTotal = 0.0f;
1366 const unsigned int dataCount = data.Size();
1368 for( unsigned int i = 0; i < dataCount; ++i )
1370 RowColumnData& dataInstance = data[ i ];
1372 if( dataInstance.sizePolicy == FILL )
1374 if( dataInstance.userFillRatio )
1376 relativeTotal += dataInstance.fillRatio;
1380 fillData.PushBack( &dataInstance );
1385 // Second pass: Distribute remaining relative space
1386 const unsigned int fillCount = fillData.Size();
1389 if( relativeTotal > 1.0f )
1391 relativeTotal = 1.0f;
1394 const float evenFillRatio = (1.0f - relativeTotal ) / fillCount;
1396 for( unsigned int i = 0; i < fillCount; ++i )
1398 fillData[ i ]->fillRatio = evenFillRatio;
1403 float TableView::CalculateTotalFixedSize( const RowColumnArray& data )
1405 float totalSize = 0.0f;
1407 const unsigned int dataCount = data.Size();
1409 for( unsigned int i = 0; i < dataCount; ++i )
1411 const RowColumnData& dataInstance = data[ i ];
1413 switch( dataInstance.sizePolicy )
1418 totalSize += dataInstance.size;
1432 void TableView::CalculateFixedSizes( RowColumnArray& data, Dimension dimension )
1434 const unsigned int dataCount = data.Size();
1436 for( unsigned int i = 0; i < dataCount; ++i )
1438 RowColumnData& dataInstance = data[ i ];
1440 if( dataInstance.sizePolicy == FIT )
1442 // Find the size of the biggest actor in the row or column
1443 float maxActorHeight = 0.0f;
1445 unsigned int fitCount = ( dimension == WIDTH ) ? mCellData.GetRows() : mCellData.GetColumns();
1447 for( unsigned int j = 0; j < fitCount; ++j )
1449 unsigned int row = ( dimension == WIDTH ) ? j : i;
1450 unsigned int column = ( dimension == WIDTH ) ? i : j;
1451 DALI_ASSERT_DEBUG( row < mCellData.GetRows() );
1452 DALI_ASSERT_DEBUG( column < mCellData.GetColumns() );
1454 Actor& actor = mCellData[ row ][ column ].actor;
1457 if( FitToChild( actor, dimension ) )
1459 maxActorHeight = std::max( maxActorHeight, actor.GetRelayoutSize( dimension ) );
1464 dataInstance.size = maxActorHeight;
1469 void TableView::CalculateRelativeSizes( RowColumnArray& data, float size )
1471 const unsigned int dataCount = data.Size();
1473 for( unsigned int i = 0; i < dataCount; ++i )
1475 RowColumnData& dataInstance = data[ i ];
1477 if( dataInstance.sizePolicy == FILL )
1479 dataInstance.size = dataInstance.fillRatio * size;
1484 bool TableView::FindFit( const RowColumnArray& data )
1486 for( unsigned int i = 0, count = data.Size(); i < count; ++i )
1488 if( data[ i ].sizePolicy == FIT )
1497 } // namespace Internal
1499 } // namespace Toolkit