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