Merge "- Update UTC for animation.h - Remove assert when duration is 0 in Animation...
[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::FLOAT:
325     {
326       AddAnimatorConnector( AnimatorConnector<float>::New( object,
327                                                            target.propertyIndex,
328                                                            target.componentIndex,
329                                                            new AnimateByFloat(relativeValue.Get<float>()),
330                                                            alpha,
331                                                            period ) );
332       break;
333     }
334
335     case Property::INTEGER:
336     {
337       AddAnimatorConnector( AnimatorConnector<int>::New( object,
338                                                          target.propertyIndex,
339                                                          target.componentIndex,
340                                                          new AnimateByInteger(relativeValue.Get<int>()),
341                                                          alpha,
342                                                          period ) );
343       break;
344     }
345
346     case Property::VECTOR2:
347     {
348       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
349                                                              target.propertyIndex,
350                                                              target.componentIndex,
351                                                              new AnimateByVector2(relativeValue.Get<Vector2>()),
352                                                              alpha,
353                                                              period ) );
354       break;
355     }
356
357     case Property::VECTOR3:
358     {
359       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
360                                                              target.propertyIndex,
361                                                              target.componentIndex,
362                                                              new AnimateByVector3(relativeValue.Get<Vector3>()),
363                                                              alpha,
364                                                              period ) );
365       break;
366     }
367
368     case Property::VECTOR4:
369     {
370       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
371                                                              target.propertyIndex,
372                                                              target.componentIndex,
373                                                              new AnimateByVector4(relativeValue.Get<Vector4>()),
374                                                              alpha,
375                                                              period ) );
376       break;
377     }
378
379     case Property::ROTATION:
380     {
381       AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
382
383       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
384                                                                 target.propertyIndex,
385                                                                 target.componentIndex,
386                                                                 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
387                                                                 alpha,
388                                                                 period ) );
389       break;
390     }
391
392     default:
393       DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
394       break;
395   }
396 }
397
398 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
399 {
400   AnimateTo(target, destinationValue, AlphaFunctions::Default, mDurationSeconds);
401 }
402
403 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
404 {
405   AnimateTo(target, destinationValue, alpha, mDurationSeconds);
406 }
407
408 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
409 {
410   AnimateTo(target, destinationValue, AlphaFunctions::Default, period);
411 }
412
413 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
414 {
415   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
416
417   AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
418 }
419
420 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
421 {
422   Property::Type type = targetObject.GetPropertyType(targetPropertyIndex);
423   if(componentIndex != Property::INVALID_COMPONENT_INDEX)
424   {
425     if( type == Property::VECTOR2
426         || type == Property::VECTOR3
427         || type == Property::VECTOR4 )
428     {
429       type = Property::FLOAT;
430     }
431   }
432   DALI_ASSERT_ALWAYS( type == destinationValue.GetType() && "DestinationValue does not match Target Property type" );
433
434   ExtendDuration( period );
435
436   switch (destinationValue.GetType())
437   {
438     case Property::BOOLEAN:
439     {
440       AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
441                                                           targetPropertyIndex,
442                                                           componentIndex,
443                                                           new AnimateToBoolean( destinationValue.Get<bool>() ),
444                                                           alpha,
445                                                           period ) );
446       break;
447     }
448
449     case Property::FLOAT:
450     {
451       AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
452                                                            targetPropertyIndex,
453                                                            componentIndex,
454                                                            new AnimateToFloat( destinationValue.Get<float>() ),
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::VECTOR2:
472     {
473       AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
474                                                              targetPropertyIndex,
475                                                              componentIndex,
476                                                              new AnimateToVector2( destinationValue.Get<Vector2>() ),
477                                                              alpha,
478                                                              period ) );
479       break;
480     }
481
482     case Property::VECTOR3:
483     {
484       if ( Dali::Actor::Property::SIZE == targetPropertyIndex )
485       {
486         // Test whether this is actually an Actor
487         Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
488         if ( maybeActor )
489         {
490           // Notify the actor that its size is being animated
491           maybeActor->NotifySizeAnimation( *this, destinationValue.Get<Vector3>() );
492         }
493       }
494
495       AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
496                                                              targetPropertyIndex,
497                                                              componentIndex,
498                                                              new AnimateToVector3( destinationValue.Get<Vector3>() ),
499                                                              alpha,
500                                                              period ) );
501       break;
502     }
503
504     case Property::VECTOR4:
505     {
506       AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
507                                                              targetPropertyIndex,
508                                                              componentIndex,
509                                                              new AnimateToVector4( destinationValue.Get<Vector4>() ),
510                                                              alpha,
511                                                              period ) );
512       break;
513     }
514
515     case Property::ROTATION:
516     {
517       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
518                                                                 targetPropertyIndex,
519                                                                 componentIndex,
520                                                                 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
521                                                                 alpha,
522                                                                 period ) );
523       break;
524     }
525
526     default:
527       DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
528       break;
529   }
530 }
531
532 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
533 {
534   AnimateBetween(target, keyFrames, mDefaultAlpha, mDurationSeconds, DEFAULT_INTERPOLATION );
535 }
536
537 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
538 {
539   AnimateBetween(target, keyFrames, mDefaultAlpha, mDurationSeconds, interpolation );
540 }
541
542 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
543 {
544   AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
545 }
546
547 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
548 {
549   AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
550 }
551
552 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
553 {
554   AnimateBetween(target, keyFrames, alpha, mDurationSeconds, DEFAULT_INTERPOLATION);
555 }
556
557 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
558 {
559   AnimateBetween(target, keyFrames, alpha, mDurationSeconds, interpolation);
560 }
561
562 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
563 {
564   AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
565 }
566
567 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
568 {
569   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
570
571   ExtendDuration( period );
572
573   switch(keyFrames.GetType())
574   {
575     case Dali::Property::BOOLEAN:
576     {
577       const KeyFrameBoolean* kf;
578       GetSpecialization(keyFrames, kf);
579       KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
580       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
581                                                           target.propertyIndex,
582                                                           target.componentIndex,
583                                                           new KeyFrameBooleanFunctor(kfCopy),
584                                                           alpha,
585                                                           period ) );
586       break;
587     }
588
589     case Dali::Property::FLOAT:
590     {
591       const KeyFrameNumber* kf;
592       GetSpecialization(keyFrames, kf);
593       KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
594       AddAnimatorConnector( AnimatorConnector<float>::New( object,
595                                                            target.propertyIndex,
596                                                            target.componentIndex,
597                                                            new KeyFrameNumberFunctor(kfCopy,interpolation),
598                                                            alpha,
599                                                            period ) );
600       break;
601     }
602
603     case Dali::Property::INTEGER:
604     {
605       const KeyFrameInteger* kf;
606       GetSpecialization(keyFrames, kf);
607       KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
608       AddAnimatorConnector( AnimatorConnector<int>::New( object,
609                                                          target.propertyIndex,
610                                                          target.componentIndex,
611                                                          new KeyFrameIntegerFunctor(kfCopy,interpolation),
612                                                          alpha,
613                                                          period ) );
614       break;
615     }
616
617     case Dali::Property::VECTOR2:
618     {
619       const KeyFrameVector2* kf;
620       GetSpecialization(keyFrames, kf);
621       KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
622       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
623                                                              target.propertyIndex,
624                                                              target.componentIndex,
625                                                              new KeyFrameVector2Functor(kfCopy,interpolation),
626                                                              alpha,
627                                                              period ) );
628       break;
629     }
630
631     case Dali::Property::VECTOR3:
632     {
633       const KeyFrameVector3* kf;
634       GetSpecialization(keyFrames, kf);
635       KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
636       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
637                                                              target.propertyIndex,
638                                                              target.componentIndex,
639                                                              new KeyFrameVector3Functor(kfCopy,interpolation),
640                                                              alpha,
641                                                              period ) );
642       break;
643     }
644
645     case Dali::Property::VECTOR4:
646     {
647       const KeyFrameVector4* kf;
648       GetSpecialization(keyFrames, kf);
649       KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
650       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
651                                                              target.propertyIndex,
652                                                              target.componentIndex,
653                                                              new KeyFrameVector4Functor(kfCopy,interpolation),
654                                                              alpha,
655                                                              period ) );
656       break;
657     }
658
659     case Dali::Property::ROTATION:
660     {
661       const KeyFrameQuaternion* kf;
662       GetSpecialization(keyFrames, kf);
663       KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
664       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
665                                                                 target.propertyIndex,
666                                                                 target.componentIndex,
667                                                                 new KeyFrameQuaternionFunctor(kfCopy),
668                                                                 alpha,
669                                                                 period ) );
670       break;
671     }
672
673     default: // not all property types are animateable
674       break;
675   }
676 }
677
678 bool Animation::HasFinished()
679 {
680   bool hasFinished(false);
681   const int playCount(mAnimation->GetPlayCount());
682
683   // If the play count has been incremented, then another notification is required
684   if (playCount > mNotificationCount)
685   {
686     // Note that only one signal is emitted, if the animation has been played repeatedly
687     mNotificationCount = playCount;
688
689     hasFinished = true;
690   }
691
692   return hasFinished;
693 }
694
695 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
696 {
697   return mFinishedSignal;
698 }
699
700 void Animation::EmitSignalFinish()
701 {
702   if ( !mFinishedSignal.Empty() )
703   {
704     Dali::Animation handle( this );
705     mFinishedSignal.Emit( handle );
706   }
707
708   // This callback is used internally, to avoid the overhead of using a signal.
709   if ( mFinishedCallback )
710   {
711     mFinishedCallback( mFinishedCallbackObject );
712   }
713 }
714
715 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
716 {
717   bool connected( true );
718   Animation* animation = dynamic_cast<Animation*>(object);
719
720   if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
721   {
722     animation->FinishedSignal().Connect( tracker, functor );
723   }
724   else
725   {
726     // signalName does not match any signal
727     connected = false;
728   }
729
730   return connected;
731 }
732
733 void Animation::SetFinishedCallback( FinishedCallback callback, Object* object )
734 {
735   mFinishedCallback = callback;
736   mFinishedCallbackObject = object;
737 }
738
739 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
740 {
741   DALI_ASSERT_DEBUG( NULL != connector );
742
743   connector->SetParent(*this);
744
745   mConnectors.PushBack( connector );
746 }
747
748 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
749 {
750   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(0.0f,GetDuration()) );
751 }
752
753 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
754 {
755   Animate( actor, path, forward, alpha, TimePeriod(0.0f,GetDuration()) );
756 }
757
758 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
759 {
760   Animate( actor, path, forward, mDefaultAlpha, period );
761 }
762
763 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
764 {
765   ExtendDuration( period );
766
767   PathPtr pathCopy = Path::Clone(path);
768
769   //Position animation
770   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
771                                                          Dali::Actor::Property::POSITION,
772                                                          Property::INVALID_COMPONENT_INDEX,
773                                                          new PathPositionFunctor( pathCopy ),
774                                                          alpha,
775                                                          period ) );
776
777   //If forward is zero, PathRotationFunctor will always return the unit quaternion
778   if( forward != Vector3::ZERO )
779   {
780     //Rotation animation
781     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
782                                                               Dali::Actor::Property::ORIENTATION,
783                                                               Property::INVALID_COMPONENT_INDEX,
784                                                               new PathRotationFunctor( pathCopy, forward ),
785                                                               alpha,
786                                                               period ) );
787   }
788 }
789
790 void Animation::Show(Actor& actor, float delaySeconds)
791 {
792   ExtendDuration( TimePeriod(delaySeconds, 0) );
793
794   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
795                                                       Dali::Actor::Property::VISIBLE,
796                                                       Property::INVALID_COMPONENT_INDEX,
797                                                       new AnimateToBoolean(SHOW_VALUE),
798                                                       AlphaFunctions::Default,
799                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
800 }
801
802 void Animation::Hide(Actor& actor, float delaySeconds)
803 {
804   ExtendDuration( TimePeriod(delaySeconds, 0) );
805
806   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
807                                                       Dali::Actor::Property::VISIBLE,
808                                                       Property::INVALID_COMPONENT_INDEX,
809                                                       new AnimateToBoolean(HIDE_VALUE),
810                                                       AlphaFunctions::Default,
811                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
812 }
813
814 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes )
815 {
816   bool done = false;
817   Animation* animation = dynamic_cast<Animation*>( object );
818
819   if( animation )
820   {
821     if( 0 == strcmp( actionName.c_str(), ACTION_PLAY ) )
822     {
823       if( attributes.size() > 0 )
824       {
825         animation->SetDuration( attributes[0].Get<float>() );
826       }
827
828       animation->Play();
829       done = true;
830     }
831     else if( 0 == strcmp( actionName.c_str(), ACTION_STOP ) )
832     {
833       animation->Stop();
834       done = true;
835     }
836     else if( 0 == strcmp( actionName.c_str(), ACTION_PAUSE ) )
837     {
838       animation->Pause();
839       done = true;
840     }
841   }
842
843   return done;
844 }
845
846 void Animation::SetCurrentProgress(float progress)
847 {
848   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
849   {
850     // mAnimation is being used in a separate thread; queue a message to set the current progress
851     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
852   }
853 }
854
855 float Animation::GetCurrentProgress()
856 {
857   if( mAnimation )
858   {
859     return mAnimation->GetCurrentProgress();
860   }
861
862   return 0.0f;
863 }
864
865 void Animation::ExtendDuration( const TimePeriod& timePeriod )
866 {
867   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
868
869   if( duration > mDurationSeconds )
870   {
871     SetDuration( duration );
872   }
873 }
874
875 void Animation::SetSpeedFactor( float factor )
876 {
877   if( mAnimation )
878   {
879     mSpeedFactor = factor;
880     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
881   }
882 }
883
884 float Animation::GetSpeedFactor() const
885 {
886   return mSpeedFactor;
887 }
888
889 void Animation::SetPlayRange( const Vector2& range)
890 {
891   //Make sure the range specified is between 0.0 and 1.0
892   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
893   {
894     Vector2 orderedRange( range );
895     //If the range is not in order swap values
896     if( range.x > range.y )
897     {
898       orderedRange = Vector2(range.y, range.x);
899     }
900
901     // Cache for public getters
902     mPlayRange = orderedRange;
903
904     // mAnimation is being used in a separate thread; queue a message to set play range
905     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
906   }
907 }
908
909 Vector2 Animation::GetPlayRange() const
910 {
911   return mPlayRange;
912 }
913
914
915 } // namespace Internal
916
917 } // namespace Dali