#include <sstream>
#include <dali/public-api/object/ref-object.h>
#include <dali/public-api/object/type-registry.h>
-#include <dali/public-api/object/type-registry-helper.h>
-#include <dali/public-api/scripting/scripting.h>
+#include <dali/devel-api/object/type-registry-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
#include <dali/integration-api/debug.h>
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("cell-index");
+const char * const ROW_SPAN_PROPERTY_NAME("row-span");
+const char * const COLUMN_SPAN_PROPERTY_NAME("column-span");
+const char * const CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME("cell-horizontal-alignment");
+const char * const CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME("cell-vertical-alignment");
/**
- * 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)
#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<Dali::Toolkit::Internal::TableView::CellData>& array )
{
TV_LOG( "Array2d<CellData> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
{
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 );
}
}
TV_LOG( "\n" );
}
+#endif // defined(TABLEVIEW_DEBUG)
#endif // defined(DEBUG_ENABLED)
} // namespace
// Setup properties, signals and actions using the type-registry.
DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TableView, Toolkit::Control, Create );
-DALI_PROPERTY_REGISTRATION( TableView, "rows", UNSIGNED_INTEGER, ROWS )
-DALI_PROPERTY_REGISTRATION( TableView, "columns", UNSIGNED_INTEGER, COLUMNS )
-DALI_PROPERTY_REGISTRATION( TableView, "cell-padding", VECTOR2, CELL_PADDING )
-DALI_PROPERTY_REGISTRATION( TableView, "layout-rows", MAP, LAYOUT_ROWS )
-DALI_PROPERTY_REGISTRATION( TableView, "layout-columns", MAP, LAYOUT_COLUMNS )
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "rows", INTEGER, ROWS )
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "columns", INTEGER, COLUMNS )
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "cell-padding", VECTOR2, CELL_PADDING )
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layout-rows", MAP, LAYOUT_ROWS )
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layout-columns", MAP, LAYOUT_COLUMNS )
DALI_TYPE_REGISTRATION_END()
-const Scripting::StringEnum< Toolkit::TableView::LayoutPolicy > LAYOUT_POLICY_STRING_TABLE[] =
+const Scripting::StringEnum LAYOUT_POLICY_STRING_TABLE[] =
{
- { "fixed", Toolkit::TableView::Fixed },
- { "relative", Toolkit::TableView::Relative },
- { "fill", Toolkit::TableView::Fill }
+ { "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 )
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 );
// 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();
}
}
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, std::vector<Actor>& 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--;
}
}
}
+
// 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, std::vector<Actor>& 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--;
}
}
}
+
// 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, std::vector<Actor>& 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();
}
}
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
}
}
{
case Toolkit::TableView::Property::ROWS:
{
- if( value.Get<unsigned int>() != tableViewImpl.GetRows() )
+ int rows = 0;
+ if( value.Get( rows ) && rows >= 0 )
{
- tableViewImpl.Resize( value.Get<unsigned int>(), tableViewImpl.GetColumns() );
+ if( static_cast<unsigned int>(rows) != tableViewImpl.GetRows() )
+ {
+ tableViewImpl.Resize( rows, tableViewImpl.GetColumns() );
+ }
}
break;
}
case Toolkit::TableView::Property::COLUMNS:
{
- if( value.Get<unsigned int>() != tableViewImpl.GetColumns() )
+ int columns = 0;
+ if( value.Get( columns ) && columns >= 0 )
{
- tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<unsigned int>() );
+ if( static_cast<unsigned int>( columns ) != tableViewImpl.GetColumns() )
+ {
+ tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<int>() );
+ }
}
break;
}
}
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:
{
- SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, value );
+ SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, &TableView::SetFitWidth, value );
break;
}
}
{
case Toolkit::TableView::Property::ROWS:
{
- value = tableViewImpl.GetRows();
+ value = static_cast<int>( tableViewImpl.GetRows() );
break;
}
case Toolkit::TableView::Property::COLUMNS:
{
- value = tableViewImpl.GetColumns();
+ value = static_cast<int>( tableViewImpl.GetColumns() );
break;
}
case Toolkit::TableView::Property::CELL_PADDING:
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<std::string >();
+ 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<std::string >();
+ 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<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
+ cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
}
- 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<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
+ cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
}
- 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 >();
+ Vector2 indices = child.GetProperty( child.GetPropertyIndex(CELL_INDEX_PROPERTY_NAME) ).Get<Vector2 >();
cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
cellPosition.columnIndex = static_cast<unsigned int>( 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();
}
}
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 );
void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& 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<CellData>& lost, std::vector<Actor>& removed,
}
}
-bool TableView::RemoveAllInstances( Actor child )
+bool TableView::RemoveAllInstances( const Actor& child )
{
bool found = false;
// walk through the layout data
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<Property::Map>();
- 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<std::string>().c_str(), LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT );
- if( policy == Toolkit::TableView::Fixed )
- {
- (tableViewImpl.*funcFixed)( rowIndex, item.GetValue("value").Get<float>() );
- }
- 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<float>() );
+ if( policy == Toolkit::TableView::FIXED )
+ {
+ (tableViewImpl.*funcFixed)( index, value->Get<float>() );
+ }
+ else if( policy == Toolkit::TableView::RELATIVE )
+ {
+ (tableViewImpl.*funcRelative)( index, value->Get<float>() );
+ }
+ else if( policy == Toolkit::TableView::FIT )
+ {
+ (tableViewImpl.*funcFit)( index );
+ }
+ // do nothing for FILL policy
}
}
}
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<float>& fixedSize, const std::vector<float>& 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*>( &(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*>( &(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;
}
}
// 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;
switch ( direction )
{
- case Toolkit::Control::Left:
+ case Toolkit::Control::KeyboardFocus::LEFT:
{
if(--currentColumn < 0)
{
}
break;
}
- case Toolkit::Control::Right:
+ case Toolkit::Control::KeyboardFocus::RIGHT:
{
if(++currentColumn > numberOfColumns - 1)
{
}
break;
}
- case Toolkit::Control::Up:
+ case Toolkit::Control::KeyboardFocus::UP:
{
if(--currentRow < 0)
{
}
break;
}
- case Toolkit::Control::Down:
+ case Toolkit::Control::KeyboardFocus::DOWN:
{
if(++currentRow > numberOfRows - 1)
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