X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Ftable-view%2Ftable-view-impl.cpp;h=d2e46fd69872c011cfa10c2528c028961677e864;hp=76eab51e2257451d35eee91f92fdf8fca796e331;hb=f3da11c2818c6d17706fbb2417f21b602b3190f5;hpb=61cec43aa084293be7e3002db0a24de1cd9a2677 diff --git a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp index 76eab51..d2e46fd 100644 --- a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp +++ b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp @@ -22,26 +22,38 @@ #include #include #include -#include +#include +#include +#include #include using namespace Dali; namespace { -const float DEFAULT_CONSTRAINT_DURATION = 0.0f; +/* + * Custom properties for where to put the actor. + * + * When an actor is add to the tableView through Actor::Add() instead of TableView::AddChild, + * the following custom properties of the actor are checked to decide the actor position inside the table + * + * These non-animatable properties should be registered to the child which would be added to the table + */ +const char * const CELL_INDEX_PROPERTY_NAME("cellIndex"); +const char * const ROW_SPAN_PROPERTY_NAME("rowSpan"); +const char * const COLUMN_SPAN_PROPERTY_NAME("columnSpan"); +const char * const CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME("cellHorizontalAlignment"); +const char * const CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME("cellVerticalAlignment"); /** - * sets a child property relative to parents size and applies a unit based padding before the relative calculation. - * @param[in] scale of parent minus padding between 0 and 1 - * @param[in] padding in world coordinate units - * @param[in] fixed part in world coordinate units - * @param[in] size of the parent - * @return The relative size with padding. + * @brief Should the tableview fit around the given actor + * + * @param[in] actor The child actor to test against + * @param[dimension] The dimension to test against */ -Vector2 RelativeToSize( const Vector2& scale, const Vector2& padding, const Vector2& fixed, const Vector2& parentSize) +bool FitToChild( Actor actor, Dimension::Type dimension ) { - return fixed + ( parentSize - padding ) * scale; + return actor.GetResizePolicy( dimension ) != ResizePolicy::FILL_TO_PARENT && actor.GetRelayoutSize( dimension ) > 0.0f; } #if defined(DEBUG_ENABLED) @@ -50,7 +62,9 @@ Vector2 RelativeToSize( const Vector2& scale, const Vector2& padding, const Vect #define TABLEVIEW_TAG "DALI Toolkit::TableView " #define TV_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args) +//#define TABLEVIEW_DEBUG 1 +#if defined(TABLEVIEW_DEBUG) void PrintArray( Array2d& array ) { TV_LOG( "Array2d size [%d,%d] \n", array.GetRows(), array.GetColumns() ); @@ -61,11 +75,13 @@ void PrintArray( Array2d& array ) { Dali::Toolkit::Internal::TableView::CellData data = array[i][j]; char actor = ' '; + std::string actorName; if( data.actor ) { actor = 'A'; + actorName = data.actor.GetName(); } - TV_LOG("Array[%d,%d]=%c %d,%d,%d,%d ", i, j, actor, + TV_LOG("Array[%d,%d]=%c %s %d,%d,%d,%d ", i, j, actor, actorName.c_str(), data.position.rowIndex, data.position.columnIndex, data.position.rowSpan, data.position.columnSpan ); } @@ -100,6 +116,7 @@ void PrintVector( std::vector& array ) } TV_LOG( "\n" ); } +#endif // defined(TABLEVIEW_DEBUG) #endif // defined(DEBUG_ENABLED) } // namespace @@ -110,41 +127,55 @@ namespace Dali namespace Toolkit { -const Property::Index TableView::PROPERTY_ROWS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX ); -const Property::Index TableView::PROPERTY_COLUMNS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 1 ); -const Property::Index TableView::PROPERTY_CELL_PADDING( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 2 ); -const Property::Index TableView::PROPERTY_LAYOUT_ROWS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 3 ); -const Property::Index TableView::PROPERTY_LAYOUT_COLUMNS( Internal::TableView::TABLEVIEW_PROPERTY_START_INDEX + 4 ); - namespace Internal { namespace { -const Scripting::StringEnum< Toolkit::TableView::LayoutPolicy > LAYOUT_POLICY_STRING_TABLE[] = +// Type registration +BaseHandle Create() { - { "fixed", Toolkit::TableView::Fixed }, - { "relative", Toolkit::TableView::Relative }, - { "fill", Toolkit::TableView::Fill } -}; + return Toolkit::TableView::New( 0, 0 ); +} + +// Setup properties, signals and actions using the type-registry. +DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TableView, Toolkit::Control, Create ); + +DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "rows", INTEGER, ROWS ) +DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "columns", INTEGER, COLUMNS ) +DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "cellPadding", VECTOR2, CELL_PADDING ) +DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutRows", MAP, LAYOUT_ROWS ) +DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutColumns", MAP, LAYOUT_COLUMNS ) + +DALI_TYPE_REGISTRATION_END() +const Scripting::StringEnum LAYOUT_POLICY_STRING_TABLE[] = +{ + { "fixed", Toolkit::TableView::FIXED }, + { "relative", Toolkit::TableView::RELATIVE }, + { "fill", Toolkit::TableView::FILL }, + { "fit", Toolkit::TableView::FIT } +}; const unsigned int LAYOUT_POLICY_STRING_TABLE_COUNT = sizeof(LAYOUT_POLICY_STRING_TABLE) / sizeof( LAYOUT_POLICY_STRING_TABLE[0] ); -// Type registration -BaseHandle Create() +const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] = { - return Toolkit::TableView::New(0, 0); -} -TypeRegistration mType( typeid(Toolkit::TableView), typeid(Toolkit::Control), Create ); + {"left", HorizontalAlignment::LEFT}, + {"center", HorizontalAlignment::CENTER}, + {"right", HorizontalAlignment::RIGHT} +}; +const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof(HORIZONTAL_ALIGNMENT_STRING_TABLE) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] ); -PropertyRegistration property1( mType, "rows", Toolkit::TableView::PROPERTY_ROWS, Property::UNSIGNED_INTEGER, &TableView::SetProperty, &TableView::GetProperty ); -PropertyRegistration property2( mType, "columns", Toolkit::TableView::PROPERTY_COLUMNS, Property::UNSIGNED_INTEGER, &TableView::SetProperty, &TableView::GetProperty ); -PropertyRegistration property3( mType, "cell-padding", Toolkit::TableView::PROPERTY_CELL_PADDING, Property::VECTOR2, &TableView::SetProperty, &TableView::GetProperty ); -PropertyRegistration property4( mType, "layout-rows", Toolkit::TableView::PROPERTY_LAYOUT_ROWS, Property::MAP, &TableView::SetProperty, &TableView::GetProperty ); -PropertyRegistration property5( mType, "layout-columns", Toolkit::TableView::PROPERTY_LAYOUT_COLUMNS, Property::MAP, &TableView::SetProperty, &TableView::GetProperty ); +const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] = +{ + {"top", VerticalAlignment::TOP}, + {"center", VerticalAlignment::CENTER}, + {"bottom", VerticalAlignment::BOTTOM} +}; +const unsigned int VERTICAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof(VERTICAL_ALIGNMENT_STRING_TABLE) / sizeof( VERTICAL_ALIGNMENT_STRING_TABLE[0] ); -} // namespace +} // Unnamed namespace Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns ) { @@ -161,97 +192,94 @@ Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initia return handle; } -bool TableView::AddChild( Actor child, Toolkit::TableView::CellPosition position ) +bool TableView::AddChild( Actor& child, const Toolkit::TableView::CellPosition& position ) { // check that the child is valid DALI_ASSERT_ALWAYS( child ); // if child is already parented, we adopt it - if( child.GetParent() ) - { - child.GetParent().Remove( child ); - } + child.Unparent(); + // check if we need to expand our data array if( position.rowIndex >= mCellData.GetRows() ) { // only adding new rows ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() ); } + if( position.columnIndex >= mCellData.GetColumns() ) { // only adding new columns ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 ); } + // check if there already is something in this cell if( mCellData[ position.rowIndex ][ position.columnIndex ].actor ) { return false; // cannot share a cell, it would complicate all logic and not bring much benefit } + RelayoutingLock lock( *this ); // adopt the child Self().Add( child ); - // put the actor to the main cell - CellData data; - data.actor = child; - data.position = position; - mCellData[ position.rowIndex ][ position.columnIndex ] = data; // if child spans multiple rows of columns - bool spanned = false; - if( position.rowSpan > 1 ) + if( ( position.rowSpan > 1 ) && ( position.rowIndex + position.rowSpan > mCellData.GetRows() ) ) { - // span might go outside table - if( position.rowIndex + position.rowSpan > mCellData.GetRows() ) - { - // increase table size for the full span, only increasing rows - ResizeContainers( position.rowIndex + position.rowSpan, mCellData.GetColumns() ); - } - spanned = true; + // increase table size for the full span, only increasing rows + ResizeContainers( position.rowIndex + position.rowSpan, mCellData.GetColumns() ); } - if( position.columnSpan > 1 ) + + if( ( position.columnSpan > 1 ) && ( position.columnIndex + position.columnSpan > mCellData.GetColumns() ) ) { - // span might go outside table - if( position.columnIndex + position.columnSpan > mCellData.GetColumns() ) - { - // increase table size for the full span, only increasing columns - ResizeContainers( mCellData.GetRows(), position.columnIndex + position.columnSpan ); - } - spanned = true; + // increase table size for the full span, only increasing columns + ResizeContainers( mCellData.GetRows(), position.columnIndex + position.columnSpan ); } - // if it spanned multiple rows, put the cellinfo in all of those - if( spanned ) + + // Fill in all cells that need the data + CellData data; + data.actor = child; + data.position = position; + + for( unsigned int row = position.rowIndex; row < ( position.rowIndex + position.rowSpan ); ++row ) { - for( unsigned int row = position.rowIndex; row < ( position.rowIndex + position.rowSpan ); ++row ) + // store same information to all cells, this way we can identify + // if a cell is the prime location of an actor or a spanned one + for( unsigned int column = position.columnIndex; column < ( position.columnIndex + position.columnSpan ); ++column ) { // store same information to all cells, this way we can identify // if a cell is the prime location of an actor or a spanned one - for( unsigned int column = position.columnIndex; column < ( position.columnIndex + position.columnSpan ); ++column ) - { - // store same information to all cells, this way we can identify - // if a cell is the prime location of an actor or a spanned one - mCellData[ row ][ column ] = data; - } + mCellData[ row ][ column ] = data; } } - // relayout the whole table + + // Relayout the whole table + if( mRowData[position.rowIndex].sizePolicy == Toolkit::TableView::FIT && position.rowSpan == 1 ) + { + mRowDirty = true; + } + if( mColumnData[position.columnIndex].sizePolicy == Toolkit::TableView::FIT && position.columnSpan == 1 ) + { + mColumnDirty = true; + } + RelayoutRequest(); - return true; // addition successful + + return true; // Addition successful } -Actor TableView::GetChildAt( Toolkit::TableView::CellPosition position ) +Actor TableView::GetChildAt( const Toolkit::TableView::CellPosition& position ) { - // check if we have this row and column in the table - if( ( position.columnIndex >= mCellData.GetColumns() )|| - ( position.rowIndex >= mCellData.GetRows() ) ) + if( ( position.rowIndex < mCellData.GetRows() ) && ( position.columnIndex < mCellData.GetColumns() ) ) { - // return an empty handle - return Actor(); + return mCellData[ position.rowIndex ][ position.columnIndex ].actor; } - // return the child handle - return mCellData[ position.rowIndex ][ position.columnIndex ].actor; + + // Return an empty handle + return Actor(); } -Actor TableView::RemoveChildAt( Toolkit::TableView::CellPosition position ) +Actor TableView::RemoveChildAt( const Toolkit::TableView::CellPosition& position ) { // get the child handle Actor child = GetChildAt( position ); @@ -265,6 +293,14 @@ Actor TableView::RemoveChildAt( Toolkit::TableView::CellPosition position ) // relayout the table only if instances were found if( RemoveAllInstances( child ) ) { + if( mRowData[position.rowIndex].sizePolicy == Toolkit::TableView::FIT ) + { + mRowDirty = true; + } + if( mColumnData[position.columnIndex].sizePolicy == Toolkit::TableView::FIT ) + { + mColumnDirty = true; + } RelayoutRequest(); } } @@ -272,62 +308,70 @@ Actor TableView::RemoveChildAt( Toolkit::TableView::CellPosition position ) return child; } -bool TableView::FindChildPosition( Actor child, Toolkit::TableView::CellPosition& position ) +bool TableView::FindChildPosition( const Actor& child, Toolkit::TableView::CellPosition& positionOut ) { - // only find valid child actors + // Only find valid child actors if( child ) { - // walk through the layout data + // Walk through the layout data const unsigned int rowCount = mCellData.GetRows(); const unsigned int columnCount = mCellData.GetColumns(); + for( unsigned int row = 0; row < rowCount; ++row ) { for( unsigned int column = 0; column < columnCount; ++column ) { if( mCellData[ row ][ column ].actor == child ) { - position = mCellData[ row ][ column ].position; + positionOut = mCellData[ row ][ column ].position; return true; } } } } + return false; } void TableView::InsertRow( unsigned int rowIndex ) { RelayoutingLock lock( *this ); + mCellData.InsertRow( rowIndex ); - // need to update the cellinfos for the items that moved + + // Need to update the cell infos for the items that moved const unsigned int rowCount = mCellData.GetRows(); const unsigned int columnCount = mCellData.GetColumns(); + for( unsigned int row = 0; row < rowCount; ++row ) { for( unsigned int column = 0; column < columnCount; ++column ) { Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position; - // if cell is spanning and above and spans to inserted row - if( ( position.rowSpan > 1 )&&( position.rowIndex <= rowIndex )&& + + // If cell is spanning and above and spans to inserted row + if( ( position.rowSpan > 1 ) && ( position.rowIndex <= rowIndex ) && ( position.rowIndex + position.rowSpan > rowIndex ) ) { - // increase span by one + // Increment span position.rowSpan++; - // copy cell to occupy the new column + + // Copy cell to occupy the new column mCellData[ rowIndex ][ column ] = mCellData[ row ][ column ]; } - // if below of inserted row, increase row index - else if( row > rowIndex ) + else if( row > rowIndex ) // If below of inserted row, increase row index { - // increase index by one + // Increment index position.rowIndex++; } } } - mRelativeSizes.InsertRow( rowIndex ); - // inserting a row requires adjusting the height vectors - mFixedHeights.insert( mFixedHeights.begin() + rowIndex, 0 ); - mRelativeHeights.insert( mRelativeHeights.begin() + rowIndex, 0 ); + + // Expand row data array + mRowData.Insert( mRowData.Begin() + rowIndex, RowColumnData() ); + + // Sizes may have changed, so relayout + mRowDirty = true; RelayoutRequest(); } @@ -340,30 +384,34 @@ void TableView::DeleteRow( unsigned int rowIndex ) void TableView::DeleteRow( unsigned int rowIndex, std::vector& removed ) { RelayoutingLock lock( *this ); + + // Delete the row std::vector< CellData > lost; mCellData.DeleteRow( rowIndex, lost ); - // need to update the cellinfos for the items that moved + + // Need to update the cell infos for the items that moved const unsigned int rowCount = mCellData.GetRows(); const unsigned int columnCount = mCellData.GetColumns(); + for( unsigned int row = 0; row < rowCount; ++row ) { for( unsigned int column = 0; column < columnCount; ++column ) { Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position; - // if cell is spanning and above and spans to deleted row - if( ( position.rowSpan > 1 )&&( position.rowIndex <= rowIndex )&& + + // If cell is spanning and above and spans to deleted row + if( ( position.rowSpan > 1 ) && ( position.rowIndex <= rowIndex ) && ( position.rowIndex + position.rowSpan > rowIndex ) ) { - // decrease span by one + // Decrement span if( position.rowSpan > 1 ) { position.rowSpan--; } } - // if below of or at the inserted row, decrease row index - else if( row >= rowIndex ) + else if( row >= rowIndex ) // If below of or at the inserted row, decrease row index { - // decrease index by one + // Decrement index if( position.rowIndex > 1 ) { position.rowIndex--; @@ -371,50 +419,61 @@ void TableView::DeleteRow( unsigned int rowIndex, std::vector& removed ) } } } + // 1 row removed, 0 columns RemoveAndGetLostActors( lost, removed, 1u, 0u ); - // resize the data structures - mRelativeSizes.DeleteRow( rowIndex ); - // deleting a row requires adjusting the height vectors - mFixedHeights.erase( mFixedHeights.begin() + rowIndex ); - mRelativeHeights.erase( mRelativeHeights.begin() + rowIndex ); + + // Contract row data array + mRowData.Erase( mRowData.Begin() + rowIndex ); + + // Sizes may have changed, so relayout + mRowDirty = true; + // it is possible that the deletion of row leads to remove of child which might further lead to the change of FIT column + mColumnDirty = true; + RelayoutRequest(); } void TableView::InsertColumn( unsigned int columnIndex ) { RelayoutingLock lock( *this ); + + // Insert the new column mCellData.InsertColumn( columnIndex ); - // need to update the cellinfos for the items that moved + + // Need to update the cell infos for the items that moved const unsigned int rowCount = mCellData.GetRows(); const unsigned int columnCount = mCellData.GetColumns(); + for( unsigned int row = 0; row < rowCount; ++row ) { for( unsigned int column = 0; column < columnCount; ++column ) { Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position; - // if cell is spanning and left side and spans to inserted column - if( ( position.columnSpan > 1 )&&( position.columnIndex <= columnIndex )&& + + // If cell is spanning and left side and spans to inserted column + if( ( position.columnSpan > 1 ) && ( position.columnIndex <= columnIndex ) && ( position.columnIndex + position.columnSpan > columnIndex ) ) { - // increase span by one + // Increment span position.columnSpan++; - // copy cell to occupy the new column + + // Copy cell to occupy the new column mCellData[ row ][ columnIndex ] = mCellData[ row ][ column ]; } - // if on the right side of inserted column, increase column index - else if( column > columnIndex ) + else if( column > columnIndex ) // If on the right side of inserted column, increase column index { - // increase index by one + // Increment index position.columnIndex++; } } } - // relative sizes gets recalculated on Relayout - mRelativeSizes.InsertColumn( columnIndex ); - // inserting a column requires adjusting the width vectors - mFixedWidths.insert( mFixedWidths.begin() + columnIndex, 0 ); - mRelativeWidths.insert( mRelativeWidths.begin() + columnIndex, 0 ); + + // Expand column data array + mColumnData.Insert( mColumnData.Begin() + columnIndex, RowColumnData() ); + + // Sizes may have changed so relayout + mColumnDirty = true; RelayoutRequest(); } @@ -427,30 +486,34 @@ void TableView::DeleteColumn( unsigned int columnIndex ) void TableView::DeleteColumn( unsigned int columnIndex, std::vector& removed ) { RelayoutingLock lock( *this ); + + // Remove the column std::vector< CellData > lost; mCellData.DeleteColumn( columnIndex, lost ); - // need to update the cellinfos for the items that moved + + // Need to update the cell infos for the items that moved const unsigned int rowCount = mCellData.GetRows(); const unsigned int columnCount = mCellData.GetColumns(); + for( unsigned int row = 0; row < rowCount; ++row ) { for( unsigned int column = 0; column < columnCount; ++column ) { Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position; - // if cell is spanning and left side and spans to inserted column - if( ( position.columnSpan > 1 )&&( position.columnIndex <= columnIndex )&& + + // If cell is spanning and left side and spans to inserted column + if( ( position.columnSpan > 1 ) && ( position.columnIndex <= columnIndex ) && ( position.columnIndex + position.columnSpan > columnIndex ) ) { - // decrease span by one + // Decrement span if( position.columnSpan > 1 ) { position.columnSpan--; } } - // if on the right side of or at the inserted column, decrease column index - else if( column >= columnIndex ) + else if( column >= columnIndex ) // If on the right side of or at the inserted column, decrease column index { - // decrease index by one + // Decrement index if( position.columnIndex > 0 ) { position.columnIndex--; @@ -458,14 +521,18 @@ void TableView::DeleteColumn( unsigned int columnIndex, std::vector& remo } } } + // 0 rows, 1 column removed RemoveAndGetLostActors( lost, removed, 0u, 1u ); - // resize the data structures - mRelativeSizes.DeleteColumn( columnIndex ); - // deleting a column requires adjusting the width vectors - mFixedWidths.erase( mFixedWidths.begin() + columnIndex ); - mRelativeWidths.erase( mRelativeWidths.begin() + columnIndex ); - // relayout + + // Contract column data array + mColumnData.Erase( mColumnData.Begin() + columnIndex ); + + // Size may have changed so relayout + mColumnDirty = true; + // it is possible that the deletion of column leads to remove of child which might further lead to the change of FIT row + mRowDirty = true; + RelayoutRequest(); } @@ -478,36 +545,46 @@ void TableView::Resize( unsigned int rows, unsigned int columns ) void TableView::Resize( unsigned int rows, unsigned int columns, std::vector& removed ) { RelayoutingLock lock( *this ); + unsigned int oldRows = GetRows(); unsigned int oldColumns = GetColumns(); - // resize data array + + // Resize data array std::vector< CellData > lost; ResizeContainers( rows, columns, lost ); - // calculate if we lost rows or columns + + // Calculate if we lost rows unsigned int rowsRemoved = 0; unsigned int newRows = GetRows(); + if( oldRows < newRows ) { rowsRemoved = newRows - oldRows; } + + // Calculate if we lost columns unsigned int columnsRemoved = 0; unsigned int newColumns = GetColumns(); if( oldColumns < newColumns ) { rowsRemoved = newColumns - oldColumns; } + RemoveAndGetLostActors( lost, removed, rowsRemoved, columnsRemoved ); - // finally relayout once all actors are removed + + // Sizes may have changed so request a relayout + mRowDirty = true; + mColumnDirty = true; RelayoutRequest(); } void TableView::SetCellPadding( Size padding ) { - // if padding really changed + // If padding really changed if( padding != mPadding ) { mPadding = padding; - // do a relayout + RelayoutRequest(); } } @@ -517,184 +594,273 @@ Size TableView::GetCellPadding() return mPadding; } +void TableView::SetFitHeight( unsigned int rowIndex ) +{ + DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() ); + + if( mRowData[ rowIndex ].sizePolicy != Toolkit::TableView::FIT ) + { + mRowData[ rowIndex ].sizePolicy = Toolkit::TableView::FIT; + + mRowDirty = true; + RelayoutRequest(); + } +} + +bool TableView::IsFitHeight( unsigned int rowIndex ) const +{ + DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() ); + + return mRowData[ rowIndex ].sizePolicy == Toolkit::TableView::FIT; +} + +void TableView::SetFitWidth( unsigned int columnIndex ) +{ + DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() ); + + if( mColumnData[ columnIndex ].sizePolicy != Toolkit::TableView::FIT ) + { + mColumnData[ columnIndex ].sizePolicy = Toolkit::TableView::FIT; + + mColumnDirty = true; + RelayoutRequest(); + } +} + +bool TableView::IsFitWidth( unsigned int columnIndex ) const +{ + DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() ); + + return mColumnData[ columnIndex ].sizePolicy == Toolkit::TableView::FIT; +} + void TableView::SetFixedHeight( unsigned int rowIndex, float height ) { - DALI_ASSERT_ALWAYS( rowIndex < mFixedHeights.size() ); - // add the fixed height to the array of fixed heights - mFixedHeights[ rowIndex ] = height; - // remove the relative height of the same row - mRelativeHeights[ rowIndex ] = 0.f; - // relayout all cells, no lock needed as nothing added or removed + DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() ); + + RowColumnData& data = mRowData[ rowIndex ]; + data.size = height; + data.sizePolicy = Toolkit::TableView::FIXED; + + mRowDirty = true; RelayoutRequest(); } float TableView::GetFixedHeight( unsigned int rowIndex ) const { - DALI_ASSERT_ALWAYS( rowIndex < mFixedHeights.size() ); + DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() ); - return mFixedHeights[ rowIndex ]; + return mRowData[ rowIndex ].size; } -void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage ) +void TableView::SetFixedWidth( unsigned int columnIndex, float width ) { - DALI_ASSERT_ALWAYS( rowIndex < mRelativeHeights.size() ); - // add the relative height to the array of relative heights - mRelativeHeights[ rowIndex ] = heightPercentage; - // remove the fixed height of the same row - mFixedHeights[ rowIndex ] = 0.f; - // relayout all cells, no lock needed as nothing added or removed + DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() ); + + RowColumnData& data = mColumnData[ columnIndex ]; + data.size = width; + data.sizePolicy = Toolkit::TableView::FIXED; + + mColumnDirty = true; RelayoutRequest(); } -float TableView::GetRelativeHeight( unsigned int rowIndex ) const +float TableView::GetFixedWidth( unsigned int columnIndex ) const { - DALI_ASSERT_ALWAYS( rowIndex < mRelativeHeights.size() ); + DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() ); - return mRelativeHeights[ rowIndex ]; + return mColumnData[ columnIndex ].size; } -void TableView::SetFixedWidth( unsigned int columnIndex, float width ) +void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage ) { - DALI_ASSERT_ALWAYS( columnIndex < mFixedWidths.size() ); - // add the fixed width to the array of fixed column widths - mFixedWidths[ columnIndex ] = width; - // remove the relative width of the same column - mRelativeWidths[ columnIndex ] = 0.f; - // relayout all cells, no lock needed as nothing added or removed + DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() ); + + RowColumnData& data = mRowData[ rowIndex ]; + data.fillRatio = heightPercentage; + data.sizePolicy = Toolkit::TableView::RELATIVE; + + mRowDirty = true; RelayoutRequest(); } -float TableView::GetFixedWidth( unsigned int columnIndex ) const +float TableView::GetRelativeHeight( unsigned int rowIndex ) const { - DALI_ASSERT_ALWAYS( columnIndex < mFixedWidths.size() ); + DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() ); - return mFixedWidths[ columnIndex ]; + return mRowData[ rowIndex ].fillRatio; } void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentage ) { - DALI_ASSERT_ALWAYS( columnIndex < mRelativeWidths.size() ); - // add the relative widths to the array of relative widths - mRelativeWidths[ columnIndex ] = widthPercentage; - // remove the fixed width of the same column - mFixedWidths[ columnIndex ] = 0.f; - // relayout all cells, no lock needed as nothing added or removed + DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() ); + + RowColumnData& data = mColumnData[ columnIndex ]; + data.fillRatio = widthPercentage; + data.sizePolicy = Toolkit::TableView::RELATIVE; + + mColumnDirty = true; RelayoutRequest(); } float TableView::GetRelativeWidth( unsigned int columnIndex ) const { - DALI_ASSERT_ALWAYS( columnIndex < mRelativeWidths.size() ); + DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() ); - return mRelativeWidths[ columnIndex ]; + return mColumnData[ columnIndex ].fillRatio; } -void TableView::OnRelayout( const Vector2& size, ActorSizeContainer& container ) +void TableView::OnCalculateRelayoutSize( Dimension::Type dimension ) { - float fixedHeightsTotal = 0.0f; - float fixedWidthsTotal = 0.0f; + if( (dimension & Dimension::WIDTH) && mColumnDirty ) + { + /* + * FIXED and FIT have size in pixel + * Nothing to do with FIXED, as its value is assigned by user and will not get changed + * + * Need to update the size for FIT column here + */ + CalculateFitSizes( mColumnData, Dimension::WIDTH ); + + /* RELATIVE and FILL have size in ratio + * Their size in pixel is not available until we get the negotiated size for the whole table + * Nothing to do with RELATIVE, as its ratio is assigned by user and will not get changed + * + * Need to update the ratio for FILL column here + */ + CalculateFillSizes( mColumnData ); + + mFixedTotals.width = CalculateTotalFixedSize( mColumnData ); + } - // 1. update the relative sizes and calculate total fixed height and width - UpdateRelativeSizes( fixedHeightsTotal, fixedWidthsTotal ); + if( (dimension & Dimension::HEIGHT) && mRowDirty ) + { + // refer to the comment above + CalculateFitSizes( mRowData, Dimension::HEIGHT ); - // 2. go through the layout data and create constraints - float cumulatedFixedHeight = 0.0f; - float cumulatedRelativeHeight = 0.0f; + // refer to the comment above + CalculateFillSizes( mRowData ); - // iterate the table - const unsigned int rowCount = mCellData.GetRows(); - const unsigned int columnCount = mCellData.GetColumns(); - // float versions of the count + 1 to keep precision - const float maxRowPlusOne( rowCount + 1 ); - const float maxColumnPlusOne( columnCount + 1 ); - for( unsigned int row = 0; row < rowCount; ++row ) + mFixedTotals.height = CalculateTotalFixedSize( mRowData ); + } +} + +void TableView::OnLayoutNegotiated( float size, Dimension::Type dimension ) +{ + // Update the column sizes + if( (dimension & Dimension::WIDTH) && mColumnDirty ) { - // reset widths at the start of each row - float cumulatedFixedWidth = 0.0f; - float cumulatedRelativeWidth = 0.0f; - for( unsigned int column = 0; column < columnCount; ++column ) + float remainingSize = size - mFixedTotals.width; + if( remainingSize < 0.0f ) { - // check if this cell has an actor - Actor actor = mCellData[ row ][ column ].actor; - const Toolkit::TableView::CellPosition position = mCellData[ row ][ column ].position; - // if there is an actor and this is the main cell of the actor - // an actor can be in multiple cells if its row or columnspan is more than 1 - // we however must only lay out each actor only once - if( ( actor )&&( position.rowIndex == row )&&( position.columnIndex == column ) ) + remainingSize = 0.0f; + } + + // update every column position in ColumnData array + float cumulatedWidth = 0.0f; + for( unsigned int column = 0, columnCount = mCellData.GetColumns(); column < columnCount; ++column ) + { + if( mColumnData[ column ].sizePolicy == Toolkit::TableView::FILL || mColumnData[ column ].sizePolicy == Toolkit::TableView::RELATIVE) { - // anchor actor correctly + mColumnData[ column ].size = mColumnData[ column ].fillRatio * remainingSize; + } + + cumulatedWidth += mColumnData[ column ].size; + mColumnData[column].position = cumulatedWidth; + } + + mColumnDirty = false; + } + + // Update the row sizes + if( (dimension & Dimension::HEIGHT) && mRowDirty ) + { + float remainingSize = size - mFixedTotals.height; + if( remainingSize < 0.0f ) + { + remainingSize = 0.0f; + } + + // update every row position in RowData array + float cumulatedHeight = 0.0f; + for( unsigned int row = 0, rowCount = mCellData.GetRows(); row < rowCount; ++row ) + { + if( mRowData[ row ].sizePolicy == Toolkit::TableView::FILL || mRowData[ row ].sizePolicy == Toolkit::TableView::RELATIVE) + { + mRowData[ row ].size = mRowData[ row ].fillRatio * remainingSize; + } + + cumulatedHeight += mRowData[ row ].size; + mRowData[row].position = cumulatedHeight; + } + + mRowDirty = false; + } +} + +void TableView::OnSizeSet( const Vector3& size ) +{ + // If this table view is size negotiated by another actor or control, then the + // rows and columns must be recalculated or the new size will not take effect. + mRowDirty = mColumnDirty = true; + RelayoutRequest(); +} + +void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container ) +{ + // Go through the layout data + for( unsigned int row = 0, rowCount = mCellData.GetRows(); row < rowCount; ++row ) + { + for( unsigned int column = 0, columnCount = mCellData.GetColumns(); column < columnCount; ++column ) + { + CellData& cellData= mCellData[ row ][ column ]; + Actor& actor = cellData.actor; + const Toolkit::TableView::CellPosition position = cellData.position; + + // If there is an actor and this is the main cell of the actor. + // An actor can be in multiple cells if its row or column span is more than 1. + // We however must lay out each actor only once. + if( actor && position.rowIndex == row && position.columnIndex == column ) + { + // Anchor actor to top left of the cell actor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); actor.SetParentOrigin( ParentOrigin::TOP_LEFT ); - // remove old constraints - actor.RemoveConstraints(); - - // 1. set position - // get the row and column indices - float rowPos( position.rowIndex ); - float colPos( position.columnIndex ); - // constrain the actor position to be relative to the width and height of table - // minus the padding of course (padding is all around cells) - Vector2 relativePosition( cumulatedRelativeWidth, cumulatedRelativeHeight ); - // fixed height rows and fixed width cells are considered as padding so - // they are removed from the total size for relative - // for position only consider cumulated fixed rows and columns from top and left - Vector2 positionPadding( maxColumnPlusOne * mPadding.width + fixedWidthsTotal, - maxRowPlusOne * mPadding.height + fixedHeightsTotal ); - Vector2 fixedPosition( ( colPos + 1.0f ) * mPadding.width + cumulatedFixedWidth, - ( rowPos + 1.0f ) * mPadding.height + cumulatedFixedHeight ); - - Vector3 actorPosition( RelativeToSize( relativePosition, positionPadding, fixedPosition, size ) ); - actor.SetPosition( actorPosition ); - - // 2. set size - // constrain the actor size to be relative to the size of table - // get the relative size for this cell - Vector2 relativeSize( mRelativeSizes[ row ][ column ] ); - Vector2 fixedSize( mFixedWidths[ column ], mFixedHeights[ row ] ); - // if we span multiple cells, need to sum them all up, both fixed and relative parts - if( position.rowSpan > 1 ) + + Padding padding; + actor.GetPadding( padding ); + + float left = column > 0 ? mColumnData[column-1].position : 0.f; + float right = mColumnData[column+position.columnSpan-1].position; + float top = row > 0 ? mRowData[row-1].position : 0.f; + float bottom = mRowData[row+position.rowSpan-1].position; + + if( cellData.horizontalAlignment == HorizontalAlignment::LEFT ) { - for( unsigned int i = 1; i < position.rowSpan; ++i ) - { - // accumulate the height only - relativeSize.height += mRelativeSizes[ row + i ][ column ].height; - fixedSize.height += mFixedHeights[ row + i ]; - } + actor.SetX( left + mPadding.width + padding.left ); } - if( position.columnSpan > 1 ) + else if( cellData.horizontalAlignment == HorizontalAlignment::RIGHT ) { - for( unsigned int i = 1; i < position.columnSpan; ++i ) - { - // accumulate the width only - relativeSize.width += mRelativeSizes[ row ][ column + i ].width; - fixedSize.width += mFixedWidths[ column + i ]; - } + actor.SetX( right - mPadding.width - padding.right - actor.GetRelayoutSize( Dimension::WIDTH ) ); + } + else //if( cellData.horizontalAlignment == HorizontalAlignment::CENTER ) + { + actor.SetX( (left + right + padding.left - padding.right - actor.GetRelayoutSize( Dimension::WIDTH )) * 0.5f ); + } + + if( cellData.verticalAlignment == VerticalAlignment::TOP ) + { + actor.SetY( top + mPadding.height + padding.top ); + } + else if( cellData.verticalAlignment == VerticalAlignment::BOTTOM ) + { + actor.SetY( bottom - mPadding.height - padding.bottom - actor.GetRelayoutSize( Dimension::HEIGHT ) ); + } + else //if( cellData.verticalAlignment = VerticalAlignment::CENTER ) + { + actor.SetY( (top + bottom + padding.top - padding.bottom - actor.GetRelayoutSize( Dimension::HEIGHT )) * 0.5f ); } - // minus the padding from size (padding is all around cells) - // if item spans multiple columns or rows then less padding is added (default span is 1) - // fixed height rows and fixed width cells are considered as padding so they are removed - // from the total available size for relative cells - Vector2 sizePadding( maxColumnPlusOne * mPadding.width + fixedWidthsTotal, - maxRowPlusOne * mPadding.height + fixedHeightsTotal ); - // and added to the fixed size multiplied by the span of rows and columns - fixedSize.width += ( position.columnSpan - 1.0f ) * mPadding.width; - fixedSize.height += ( position.rowSpan - 1.0f ) * mPadding.height; - - Vector2 actorSize( RelativeToSize( relativeSize, sizePadding, fixedSize, size ) ); - actor.SetSize(actorSize.x, actorSize.y); - - // Relayout Children - Relayout ( actor, actorSize, container ); } - // for position we need to keep track of current fixed width and relative width - // increase for next column - cumulatedFixedWidth += mFixedWidths[ column ]; - cumulatedRelativeWidth += mRelativeSizes[ row ][ column ].width; } - // for position we need to keep track of current fixed height and relative height - // increase for next row - cumulatedFixedHeight += mFixedHeights[ row ]; - cumulatedRelativeHeight += mRelativeSizes[ row ][ 0 ].height; // all columns share same height } } @@ -717,35 +883,43 @@ void TableView::SetProperty( BaseObject* object, Property::Index index, const Pr TableView& tableViewImpl( GetImpl( tableView ) ); switch( index ) { - case Toolkit::TableView::PROPERTY_ROWS: + case Toolkit::TableView::Property::ROWS: { - if( value.Get() != tableViewImpl.GetRows() ) + int rows = 0; + if( value.Get( rows ) && rows >= 0 ) { - tableViewImpl.Resize( value.Get(), tableViewImpl.GetColumns() ); + if( static_cast(rows) != tableViewImpl.GetRows() ) + { + tableViewImpl.Resize( rows, tableViewImpl.GetColumns() ); + } } break; } - case Toolkit::TableView::PROPERTY_COLUMNS: + case Toolkit::TableView::Property::COLUMNS: { - if( value.Get() != tableViewImpl.GetColumns() ) + int columns = 0; + if( value.Get( columns ) && columns >= 0 ) { - tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get() ); + if( static_cast( columns ) != tableViewImpl.GetColumns() ) + { + tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get() ); + } } break; } - case Toolkit::TableView::PROPERTY_CELL_PADDING: + case Toolkit::TableView::Property::CELL_PADDING: { tableViewImpl.SetCellPadding( value.Get() ); break; } - case Toolkit::TableView::PROPERTY_LAYOUT_ROWS: + case Toolkit::TableView::Property::LAYOUT_ROWS: { - SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, value ); + SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, &TableView::SetFitHeight, value ); break; } - case Toolkit::TableView::PROPERTY_LAYOUT_COLUMNS: + case Toolkit::TableView::Property::LAYOUT_COLUMNS: { - SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, value ); + SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, &TableView::SetFitWidth, value ); break; } } @@ -763,27 +937,27 @@ Property::Value TableView::GetProperty( BaseObject* object, Property::Index inde TableView& tableViewImpl( GetImpl( tableView ) ); switch( index ) { - case Toolkit::TableView::PROPERTY_ROWS: + case Toolkit::TableView::Property::ROWS: { - value = tableViewImpl.GetRows(); + value = static_cast( tableViewImpl.GetRows() ); break; } - case Toolkit::TableView::PROPERTY_COLUMNS: + case Toolkit::TableView::Property::COLUMNS: { - value = tableViewImpl.GetColumns(); + value = static_cast( tableViewImpl.GetColumns() ); break; } - case Toolkit::TableView::PROPERTY_CELL_PADDING: + case Toolkit::TableView::Property::CELL_PADDING: { value = tableViewImpl.GetCellPadding(); break; } - case Toolkit::TableView::PROPERTY_LAYOUT_ROWS: + case Toolkit::TableView::Property::LAYOUT_ROWS: { value = tableViewImpl.GetRowHeightsPropertyValue(); break; } - case Toolkit::TableView::PROPERTY_LAYOUT_COLUMNS: + case Toolkit::TableView::Property::LAYOUT_COLUMNS: { value = tableViewImpl.GetColumnWidthsPropertyValue(); break; @@ -802,59 +976,88 @@ void TableView::OnControlChildAdd( Actor& child ) return; } + // Test properties on actor + HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT; + VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP; + if( child.GetPropertyIndex( CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME ) != Property::INVALID_INDEX ) + { + std::string value = child.GetProperty( child.GetPropertyIndex(CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME) ).Get(); + Scripting::GetEnumeration< HorizontalAlignment::Type >( value.c_str(), + HORIZONTAL_ALIGNMENT_STRING_TABLE, + HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT, + horizontalAlignment ); + } + if( child.GetPropertyIndex( CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME ) != Property::INVALID_INDEX ) + { + std::string value = child.GetProperty( child.GetPropertyIndex(CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME) ).Get(); + Scripting::GetEnumeration< VerticalAlignment::Type >( value.c_str(), + VERTICAL_ALIGNMENT_STRING_TABLE, + VERTICAL_ALIGNMENT_STRING_TABLE_COUNT, + verticalAlignment ); + } + + Toolkit::TableView::CellPosition cellPosition; - if( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX ) + if( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX ) { - cellPosition.rowSpan = static_cast( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) ).Get() ); + cellPosition.rowSpan = static_cast( child.GetProperty( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) ).Get() ); } - if( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX ) + + if( child.GetPropertyIndex(COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX ) { - cellPosition.columnSpan = static_cast( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) ).Get() ); + cellPosition.columnSpan = static_cast( child.GetProperty( child.GetPropertyIndex(COLUMN_SPAN_PROPERTY_NAME) ).Get() ); } - if( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) != Property::INVALID_INDEX ) + + if( child.GetPropertyIndex(CELL_INDEX_PROPERTY_NAME) != Property::INVALID_INDEX ) { - Vector2 indices = child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) ).Get(); + Vector2 indices = child.GetProperty( child.GetPropertyIndex(CELL_INDEX_PROPERTY_NAME) ).Get(); cellPosition.rowIndex = static_cast( indices.x ); cellPosition.columnIndex = static_cast( indices.y ); AddChild( child, cellPosition ); - // donot continue + SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment); + + // Do not continue return; } - // check if we're already laying out this child somewhere on the table - // walk through the layout data + // Find the first available cell to store the actor in const unsigned int rowCount = mCellData.GetRows(); const unsigned int columnCount = mCellData.GetColumns(); - // child not yet laid out, find the first free slot for( unsigned int row = 0; row < rowCount; ++row ) { for( unsigned int column = 0; column < columnCount; ++column ) { - // no actor means free cell if( !(mCellData[ row ][ column ].actor) ) { - // put the actor in the cell + // Put the actor in the cell CellData data; data.actor = child; data.position.columnIndex = column; data.position.rowIndex = row; + data.horizontalAlignment = horizontalAlignment; + data.verticalAlignment = verticalAlignment; mCellData[ row ][ column ] = data; + + // Don't continue RelayoutRequest(); - // don' continue return; } } } - // still here, no room for the poor child so increase the array. Need a new row - ResizeContainers( rowCount + 1, columnCount ); - // put the actor to the first cell of the new row + + // No empty cells, so increase size of the table + unsigned int newColumnCount = ( columnCount > 0 ) ? columnCount : 1; + ResizeContainers( rowCount + 1, newColumnCount ); + + // Put the actor in the first cell of the new row CellData data; data.actor = child; data.position.rowIndex = rowCount; data.position.columnIndex = 0; + data.horizontalAlignment = horizontalAlignment; + data.verticalAlignment = verticalAlignment; mCellData[ rowCount ][ 0 ] = data; - // finally relayout the table RelayoutRequest(); } @@ -872,9 +1075,11 @@ void TableView::OnControlChildRemove( Actor& child ) } TableView::TableView( unsigned int initialRows, unsigned int initialColumns ) -: Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ), +: Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ), mCellData( initialRows, initialColumns ), - mLayoutingChild( false ) + mLayoutingChild( false ), + mRowDirty( true ), // Force recalculation first time + mColumnDirty( true ) { SetKeyboardNavigationSupport( true ); ResizeContainers( initialRows, initialColumns ); @@ -896,13 +1101,12 @@ void TableView::ResizeContainers( unsigned int rows, unsigned int columns ) void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector& removed ) { + // Resize cell data mCellData.Resize( rows, columns, removed ); - // we dont care if these go smaller, data will be regenerated or is not needed anymore - mRelativeSizes.Resize( rows, columns ); - mFixedHeights.resize( rows ); - mRelativeHeights.resize( rows ); - mFixedWidths.resize( columns ); - mRelativeWidths.resize( columns ); + + // We don't care if these go smaller, data will be regenerated or is not needed anymore + mRowData.Resize( rows ); + mColumnData.Resize( columns ); } void TableView::RemoveAndGetLostActors( const std::vector& lost, std::vector& removed, @@ -953,7 +1157,7 @@ void TableView::RemoveAndGetLostActors( const std::vector& lost, std:: } } -bool TableView::RemoveAllInstances( Actor child ) +bool TableView::RemoveAllInstances( const Actor& child ) { bool found = false; // walk through the layout data @@ -974,130 +1178,49 @@ bool TableView::RemoveAllInstances( Actor child ) return found; } -void TableView::UpdateRelativeSizes( float& fixedHeightsTotal, float& fixedWidthsTotal ) -{ - // 1. check all the fixed heights and widths to know how much size they take in total - // as well as the relative heights and widths to know how much is left for the 'fill' cells - unsigned int fixedRowCount = 0; - unsigned int relativeRowCount = 0; - float relativeHeightsTotal = 0.0f; - const unsigned int rowCount = mCellData.GetRows(); - for( unsigned int row = 0; row < rowCount; ++row ) - { - if( mFixedHeights[ row ] > 0.0f ) - { - ++fixedRowCount; - fixedHeightsTotal += mFixedHeights[ row ]; - } - if( mRelativeHeights[ row ] > 0.0f ) - { - ++relativeRowCount; - relativeHeightsTotal += mRelativeHeights[ row ]; - } - } - unsigned int fixedColumnCount = 0; - unsigned int relativeColumnCount = 0; - const unsigned int columnCount = mCellData.GetColumns(); - float relativeWidthsTotal = 0.0f; - for( unsigned int column = 0; column < columnCount; ++column ) - { - if( mFixedWidths[ column ] > 0.0f ) - { - ++fixedColumnCount; - fixedWidthsTotal += mFixedWidths[ column ]; - } - if( mRelativeWidths[ column ] > 0.0f ) - { - ++relativeColumnCount; - relativeWidthsTotal += mRelativeWidths[ column ]; - } - } - - // 2. cap the relative width and height totals to 100% - if( relativeHeightsTotal > 1.0f ) - { - relativeHeightsTotal = 1.0f; - } - if( relativeWidthsTotal > 1.0f ) - { - relativeWidthsTotal = 1.0f; - } - - // 3. create a table of relative sizes so we can lookup for cells that span multiple rows & colums - const float fillRowCount( rowCount - relativeRowCount - fixedRowCount ); - const float fillColumnCount( columnCount - relativeColumnCount - fixedColumnCount ); - - // walk through the data containers - for( unsigned int row = 0; row < rowCount; ++row ) - { - float relativeHeight = 0.0f; - // if we have a fixed height, relative height is 0 - if( mFixedHeights[ row ] > 0.0f ) - { - relativeHeight = 0.0f; - } - // else if we're given a specific row height %, use that - else if( mRelativeHeights[ row ] > 0.0f ) - { - relativeHeight = mRelativeHeights[ row ]; - } - // else if there are fill rows - else if( fillRowCount > 0 ) - { - // this is a 'fill' row. it gets the remainder of the 100% divided evenly between 'fill' rows - relativeHeight = (1.0f - relativeHeightsTotal ) / fillRowCount; - } - for( unsigned int column = 0; column < columnCount; ++column ) - { - float relativeWidth = 0.0f; - // if we have a fixed width, relative width is 0 - if( mFixedWidths[ column ] > 0.0f ) - { - relativeWidth = 0.0f; - } - // else if we're given a specific column width %, use that - else if( mRelativeWidths[ column ] > 0.0f ) - { - relativeWidth = mRelativeWidths[ column ]; - } - // else if there are fill columns - else if( fillColumnCount > 0 ) - { - // this is a 'fill' column. it gets the remainder of the 100% divided evenly between 'fill' columns - relativeWidth = (1.0f - relativeWidthsTotal ) / fillColumnCount; - } - // store the value - mRelativeSizes[ row ][ column ] = Size( relativeWidth, relativeHeight ); - } - } -} - void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl, void(TableView::*funcFixed)(unsigned int, float), void(TableView::*funcRelative)(unsigned int, float), + void(TableView::*funcFit)(unsigned int), const Property::Value& value ) { - if( Property::MAP == value.GetType() ) + Property::Map* map = value.GetMap(); + if( map ) { - Property::Map map = value.Get(); - unsigned int rowIndex(0); - for ( unsigned int i = 0, count = map.Count(); i < count; ++i ) + unsigned int index(0); + for ( unsigned int i = 0, count = map->Count(); i < count; ++i ) { - Property::Value& item = map.GetValue(i); + Property::Value& item = map->GetValue(i); + Property::Map* childMap = item.GetMap(); - if( std::istringstream(map.GetKey(i)) >> rowIndex // the key is a number - && Property::MAP == item.GetType()) + std::istringstream( map->GetKey(i) ) >> index; + if( childMap ) { - if( item.HasKey( "policy" ) && item.HasKey( "value" ) ) + Property::Value* policy = childMap->Find( "policy" ); + Property::Value* value = childMap->Find( "value" ); + if( policy && value ) { - Toolkit::TableView::LayoutPolicy policy = Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( item.GetValue("policy").Get(), LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ); - if( policy == Toolkit::TableView::Fixed ) - { - (tableViewImpl.*funcFixed)( rowIndex, item.GetValue("value").Get() ); - } - else if( policy == Toolkit::TableView::Relative ) + std::string policyValue; + policy->Get( policyValue ); + Toolkit::TableView::LayoutPolicy policy; + if( Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( policyValue.c_str(), + LAYOUT_POLICY_STRING_TABLE, + LAYOUT_POLICY_STRING_TABLE_COUNT, + policy ) ) { - (tableViewImpl.*funcRelative)( rowIndex, item.GetValue("value").Get() ); + if( policy == Toolkit::TableView::FIXED ) + { + (tableViewImpl.*funcFixed)( index, value->Get() ); + } + else if( policy == Toolkit::TableView::RELATIVE ) + { + (tableViewImpl.*funcRelative)( index, value->Get() ); + } + else if( policy == Toolkit::TableView::FIT ) + { + (tableViewImpl.*funcFit)( index ); + } + // do nothing for FILL policy } } } @@ -1108,41 +1231,69 @@ void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl, Property::Value TableView::GetRowHeightsPropertyValue() { Property::Map map; - GetMapPropertyValue( mFixedHeights, mRelativeHeights, map); + GetMapPropertyValue( mRowData, map); return Property::Value(map); } Property::Value TableView::GetColumnWidthsPropertyValue() { Property::Map map; - GetMapPropertyValue( mFixedWidths, mRelativeWidths, map); + GetMapPropertyValue( mColumnData, map); return Property::Value(map); } -void TableView::GetMapPropertyValue( const std::vector& fixedSize, const std::vector& relativeSize, Property::Map& map ) +void TableView::GetMapPropertyValue( const RowColumnArray& data, Property::Map& map ) { - std::string fixedPolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::Fixed, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) ); - std::string relativePolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::Relative, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) ); - - size_t count = fixedSize.size(); - for( size_t index = 0; index < count; index++ ) + const char* fixedPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIXED, + LAYOUT_POLICY_STRING_TABLE, + LAYOUT_POLICY_STRING_TABLE_COUNT ); + const char* relativePolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::RELATIVE, + LAYOUT_POLICY_STRING_TABLE, + LAYOUT_POLICY_STRING_TABLE_COUNT ); + const char* fillPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FILL, + LAYOUT_POLICY_STRING_TABLE, + LAYOUT_POLICY_STRING_TABLE_COUNT ); + const char* fitPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIT, + LAYOUT_POLICY_STRING_TABLE, + LAYOUT_POLICY_STRING_TABLE_COUNT ); + + const RowColumnArray::SizeType count = data.Size(); + for( RowColumnArray::SizeType i = 0; i < count; i++ ) { - if( ! EqualsZero( fixedSize[index] ) ) - { - Property::Map item; - item[ "policy" ] = fixedPolicy; - item[ "value" ] = fixedSize[index]; + const RowColumnData& dataInstance = data[ i ]; - map[ static_cast( &(std::ostringstream() << index ) )->str() ] = item; - } - else if( ! EqualsZero( relativeSize[index] ) ) + Property::Map item; + switch( dataInstance.sizePolicy ) { - Property::Map item; - item[ "policy" ] = relativePolicy; - item[ "value" ] = relativeSize[index]; - - map[ static_cast( &(std::ostringstream() << index ) )->str() ] = item; + case Toolkit::TableView::FIXED: + { + item[ "policy" ] = fixedPolicy; + item[ "value" ] = dataInstance.size; + break; + } + case Toolkit::TableView::RELATIVE: + { + item[ "policy" ] = relativePolicy; + item[ "value" ] = dataInstance.fillRatio; + break; + } + case Toolkit::TableView::FIT: + { + item[ "policy" ] = fitPolicy; + item[ "value" ] = 0.f; + break; + } + case Toolkit::TableView::FILL: + default: + { + item[ "policy" ] = fillPolicy; + item[ "value" ] = 0.f; + break; + } } + std::ostringstream ss; + ss << i; + map[ ss.str() ] = item; } } @@ -1151,7 +1302,7 @@ TableView::~TableView() // nothing to do } -Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled) +Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled) { Actor nextFocusableActor; @@ -1174,7 +1325,7 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolki switch ( direction ) { - case Toolkit::Control::Left: + case Toolkit::Control::KeyboardFocus::LEFT: { if(--currentColumn < 0) { @@ -1187,7 +1338,7 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolki } break; } - case Toolkit::Control::Right: + case Toolkit::Control::KeyboardFocus::RIGHT: { if(++currentColumn > numberOfColumns - 1) { @@ -1200,7 +1351,7 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolki } break; } - case Toolkit::Control::Up: + case Toolkit::Control::KeyboardFocus::UP: { if(--currentRow < 0) { @@ -1209,7 +1360,8 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolki } break; } - case Toolkit::Control::Down: + case Toolkit::Control::KeyboardFocus::DOWN: + { if(++currentRow > numberOfRows - 1) { @@ -1236,6 +1388,234 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolki return nextFocusableActor; } +Vector3 TableView::GetNaturalSize() +{ + // Natural size is the size of all fixed cell widths or heights. This ignores cells with relative heights. + return Vector3( mFixedTotals.width, mFixedTotals.height, 1.0f ); +} + +float TableView::CalculateChildSize( const Actor& child, Dimension::Type dimension ) +{ + Toolkit::TableView::CellPosition position; + if( FindChildPosition( child, position) ) + { + switch( dimension ) + { + case Dimension::WIDTH: + { + float cellSize = 0.0f; + cellSize = mColumnData[position.columnIndex+position.columnSpan-1].position + - (position.columnIndex > 0 ? mColumnData[position.columnIndex-1].position : 0.f) + - mPadding.width * 2.0f; + + if( cellSize < 0.0f ) + { + cellSize = 0.0f; + } + + return cellSize; + } + + case Dimension::HEIGHT: + { + float cellSize = 0.0f; + + cellSize = mRowData[position.rowIndex+position.rowSpan-1].position + - (position.rowIndex > 0 ? mRowData[position.rowIndex-1].position : 0.f) + - mPadding.height * 2.0f; + + if( cellSize < 0.0f ) + { + cellSize = 0.0f; + } + + return cellSize; + } + default: + { + return 0.0f; + } + } + } + + return 0.0f; // Child not found +} + +bool TableView::RelayoutDependentOnChildren( Dimension::Type dimension ) +{ + if ( Control::RelayoutDependentOnChildren( dimension ) ) + { + return true; + } + + return FindFit( mRowData ) || FindFit( mColumnData ); +} + +void TableView::SetCellAlignment( Toolkit::TableView::CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical ) +{ + // Check if we need to expand our data array + if( position.rowIndex >= mCellData.GetRows() ) + { + // Only adding new rows + ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() ); + } + + if( position.columnIndex >= mCellData.GetColumns() ) + { + // Only adding new columns + ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 ); + } + + // Set the alignment of the cell + CellData& data = mCellData[ position.rowIndex ][ position.columnIndex ]; + data.horizontalAlignment = horizontal; + data.verticalAlignment = vertical; +} + +void TableView::CalculateFillSizes( RowColumnArray& data ) +{ + // First pass: Count number of fill entries and calculate used relative space + Dali::Vector< RowColumnData* > fillData; + float relativeTotal = 0.0f; + + const unsigned int dataCount = data.Size(); + + for( unsigned int i = 0; i < dataCount; ++i ) + { + RowColumnData& dataInstance = data[ i ]; + + if( dataInstance.sizePolicy == Toolkit::TableView::RELATIVE ) + { + relativeTotal += dataInstance.fillRatio; + } + else if(dataInstance.sizePolicy == Toolkit::TableView::FILL) + { + fillData.PushBack( &dataInstance ); + } + } + + // Second pass: Distribute remaining relative space + const unsigned int fillCount = fillData.Size(); + if( fillCount > 0 ) + { + if( relativeTotal > 1.0f ) + { + relativeTotal = 1.0f; + } + + const float evenFillRatio = (1.0f - relativeTotal ) / fillCount; + + for( unsigned int i = 0; i < fillCount; ++i ) + { + fillData[ i ]->fillRatio = evenFillRatio; + } + } +} + +float TableView::CalculateTotalFixedSize( const RowColumnArray& data ) +{ + float totalSize = 0.0f; + + const unsigned int dataCount = data.Size(); + + for( unsigned int i = 0; i < dataCount; ++i ) + { + const RowColumnData& dataInstance = data[ i ]; + + switch( dataInstance.sizePolicy ) + { + // we have absolute size to FIXED and FIT column/row and relative size for RELATIVE and FILL column/row + case Toolkit::TableView::FIXED: + case Toolkit::TableView::FIT: + { + totalSize += dataInstance.size; + break; + } + + default: + { + break; + } + } + } + + return totalSize; +} + +Vector2 TableView::GetCellPadding( Dimension::Type dimension ) +{ + switch( dimension ) + { + case Dimension::WIDTH: + { + return Vector2( mPadding.x, mPadding.x ); + } + case Dimension::HEIGHT: + { + return Vector2( mPadding.y, mPadding.y ); + } + default: + { + break; + } + } + + return Vector2(); +} + +void TableView::CalculateFitSizes( RowColumnArray& data, Dimension::Type dimension ) +{ + Vector2 cellPadding = GetCellPadding( dimension ); + + const unsigned int dataCount = data.Size(); + + for( unsigned int i = 0; i < dataCount; ++i ) + { + RowColumnData& dataInstance = data[ i ]; + + if( dataInstance.sizePolicy == Toolkit::TableView::FIT ) + { + // Find the size of the biggest actor in the row or column + float maxActorHeight = 0.0f; + + unsigned int fitCount = ( dimension == Dimension::WIDTH ) ? mCellData.GetRows() : mCellData.GetColumns(); + + for( unsigned int j = 0; j < fitCount; ++j ) + { + unsigned int row = ( dimension == Dimension::WIDTH ) ? j : i; + unsigned int column = ( dimension == Dimension::WIDTH ) ? i : j; + DALI_ASSERT_DEBUG( row < mCellData.GetRows() ); + DALI_ASSERT_DEBUG( column < mCellData.GetColumns() ); + + const CellData& cellData = mCellData[ row ][ column ]; + const Actor& actor = cellData.actor; + if( actor ) + { + if( FitToChild( actor, dimension ) && ( dimension == Dimension::WIDTH ) ? ( cellData.position.columnSpan == 1 ) : ( cellData.position.rowSpan == 1 ) ) + { + maxActorHeight = std::max( maxActorHeight, actor.GetRelayoutSize( dimension ) + cellPadding.x + cellPadding.y ); + } + } + } + + dataInstance.size = maxActorHeight; + } + } +} + +bool TableView::FindFit( const RowColumnArray& data ) +{ + for( unsigned int i = 0, count = data.Size(); i < count; ++i ) + { + if( data[ i ].sizePolicy == Toolkit::TableView::FIT ) + { + return true; + } + } + + return false; +} + } // namespace Internal } // namespace Toolkit