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