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