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