[Tizen] Make mScene nullptr when the Actor is disconnected from Scene recursively
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-parent-impl.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 // CLASS HEADER
18 #include <dali/internal/event/actors/actor-parent.h>
19
20 // INTERNAL INCLUDES
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>
25
26 // EXTERNAL INCLUDES
27 #include <algorithm>
28
29 namespace Dali
30 {
31 namespace Internal
32 {
33 namespace
34 {
35 /// Helper for emitting signals with multiple parameters
36 template<typename Signal, typename... Param>
37 void EmitSignal(Actor& actor, Signal& signal, Param... params)
38 {
39   if(!signal.Empty())
40   {
41     Dali::Actor handle(&actor);
42     signal.Emit(handle, params...);
43   }
44 }
45
46 } //anonymous namespace
47
48 ActorParentImpl::ActorParentImpl(Actor& owner)
49 : mOwner(owner),
50   mChildAddedSignal(),
51   mChildRemovedSignal(),
52   mChildOrderChangedSignal()
53 {
54 }
55
56 ActorParentImpl::~ActorParentImpl()
57 {
58   delete mChildren;
59 }
60
61 void ActorParentImpl::Add(Actor& child, bool notify)
62 {
63   DALI_ASSERT_ALWAYS(&mOwner != &child && "Cannot add actor to itself");
64   DALI_ASSERT_ALWAYS(!child.IsRoot() && "Cannot add root actor");
65
66   if(!mChildren)
67   {
68     mChildren = new ActorContainer;
69   }
70
71   Actor* oldParent = child.GetParent();
72
73   // child might already be ours
74   if(&mOwner != oldParent)
75   {
76     // if we already have parent, unparent us first
77     if(oldParent)
78     {
79       oldParent->Remove(child, notify); // This causes OnChildRemove callback & ChildRemoved signal
80
81       // Old parent may need to readjust to missing child
82       if(oldParent->RelayoutDependentOnChildren())
83       {
84         oldParent->RelayoutRequest();
85       }
86     }
87
88     // Guard against Add() during previous OnChildRemove callback
89     if(!child.GetParent())
90     {
91       // Do this first, since user callbacks from within SetParent() may need to remove child
92       mChildren->push_back(ActorPtr(&child));
93
94       // SetParent asserts that child can be added
95       child.SetParent(&mOwner, notify);
96
97       if(notify)
98       {
99         // Notification for derived classes
100         mOwner.OnChildAdd(child);
101         EmitChildAddedSignal(child);
102       }
103
104       child.mParentImpl.InheritLayoutDirectionRecursively(mOwner.GetLayoutDirection());
105
106       // Only put in a relayout request if there is a suitable dependency
107       if(mOwner.RelayoutDependentOnChildren())
108       {
109         mOwner.RelayoutRequest();
110       }
111     }
112   }
113 }
114
115 void ActorParentImpl::Remove(Actor& child, bool notify)
116 {
117   if((&mOwner == &child) || (!mChildren))
118   {
119     // no children or removing itself
120     return;
121   }
122
123   ActorPtr removed;
124
125   // Find the child in mChildren, and unparent it
126   ActorIter end = mChildren->end();
127   for(ActorIter iter = mChildren->begin(); iter != end; ++iter)
128   {
129     ActorPtr actor = (*iter);
130
131     if(actor.Get() == &child)
132     {
133       // Keep handle for OnChildRemove notification
134       removed = actor;
135
136       // Do this first, since user callbacks from within SetParent() may need to add the child
137       mChildren->erase(iter);
138
139       DALI_ASSERT_DEBUG(actor->GetParent() == &mOwner);
140       actor->SetParent(nullptr, notify);
141
142       break;
143     }
144   }
145
146   if(removed)
147   {
148     // Only put in a relayout request if there is a suitable dependency
149     if(mOwner.RelayoutDependentOnChildren())
150     {
151       mOwner.RelayoutRequest();
152     }
153   }
154
155   if(notify)
156   {
157     // Notification for derived classes
158     mOwner.OnChildRemove(child);
159     EmitChildRemovedSignal(child);
160   }
161 }
162
163 uint32_t ActorParentImpl::GetChildCount() const
164 {
165   return (nullptr != mChildren) ? static_cast<uint32_t>(mChildren->size()) : 0; // only 4,294,967,295 children per actor
166 }
167
168 ActorPtr ActorParentImpl::GetChildAt(uint32_t index) const
169 {
170   DALI_ASSERT_ALWAYS(index < GetChildCount());
171
172   return ((mChildren) ? (*mChildren)[index] : ActorPtr());
173 }
174
175 ActorPtr ActorParentImpl::FindChildByName(ConstString actorName)
176 {
177   ActorPtr child = nullptr;
178   if(actorName.GetStringView() == mOwner.GetName())
179   {
180     child = &mOwner;
181   }
182   else if(mChildren)
183   {
184     for(const auto& actor : *mChildren)
185     {
186       child = actor->FindChildByName(actorName);
187
188       if(child)
189       {
190         break;
191       }
192     }
193   }
194   return child;
195 }
196
197 ActorPtr ActorParentImpl::FindChildById(const uint32_t id)
198 {
199   ActorPtr child = nullptr;
200   if(id == mOwner.GetId())
201   {
202     child = &mOwner;
203   }
204   else if(mChildren)
205   {
206     for(const auto& actor : *mChildren)
207     {
208       child = actor->FindChildById(id);
209
210       if(child)
211       {
212         break;
213       }
214     }
215   }
216   return child;
217 }
218
219 void ActorParentImpl::UnparentChildren()
220 {
221   if(mChildren)
222   {
223     for(const auto& child : *mChildren)
224     {
225       child->SetParent(nullptr);
226     }
227   }
228 }
229
230 void ActorParentImpl::SetSiblingOrderOfChild(
231   Actor&   child,
232   uint32_t order)
233 {
234   if(mChildren)
235   {
236     uint32_t currentOrder = GetSiblingOrderOfChild(child);
237     if(order != currentOrder)
238     {
239       if(order == 0)
240       {
241         LowerChildToBottom(child);
242       }
243       else if(order < mChildren->size() - 1)
244       {
245         if(order > currentOrder)
246         {
247           RaiseChildAbove(child, *((*mChildren)[order]));
248         }
249         else
250         {
251           LowerChildBelow(child, *((*mChildren)[order]));
252         }
253       }
254       else
255       {
256         RaiseChildToTop(child);
257       }
258     }
259   }
260 }
261
262 uint32_t ActorParentImpl::GetSiblingOrderOfChild(const Actor& child) const
263 {
264   uint32_t order = 0;
265   if(mChildren)
266   {
267     for(std::size_t i = 0; i < mChildren->size(); ++i)
268     {
269       if((*mChildren)[i] == &child)
270       {
271         order = static_cast<uint32_t>(i);
272         break;
273       }
274     }
275   }
276   return order;
277 }
278
279 void ActorParentImpl::RaiseChild(Actor& child)
280 {
281   bool changed = false;
282   if(mChildren && mChildren->back() != &child) // If not already at end
283   {
284     for(std::size_t i = 0; i < mChildren->size(); ++i)
285     {
286       if((*mChildren)[i] == &child)
287       {
288         // Swap with next
289         ActorPtr next       = (*mChildren)[i + 1];
290         (*mChildren)[i + 1] = &child;
291         (*mChildren)[i]     = next;
292         changed             = true;
293         break;
294       }
295     }
296   }
297   if(changed)
298   {
299     EmitOrderChangedAndRebuild(child);
300   }
301 }
302
303 void ActorParentImpl::LowerChild(Actor& child)
304 {
305   bool changed = false;
306   if(mChildren && mChildren->front() != &child) // If not already at beginning
307   {
308     for(std::size_t i = 1; i < mChildren->size(); ++i)
309     {
310       if((*mChildren)[i] == &child)
311       {
312         // Swap with previous
313         ActorPtr previous   = (*mChildren)[i - 1];
314         (*mChildren)[i - 1] = &child;
315         (*mChildren)[i]     = previous;
316         changed             = true;
317         break;
318       }
319     }
320   }
321   if(changed)
322   {
323     EmitOrderChangedAndRebuild(child);
324   }
325 }
326
327 void ActorParentImpl::RaiseChildToTop(Actor& child)
328 {
329   bool changed = false;
330   if(mChildren && mChildren->back() != &child) // If not already at end
331   {
332     auto iter = std::find(mChildren->begin(), mChildren->end(), &child);
333     if(iter != mChildren->end())
334     {
335       mChildren->erase(iter);
336       mChildren->push_back(ActorPtr(&child));
337       changed = true;
338     }
339   }
340   if(changed)
341   {
342     EmitOrderChangedAndRebuild(child);
343   }
344 }
345
346 void ActorParentImpl::LowerChildToBottom(Actor& child)
347 {
348   bool changed = false;
349   if(mChildren && mChildren->front() != &child) // If not already at bottom,
350   {
351     ActorPtr childPtr(&child); // ensure actor remains referenced.
352
353     auto iter = std::find(mChildren->begin(), mChildren->end(), &child);
354     if(iter != mChildren->end())
355     {
356       mChildren->erase(iter);
357       mChildren->insert(mChildren->begin(), childPtr);
358       changed = true;
359     }
360   }
361   if(changed)
362   {
363     EmitOrderChangedAndRebuild(child);
364   }
365 }
366
367 void ActorParentImpl::RaiseChildAbove(Actor& child, Actor& target)
368 {
369   bool raised = false;
370   if(mChildren && mChildren->back() != &child && target.GetParent() == child.GetParent()) // If not already at top
371   {
372     ActorPtr childPtr(&child); // ensure actor actor remains referenced.
373
374     auto targetIter = std::find(mChildren->begin(), mChildren->end(), &target);
375     auto childIter  = std::find(mChildren->begin(), mChildren->end(), &child);
376     if(childIter < targetIter)
377     {
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);
382       ++targetIter;
383       mChildren->insert(targetIter, childPtr);
384     }
385     raised = true;
386   }
387   if(raised)
388   {
389     EmitOrderChangedAndRebuild(child);
390   }
391 }
392
393 void ActorParentImpl::LowerChildBelow(Actor& child, Actor& target)
394 {
395   bool lowered = false;
396
397   // If not already at bottom
398   if(mChildren && mChildren->front() != &child && target.GetParent() == child.GetParent())
399   {
400     ActorPtr childPtr(&child); // ensure actor actor remains referenced.
401
402     auto targetIter = std::find(mChildren->begin(), mChildren->end(), &target);
403     auto childIter  = std::find(mChildren->begin(), mChildren->end(), &child);
404
405     if(childIter > targetIter)
406     {
407       mChildren->erase(childIter); // actor only invalidates iterators at or after actor point.
408       mChildren->insert(targetIter, childPtr);
409     }
410     lowered = true;
411   }
412   if(lowered)
413   {
414     EmitOrderChangedAndRebuild(child);
415   }
416 }
417
418 void ActorParentImpl::DepthTraverseActorTree(OwnerPointer<SceneGraph::NodeDepths>& sceneGraphNodeDepths,
419                                              int32_t&                              depthIndex)
420 {
421   uint32_t sortedDepth = depthIndex * DevelLayer::SIBLING_ORDER_MULTIPLIER;
422   mOwner.SetSortingDepth(sortedDepth);
423   sceneGraphNodeDepths->Add(const_cast<SceneGraph::Node*>(&mOwner.GetNode()), sortedDepth);
424
425   // Create/add to children of this node
426   if(mChildren)
427   {
428     for(const auto& actor : *mChildren)
429     {
430       ++depthIndex;
431       actor->mParentImpl.DepthTraverseActorTree(sceneGraphNodeDepths, depthIndex);
432     }
433   }
434 }
435
436 void ActorParentImpl::RecursiveConnectToScene(ActorContainer& connectionList, uint32_t depth)
437 {
438   DALI_ASSERT_ALWAYS(!mOwner.OnScene());
439
440   mOwner.mIsOnScene = true;
441   mOwner.mDepth     = static_cast<uint16_t>(depth); // overflow ignored, not expected in practice
442   mOwner.ConnectToSceneGraph();
443
444   // Notification for internal derived classes
445   mOwner.OnSceneConnectionInternal();
446
447   // This stage is atomic; avoid emitting callbacks until all Actors are connected
448   connectionList.push_back(ActorPtr(&mOwner));
449
450   // Recursively connect children
451   if(mChildren)
452   {
453     for(const auto& actor : *mChildren)
454     {
455       actor->SetScene(*mOwner.mScene);
456       actor->mParentImpl.RecursiveConnectToScene(connectionList, depth + 1);
457     }
458   }
459 }
460
461 void ActorParentImpl::RecursiveDisconnectFromScene(ActorContainer& disconnectionList)
462 {
463   // need to change state first so that internals relying on IsOnScene() inside OnSceneDisconnectionInternal() get the correct value
464   mOwner.mIsOnScene = false;
465   mOwner.mScene     = nullptr;
466
467   // Recursively disconnect children
468   if(mChildren)
469   {
470     for(const auto& actor : *mChildren)
471     {
472       actor->mParentImpl.RecursiveDisconnectFromScene(disconnectionList);
473     }
474   }
475
476   // This stage is atomic; avoid emitting callbacks until all Actors are disconnected
477   disconnectionList.push_back(ActorPtr(&mOwner));
478
479   // Notification for internal derived classes
480   mOwner.OnSceneDisconnectionInternal();
481   mOwner.DisconnectFromSceneGraph();
482 }
483
484 void ActorParentImpl::InheritLayoutDirectionRecursively(Dali::LayoutDirection::Type direction, bool set)
485 {
486   if(mOwner.mInheritLayoutDirection || set)
487   {
488     if(mOwner.mLayoutDirection != direction)
489     {
490       mOwner.mLayoutDirection = direction;
491       mOwner.EmitLayoutDirectionChangedSignal(direction);
492       mOwner.RelayoutRequest();
493     }
494
495     if(mChildren)
496     {
497       for(const auto& child : *mChildren)
498       {
499         child->mParentImpl.InheritLayoutDirectionRecursively(direction);
500       }
501     }
502   }
503 }
504
505 void ActorParentImpl::EmitVisibilityChangedSignalRecursively(
506   bool                               visible,
507   DevelActor::VisibilityChange::Type type)
508 {
509   mOwner.EmitVisibilityChangedSignal(visible, type);
510
511   if(mChildren)
512   {
513     for(const auto& child : *mChildren)
514     {
515       child->mParentImpl.EmitVisibilityChangedSignalRecursively(visible, DevelActor::VisibilityChange::PARENT);
516     }
517   }
518 }
519
520 void ActorParentImpl::EmitChildAddedSignal(Actor& child)
521 {
522   EmitSignal(child, mChildAddedSignal);
523 }
524
525 void ActorParentImpl::EmitChildRemovedSignal(Actor& child)
526 {
527   EmitSignal(child, mChildRemovedSignal);
528 }
529
530 void ActorParentImpl::EmitOrderChangedAndRebuild(Actor& child)
531 {
532   EmitSignal(child, mChildOrderChangedSignal);
533
534   if(mOwner.OnScene())
535   {
536     mOwner.GetScene().RequestRebuildDepthTree();
537   }
538 }
539
540 } // namespace Internal
541
542 } // namespace Dali