Merge "(Animation) Ensure AnimateBetween 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   // Store data to later notify the object that its property is being animated
653   ConnectorTargetValues connectorPair;
654   connectorPair.targetValue = keyFrames.GetLastKeyFrameValue();
655   connectorPair.connectorIndex = mConnectors.Count();
656   connectorPair.timePeriod = period;
657   connectorPair.animatorType = BETWEEN;
658   mConnectorTargetValues.push_back( connectorPair );
659
660   switch(keyFrames.GetType())
661   {
662     case Dali::Property::BOOLEAN:
663     {
664       const KeyFrameBoolean* kf;
665       GetSpecialization(keyFrames, kf);
666       KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
667       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
668                                                           target.propertyIndex,
669                                                           target.componentIndex,
670                                                           new KeyFrameBooleanFunctor(kfCopy),
671                                                           alpha,
672                                                           period ) );
673       break;
674     }
675
676     case Dali::Property::INTEGER:
677     {
678       const KeyFrameInteger* kf;
679       GetSpecialization(keyFrames, kf);
680       KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
681       AddAnimatorConnector( AnimatorConnector<int>::New( object,
682                                                          target.propertyIndex,
683                                                          target.componentIndex,
684                                                          new KeyFrameIntegerFunctor(kfCopy,interpolation),
685                                                          alpha,
686                                                          period ) );
687       break;
688     }
689
690     case Dali::Property::FLOAT:
691     {
692       const KeyFrameNumber* kf;
693       GetSpecialization(keyFrames, kf);
694       KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
695       AddAnimatorConnector( AnimatorConnector<float>::New( object,
696                                                            target.propertyIndex,
697                                                            target.componentIndex,
698                                                            new KeyFrameNumberFunctor(kfCopy,interpolation),
699                                                            alpha,
700                                                            period ) );
701       break;
702     }
703
704     case Dali::Property::VECTOR2:
705     {
706       const KeyFrameVector2* kf;
707       GetSpecialization(keyFrames, kf);
708       KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
709       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
710                                                              target.propertyIndex,
711                                                              target.componentIndex,
712                                                              new KeyFrameVector2Functor(kfCopy,interpolation),
713                                                              alpha,
714                                                              period ) );
715       break;
716     }
717
718     case Dali::Property::VECTOR3:
719     {
720       const KeyFrameVector3* kf;
721       GetSpecialization(keyFrames, kf);
722       KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
723       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
724                                                              target.propertyIndex,
725                                                              target.componentIndex,
726                                                              new KeyFrameVector3Functor(kfCopy,interpolation),
727                                                              alpha,
728                                                              period ) );
729       break;
730     }
731
732     case Dali::Property::VECTOR4:
733     {
734       const KeyFrameVector4* kf;
735       GetSpecialization(keyFrames, kf);
736       KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
737       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
738                                                              target.propertyIndex,
739                                                              target.componentIndex,
740                                                              new KeyFrameVector4Functor(kfCopy,interpolation),
741                                                              alpha,
742                                                              period ) );
743       break;
744     }
745
746     case Dali::Property::ROTATION:
747     {
748       const KeyFrameQuaternion* kf;
749       GetSpecialization(keyFrames, kf);
750       KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
751       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
752                                                                 target.propertyIndex,
753                                                                 target.componentIndex,
754                                                                 new KeyFrameQuaternionFunctor(kfCopy),
755                                                                 alpha,
756                                                                 period ) );
757       break;
758     }
759
760     default:
761     {
762       // non animatable types handled by keyframes
763     }
764   }
765 }
766
767 bool Animation::HasFinished()
768 {
769   bool hasFinished(false);
770   const int playedCount(mAnimation->GetPlayedCount());
771
772   // If the play count has been incremented, then another notification is required
773   mCurrentLoop = mAnimation->GetCurrentLoop();
774
775   if (playedCount > mNotificationCount)
776   {
777     // Note that only one signal is emitted, if the animation has been played repeatedly
778     mNotificationCount = playedCount;
779
780     hasFinished = true;
781
782     mState = Dali::Animation::STOPPED;
783   }
784
785   return hasFinished;
786 }
787
788 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
789 {
790   return mFinishedSignal;
791 }
792
793 void Animation::EmitSignalFinish()
794 {
795   if ( !mFinishedSignal.Empty() )
796   {
797     Dali::Animation handle( this );
798     mFinishedSignal.Emit( handle );
799   }
800 }
801
802 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
803 {
804   bool connected( true );
805   Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
806
807   if( 0 == signalName.compare( SIGNAL_FINISHED ) )
808   {
809     animation->FinishedSignal().Connect( tracker, functor );
810   }
811   else
812   {
813     // signalName does not match any signal
814     connected = false;
815   }
816
817   return connected;
818 }
819
820 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
821 {
822   DALI_ASSERT_DEBUG( NULL != connector );
823
824   connector->SetParent(*this);
825
826   mConnectors.PushBack( connector );
827 }
828
829 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
830 {
831   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
832 }
833
834 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
835 {
836   Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
837 }
838
839 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
840 {
841   Animate( actor, path, forward, mDefaultAlpha, period );
842 }
843
844 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
845 {
846   ExtendDuration( period );
847
848   PathPtr pathCopy = Path::Clone(path);
849
850   //Position animation
851   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
852                                                          Dali::Actor::Property::POSITION,
853                                                          Property::INVALID_COMPONENT_INDEX,
854                                                          new PathPositionFunctor( pathCopy ),
855                                                          alpha,
856                                                          period ) );
857
858   //If forward is zero, PathRotationFunctor will always return the unit quaternion
859   if( forward != Vector3::ZERO )
860   {
861     //Rotation animation
862     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
863                                                               Dali::Actor::Property::ORIENTATION,
864                                                               Property::INVALID_COMPONENT_INDEX,
865                                                               new PathRotationFunctor( pathCopy, forward ),
866                                                               alpha,
867                                                               period ) );
868   }
869 }
870
871 void Animation::Show(Actor& actor, float delaySeconds)
872 {
873   ExtendDuration( TimePeriod(delaySeconds, 0) );
874
875   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
876                                                       Dali::Actor::Property::VISIBLE,
877                                                       Property::INVALID_COMPONENT_INDEX,
878                                                       new AnimateToBoolean(SHOW_VALUE),
879                                                       mDefaultAlpha,
880                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
881 }
882
883 void Animation::Hide(Actor& actor, float delaySeconds)
884 {
885   ExtendDuration( TimePeriod(delaySeconds, 0) );
886
887   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
888                                                       Dali::Actor::Property::VISIBLE,
889                                                       Property::INVALID_COMPONENT_INDEX,
890                                                       new AnimateToBoolean(HIDE_VALUE),
891                                                       mDefaultAlpha,
892                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
893 }
894
895 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
896 {
897   bool done = false;
898   Animation* animation = dynamic_cast<Animation*>( object );
899
900   if( animation )
901   {
902     if( 0 == actionName.compare( ACTION_PLAY ) )
903     {
904       if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
905       {
906         animation->SetDuration( value->Get<float>() );
907       }
908
909       animation->Play();
910       done = true;
911     }
912     else if( 0 == actionName.compare( ACTION_STOP ) )
913     {
914       animation->Stop();
915       done = true;
916     }
917     else if( 0 == actionName.compare( ACTION_PAUSE ) )
918     {
919       animation->Pause();
920       done = true;
921     }
922   }
923
924   return done;
925 }
926
927 void Animation::SetCurrentProgress(float progress)
928 {
929   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
930   {
931     // mAnimation is being used in a separate thread; queue a message to set the current progress
932     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
933   }
934 }
935
936 float Animation::GetCurrentProgress()
937 {
938   if( mAnimation )
939   {
940     return mAnimation->GetCurrentProgress();
941   }
942
943   return 0.0f;
944 }
945
946 void Animation::ExtendDuration( const TimePeriod& timePeriod )
947 {
948   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
949
950   if( duration > mDurationSeconds )
951   {
952     SetDuration( duration );
953   }
954 }
955
956 void Animation::SetSpeedFactor( float factor )
957 {
958   if( mAnimation )
959   {
960     mSpeedFactor = factor;
961     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
962   }
963 }
964
965 float Animation::GetSpeedFactor() const
966 {
967   return mSpeedFactor;
968 }
969
970 void Animation::SetPlayRange( const Vector2& range)
971 {
972   //Make sure the range specified is between 0.0 and 1.0
973   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
974   {
975     Vector2 orderedRange( range );
976     //If the range is not in order swap values
977     if( range.x > range.y )
978     {
979       orderedRange = Vector2(range.y, range.x);
980     }
981
982     // Cache for public getters
983     mPlayRange = orderedRange;
984
985     // mAnimation is being used in a separate thread; queue a message to set play range
986     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
987   }
988 }
989
990 Vector2 Animation::GetPlayRange() const
991 {
992   return mPlayRange;
993 }
994
995 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
996 {
997   return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
998 }
999
1000 } // namespace Internal
1001
1002 } // namespace Dali