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=94ba40297ca993de2025564da1b864b9faccf730;hp=d702ced3a40557789b6275d323204c668b1a1670;hb=c46d8cb79f848d9e1fda57a46a987aadea57a7cd;hpb=e2eda444afbe82e9591fe198eef339227f90a616 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 d702ced..94ba402 100644 --- a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp +++ b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp @@ -1,83 +1,56 @@ -// -// Copyright (c) 2014 Samsung Electronics Co., Ltd. -// -// Licensed under the Flora License, Version 1.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://floralicense.org/license/ -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ // CLASS HEADER -#include "dali-toolkit/internal/controls/table-view/table-view-impl.h" -#include +#include // EXTERNAL INCLUDES +#include #include -#include +#include +#include +#include +#include +#include using namespace Dali; -using namespace std; namespace { -// Type registration -BaseHandle Create() -{ - return Toolkit::TableView::New(0, 0); -} -TypeRegistration mType( typeid(Toolkit::TableView), typeid(Toolkit::Control), Create ); - -const float DEFAULT_CONSTRAINT_DURATION = 0.0f; - /** - * Constraint that sets a child property relative to parents Width or Height + * @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 */ -struct RelativeToWidthOrHeight -{ - /** - * Constraint that is relative (%) to parent width/height and applies a - * unit based padding before the relative calculation. - * @param scale of parent minus padding between 0 and 1 - * @param padding in world coordinate units - * @param fixed part in world coordinate units - */ - RelativeToWidthOrHeight( float scale, float padding, float fixed ) - : mScaleFactor( scale ), - mPadding( padding ), - mFixed( fixed ) - { - } - - inline float operator()( const float& parentWidthOrHeight ) - { - return mFixed + ( parentWidthOrHeight - mPadding ) * mScaleFactor; - } - - float operator()( const float& current, - const PropertyInput& parentWidthOrHeight ) - { - return operator()( parentWidthOrHeight.GetFloat() ); - } - - float mScaleFactor; - float mPadding; - float mFixed; -}; +bool FitToChild( Actor actor, Dimension::Type dimension ) +{ + return actor.GetResizePolicy( dimension ) != ResizePolicy::FILL_TO_PARENT && actor.GetRelayoutSize( dimension ) > 0.0f; +} #if defined(DEBUG_ENABLED) // debugging support, very useful when new features are added or bugs are hunted down // currently not called from code so compiler will optimize these away, kept here for future debugging -#define TABLEVIEW_TAG "DALI Toolkit::TableView" -#define TV_LOG(fmt, args...) LOG(LOG_INFO, TABLEVIEW_TAG, fmt, ## args) +#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() ); @@ -88,11 +61,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 ); } @@ -117,7 +92,7 @@ void PrintArray( Array2d& array ) } // debugging support, very useful when new features are added or bugs are hunted down // currently not called from code so compiler will optimize these away, kept here for future debugging -void PrintVector( vector& array ) +void PrintVector( std::vector& array ) { TV_LOG( "vector, size [%d]\n", array.size() ); // print values @@ -127,6 +102,7 @@ void PrintVector( vector& array ) } TV_LOG( "\n" ); } +#endif // defined(TABLEVIEW_DEBUG) #endif // defined(DEBUG_ENABLED) } // namespace @@ -140,6 +116,58 @@ namespace Toolkit namespace Internal { +namespace +{ + +// Type registration +BaseHandle Create() +{ + 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_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellIndex", VECTOR2, CELL_INDEX ) +DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "rowSpan", FLOAT, ROW_SPAN ) +DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "columnSpan", FLOAT, COLUMN_SPAN ) +DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellHorizontalAlignment", STRING, CELL_HORIZONTAL_ALIGNMENT ) +DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellVerticalAlignment", STRING, CELL_VERTICAL_ALIGNMENT ) + +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] ); + +const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] = +{ + {"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] ); + +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] ); + +} // Unnamed namespace + Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns ) { // Create the implementation, temporarily owned by this handle on stack @@ -155,97 +183,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 ); @@ -253,12 +278,20 @@ Actor TableView::RemoveChildAt( Toolkit::TableView::CellPosition position ) if( child ) { RelayoutingLock lock( *this ); - // Remove the child, this will trigger a call to OnControlChildRemove + // Remove the child, this will trigger a call to OnChildRemove Self().Remove( child ); // 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(); } } @@ -266,185 +299,212 @@ 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(); } void TableView::DeleteRow( unsigned int rowIndex ) { - vector< Actor > ignored; + std::vector< Actor > ignored; DeleteRow( rowIndex, ignored ); } -void TableView::DeleteRow( unsigned int rowIndex, vector& removed ) +void TableView::DeleteRow( unsigned int rowIndex, std::vector& removed ) { RelayoutingLock lock( *this ); - vector< CellData > lost; + + // 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 - if( position.rowIndex > 1 ) + // Decrement index + if( position.rowIndex > 0 ) { position.rowIndex--; } } } } + // 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(); } void TableView::DeleteColumn( unsigned int columnIndex ) { - vector< Actor > ignored; + std::vector< Actor > ignored; DeleteColumn( columnIndex, ignored ); } -void TableView::DeleteColumn( unsigned int columnIndex, vector& removed ) +void TableView::DeleteColumn( unsigned int columnIndex, std::vector& removed ) { RelayoutingLock lock( *this ); - vector< CellData > lost; + + // 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--; @@ -452,56 +512,70 @@ void TableView::DeleteColumn( unsigned int columnIndex, vector& removed ) } } } + // 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(); } void TableView::Resize( unsigned int rows, unsigned int columns ) { - vector< Actor > ignored; + std::vector< Actor > ignored; Resize( rows, columns, ignored ); } -void TableView::Resize( unsigned int rows, unsigned int columns, vector& removed ) +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 - vector< CellData > lost; + + // 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(); } } @@ -511,219 +585,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; - // 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; - // 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; - // 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; - // 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::SetLayoutAnimationDuration( float duration ) +void TableView::OnCalculateRelayoutSize( Dimension::Type dimension ) { - mConstraintDuration = duration; -} + 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 ); + } -float TableView::GetLayoutAnimationDuration() -{ - return mConstraintDuration; + if( (dimension & Dimension::HEIGHT) && mRowDirty ) + { + // refer to the comment above + CalculateFitSizes( mRowData, Dimension::HEIGHT ); + + // refer to the comment above + CalculateFillSizes( mRowData ); + + mFixedTotals.height = CalculateTotalFixedSize( mRowData ); + } } -void TableView::OnRelaidOut( Vector2 size, ActorSizeContainer& container ) +void TableView::OnLayoutNegotiated( float size, Dimension::Type dimension ) { - float fixedHeightsTotal = 0.0f; - float fixedWidthsTotal = 0.0f; + // Update the column sizes + if( (dimension & Dimension::WIDTH) && mColumnDirty ) + { + float remainingSize = size - mFixedTotals.width; + if( remainingSize < 0.0f ) + { + remainingSize = 0.0f; + } - // 1. update the relative sizes and calculate total fixed height and width - UpdateRelativeSizes( fixedHeightsTotal, fixedWidthsTotal ); + // 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) + { + mColumnData[ column ].size = mColumnData[ column ].fillRatio * remainingSize; + } - // 2. go through the layout data and create constraints - float cumulatedFixedHeight = 0.0f; - float cumulatedRelativeHeight = 0.0f; + cumulatedWidth += mColumnData[ column ].size; + mColumnData[column].position = cumulatedWidth; + } - // 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 ) + mColumnDirty = false; + } + + // Update the row sizes + if( (dimension & Dimension::HEIGHT) && mRowDirty ) { - // 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.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 ) { - // 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 ) ) + 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 correctly + // 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 ); - - Constraint widthConstraint = Constraint::New( Actor::POSITION_X, - ParentSource( Actor::SIZE_WIDTH ), - RelativeToWidthOrHeight( relativePosition.x, positionPadding.x, fixedPosition.x ) ); - - Constraint heightConstraint = Constraint::New( Actor::POSITION_Y, - ParentSource( Actor::SIZE_HEIGHT ), - RelativeToWidthOrHeight( relativePosition.y, positionPadding.y, fixedPosition.y ) ); - - widthConstraint.SetApplyTime( mConstraintDuration ); - heightConstraint.SetApplyTime( mConstraintDuration ); - - // bake constrained position value if constraint is removed - widthConstraint.SetRemoveAction( Constraint::Bake ); - heightConstraint.SetRemoveAction( Constraint::Bake ); - - actor.ApplyConstraint( widthConstraint ); - actor.ApplyConstraint( heightConstraint ); - - // 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; - - RelativeToWidthOrHeight relativeWidthFunctor( relativeSize.x, sizePadding.x, fixedSize.x ); - RelativeToWidthOrHeight relativeHeightFunctor( relativeSize.y, sizePadding.y, fixedSize.y ); - - widthConstraint = Constraint::New( Actor::SIZE_WIDTH, - ParentSource( Actor::SIZE_WIDTH ), - relativeWidthFunctor ); - - heightConstraint = Constraint::New( Actor::SIZE_HEIGHT, - ParentSource( Actor::SIZE_HEIGHT ), - relativeHeightFunctor ); - - widthConstraint.SetApplyTime( mConstraintDuration ); - heightConstraint.SetApplyTime( mConstraintDuration ); - - // bake constrained size value if constraint is removed - widthConstraint.SetRemoveAction( Constraint::Bake ); - heightConstraint.SetRemoveAction( Constraint::Bake ); - - actor.ApplyConstraint( widthConstraint ); - actor.ApplyConstraint( heightConstraint ); - - // Relayout Children - Relayout ( actor, Vector2( relativeWidthFunctor( size.width ), relativeHeightFunctor( size.height ) ), 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 } } @@ -737,50 +865,197 @@ unsigned int TableView::GetColumns() return mCellData.GetColumns(); } -void TableView::OnControlChildAdd( Actor& child ) +void TableView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) { + Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) ); + + if( tableView ) + { + TableView& tableViewImpl( GetImpl( tableView ) ); + switch( index ) + { + case Toolkit::TableView::Property::ROWS: + { + int rows = 0; + if( value.Get( rows ) && rows >= 0 ) + { + if( static_cast(rows) != tableViewImpl.GetRows() ) + { + tableViewImpl.Resize( rows, tableViewImpl.GetColumns() ); + } + } + break; + } + case Toolkit::TableView::Property::COLUMNS: + { + int columns = 0; + if( value.Get( columns ) && columns >= 0 ) + { + if( static_cast( columns ) != tableViewImpl.GetColumns() ) + { + tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get() ); + } + } + break; + } + case Toolkit::TableView::Property::CELL_PADDING: + { + tableViewImpl.SetCellPadding( value.Get() ); + break; + } + case Toolkit::TableView::Property::LAYOUT_ROWS: + { + SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, &TableView::SetFitHeight, value ); + break; + } + case Toolkit::TableView::Property::LAYOUT_COLUMNS: + { + SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, &TableView::SetFitWidth, value ); + break; + } + } + } +} + +Property::Value TableView::GetProperty( BaseObject* object, Property::Index index ) +{ + Property::Value value; + + Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) ); + + if( tableView ) + { + TableView& tableViewImpl( GetImpl( tableView ) ); + switch( index ) + { + case Toolkit::TableView::Property::ROWS: + { + value = static_cast( tableViewImpl.GetRows() ); + break; + } + case Toolkit::TableView::Property::COLUMNS: + { + value = static_cast( tableViewImpl.GetColumns() ); + break; + } + case Toolkit::TableView::Property::CELL_PADDING: + { + value = tableViewImpl.GetCellPadding(); + break; + } + case Toolkit::TableView::Property::LAYOUT_ROWS: + { + value = tableViewImpl.GetRowHeightsPropertyValue(); + break; + } + case Toolkit::TableView::Property::LAYOUT_COLUMNS: + { + value = tableViewImpl.GetColumnWidthsPropertyValue(); + break; + } + } + } + + return value; +} + +void TableView::OnChildAdd( Actor& child ) +{ + Control::OnChildAdd( child ); + if( mLayoutingChild ) { // we're in the middle of laying out children so no point doing anything here return; } - // check if we're already laying out this child somewhere on the table - // walk through the layout data + + // Check child properties on actor to decide its position inside the table + HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT; + VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP; + + if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ) != Property::NONE ) + { + std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ).Get(); + Scripting::GetEnumeration< HorizontalAlignment::Type >( value.c_str(), + HORIZONTAL_ALIGNMENT_STRING_TABLE, + HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT, + horizontalAlignment ); + } + + if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ) != Property::NONE ) + { + std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ).Get(); + Scripting::GetEnumeration< VerticalAlignment::Type >( value.c_str(), + VERTICAL_ALIGNMENT_STRING_TABLE, + VERTICAL_ALIGNMENT_STRING_TABLE_COUNT, + verticalAlignment ); + } + + Toolkit::TableView::CellPosition cellPosition; + if( child.GetPropertyType( Toolkit::TableView::ChildProperty::ROW_SPAN ) != Property::NONE ) + { + cellPosition.rowSpan = static_cast( child.GetProperty( Toolkit::TableView::ChildProperty::ROW_SPAN ).Get() ); + } + + if( child.GetPropertyType( Toolkit::TableView::ChildProperty::COLUMN_SPAN ) != Property::NONE ) + { + cellPosition.columnSpan = static_cast( child.GetProperty( Toolkit::TableView::ChildProperty::COLUMN_SPAN ).Get() ); + } + + if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_INDEX ) != Property::NONE ) + { + Vector2 indices = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_INDEX ).Get(); + cellPosition.rowIndex = static_cast( indices.x ); + cellPosition.columnIndex = static_cast( indices.y ); + + AddChild( child, cellPosition ); + SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment); + + // Do not continue + return; + } + + // 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(); } -void TableView::OnControlChildRemove( Actor& child ) +void TableView::OnChildRemove( Actor& child ) { // dont process if we're in the middle of bigger operation like delete row, column or resize if( !mLayoutingChild ) @@ -791,13 +1066,16 @@ void TableView::OnControlChildRemove( Actor& child ) RelayoutRequest(); } } + + Control::OnChildRemove( child ); } TableView::TableView( unsigned int initialRows, unsigned int initialColumns ) -: ControlImpl( true ), // requires touch +: Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ), mCellData( initialRows, initialColumns ), mLayoutingChild( false ), - mConstraintDuration( DEFAULT_CONSTRAINT_DURATION ) + mRowDirty( true ), // Force recalculation first time + mColumnDirty( true ) { SetKeyboardNavigationSupport( true ); ResizeContainers( initialRows, initialColumns ); @@ -813,26 +1091,25 @@ void TableView::OnInitialize() void TableView::ResizeContainers( unsigned int rows, unsigned int columns ) { - vector ignored; + std::vector ignored; ResizeContainers( rows, columns, ignored ); } -void TableView::ResizeContainers( unsigned int rows, unsigned int columns, vector& removed ) +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 vector& lost, vector& removed, +void TableView::RemoveAndGetLostActors( const std::vector& lost, std::vector& removed, unsigned int rowsRemoved, unsigned int columnsRemoved ) { // iterate through all lost cells - vector< CellData >::const_iterator iter = lost.begin(); + std::vector< CellData >::const_iterator iter = lost.begin(); for( ; iter != lost.end(); ++iter ) { // if it is a valid actor @@ -876,7 +1153,7 @@ void TableView::RemoveAndGetLostActors( const vector& lost, vector 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 ) + Property::Map* map = value.GetMap(); + if( map ) { - if( mFixedWidths[ column ] > 0.0f ) - { - ++fixedColumnCount; - fixedWidthsTotal += mFixedWidths[ column ]; - } - if( mRelativeWidths[ column ] > 0.0f ) + unsigned int index(0); + for ( unsigned int i = 0, count = map->Count(); i < count; ++i ) { - ++relativeColumnCount; - relativeWidthsTotal += mRelativeWidths[ column ]; + Property::Value& item = map->GetValue(i); + Property::Map* childMap = item.GetMap(); + + std::istringstream( map->GetKey(i) ) >> index; + if( childMap ) + { + Property::Value* policy = childMap->Find( "policy" ); + Property::Value* childMapValue = childMap->Find( "value" ); + if( policy && childMapValue ) + { + 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 ) ) + { + if( policy == Toolkit::TableView::FIXED ) + { + (tableViewImpl.*funcFixed)( index, childMapValue->Get() ); + } + else if( policy == Toolkit::TableView::RELATIVE ) + { + (tableViewImpl.*funcRelative)( index, childMapValue->Get() ); + } + else if( policy == Toolkit::TableView::FIT ) + { + (tableViewImpl.*funcFit)( index ); + } + // do nothing for FILL policy + } + } + } } } +} - // 2. cap the relative width and height totals to 100% - if( relativeHeightsTotal > 1.0f ) - { - relativeHeightsTotal = 1.0f; - } - if( relativeWidthsTotal > 1.0f ) - { - relativeWidthsTotal = 1.0f; - } +Property::Value TableView::GetRowHeightsPropertyValue() +{ + Property::Map map; + GetMapPropertyValue( mRowData, map); + return Property::Value(map); +} - // 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 ); +Property::Value TableView::GetColumnWidthsPropertyValue() +{ + Property::Map map; + GetMapPropertyValue( mColumnData, map); + return Property::Value(map); +} - // walk through the data containers - for( unsigned int row = 0; row < rowCount; ++row ) +void TableView::GetMapPropertyValue( const RowColumnArray& data, Property::Map& map ) +{ + 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++ ) { - 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 ) + const RowColumnData& dataInstance = data[ i ]; + + Property::Map item; + switch( dataInstance.sizePolicy ) { - float relativeWidth = 0.0f; - // if we have a fixed width, relative width is 0 - if( mFixedWidths[ column ] > 0.0f ) + case Toolkit::TableView::FIXED: + { + item[ "policy" ] = fixedPolicy; + item[ "value" ] = dataInstance.size; + break; + } + case Toolkit::TableView::RELATIVE: { - relativeWidth = 0.0f; + item[ "policy" ] = relativePolicy; + item[ "value" ] = dataInstance.fillRatio; + break; } - // else if we're given a specific column width %, use that - else if( mRelativeWidths[ column ] > 0.0f ) + case Toolkit::TableView::FIT: { - relativeWidth = mRelativeWidths[ column ]; + item[ "policy" ] = fitPolicy; + item[ "value" ] = 0.f; + break; } - // else if there are fill columns - else if( fillColumnCount > 0 ) + case Toolkit::TableView::FILL: + default: { - // this is a 'fill' column. it gets the remainder of the 100% divided evenly between 'fill' columns - relativeWidth = (1.0f - relativeWidthsTotal ) / fillColumnCount; + item[ "policy" ] = fillPolicy; + item[ "value" ] = 0.f; + break; } - // store the value - mRelativeSizes[ row ][ column ] = Size( relativeWidth, relativeHeight ); } + std::ostringstream ss; + ss << i; + map[ ss.str() ] = item; } } @@ -1000,7 +1298,7 @@ TableView::~TableView() // nothing to do } -Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Control::KeyboardFocusNavigationDirection direction, bool loopEnabled) +Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled) { Actor nextFocusableActor; @@ -1023,7 +1321,7 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Contro switch ( direction ) { - case Control::Left: + case Toolkit::Control::KeyboardFocus::LEFT: { if(--currentColumn < 0) { @@ -1036,7 +1334,7 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Contro } break; } - case Control::Right: + case Toolkit::Control::KeyboardFocus::RIGHT: { if(++currentColumn > numberOfColumns - 1) { @@ -1049,7 +1347,7 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Contro } break; } - case Control::Up: + case Toolkit::Control::KeyboardFocus::UP: { if(--currentRow < 0) { @@ -1058,7 +1356,8 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Contro } break; } - case Control::Down: + case Toolkit::Control::KeyboardFocus::DOWN: + { if(++currentRow > numberOfRows - 1) { @@ -1085,6 +1384,234 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Contro 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