Simplified the Constraint removal logic
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / active-constraint-base.cpp
1 /*
2  * Copyright (c) 2014 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/active-constraint-base.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/animation/active-constraint.h>
23 #include <dali/public-api/object/handle.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/internal/common/event-to-update.h>
26 #include <dali/internal/event/animation/animation-impl.h>
27 #include <dali/internal/update/common/animatable-property.h>
28 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
29 #include <dali/internal/update/common/property-owner-messages.h>
30
31 using Dali::Internal::SceneGraph::AnimatableProperty;
32
33 namespace Dali
34 {
35
36 const Property::Index ActiveConstraint::WEIGHT = 0;
37
38 namespace Internal
39 {
40
41 namespace // unnamed namespace
42 {
43
44 BaseHandle Create()
45 {
46   // not directly creatable
47   return BaseHandle();
48 }
49
50 TypeRegistration mType( typeid(Dali::ActiveConstraint), typeid(Dali::Handle), Create );
51
52 SignalConnectorType signalConnector1( mType, Dali::ActiveConstraint::SIGNAL_APPLIED, &ActiveConstraintBase::DoConnectSignal );
53
54 }
55
56
57 namespace // unnamed namespace
58 {
59
60 /**
61  * We want to discourage the use of property strings (minimize string comparisons),
62  * particularly for the default properties.
63  */
64 const std::string DEFAULT_PROPERTY_NAMES[] =
65 {
66   "weight"
67 };
68 const int DEFAULT_PROPERTY_COUNT = sizeof( DEFAULT_PROPERTY_NAMES ) / sizeof( std::string );
69
70 const Property::Type DEFAULT_PROPERTY_TYPES[DEFAULT_PROPERTY_COUNT] =
71 {
72   Property::FLOAT // WEIGHT
73 };
74
75 } // unnamed namespace
76
77 ActiveConstraintBase::ActiveConstraintBase( EventToUpdate& eventToUpdate, Property::Index targetPropertyIndex, SourceContainer& sources, unsigned int sourceCount )
78 : mEventToUpdate( eventToUpdate ),
79   mTargetPropertyIndex( targetPropertyIndex ),
80   mSources( sources ),
81   mSourceCount( sourceCount ),
82   mTargetProxy( NULL ),
83   mObservedProxies(),
84   mSceneGraphConstraint( NULL ),
85   mCustomWeight( NULL ),
86   mOffstageWeight( Dali::ActiveConstraint::DEFAULT_WEIGHT ),
87   mAlphaFunction( Dali::Constraint::DEFAULT_ALPHA_FUNCTION ),
88   mRemoveAction( Dali::Constraint::DEFAULT_REMOVE_ACTION ),
89   mTag(0),
90   mApplyAnimation()
91 {
92   // Skip init when any of the proxy objects have been destroyed
93   if ( mSources.size() != mSourceCount )
94   {
95     // Discard all proxy pointers
96     mTargetProxy = NULL;
97     mSources.clear();
98   }
99
100   // Observe the objects providing properties
101   for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
102   {
103     if ( OBJECT_PROPERTY == iter->sourceType )
104     {
105       DALI_ASSERT_ALWAYS( NULL != iter->object && "ActiveConstraint source object not found" );
106
107       ObserveProxy( *(iter->object) );
108     }
109   }
110 }
111
112 ActiveConstraintBase::~ActiveConstraintBase()
113 {
114   StopObservation();
115
116   // Disconnect from internal animation signals
117   if ( mApplyAnimation )
118   {
119     GetImplementation(mApplyAnimation).SetFinishedCallback( NULL, NULL );
120   }
121 }
122
123 void ActiveConstraintBase::SetCustomWeightObject( ProxyObject& weightObject, Property::Index weightIndex )
124 {
125   const SceneGraph::PropertyBase* base = weightObject.GetSceneObjectAnimatableProperty( weightIndex );
126   const SceneGraph::AnimatableProperty<float>* sceneProperty = dynamic_cast< const SceneGraph::AnimatableProperty<float>* >( base );
127
128   if( sceneProperty )
129   {
130     mCustomWeight = sceneProperty;
131
132     ObserveProxy( weightObject );
133   }
134 }
135
136 void ActiveConstraintBase::FirstApply( ProxyObject& parent, TimePeriod applyTime )
137 {
138   DALI_ASSERT_ALWAYS( NULL == mTargetProxy && "Parent of ActiveConstraint already set" );
139
140   // No need to do anything, if the source objects are gone
141   if( mSources.size() == mSourceCount )
142   {
143     mTargetProxy = &parent;
144
145     ConnectConstraint();
146   }
147
148   if ( applyTime.durationSeconds > 0.0f )
149   {
150     DALI_ASSERT_DEBUG( !mApplyAnimation );
151
152     // Set start weight
153     SetWeight( 0.0f );
154
155     // Automatically animate (increase) the weight, until the constraint is fully applied
156     mApplyAnimation = Dali::Animation::New( applyTime.delaySeconds + applyTime.durationSeconds );
157     Dali::ActiveConstraint self( this );
158     mApplyAnimation.AnimateTo( Property( self, Dali::ActiveConstraint::WEIGHT ), Dali::ActiveConstraint::FINAL_WEIGHT, mAlphaFunction, applyTime );
159     mApplyAnimation.Play();
160
161     // Chain "Finish" to "Applied" signal
162     GetImplementation(mApplyAnimation).SetFinishedCallback( &ActiveConstraintBase::FirstApplyFinished, this );
163   }
164 }
165
166 void ActiveConstraintBase::OnParentDestroyed()
167 {
168   // Stop observing the remaining proxies
169   StopObservation();
170
171   // Discard all proxy pointers
172   mTargetProxy = NULL;
173   mSources.clear();
174 }
175
176 void ActiveConstraintBase::OnParentSceneObjectAdded()
177 {
178   if ( NULL == mSceneGraphConstraint &&
179        mTargetProxy )
180   {
181     ConnectConstraint();
182   }
183 }
184
185 void ActiveConstraintBase::OnParentSceneObjectRemoved()
186 {
187   if ( mSceneGraphConstraint )
188   {
189     // Notify base class that the scene-graph constraint is being removed
190     OnSceneObjectRemove();
191
192     // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
193     mSceneGraphConstraint = NULL;
194   }
195 }
196
197 void ActiveConstraintBase::BeginRemove()
198 {
199   // Stop observing the remaining proxies
200   StopObservation();
201
202   // Discard all proxy pointers
203   mSources.clear();
204
205   const SceneGraph::PropertyOwner* propertyOwner = mTargetProxy ? mTargetProxy->GetSceneObject() : NULL;
206
207   if ( propertyOwner &&
208        mSceneGraphConstraint )
209   {
210     // Notify base class that the scene-graph constraint is being removed
211     OnSceneObjectRemove();
212
213     // Remove from scene-graph
214     RemoveConstraintMessage( mEventToUpdate, *propertyOwner, *(mSceneGraphConstraint) );
215
216     // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
217     mSceneGraphConstraint = NULL;
218   }
219 }
220
221 ProxyObject* ActiveConstraintBase::GetParent()
222 {
223   return mTargetProxy;
224 }
225
226 bool ActiveConstraintBase::Supports( Capability capability ) const
227 {
228   return false; // switch-off support for dynamic properties
229 }
230
231 Dali::Handle ActiveConstraintBase::GetTargetObject()
232 {
233   return Dali::Handle( mTargetProxy );
234 }
235
236 Property::Index ActiveConstraintBase::GetTargetProperty()
237 {
238   return mTargetPropertyIndex;
239 }
240
241 void ActiveConstraintBase::SetWeight( float weight )
242 {
243   if ( mSceneGraphConstraint )
244   {
245     BakeWeightMessage( mEventToUpdate, *mSceneGraphConstraint, weight );
246   }
247   else
248   {
249     mOffstageWeight = weight;
250   }
251 }
252
253 float ActiveConstraintBase::GetCurrentWeight() const
254 {
255   float currentWeight( mOffstageWeight );
256
257   if ( mSceneGraphConstraint )
258   {
259     currentWeight = mSceneGraphConstraint->GetWeight( mEventToUpdate.GetEventBufferIndex() );
260   }
261
262   return currentWeight;
263 }
264
265 ActiveConstraintSignalV2& ActiveConstraintBase::AppliedSignal()
266 {
267   return mAppliedSignal;
268 }
269
270 bool ActiveConstraintBase::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
271 {
272   bool connected( true );
273   ActiveConstraintBase* constraint = dynamic_cast<ActiveConstraintBase*>(object);
274
275   if ( Dali::ActiveConstraint::SIGNAL_APPLIED == signalName )
276   {
277     constraint->AppliedSignal().Connect( tracker, functor );
278   }
279   else
280   {
281     // signalName does not match any signal
282     connected = false;
283   }
284
285   return connected;
286 }
287
288 void ActiveConstraintBase::SetAlphaFunction( AlphaFunction alphaFunc )
289 {
290   mAlphaFunction = alphaFunc;
291 }
292
293 AlphaFunction ActiveConstraintBase::GetAlphaFunction() const
294 {
295   return mAlphaFunction;
296 }
297
298 void ActiveConstraintBase::SetRemoveAction( ActiveConstraintBase::RemoveAction action )
299 {
300   mRemoveAction = action;
301 }
302
303 ActiveConstraintBase::RemoveAction ActiveConstraintBase::GetRemoveAction() const
304 {
305   return mRemoveAction;
306 }
307
308 void ActiveConstraintBase::SetTag(const unsigned int tag)
309 {
310   mTag = tag;
311 }
312
313 unsigned int ActiveConstraintBase::GetTag() const
314 {
315   return mTag;
316 }
317
318 bool ActiveConstraintBase::IsSceneObjectRemovable() const
319 {
320   return true; // The constraint removed when target SceneGraph::PropertyOwner is destroyed
321 }
322
323 unsigned int ActiveConstraintBase::GetDefaultPropertyCount() const
324 {
325   return DEFAULT_PROPERTY_COUNT;
326 }
327
328 void ActiveConstraintBase::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
329 {
330   indices.reserve( DEFAULT_PROPERTY_COUNT );
331
332   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
333   {
334     indices.push_back( i );
335   }
336 }
337
338 const std::string& ActiveConstraintBase::GetDefaultPropertyName( Property::Index index ) const
339 {
340   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
341   {
342     return DEFAULT_PROPERTY_NAMES[index];
343   }
344   else
345   {
346     // index out of range..return empty string
347     static const std::string INVALID_PROPERTY_NAME;
348     return INVALID_PROPERTY_NAME;
349   }
350 }
351
352 Property::Index ActiveConstraintBase::GetDefaultPropertyIndex( const std::string& name ) const
353 {
354   Property::Index index = Property::INVALID_INDEX;
355
356   // Only one name to compare with...
357   if ( name == DEFAULT_PROPERTY_NAMES[0] )
358   {
359     index = 0;
360   }
361
362   return index;
363 }
364
365 bool ActiveConstraintBase::IsDefaultPropertyWritable( Property::Index index ) const
366 {
367   return true; // All default properties are currently writable
368 }
369
370 bool ActiveConstraintBase::IsDefaultPropertyAnimatable( Property::Index index ) const
371 {
372   return true; // All default properties are currently animatable
373 }
374
375 bool ActiveConstraintBase::IsDefaultPropertyAConstraintInput( Property::Index index ) const
376 {
377   return true; // All default properties can currently be used as a constraint input
378 }
379
380 Property::Type ActiveConstraintBase::GetDefaultPropertyType( Property::Index index ) const
381 {
382   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
383   {
384     return DEFAULT_PROPERTY_TYPES[index];
385   }
386   else
387   {
388     // Index out-of-range
389     return Property::NONE;
390   }
391 }
392
393 void ActiveConstraintBase::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
394 {
395   switch ( index )
396   {
397     case Dali::ActiveConstraint::WEIGHT:
398     {
399       SetWeight( propertyValue.Get<float>() );
400       break;
401     }
402
403     default:
404     {
405       DALI_ASSERT_ALWAYS( false && "ActiveConstraint property out of bounds" ); // should not come here
406       break;
407     }
408   }
409 }
410
411 void ActiveConstraintBase::SetCustomProperty( Property::Index index, const CustomProperty& entry, const Property::Value& value )
412 {
413   DALI_ASSERT_ALWAYS( false && "ActiveConstraintBase does not have custom properties"); // should not come here
414 }
415
416 Property::Value ActiveConstraintBase::GetDefaultProperty( Property::Index index ) const
417 {
418   Property::Value value;
419
420   switch ( index )
421   {
422     case Dali::ActiveConstraint::WEIGHT:
423     {
424       value = GetCurrentWeight();
425       break;
426     }
427
428     default:
429     {
430       DALI_ASSERT_ALWAYS( false && "ActiveConstraint property out of bounds" ); // should not come here
431       break;
432     }
433   }
434
435   return value;
436 }
437
438 void ActiveConstraintBase::InstallSceneObjectProperty( SceneGraph::PropertyBase& newProperty, const std::string& name, unsigned int index )
439 {
440   DALI_ASSERT_ALWAYS( false && "ActiveConstraintBase does not have custom properties" ); // should not come here
441 }
442
443 const SceneGraph::PropertyOwner* ActiveConstraintBase::GetSceneObject() const
444 {
445   return mSceneGraphConstraint;
446 }
447
448 const SceneGraph::PropertyBase* ActiveConstraintBase::GetSceneObjectAnimatableProperty( Property::Index index ) const
449 {
450   DALI_ASSERT_DEBUG( 0 == index ); // only 1 property supported
451
452   // This method should only return a property which is part of the scene-graph
453   if ( !mSceneGraphConstraint )
454   {
455     return NULL;
456   }
457
458   return &mSceneGraphConstraint->mWeight;
459 }
460
461 const PropertyInputImpl* ActiveConstraintBase::GetSceneObjectInputProperty( Property::Index index ) const
462 {
463   DALI_ASSERT_DEBUG( 0 == index ); // only 1 property supported
464
465   // This method should only return a property which is part of the scene-graph
466   if ( !mSceneGraphConstraint )
467   {
468     return NULL;
469   }
470
471   return &mSceneGraphConstraint->mWeight;
472 }
473
474 void ActiveConstraintBase::SceneObjectAdded( ProxyObject& proxy )
475 {
476   // Should not be getting callbacks when mSources has been cleared
477    DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
478
479   if ( NULL == mSceneGraphConstraint &&
480        mTargetProxy )
481   {
482     ConnectConstraint();
483   }
484 }
485
486 void ActiveConstraintBase::SceneObjectRemoved( ProxyObject& proxy )
487 {
488   // Notify base class that the scene-graph constraint is being removed
489   OnSceneObjectRemove();
490
491   if ( mSceneGraphConstraint )
492   {
493     // Preserve the previous weight
494     mOffstageWeight = mSceneGraphConstraint->GetWeight( mEventToUpdate.GetEventBufferIndex() );
495
496     const SceneGraph::PropertyOwner* propertyOwner = mTargetProxy ? mTargetProxy->GetSceneObject() : NULL;
497
498     if( propertyOwner )
499     {
500       // Remove from scene-graph
501       RemoveConstraintMessage( mEventToUpdate, *propertyOwner, *(mSceneGraphConstraint) );
502     }
503
504     // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
505     mSceneGraphConstraint = NULL;
506   }
507 }
508
509 void ActiveConstraintBase::ProxyDestroyed( ProxyObject& proxy )
510 {
511   // Remove proxy pointer from observation set
512   ProxyObjectIter iter = mObservedProxies.find( &proxy );
513   DALI_ASSERT_DEBUG( mObservedProxies.end() != iter );
514   mObservedProxies.erase( iter );
515
516   // Stop observing the remaining proxies
517   StopObservation();
518
519   // Discard all proxy & scene-graph pointers
520   mSceneGraphConstraint = NULL;
521   mTargetProxy = NULL;
522   mSources.clear();
523 }
524
525 void ActiveConstraintBase::ObserveProxy( ProxyObject& proxy )
526 {
527   if ( mObservedProxies.end() == mObservedProxies.find(&proxy) )
528   {
529     proxy.AddObserver( *this );
530     mObservedProxies.insert( &proxy );
531   }
532 }
533
534 void ActiveConstraintBase::StopObservation()
535 {
536   for( ProxyObjectIter iter = mObservedProxies.begin(); mObservedProxies.end() != iter; ++iter )
537   {
538     (*iter)->RemoveObserver( *this );
539   }
540
541   mObservedProxies.clear();
542 }
543
544 void ActiveConstraintBase::FirstApplyFinished( Object* object )
545 {
546   ActiveConstraintBase& self = dynamic_cast<ActiveConstraintBase&>( *object );
547
548   // This is necessary when the constraint was not added to scene-graph during the animation
549   self.SetWeight( Dali::ActiveConstraint::FINAL_WEIGHT );
550
551   // The animation is no longer needed
552   GetImplementation(self.mApplyAnimation).SetFinishedCallback( NULL, NULL );
553   self.mApplyAnimation.Reset();
554
555   // Chain "Finish" to "Applied" signal
556
557   if ( !self.mAppliedSignal.Empty() )
558   {
559     Dali::ActiveConstraint handle( &self );
560
561     self.mAppliedSignal.Emit( handle );
562   }
563
564   // WARNING - this constraint may now have been deleted; don't do anything else here
565 }
566
567 } // namespace Internal
568
569 } // namespace Dali