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 {
67   ObserveObject(object);
68 }
69
70 ConstraintBase* ConstraintBase::Clone(Object& object)
71 {
72   DALI_ASSERT_ALWAYS(!mSourceDestroyed && "An input source object has been destroyed");
73
74   // create the type specific object
75   ConstraintBase* clone = DoClone(object);
76   clone->SetRemoveAction(mRemoveAction);
77   clone->SetTag(mTag);
78   return clone;
79 }
80
81 ConstraintBase::~ConstraintBase()
82 {
83   StopObservation();
84
85   RemoveInternal();
86 }
87
88 void ConstraintBase::AddSource(Source source)
89 {
90   mSources.push_back(source);
91
92   // Observe the object providing this property
93   if(OBJECT_PROPERTY == source.sourceType)
94   {
95     if(source.object != nullptr)
96     {
97       ObserveObject(*source.object);
98     }
99     else
100     {
101       DALI_LOG_ERROR("Constraint source object not found\n");
102     }
103   }
104 }
105
106 void ConstraintBase::Apply()
107 {
108   if(mTargetObject && !mApplied && !mSourceDestroyed)
109   {
110     mApplied = true;
111     ConnectConstraint();
112
113     mTargetObject->ApplyConstraint(*this);
114   }
115 }
116
117 void ConstraintBase::Remove()
118 {
119   RemoveInternal();
120
121   if(mTargetObject)
122   {
123     mTargetObject->RemoveConstraint(*this);
124   }
125 }
126
127 void ConstraintBase::RemoveInternal()
128 {
129   if(mApplied)
130   {
131     mApplied = false;
132
133     // Guard against constraint sending messages during core destruction
134     if(Stage::IsInstalled())
135     {
136       if(mTargetObject && mSceneGraphConstraint)
137       {
138         const SceneGraph::PropertyOwner& propertyOwner = mTargetObject->GetSceneObject();
139         // Remove from scene-graph
140         RemoveConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
141         // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
142         mSceneGraphConstraint = nullptr;
143       }
144     }
145   }
146 }
147
148 Object* ConstraintBase::GetParent()
149 {
150   return mTargetObject;
151 }
152
153 Dali::Handle ConstraintBase::GetTargetObject()
154 {
155   return Dali::Handle(mTargetObject);
156 }
157
158 Property::Index ConstraintBase::GetTargetProperty()
159 {
160   return mTargetPropertyIndex;
161 }
162
163 void ConstraintBase::SetRemoveAction(ConstraintBase::RemoveAction action)
164 {
165   mRemoveAction = action;
166 }
167
168 ConstraintBase::RemoveAction ConstraintBase::GetRemoveAction() const
169 {
170   return mRemoveAction;
171 }
172
173 void ConstraintBase::SetTag(uint32_t tag)
174 {
175   mTag = tag;
176 }
177
178 uint32_t ConstraintBase::GetTag() const
179 {
180   return mTag;
181 }
182
183 void ConstraintBase::SceneObjectAdded(Object& object)
184 {
185   if(mApplied &&
186      (nullptr == mSceneGraphConstraint) &&
187      mTargetObject)
188   {
189     ConnectConstraint();
190   }
191 }
192
193 void ConstraintBase::SceneObjectRemoved(Object& object)
194 {
195   if(mSceneGraphConstraint)
196   {
197     // An input property owning source has been deleted, need to tell the scene-graph-constraint owner to remove it
198     if(&object != mTargetObject)
199     {
200       if(mTargetObject)
201       {
202         const SceneGraph::PropertyOwner& propertyOwner = mTargetObject->GetSceneObject();
203         // Remove from scene-graph
204         RemoveConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
205       }
206     }
207
208     // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
209     mSceneGraphConstraint = nullptr;
210   }
211 }
212
213 void ConstraintBase::ObjectDestroyed(Object& object)
214 {
215   // Remove object pointer from observation set
216   ObjectIter iter = std::find(mObservedObjects.Begin(), mObservedObjects.End(), &object);
217   DALI_ASSERT_DEBUG(mObservedObjects.End() != iter);
218   mObservedObjects.Erase(iter);
219
220   // Constraint is not useful anymore as an input-source has been destroyed
221   mSourceDestroyed = true;
222
223   // Stop observing the remaining objects
224   StopObservation();
225
226   // Clear our sources as well
227   mSources.clear();
228
229   // Discard all object & scene-graph pointers
230   mSceneGraphConstraint = nullptr;
231   mTargetObject         = nullptr;
232 }
233
234 void ConstraintBase::ObserveObject(Object& object)
235 {
236   ObjectIter iter = std::find(mObservedObjects.Begin(), mObservedObjects.End(), &object);
237   if(mObservedObjects.End() == iter)
238   {
239     object.AddObserver(*this);
240     mObservedObjects.PushBack(&object);
241   }
242 }
243
244 void ConstraintBase::StopObservation()
245 {
246   const ObjectIter end = mObservedObjects.End();
247   for(ObjectIter iter = mObservedObjects.Begin(); iter != end; ++iter)
248   {
249     (*iter)->RemoveObserver(*this);
250   }
251
252   mObservedObjects.Clear();
253 }
254
255 PropertyInputImpl* ConstraintBase::AddInputProperty(Source& source, SceneGraph::PropertyOwnerContainer& propertyOwners, int32_t& componentIndex)
256 {
257   PropertyInputImpl* inputProperty = nullptr;
258
259   if(OBJECT_PROPERTY == source.sourceType)
260   {
261     DALI_ASSERT_ALWAYS(source.object->IsPropertyAConstraintInput(source.propertyIndex));
262
263     SceneGraph::PropertyOwner& owner = const_cast<SceneGraph::PropertyOwner&>(source.object->GetSceneObject());
264
265     AddUnique(propertyOwners, &owner);
266     inputProperty  = const_cast<PropertyInputImpl*>(source.object->GetSceneObjectInputProperty(source.propertyIndex));
267     componentIndex = source.object->GetPropertyComponentIndex(source.propertyIndex);
268
269     // The scene-object property should exist, when the property owner exists
270     DALI_ASSERT_ALWAYS(inputProperty && "Constraint source property does not exist");
271   }
272   else if(LOCAL_PROPERTY == source.sourceType)
273   {
274     DALI_ASSERT_ALWAYS(mTargetObject->IsPropertyAConstraintInput(source.propertyIndex));
275
276     inputProperty  = const_cast<PropertyInputImpl*>(mTargetObject->GetSceneObjectInputProperty(source.propertyIndex));
277     componentIndex = mTargetObject->GetPropertyComponentIndex(source.propertyIndex);
278
279     // The target scene-object should provide this property
280     DALI_ASSERT_ALWAYS(inputProperty && "Constraint source property does not exist");
281   }
282   else
283   {
284     DALI_ASSERT_ALWAYS(PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid");
285
286     Object* objectParent = dynamic_cast<Actor&>(*mTargetObject).GetParent();
287
288     // This will not exist, if the target object is off-stage
289     if(objectParent)
290     {
291       DALI_ASSERT_ALWAYS(objectParent->IsPropertyAConstraintInput(source.propertyIndex));
292
293       SceneGraph::PropertyOwner& owner = const_cast<SceneGraph::PropertyOwner&>(objectParent->GetSceneObject());
294
295       AddUnique(propertyOwners, &owner);
296       inputProperty  = const_cast<PropertyInputImpl*>(objectParent->GetSceneObjectInputProperty(source.propertyIndex));
297       componentIndex = objectParent->GetPropertyComponentIndex(source.propertyIndex);
298
299       // The scene-object property should exist, when the property owner exists
300       DALI_ASSERT_ALWAYS(inputProperty && "Constraint source property does not exist");
301     }
302   }
303   return inputProperty;
304 }
305
306 } // namespace Internal
307
308 } // namespace Dali