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