2 * Copyright (c) 2023 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(
234 if(mChildren && !mChildren->empty())
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
265 if(mChildren && !mChildren->empty())
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->empty() && mChildren->back() != &child) // If not already at end
284 for(std::size_t i = 0; i + 1 < mChildren->size(); ++i)
286 if((*mChildren)[i] == &child)
289 ActorPtr next = std::move((*mChildren)[i + 1]);
290 (*mChildren)[i + 1] = &child;
291 (*mChildren)[i] = std::move(next);
299 EmitOrderChangedAndRebuild(child);
303 void ActorParentImpl::LowerChild(Actor& child)
305 bool changed = false;
306 if(mChildren && !mChildren->empty() && 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 = std::move((*mChildren)[i - 1]);
314 (*mChildren)[i - 1] = &child;
315 (*mChildren)[i] = std::move(previous);
323 EmitOrderChangedAndRebuild(child);
327 void ActorParentImpl::RaiseChildToTop(Actor& child)
329 bool changed = false;
330 if(mChildren && !mChildren->empty() && 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->empty() && 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->empty() && 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->empty() && 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 layer3DParentsCount, uint32_t depth)
438 DALI_ASSERT_ALWAYS(!mOwner.OnScene());
442 if(static_cast<Dali::Internal::Layer*>(&mOwner)->GetBehavior() == Dali::Layer::Behavior::LAYER_3D)
444 // This is 3d layer. Propagate it to all children.
445 ++layer3DParentsCount;
449 mOwner.mIsOnScene = true;
450 mOwner.mDepth = static_cast<uint16_t>(depth); // overflow ignored, not expected in practice
451 mOwner.mLayer3DParentsCount = static_cast<uint16_t>(layer3DParentsCount); // overflow ignored, not expected in practice
452 mOwner.ConnectToSceneGraph();
454 // Notification for internal derived classes
455 mOwner.OnSceneConnectionInternal();
457 // This stage is atomic; avoid emitting callbacks until all Actors are connected
458 connectionList.push_back(ActorPtr(&mOwner));
460 // Recursively connect children
463 for(const auto& actor : *mChildren)
465 actor->SetScene(*mOwner.mScene);
466 actor->mParentImpl.RecursiveConnectToScene(connectionList, layer3DParentsCount, depth + 1);
471 void ActorParentImpl::RecursiveDisconnectFromScene(ActorContainer& disconnectionList)
473 // need to change state first so that internals relying on IsOnScene() inside OnSceneDisconnectionInternal() get the correct value
474 mOwner.mIsOnScene = false;
475 mOwner.mScene = nullptr;
476 mOwner.mLayer3DParentsCount = 0;
478 // Recursively disconnect children
481 for(const auto& actor : *mChildren)
483 actor->mParentImpl.RecursiveDisconnectFromScene(disconnectionList);
487 // This stage is atomic; avoid emitting callbacks until all Actors are disconnected
488 disconnectionList.push_back(ActorPtr(&mOwner));
490 // Notification for internal derived classes
491 mOwner.OnSceneDisconnectionInternal();
492 mOwner.DisconnectFromSceneGraph();
495 void ActorParentImpl::RecursiveChangeLayer3dCount(int32_t layer3DParentsCountDiff)
497 mOwner.mLayer3DParentsCount += layer3DParentsCountDiff; // overflow ignored, not expected in practice
499 // Recursively change the value
502 for(const auto& actor : *mChildren)
504 actor->mParentImpl.RecursiveChangeLayer3dCount(layer3DParentsCountDiff);
509 void ActorParentImpl::InheritLayoutDirectionRecursively(Dali::LayoutDirection::Type direction, bool set)
511 if(mOwner.mInheritLayoutDirection || set)
513 if(mOwner.mLayoutDirection != direction)
515 mOwner.mLayoutDirection = direction;
516 mOwner.EmitLayoutDirectionChangedSignal(direction);
517 mOwner.RelayoutRequest();
522 for(const auto& child : *mChildren)
524 child->mParentImpl.InheritLayoutDirectionRecursively(direction);
530 void ActorParentImpl::EmitVisibilityChangedSignalRecursively(
532 DevelActor::VisibilityChange::Type type)
534 if(!visible && mOwner.OnScene())
536 //The actor should receive an interrupted event when it is hidden.
537 mOwner.GetScene().SendInterruptedEvents(&mOwner);
540 mOwner.EmitVisibilityChangedSignal(visible, type);
544 for(const auto& child : *mChildren)
546 child->mParentImpl.EmitVisibilityChangedSignalRecursively(visible, DevelActor::VisibilityChange::PARENT);
551 void ActorParentImpl::EmitChildAddedSignal(Actor& child)
553 EmitSignal(child, mChildAddedSignal);
556 void ActorParentImpl::EmitChildRemovedSignal(Actor& child)
558 EmitSignal(child, mChildRemovedSignal);
561 void ActorParentImpl::EmitOrderChangedAndRebuild(Actor& child)
563 EmitSignal(child, mChildOrderChangedSignal);
567 mOwner.GetScene().RequestRebuildDepthTree();
571 } // namespace Internal