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