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