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