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/internal/event/actors/actor-impl.h>
22 #include <dali/internal/event/common/scene-impl.h>
23 #include <dali/public-api/common/vector-wrapper.h>
34 /// Helper for emitting signals with multiple parameters
35 template<typename Signal, typename... Param>
36 void EmitSignal(Actor& actor, Signal& signal, Param... params)
40 Dali::Actor handle(&actor);
41 signal.Emit(handle, params...);
45 } //anonymous namespace
47 ActorParentImpl::ActorParentImpl(Actor& owner)
50 mChildRemovedSignal(),
51 mChildOrderChangedSignal()
55 ActorParentImpl::~ActorParentImpl()
60 void ActorParentImpl::Add(Actor& child, bool notify)
62 DALI_ASSERT_ALWAYS(&mOwner != &child && "Cannot add actor to itself");
63 DALI_ASSERT_ALWAYS(!child.IsRoot() && "Cannot add root actor");
67 mChildren = new ActorContainer;
70 Actor* oldParent = child.GetParent();
72 // child might already be ours
73 if(&mOwner != oldParent)
75 // if we already have parent, unparent us first
78 oldParent->Remove(child, notify); // This causes OnChildRemove callback & ChildRemoved signal
80 // Old parent may need to readjust to missing child
81 if(oldParent->RelayoutDependentOnChildren())
83 oldParent->RelayoutRequest();
87 // Guard against Add() during previous OnChildRemove callback
88 if(!child.GetParent())
90 // Do this first, since user callbacks from within SetParent() may need to remove child
91 mChildren->push_back(ActorPtr(&child));
93 // SetParent asserts that child can be added
94 child.SetParent(&mOwner, !notify);
98 // Notification for derived classes
99 mOwner.OnChildAdd(child);
100 EmitChildAddedSignal(child);
103 child.InheritLayoutDirectionRecursively(mOwner.GetLayoutDirection());
105 // Only put in a relayout request if there is a suitable dependency
106 if(mOwner.RelayoutDependentOnChildren())
108 mOwner.RelayoutRequest();
114 void ActorParentImpl::Remove(Actor& child, bool notify)
116 if((&mOwner == &child) || (!mChildren))
118 // no children or removing itself
124 // Find the child in mChildren, and unparent it
125 ActorIter end = mChildren->end();
126 for(ActorIter iter = mChildren->begin(); iter != end; ++iter)
128 ActorPtr actor = (*iter);
130 if(actor.Get() == &child)
132 // Keep handle for OnChildRemove notification
135 // Do this first, since user callbacks from within SetParent() may need to add the child
136 mChildren->erase(iter);
138 DALI_ASSERT_DEBUG(actor->GetParent() == &mOwner);
139 actor->SetParent(nullptr, (notify) ? false : true);
147 // Only put in a relayout request if there is a suitable dependency
148 if(mOwner.RelayoutDependentOnChildren())
150 mOwner.RelayoutRequest();
156 // Notification for derived classes
157 mOwner.OnChildRemove(child);
158 EmitChildRemovedSignal(child);
162 uint32_t ActorParentImpl::GetChildCount() const
164 return (nullptr != mChildren) ? static_cast<uint32_t>(mChildren->size()) : 0; // only 4,294,967,295 children per actor
167 ActorPtr ActorParentImpl::GetChildAt(uint32_t index) const
169 DALI_ASSERT_ALWAYS(index < GetChildCount());
171 return ((mChildren) ? (*mChildren)[index] : ActorPtr());
174 ActorPtr ActorParentImpl::FindChildByName(ConstString actorName)
176 ActorPtr child = nullptr;
177 if(actorName.GetStringView() == mOwner.GetName())
183 for(const auto& actor : *mChildren)
185 child = actor->FindChildByName(actorName);
196 ActorPtr ActorParentImpl::FindChildById(const uint32_t id)
198 ActorPtr child = nullptr;
199 if(id == mOwner.GetId())
205 for(const auto& actor : *mChildren)
207 child = actor->FindChildById(id);
218 void ActorParentImpl::UnparentChildren()
222 for(const auto& child : *mChildren)
224 child->SetParent(nullptr);
229 void ActorParentImpl::SetSiblingOrderOfChild(
235 uint32_t currentOrder = GetSiblingOrderOfChild(child);
236 if(order != currentOrder)
240 LowerChildToBottom(child);
242 else if(order < mChildren->size() - 1)
244 if(order > currentOrder)
246 RaiseChildAbove(child, *((*mChildren)[order]));
250 LowerChildBelow(child, *((*mChildren)[order]));
255 RaiseChildToTop(child);
261 uint32_t ActorParentImpl::GetSiblingOrderOfChild(const Actor& child) const
266 for(std::size_t i = 0; i < mChildren->size(); ++i)
268 if((*mChildren)[i] == &child)
270 order = static_cast<uint32_t>(i);
278 void ActorParentImpl::RaiseChild(Actor& child)
280 bool changed = false;
281 if(mChildren && mChildren->back() != &child) // If not already at end
283 for(std::size_t i = 0; i < mChildren->size(); ++i)
285 if((*mChildren)[i] == &child)
288 ActorPtr next = (*mChildren)[i + 1];
289 (*mChildren)[i + 1] = &child;
290 (*mChildren)[i] = next;
298 EmitOrderChangedAndRebuild(child);
302 void ActorParentImpl::LowerChild(Actor& child)
304 bool changed = false;
305 if(mChildren && mChildren->front() != &child) // If not already at beginning
307 for(std::size_t i = 1; i < mChildren->size(); ++i)
309 if((*mChildren)[i] == &child)
311 // Swap with previous
312 ActorPtr previous = (*mChildren)[i - 1];
313 (*mChildren)[i - 1] = &child;
314 (*mChildren)[i] = previous;
322 EmitOrderChangedAndRebuild(child);
326 void ActorParentImpl::RaiseChildToTop(Actor& child)
328 bool changed = false;
329 if(mChildren && mChildren->back() != &child) // If not already at end
331 auto iter = std::find(mChildren->begin(), mChildren->end(), &child);
332 if(iter != mChildren->end())
334 mChildren->erase(iter);
335 mChildren->push_back(ActorPtr(&child));
341 EmitOrderChangedAndRebuild(child);
345 void ActorParentImpl::LowerChildToBottom(Actor& child)
347 bool changed = false;
348 if(mChildren && mChildren->front() != &child) // If not already at bottom,
350 ActorPtr childPtr(&child); // ensure actor remains referenced.
352 auto iter = std::find(mChildren->begin(), mChildren->end(), &child);
353 if(iter != mChildren->end())
355 mChildren->erase(iter);
356 mChildren->insert(mChildren->begin(), childPtr);
362 EmitOrderChangedAndRebuild(child);
366 void ActorParentImpl::RaiseChildAbove(Actor& child, Actor& target)
369 if(mChildren && mChildren->back() != &child && target.GetParent() == child.GetParent()) // If not already at top
371 ActorPtr childPtr(&child); // ensure actor actor remains referenced.
373 auto targetIter = std::find(mChildren->begin(), mChildren->end(), &target);
374 auto childIter = std::find(mChildren->begin(), mChildren->end(), &child);
375 if(childIter < targetIter)
377 mChildren->erase(childIter);
378 // Erasing early invalidates the targetIter. (Conversely, inserting first may also
379 // invalidate actorIter)
380 targetIter = std::find(mChildren->begin(), mChildren->end(), &target);
382 mChildren->insert(targetIter, childPtr);
388 EmitOrderChangedAndRebuild(child);
392 void ActorParentImpl::LowerChildBelow(Actor& child, Actor& target)
394 bool lowered = false;
396 // If not already at bottom
397 if(mChildren && mChildren->front() != &child && target.GetParent() == child.GetParent())
399 ActorPtr childPtr(&child); // ensure actor actor remains referenced.
401 auto targetIter = std::find(mChildren->begin(), mChildren->end(), &target);
402 auto childIter = std::find(mChildren->begin(), mChildren->end(), &child);
404 if(childIter > targetIter)
406 mChildren->erase(childIter); // actor only invalidates iterators at or after actor point.
407 mChildren->insert(targetIter, childPtr);
413 EmitOrderChangedAndRebuild(child);
417 void ActorParentImpl::EmitChildAddedSignal(Actor& child)
419 EmitSignal(child, mChildAddedSignal);
422 void ActorParentImpl::EmitChildRemovedSignal(Actor& child)
424 EmitSignal(child, mChildRemovedSignal);
427 void ActorParentImpl::EmitOrderChangedAndRebuild(Actor& child)
429 EmitSignal(child, mChildOrderChangedSignal);
433 mOwner.GetScene().RequestRebuildDepthTree();
437 } // namespace Internal