[dali_1.0.36] Merge branch 'tizen'
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / animation-impl.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/animation-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/actors/actor.h>
23 #include <dali/public-api/animation/alpha-functions.h>
24 #include <dali/public-api/animation/time-period.h>
25 #include <dali/public-api/common/dali-common.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/math/vector2.h>
28 #include <dali/public-api/math/radian.h>
29 #include <dali/internal/event/actors/actor-impl.h>
30 #include <dali/internal/event/animation/animation-playlist.h>
31 #include <dali/internal/event/animation/animator-connector.h>
32 #include <dali/internal/event/common/notification-manager.h>
33 #include <dali/internal/event/common/property-helper.h>
34 #include <dali/internal/event/common/stage-impl.h>
35 #include <dali/internal/event/common/thread-local-storage.h>
36 #include <dali/internal/event/effects/shader-effect-impl.h>
37 #include <dali/internal/update/manager/update-manager.h>
38
39 using Dali::Internal::SceneGraph::UpdateManager;
40 using Dali::Internal::SceneGraph::AnimatorBase;
41 using Dali::Internal::SceneGraph::Shader;
42
43 namespace Dali
44 {
45
46 namespace Internal
47 {
48
49 static bool SHOW_VALUE = true;
50 static bool HIDE_VALUE = false;
51
52 namespace
53 {
54
55 // Signals
56
57 const char* const SIGNAL_FINISHED = "finished";
58
59 // Actions
60
61 const char* const ACTION_PLAY =     "play";
62 const char* const ACTION_STOP =     "stop";
63 const char* const ACTION_PAUSE =    "pause";
64
65 BaseHandle Create()
66 {
67   return Dali::Animation::New(0.f);
68 }
69
70 TypeRegistration mType( typeid( Dali::Animation ), typeid( Dali::BaseHandle ), Create );
71
72 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &Animation::DoConnectSignal );
73
74 TypeAction action1( mType, ACTION_PLAY,  &Animation::DoAction );
75 TypeAction action2( mType, ACTION_STOP,  &Animation::DoAction );
76 TypeAction action3( mType, ACTION_PAUSE, &Animation::DoAction );
77
78 const Dali::Animation::EndAction DEFAULT_END_ACTION( Dali::Animation::Bake );
79 const Dali::Animation::EndAction DEFAULT_DISCONNECT_ACTION( Dali::Animation::BakeFinal );
80 const Dali::Animation::Interpolation DEFAULT_INTERPOLATION( Dali::Animation::Linear );
81
82 } // anon namespace
83
84
85 AnimationPtr Animation::New(float durationSeconds)
86 {
87   Stage* stage = Stage::GetCurrent();
88
89   AnimationPlaylist& playlist = stage->GetAnimationPlaylist();
90
91   AnimationPtr animation = new Animation( *stage, playlist, durationSeconds, DEFAULT_END_ACTION, DEFAULT_DISCONNECT_ACTION, Dali::AlphaFunctions::Linear );
92
93   // Second-phase construction
94   animation->Initialize();
95
96   return animation;
97 }
98
99 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
100 : mEventThreadServices( eventThreadServices ),
101   mPlaylist( playlist ),
102   mAnimation( NULL ),
103   mNotificationCount( 0 ),
104   mFinishedCallback( NULL ),
105   mFinishedCallbackObject( NULL ),
106   mDurationSeconds( durationSeconds ),
107   mSpeedFactor(1.0f),
108   mIsLooping( false ),
109   mPlayRange( Vector2(0.0f,1.0f)),
110   mEndAction( endAction ),
111   mDisconnectAction( disconnectAction ),
112   mDefaultAlpha( defaultAlpha )
113 {
114 }
115
116 void Animation::Initialize()
117 {
118   // Connect to the animation playlist
119   mPlaylist.AnimationCreated( *this );
120
121   CreateSceneObject();
122
123   RegisterObject();
124 }
125
126 Animation::~Animation()
127 {
128   // Guard to allow handle destruction after Core has been destroyed
129   if ( Stage::IsInstalled() )
130   {
131     // Disconnect from the animation playlist
132     mPlaylist.AnimationDestroyed( *this );
133
134     DestroySceneObject();
135
136     UnregisterObject();
137   }
138 }
139
140 void Animation::CreateSceneObject()
141 {
142   DALI_ASSERT_DEBUG( mAnimation == NULL );
143
144   // Create a new animation, temporarily owned
145   SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mIsLooping, mEndAction, mDisconnectAction );
146
147   // Keep a const pointer to the animation.
148   mAnimation = animation;
149
150   // Transfer animation ownership to the update manager through a message
151   AddAnimationMessage( mEventThreadServices.GetUpdateManager(), animation );
152 }
153
154 void Animation::DestroySceneObject()
155 {
156   if ( mAnimation != NULL )
157   {
158     // Remove animation using a message to the update manager
159     RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
160     mAnimation = NULL;
161   }
162 }
163
164 void Animation::SetDuration(float seconds)
165 {
166   // Cache for public getters
167   mDurationSeconds = seconds;
168
169   // mAnimation is being used in a separate thread; queue a message to set the value
170   SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
171 }
172
173 float Animation::GetDuration() const
174 {
175   // This is not animatable; the cached value is up-to-date.
176   return mDurationSeconds;
177 }
178
179 void Animation::SetLooping(bool looping)
180 {
181   // Cache for public getters
182   mIsLooping = looping;
183
184   // mAnimation is being used in a separate thread; queue a message to set the value
185   SetLoopingMessage( mEventThreadServices, *mAnimation, looping );
186 }
187
188 bool Animation::IsLooping() const
189 {
190   // This is not animatable; the cached value is up-to-date.
191   return mIsLooping;
192 }
193
194 void Animation::SetEndAction(EndAction action)
195 {
196   // Cache for public getters
197   mEndAction = action;
198
199   // mAnimation is being used in a separate thread; queue a message to set the value
200   SetEndActionMessage( mEventThreadServices, *mAnimation, action );
201 }
202
203 Dali::Animation::EndAction Animation::GetEndAction() const
204 {
205   // This is not animatable; the cached value is up-to-date.
206   return mEndAction;
207 }
208
209 void Animation::SetDisconnectAction(EndAction action)
210 {
211   // Cache for public getters
212   mDisconnectAction = action;
213
214   // mAnimation is being used in a separate thread; queue a message to set the value
215   SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
216 }
217
218 Dali::Animation::EndAction Animation::GetDisconnectAction() const
219 {
220   // This is not animatable; the cached value is up-to-date.
221   return mDisconnectAction;
222 }
223
224 void Animation::Play()
225 {
226   // Update the current playlist
227   mPlaylist.OnPlay( *this );
228
229   // mAnimation is being used in a separate thread; queue a Play message
230   PlayAnimationMessage( mEventThreadServices, *mAnimation );
231 }
232
233 void Animation::PlayFrom( float progress )
234 {
235   if( progress >= mPlayRange.x && progress <= mPlayRange.y )
236   {
237     // Update the current playlist
238     mPlaylist.OnPlay( *this );
239
240     // mAnimation is being used in a separate thread; queue a Play message
241     PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
242   }
243 }
244
245 void Animation::Pause()
246 {
247   // mAnimation is being used in a separate thread; queue a Pause message
248   PauseAnimationMessage( mEventThreadServices, *mAnimation );
249 }
250
251 void Animation::Stop()
252 {
253   // mAnimation is being used in a separate thread; queue a Stop message
254   StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
255 }
256
257 void Animation::Clear()
258 {
259   DALI_ASSERT_DEBUG(mAnimation);
260
261   // Remove all the connectors
262   mConnectors.Clear();
263
264   // Replace the old scene-object with a new one
265   DestroySceneObject();
266   CreateSceneObject();
267
268   // Reset the notification count, since the new scene-object has never been played
269   mNotificationCount = 0;
270
271   // Update the current playlist
272   mPlaylist.OnClear( *this );
273 }
274
275 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
276 {
277   AnimateBy(target, relativeValue, AlphaFunctions::Default, mDurationSeconds);
278 }
279
280 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
281 {
282   AnimateBy(target, relativeValue, alpha, mDurationSeconds);
283 }
284
285 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
286 {
287   AnimateBy(target, relativeValue, AlphaFunctions::Default, period);
288 }
289
290 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
291 {
292   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
293
294   ExtendDuration( period );
295
296   switch ( relativeValue.GetType() )
297   {
298     case Property::BOOLEAN:
299     {
300       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
301                                                           target.propertyIndex,
302                                                           target.componentIndex,
303                                                           new AnimateByBoolean(relativeValue.Get<bool>()),
304                                                           alpha,
305                                                           period ) );
306       break;
307     }
308
309     case Property::FLOAT:
310     {
311       AddAnimatorConnector( AnimatorConnector<float>::New( object,
312                                                            target.propertyIndex,
313                                                            target.componentIndex,
314                                                            new AnimateByFloat(relativeValue.Get<float>()),
315                                                            alpha,
316                                                            period ) );
317       break;
318     }
319
320     case Property::INTEGER:
321     {
322       AddAnimatorConnector( AnimatorConnector<int>::New( object,
323                                                          target.propertyIndex,
324                                                          target.componentIndex,
325                                                          new AnimateByInteger(relativeValue.Get<int>()),
326                                                          alpha,
327                                                          period ) );
328       break;
329     }
330
331     case Property::VECTOR2:
332     {
333       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
334                                                              target.propertyIndex,
335                                                              target.componentIndex,
336                                                              new AnimateByVector2(relativeValue.Get<Vector2>()),
337                                                              alpha,
338                                                              period ) );
339       break;
340     }
341
342     case Property::VECTOR3:
343     {
344       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
345                                                              target.propertyIndex,
346                                                              target.componentIndex,
347                                                              new AnimateByVector3(relativeValue.Get<Vector3>()),
348                                                              alpha,
349                                                              period ) );
350       break;
351     }
352
353     case Property::VECTOR4:
354     {
355       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
356                                                              target.propertyIndex,
357                                                              target.componentIndex,
358                                                              new AnimateByVector4(relativeValue.Get<Vector4>()),
359                                                              alpha,
360                                                              period ) );
361       break;
362     }
363
364     case Property::ROTATION:
365     {
366       AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
367
368       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
369                                                                 target.propertyIndex,
370                                                                 target.componentIndex,
371                                                                 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
372                                                                 alpha,
373                                                                 period ) );
374       break;
375     }
376
377     default:
378       DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
379       break;
380   }
381 }
382
383 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
384 {
385   AnimateTo(target, destinationValue, AlphaFunctions::Default, mDurationSeconds);
386 }
387
388 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
389 {
390   AnimateTo(target, destinationValue, alpha, mDurationSeconds);
391 }
392
393 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
394 {
395   AnimateTo(target, destinationValue, AlphaFunctions::Default, period);
396 }
397
398 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
399 {
400   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
401
402   AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
403 }
404
405 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
406 {
407   Property::Type type = targetObject.GetPropertyType(targetPropertyIndex);
408   if(componentIndex != Property::INVALID_COMPONENT_INDEX)
409   {
410     if( type == Property::VECTOR2
411         || type == Property::VECTOR3
412         || type == Property::VECTOR4 )
413     {
414       type = Property::FLOAT;
415     }
416   }
417   DALI_ASSERT_ALWAYS( type == destinationValue.GetType() && "DestinationValue does not match Target Property type" );
418
419   ExtendDuration( period );
420
421   switch (destinationValue.GetType())
422   {
423     case Property::BOOLEAN:
424     {
425       AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
426                                                           targetPropertyIndex,
427                                                           componentIndex,
428                                                           new AnimateToBoolean( destinationValue.Get<bool>() ),
429                                                           alpha,
430                                                           period ) );
431       break;
432     }
433
434     case Property::FLOAT:
435     {
436       AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
437                                                            targetPropertyIndex,
438                                                            componentIndex,
439                                                            new AnimateToFloat( destinationValue.Get<float>() ),
440                                                            alpha,
441                                                            period ) );
442       break;
443     }
444
445     case Property::INTEGER:
446     {
447       AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
448                                                          targetPropertyIndex,
449                                                          componentIndex,
450                                                          new AnimateToInteger( destinationValue.Get<int>() ),
451                                                          alpha,
452                                                          period ) );
453       break;
454     }
455
456     case Property::VECTOR2:
457     {
458       AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
459                                                              targetPropertyIndex,
460                                                              componentIndex,
461                                                              new AnimateToVector2( destinationValue.Get<Vector2>() ),
462                                                              alpha,
463                                                              period ) );
464       break;
465     }
466
467     case Property::VECTOR3:
468     {
469       if ( Dali::Actor::Property::SIZE == targetPropertyIndex )
470       {
471         // Test whether this is actually an Actor
472         Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
473         if ( maybeActor )
474         {
475           // Notify the actor that its size is being animated
476           maybeActor->NotifySizeAnimation( *this, destinationValue.Get<Vector3>() );
477         }
478       }
479
480       AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
481                                                              targetPropertyIndex,
482                                                              componentIndex,
483                                                              new AnimateToVector3( destinationValue.Get<Vector3>() ),
484                                                              alpha,
485                                                              period ) );
486       break;
487     }
488
489     case Property::VECTOR4:
490     {
491       AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
492                                                              targetPropertyIndex,
493                                                              componentIndex,
494                                                              new AnimateToVector4( destinationValue.Get<Vector4>() ),
495                                                              alpha,
496                                                              period ) );
497       break;
498     }
499
500     case Property::ROTATION:
501     {
502       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
503                                                                 targetPropertyIndex,
504                                                                 componentIndex,
505                                                                 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
506                                                                 alpha,
507                                                                 period ) );
508       break;
509     }
510
511     default:
512       DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
513       break;
514   }
515 }
516
517 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
518 {
519   AnimateBetween(target, keyFrames, mDefaultAlpha, mDurationSeconds, DEFAULT_INTERPOLATION );
520 }
521
522 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
523 {
524   AnimateBetween(target, keyFrames, mDefaultAlpha, mDurationSeconds, interpolation );
525 }
526
527 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
528 {
529   AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
530 }
531
532 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
533 {
534   AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
535 }
536
537 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
538 {
539   AnimateBetween(target, keyFrames, alpha, mDurationSeconds, DEFAULT_INTERPOLATION);
540 }
541
542 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
543 {
544   AnimateBetween(target, keyFrames, alpha, mDurationSeconds, interpolation);
545 }
546
547 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
548 {
549   AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
550 }
551
552 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
553 {
554   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
555
556   ExtendDuration( period );
557
558   switch(keyFrames.GetType())
559   {
560     case Dali::Property::BOOLEAN:
561     {
562       const KeyFrameBoolean* kf;
563       GetSpecialization(keyFrames, kf);
564       KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
565       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
566                                                           target.propertyIndex,
567                                                           target.componentIndex,
568                                                           new KeyFrameBooleanFunctor(kfCopy),
569                                                           alpha,
570                                                           period ) );
571       break;
572     }
573
574     case Dali::Property::FLOAT:
575     {
576       const KeyFrameNumber* kf;
577       GetSpecialization(keyFrames, kf);
578       KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
579       AddAnimatorConnector( AnimatorConnector<float>::New( object,
580                                                            target.propertyIndex,
581                                                            target.componentIndex,
582                                                            new KeyFrameNumberFunctor(kfCopy,interpolation),
583                                                            alpha,
584                                                            period ) );
585       break;
586     }
587
588     case Dali::Property::INTEGER:
589     {
590       const KeyFrameInteger* kf;
591       GetSpecialization(keyFrames, kf);
592       KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
593       AddAnimatorConnector( AnimatorConnector<int>::New( object,
594                                                          target.propertyIndex,
595                                                          target.componentIndex,
596                                                          new KeyFrameIntegerFunctor(kfCopy,interpolation),
597                                                          alpha,
598                                                          period ) );
599       break;
600     }
601
602     case Dali::Property::VECTOR2:
603     {
604       const KeyFrameVector2* kf;
605       GetSpecialization(keyFrames, kf);
606       KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
607       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
608                                                              target.propertyIndex,
609                                                              target.componentIndex,
610                                                              new KeyFrameVector2Functor(kfCopy,interpolation),
611                                                              alpha,
612                                                              period ) );
613       break;
614     }
615
616     case Dali::Property::VECTOR3:
617     {
618       const KeyFrameVector3* kf;
619       GetSpecialization(keyFrames, kf);
620       KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
621       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
622                                                              target.propertyIndex,
623                                                              target.componentIndex,
624                                                              new KeyFrameVector3Functor(kfCopy,interpolation),
625                                                              alpha,
626                                                              period ) );
627       break;
628     }
629
630     case Dali::Property::VECTOR4:
631     {
632       const KeyFrameVector4* kf;
633       GetSpecialization(keyFrames, kf);
634       KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
635       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
636                                                              target.propertyIndex,
637                                                              target.componentIndex,
638                                                              new KeyFrameVector4Functor(kfCopy,interpolation),
639                                                              alpha,
640                                                              period ) );
641       break;
642     }
643
644     case Dali::Property::ROTATION:
645     {
646       const KeyFrameQuaternion* kf;
647       GetSpecialization(keyFrames, kf);
648       KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
649       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
650                                                                 target.propertyIndex,
651                                                                 target.componentIndex,
652                                                                 new KeyFrameQuaternionFunctor(kfCopy),
653                                                                 alpha,
654                                                                 period ) );
655       break;
656     }
657
658     default: // not all property types are animateable
659       break;
660   }
661 }
662
663 bool Animation::HasFinished()
664 {
665   bool hasFinished(false);
666   const int playCount(mAnimation->GetPlayCount());
667
668   // If the play count has been incremented, then another notification is required
669   if (playCount > mNotificationCount)
670   {
671     // Note that only one signal is emitted, if the animation has been played repeatedly
672     mNotificationCount = playCount;
673
674     hasFinished = true;
675   }
676
677   return hasFinished;
678 }
679
680 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
681 {
682   return mFinishedSignal;
683 }
684
685 void Animation::EmitSignalFinish()
686 {
687   if ( !mFinishedSignal.Empty() )
688   {
689     Dali::Animation handle( this );
690     mFinishedSignal.Emit( handle );
691   }
692
693   // This callback is used internally, to avoid the overhead of using a signal.
694   if ( mFinishedCallback )
695   {
696     mFinishedCallback( mFinishedCallbackObject );
697   }
698 }
699
700 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
701 {
702   bool connected( true );
703   Animation* animation = dynamic_cast<Animation*>(object);
704
705   if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
706   {
707     animation->FinishedSignal().Connect( tracker, functor );
708   }
709   else
710   {
711     // signalName does not match any signal
712     connected = false;
713   }
714
715   return connected;
716 }
717
718 void Animation::SetFinishedCallback( FinishedCallback callback, Object* object )
719 {
720   mFinishedCallback = callback;
721   mFinishedCallbackObject = object;
722 }
723
724 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
725 {
726   DALI_ASSERT_DEBUG( NULL != connector );
727
728   connector->SetParent(*this);
729
730   mConnectors.PushBack( connector );
731 }
732
733 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
734 {
735   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(0.0f,GetDuration()) );
736 }
737
738 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
739 {
740   Animate( actor, path, forward, alpha, TimePeriod(0.0f,GetDuration()) );
741 }
742
743 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
744 {
745   Animate( actor, path, forward, mDefaultAlpha, period );
746 }
747
748 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
749 {
750   ExtendDuration( period );
751
752   PathPtr pathCopy = Path::Clone(path);
753
754   //Position animation
755   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
756                                                          Dali::Actor::Property::POSITION,
757                                                          Property::INVALID_COMPONENT_INDEX,
758                                                          new PathPositionFunctor( pathCopy ),
759                                                          alpha,
760                                                          period ) );
761
762   //If forward is zero, PathRotationFunctor will always return the unit quaternion
763   if( forward != Vector3::ZERO )
764   {
765     //Rotation animation
766     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
767                                                               Dali::Actor::Property::ORIENTATION,
768                                                               Property::INVALID_COMPONENT_INDEX,
769                                                               new PathRotationFunctor( pathCopy, forward ),
770                                                               alpha,
771                                                               period ) );
772   }
773 }
774
775 void Animation::Show(Actor& actor, float delaySeconds)
776 {
777   ExtendDuration( TimePeriod(delaySeconds, 0) );
778
779   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
780                                                       Dali::Actor::Property::VISIBLE,
781                                                       Property::INVALID_COMPONENT_INDEX,
782                                                       new AnimateToBoolean(SHOW_VALUE),
783                                                       AlphaFunctions::Default,
784                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
785 }
786
787 void Animation::Hide(Actor& actor, float delaySeconds)
788 {
789   ExtendDuration( TimePeriod(delaySeconds, 0) );
790
791   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
792                                                       Dali::Actor::Property::VISIBLE,
793                                                       Property::INVALID_COMPONENT_INDEX,
794                                                       new AnimateToBoolean(HIDE_VALUE),
795                                                       AlphaFunctions::Default,
796                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
797 }
798
799 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes )
800 {
801   bool done = false;
802   Animation* animation = dynamic_cast<Animation*>( object );
803
804   if( animation )
805   {
806     if( 0 == strcmp( actionName.c_str(), ACTION_PLAY ) )
807     {
808       if( attributes.size() > 0 )
809       {
810         animation->SetDuration( attributes[0].Get<float>() );
811       }
812
813       animation->Play();
814       done = true;
815     }
816     else if( 0 == strcmp( actionName.c_str(), ACTION_STOP ) )
817     {
818       animation->Stop();
819       done = true;
820     }
821     else if( 0 == strcmp( actionName.c_str(), ACTION_PAUSE ) )
822     {
823       animation->Pause();
824       done = true;
825     }
826   }
827
828   return done;
829 }
830
831 void Animation::SetCurrentProgress(float progress)
832 {
833   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
834   {
835     // mAnimation is being used in a separate thread; queue a message to set the current progress
836     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
837   }
838 }
839
840 float Animation::GetCurrentProgress()
841 {
842   if( mAnimation )
843   {
844     return mAnimation->GetCurrentProgress();
845   }
846
847   return 0.0f;
848 }
849
850 void Animation::ExtendDuration( const TimePeriod& timePeriod )
851 {
852   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
853
854   if( duration > mDurationSeconds )
855   {
856     SetDuration( duration );
857   }
858 }
859
860 void Animation::SetSpeedFactor( float factor )
861 {
862   if( mAnimation )
863   {
864     mSpeedFactor = factor;
865     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
866   }
867 }
868
869 float Animation::GetSpeedFactor() const
870 {
871   return mSpeedFactor;
872 }
873
874 void Animation::SetPlayRange( const Vector2& range)
875 {
876   //Make sure the range specified is between 0.0 and 1.0
877   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
878   {
879     Vector2 orderedRange( range );
880     //If the range is not in order swap values
881     if( range.x > range.y )
882     {
883       orderedRange = Vector2(range.y, range.x);
884     }
885
886     // Cache for public getters
887     mPlayRange = orderedRange;
888
889     // mAnimation is being used in a separate thread; queue a message to set play range
890     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
891   }
892 }
893
894 Vector2 Animation::GetPlayRange() const
895 {
896   return mPlayRange;
897 }
898
899
900 } // namespace Internal
901
902 } // namespace Dali