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