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