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