2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali/internal/event/actors/actor-parent.h>
21 #include <dali/devel-api/actors/layer-devel.h>
22 #include <dali/internal/event/actors/actor-impl.h>
23 #include <dali/internal/event/common/scene-impl.h>
24 #include <dali/public-api/common/vector-wrapper.h>
35 /// Helper for emitting signals with multiple parameters
36 template<typename Signal, typename... Param>
37 void EmitSignal(Actor& actor, Signal& signal, Param... params)
41 Dali::Actor handle(&actor);
42 signal.Emit(handle, params...);
46 } //anonymous namespace
48 ActorParentImpl::ActorParentImpl(Actor& owner)
51 mChildRemovedSignal(),
52 mChildOrderChangedSignal()
56 ActorParentImpl::~ActorParentImpl()
61 void ActorParentImpl::Add(Actor& child, bool notify)
63 DALI_ASSERT_ALWAYS(&mOwner != &child && "Cannot add actor to itself");
64 DALI_ASSERT_ALWAYS(!child.IsRoot() && "Cannot add root actor");
68 mChildren = new ActorContainer;
71 Actor* oldParent = child.GetParent();
73 // child might already be ours
74 if(&mOwner != oldParent)
76 // if we already have parent, unparent us first
79 oldParent->Remove(child, notify); // This causes OnChildRemove callback & ChildRemoved signal
81 // Old parent may need to readjust to missing child
82 if(oldParent->RelayoutDependentOnChildren())
84 oldParent->RelayoutRequest();
88 // Guard against Add() during previous OnChildRemove callback
89 if(!child.GetParent())
91 // Do this first, since user callbacks from within SetParent() may need to remove child
92 mChildren->push_back(ActorPtr(&child));
94 // SetParent asserts that child can be added
95 child.SetParent(&mOwner, notify);
99 // Notification for derived classes
100 mOwner.OnChildAdd(child);
101 EmitChildAddedSignal(child);
104 child.mParentImpl.InheritLayoutDirectionRecursively(mOwner.GetLayoutDirection());
106 // Only put in a relayout request if there is a suitable dependency
107 if(mOwner.RelayoutDependentOnChildren())
109 mOwner.RelayoutRequest();
115 void ActorParentImpl::Remove(Actor& child, bool notify)
117 if((&mOwner == &child) || (!mChildren))
119 // no children or removing itself
125 // Find the child in mChildren, and unparent it
126 ActorIter end = mChildren->end();
127 for(ActorIter iter = mChildren->begin(); iter != end; ++iter)
129 ActorPtr actor = (*iter);
131 if(actor.Get() == &child)
133 // Keep handle for OnChildRemove notification
136 // Do this first, since user callbacks from within SetParent() may need to add the child
137 mChildren->erase(iter);
139 DALI_ASSERT_DEBUG(actor->GetParent() == &mOwner);
140 actor->SetParent(nullptr, notify);
148 // Only put in a relayout request if there is a suitable dependency
149 if(mOwner.RelayoutDependentOnChildren())
151 mOwner.RelayoutRequest();
157 // Notification for derived classes
158 mOwner.OnChildRemove(child);
159 EmitChildRemovedSignal(child);
163 uint32_t ActorParentImpl::GetChildCount() const
165 return (nullptr != mChildren) ? static_cast<uint32_t>(mChildren->size()) : 0; // only 4,294,967,295 children per actor
168 ActorPtr ActorParentImpl::GetChildAt(uint32_t index) const
170 DALI_ASSERT_ALWAYS(index < GetChildCount());
172 return ((mChildren) ? (*mChildren)[index] : ActorPtr());
175 ActorPtr ActorParentImpl::FindChildByName(ConstString actorName)
177 ActorPtr child = nullptr;
178 if(actorName.GetStringView() == mOwner.GetName())
184 for(const auto& actor : *mChildren)
186 child = actor->FindChildByName(actorName);
197 ActorPtr ActorParentImpl::FindChildById(const uint32_t id)
199 ActorPtr child = nullptr;
200 if(id == mOwner.GetId())
206 for(const auto& actor : *mChildren)
208 child = actor->FindChildById(id);
219 void ActorParentImpl::UnparentChildren()
223 for(const auto& child : *mChildren)
225 child->SetParent(nullptr);
230 void ActorParentImpl::SetSiblingOrderOfChild(
236 uint32_t currentOrder = GetSiblingOrderOfChild(child);
237 if(order != currentOrder)
241 LowerChildToBottom(child);
243 else if(order < mChildren->size() - 1)
245 if(order > currentOrder)
247 RaiseChildAbove(child, *((*mChildren)[order]));
251 LowerChildBelow(child, *((*mChildren)[order]));
256 RaiseChildToTop(child);
262 uint32_t ActorParentImpl::GetSiblingOrderOfChild(const Actor& child) const
267 for(std::size_t i = 0; i < mChildren->size(); ++i)
269 if((*mChildren)[i] == &child)
271 order = static_cast<uint32_t>(i);
279 void ActorParentImpl::RaiseChild(Actor& child)
281 bool changed = false;
282 if(mChildren && mChildren->back() != &child) // If not already at end
284 for(std::size_t i = 0; i < mChildren->size(); ++i)
286 if((*mChildren)[i] == &child)
289 ActorPtr next = (*mChildren)[i + 1];
290 (*mChildren)[i + 1] = &child;
291 (*mChildren)[i] = next;
299 EmitOrderChangedAndRebuild(child);
303 void ActorParentImpl::LowerChild(Actor& child)
305 bool changed = false;
306 if(mChildren && mChildren->front() != &child) // If not already at beginning
308 for(std::size_t i = 1; i < mChildren->size(); ++i)
310 if((*mChildren)[i] == &child)
312 // Swap with previous
313 ActorPtr previous = (*mChildren)[i - 1];
314 (*mChildren)[i - 1] = &child;
315 (*mChildren)[i] = previous;
323 EmitOrderChangedAndRebuild(child);
327 void ActorParentImpl::RaiseChildToTop(Actor& child)
329 bool changed = false;
330 if(mChildren && mChildren->back() != &child) // If not already at end
332 auto iter = std::find(mChildren->begin(), mChildren->end(), &child);
333 if(iter != mChildren->end())
335 mChildren->erase(iter);
336 mChildren->push_back(ActorPtr(&child));
342 EmitOrderChangedAndRebuild(child);
346 void ActorParentImpl::LowerChildToBottom(Actor& child)
348 bool changed = false;
349 if(mChildren && mChildren->front() != &child) // If not already at bottom,
351 ActorPtr childPtr(&child); // ensure actor remains referenced.
353 auto iter = std::find(mChildren->begin(), mChildren->end(), &child);
354 if(iter != mChildren->end())
356 mChildren->erase(iter);
357 mChildren->insert(mChildren->begin(), childPtr);
363 EmitOrderChangedAndRebuild(child);
367 void ActorParentImpl::RaiseChildAbove(Actor& child, Actor& target)
370 if(mChildren && mChildren->back() != &child && target.GetParent() == child.GetParent()) // If not already at top
372 ActorPtr childPtr(&child); // ensure actor actor remains referenced.
374 auto targetIter = std::find(mChildren->begin(), mChildren->end(), &target);
375 auto childIter = std::find(mChildren->begin(), mChildren->end(), &child);
376 if(childIter < targetIter)
378 mChildren->erase(childIter);
379 // Erasing early invalidates the targetIter. (Conversely, inserting first may also
380 // invalidate actorIter)
381 targetIter = std::find(mChildren->begin(), mChildren->end(), &target);
383 mChildren->insert(targetIter, childPtr);
389 EmitOrderChangedAndRebuild(child);
393 void ActorParentImpl::LowerChildBelow(Actor& child, Actor& target)
395 bool lowered = false;
397 // If not already at bottom
398 if(mChildren && mChildren->front() != &child && target.GetParent() == child.GetParent())
400 ActorPtr childPtr(&child); // ensure actor actor remains referenced.
402 auto targetIter = std::find(mChildren->begin(), mChildren->end(), &target);
403 auto childIter = std::find(mChildren->begin(), mChildren->end(), &child);
405 if(childIter > targetIter)
407 mChildren->erase(childIter); // actor only invalidates iterators at or after actor point.
408 mChildren->insert(targetIter, childPtr);
414 EmitOrderChangedAndRebuild(child);
418 void ActorParentImpl::DepthTraverseActorTree(OwnerPointer<SceneGraph::NodeDepths>& sceneGraphNodeDepths,
421 uint32_t sortedDepth = depthIndex * DevelLayer::SIBLING_ORDER_MULTIPLIER;
422 mOwner.SetSortingDepth(sortedDepth);
423 sceneGraphNodeDepths->Add(const_cast<SceneGraph::Node*>(&mOwner.GetNode()), sortedDepth);
425 // Create/add to children of this node
428 for(const auto& actor : *mChildren)
431 actor->mParentImpl.DepthTraverseActorTree(sceneGraphNodeDepths, depthIndex);
436 void ActorParentImpl::RecursiveConnectToScene(ActorContainer& connectionList, uint32_t depth)
438 DALI_ASSERT_ALWAYS(!mOwner.OnScene());
440 mOwner.mIsOnScene = true;
441 mOwner.mDepth = static_cast<uint16_t>(depth); // overflow ignored, not expected in practice
442 mOwner.ConnectToSceneGraph();
444 // Notification for internal derived classes
445 mOwner.OnSceneConnectionInternal();
447 // This stage is atomic; avoid emitting callbacks until all Actors are connected
448 connectionList.push_back(ActorPtr(&mOwner));
450 // Recursively connect children
453 for(const auto& actor : *mChildren)
455 actor->SetScene(*mOwner.mScene);
456 actor->mParentImpl.RecursiveConnectToScene(connectionList, depth + 1);
461 void ActorParentImpl::RecursiveDisconnectFromScene(ActorContainer& disconnectionList)
463 // need to change state first so that internals relying on IsOnScene() inside OnSceneDisconnectionInternal() get the correct value
464 mOwner.mIsOnScene = false;
466 // Recursively disconnect children
469 for(const auto& actor : *mChildren)
471 actor->mParentImpl.RecursiveDisconnectFromScene(disconnectionList);
475 // This stage is atomic; avoid emitting callbacks until all Actors are disconnected
476 disconnectionList.push_back(ActorPtr(&mOwner));
478 // Notification for internal derived classes
479 mOwner.OnSceneDisconnectionInternal();
480 mOwner.DisconnectFromSceneGraph();
483 void ActorParentImpl::InheritLayoutDirectionRecursively(Dali::LayoutDirection::Type direction, bool set)
485 if(mOwner.mInheritLayoutDirection || set)
487 if(mOwner.mLayoutDirection != direction)
489 mOwner.mLayoutDirection = direction;
490 mOwner.EmitLayoutDirectionChangedSignal(direction);
491 mOwner.RelayoutRequest();
496 for(const auto& child : *mChildren)
498 child->mParentImpl.InheritLayoutDirectionRecursively(direction);
504 void ActorParentImpl::EmitVisibilityChangedSignalRecursively(
506 DevelActor::VisibilityChange::Type type)
508 mOwner.EmitVisibilityChangedSignal(visible, type);
512 for(const auto& child : *mChildren)
514 child->mParentImpl.EmitVisibilityChangedSignalRecursively(visible, DevelActor::VisibilityChange::PARENT);
519 void ActorParentImpl::EmitChildAddedSignal(Actor& child)
521 EmitSignal(child, mChildAddedSignal);
524 void ActorParentImpl::EmitChildRemovedSignal(Actor& child)
526 EmitSignal(child, mChildRemovedSignal);
529 void ActorParentImpl::EmitOrderChangedAndRebuild(Actor& child)
531 EmitSignal(child, mChildOrderChangedSignal);
535 mOwner.GetScene().RequestRebuildDepthTree();
539 } // namespace Internal