Merge "Add KeyEventGeneratedSignal for Get KeyEvent normally" 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::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( Notify::USE_TARGET_VALUE );
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( Notify::USE_TARGET_VALUE );
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( Notify::USE_TARGET_VALUE );
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   // Notify the objects with the _paused_, i.e. current values
376   NotifyObjects( Notify::FORCE_CURRENT_VALUE );
377 }
378
379 Dali::Animation::State Animation::GetState() const
380 {
381   return mState;
382 }
383
384 void Animation::Stop()
385 {
386   mState = Dali::Animation::STOPPED;
387
388   // mAnimation is being used in a separate thread; queue a Stop message
389   StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
390
391   // Only notify the objects with the _stopped_, i.e. current values if the end action is set to BAKE
392   if( mEndAction == EndAction::Bake )
393   {
394     NotifyObjects( Notify::USE_CURRENT_VALUE );
395   }
396 }
397
398 void Animation::Clear()
399 {
400   DALI_ASSERT_DEBUG(mAnimation);
401
402   // Only notify the objects with the current values if the end action is set to BAKE
403   if( mEndAction == EndAction::Bake )
404   {
405     NotifyObjects( Notify::USE_CURRENT_VALUE );
406   }
407
408   // Remove all the connectors
409   mConnectors.Clear();
410
411   // Reset the connector target values
412   mConnectorTargetValues.clear();
413
414   // Replace the old scene-object with a new one
415   DestroySceneObject();
416   CreateSceneObject();
417
418   // Reset the notification count, since the new scene-object has never been played
419   mNotificationCount = 0;
420
421   // Update the current playlist
422   mPlaylist.OnClear( *this );
423 }
424
425 void Animation::AnimateBy( Property& target, Property::Value& relativeValue )
426 {
427   AnimateBy( target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds) );
428 }
429
430 void Animation::AnimateBy( Property& target, Property::Value& relativeValue, AlphaFunction alpha )
431 {
432   AnimateBy( target, relativeValue, alpha, TimePeriod(mDurationSeconds) );
433 }
434
435 void Animation::AnimateBy( Property& target, Property::Value& relativeValue, TimePeriod period )
436 {
437   AnimateBy( target, relativeValue, mDefaultAlpha, period );
438 }
439
440 void Animation::AnimateBy( Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period )
441 {
442   Object& object = GetImplementation(target.object);
443   const Property::Type propertyType = object.GetPropertyType( target.propertyIndex );
444   const Property::Type destinationType = relativeValue.GetType();
445
446   // validate animation parameters, if component index is set then use float as checked type
447   ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT,
448                       destinationType, period );
449
450   ExtendDuration(period);
451
452   // Store data to later notify the object that its property is being animated
453   ConnectorTargetValues connectorPair;
454   connectorPair.targetValue = relativeValue;
455   connectorPair.connectorIndex = mConnectors.Count();
456   connectorPair.timePeriod = period;
457   connectorPair.animatorType = Animation::BY;
458   mConnectorTargetValues.push_back( connectorPair );
459
460   // using destination type so component animation gets correct type
461   switch ( destinationType )
462   {
463     case Property::BOOLEAN:
464     {
465       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
466                                                           target.propertyIndex,
467                                                           target.componentIndex,
468                                                           new AnimateByBoolean(relativeValue.Get<bool>()),
469                                                           alpha,
470                                                           period ) );
471       break;
472     }
473
474     case Property::INTEGER:
475     {
476       AddAnimatorConnector( AnimatorConnector<int32_t>::New( object,
477                                                              target.propertyIndex,
478                                                              target.componentIndex,
479                                                              new AnimateByInteger(relativeValue.Get<int32_t>()),
480                                                              alpha,
481                                                              period ) );
482       break;
483     }
484
485     case Property::FLOAT:
486     {
487       AddAnimatorConnector( AnimatorConnector<float>::New( object,
488                                                            target.propertyIndex,
489                                                            target.componentIndex,
490                                                            new AnimateByFloat(relativeValue.Get<float>()),
491                                                            alpha,
492                                                            period ) );
493       break;
494     }
495
496     case Property::VECTOR2:
497     {
498       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
499                                                              target.propertyIndex,
500                                                              target.componentIndex,
501                                                              new AnimateByVector2(relativeValue.Get<Vector2>()),
502                                                              alpha,
503                                                              period ) );
504       break;
505     }
506
507     case Property::VECTOR3:
508     {
509       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
510                                                              target.propertyIndex,
511                                                              target.componentIndex,
512                                                              new AnimateByVector3(relativeValue.Get<Vector3>()),
513                                                              alpha,
514                                                              period ) );
515       break;
516     }
517
518     case Property::VECTOR4:
519     {
520       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
521                                                              target.propertyIndex,
522                                                              target.componentIndex,
523                                                              new AnimateByVector4(relativeValue.Get<Vector4>()),
524                                                              alpha,
525                                                              period ) );
526       break;
527     }
528
529     case Property::ROTATION:
530     {
531       AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
532
533       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
534                                                                 target.propertyIndex,
535                                                                 target.componentIndex,
536                                                                 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
537                                                                 alpha,
538                                                                 period ) );
539       break;
540     }
541
542     default:
543     {
544       // non animatable types handled already
545     }
546   }
547 }
548
549 void Animation::AnimateTo( Property& target, Property::Value& destinationValue )
550 {
551   AnimateTo( target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds) );
552 }
553
554 void Animation::AnimateTo( Property& target, Property::Value& destinationValue, AlphaFunction alpha )
555 {
556   AnimateTo( target, destinationValue, alpha, TimePeriod(mDurationSeconds));
557 }
558
559 void Animation::AnimateTo( Property& target, Property::Value& destinationValue, TimePeriod period )
560 {
561   AnimateTo( target, destinationValue, mDefaultAlpha, period );
562 }
563
564 void Animation::AnimateTo( Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period )
565 {
566   Object& object = GetImplementation( target.object );
567   const Property::Type propertyType = object.GetPropertyType( target.propertyIndex );
568   const Property::Type destinationType = destinationValue.GetType();
569
570   // validate animation parameters, if component index is set then use float as checked type
571   ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT,
572                       destinationType, period );
573
574   ExtendDuration( period );
575
576   // Store data to later notify the object that its property is being animated
577   ConnectorTargetValues connectorPair;
578   connectorPair.targetValue = destinationValue;
579   connectorPair.connectorIndex = mConnectors.Count();
580   connectorPair.timePeriod = period;
581   connectorPair.animatorType = Animation::TO;
582   mConnectorTargetValues.push_back( connectorPair );
583
584   // using destination type so component animation gets correct type
585   switch ( destinationType )
586   {
587     case Property::BOOLEAN:
588     {
589       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
590                                                           target.propertyIndex,
591                                                           target.componentIndex,
592                                                           new AnimateToBoolean( destinationValue.Get<bool>() ),
593                                                           alpha,
594                                                           period ) );
595       break;
596     }
597
598     case Property::INTEGER:
599     {
600       AddAnimatorConnector( AnimatorConnector<int32_t>::New( object,
601                                                              target.propertyIndex,
602                                                              target.componentIndex,
603                                                              new AnimateToInteger( destinationValue.Get<int32_t>() ),
604                                                              alpha,
605                                                              period ) );
606       break;
607     }
608
609     case Property::FLOAT:
610     {
611       AddAnimatorConnector( AnimatorConnector<float>::New( object,
612                                                            target.propertyIndex,
613                                                            target.componentIndex,
614                                                            new AnimateToFloat( destinationValue.Get<float>() ),
615                                                            alpha,
616                                                            period ) );
617       break;
618     }
619
620     case Property::VECTOR2:
621     {
622       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
623                                                              target.propertyIndex,
624                                                              target.componentIndex,
625                                                              new AnimateToVector2( destinationValue.Get<Vector2>() ),
626                                                              alpha,
627                                                              period ) );
628       break;
629     }
630
631     case Property::VECTOR3:
632     {
633       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
634                                                              target.propertyIndex,
635                                                              target.componentIndex,
636                                                              new AnimateToVector3( destinationValue.Get<Vector3>() ),
637                                                              alpha,
638                                                              period ) );
639       break;
640     }
641
642     case Property::VECTOR4:
643     {
644       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
645                                                              target.propertyIndex,
646                                                              target.componentIndex,
647                                                              new AnimateToVector4( destinationValue.Get<Vector4>() ),
648                                                              alpha,
649                                                              period ) );
650       break;
651     }
652
653     case Property::ROTATION:
654     {
655       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
656                                                                 target.propertyIndex,
657                                                                 target.componentIndex,
658                                                                 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
659                                                                 alpha,
660                                                                 period ) );
661       break;
662     }
663
664     default:
665     {
666       // non animatable types handled already
667     }
668   }
669 }
670
671 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames )
672 {
673   AnimateBetween( target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
674 }
675
676 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, Interpolation interpolation )
677 {
678   AnimateBetween( target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
679 }
680
681 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, TimePeriod period )
682 {
683   AnimateBetween( target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION );
684 }
685
686 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation )
687 {
688   AnimateBetween( target, keyFrames, mDefaultAlpha, period, interpolation );
689 }
690
691 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha )
692 {
693   AnimateBetween( target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
694 }
695
696 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation )
697 {
698   AnimateBetween( target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation );
699 }
700
701 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period )
702 {
703   AnimateBetween( target, keyFrames, alpha, period, DEFAULT_INTERPOLATION );
704 }
705
706 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation )
707 {
708   Object& object = GetImplementation( target.object );
709   const Property::Type propertyType = object.GetPropertyType( target.propertyIndex );
710   const Property::Type destinationType = keyFrames.GetType();
711
712   // validate animation parameters, if component index is set then use float as checked type
713   ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT,
714                       destinationType, period );
715
716   ExtendDuration( period );
717
718   // Store data to later notify the object that its property is being animated
719   ConnectorTargetValues connectorPair;
720   connectorPair.targetValue = keyFrames.GetLastKeyFrameValue();
721   connectorPair.connectorIndex = mConnectors.Count();
722   connectorPair.timePeriod = period;
723   connectorPair.animatorType = BETWEEN;
724   mConnectorTargetValues.push_back( connectorPair );
725
726   // using destination type so component animation gets correct type
727   switch( destinationType )
728   {
729     case Dali::Property::BOOLEAN:
730     {
731       const KeyFrameBoolean* kf;
732       GetSpecialization(keyFrames, kf);
733       KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
734       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
735                                                           target.propertyIndex,
736                                                           target.componentIndex,
737                                                           new KeyFrameBooleanFunctor(kfCopy),
738                                                           alpha,
739                                                           period ) );
740       break;
741     }
742
743     case Dali::Property::INTEGER:
744     {
745       const KeyFrameInteger* kf;
746       GetSpecialization(keyFrames, kf);
747       KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
748       AddAnimatorConnector( AnimatorConnector<int32_t>::New( object,
749                                                          target.propertyIndex,
750                                                          target.componentIndex,
751                                                          new KeyFrameIntegerFunctor(kfCopy,interpolation),
752                                                          alpha,
753                                                          period ) );
754       break;
755     }
756
757     case Dali::Property::FLOAT:
758     {
759       const KeyFrameNumber* kf;
760       GetSpecialization(keyFrames, kf);
761       KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
762       AddAnimatorConnector( AnimatorConnector<float>::New( object,
763                                                            target.propertyIndex,
764                                                            target.componentIndex,
765                                                            new KeyFrameNumberFunctor(kfCopy,interpolation),
766                                                            alpha,
767                                                            period ) );
768       break;
769     }
770
771     case Dali::Property::VECTOR2:
772     {
773       const KeyFrameVector2* kf;
774       GetSpecialization(keyFrames, kf);
775       KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
776       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
777                                                              target.propertyIndex,
778                                                              target.componentIndex,
779                                                              new KeyFrameVector2Functor(kfCopy,interpolation),
780                                                              alpha,
781                                                              period ) );
782       break;
783     }
784
785     case Dali::Property::VECTOR3:
786     {
787       const KeyFrameVector3* kf;
788       GetSpecialization(keyFrames, kf);
789       KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
790       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
791                                                              target.propertyIndex,
792                                                              target.componentIndex,
793                                                              new KeyFrameVector3Functor(kfCopy,interpolation),
794                                                              alpha,
795                                                              period ) );
796       break;
797     }
798
799     case Dali::Property::VECTOR4:
800     {
801       const KeyFrameVector4* kf;
802       GetSpecialization(keyFrames, kf);
803       KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
804       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
805                                                              target.propertyIndex,
806                                                              target.componentIndex,
807                                                              new KeyFrameVector4Functor(kfCopy,interpolation),
808                                                              alpha,
809                                                              period ) );
810       break;
811     }
812
813     case Dali::Property::ROTATION:
814     {
815       const KeyFrameQuaternion* kf;
816       GetSpecialization(keyFrames, kf);
817       KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
818       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
819                                                                 target.propertyIndex,
820                                                                 target.componentIndex,
821                                                                 new KeyFrameQuaternionFunctor(kfCopy),
822                                                                 alpha,
823                                                                 period ) );
824       break;
825     }
826
827     default:
828     {
829       // non animatable types handled by keyframes
830     }
831   }
832 }
833
834 bool Animation::HasFinished()
835 {
836   bool hasFinished(false);
837   const int32_t playedCount(mAnimation->GetPlayedCount());
838
839   // If the play count has been incremented, then another notification is required
840   mCurrentLoop = mAnimation->GetCurrentLoop();
841
842   if (playedCount > mNotificationCount)
843   {
844     // Note that only one signal is emitted, if the animation has been played repeatedly
845     mNotificationCount = playedCount;
846
847     hasFinished = true;
848
849     mState = Dali::Animation::STOPPED;
850   }
851
852   return hasFinished;
853 }
854
855 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
856 {
857   return mFinishedSignal;
858 }
859
860 Dali::Animation::AnimationSignalType& Animation::ProgressReachedSignal()
861 {
862   return mProgressReachedSignal;
863 }
864
865 void Animation::EmitSignalFinish()
866 {
867   if ( !mFinishedSignal.Empty() )
868   {
869     Dali::Animation handle( this );
870     mFinishedSignal.Emit( handle );
871   }
872 }
873
874 void Animation::EmitSignalProgressReached()
875 {
876   if ( !mProgressReachedSignal.Empty() )
877   {
878     Dali::Animation handle( this );
879     mProgressReachedSignal.Emit( handle );
880   }
881 }
882
883 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
884 {
885   bool connected( false );
886   Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
887
888   if( 0 == signalName.compare( SIGNAL_FINISHED ) )
889   {
890     animation->FinishedSignal().Connect( tracker, functor );
891     connected = true;
892   }
893
894   return connected;
895 }
896
897 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
898 {
899   DALI_ASSERT_DEBUG( NULL != connector );
900
901   connector->SetParent(*this);
902
903   mConnectors.PushBack( connector );
904 }
905
906 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
907 {
908   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
909 }
910
911 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
912 {
913   Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
914 }
915
916 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
917 {
918   Animate( actor, path, forward, mDefaultAlpha, period );
919 }
920
921 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
922 {
923   ExtendDuration( period );
924
925   PathPtr pathCopy = Path::Clone(path);
926
927   //Position animation
928   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
929                                                          Dali::Actor::Property::POSITION,
930                                                          Property::INVALID_COMPONENT_INDEX,
931                                                          new PathPositionFunctor( pathCopy ),
932                                                          alpha,
933                                                          period ) );
934
935   //If forward is zero, PathRotationFunctor will always return the unit quaternion
936   if( forward != Vector3::ZERO )
937   {
938     //Rotation animation
939     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
940                                                               Dali::Actor::Property::ORIENTATION,
941                                                               Property::INVALID_COMPONENT_INDEX,
942                                                               new PathRotationFunctor( pathCopy, forward ),
943                                                               alpha,
944                                                               period ) );
945   }
946 }
947
948 void Animation::Show(Actor& actor, float delaySeconds)
949 {
950   ExtendDuration( TimePeriod(delaySeconds, 0) );
951
952   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
953                                                       Dali::Actor::Property::VISIBLE,
954                                                       Property::INVALID_COMPONENT_INDEX,
955                                                       new AnimateToBoolean(SHOW_VALUE),
956                                                       mDefaultAlpha,
957                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
958 }
959
960 void Animation::Hide(Actor& actor, float delaySeconds)
961 {
962   ExtendDuration( TimePeriod(delaySeconds, 0) );
963
964   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
965                                                       Dali::Actor::Property::VISIBLE,
966                                                       Property::INVALID_COMPONENT_INDEX,
967                                                       new AnimateToBoolean(HIDE_VALUE),
968                                                       mDefaultAlpha,
969                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
970 }
971
972 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
973 {
974   bool done = false;
975   Animation* animation = dynamic_cast<Animation*>( object );
976
977   if( animation )
978   {
979     if( 0 == actionName.compare( ACTION_PLAY ) )
980     {
981       if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
982       {
983         animation->SetDuration( value->Get<float>() );
984       }
985
986       animation->Play();
987       done = true;
988     }
989     else if( 0 == actionName.compare( ACTION_STOP ) )
990     {
991       animation->Stop();
992       done = true;
993     }
994     else if( 0 == actionName.compare( ACTION_PAUSE ) )
995     {
996       animation->Pause();
997       done = true;
998     }
999   }
1000
1001   return done;
1002 }
1003
1004 void Animation::SetCurrentProgress(float progress)
1005 {
1006   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
1007   {
1008     // mAnimation is being used in a separate thread; queue a message to set the current progress
1009     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
1010   }
1011 }
1012
1013 float Animation::GetCurrentProgress()
1014 {
1015   float progress = 0.f;
1016   if( mAnimation ) // always exists in practice
1017   {
1018     progress = mAnimation->GetCurrentProgress();
1019   }
1020
1021   return progress;
1022 }
1023
1024 void Animation::ExtendDuration( const TimePeriod& timePeriod )
1025 {
1026   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
1027
1028   if( duration > mDurationSeconds )
1029   {
1030     SetDuration( duration );
1031   }
1032 }
1033
1034 void Animation::SetSpeedFactor( float factor )
1035 {
1036   if( mAnimation )
1037   {
1038     mSpeedFactor = factor;
1039     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
1040   }
1041 }
1042
1043 float Animation::GetSpeedFactor() const
1044 {
1045   return mSpeedFactor;
1046 }
1047
1048 void Animation::SetPlayRange( const Vector2& range)
1049 {
1050   //Make sure the range specified is between 0.0 and 1.0
1051   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
1052   {
1053     Vector2 orderedRange( range );
1054     //If the range is not in order swap values
1055     if( range.x > range.y )
1056     {
1057       orderedRange = Vector2(range.y, range.x);
1058     }
1059
1060     // Cache for public getters
1061     mPlayRange = orderedRange;
1062
1063     // mAnimation is being used in a separate thread; queue a message to set play range
1064     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
1065   }
1066 }
1067
1068 Vector2 Animation::GetPlayRange() const
1069 {
1070   return mPlayRange;
1071 }
1072
1073 void Animation::SetLoopingMode( Dali::Animation::LoopingMode loopingMode )
1074 {
1075   mAutoReverseEnabled = ( loopingMode == Dali::Animation::LoopingMode::AUTO_REVERSE );
1076
1077   // mAnimation is being used in a separate thread; queue a message to set play range
1078   SetLoopingModeMessage( mEventThreadServices, *mAnimation, mAutoReverseEnabled );
1079 }
1080
1081 Dali::Animation::LoopingMode Animation::GetLoopingMode() const
1082 {
1083   return mAutoReverseEnabled ? Dali::Animation::AUTO_REVERSE : Dali::Animation::RESTART;
1084 }
1085
1086 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
1087 {
1088   return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
1089 }
1090
1091 void Animation::NotifyObjects( Animation::Notify notifyValueType )
1092 {
1093   // If the animation is discarded, then we do not want to change the target values unless we want to force the current values
1094   if( mEndAction != EndAction::Discard || notifyValueType == Notify::FORCE_CURRENT_VALUE )
1095   {
1096     // Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
1097     // Only do this if we're using the target value
1098     if( notifyValueType == Notify::USE_TARGET_VALUE )
1099     {
1100       std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
1101     }
1102
1103     // Loop through all connector target values sorted by increasing end time
1104     ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
1105     const ConnectorTargetValuesContainer::const_iterator endIter = mConnectorTargetValues.end();
1106     for( ; iter != endIter; ++iter )
1107     {
1108       AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ];
1109
1110       Object* object = connector->GetObject();
1111       if( object )
1112       {
1113         const auto propertyIndex = connector->GetPropertyIndex();
1114         object->NotifyPropertyAnimation(
1115           *this,
1116           propertyIndex,
1117           ( notifyValueType == Notify::USE_TARGET_VALUE ) ? iter->targetValue : object->GetCurrentProperty( propertyIndex ),
1118           iter->animatorType );
1119       }
1120     }
1121   }
1122 }
1123
1124
1125 void Animation::SendFinalProgressNotificationMessage()
1126 {
1127   if ( mProgressReachedMarker > 0.0f )
1128   {
1129     float progressMarkerSeconds = mDurationSeconds * mProgressReachedMarker;
1130     SetProgressNotificationMessage( mEventThreadServices, *mAnimation, progressMarkerSeconds );
1131   }
1132 }
1133
1134 } // namespace Internal
1135
1136 } // namespace Dali