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