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