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