Cleaning up the property framework; removal of duplicate methods and incorrect assers
[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 char* 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 unsigned int ActiveConstraintBase::GetDefaultPropertyCount() const
319 {
320   return DEFAULT_PROPERTY_COUNT;
321 }
322
323 void ActiveConstraintBase::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
324 {
325   indices.reserve( DEFAULT_PROPERTY_COUNT );
326
327   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
328   {
329     indices.push_back( i );
330   }
331 }
332
333 const char* ActiveConstraintBase::GetDefaultPropertyName( Property::Index index ) const
334 {
335   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
336   {
337     return DEFAULT_PROPERTY_NAMES[index];
338   }
339   else
340   {
341     return NULL;
342   }
343 }
344
345 Property::Index ActiveConstraintBase::GetDefaultPropertyIndex( const std::string& name ) const
346 {
347   Property::Index index = Property::INVALID_INDEX;
348
349   // Only one name to compare with...
350   if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_NAMES[0] ) ) // dont want to convert rhs to string
351   {
352     index = 0;
353   }
354
355   return index;
356 }
357
358 bool ActiveConstraintBase::IsDefaultPropertyWritable( Property::Index index ) const
359 {
360   return true; // All default properties are currently writable
361 }
362
363 bool ActiveConstraintBase::IsDefaultPropertyAnimatable( Property::Index index ) const
364 {
365   return true; // All default properties are currently animatable
366 }
367
368 bool ActiveConstraintBase::IsDefaultPropertyAConstraintInput( Property::Index index ) const
369 {
370   return true; // All default properties can currently be used as a constraint input
371 }
372
373 Property::Type ActiveConstraintBase::GetDefaultPropertyType( Property::Index index ) const
374 {
375   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
376   {
377     return DEFAULT_PROPERTY_TYPES[index];
378   }
379   else
380   {
381     // Index out-of-range
382     return Property::NONE;
383   }
384 }
385
386 void ActiveConstraintBase::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
387 {
388   if( Dali::ActiveConstraint::WEIGHT == index )
389   {
390     SetWeight( propertyValue.Get<float>() );
391   }
392 }
393
394 Property::Value ActiveConstraintBase::GetDefaultProperty( Property::Index index ) const
395 {
396   Property::Value value;
397
398   if( Dali::ActiveConstraint::WEIGHT == index )
399   {
400     value = GetCurrentWeight();
401   }
402
403   return value;
404 }
405
406 const SceneGraph::PropertyOwner* ActiveConstraintBase::GetSceneObject() const
407 {
408   return mSceneGraphConstraint;
409 }
410
411 const SceneGraph::PropertyBase* ActiveConstraintBase::GetSceneObjectAnimatableProperty( Property::Index index ) const
412 {
413   DALI_ASSERT_DEBUG( 0 == index ); // only 1 property supported
414
415   // This method should only return a property which is part of the scene-graph
416   if ( !mSceneGraphConstraint )
417   {
418     return NULL;
419   }
420
421   return &mSceneGraphConstraint->mWeight;
422 }
423
424 const PropertyInputImpl* ActiveConstraintBase::GetSceneObjectInputProperty( Property::Index index ) const
425 {
426   DALI_ASSERT_DEBUG( 0 == index ); // only 1 property supported
427
428   // This method should only return a property which is part of the scene-graph
429   if ( !mSceneGraphConstraint )
430   {
431     return NULL;
432   }
433
434   return &mSceneGraphConstraint->mWeight;
435 }
436
437 void ActiveConstraintBase::SceneObjectAdded( ProxyObject& proxy )
438 {
439   // Should not be getting callbacks when mSources has been cleared
440    DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
441
442   if ( NULL == mSceneGraphConstraint &&
443        mTargetProxy )
444   {
445     ConnectConstraint();
446   }
447 }
448
449 void ActiveConstraintBase::SceneObjectRemoved( ProxyObject& proxy )
450 {
451   // Notify base class that the scene-graph constraint is being removed
452   OnSceneObjectRemove();
453
454   if ( mSceneGraphConstraint )
455   {
456     // Preserve the previous weight
457     mOffstageWeight = mSceneGraphConstraint->GetWeight( mEventToUpdate.GetEventBufferIndex() );
458
459     const SceneGraph::PropertyOwner* propertyOwner = mTargetProxy ? mTargetProxy->GetSceneObject() : NULL;
460
461     if( propertyOwner )
462     {
463       // Remove from scene-graph
464       RemoveConstraintMessage( mEventToUpdate, *propertyOwner, *(mSceneGraphConstraint) );
465     }
466
467     // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
468     mSceneGraphConstraint = NULL;
469   }
470 }
471
472 void ActiveConstraintBase::ProxyDestroyed( ProxyObject& proxy )
473 {
474   // Remove proxy pointer from observation set
475   ProxyObjectIter iter = std::find( mObservedProxies.Begin(), mObservedProxies.End(), &proxy );
476   DALI_ASSERT_DEBUG( mObservedProxies.End() != iter );
477   mObservedProxies.Erase( iter );
478
479   // Stop observing the remaining proxies
480   StopObservation();
481
482   // Discard all proxy & scene-graph pointers
483   mSceneGraphConstraint = NULL;
484   mTargetProxy = NULL;
485   mSources.clear();
486 }
487
488 void ActiveConstraintBase::ObserveProxy( ProxyObject& proxy )
489 {
490   ProxyObjectIter iter = std::find( mObservedProxies.Begin(), mObservedProxies.End(), &proxy );
491   if ( mObservedProxies.End() == iter )
492   {
493     proxy.AddObserver( *this );
494     mObservedProxies.PushBack( &proxy );
495   }
496 }
497
498 void ActiveConstraintBase::StopObservation()
499 {
500   const ProxyObjectIter end = mObservedProxies.End();
501   for( ProxyObjectIter iter = mObservedProxies.Begin(); iter != end; ++iter )
502   {
503     (*iter)->RemoveObserver( *this );
504   }
505
506   mObservedProxies.Clear();
507 }
508
509 void ActiveConstraintBase::FirstApplyFinished( Object* object )
510 {
511   // trust the object is correct as its set in FirstApply (in this same file)
512   ActiveConstraintBase* self = static_cast<ActiveConstraintBase*>( object );
513
514   // This is necessary when the constraint was not added to scene-graph during the animation
515   self->SetWeight( Dali::ActiveConstraint::FINAL_WEIGHT );
516
517   // The animation is no longer needed
518   GetImplementation(self->mApplyAnimation).SetFinishedCallback( NULL, NULL );
519   self->mApplyAnimation.Reset();
520
521   // Chain "Finish" to "Applied" signal
522
523   if ( !self->mAppliedSignal.Empty() )
524   {
525     Dali::ActiveConstraint handle( self );
526     self->mAppliedSignal.Emit( handle );
527   }
528
529   // WARNING - this constraint may now have been deleted; don't do anything else here
530 }
531
532 } // namespace Internal
533
534 } // namespace Dali