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