[dali_1.2.40] Merge branch 'devel/master'
[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     // Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
272     std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
273
274     // Loop through all connector target values sorted by increasing end time
275     ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
276     const ConnectorTargetValuesContainer::const_iterator endIter = mConnectorTargetValues.end();
277     for( ; iter != endIter; ++iter )
278     {
279       AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ];
280
281       Object* object = connector->GetObject();
282       if( object )
283       {
284         object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), iter->targetValue );
285       }
286     }
287   }
288
289   // mAnimation is being used in a separate thread; queue a Play message
290   PlayAnimationMessage( mEventThreadServices, *mAnimation );
291 }
292
293 void Animation::PlayFrom( float progress )
294 {
295   if( progress >= mPlayRange.x && progress <= mPlayRange.y )
296   {
297     // Update the current playlist
298     mPlaylist.OnPlay( *this );
299
300     mState = Dali::Animation::PLAYING;
301
302     // mAnimation is being used in a separate thread; queue a Play message
303     PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
304   }
305 }
306
307 void Animation::Pause()
308 {
309   mState = Dali::Animation::PAUSED;
310
311   // mAnimation is being used in a separate thread; queue a Pause message
312   PauseAnimationMessage( mEventThreadServices, *mAnimation );
313 }
314
315 Dali::Animation::State Animation::GetState() const
316 {
317   return mState;
318 }
319
320 void Animation::Stop()
321 {
322   mState = Dali::Animation::STOPPED;
323
324   // mAnimation is being used in a separate thread; queue a Stop message
325   StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
326 }
327
328 void Animation::Clear()
329 {
330   DALI_ASSERT_DEBUG(mAnimation);
331
332   // Remove all the connectors
333   mConnectors.Clear();
334
335   // Reset the connector target values
336   mConnectorTargetValues.clear();
337
338   // Replace the old scene-object with a new one
339   DestroySceneObject();
340   CreateSceneObject();
341
342   // Reset the notification count, since the new scene-object has never been played
343   mNotificationCount = 0;
344
345   // Update the current playlist
346   mPlaylist.OnClear( *this );
347 }
348
349 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
350 {
351   AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
352 }
353
354 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
355 {
356   AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds));
357 }
358
359 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
360 {
361   AnimateBy(target, relativeValue, mDefaultAlpha, period);
362 }
363
364 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
365 {
366   Object& object = GetImplementation( target.object );
367   const Property::Type targetType = object.GetPropertyType( target.propertyIndex );
368   const Property::Type destinationType = relativeValue.GetType();
369   DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
370
371   ExtendDuration( period );
372
373   switch ( targetType )
374   {
375     case Property::BOOLEAN:
376     {
377       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
378                                                           target.propertyIndex,
379                                                           target.componentIndex,
380                                                           new AnimateByBoolean(relativeValue.Get<bool>()),
381                                                           alpha,
382                                                           period ) );
383       break;
384     }
385
386     case Property::INTEGER:
387     {
388       AddAnimatorConnector( AnimatorConnector<int>::New( object,
389                                                          target.propertyIndex,
390                                                          target.componentIndex,
391                                                          new AnimateByInteger(relativeValue.Get<int>()),
392                                                          alpha,
393                                                          period ) );
394       break;
395     }
396
397     case Property::FLOAT:
398     {
399       AddAnimatorConnector( AnimatorConnector<float>::New( object,
400                                                            target.propertyIndex,
401                                                            target.componentIndex,
402                                                            new AnimateByFloat(relativeValue.Get<float>()),
403                                                            alpha,
404                                                            period ) );
405       break;
406     }
407
408     case Property::VECTOR2:
409     {
410       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
411                                                              target.propertyIndex,
412                                                              target.componentIndex,
413                                                              new AnimateByVector2(relativeValue.Get<Vector2>()),
414                                                              alpha,
415                                                              period ) );
416       break;
417     }
418
419     case Property::VECTOR3:
420     {
421       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
422                                                              target.propertyIndex,
423                                                              target.componentIndex,
424                                                              new AnimateByVector3(relativeValue.Get<Vector3>()),
425                                                              alpha,
426                                                              period ) );
427       break;
428     }
429
430     case Property::VECTOR4:
431     {
432       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
433                                                              target.propertyIndex,
434                                                              target.componentIndex,
435                                                              new AnimateByVector4(relativeValue.Get<Vector4>()),
436                                                              alpha,
437                                                              period ) );
438       break;
439     }
440
441     case Property::ROTATION:
442     {
443       AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
444
445       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
446                                                                 target.propertyIndex,
447                                                                 target.componentIndex,
448                                                                 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
449                                                                 alpha,
450                                                                 period ) );
451       break;
452     }
453
454     default:
455     {
456       // non animatable types handled already
457     }
458   }
459 }
460
461 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
462 {
463   AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
464 }
465
466 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
467 {
468   AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
469 }
470
471 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
472 {
473   AnimateTo(target, destinationValue, mDefaultAlpha, period);
474 }
475
476 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
477 {
478   Object& object = GetImplementation(target.object);
479
480   AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
481 }
482
483 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
484 {
485   Property::Type targetType = targetObject.GetPropertyType(targetPropertyIndex);
486   if( componentIndex != Property::INVALID_COMPONENT_INDEX )
487   {
488     if( ( targetType == Property::VECTOR2 ) ||
489         ( targetType == Property::VECTOR3 ) ||
490         ( targetType == Property::VECTOR4 ) )
491     {
492       targetType = Property::FLOAT;
493     }
494   }
495   const Property::Type destinationType = destinationValue.GetType();
496   DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
497
498   ExtendDuration( period );
499
500   // Store data to later notify the object that its property is being animated
501   ConnectorTargetValues connectorPair;
502   connectorPair.targetValue = destinationValue;
503   connectorPair.connectorIndex = mConnectors.Count();
504   connectorPair.timePeriod = period;
505   mConnectorTargetValues.push_back( connectorPair );
506
507   switch ( destinationType )
508   {
509     case Property::BOOLEAN:
510     {
511       AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
512                                                           targetPropertyIndex,
513                                                           componentIndex,
514                                                           new AnimateToBoolean( destinationValue.Get<bool>() ),
515                                                           alpha,
516                                                           period ) );
517       break;
518     }
519
520     case Property::INTEGER:
521     {
522       AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
523                                                          targetPropertyIndex,
524                                                          componentIndex,
525                                                          new AnimateToInteger( destinationValue.Get<int>() ),
526                                                          alpha,
527                                                          period ) );
528       break;
529     }
530
531     case Property::FLOAT:
532     {
533       AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
534                                                            targetPropertyIndex,
535                                                            componentIndex,
536                                                            new AnimateToFloat( destinationValue.Get<float>() ),
537                                                            alpha,
538                                                            period ) );
539       break;
540     }
541
542     case Property::VECTOR2:
543     {
544       AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
545                                                              targetPropertyIndex,
546                                                              componentIndex,
547                                                              new AnimateToVector2( destinationValue.Get<Vector2>() ),
548                                                              alpha,
549                                                              period ) );
550       break;
551     }
552
553     case Property::VECTOR3:
554     {
555       AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
556                                                              targetPropertyIndex,
557                                                              componentIndex,
558                                                              new AnimateToVector3( destinationValue.Get<Vector3>() ),
559                                                              alpha,
560                                                              period ) );
561       break;
562     }
563
564     case Property::VECTOR4:
565     {
566       AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
567                                                              targetPropertyIndex,
568                                                              componentIndex,
569                                                              new AnimateToVector4( destinationValue.Get<Vector4>() ),
570                                                              alpha,
571                                                              period ) );
572       break;
573     }
574
575     case Property::ROTATION:
576     {
577       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
578                                                                 targetPropertyIndex,
579                                                                 componentIndex,
580                                                                 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
581                                                                 alpha,
582                                                                 period ) );
583       break;
584     }
585
586     default:
587     {
588       // non animatable types handled already
589     }
590   }
591 }
592
593 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
594 {
595   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
596 }
597
598 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
599 {
600   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
601 }
602
603 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
604 {
605   AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
606 }
607
608 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
609 {
610   AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
611 }
612
613 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
614 {
615   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION);
616 }
617
618 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
619 {
620   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation);
621 }
622
623 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
624 {
625   AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
626 }
627
628 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
629 {
630   Object& object = GetImplementation( target.object );
631
632   ExtendDuration( period );
633
634   switch(keyFrames.GetType())
635   {
636     case Dali::Property::BOOLEAN:
637     {
638       const KeyFrameBoolean* kf;
639       GetSpecialization(keyFrames, kf);
640       KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
641       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
642                                                           target.propertyIndex,
643                                                           target.componentIndex,
644                                                           new KeyFrameBooleanFunctor(kfCopy),
645                                                           alpha,
646                                                           period ) );
647       break;
648     }
649
650     case Dali::Property::INTEGER:
651     {
652       const KeyFrameInteger* kf;
653       GetSpecialization(keyFrames, kf);
654       KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
655       AddAnimatorConnector( AnimatorConnector<int>::New( object,
656                                                          target.propertyIndex,
657                                                          target.componentIndex,
658                                                          new KeyFrameIntegerFunctor(kfCopy,interpolation),
659                                                          alpha,
660                                                          period ) );
661       break;
662     }
663
664     case Dali::Property::FLOAT:
665     {
666       const KeyFrameNumber* kf;
667       GetSpecialization(keyFrames, kf);
668       KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
669       AddAnimatorConnector( AnimatorConnector<float>::New( object,
670                                                            target.propertyIndex,
671                                                            target.componentIndex,
672                                                            new KeyFrameNumberFunctor(kfCopy,interpolation),
673                                                            alpha,
674                                                            period ) );
675       break;
676     }
677
678     case Dali::Property::VECTOR2:
679     {
680       const KeyFrameVector2* kf;
681       GetSpecialization(keyFrames, kf);
682       KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
683       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
684                                                              target.propertyIndex,
685                                                              target.componentIndex,
686                                                              new KeyFrameVector2Functor(kfCopy,interpolation),
687                                                              alpha,
688                                                              period ) );
689       break;
690     }
691
692     case Dali::Property::VECTOR3:
693     {
694       const KeyFrameVector3* kf;
695       GetSpecialization(keyFrames, kf);
696       KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
697       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
698                                                              target.propertyIndex,
699                                                              target.componentIndex,
700                                                              new KeyFrameVector3Functor(kfCopy,interpolation),
701                                                              alpha,
702                                                              period ) );
703       break;
704     }
705
706     case Dali::Property::VECTOR4:
707     {
708       const KeyFrameVector4* kf;
709       GetSpecialization(keyFrames, kf);
710       KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
711       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
712                                                              target.propertyIndex,
713                                                              target.componentIndex,
714                                                              new KeyFrameVector4Functor(kfCopy,interpolation),
715                                                              alpha,
716                                                              period ) );
717       break;
718     }
719
720     case Dali::Property::ROTATION:
721     {
722       const KeyFrameQuaternion* kf;
723       GetSpecialization(keyFrames, kf);
724       KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
725       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
726                                                                 target.propertyIndex,
727                                                                 target.componentIndex,
728                                                                 new KeyFrameQuaternionFunctor(kfCopy),
729                                                                 alpha,
730                                                                 period ) );
731       break;
732     }
733
734     default:
735     {
736       // non animatable types handled by keyframes
737     }
738   }
739 }
740
741 bool Animation::HasFinished()
742 {
743   bool hasFinished(false);
744   const int playedCount(mAnimation->GetPlayedCount());
745
746   // If the play count has been incremented, then another notification is required
747   mCurrentLoop = mAnimation->GetCurrentLoop();
748
749   if (playedCount > mNotificationCount)
750   {
751     // Note that only one signal is emitted, if the animation has been played repeatedly
752     mNotificationCount = playedCount;
753
754     hasFinished = true;
755
756     mState = Dali::Animation::STOPPED;
757   }
758
759   return hasFinished;
760 }
761
762 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
763 {
764   return mFinishedSignal;
765 }
766
767 void Animation::EmitSignalFinish()
768 {
769   if ( !mFinishedSignal.Empty() )
770   {
771     Dali::Animation handle( this );
772     mFinishedSignal.Emit( handle );
773   }
774 }
775
776 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
777 {
778   bool connected( true );
779   Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
780
781   if( 0 == signalName.compare( SIGNAL_FINISHED ) )
782   {
783     animation->FinishedSignal().Connect( tracker, functor );
784   }
785   else
786   {
787     // signalName does not match any signal
788     connected = false;
789   }
790
791   return connected;
792 }
793
794 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
795 {
796   DALI_ASSERT_DEBUG( NULL != connector );
797
798   connector->SetParent(*this);
799
800   mConnectors.PushBack( connector );
801 }
802
803 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
804 {
805   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
806 }
807
808 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
809 {
810   Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
811 }
812
813 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
814 {
815   Animate( actor, path, forward, mDefaultAlpha, period );
816 }
817
818 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
819 {
820   ExtendDuration( period );
821
822   PathPtr pathCopy = Path::Clone(path);
823
824   //Position animation
825   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
826                                                          Dali::Actor::Property::POSITION,
827                                                          Property::INVALID_COMPONENT_INDEX,
828                                                          new PathPositionFunctor( pathCopy ),
829                                                          alpha,
830                                                          period ) );
831
832   //If forward is zero, PathRotationFunctor will always return the unit quaternion
833   if( forward != Vector3::ZERO )
834   {
835     //Rotation animation
836     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
837                                                               Dali::Actor::Property::ORIENTATION,
838                                                               Property::INVALID_COMPONENT_INDEX,
839                                                               new PathRotationFunctor( pathCopy, forward ),
840                                                               alpha,
841                                                               period ) );
842   }
843 }
844
845 void Animation::Show(Actor& actor, float delaySeconds)
846 {
847   ExtendDuration( TimePeriod(delaySeconds, 0) );
848
849   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
850                                                       Dali::Actor::Property::VISIBLE,
851                                                       Property::INVALID_COMPONENT_INDEX,
852                                                       new AnimateToBoolean(SHOW_VALUE),
853                                                       mDefaultAlpha,
854                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
855 }
856
857 void Animation::Hide(Actor& actor, float delaySeconds)
858 {
859   ExtendDuration( TimePeriod(delaySeconds, 0) );
860
861   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
862                                                       Dali::Actor::Property::VISIBLE,
863                                                       Property::INVALID_COMPONENT_INDEX,
864                                                       new AnimateToBoolean(HIDE_VALUE),
865                                                       mDefaultAlpha,
866                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
867 }
868
869 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
870 {
871   bool done = false;
872   Animation* animation = dynamic_cast<Animation*>( object );
873
874   if( animation )
875   {
876     if( 0 == actionName.compare( ACTION_PLAY ) )
877     {
878       if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
879       {
880         animation->SetDuration( value->Get<float>() );
881       }
882
883       animation->Play();
884       done = true;
885     }
886     else if( 0 == actionName.compare( ACTION_STOP ) )
887     {
888       animation->Stop();
889       done = true;
890     }
891     else if( 0 == actionName.compare( ACTION_PAUSE ) )
892     {
893       animation->Pause();
894       done = true;
895     }
896   }
897
898   return done;
899 }
900
901 void Animation::SetCurrentProgress(float progress)
902 {
903   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
904   {
905     // mAnimation is being used in a separate thread; queue a message to set the current progress
906     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
907   }
908 }
909
910 float Animation::GetCurrentProgress()
911 {
912   if( mAnimation )
913   {
914     return mAnimation->GetCurrentProgress();
915   }
916
917   return 0.0f;
918 }
919
920 void Animation::ExtendDuration( const TimePeriod& timePeriod )
921 {
922   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
923
924   if( duration > mDurationSeconds )
925   {
926     SetDuration( duration );
927   }
928 }
929
930 void Animation::SetSpeedFactor( float factor )
931 {
932   if( mAnimation )
933   {
934     mSpeedFactor = factor;
935     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
936   }
937 }
938
939 float Animation::GetSpeedFactor() const
940 {
941   return mSpeedFactor;
942 }
943
944 void Animation::SetPlayRange( const Vector2& range)
945 {
946   //Make sure the range specified is between 0.0 and 1.0
947   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
948   {
949     Vector2 orderedRange( range );
950     //If the range is not in order swap values
951     if( range.x > range.y )
952     {
953       orderedRange = Vector2(range.y, range.x);
954     }
955
956     // Cache for public getters
957     mPlayRange = orderedRange;
958
959     // mAnimation is being used in a separate thread; queue a message to set play range
960     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
961   }
962 }
963
964 Vector2 Animation::GetPlayRange() const
965 {
966   return mPlayRange;
967 }
968
969 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
970 {
971   return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
972 }
973
974 } // namespace Internal
975
976 } // namespace Dali