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