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