/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
#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/actors/actor-devel.h>
+#include <dali/devel-api/scripting/scripting.h>
#include <dali/public-api/size-negotiation/relayout-container.h>
#include <dali/integration-api/debug.h>
namespace
{
-
/**
* @brief Should the tableview fit around the given actor
*
* @param[in] actor The child actor to test against
- * @param[dimension] The dimnesion to test against
+ * @param[dimension] The dimension to test against
*/
bool FitToChild( Actor actor, Dimension::Type dimension )
{
#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() );
}
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, "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", INTEGER, ROW_SPAN )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "columnSpan", INTEGER, 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< 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 }
+ { "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 )
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() )
}
// 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
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();
}
}
mRowData.Insert( mRowData.Begin() + rowIndex, RowColumnData() );
// Sizes may have changed, so relayout
- mRowColumnDirty = true;
+ mRowDirty = true;
RelayoutRequest();
}
else if( row >= rowIndex ) // If below of or at the inserted row, decrease row index
{
// Decrement index
- if( position.rowIndex > 1 )
+ if( position.rowIndex > 0 )
{
position.rowIndex--;
}
mRowData.Erase( mRowData.Begin() + rowIndex );
// Sizes may have changed, so relayout
- mRowColumnDirty = true;
+ 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();
}
mColumnData.Insert( mColumnData.Begin() + columnIndex, RowColumnData() );
// Sizes may have changed so relayout
- mRowColumnDirty = true;
+ mColumnDirty = true;
RelayoutRequest();
}
mColumnData.Erase( mColumnData.Begin() + columnIndex );
// Size may have changed so relayout
- mRowColumnDirty = true;
+ 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();
}
RemoveAndGetLostActors( lost, removed, rowsRemoved, columnsRemoved );
// Sizes may have changed so request a relayout
- mRowColumnDirty = true;
+ mRowDirty = true;
+ mColumnDirty = true;
RelayoutRequest();
}
return mPadding;
}
-void TableView::SetRowPolicy( unsigned int rowIndex, CellSizePolicy policy )
+void TableView::SetFitHeight( unsigned int rowIndex )
{
DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
- if( mRowData[ rowIndex ].sizePolicy != policy )
+ if( mRowData[ rowIndex ].sizePolicy != Toolkit::TableView::FIT )
{
- mRowData[ rowIndex ].sizePolicy = policy;
+ mRowData[ rowIndex ].sizePolicy = Toolkit::TableView::FIT;
- mRowColumnDirty = true;
+ mRowDirty = true;
RelayoutRequest();
}
}
-TableView::CellSizePolicy TableView::GetRowPolicy( unsigned int rowIndex ) const
+bool TableView::IsFitHeight( unsigned int rowIndex ) const
{
DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
- return mRowData[ rowIndex ].sizePolicy;
+ return mRowData[ rowIndex ].sizePolicy == Toolkit::TableView::FIT;
}
-void TableView::SetColumnPolicy( unsigned int columnIndex, CellSizePolicy policy )
+void TableView::SetFitWidth( unsigned int columnIndex )
{
DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
- if( mColumnData[ columnIndex ].sizePolicy != policy )
+ if( mColumnData[ columnIndex ].sizePolicy != Toolkit::TableView::FIT )
{
- mColumnData[ columnIndex ].sizePolicy = policy;
+ mColumnData[ columnIndex ].sizePolicy = Toolkit::TableView::FIT;
- mRowColumnDirty = true;
+ mColumnDirty = true;
RelayoutRequest();
}
}
-TableView::CellSizePolicy TableView::GetColumnPolicy( unsigned int columnIndex ) const
+bool TableView::IsFitWidth( unsigned int columnIndex ) const
{
DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
- return mColumnData[ columnIndex ].sizePolicy;
+ return mColumnData[ columnIndex ].sizePolicy == Toolkit::TableView::FIT;
}
void TableView::SetFixedHeight( unsigned int rowIndex, float height )
RowColumnData& data = mRowData[ rowIndex ];
data.size = height;
- data.sizePolicy = FIXED;
+ data.sizePolicy = Toolkit::TableView::FIXED;
- mRowColumnDirty = true;
+ mRowDirty = true;
RelayoutRequest();
}
RowColumnData& data = mColumnData[ columnIndex ];
data.size = width;
- data.sizePolicy = FIXED;
+ data.sizePolicy = Toolkit::TableView::FIXED;
- mRowColumnDirty = true;
+ mColumnDirty = true;
RelayoutRequest();
}
RowColumnData& data = mRowData[ rowIndex ];
data.fillRatio = heightPercentage;
- data.userFillRatio = true;
- data.sizePolicy = FILL;
+ data.sizePolicy = Toolkit::TableView::RELATIVE;
- mRowColumnDirty = true;
+ mRowDirty = true;
RelayoutRequest();
}
RowColumnData& data = mColumnData[ columnIndex ];
data.fillRatio = widthPercentage;
- data.userFillRatio = true;
- data.sizePolicy = FILL;
+ data.sizePolicy = Toolkit::TableView::RELATIVE;
- mRowColumnDirty = true;
+ mColumnDirty = true;
RelayoutRequest();
}
return mColumnData[ columnIndex ].fillRatio;
}
-void TableView::CalculateRowColumnData()
-{
- // Calculate the relative sizes
- if( mRowColumnDirty )
- {
- ComputeRelativeSizes( mRowData );
- ComputeRelativeSizes( mColumnData );
-
- mRowColumnDirty = false;
- }
-}
-
void TableView::OnCalculateRelayoutSize( Dimension::Type dimension )
{
- CalculateRowColumnData();
-
- if( dimension & Dimension::WIDTH )
+ if( (dimension & Dimension::WIDTH) && mColumnDirty )
{
- CalculateFixedSizes( mColumnData, Dimension::WIDTH );
+ /*
+ * 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 );
}
- if( dimension & Dimension::HEIGHT )
+ if( (dimension & Dimension::HEIGHT) && mRowDirty )
{
- CalculateFixedSizes( mRowData, Dimension::HEIGHT );
+ // refer to the comment above
+ CalculateFitSizes( mRowData, Dimension::HEIGHT );
+
+ // refer to the comment above
+ CalculateFillSizes( mRowData );
+
mFixedTotals.height = CalculateTotalFixedSize( mRowData );
}
}
void TableView::OnLayoutNegotiated( float size, Dimension::Type dimension )
{
- CalculateRowColumnData();
-
- // Calculate the value of all relative sized rows and columns
- if( dimension & Dimension::WIDTH )
+ // Update the column sizes
+ if( (dimension & Dimension::WIDTH) && mColumnDirty )
{
float remainingSize = size - mFixedTotals.width;
if( remainingSize < 0.0f )
remainingSize = 0.0f;
}
- CalculateRelativeSizes( mColumnData, remainingSize );
+ // 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;
+ }
+
+ cumulatedWidth += mColumnData[ column ].size;
+ mColumnData[column].position = cumulatedWidth;
+ }
+
+ mColumnDirty = false;
}
- if( dimension & Dimension::HEIGHT )
+ // Update the row sizes
+ if( (dimension & Dimension::HEIGHT) && mRowDirty )
{
float remainingSize = size - mFixedTotals.height;
if( remainingSize < 0.0f )
remainingSize = 0.0f;
}
- CalculateRelativeSizes( mRowData, remainingSize );
+ // 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::OnRelayout( const Vector2& size, RelayoutContainer& container )
+void TableView::OnSizeSet( const Vector3& size )
{
- CalculateRowColumnData();
-
- // Go through the layout data
- float cumulatedHeight = 0.0f;
+ // 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();
- const unsigned int rowCount = mCellData.GetRows();
- const unsigned int columnCount = mCellData.GetColumns();
+ Control::OnSizeSet( size );
+}
- for( unsigned int row = 0; row < rowCount; ++row )
+void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+ // Go through the layout data
+ for( unsigned int row = 0, rowCount = mCellData.GetRows(); row < rowCount; ++row )
{
- float cumulatedWidth = 0.0f;
-
- for( unsigned int column = 0; column < columnCount; ++column )
+ for( unsigned int column = 0, columnCount = mCellData.GetColumns(); column < columnCount; ++column )
{
- Actor& actor = mCellData[ row ][ column ].actor;
- const Toolkit::TableView::CellPosition position = mCellData[ row ][ column ].position;
+ 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 columnspan is more than 1.
+ // 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 ) )
+ if( actor && position.rowIndex == row && position.columnIndex == column )
{
- // Anchor actor to top left of table view
- actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+ // Anchor actor to top left of the cell
+ if( actor.GetProperty( DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
+ {
+ actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+ }
actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
Padding padding;
actor.GetPadding( padding );
- Vector3 actorPosition( cumulatedWidth + mPadding.width + padding.left, // Left padding
- cumulatedHeight + mPadding.height + padding.top, // Top padding
- 0.0f );
- actor.SetPosition( actorPosition );
- }
+ 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;
- DALI_ASSERT_DEBUG( column < mColumnData.Size() );
- cumulatedWidth += mColumnData[ column ].size;
- }
+ if( cellData.horizontalAlignment == HorizontalAlignment::LEFT )
+ {
+ actor.SetX( left + mPadding.width + padding.left );
+ }
+ else if( cellData.horizontalAlignment == HorizontalAlignment::RIGHT )
+ {
+ 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 );
+ }
- DALI_ASSERT_DEBUG( row < mRowData.Size() );
- cumulatedHeight += mRowData[ row ].size;
+ 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 );
+ }
+ }
+ }
}
}
{
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 value;
}
-void TableView::OnControlChildAdd( Actor& child )
+void TableView::OnChildAdd( Actor& child )
{
- if( mLayoutingChild )
+ if( ! mLayoutingChild )
{
- // we're in the middle of laying out children so no point doing anything here
- return;
- }
+ // Ensure we're not in the middle of laying out children
- RelayoutRequest();
+ // Check child properties on actor to decide its position inside the table
+ HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT;
+ VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP;
- // Test properties on actor
- Toolkit::TableView::CellPosition cellPosition;
- if( child.GetPropertyIndex(Toolkit::TableView::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>() );
- }
+ if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ) != Property::NONE )
+ {
+ std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ).Get<std::string >();
+ Scripting::GetEnumeration< HorizontalAlignment::Type >( value.c_str(),
+ HORIZONTAL_ALIGNMENT_STRING_TABLE,
+ HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
+ horizontalAlignment );
+ }
- if( child.GetPropertyIndex(Toolkit::TableView::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>() );
- }
+ if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ) != Property::NONE )
+ {
+ std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ).Get<std::string >();
+ Scripting::GetEnumeration< VerticalAlignment::Type >( value.c_str(),
+ VERTICAL_ALIGNMENT_STRING_TABLE,
+ VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
+ verticalAlignment );
+ }
- if( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) != Property::INVALID_INDEX )
- {
- Vector2 indices = child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) ).Get<Vector2 >();
- cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
- cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
+ Toolkit::TableView::CellPosition cellPosition;
+ if( child.GetPropertyType( Toolkit::TableView::ChildProperty::ROW_SPAN ) != Property::NONE )
+ {
+ cellPosition.rowSpan = child.GetProperty( Toolkit::TableView::ChildProperty::ROW_SPAN ).Get< int >();
+ }
- AddChild( child, cellPosition );
+ if( child.GetPropertyType( Toolkit::TableView::ChildProperty::COLUMN_SPAN ) != Property::NONE )
+ {
+ cellPosition.columnSpan = child.GetProperty( Toolkit::TableView::ChildProperty::COLUMN_SPAN ).Get< int >();
+ }
- // Do not continue
- return;
- }
+ if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_INDEX ) != Property::NONE )
+ {
+ Vector2 indices = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_INDEX ).Get<Vector2 >();
+ cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
+ cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
- // Find the first available cell to store the actor in
- 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 )
+ AddChild( child, cellPosition );
+ SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment);
+ }
+ else
{
- if( !(mCellData[ row ][ column ].actor) )
+ bool availableCellFound = false;
+
+ // Find the first available cell to store the actor in
+ const unsigned int rowCount = mCellData.GetRows();
+ const unsigned int columnCount = mCellData.GetColumns();
+ for( unsigned int row = 0; row < rowCount && !availableCellFound; ++row )
{
- // Put the actor in the cell
+ for( unsigned int column = 0; column < columnCount && !availableCellFound; ++column )
+ {
+ if( !(mCellData[ row ][ column ].actor) )
+ {
+ // 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;
+
+ availableCellFound = true;
+ break;
+ }
+ }
+ }
+
+ if( ! availableCellFound )
+ {
+ // 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.columnIndex = column;
- data.position.rowIndex = row;
- mCellData[ row ][ column ] = data;
-
- // Don't continue
- return;
+ data.position.rowIndex = rowCount;
+ data.position.columnIndex = 0;
+ data.horizontalAlignment = horizontalAlignment;
+ data.verticalAlignment = verticalAlignment;
+ mCellData[ rowCount ][ 0 ] = data;
}
+
+ RelayoutRequest();
}
}
- // 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;
- mCellData[ rowCount ][ 0 ] = data;
+ Control::OnChildAdd( child );
}
-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 )
RelayoutRequest();
}
}
+
+ Control::OnChildRemove( child );
}
TableView::TableView( unsigned int initialRows, unsigned int initialColumns )
-: Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
mCellData( initialRows, initialColumns ),
+ mPreviousFocusedActor(),
mLayoutingChild( false ),
- mRowColumnDirty( true ) // Force recalculation first time
+ mRowDirty( true ), // Force recalculation first time
+ mColumnDirty( true )
{
SetKeyboardNavigationSupport( true );
ResizeContainers( initialRows, initialColumns );
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* childMapValue = childMap->Find( "value" );
+ if( policy && childMapValue )
{
- 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, childMapValue->Get<float>() );
+ }
+ else if( policy == Toolkit::TableView::RELATIVE )
+ {
+ (tableViewImpl.*funcRelative)( index, childMapValue->Get<float>() );
+ }
+ else if( policy == Toolkit::TableView::FIT )
+ {
+ (tableViewImpl.*funcFit)( index );
+ }
+ // do nothing for FILL policy
}
}
}
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 ) );
+ 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++ )
{
const RowColumnData& dataInstance = data[ i ];
+ Property::Map item;
switch( dataInstance.sizePolicy )
{
- case FIXED:
+ case Toolkit::TableView::FIXED:
{
- Property::Map item;
item[ "policy" ] = fixedPolicy;
item[ "value" ] = dataInstance.size;
-
- std::ostringstream ss;
- ss << i;
-
- map[ ss.str() ] = item;
-
break;
}
-
- case FILL:
+ case Toolkit::TableView::RELATIVE:
{
- Property::Map item;
item[ "policy" ] = relativePolicy;
item[ "value" ] = dataInstance.fillRatio;
-
- std::ostringstream ss;
- ss << i;
-
- map[ ss.str() ] = item;
-
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;
int numberOfColumns = GetColumns();
int numberOfRows = GetRows();
+ bool lastCell = false;
+ Actor nextValidActor;
+
switch ( direction )
{
- case Toolkit::Control::Left:
+ case Toolkit::Control::KeyboardFocus::LEFT:
{
- if(--currentColumn < 0)
+ do
{
- currentColumn = numberOfColumns - 1;
- if(--currentRow < 0)
+ if(--currentColumn < 0)
{
- currentRow = loopEnabled ? numberOfRows - 1 : 0;
- focusLost = (currentRow == 0);
+ currentColumn = numberOfColumns - 1;
+ if(--currentRow < 0)
+ {
+ lastCell = true;
+ currentRow = loopEnabled ? numberOfRows - 1 : 0;
+ focusLost = (currentRow == 0);
+ }
}
- }
+ nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+ } while ( !nextValidActor && !lastCell );
break;
}
- case Toolkit::Control::Right:
+ case Toolkit::Control::KeyboardFocus::RIGHT:
{
- if(++currentColumn > numberOfColumns - 1)
+ do
{
- currentColumn = 0;
- if(++currentRow > numberOfRows - 1)
+ if(++currentColumn > numberOfColumns - 1)
{
- currentRow = loopEnabled ? 0 : numberOfRows - 1;
- focusLost = (currentRow == numberOfRows - 1);
+ currentColumn = 0;
+ if(++currentRow > numberOfRows - 1)
+ {
+ lastCell = true;
+ currentRow = loopEnabled ? 0 : numberOfRows - 1;
+ focusLost = (currentRow == numberOfRows - 1);
+ }
}
- }
+ nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+ } while ( !nextValidActor && !lastCell );
break;
}
- case Toolkit::Control::Up:
+ case Toolkit::Control::KeyboardFocus::UP:
{
- if(--currentRow < 0)
+ do
{
- currentRow = loopEnabled ? numberOfRows - 1 : 0;
- focusLost = (currentRow == 0);
- }
+ if(--currentRow < 0)
+ {
+ lastCell = true;
+ currentRow = loopEnabled ? numberOfRows - 1 : 0;
+ focusLost = (currentRow == 0);
+ }
+ nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+ } while ( !nextValidActor && !lastCell );
break;
}
- case Toolkit::Control::Down:
+ case Toolkit::Control::KeyboardFocus::DOWN:
{
- if(++currentRow > numberOfRows - 1)
+ do
{
- currentRow = loopEnabled ? 0 : numberOfRows - 1;
- focusLost = (currentRow == numberOfRows - 1);
- }
+ if(++currentRow > numberOfRows - 1)
+ {
+ lastCell = true;
+ currentRow = loopEnabled ? 0 : numberOfRows - 1;
+ focusLost = (currentRow == numberOfRows - 1);
+ }
+ nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+ } while ( !nextValidActor && !lastCell );
+ break;
+ }
+ default:
+ {
break;
}
}
if(!focusLost)
{
nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+
+ // Save the focused actor in the TableView.
+ mPreviousFocusedActor = nextFocusableActor;
}
}
else
{
- // The current focused actor is not within table view, so the child in the first cell should be focused.
- nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
+ // The current focused actor is not within this TableView.
+
+ unsigned int numberOfColumns = GetColumns();
+ unsigned int numberOfRows = GetRows();
+
+ // Check whether the previous focused actor is a focus group (i.e. a layout container)
+ bool wasFocusedOnLayoutContainer = false;
+ Actor previousFocusedActor = mPreviousFocusedActor.GetHandle();
+ if( previousFocusedActor )
+ {
+ Toolkit::Control control = Toolkit::Control::DownCast( previousFocusedActor );
+ if( control )
+ {
+ Internal::Control& controlImpl = static_cast<Internal::Control&>(control.GetImplementation());
+ wasFocusedOnLayoutContainer = controlImpl.IsKeyboardFocusGroup();
+ }
+ }
+
+ // Check whether the previous focused actor is a layout container and also a child of this TableView
+ Toolkit::TableView::CellPosition position;
+ if( wasFocusedOnLayoutContainer && FindChildPosition( previousFocusedActor, position ) )
+ {
+ nextFocusableActor = GetNextKeyboardFocusableActor(previousFocusedActor, direction, loopEnabled);
+ }
+ else
+ {
+ // Otherwise, move the focus to either the first or the last cell according to the given direction.
+ if(direction == Toolkit::Control::KeyboardFocus::LEFT || direction == Toolkit::Control::KeyboardFocus::UP)
+ {
+ nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(numberOfRows - 1, numberOfColumns - 1));
+ }
+ else
+ {
+ nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
+ }
+ }
}
}
float TableView::CalculateChildSize( const Actor& child, Dimension::Type dimension )
{
- CalculateRowColumnData();
-
- const unsigned int rowCount = mCellData.GetRows();
- const unsigned int columnCount = mCellData.GetColumns();
-
- for( unsigned int row = 0; row < rowCount; ++row )
+ Toolkit::TableView::CellPosition position;
+ if( FindChildPosition( child, position) )
{
- for( unsigned int column = 0; column < columnCount; ++column )
+ switch( dimension )
{
- // check if this cell has an actor
- Actor& actor = mCellData[ row ][ column ].actor;
-
- if( actor && ( actor == child ) )
+ case Dimension::WIDTH:
{
- const Toolkit::TableView::CellPosition position = mCellData[ row ][ column ].position;
+ 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 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.
- if ( ( position.rowIndex == row ) && ( position.columnIndex == column ) )
+ if( cellSize < 0.0f )
{
- switch( dimension )
- {
- case Dimension::WIDTH:
- {
- float cellSize = 0.0f;
-
- // Accumulate the width
- for( unsigned int i = 0; i < position.columnSpan; ++i )
- {
- DALI_ASSERT_DEBUG( column + i < mColumnData.Size() );
- cellSize += mColumnData[ column + i ].size;
- }
-
- // Apply padding
- cellSize -= mPadding.width * 2.0f;
- if( cellSize < 0.0f )
- {
- cellSize = 0.0f;
- }
-
- return cellSize;
- }
-
- case Dimension::HEIGHT:
- {
- float cellSize = 0.0f;
+ cellSize = 0.0f;
+ }
- // Accumulate the height
- for( unsigned int i = 0; i < position.rowSpan; ++i )
- {
- DALI_ASSERT_DEBUG( row + i < mRowData.Size() );
- cellSize += mRowData[ row + i ].size;
- }
+ return cellSize;
+ }
- // Apply padding
- cellSize -= mPadding.width * 2.0f;
- if( cellSize < 0.0f )
- {
- cellSize = 0.0f;
- }
+ case Dimension::HEIGHT:
+ {
+ float cellSize = 0.0f;
- return cellSize;
- }
+ cellSize = mRowData[position.rowIndex+position.rowSpan-1].position
+ - (position.rowIndex > 0 ? mRowData[position.rowIndex-1].position : 0.f)
+ - mPadding.height * 2.0f;
- default:
- {
- return 0.0f;
- }
- }
+ if( cellSize < 0.0f )
+ {
+ cellSize = 0.0f;
}
+
+ return cellSize;
+ }
+ default:
+ {
+ return 0.0f;
}
}
}
data.verticalAlignment = vertical;
}
-void TableView::ComputeRelativeSizes( RowColumnArray& data )
+void TableView::CalculateFillSizes( RowColumnArray& data )
{
// First pass: Count number of fill entries and calculate used relative space
Dali::Vector< RowColumnData* > fillData;
{
RowColumnData& dataInstance = data[ i ];
- if( dataInstance.sizePolicy == FILL )
+ if( dataInstance.sizePolicy == Toolkit::TableView::RELATIVE )
{
- if( dataInstance.userFillRatio )
- {
- relativeTotal += dataInstance.fillRatio;
- }
- else
- {
- fillData.PushBack( &dataInstance );
- }
+ relativeTotal += dataInstance.fillRatio;
+ }
+ else if(dataInstance.sizePolicy == Toolkit::TableView::FILL)
+ {
+ fillData.PushBack( &dataInstance );
}
}
switch( dataInstance.sizePolicy )
{
- case FIXED:
- case FIT:
+ // 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;
return Vector2();
}
-void TableView::CalculateFixedSizes( RowColumnArray& data, Dimension::Type dimension )
+void TableView::CalculateFitSizes( RowColumnArray& data, Dimension::Type dimension )
{
Vector2 cellPadding = GetCellPadding( dimension );
{
RowColumnData& dataInstance = data[ i ];
- if( dataInstance.sizePolicy == FIT )
+ if( dataInstance.sizePolicy == Toolkit::TableView::FIT )
{
// Find the size of the biggest actor in the row or column
float maxActorHeight = 0.0f;
DALI_ASSERT_DEBUG( row < mCellData.GetRows() );
DALI_ASSERT_DEBUG( column < mCellData.GetColumns() );
- Actor& actor = mCellData[ row ][ column ].actor;
+ const CellData& cellData = mCellData[ row ][ column ];
+ const Actor& actor = cellData.actor;
if( actor )
{
- if( FitToChild( actor, dimension ) )
+ 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 );
}
}
}
-void TableView::CalculateRelativeSizes( RowColumnArray& data, float size )
-{
- const unsigned int dataCount = data.Size();
-
- for( unsigned int i = 0; i < dataCount; ++i )
- {
- RowColumnData& dataInstance = data[ i ];
-
- if( dataInstance.sizePolicy == FILL )
- {
- dataInstance.size = dataInstance.fillRatio * size;
- }
- }
-}
-
bool TableView::FindFit( const RowColumnArray& data )
{
for( unsigned int i = 0, count = data.Size(); i < count; ++i )
{
- if( data[ i ].sizePolicy == FIT )
+ if( data[ i ].sizePolicy == Toolkit::TableView::FIT )
{
return true;
}