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