/*
- * 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 <sstream>
#include <dali/public-api/object/ref-object.h>
#include <dali/public-api/object/type-registry.h>
-#include <dali/devel-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry-helper.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
{
-/*
- * Custom properties for where to put the actor.
- *
- * When an actor is add to the tableView through Actor::Add() instead of TableView::AddChild,
- * the following custom properties of the actor are checked to decide the actor position inside the table
- *
- * These non-animatable properties should be registered to the child which would be added to the table
- */
-const char * const CELL_INDEX_PROPERTY_NAME("cellIndex");
-const char * const ROW_SPAN_PROPERTY_NAME("rowSpan");
-const char * const COLUMN_SPAN_PROPERTY_NAME("columnSpan");
-const char * const CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME("cellHorizontalAlignment");
-const char * const CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME("cellVerticalAlignment");
-
/**
* @brief Should the tableview fit around the given actor
*
DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "cellPadding", VECTOR2, CELL_PADDING )
DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutRows", MAP, LAYOUT_ROWS )
DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutColumns", MAP, LAYOUT_COLUMNS )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellIndex", VECTOR2, CELL_INDEX )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "rowSpan", FLOAT, ROW_SPAN )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "columnSpan", FLOAT, COLUMN_SPAN )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellHorizontalAlignment", STRING, CELL_HORIZONTAL_ALIGNMENT )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellVerticalAlignment", STRING, CELL_VERTICAL_ALIGNMENT )
DALI_TYPE_REGISTRATION_END()
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
// rows and columns must be recalculated or the new size will not take effect.
mRowDirty = mColumnDirty = true;
RelayoutRequest();
+
+ Control::OnSizeSet( size );
}
void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
if( actor && position.rowIndex == row && position.columnIndex == column )
{
// Anchor actor to top left of the cell
- actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+ if( actor.GetProperty( DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
+ {
+ actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+ }
actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
Padding padding;
return value;
}
-void TableView::OnControlChildAdd( Actor& child )
+void TableView::OnChildAdd( Actor& child )
{
- if( mLayoutingChild )
- {
- // we're in the middle of laying out children so no point doing anything here
- 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 )
+ if( ! mLayoutingChild )
{
- 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 );
- }
+ // Ensure we're not in the middle of laying out children
+ // Check child properties on actor to decide its position inside the table
+ HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT;
+ VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP;
- Toolkit::TableView::CellPosition cellPosition;
- if( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
- {
- cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(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(COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
- {
- cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(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(CELL_INDEX_PROPERTY_NAME) != Property::INVALID_INDEX )
- {
- 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 );
+ Toolkit::TableView::CellPosition cellPosition;
+ if( child.GetPropertyType( Toolkit::TableView::ChildProperty::ROW_SPAN ) != Property::NONE )
+ {
+ cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( Toolkit::TableView::ChildProperty::ROW_SPAN ).Get<float>() );
+ }
- AddChild( child, cellPosition );
- SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment);
+ if( child.GetPropertyType( Toolkit::TableView::ChildProperty::COLUMN_SPAN ) != Property::NONE )
+ {
+ cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( Toolkit::TableView::ChildProperty::COLUMN_SPAN ).Get<float>() );
+ }
- // 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 )
+ {
+ 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 )
{
- // Put the actor in the cell
+ // 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;
+ data.position.rowIndex = rowCount;
+ data.position.columnIndex = 0;
data.horizontalAlignment = horizontalAlignment;
data.verticalAlignment = verticalAlignment;
- mCellData[ row ][ column ] = data;
-
- // Don't continue
- RelayoutRequest();
- return;
+ 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;
- data.horizontalAlignment = horizontalAlignment;
- data.verticalAlignment = verticalAlignment;
- mCellData[ rowCount ][ 0 ] = data;
- RelayoutRequest();
+ 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_STYLE_CHANGE_SIGNALS ) ),
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
mCellData( initialRows, initialColumns ),
+ mPreviousFocusedActor(),
mLayoutingChild( false ),
mRowDirty( true ), // Force recalculation first time
mColumnDirty( true )
int numberOfColumns = GetColumns();
int numberOfRows = GetRows();
+ bool lastCell = false;
+ Actor nextValidActor;
+
switch ( direction )
{
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::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::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::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));
+ }
+ }
}
}