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