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/integration-api/debug.h>
33 const float DEFAULT_CONSTRAINT_DURATION = 0.0f;
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.
43 Vector2 RelativeToSize( const Vector2& scale, const Vector2& padding, const Vector2& fixed, const Vector2& parentSize)
45 return fixed + ( parentSize - padding ) * scale;
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
52 #define TABLEVIEW_TAG "DALI Toolkit::TableView "
53 #define TV_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
55 void PrintArray( Array2d<Dali::Toolkit::Internal::TableView::CellData>& array )
57 TV_LOG( "Array2d<CellData> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
59 for( unsigned int i = 0; i < array.GetRows(); ++i )
61 for( unsigned int j = 0; j < array.GetColumns(); ++j )
63 Dali::Toolkit::Internal::TableView::CellData data = array[i][j];
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 );
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 )
81 TV_LOG( "Array2d<Size> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
83 for( unsigned int i = 0; i < array.GetRows(); ++i )
85 for( unsigned int j = 0; j < array.GetColumns(); ++j )
87 TV_LOG( "Array[%d,%d]=%.2f,%.2f ", i, j, array[i][j].width, array[i][j].height );
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 )
96 TV_LOG( "vector, size [%d]\n", array.size() );
98 for( unsigned int i = 0; i < array.size(); ++i )
100 TV_LOG( "vector[%d]=%.2f ", i, array[i] );
104 #endif // defined(DEBUG_ENABLED)
123 return Toolkit::TableView::New( 0, 0 );
126 // Setup properties, signals and actions using the type-registry.
127 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TableView, Toolkit::Control, Create );
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 )
135 DALI_TYPE_REGISTRATION_END()
137 const Scripting::StringEnum< Toolkit::TableView::LayoutPolicy > LAYOUT_POLICY_STRING_TABLE[] =
139 { "fixed", Toolkit::TableView::Fixed },
140 { "relative", Toolkit::TableView::Relative },
141 { "fill", Toolkit::TableView::Fill }
144 const unsigned int LAYOUT_POLICY_STRING_TABLE_COUNT = sizeof(LAYOUT_POLICY_STRING_TABLE) / sizeof( LAYOUT_POLICY_STRING_TABLE[0] );
146 } // Unnamed namespace
148 Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns )
150 // Create the implementation, temporarily owned by this handle on stack
151 IntrusivePtr< TableView > impl = new TableView( initialRows, initialColumns );
153 // Pass ownership to CustomActor handle
154 Toolkit::TableView handle( *impl );
156 // Second-phase init of the implementation
157 // This can only be done after the CustomActor connection has been made...
163 bool TableView::AddChild( Actor child, Toolkit::TableView::CellPosition position )
165 // check that the child is valid
166 DALI_ASSERT_ALWAYS( child );
168 // if child is already parented, we adopt it
169 if( child.GetParent() )
171 child.GetParent().Remove( child );
173 // check if we need to expand our data array
174 if( position.rowIndex >= mCellData.GetRows() )
176 // only adding new rows
177 ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
179 if( position.columnIndex >= mCellData.GetColumns() )
181 // only adding new columns
182 ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
184 // check if there already is something in this cell
185 if( mCellData[ position.rowIndex ][ position.columnIndex ].actor )
187 return false; // cannot share a cell, it would complicate all logic and not bring much benefit
189 RelayoutingLock lock( *this );
193 // put the actor to the main cell
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 )
202 // span might go outside table
203 if( position.rowIndex + position.rowSpan > mCellData.GetRows() )
205 // increase table size for the full span, only increasing rows
206 ResizeContainers( position.rowIndex + position.rowSpan, mCellData.GetColumns() );
210 if( position.columnSpan > 1 )
212 // span might go outside table
213 if( position.columnIndex + position.columnSpan > mCellData.GetColumns() )
215 // increase table size for the full span, only increasing columns
216 ResizeContainers( mCellData.GetRows(), position.columnIndex + position.columnSpan );
220 // if it spanned multiple rows, put the cellinfo in all of those
223 for( unsigned int row = position.rowIndex; row < ( position.rowIndex + position.rowSpan ); ++row )
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 )
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;
235 // relayout the whole table
237 return true; // addition successful
240 Actor TableView::GetChildAt( Toolkit::TableView::CellPosition position )
242 // check if we have this row and column in the table
243 if( ( position.columnIndex >= mCellData.GetColumns() )||
244 ( position.rowIndex >= mCellData.GetRows() ) )
246 // return an empty handle
249 // return the child handle
250 return mCellData[ position.rowIndex ][ position.columnIndex ].actor;
253 Actor TableView::RemoveChildAt( Toolkit::TableView::CellPosition position )
255 // get the child handle
256 Actor child = GetChildAt( position );
257 // if no real actor there, nothing else to be done
260 RelayoutingLock lock( *this );
261 // Remove the child, this will trigger a call to OnControlChildRemove
262 Self().Remove( child );
264 // relayout the table only if instances were found
265 if( RemoveAllInstances( child ) )
270 // return the child back to caller
274 bool TableView::FindChildPosition( Actor child, Toolkit::TableView::CellPosition& position )
276 // only find valid child actors
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 )
284 for( unsigned int column = 0; column < columnCount; ++column )
286 if( mCellData[ row ][ column ].actor == child )
288 position = mCellData[ row ][ column ].position;
297 void TableView::InsertRow( unsigned int rowIndex )
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 )
306 for( unsigned int column = 0; column < columnCount; ++column )
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 ) )
313 // increase span by one
315 // copy cell to occupy the new column
316 mCellData[ rowIndex ][ column ] = mCellData[ row ][ column ];
318 // if below of inserted row, increase row index
319 else if( row > rowIndex )
321 // increase index by one
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 );
333 void TableView::DeleteRow( unsigned int rowIndex )
335 std::vector< Actor > ignored;
336 DeleteRow( rowIndex, ignored );
339 void TableView::DeleteRow( unsigned int rowIndex, std::vector<Actor>& removed )
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 )
349 for( unsigned int column = 0; column < columnCount; ++column )
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 ) )
356 // decrease span by one
357 if( position.rowSpan > 1 )
362 // if below of or at the inserted row, decrease row index
363 else if( row >= rowIndex )
365 // decrease index by one
366 if( position.rowIndex > 1 )
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 );
383 void TableView::InsertColumn( unsigned int columnIndex )
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 )
392 for( unsigned int column = 0; column < columnCount; ++column )
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 ) )
399 // increase span by one
400 position.columnSpan++;
401 // copy cell to occupy the new column
402 mCellData[ row ][ columnIndex ] = mCellData[ row ][ column ];
404 // if on the right side of inserted column, increase column index
405 else if( column > columnIndex )
407 // increase index by one
408 position.columnIndex++;
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 );
420 void TableView::DeleteColumn( unsigned int columnIndex )
422 std::vector< Actor > ignored;
423 DeleteColumn( columnIndex, ignored );
426 void TableView::DeleteColumn( unsigned int columnIndex, std::vector<Actor>& removed )
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 )
436 for( unsigned int column = 0; column < columnCount; ++column )
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 ) )
443 // decrease span by one
444 if( position.columnSpan > 1 )
446 position.columnSpan--;
449 // if on the right side of or at the inserted column, decrease column index
450 else if( column >= columnIndex )
452 // decrease index by one
453 if( position.columnIndex > 0 )
455 position.columnIndex--;
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 );
471 void TableView::Resize( unsigned int rows, unsigned int columns )
473 std::vector< Actor > ignored;
474 Resize( rows, columns, ignored );
477 void TableView::Resize( unsigned int rows, unsigned int columns, std::vector<Actor>& removed )
479 RelayoutingLock lock( *this );
480 unsigned int oldRows = GetRows();
481 unsigned int oldColumns = GetColumns();
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 )
490 rowsRemoved = newRows - oldRows;
492 unsigned int columnsRemoved = 0;
493 unsigned int newColumns = GetColumns();
494 if( oldColumns < newColumns )
496 rowsRemoved = newColumns - oldColumns;
498 RemoveAndGetLostActors( lost, removed, rowsRemoved, columnsRemoved );
499 // finally relayout once all actors are removed
503 void TableView::SetCellPadding( Size padding )
505 // if padding really changed
506 if( padding != mPadding )
514 Size TableView::GetCellPadding()
519 void TableView::SetFixedHeight( unsigned int rowIndex, float height )
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
530 float TableView::GetFixedHeight( unsigned int rowIndex ) const
532 DALI_ASSERT_ALWAYS( rowIndex < mFixedHeights.size() );
534 return mFixedHeights[ rowIndex ];
537 void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage )
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
548 float TableView::GetRelativeHeight( unsigned int rowIndex ) const
550 DALI_ASSERT_ALWAYS( rowIndex < mRelativeHeights.size() );
552 return mRelativeHeights[ rowIndex ];
555 void TableView::SetFixedWidth( unsigned int columnIndex, float width )
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
566 float TableView::GetFixedWidth( unsigned int columnIndex ) const
568 DALI_ASSERT_ALWAYS( columnIndex < mFixedWidths.size() );
570 return mFixedWidths[ columnIndex ];
573 void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentage )
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
584 float TableView::GetRelativeWidth( unsigned int columnIndex ) const
586 DALI_ASSERT_ALWAYS( columnIndex < mRelativeWidths.size() );
588 return mRelativeWidths[ columnIndex ];
591 void TableView::OnRelayout( const Vector2& size, ActorSizeContainer& container )
593 float fixedHeightsTotal = 0.0f;
594 float fixedWidthsTotal = 0.0f;
596 // 1. update the relative sizes and calculate total fixed height and width
597 UpdateRelativeSizes( fixedHeightsTotal, fixedWidthsTotal );
599 // 2. go through the layout data and create constraints
600 float cumulatedFixedHeight = 0.0f;
601 float cumulatedRelativeHeight = 0.0f;
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 )
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 )
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 ) )
624 // anchor actor correctly
625 actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
626 actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
627 // remove old constraints
628 actor.RemoveConstraints();
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 );
645 Vector3 actorPosition( RelativeToSize( relativePosition, positionPadding, fixedPosition, size ) );
646 actor.SetPosition( actorPosition );
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 )
656 for( unsigned int i = 1; i < position.rowSpan; ++i )
658 // accumulate the height only
659 relativeSize.height += mRelativeSizes[ row + i ][ column ].height;
660 fixedSize.height += mFixedHeights[ row + i ];
663 if( position.columnSpan > 1 )
665 for( unsigned int i = 1; i < position.columnSpan; ++i )
667 // accumulate the width only
668 relativeSize.width += mRelativeSizes[ row ][ column + i ].width;
669 fixedSize.width += mFixedWidths[ column + i ];
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;
682 Vector2 actorSize( RelativeToSize( relativeSize, sizePadding, fixedSize, size ) );
683 actor.SetSize(actorSize.x, actorSize.y);
686 Relayout ( actor, actorSize, container );
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;
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
700 unsigned int TableView::GetRows()
702 return mCellData.GetRows();
705 unsigned int TableView::GetColumns()
707 return mCellData.GetColumns();
710 void TableView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
712 Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
716 TableView& tableViewImpl( GetImpl( tableView ) );
719 case Toolkit::TableView::Property::ROWS:
721 if( value.Get<unsigned int>() != tableViewImpl.GetRows() )
723 tableViewImpl.Resize( value.Get<unsigned int>(), tableViewImpl.GetColumns() );
727 case Toolkit::TableView::Property::COLUMNS:
729 if( value.Get<unsigned int>() != tableViewImpl.GetColumns() )
731 tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<unsigned int>() );
735 case Toolkit::TableView::Property::CELL_PADDING:
737 tableViewImpl.SetCellPadding( value.Get<Vector2>() );
740 case Toolkit::TableView::Property::LAYOUT_ROWS:
742 SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, value );
745 case Toolkit::TableView::Property::LAYOUT_COLUMNS:
747 SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, value );
754 Property::Value TableView::GetProperty( BaseObject* object, Property::Index index )
756 Property::Value value;
758 Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
762 TableView& tableViewImpl( GetImpl( tableView ) );
765 case Toolkit::TableView::Property::ROWS:
767 value = tableViewImpl.GetRows();
770 case Toolkit::TableView::Property::COLUMNS:
772 value = tableViewImpl.GetColumns();
775 case Toolkit::TableView::Property::CELL_PADDING:
777 value = tableViewImpl.GetCellPadding();
780 case Toolkit::TableView::Property::LAYOUT_ROWS:
782 value = tableViewImpl.GetRowHeightsPropertyValue();
785 case Toolkit::TableView::Property::LAYOUT_COLUMNS:
787 value = tableViewImpl.GetColumnWidthsPropertyValue();
796 void TableView::OnControlChildAdd( Actor& child )
798 if( mLayoutingChild )
800 // we're in the middle of laying out children so no point doing anything here
804 Toolkit::TableView::CellPosition cellPosition;
805 if( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
807 cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
809 if( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
811 cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
813 if( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) != Property::INVALID_INDEX )
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 );
819 AddChild( child, cellPosition );
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 )
831 for( unsigned int column = 0; column < columnCount; ++column )
833 // no actor means free cell
834 if( !(mCellData[ row ][ column ].actor) )
836 // put the actor in the cell
839 data.position.columnIndex = column;
840 data.position.rowIndex = row;
841 mCellData[ row ][ column ] = data;
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
853 data.position.rowIndex = rowCount;
854 data.position.columnIndex = 0;
855 mCellData[ rowCount ][ 0 ] = data;
856 // finally relayout the table
860 void TableView::OnControlChildRemove( Actor& child )
862 // dont process if we're in the middle of bigger operation like delete row, column or resize
863 if( !mLayoutingChild )
865 // relayout the table only if instances were found
866 if( RemoveAllInstances( child ) )
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 )
878 SetKeyboardNavigationSupport( true );
879 ResizeContainers( initialRows, initialColumns );
882 void TableView::OnInitialize()
884 // Make self as keyboard focusable and focus group
886 self.SetKeyboardFocusable(true);
887 SetAsKeyboardFocusGroup(true);
890 void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
892 std::vector<CellData> ignored;
893 ResizeContainers( rows, columns, ignored );
896 void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& removed )
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 );
907 void TableView::RemoveAndGetLostActors( const std::vector<CellData>& lost, std::vector<Actor>& removed,
908 unsigned int rowsRemoved, unsigned int columnsRemoved )
910 // iterate through all lost cells
911 std::vector< CellData >::const_iterator iter = lost.begin();
912 for( ; iter != lost.end(); ++iter )
914 // if it is a valid actor
917 // is this actor still somewhere else in the table
918 Toolkit::TableView::CellPosition position;
919 if( FindChildPosition( (*iter).actor, position ) )
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 )
925 // if column span is greater than 1
926 if( mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan > 1 )
928 // decrease column span
929 mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan -= columnsRemoved;
932 // check if position is left of the removed location
933 if( position.rowIndex < (*iter).position.rowIndex )
935 // if row span is greater than 1
936 if( mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan > 1 )
939 mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan -= rowsRemoved;
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 );
955 bool TableView::RemoveAllInstances( Actor child )
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 )
963 for( unsigned int column = 0; column < columnCount; ++column )
965 if( mCellData[ row ][ column ].actor == child )
967 // clear the cell, NOTE that the cell might be spanning multiple cells
968 mCellData[ row ][ column ] = CellData();
976 void TableView::UpdateRelativeSizes( float& fixedHeightsTotal, float& fixedWidthsTotal )
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 )
986 if( mFixedHeights[ row ] > 0.0f )
989 fixedHeightsTotal += mFixedHeights[ row ];
991 if( mRelativeHeights[ row ] > 0.0f )
994 relativeHeightsTotal += mRelativeHeights[ row ];
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 )
1003 if( mFixedWidths[ column ] > 0.0f )
1006 fixedWidthsTotal += mFixedWidths[ column ];
1008 if( mRelativeWidths[ column ] > 0.0f )
1010 ++relativeColumnCount;
1011 relativeWidthsTotal += mRelativeWidths[ column ];
1015 // 2. cap the relative width and height totals to 100%
1016 if( relativeHeightsTotal > 1.0f )
1018 relativeHeightsTotal = 1.0f;
1020 if( relativeWidthsTotal > 1.0f )
1022 relativeWidthsTotal = 1.0f;
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 );
1029 // walk through the data containers
1030 for( unsigned int row = 0; row < rowCount; ++row )
1032 float relativeHeight = 0.0f;
1033 // if we have a fixed height, relative height is 0
1034 if( mFixedHeights[ row ] > 0.0f )
1036 relativeHeight = 0.0f;
1038 // else if we're given a specific row height %, use that
1039 else if( mRelativeHeights[ row ] > 0.0f )
1041 relativeHeight = mRelativeHeights[ row ];
1043 // else if there are fill rows
1044 else if( fillRowCount > 0 )
1046 // this is a 'fill' row. it gets the remainder of the 100% divided evenly between 'fill' rows
1047 relativeHeight = (1.0f - relativeHeightsTotal ) / fillRowCount;
1049 for( unsigned int column = 0; column < columnCount; ++column )
1051 float relativeWidth = 0.0f;
1052 // if we have a fixed width, relative width is 0
1053 if( mFixedWidths[ column ] > 0.0f )
1055 relativeWidth = 0.0f;
1057 // else if we're given a specific column width %, use that
1058 else if( mRelativeWidths[ column ] > 0.0f )
1060 relativeWidth = mRelativeWidths[ column ];
1062 // else if there are fill columns
1063 else if( fillColumnCount > 0 )
1065 // this is a 'fill' column. it gets the remainder of the 100% divided evenly between 'fill' columns
1066 relativeWidth = (1.0f - relativeWidthsTotal ) / fillColumnCount;
1069 mRelativeSizes[ row ][ column ] = Size( relativeWidth, relativeHeight );
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 )
1079 if( Property::MAP == value.GetType() )
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 )
1085 Property::Value& item = map.GetValue(i);
1087 if( std::istringstream(map.GetKey(i)) >> rowIndex // the key is a number
1088 && Property::MAP == item.GetType())
1090 if( item.HasKey( "policy" ) && item.HasKey( "value" ) )
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 )
1095 (tableViewImpl.*funcFixed)( rowIndex, item.GetValue("value").Get<float>() );
1097 else if( policy == Toolkit::TableView::Relative )
1099 (tableViewImpl.*funcRelative)( rowIndex, item.GetValue("value").Get<float>() );
1107 Property::Value TableView::GetRowHeightsPropertyValue()
1110 GetMapPropertyValue( mFixedHeights, mRelativeHeights, map);
1111 return Property::Value(map);
1114 Property::Value TableView::GetColumnWidthsPropertyValue()
1117 GetMapPropertyValue( mFixedWidths, mRelativeWidths, map);
1118 return Property::Value(map);
1121 void TableView::GetMapPropertyValue( const std::vector<float>& fixedSize, const std::vector<float>& relativeSize, Property::Map& map )
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 ) );
1126 size_t count = fixedSize.size();
1127 for( size_t index = 0; index < count; index++ )
1129 if( ! EqualsZero( fixedSize[index] ) )
1132 item[ "policy" ] = fixedPolicy;
1133 item[ "value" ] = fixedSize[index];
1135 map[ static_cast<std::ostringstream*>( &(std::ostringstream() << index ) )->str() ] = item;
1137 else if( ! EqualsZero( relativeSize[index] ) )
1140 item[ "policy" ] = relativePolicy;
1141 item[ "value" ] = relativeSize[index];
1143 map[ static_cast<std::ostringstream*>( &(std::ostringstream() << index ) )->str() ] = item;
1148 TableView::~TableView()
1153 Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1155 Actor nextFocusableActor;
1157 if ( !currentFocusedActor )
1159 // Nothing is currently focused, so the child in the first cell should be focused.
1160 nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
1164 Toolkit::TableView::CellPosition position;
1165 if( FindChildPosition( currentFocusedActor, position ) )
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();
1174 switch ( direction )
1176 case Toolkit::Control::Left:
1178 if(--currentColumn < 0)
1180 currentColumn = numberOfColumns - 1;
1181 if(--currentRow < 0)
1183 currentRow = loopEnabled ? numberOfRows - 1 : 0;
1184 focusLost = (currentRow == 0);
1189 case Toolkit::Control::Right:
1191 if(++currentColumn > numberOfColumns - 1)
1194 if(++currentRow > numberOfRows - 1)
1196 currentRow = loopEnabled ? 0 : numberOfRows - 1;
1197 focusLost = (currentRow == numberOfRows - 1);
1202 case Toolkit::Control::Up:
1204 if(--currentRow < 0)
1206 currentRow = loopEnabled ? numberOfRows - 1 : 0;
1207 focusLost = (currentRow == 0);
1211 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