Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / constraint-base.cpp
1 /*
2  * Copyright (c) 2021 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
18 // CLASS HEADER
19 #include <dali/internal/event/animation/constraint-base.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/event/common/event-thread-services.h>
23 #include <dali/internal/event/common/property-helper.h>
24 #include <dali/internal/event/common/stage-impl.h>
25 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
26 #include <dali/internal/update/common/animatable-property.h>
27 #include <dali/internal/update/common/property-owner-messages.h>
28 #include <dali/public-api/object/handle.h>
29 #include <dali/public-api/object/type-registry.h>
30
31 using Dali::Internal::SceneGraph::AnimatableProperty;
32
33 namespace Dali
34 {
35 namespace Internal
36 {
37 namespace
38 {
39 /**
40  * Helper to add only unique entries to the propertyOwner container
41  * @param propertyOwners to add the entries to
42  * @param object to add
43  */
44 inline void AddUnique(SceneGraph::PropertyOwnerContainer& propertyOwners, SceneGraph::PropertyOwner* object)
45 {
46   const SceneGraph::PropertyOwnerIter iter = std::find(propertyOwners.Begin(), propertyOwners.End(), object);
47   if(iter == propertyOwners.End())
48   {
49     // each owner should only be added once
50     propertyOwners.PushBack(object);
51   }
52 }
53 } // unnamed namespace
54
55 ConstraintBase::ConstraintBase(Object& object, Property::Index targetPropertyIndex, SourceContainer& sources)
56 : mEventThreadServices(EventThreadServices::Get()),
57   mTargetObject(&object),
58   mSceneGraphConstraint(nullptr),
59   mSources(sources),
60   mObservedObjects(),
61   mTargetPropertyIndex(targetPropertyIndex),
62   mRemoveAction(Dali::Constraint::DEFAULT_REMOVE_ACTION),
63   mTag(0),
64   mApplied(false),
65   mSourceDestroyed(false),
66   mIsPreConstraint(true)
67 {
68   ObserveObject(object);
69 }
70
71 ConstraintBase* ConstraintBase::Clone(Object& object)
72 {
73   DALI_ASSERT_ALWAYS(!mSourceDestroyed && "An input source object has been destroyed");
74
75   // create the type specific object
76   ConstraintBase* clone = DoClone(object);
77   clone->SetRemoveAction(mRemoveAction);
78   clone->SetTag(mTag);
79   return clone;
80 }
81
82 ConstraintBase::~ConstraintBase()
83 {
84   StopObservation();
85
86   RemoveInternal();
87 }
88
89 void ConstraintBase::AddSource(Source source)
90 {
91   mSources.push_back(source);
92
93   // Observe the object providing this property
94   if(OBJECT_PROPERTY == source.sourceType)
95   {
96     if(source.object != nullptr)
97     {
98       ObserveObject(*source.object);
99     }
100     else
101     {
102       DALI_LOG_ERROR("Constraint source object not found\n");
103     }
104   }
105 }
106
107 void ConstraintBase::Apply(bool isPreConstraint)
108 {
109   if(mTargetObject && !mApplied && !mSourceDestroyed)
110   {
111     mApplied = true;
112     mIsPreConstraint = isPreConstraint;
113     ConnectConstraint(mIsPreConstraint);
114
115     mTargetObject->ApplyConstraint(*this);
116   }
117   else
118   {
119     DALI_LOG_ERROR("Fail to apply constraint\n");
120   }
121 }
122
123 void ConstraintBase::ApplyPost()
124 {
125   Apply(false);
126 }
127
128 void ConstraintBase::Remove()
129 {
130   RemoveInternal();
131
132   if(mTargetObject)
133   {
134     mTargetObject->RemoveConstraint(*this);
135   }
136   mIsPreConstraint = true;
137 }
138
139 void ConstraintBase::RemoveInternal()
140 {
141   if(mApplied)
142   {
143     mApplied = false;
144
145     // Guard against constraint sending messages during core destruction
146     if(Stage::IsInstalled())
147     {
148       if(mTargetObject && mSceneGraphConstraint)
149       {
150         const SceneGraph::PropertyOwner& propertyOwner = mTargetObject->GetSceneObject();
151         // Remove from scene-graph
152         if(mIsPreConstraint)
153         {
154           RemoveConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
155         }
156         else
157         {
158           RemovePostConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
159         }
160         // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
161         mSceneGraphConstraint = nullptr;
162       }
163     }
164   }
165 }
166
167 Object* ConstraintBase::GetParent()
168 {
169   return mTargetObject;
170 }
171
172 Dali::Handle ConstraintBase::GetTargetObject()
173 {
174   return Dali::Handle(mTargetObject);
175 }
176
177 Property::Index ConstraintBase::GetTargetProperty()
178 {
179   return mTargetPropertyIndex;
180 }
181
182 void ConstraintBase::SetRemoveAction(ConstraintBase::RemoveAction action)
183 {
184   mRemoveAction = action;
185 }
186
187 ConstraintBase::RemoveAction ConstraintBase::GetRemoveAction() const
188 {
189   return mRemoveAction;
190 }
191
192 void ConstraintBase::SetTag(uint32_t tag)
193 {
194   mTag = tag;
195 }
196
197 uint32_t ConstraintBase::GetTag() const
198 {
199   return mTag;
200 }
201
202 void ConstraintBase::SceneObjectAdded(Object& object)
203 {
204   if(mApplied &&
205      (nullptr == mSceneGraphConstraint) &&
206      mTargetObject)
207   {
208     ConnectConstraint(mIsPreConstraint);
209   }
210 }
211
212 void ConstraintBase::SceneObjectRemoved(Object& object)
213 {
214   if(mSceneGraphConstraint)
215   {
216     // An input property owning source has been deleted, need to tell the scene-graph-constraint owner to remove it
217     if(&object != mTargetObject)
218     {
219       if(mTargetObject)
220       {
221         const SceneGraph::PropertyOwner& propertyOwner = mTargetObject->GetSceneObject();
222         // Remove from scene-graph
223         RemoveConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
224       }
225     }
226
227     // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
228     mSceneGraphConstraint = nullptr;
229   }
230 }
231
232 void ConstraintBase::ObjectDestroyed(Object& object)
233 {
234   // Remove object pointer from observation set
235   ObjectIter iter = std::find(mObservedObjects.Begin(), mObservedObjects.End(), &object);
236   DALI_ASSERT_DEBUG(mObservedObjects.End() != iter);
237   mObservedObjects.Erase(iter);
238
239   // Constraint is not useful anymore as an input-source has been destroyed
240   mSourceDestroyed = true;
241
242   // Stop observing the remaining objects
243   StopObservation();
244
245   // Clear our sources as well
246   mSources.clear();
247
248   // Discard all object & scene-graph pointers
249   mSceneGraphConstraint = nullptr;
250   mTargetObject         = nullptr;
251 }
252
253 void ConstraintBase::ObserveObject(Object& object)
254 {
255   ObjectIter iter = std::find(mObservedObjects.Begin(), mObservedObjects.End(), &object);
256   if(mObservedObjects.End() == iter)
257   {
258     object.AddObserver(*this);
259     mObservedObjects.PushBack(&object);
260   }
261 }
262
263 void ConstraintBase::StopObservation()
264 {
265   const ObjectIter end = mObservedObjects.End();
266   for(ObjectIter iter = mObservedObjects.Begin(); iter != end; ++iter)
267   {
268     (*iter)->RemoveObserver(*this);
269   }
270
271   mObservedObjects.Clear();
272 }
273
274 PropertyInputImpl* ConstraintBase::AddInputProperty(Source& source, SceneGraph::PropertyOwnerContainer& propertyOwners, int32_t& componentIndex)
275 {
276   PropertyInputImpl* inputProperty = nullptr;
277
278   if(OBJECT_PROPERTY == source.sourceType)
279   {
280     DALI_ASSERT_ALWAYS(source.object->IsPropertyAConstraintInput(source.propertyIndex));
281
282     SceneGraph::PropertyOwner& owner = const_cast<SceneGraph::PropertyOwner&>(source.object->GetSceneObject());
283
284     AddUnique(propertyOwners, &owner);
285     inputProperty  = const_cast<PropertyInputImpl*>(source.object->GetSceneObjectInputProperty(source.propertyIndex));
286     componentIndex = source.object->GetPropertyComponentIndex(source.propertyIndex);
287
288     // The scene-object property should exist, when the property owner exists
289     DALI_ASSERT_ALWAYS(inputProperty && "Constraint source property does not exist");
290   }
291   else if(LOCAL_PROPERTY == source.sourceType)
292   {
293     DALI_ASSERT_ALWAYS(mTargetObject->IsPropertyAConstraintInput(source.propertyIndex));
294
295     inputProperty  = const_cast<PropertyInputImpl*>(mTargetObject->GetSceneObjectInputProperty(source.propertyIndex));
296     componentIndex = mTargetObject->GetPropertyComponentIndex(source.propertyIndex);
297
298     // The target scene-object should provide this property
299     DALI_ASSERT_ALWAYS(inputProperty && "Constraint source property does not exist");
300   }
301   else
302   {
303     DALI_ASSERT_ALWAYS(PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid");
304
305     Object* objectParent = dynamic_cast<Actor&>(*mTargetObject).GetParent();
306
307     // This will not exist, if the target object is off-stage
308     if(objectParent)
309     {
310       DALI_ASSERT_ALWAYS(objectParent->IsPropertyAConstraintInput(source.propertyIndex));
311
312       SceneGraph::PropertyOwner& owner = const_cast<SceneGraph::PropertyOwner&>(objectParent->GetSceneObject());
313
314       AddUnique(propertyOwners, &owner);
315       inputProperty  = const_cast<PropertyInputImpl*>(objectParent->GetSceneObjectInputProperty(source.propertyIndex));
316       componentIndex = objectParent->GetPropertyComponentIndex(source.propertyIndex);
317
318       // The scene-object property should exist, when the property owner exists
319       DALI_ASSERT_ALWAYS(inputProperty && "Constraint source property does not exist");
320     }
321   }
322   return inputProperty;
323 }
324
325 } // namespace Internal
326
327 } // namespace Dali