END_TEST;
}
+int UtcDaliActorInsert(void)
+{
+ tet_infoline("Testing Actor::Insert");
+ TestApplication application;
+
+ Actor parent = Actor::New();
+ Stage::GetCurrent().Add( parent );
+ Actor first = Actor::New();
+ Actor second = Actor::New();
+ Actor third = Actor::New();
+
+ parent.Insert(1, first); // test insert beyond range
+ DALI_TEST_EQUALS( parent.GetChildCount(), 1u, TEST_LOCATION );
+ parent.Insert(0, second);
+ DALI_TEST_EQUALS( parent.GetChildCount(), 2u, TEST_LOCATION );
+ parent.Insert(1, third);
+
+ DALI_TEST_EQUALS( parent.GetChildCount(), 3u, TEST_LOCATION );
+
+ DALI_TEST_CHECK(parent.GetChildAt(0) == first);
+ DALI_TEST_CHECK(parent.GetChildAt(1) == second);
+ DALI_TEST_CHECK(parent.GetChildAt(2) == third);
+
+ END_TEST;
+}
+
+
int UtcDaliActorRemove01(void)
{
tet_infoline("Testing Actor::Remove");
}
}
+void Actor::Insert(unsigned int index, Actor& child)
+{
+ DALI_ASSERT_ALWAYS( this != &child && "Cannot add actor to itself" );
+ DALI_ASSERT_ALWAYS( !child.IsRoot() && "Cannot add root actor" );
+
+ if( !mChildren )
+ {
+ mChildren = new ActorContainer;
+ }
+
+ Actor* const oldParent( child.mParent );
+
+ // since an explicit position has been given, always insert, even if already a child
+ if( oldParent )
+ {
+ oldParent->Remove( child ); // This causes OnChildRemove callback
+ }
+
+ // Guard against Add() during previous OnChildRemove callback
+ if ( !child.mParent )
+ {
+ // Do this first, since user callbacks from within SetParent() may need to remove child
+ if (index < child.GetChildCount())
+ {
+ ActorIter it = mChildren->begin();
+ std::advance(it, index);
+ mChildren->insert(it, Dali::Actor(&child));
+ }
+ else
+ {
+ mChildren->push_back(Dali::Actor(&child));
+ }
+ // SetParent asserts that child can be added
+ child.SetParent(this, index);
+
+ // Notification for derived classes
+ OnChildAdd(child);
+ }
+}
+
void Actor::Remove(Actor& child)
{
DALI_ASSERT_ALWAYS( this != &child && "Cannot remove actor from itself" );
delete mAnchorPoint;
}
-void Actor::ConnectToStage( Stage& stage )
+void Actor::ConnectToStage( Stage& stage, int index )
{
// This container is used instead of walking the Actor hierachy.
// It protects us when the Actor hierachy is modified during OnStageConnectionExternal callbacks.
ActorContainer connectionList;
// This stage is atomic i.e. not interrupted by user callbacks
- RecursiveConnectToStage( stage, connectionList );
+ RecursiveConnectToStage( stage, connectionList, index );
// Notify applications about the newly connected actors.
const ActorIter endIter = connectionList.end();
}
}
-void Actor::RecursiveConnectToStage( Stage& stage, ActorContainer& connectionList )
+void Actor::RecursiveConnectToStage( Stage& stage, ActorContainer& connectionList, int index )
{
DALI_ASSERT_ALWAYS( !OnStage() );
mIsOnStage = true;
- ConnectToSceneGraph();
+ ConnectToSceneGraph(index);
// Notification for internal derived classes
OnStageConnectionInternal();
* The child must connect its Node to the parent's Node.
* This is resursive; the child calls ConnectToStage() for its children.
*/
-void Actor::ConnectToSceneGraph()
+void Actor::ConnectToSceneGraph(int index)
{
DALI_ASSERT_DEBUG( mNode != NULL);
DALI_ASSERT_DEBUG( mParent != NULL);
if( NULL != mNode )
{
// Reparent Node in next Update
- ConnectNodeMessage( mStage->GetUpdateManager(), *(mParent->mNode), *mNode );
+ ConnectNodeMessage( mStage->GetUpdateManager(), *(mParent->mNode), *mNode, index );
}
// Notify attachment
return componentIndex;
}
-void Actor::SetParent(Actor* parent)
+void Actor::SetParent(Actor* parent, int index)
{
if( parent )
{
StagePtr stage = parent->mStage;
// Instruct each actor to create a corresponding node in the scene graph
- ConnectToStage(*stage);
+ ConnectToStage(*stage, index);
}
}
else // parent being set to NULL
void Add(Actor& child);
/**
+ * Inserts a child Actor to this Actor's child list
+ * @pre The child actor is not the same as the parent actor.
+ * @pre The child actor does not already have a parent.
+ * @param [in] index in childlist to insert child at
+ * @param [in] child The child.
+ * @post The child will be referenced by its parent.
+ */
+ void Insert(unsigned int index, Actor& child);
+
+ /**
* Removes a child Actor from this Actor.
* @param [in] child The child.
* @post The child will be unreferenced.
/**
* Called on a child during Add() when the parent actor is connected to the Stage.
* @param[in] stage The stage.
+ * @param[in] index If set, it is only used for positioning the actor within the parent's child list.
*/
- void ConnectToStage(Stage& stage);
+ void ConnectToStage(Stage& stage, int index = -1);
/**
* Helper for ConnectToStage, to recursively connect a tree of actors.
* This is atomic i.e. not interrupted by user callbacks.
* @param[in] stage The stage.
+ * @param[in] index If set, it is only used for positioning the actor within the parent's child list.
* @param[out] connectionList On return, the list of connected actors which require notification.
*/
- void RecursiveConnectToStage( Stage& stage, ActorContainer& connectionList );
+ void RecursiveConnectToStage( Stage& stage, ActorContainer& connectionList, int index = -1 );
/**
* Connect the Node associated with this Actor to the scene-graph.
+ * @param[in] index If set, it is only used for positioning the actor within the parent's child list.
*/
- void ConnectToSceneGraph();
+ void ConnectToSceneGraph(int index = -1);
/**
* Helper for ConnectToStage, to notify a connected actor through the public API.
/**
* Set the actors parent.
* @param[in] parent The new parent.
+ * @param[in] index If set, it is only used for positioning the actor within the parent's child list.
*/
- void SetParent(Actor* parent);
+ void SetParent(Actor* parent, int index = -1);
/**
* Helper to create a Node for this Actor.
mImpl->activeDisconnectedNodes.insert( node ); // Takes ownership of node
}
-void UpdateManager::ConnectNode( Node* parent, Node* node )
+void UpdateManager::ConnectNode( Node* parent, Node* node, int index )
{
DALI_ASSERT_ALWAYS( NULL != parent );
DALI_ASSERT_ALWAYS( NULL != node );
node->SetActive( true );
- parent->ConnectChild( node );
+ parent->ConnectChild( node, index );
}
void UpdateManager::DisconnectNode( Node* node )
* @param[in] node The new parent node.
* @param[in] node The node to connect.
*/
- void ConnectNode( Node* parent, Node* node );
+ void ConnectNode( Node* parent, Node* node, int index );
/**
* Disconnect a Node from the scene-graph.
new (slot) LocalType( &manager, &UpdateManager::AddNode, &node );
}
-inline void ConnectNodeMessage( UpdateManager& manager, const Node& constParent, const Node& constChild )
+inline void ConnectNodeMessage( UpdateManager& manager, const Node& constParent, const Node& constChild, int index )
{
// Update thread can edit the object
Node& parent = const_cast< Node& >( constParent );
Node& child = const_cast< Node& >( constChild );
- typedef MessageValue2< UpdateManager, Node*, Node* > LocalType;
+ typedef MessageValue3< UpdateManager, Node*, Node*, int > LocalType;
// Reserve some memory inside the message queue
unsigned int* slot = manager.GetEventToUpdate().ReserveMessageSlot( sizeof( LocalType ) );
// Construct message in the message queue memory; note that delete should not be called on the return value
- new (slot) LocalType( &manager, &UpdateManager::ConnectNode, &parent, &child );
+ new (slot) LocalType( &manager, &UpdateManager::ConnectNode, &parent, &child, index );
}
inline void DisconnectNodeMessage( UpdateManager& manager, const Node& constNode )
mIsRoot = isRoot;
}
-void Node::ConnectChild( Node* childNode )
+void Node::ConnectChild( Node* childNode, int index )
{
DALI_ASSERT_ALWAYS( this != childNode );
DALI_ASSERT_ALWAYS( IsRoot() || NULL != mParent ); // Parent should be connected first
// Everything should be reinherited when reconnected to scene-graph
childNode->SetAllDirtyFlags();
- mChildren.PushBack( childNode );
+ if (index == -1)
+ {
+ mChildren.PushBack( childNode );
+ }
+ else
+ {
+ mChildren.Insert(mChildren.Begin()+index, childNode);
+ }
}
void Node::DisconnectChild( BufferIndex updateBufferIndex, Node& childNode, std::set<Node*>& connectedNodes, std::set<Node*>& disconnectedNodes )
* @pre The childNode does not already have a parent.
* @pre The childNode is not a root node.
* @param[in] childNode The child to add.
+ * @param[in] index to insert at, if not supplied or -1 it will be appended
+ *
*/
- void ConnectChild( Node* childNode );
+ void ConnectChild( Node* childNode, int index = -1);
/**
* Disconnect a child (& its children) from the scene-graph.
GetImplementation(*this).Add(GetImplementation(actor));
}
+void Actor::Insert(unsigned int index, Actor actor)
+{
+ GetImplementation(*this).Insert(index, GetImplementation(actor));
+}
+
void Actor::Remove(Actor actor)
{
GetImplementation(*this).Remove(GetImplementation(actor));
void Add(Actor child);
/**
+ * @brief Inserts a child Actor to this actor's list of children at the given index
+ *
+ * NOTE! if the child already has a parent, it will be removed from old parent
+ * and reparented to this actor. This may change childs position, color,
+ * scale etc as it now inherits them from this actor
+ * @pre This Actor (the parent) has been initialized.
+ * @pre The child actor has been initialized.
+ * @pre The child actor is not the same as the parent actor.
+ * @pre The actor is not the Root actor
+ * @param [in] index of actor to insert before
+ * @param [in] child The child.
+ * @post The child will be referenced by its parent. This means that the child will be kept alive,
+ * even if the handle passed into this method is reset or destroyed.
+ * @post If the index is greater than the current child count, it will be ignored and added at the end.
+ * @post This may invalidate ActorContainer iterators.
+ */
+ void Insert(unsigned int index, Actor child);
+
+ /**
* @brief Removes a child Actor from this Actor.
*
* If the actor was not a child of this actor, this is a no-op.