[dali_1.2.15] Merge branch 'devel/master'
[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 = dynamic_cast<Object&>( GetImplementation(target.object) );
345
346   ExtendDuration( period );
347
348   switch ( relativeValue.GetType() )
349   {
350     case Property::BOOLEAN:
351     {
352       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
353                                                           target.propertyIndex,
354                                                           target.componentIndex,
355                                                           new AnimateByBoolean(relativeValue.Get<bool>()),
356                                                           alpha,
357                                                           period ) );
358       break;
359     }
360
361     case Property::INTEGER:
362     {
363       AddAnimatorConnector( AnimatorConnector<int>::New( object,
364                                                          target.propertyIndex,
365                                                          target.componentIndex,
366                                                          new AnimateByInteger(relativeValue.Get<int>()),
367                                                          alpha,
368                                                          period ) );
369       break;
370     }
371
372     case Property::FLOAT:
373     {
374       AddAnimatorConnector( AnimatorConnector<float>::New( object,
375                                                            target.propertyIndex,
376                                                            target.componentIndex,
377                                                            new AnimateByFloat(relativeValue.Get<float>()),
378                                                            alpha,
379                                                            period ) );
380       break;
381     }
382
383     case Property::VECTOR2:
384     {
385       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
386                                                              target.propertyIndex,
387                                                              target.componentIndex,
388                                                              new AnimateByVector2(relativeValue.Get<Vector2>()),
389                                                              alpha,
390                                                              period ) );
391       break;
392     }
393
394     case Property::VECTOR3:
395     {
396       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
397                                                              target.propertyIndex,
398                                                              target.componentIndex,
399                                                              new AnimateByVector3(relativeValue.Get<Vector3>()),
400                                                              alpha,
401                                                              period ) );
402       break;
403     }
404
405     case Property::VECTOR4:
406     {
407       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
408                                                              target.propertyIndex,
409                                                              target.componentIndex,
410                                                              new AnimateByVector4(relativeValue.Get<Vector4>()),
411                                                              alpha,
412                                                              period ) );
413       break;
414     }
415
416     case Property::ROTATION:
417     {
418       AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
419
420       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
421                                                                 target.propertyIndex,
422                                                                 target.componentIndex,
423                                                                 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
424                                                                 alpha,
425                                                                 period ) );
426       break;
427     }
428
429     default:
430       DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
431       break;
432   }
433 }
434
435 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
436 {
437   AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
438 }
439
440 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
441 {
442   AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
443 }
444
445 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
446 {
447   AnimateTo(target, destinationValue, mDefaultAlpha, period);
448 }
449
450 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
451 {
452   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
453
454   AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
455 }
456
457 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
458 {
459   Property::Type type = targetObject.GetPropertyType(targetPropertyIndex);
460   if(componentIndex != Property::INVALID_COMPONENT_INDEX)
461   {
462     if( type == Property::VECTOR2
463         || type == Property::VECTOR3
464         || type == Property::VECTOR4 )
465     {
466       type = Property::FLOAT;
467     }
468   }
469   DALI_ASSERT_ALWAYS( type == destinationValue.GetType() && "DestinationValue does not match Target Property type" );
470
471   ExtendDuration( period );
472
473   switch (destinationValue.GetType())
474   {
475     case Property::BOOLEAN:
476     {
477       AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
478                                                           targetPropertyIndex,
479                                                           componentIndex,
480                                                           new AnimateToBoolean( destinationValue.Get<bool>() ),
481                                                           alpha,
482                                                           period ) );
483       break;
484     }
485
486     case Property::INTEGER:
487     {
488       AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
489                                                          targetPropertyIndex,
490                                                          componentIndex,
491                                                          new AnimateToInteger( destinationValue.Get<int>() ),
492                                                          alpha,
493                                                          period ) );
494       break;
495     }
496
497     case Property::FLOAT:
498     {
499       if ( ( Dali::Actor::Property::SIZE_WIDTH == targetPropertyIndex ) ||
500            ( Dali::Actor::Property::SIZE_HEIGHT == targetPropertyIndex ) ||
501            ( Dali::Actor::Property::SIZE_DEPTH == targetPropertyIndex ) )
502       {
503         // Test whether this is actually an Actor
504         Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
505         if ( maybeActor )
506         {
507           // Notify the actor that its size is being animated
508           maybeActor->NotifySizeAnimation( *this, destinationValue.Get<float>(), targetPropertyIndex );
509         }
510       }
511       else if ( ( Dali::Actor::Property::POSITION_X == targetPropertyIndex ) ||
512                  ( Dali::Actor::Property::POSITION_Y == targetPropertyIndex ) ||
513                  ( Dali::Actor::Property::POSITION_Z == targetPropertyIndex ) )
514       {
515         // Test whether this is actually an Actor
516         Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
517         if ( maybeActor )
518         {
519           // Notify the actor that its position is being animated
520           maybeActor->NotifyPositionAnimation( *this, destinationValue.Get<float>(), targetPropertyIndex );
521         }
522       }
523
524       AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
525                                                            targetPropertyIndex,
526                                                            componentIndex,
527                                                            new AnimateToFloat( destinationValue.Get<float>() ),
528                                                            alpha,
529                                                            period ) );
530       break;
531     }
532
533     case Property::VECTOR2:
534     {
535       AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
536                                                              targetPropertyIndex,
537                                                              componentIndex,
538                                                              new AnimateToVector2( destinationValue.Get<Vector2>() ),
539                                                              alpha,
540                                                              period ) );
541       break;
542     }
543
544     case Property::VECTOR3:
545     {
546       if ( Dali::Actor::Property::SIZE == targetPropertyIndex )
547       {
548         // Test whether this is actually an Actor
549         Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
550         if ( maybeActor )
551         {
552           // Notify the actor that its size is being animated
553           maybeActor->NotifySizeAnimation( *this, destinationValue.Get<Vector3>() );
554         }
555       }
556       else if ( Dali::Actor::Property::POSITION == targetPropertyIndex )
557       {
558         // Test whether this is actually an Actor
559         Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
560         if ( maybeActor )
561         {
562           // Notify the actor that its position is being animated
563           maybeActor->NotifyPositionAnimation( *this, destinationValue.Get<Vector3>() );
564         }
565       }
566
567       AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
568                                                              targetPropertyIndex,
569                                                              componentIndex,
570                                                              new AnimateToVector3( destinationValue.Get<Vector3>() ),
571                                                              alpha,
572                                                              period ) );
573       break;
574     }
575
576     case Property::VECTOR4:
577     {
578       AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
579                                                              targetPropertyIndex,
580                                                              componentIndex,
581                                                              new AnimateToVector4( destinationValue.Get<Vector4>() ),
582                                                              alpha,
583                                                              period ) );
584       break;
585     }
586
587     case Property::ROTATION:
588     {
589       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
590                                                                 targetPropertyIndex,
591                                                                 componentIndex,
592                                                                 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
593                                                                 alpha,
594                                                                 period ) );
595       break;
596     }
597
598     default:
599       DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
600       break;
601   }
602 }
603
604 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
605 {
606   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
607 }
608
609 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
610 {
611   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
612 }
613
614 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
615 {
616   AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
617 }
618
619 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
620 {
621   AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
622 }
623
624 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
625 {
626   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION);
627 }
628
629 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
630 {
631   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation);
632 }
633
634 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
635 {
636   AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
637 }
638
639 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
640 {
641   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
642
643   ExtendDuration( period );
644
645   switch(keyFrames.GetType())
646   {
647     case Dali::Property::BOOLEAN:
648     {
649       const KeyFrameBoolean* kf;
650       GetSpecialization(keyFrames, kf);
651       KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
652       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
653                                                           target.propertyIndex,
654                                                           target.componentIndex,
655                                                           new KeyFrameBooleanFunctor(kfCopy),
656                                                           alpha,
657                                                           period ) );
658       break;
659     }
660
661     case Dali::Property::INTEGER:
662     {
663       const KeyFrameInteger* kf;
664       GetSpecialization(keyFrames, kf);
665       KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
666       AddAnimatorConnector( AnimatorConnector<int>::New( object,
667                                                          target.propertyIndex,
668                                                          target.componentIndex,
669                                                          new KeyFrameIntegerFunctor(kfCopy,interpolation),
670                                                          alpha,
671                                                          period ) );
672       break;
673     }
674
675     case Dali::Property::FLOAT:
676     {
677       const KeyFrameNumber* kf;
678       GetSpecialization(keyFrames, kf);
679       KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
680       AddAnimatorConnector( AnimatorConnector<float>::New( object,
681                                                            target.propertyIndex,
682                                                            target.componentIndex,
683                                                            new KeyFrameNumberFunctor(kfCopy,interpolation),
684                                                            alpha,
685                                                            period ) );
686       break;
687     }
688
689     case Dali::Property::VECTOR2:
690     {
691       const KeyFrameVector2* kf;
692       GetSpecialization(keyFrames, kf);
693       KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
694       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
695                                                              target.propertyIndex,
696                                                              target.componentIndex,
697                                                              new KeyFrameVector2Functor(kfCopy,interpolation),
698                                                              alpha,
699                                                              period ) );
700       break;
701     }
702
703     case Dali::Property::VECTOR3:
704     {
705       const KeyFrameVector3* kf;
706       GetSpecialization(keyFrames, kf);
707       KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
708       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
709                                                              target.propertyIndex,
710                                                              target.componentIndex,
711                                                              new KeyFrameVector3Functor(kfCopy,interpolation),
712                                                              alpha,
713                                                              period ) );
714       break;
715     }
716
717     case Dali::Property::VECTOR4:
718     {
719       const KeyFrameVector4* kf;
720       GetSpecialization(keyFrames, kf);
721       KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
722       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
723                                                              target.propertyIndex,
724                                                              target.componentIndex,
725                                                              new KeyFrameVector4Functor(kfCopy,interpolation),
726                                                              alpha,
727                                                              period ) );
728       break;
729     }
730
731     case Dali::Property::ROTATION:
732     {
733       const KeyFrameQuaternion* kf;
734       GetSpecialization(keyFrames, kf);
735       KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
736       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
737                                                                 target.propertyIndex,
738                                                                 target.componentIndex,
739                                                                 new KeyFrameQuaternionFunctor(kfCopy),
740                                                                 alpha,
741                                                                 period ) );
742       break;
743     }
744
745     default: // not all property types are animateable
746       break;
747   }
748 }
749
750 bool Animation::HasFinished()
751 {
752   bool hasFinished(false);
753   const int playedCount(mAnimation->GetPlayedCount());
754
755   // If the play count has been incremented, then another notification is required
756   mCurrentLoop = mAnimation->GetCurrentLoop();
757
758   if (playedCount > mNotificationCount)
759   {
760     // Note that only one signal is emitted, if the animation has been played repeatedly
761     mNotificationCount = playedCount;
762
763     hasFinished = true;
764
765     mState = Dali::Animation::STOPPED;
766   }
767
768   return hasFinished;
769 }
770
771 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
772 {
773   return mFinishedSignal;
774 }
775
776 void Animation::EmitSignalFinish()
777 {
778   if ( !mFinishedSignal.Empty() )
779   {
780     Dali::Animation handle( this );
781     mFinishedSignal.Emit( handle );
782   }
783
784   // This callback is used internally, to avoid the overhead of using a signal.
785   if ( mFinishedCallback )
786   {
787     mFinishedCallback( mFinishedCallbackObject );
788   }
789 }
790
791 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
792 {
793   bool connected( true );
794   Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
795
796   if( 0 == signalName.compare( SIGNAL_FINISHED ) )
797   {
798     animation->FinishedSignal().Connect( tracker, functor );
799   }
800   else
801   {
802     // signalName does not match any signal
803     connected = false;
804   }
805
806   return connected;
807 }
808
809 void Animation::SetFinishedCallback( FinishedCallback callback, Object* object )
810 {
811   mFinishedCallback = callback;
812   mFinishedCallbackObject = object;
813 }
814
815 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
816 {
817   DALI_ASSERT_DEBUG( NULL != connector );
818
819   connector->SetParent(*this);
820
821   mConnectors.PushBack( connector );
822 }
823
824 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
825 {
826   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
827 }
828
829 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
830 {
831   Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
832 }
833
834 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
835 {
836   Animate( actor, path, forward, mDefaultAlpha, period );
837 }
838
839 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
840 {
841   ExtendDuration( period );
842
843   PathPtr pathCopy = Path::Clone(path);
844
845   //Position animation
846   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
847                                                          Dali::Actor::Property::POSITION,
848                                                          Property::INVALID_COMPONENT_INDEX,
849                                                          new PathPositionFunctor( pathCopy ),
850                                                          alpha,
851                                                          period ) );
852
853   //If forward is zero, PathRotationFunctor will always return the unit quaternion
854   if( forward != Vector3::ZERO )
855   {
856     //Rotation animation
857     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
858                                                               Dali::Actor::Property::ORIENTATION,
859                                                               Property::INVALID_COMPONENT_INDEX,
860                                                               new PathRotationFunctor( pathCopy, forward ),
861                                                               alpha,
862                                                               period ) );
863   }
864 }
865
866 void Animation::Show(Actor& actor, float delaySeconds)
867 {
868   ExtendDuration( TimePeriod(delaySeconds, 0) );
869
870   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
871                                                       Dali::Actor::Property::VISIBLE,
872                                                       Property::INVALID_COMPONENT_INDEX,
873                                                       new AnimateToBoolean(SHOW_VALUE),
874                                                       mDefaultAlpha,
875                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
876 }
877
878 void Animation::Hide(Actor& actor, float delaySeconds)
879 {
880   ExtendDuration( TimePeriod(delaySeconds, 0) );
881
882   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
883                                                       Dali::Actor::Property::VISIBLE,
884                                                       Property::INVALID_COMPONENT_INDEX,
885                                                       new AnimateToBoolean(HIDE_VALUE),
886                                                       mDefaultAlpha,
887                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
888 }
889
890 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
891 {
892   bool done = false;
893   Animation* animation = dynamic_cast<Animation*>( object );
894
895   if( animation )
896   {
897     if( 0 == actionName.compare( ACTION_PLAY ) )
898     {
899       if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
900       {
901         animation->SetDuration( value->Get<float>() );
902       }
903
904       animation->Play();
905       done = true;
906     }
907     else if( 0 == actionName.compare( ACTION_STOP ) )
908     {
909       animation->Stop();
910       done = true;
911     }
912     else if( 0 == actionName.compare( ACTION_PAUSE ) )
913     {
914       animation->Pause();
915       done = true;
916     }
917   }
918
919   return done;
920 }
921
922 void Animation::SetCurrentProgress(float progress)
923 {
924   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
925   {
926     // mAnimation is being used in a separate thread; queue a message to set the current progress
927     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
928   }
929 }
930
931 float Animation::GetCurrentProgress()
932 {
933   if( mAnimation )
934   {
935     return mAnimation->GetCurrentProgress();
936   }
937
938   return 0.0f;
939 }
940
941 void Animation::ExtendDuration( const TimePeriod& timePeriod )
942 {
943   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
944
945   if( duration > mDurationSeconds )
946   {
947     SetDuration( duration );
948   }
949 }
950
951 void Animation::SetSpeedFactor( float factor )
952 {
953   if( mAnimation )
954   {
955     mSpeedFactor = factor;
956     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
957   }
958 }
959
960 float Animation::GetSpeedFactor() const
961 {
962   return mSpeedFactor;
963 }
964
965 void Animation::SetPlayRange( const Vector2& range)
966 {
967   //Make sure the range specified is between 0.0 and 1.0
968   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
969   {
970     Vector2 orderedRange( range );
971     //If the range is not in order swap values
972     if( range.x > range.y )
973     {
974       orderedRange = Vector2(range.y, range.x);
975     }
976
977     // Cache for public getters
978     mPlayRange = orderedRange;
979
980     // mAnimation is being used in a separate thread; queue a message to set play range
981     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
982   }
983 }
984
985 Vector2 Animation::GetPlayRange() const
986 {
987   return mPlayRange;
988 }
989
990
991 } // namespace Internal
992
993 } // namespace Dali