Merge "Updated test harness behaviour" into tizen
[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 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 char* 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     return NULL;
347   }
348 }
349
350 Property::Index ActiveConstraintBase::GetDefaultPropertyIndex( const std::string& name ) const
351 {
352   Property::Index index = Property::INVALID_INDEX;
353
354   // Only one name to compare with...
355   if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_NAMES[0] ) ) // dont want to convert rhs to string
356   {
357     index = 0;
358   }
359
360   return index;
361 }
362
363 bool ActiveConstraintBase::IsDefaultPropertyWritable( Property::Index index ) const
364 {
365   return true; // All default properties are currently writable
366 }
367
368 bool ActiveConstraintBase::IsDefaultPropertyAnimatable( Property::Index index ) const
369 {
370   return true; // All default properties are currently animatable
371 }
372
373 bool ActiveConstraintBase::IsDefaultPropertyAConstraintInput( Property::Index index ) const
374 {
375   return true; // All default properties can currently be used as a constraint input
376 }
377
378 Property::Type ActiveConstraintBase::GetDefaultPropertyType( Property::Index index ) const
379 {
380   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
381   {
382     return DEFAULT_PROPERTY_TYPES[index];
383   }
384   else
385   {
386     // Index out-of-range
387     return Property::NONE;
388   }
389 }
390
391 void ActiveConstraintBase::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
392 {
393   switch ( index )
394   {
395     case Dali::ActiveConstraint::WEIGHT:
396     {
397       SetWeight( propertyValue.Get<float>() );
398       break;
399     }
400
401     default:
402     {
403       DALI_ASSERT_ALWAYS( false && "ActiveConstraint property out of bounds" ); // should not come here
404       break;
405     }
406   }
407 }
408
409 void ActiveConstraintBase::SetCustomProperty( Property::Index index, const CustomProperty& entry, const Property::Value& value )
410 {
411   DALI_ASSERT_ALWAYS( false && "ActiveConstraintBase does not have custom properties"); // should not come here
412 }
413
414 Property::Value ActiveConstraintBase::GetDefaultProperty( Property::Index index ) const
415 {
416   Property::Value value;
417
418   switch ( index )
419   {
420     case Dali::ActiveConstraint::WEIGHT:
421     {
422       value = GetCurrentWeight();
423       break;
424     }
425
426     default:
427     {
428       DALI_ASSERT_ALWAYS( false && "ActiveConstraint property out of bounds" ); // should not come here
429       break;
430     }
431   }
432
433   return value;
434 }
435
436 void ActiveConstraintBase::InstallSceneObjectProperty( SceneGraph::PropertyBase& newProperty, const std::string& name, unsigned int index )
437 {
438   DALI_ASSERT_ALWAYS( false && "ActiveConstraintBase does not have custom properties" ); // should not come here
439 }
440
441 const SceneGraph::PropertyOwner* ActiveConstraintBase::GetSceneObject() const
442 {
443   return mSceneGraphConstraint;
444 }
445
446 const SceneGraph::PropertyBase* ActiveConstraintBase::GetSceneObjectAnimatableProperty( Property::Index index ) const
447 {
448   DALI_ASSERT_DEBUG( 0 == index ); // only 1 property supported
449
450   // This method should only return a property which is part of the scene-graph
451   if ( !mSceneGraphConstraint )
452   {
453     return NULL;
454   }
455
456   return &mSceneGraphConstraint->mWeight;
457 }
458
459 const PropertyInputImpl* ActiveConstraintBase::GetSceneObjectInputProperty( Property::Index index ) const
460 {
461   DALI_ASSERT_DEBUG( 0 == index ); // only 1 property supported
462
463   // This method should only return a property which is part of the scene-graph
464   if ( !mSceneGraphConstraint )
465   {
466     return NULL;
467   }
468
469   return &mSceneGraphConstraint->mWeight;
470 }
471
472 void ActiveConstraintBase::SceneObjectAdded( ProxyObject& proxy )
473 {
474   // Should not be getting callbacks when mSources has been cleared
475    DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
476
477   if ( NULL == mSceneGraphConstraint &&
478        mTargetProxy )
479   {
480     ConnectConstraint();
481   }
482 }
483
484 void ActiveConstraintBase::SceneObjectRemoved( ProxyObject& proxy )
485 {
486   // Notify base class that the scene-graph constraint is being removed
487   OnSceneObjectRemove();
488
489   if ( mSceneGraphConstraint )
490   {
491     // Preserve the previous weight
492     mOffstageWeight = mSceneGraphConstraint->GetWeight( mEventToUpdate.GetEventBufferIndex() );
493
494     const SceneGraph::PropertyOwner* propertyOwner = mTargetProxy ? mTargetProxy->GetSceneObject() : NULL;
495
496     if( propertyOwner )
497     {
498       // Remove from scene-graph
499       RemoveConstraintMessage( mEventToUpdate, *propertyOwner, *(mSceneGraphConstraint) );
500     }
501
502     // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
503     mSceneGraphConstraint = NULL;
504   }
505 }
506
507 void ActiveConstraintBase::ProxyDestroyed( ProxyObject& proxy )
508 {
509   // Remove proxy pointer from observation set
510   ProxyObjectIter iter = std::find( mObservedProxies.Begin(), mObservedProxies.End(), &proxy );
511   DALI_ASSERT_DEBUG( mObservedProxies.End() != iter );
512   mObservedProxies.Erase( iter );
513
514   // Stop observing the remaining proxies
515   StopObservation();
516
517   // Discard all proxy & scene-graph pointers
518   mSceneGraphConstraint = NULL;
519   mTargetProxy = NULL;
520   mSources.clear();
521 }
522
523 void ActiveConstraintBase::ObserveProxy( ProxyObject& proxy )
524 {
525   ProxyObjectIter iter = std::find( mObservedProxies.Begin(), mObservedProxies.End(), &proxy );
526   if ( mObservedProxies.End() == iter )
527   {
528     proxy.AddObserver( *this );
529     mObservedProxies.PushBack( &proxy );
530   }
531 }
532
533 void ActiveConstraintBase::StopObservation()
534 {
535   const ProxyObjectIter end = mObservedProxies.End();
536   for( ProxyObjectIter iter = mObservedProxies.Begin(); iter != end; ++iter )
537   {
538     (*iter)->RemoveObserver( *this );
539   }
540
541   mObservedProxies.Clear();
542 }
543
544 void ActiveConstraintBase::FirstApplyFinished( Object* object )
545 {
546   // trust the object is correct as its set in FirstApply (in this same file)
547   ActiveConstraintBase* self = static_cast<ActiveConstraintBase*>( object );
548
549   // This is necessary when the constraint was not added to scene-graph during the animation
550   self->SetWeight( Dali::ActiveConstraint::FINAL_WEIGHT );
551
552   // The animation is no longer needed
553   GetImplementation(self->mApplyAnimation).SetFinishedCallback( NULL, NULL );
554   self->mApplyAnimation.Reset();
555
556   // Chain "Finish" to "Applied" signal
557
558   if ( !self->mAppliedSignal.Empty() )
559   {
560     Dali::ActiveConstraint handle( self );
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