Ensure cached values of properties animated using AnimateTo are updated
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / animation-impl.cpp
1 /*
2  * Copyright (c) 2017 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/animation/alpha-function.h>
26 #include <dali/public-api/animation/time-period.h>
27 #include <dali/public-api/common/dali-common.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/public-api/math/vector2.h>
30 #include <dali/public-api/math/radian.h>
31 #include <dali/internal/event/animation/animation-playlist.h>
32 #include <dali/internal/event/animation/animator-connector.h>
33 #include <dali/internal/event/common/notification-manager.h>
34 #include <dali/internal/event/common/property-helper.h>
35 #include <dali/internal/event/common/stage-impl.h>
36 #include <dali/internal/event/common/thread-local-storage.h>
37 #include <dali/internal/update/animation/scene-graph-animator.h>
38 #include <dali/internal/update/manager/update-manager.h>
39
40 using Dali::Internal::SceneGraph::UpdateManager;
41 using Dali::Internal::SceneGraph::AnimatorBase;
42 using Dali::Internal::SceneGraph::Shader;
43
44 namespace Dali
45 {
46
47 namespace Internal
48 {
49
50 static bool SHOW_VALUE = true;
51 static bool HIDE_VALUE = false;
52
53 namespace
54 {
55
56 // Signals
57
58 const char* const SIGNAL_FINISHED = "finished";
59
60 // Actions
61
62 const char* const ACTION_PLAY =     "play";
63 const char* const ACTION_STOP =     "stop";
64 const char* const ACTION_PAUSE =    "pause";
65
66 BaseHandle Create()
67 {
68   return Dali::Animation::New(0.f);
69 }
70
71 TypeRegistration mType( typeid( Dali::Animation ), typeid( Dali::BaseHandle ), Create );
72
73 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &Animation::DoConnectSignal );
74
75 TypeAction action1( mType, ACTION_PLAY,  &Animation::DoAction );
76 TypeAction action2( mType, ACTION_STOP,  &Animation::DoAction );
77 TypeAction action3( mType, ACTION_PAUSE, &Animation::DoAction );
78
79 const Dali::Animation::EndAction DEFAULT_END_ACTION( Dali::Animation::Bake );
80 const Dali::Animation::EndAction DEFAULT_DISCONNECT_ACTION( Dali::Animation::BakeFinal );
81 const Dali::Animation::Interpolation DEFAULT_INTERPOLATION( Dali::Animation::Linear );
82 const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION( Dali::AlphaFunction::DEFAULT );
83
84 } // anon namespace
85
86
87 AnimationPtr Animation::New(float durationSeconds)
88 {
89   Stage* stage = Stage::GetCurrent();
90
91   if( stage )
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   else
109   {
110     return NULL;
111   }
112 }
113
114 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
115 : mEventThreadServices( eventThreadServices ),
116   mPlaylist( playlist ),
117   mAnimation( NULL ),
118   mNotificationCount( 0 ),
119   mFinishedCallback( NULL ),
120   mFinishedCallbackObject( NULL ),
121   mDurationSeconds( durationSeconds ),
122   mSpeedFactor(1.0f),
123   mLoopCount(1),
124   mCurrentLoop(0),
125   mPlayRange( Vector2(0.0f,1.0f)),
126   mEndAction( endAction ),
127   mDisconnectAction( disconnectAction ),
128   mDefaultAlpha( defaultAlpha ),
129   mState(Dali::Animation::STOPPED)
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, mLoopCount, 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 on)
203 {
204   SetLoopCount( on ? 0 : 1 );
205 }
206
207 void Animation::SetLoopCount(int count)
208 {
209   // Cache for public getters
210   mLoopCount = count;
211
212   // mAnimation is being used in a separate thread; queue a message to set the value
213   SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount );
214 }
215
216 int Animation::GetLoopCount()
217 {
218   return mLoopCount;
219 }
220
221 int Animation::GetCurrentLoop()
222 {
223   return mCurrentLoop;
224 }
225
226 bool Animation::IsLooping() const
227 {
228   return mLoopCount != 1;
229 }
230
231 void Animation::SetEndAction(EndAction action)
232 {
233   // Cache for public getters
234   mEndAction = action;
235
236   // mAnimation is being used in a separate thread; queue a message to set the value
237   SetEndActionMessage( mEventThreadServices, *mAnimation, action );
238 }
239
240 Dali::Animation::EndAction Animation::GetEndAction() const
241 {
242   // This is not animatable; the cached value is up-to-date.
243   return mEndAction;
244 }
245
246 void Animation::SetDisconnectAction(EndAction action)
247 {
248   // Cache for public getters
249   mDisconnectAction = action;
250
251   // mAnimation is being used in a separate thread; queue a message to set the value
252   SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
253 }
254
255 Dali::Animation::EndAction Animation::GetDisconnectAction() const
256 {
257   // This is not animatable; the cached value is up-to-date.
258   return mDisconnectAction;
259 }
260
261 void Animation::Play()
262 {
263   // Update the current playlist
264   mPlaylist.OnPlay( *this );
265
266   mState = Dali::Animation::PLAYING;
267
268   if( mEndAction != EndAction::Discard ) // If the animation is discarded, then we do not want to change the target values
269   {
270     unsigned int connectorTargetValuesIndex( 0 );
271     unsigned int numberOfConnectorTargetValues = mConnectorTargetValues.size();
272
273     /*
274      * Loop through all Animator connectors, if connector index matches the current index stored in mConnectorTargetValues container then
275      * should apply target values for this index to the object.
276      */
277     for ( unsigned int connectorIndex = 0; connectorIndex < mConnectors.Count(); connectorIndex ++)
278     {
279       // Use index to check if the current connector is next in the mConnectorTargetValues container, meaning targetValues have been pushed in AnimateXXFunction
280       if ( connectorTargetValuesIndex < numberOfConnectorTargetValues )
281       {
282         ConnectorTargetValues& connectorPair = mConnectorTargetValues[ connectorTargetValuesIndex ];
283
284         if ( connectorPair.connectorIndex == connectorIndex )
285         {
286           // Current connector index matches next in the stored connectors with target values so apply target value.
287           connectorTargetValuesIndex++; // Found a match for connector so increment index to next one
288
289           AnimatorConnectorBase* connector = mConnectors[ connectorIndex ];
290
291           Object* object = connector->GetObject();
292           if( object )
293           {
294             object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), connectorPair.targetValue );
295           }
296         }
297       }
298     }
299   }
300
301   // mAnimation is being used in a separate thread; queue a Play message
302   PlayAnimationMessage( mEventThreadServices, *mAnimation );
303 }
304
305 void Animation::PlayFrom( float progress )
306 {
307   if( progress >= mPlayRange.x && progress <= mPlayRange.y )
308   {
309     // Update the current playlist
310     mPlaylist.OnPlay( *this );
311
312     mState = Dali::Animation::PLAYING;
313
314     // mAnimation is being used in a separate thread; queue a Play message
315     PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
316   }
317 }
318
319 void Animation::Pause()
320 {
321   mState = Dali::Animation::PAUSED;
322
323   // mAnimation is being used in a separate thread; queue a Pause message
324   PauseAnimationMessage( mEventThreadServices, *mAnimation );
325 }
326
327 Dali::Animation::State Animation::GetState() const
328 {
329   return mState;
330 }
331
332 void Animation::Stop()
333 {
334   mState = Dali::Animation::STOPPED;
335
336   // mAnimation is being used in a separate thread; queue a Stop message
337   StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
338 }
339
340 void Animation::Clear()
341 {
342   DALI_ASSERT_DEBUG(mAnimation);
343
344   // Remove all the connectors
345   mConnectors.Clear();
346
347   // Reset the connector target values
348   mConnectorTargetValues.clear();
349
350   // Replace the old scene-object with a new one
351   DestroySceneObject();
352   CreateSceneObject();
353
354   // Reset the notification count, since the new scene-object has never been played
355   mNotificationCount = 0;
356
357   // Update the current playlist
358   mPlaylist.OnClear( *this );
359 }
360
361 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
362 {
363   AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
364 }
365
366 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
367 {
368   AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds));
369 }
370
371 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
372 {
373   AnimateBy(target, relativeValue, mDefaultAlpha, period);
374 }
375
376 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
377 {
378   Object& object = GetImplementation( target.object );
379   const Property::Type targetType = object.GetPropertyType( target.propertyIndex );
380   const Property::Type destinationType = relativeValue.GetType();
381   DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
382
383   ExtendDuration( period );
384
385   switch ( targetType )
386   {
387     case Property::BOOLEAN:
388     {
389       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
390                                                           target.propertyIndex,
391                                                           target.componentIndex,
392                                                           new AnimateByBoolean(relativeValue.Get<bool>()),
393                                                           alpha,
394                                                           period ) );
395       break;
396     }
397
398     case Property::INTEGER:
399     {
400       AddAnimatorConnector( AnimatorConnector<int>::New( object,
401                                                          target.propertyIndex,
402                                                          target.componentIndex,
403                                                          new AnimateByInteger(relativeValue.Get<int>()),
404                                                          alpha,
405                                                          period ) );
406       break;
407     }
408
409     case Property::FLOAT:
410     {
411       AddAnimatorConnector( AnimatorConnector<float>::New( object,
412                                                            target.propertyIndex,
413                                                            target.componentIndex,
414                                                            new AnimateByFloat(relativeValue.Get<float>()),
415                                                            alpha,
416                                                            period ) );
417       break;
418     }
419
420     case Property::VECTOR2:
421     {
422       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
423                                                              target.propertyIndex,
424                                                              target.componentIndex,
425                                                              new AnimateByVector2(relativeValue.Get<Vector2>()),
426                                                              alpha,
427                                                              period ) );
428       break;
429     }
430
431     case Property::VECTOR3:
432     {
433       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
434                                                              target.propertyIndex,
435                                                              target.componentIndex,
436                                                              new AnimateByVector3(relativeValue.Get<Vector3>()),
437                                                              alpha,
438                                                              period ) );
439       break;
440     }
441
442     case Property::VECTOR4:
443     {
444       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
445                                                              target.propertyIndex,
446                                                              target.componentIndex,
447                                                              new AnimateByVector4(relativeValue.Get<Vector4>()),
448                                                              alpha,
449                                                              period ) );
450       break;
451     }
452
453     case Property::ROTATION:
454     {
455       AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
456
457       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
458                                                                 target.propertyIndex,
459                                                                 target.componentIndex,
460                                                                 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
461                                                                 alpha,
462                                                                 period ) );
463       break;
464     }
465
466     default:
467     {
468       // non animatable types handled already
469     }
470   }
471 }
472
473 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
474 {
475   AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
476 }
477
478 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
479 {
480   AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
481 }
482
483 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
484 {
485   AnimateTo(target, destinationValue, mDefaultAlpha, period);
486 }
487
488 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
489 {
490   Object& object = GetImplementation(target.object);
491
492   AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
493 }
494
495 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
496 {
497   Property::Type targetType = targetObject.GetPropertyType(targetPropertyIndex);
498   if( componentIndex != Property::INVALID_COMPONENT_INDEX )
499   {
500     if( ( targetType == Property::VECTOR2 ) ||
501         ( targetType == Property::VECTOR3 ) ||
502         ( targetType == Property::VECTOR4 ) )
503     {
504       targetType = Property::FLOAT;
505     }
506   }
507   const Property::Type destinationType = destinationValue.GetType();
508   DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
509
510   ExtendDuration( period );
511
512   // Store data to later notify the object that its property is being animated
513   ConnectorTargetValues connectorPair;
514   connectorPair.targetValue = destinationValue;
515   connectorPair.connectorIndex = mConnectors.Count();
516   mConnectorTargetValues.push_back( connectorPair );
517
518   switch ( destinationType )
519   {
520     case Property::BOOLEAN:
521     {
522       AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
523                                                           targetPropertyIndex,
524                                                           componentIndex,
525                                                           new AnimateToBoolean( destinationValue.Get<bool>() ),
526                                                           alpha,
527                                                           period ) );
528       break;
529     }
530
531     case Property::INTEGER:
532     {
533       AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
534                                                          targetPropertyIndex,
535                                                          componentIndex,
536                                                          new AnimateToInteger( destinationValue.Get<int>() ),
537                                                          alpha,
538                                                          period ) );
539       break;
540     }
541
542     case Property::FLOAT:
543     {
544       AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
545                                                            targetPropertyIndex,
546                                                            componentIndex,
547                                                            new AnimateToFloat( destinationValue.Get<float>() ),
548                                                            alpha,
549                                                            period ) );
550       break;
551     }
552
553     case Property::VECTOR2:
554     {
555       AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
556                                                              targetPropertyIndex,
557                                                              componentIndex,
558                                                              new AnimateToVector2( destinationValue.Get<Vector2>() ),
559                                                              alpha,
560                                                              period ) );
561       break;
562     }
563
564     case Property::VECTOR3:
565     {
566       AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
567                                                              targetPropertyIndex,
568                                                              componentIndex,
569                                                              new AnimateToVector3( destinationValue.Get<Vector3>() ),
570                                                              alpha,
571                                                              period ) );
572       break;
573     }
574
575     case Property::VECTOR4:
576     {
577       AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
578                                                              targetPropertyIndex,
579                                                              componentIndex,
580                                                              new AnimateToVector4( destinationValue.Get<Vector4>() ),
581                                                              alpha,
582                                                              period ) );
583       break;
584     }
585
586     case Property::ROTATION:
587     {
588       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
589                                                                 targetPropertyIndex,
590                                                                 componentIndex,
591                                                                 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
592                                                                 alpha,
593                                                                 period ) );
594       break;
595     }
596
597     default:
598     {
599       // non animatable types handled already
600     }
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 = 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:
746     {
747       // non animatable types handled by keyframes
748     }
749   }
750 }
751
752 bool Animation::HasFinished()
753 {
754   bool hasFinished(false);
755   const int playedCount(mAnimation->GetPlayedCount());
756
757   // If the play count has been incremented, then another notification is required
758   mCurrentLoop = mAnimation->GetCurrentLoop();
759
760   if (playedCount > mNotificationCount)
761   {
762     // Note that only one signal is emitted, if the animation has been played repeatedly
763     mNotificationCount = playedCount;
764
765     hasFinished = true;
766
767     mState = Dali::Animation::STOPPED;
768   }
769
770   return hasFinished;
771 }
772
773 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
774 {
775   return mFinishedSignal;
776 }
777
778 void Animation::EmitSignalFinish()
779 {
780   if ( !mFinishedSignal.Empty() )
781   {
782     Dali::Animation handle( this );
783     mFinishedSignal.Emit( handle );
784   }
785
786   // This callback is used internally, to avoid the overhead of using a signal.
787   if ( mFinishedCallback )
788   {
789     mFinishedCallback( mFinishedCallbackObject );
790   }
791 }
792
793 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
794 {
795   bool connected( true );
796   Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
797
798   if( 0 == signalName.compare( SIGNAL_FINISHED ) )
799   {
800     animation->FinishedSignal().Connect( tracker, functor );
801   }
802   else
803   {
804     // signalName does not match any signal
805     connected = false;
806   }
807
808   return connected;
809 }
810
811 void Animation::SetFinishedCallback( FinishedCallback callback, Object* object )
812 {
813   mFinishedCallback = callback;
814   mFinishedCallbackObject = object;
815 }
816
817 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
818 {
819   DALI_ASSERT_DEBUG( NULL != connector );
820
821   connector->SetParent(*this);
822
823   mConnectors.PushBack( connector );
824 }
825
826 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
827 {
828   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
829 }
830
831 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
832 {
833   Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
834 }
835
836 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
837 {
838   Animate( actor, path, forward, mDefaultAlpha, period );
839 }
840
841 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
842 {
843   ExtendDuration( period );
844
845   PathPtr pathCopy = Path::Clone(path);
846
847   //Position animation
848   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
849                                                          Dali::Actor::Property::POSITION,
850                                                          Property::INVALID_COMPONENT_INDEX,
851                                                          new PathPositionFunctor( pathCopy ),
852                                                          alpha,
853                                                          period ) );
854
855   //If forward is zero, PathRotationFunctor will always return the unit quaternion
856   if( forward != Vector3::ZERO )
857   {
858     //Rotation animation
859     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
860                                                               Dali::Actor::Property::ORIENTATION,
861                                                               Property::INVALID_COMPONENT_INDEX,
862                                                               new PathRotationFunctor( pathCopy, forward ),
863                                                               alpha,
864                                                               period ) );
865   }
866 }
867
868 void Animation::Show(Actor& actor, float delaySeconds)
869 {
870   ExtendDuration( TimePeriod(delaySeconds, 0) );
871
872   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
873                                                       Dali::Actor::Property::VISIBLE,
874                                                       Property::INVALID_COMPONENT_INDEX,
875                                                       new AnimateToBoolean(SHOW_VALUE),
876                                                       mDefaultAlpha,
877                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
878 }
879
880 void Animation::Hide(Actor& actor, float delaySeconds)
881 {
882   ExtendDuration( TimePeriod(delaySeconds, 0) );
883
884   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
885                                                       Dali::Actor::Property::VISIBLE,
886                                                       Property::INVALID_COMPONENT_INDEX,
887                                                       new AnimateToBoolean(HIDE_VALUE),
888                                                       mDefaultAlpha,
889                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
890 }
891
892 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
893 {
894   bool done = false;
895   Animation* animation = dynamic_cast<Animation*>( object );
896
897   if( animation )
898   {
899     if( 0 == actionName.compare( ACTION_PLAY ) )
900     {
901       if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
902       {
903         animation->SetDuration( value->Get<float>() );
904       }
905
906       animation->Play();
907       done = true;
908     }
909     else if( 0 == actionName.compare( ACTION_STOP ) )
910     {
911       animation->Stop();
912       done = true;
913     }
914     else if( 0 == actionName.compare( ACTION_PAUSE ) )
915     {
916       animation->Pause();
917       done = true;
918     }
919   }
920
921   return done;
922 }
923
924 void Animation::SetCurrentProgress(float progress)
925 {
926   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
927   {
928     // mAnimation is being used in a separate thread; queue a message to set the current progress
929     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
930   }
931 }
932
933 float Animation::GetCurrentProgress()
934 {
935   if( mAnimation )
936   {
937     return mAnimation->GetCurrentProgress();
938   }
939
940   return 0.0f;
941 }
942
943 void Animation::ExtendDuration( const TimePeriod& timePeriod )
944 {
945   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
946
947   if( duration > mDurationSeconds )
948   {
949     SetDuration( duration );
950   }
951 }
952
953 void Animation::SetSpeedFactor( float factor )
954 {
955   if( mAnimation )
956   {
957     mSpeedFactor = factor;
958     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
959   }
960 }
961
962 float Animation::GetSpeedFactor() const
963 {
964   return mSpeedFactor;
965 }
966
967 void Animation::SetPlayRange( const Vector2& range)
968 {
969   //Make sure the range specified is between 0.0 and 1.0
970   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
971   {
972     Vector2 orderedRange( range );
973     //If the range is not in order swap values
974     if( range.x > range.y )
975     {
976       orderedRange = Vector2(range.y, range.x);
977     }
978
979     // Cache for public getters
980     mPlayRange = orderedRange;
981
982     // mAnimation is being used in a separate thread; queue a message to set play range
983     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
984   }
985 }
986
987 Vector2 Animation::GetPlayRange() const
988 {
989   return mPlayRange;
990 }
991
992
993 } // namespace Internal
994
995 } // namespace Dali