[Tizen] (Animation) Ensure AnimateBy updates the cached event-side properties
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / animation-impl.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/animation/animation-impl.h>
20 #include <dali/public-api/object/property-map.h>
21
22 // EXTERNAL INCLUDES
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/animation/alpha-function.h>
26 #include <dali/public-api/animation/time-period.h>
27 #include <dali/public-api/common/dali-common.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/public-api/math/vector2.h>
30 #include <dali/public-api/math/radian.h>
31 #include <dali/internal/event/animation/animation-playlist.h>
32 #include <dali/internal/event/animation/animator-connector.h>
33 #include <dali/internal/event/common/notification-manager.h>
34 #include <dali/internal/event/common/property-helper.h>
35 #include <dali/internal/event/common/stage-impl.h>
36 #include <dali/internal/event/common/thread-local-storage.h>
37 #include <dali/internal/update/animation/scene-graph-animator.h>
38 #include <dali/internal/update/manager/update-manager.h>
39
40 using Dali::Internal::SceneGraph::UpdateManager;
41 using Dali::Internal::SceneGraph::AnimatorBase;
42 using Dali::Internal::SceneGraph::Shader;
43
44 namespace Dali
45 {
46
47 namespace Internal
48 {
49
50 static bool SHOW_VALUE = true;
51 static bool HIDE_VALUE = false;
52
53 namespace
54 {
55
56 // Signals
57
58 const char* const SIGNAL_FINISHED = "finished";
59
60 // Actions
61
62 const char* const ACTION_PLAY =     "play";
63 const char* const ACTION_STOP =     "stop";
64 const char* const ACTION_PAUSE =    "pause";
65
66 BaseHandle Create()
67 {
68   return Dali::Animation::New(0.f);
69 }
70
71 TypeRegistration mType( typeid( Dali::Animation ), typeid( Dali::BaseHandle ), Create );
72
73 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &Animation::DoConnectSignal );
74
75 TypeAction action1( mType, ACTION_PLAY,  &Animation::DoAction );
76 TypeAction action2( mType, ACTION_STOP,  &Animation::DoAction );
77 TypeAction action3( mType, ACTION_PAUSE, &Animation::DoAction );
78
79 const Dali::Animation::EndAction DEFAULT_END_ACTION( Dali::Animation::Bake );
80 const Dali::Animation::EndAction DEFAULT_DISCONNECT_ACTION( Dali::Animation::BakeFinal );
81 const Dali::Animation::Interpolation DEFAULT_INTERPOLATION( Dali::Animation::Linear );
82 const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION( Dali::AlphaFunction::DEFAULT );
83
84 } // anon namespace
85
86
87 AnimationPtr Animation::New(float durationSeconds)
88 {
89   Stage* stage = Stage::GetCurrent();
90
91   if( stage )
92   {
93     AnimationPlaylist& playlist = stage->GetAnimationPlaylist();
94
95     if( durationSeconds < 0.0f )
96     {
97       DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
98       durationSeconds = 0.0f;
99     }
100
101     AnimationPtr animation = new Animation( *stage, playlist, durationSeconds, DEFAULT_END_ACTION, DEFAULT_DISCONNECT_ACTION, DEFAULT_ALPHA_FUNCTION );
102
103     // Second-phase construction
104     animation->Initialize();
105
106     return animation;
107   }
108   else
109   {
110     return NULL;
111   }
112 }
113
114 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
115 : mAnimation( NULL ),
116   mEventThreadServices( eventThreadServices ),
117   mPlaylist( playlist ),
118   mFinishedSignal(),
119   mConnectors(),
120   mConnectorTargetValues(),
121   mPlayRange( Vector2(0.0f,1.0f)),
122   mDurationSeconds( durationSeconds ),
123   mSpeedFactor(1.0f),
124   mNotificationCount( 0 ),
125   mLoopCount(1),
126   mCurrentLoop(0),
127   mEndAction( endAction ),
128   mDisconnectAction( disconnectAction ),
129   mDefaultAlpha( defaultAlpha ),
130   mState(Dali::Animation::STOPPED)
131 {
132 }
133
134 void Animation::Initialize()
135 {
136   // Connect to the animation playlist
137   mPlaylist.AnimationCreated( *this );
138
139   CreateSceneObject();
140
141   RegisterObject();
142 }
143
144 Animation::~Animation()
145 {
146   // Guard to allow handle destruction after Core has been destroyed
147   if ( Stage::IsInstalled() )
148   {
149     // Disconnect from the animation playlist
150     mPlaylist.AnimationDestroyed( *this );
151
152     DestroySceneObject();
153
154     UnregisterObject();
155   }
156 }
157
158 void Animation::CreateSceneObject()
159 {
160   DALI_ASSERT_DEBUG( mAnimation == NULL );
161
162   // Create a new animation, temporarily owned
163   SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction );
164
165   // Keep a const pointer to the animation.
166   mAnimation = animation;
167
168   // Transfer animation ownership to the update manager through a message
169   AddAnimationMessage( mEventThreadServices.GetUpdateManager(), animation );
170 }
171
172 void Animation::DestroySceneObject()
173 {
174   if ( mAnimation != NULL )
175   {
176     // Remove animation using a message to the update manager
177     RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
178     mAnimation = NULL;
179   }
180 }
181
182 void Animation::SetDuration(float seconds)
183 {
184   if( seconds < 0.0f )
185   {
186     DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
187     seconds = 0.0f;
188   }
189
190   // Cache for public getters
191   mDurationSeconds = seconds;
192
193   // mAnimation is being used in a separate thread; queue a message to set the value
194   SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
195 }
196
197 float Animation::GetDuration() const
198 {
199   // This is not animatable; the cached value is up-to-date.
200   return mDurationSeconds;
201 }
202
203 void Animation::SetLooping(bool on)
204 {
205   SetLoopCount( on ? 0 : 1 );
206 }
207
208 void Animation::SetLoopCount(int count)
209 {
210   // Cache for public getters
211   mLoopCount = count;
212
213   // mAnimation is being used in a separate thread; queue a message to set the value
214   SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount );
215 }
216
217 int Animation::GetLoopCount()
218 {
219   return mLoopCount;
220 }
221
222 int Animation::GetCurrentLoop()
223 {
224   return mCurrentLoop;
225 }
226
227 bool Animation::IsLooping() const
228 {
229   return mLoopCount != 1;
230 }
231
232 void Animation::SetEndAction(EndAction action)
233 {
234   // Cache for public getters
235   mEndAction = action;
236
237   // mAnimation is being used in a separate thread; queue a message to set the value
238   SetEndActionMessage( mEventThreadServices, *mAnimation, action );
239 }
240
241 Dali::Animation::EndAction Animation::GetEndAction() const
242 {
243   // This is not animatable; the cached value is up-to-date.
244   return mEndAction;
245 }
246
247 void Animation::SetDisconnectAction(EndAction action)
248 {
249   // Cache for public getters
250   mDisconnectAction = action;
251
252   // mAnimation is being used in a separate thread; queue a message to set the value
253   SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
254 }
255
256 Dali::Animation::EndAction Animation::GetDisconnectAction() const
257 {
258   // This is not animatable; the cached value is up-to-date.
259   return mDisconnectAction;
260 }
261
262 void Animation::Play()
263 {
264   // Update the current playlist
265   mPlaylist.OnPlay( *this );
266
267   mState = Dali::Animation::PLAYING;
268
269   if( mEndAction != EndAction::Discard ) // If the animation is discarded, then we do not want to change the target values
270   {
271     // Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
272     std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
273
274     // Loop through all connector target values sorted by increasing end time
275     ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
276     const ConnectorTargetValuesContainer::const_iterator endIter = mConnectorTargetValues.end();
277     for( ; iter != endIter; ++iter )
278     {
279       AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ];
280
281       Object* object = connector->GetObject();
282       if( object )
283       {
284         object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), iter->targetValue, iter->propertyChangeType );
285       }
286     }
287   }
288
289   // mAnimation is being used in a separate thread; queue a Play message
290   PlayAnimationMessage( mEventThreadServices, *mAnimation );
291 }
292
293 void Animation::PlayFrom( float progress )
294 {
295   if( progress >= mPlayRange.x && progress <= mPlayRange.y )
296   {
297     // Update the current playlist
298     mPlaylist.OnPlay( *this );
299
300     mState = Dali::Animation::PLAYING;
301
302     // mAnimation is being used in a separate thread; queue a Play message
303     PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
304   }
305 }
306
307 void Animation::Pause()
308 {
309   mState = Dali::Animation::PAUSED;
310
311   // mAnimation is being used in a separate thread; queue a Pause message
312   PauseAnimationMessage( mEventThreadServices, *mAnimation );
313 }
314
315 Dali::Animation::State Animation::GetState() const
316 {
317   return mState;
318 }
319
320 void Animation::Stop()
321 {
322   mState = Dali::Animation::STOPPED;
323
324   // mAnimation is being used in a separate thread; queue a Stop message
325   StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
326 }
327
328 void Animation::Clear()
329 {
330   DALI_ASSERT_DEBUG(mAnimation);
331
332   // Remove all the connectors
333   mConnectors.Clear();
334
335   // Reset the connector target values
336   mConnectorTargetValues.clear();
337
338   // Replace the old scene-object with a new one
339   DestroySceneObject();
340   CreateSceneObject();
341
342   // Reset the notification count, since the new scene-object has never been played
343   mNotificationCount = 0;
344
345   // Update the current playlist
346   mPlaylist.OnClear( *this );
347 }
348
349 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
350 {
351   AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
352 }
353
354 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
355 {
356   AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds));
357 }
358
359 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
360 {
361   AnimateBy(target, relativeValue, mDefaultAlpha, period);
362 }
363
364 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
365 {
366   Object& object = GetImplementation( target.object );
367   const Property::Type targetType = object.GetPropertyType( target.propertyIndex );
368   const Property::Type destinationType = relativeValue.GetType();
369   DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
370
371   ExtendDuration( period );
372
373   // Store data to later notify the object that its property is being animated
374   ConnectorTargetValues connectorPair;
375   connectorPair.targetValue = relativeValue;
376   connectorPair.connectorIndex = mConnectors.Count();
377   connectorPair.timePeriod = period;
378   connectorPair.propertyChangeType = Object::PropertyChange::ADJUST_VALUE_BY;
379   mConnectorTargetValues.push_back( connectorPair );
380
381   switch ( targetType )
382   {
383     case Property::BOOLEAN:
384     {
385       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
386                                                           target.propertyIndex,
387                                                           target.componentIndex,
388                                                           new AnimateByBoolean(relativeValue.Get<bool>()),
389                                                           alpha,
390                                                           period ) );
391       break;
392     }
393
394     case Property::INTEGER:
395     {
396       AddAnimatorConnector( AnimatorConnector<int>::New( object,
397                                                          target.propertyIndex,
398                                                          target.componentIndex,
399                                                          new AnimateByInteger(relativeValue.Get<int>()),
400                                                          alpha,
401                                                          period ) );
402       break;
403     }
404
405     case Property::FLOAT:
406     {
407       AddAnimatorConnector( AnimatorConnector<float>::New( object,
408                                                            target.propertyIndex,
409                                                            target.componentIndex,
410                                                            new AnimateByFloat(relativeValue.Get<float>()),
411                                                            alpha,
412                                                            period ) );
413       break;
414     }
415
416     case Property::VECTOR2:
417     {
418       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
419                                                              target.propertyIndex,
420                                                              target.componentIndex,
421                                                              new AnimateByVector2(relativeValue.Get<Vector2>()),
422                                                              alpha,
423                                                              period ) );
424       break;
425     }
426
427     case Property::VECTOR3:
428     {
429       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
430                                                              target.propertyIndex,
431                                                              target.componentIndex,
432                                                              new AnimateByVector3(relativeValue.Get<Vector3>()),
433                                                              alpha,
434                                                              period ) );
435       break;
436     }
437
438     case Property::VECTOR4:
439     {
440       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
441                                                              target.propertyIndex,
442                                                              target.componentIndex,
443                                                              new AnimateByVector4(relativeValue.Get<Vector4>()),
444                                                              alpha,
445                                                              period ) );
446       break;
447     }
448
449     case Property::ROTATION:
450     {
451       AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
452
453       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
454                                                                 target.propertyIndex,
455                                                                 target.componentIndex,
456                                                                 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
457                                                                 alpha,
458                                                                 period ) );
459       break;
460     }
461
462     default:
463     {
464       // non animatable types handled already
465     }
466   }
467 }
468
469 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
470 {
471   AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
472 }
473
474 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
475 {
476   AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
477 }
478
479 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
480 {
481   AnimateTo(target, destinationValue, mDefaultAlpha, period);
482 }
483
484 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
485 {
486   Object& object = GetImplementation(target.object);
487
488   AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
489 }
490
491 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
492 {
493   Property::Type targetType = targetObject.GetPropertyType(targetPropertyIndex);
494   if( componentIndex != Property::INVALID_COMPONENT_INDEX )
495   {
496     if( ( targetType == Property::VECTOR2 ) ||
497         ( targetType == Property::VECTOR3 ) ||
498         ( targetType == Property::VECTOR4 ) )
499     {
500       targetType = Property::FLOAT;
501     }
502   }
503   const Property::Type destinationType = destinationValue.GetType();
504   DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
505
506   ExtendDuration( period );
507
508   // Store data to later notify the object that its property is being animated
509   ConnectorTargetValues connectorPair;
510   connectorPair.targetValue = destinationValue;
511   connectorPair.connectorIndex = mConnectors.Count();
512   connectorPair.timePeriod = period;
513   connectorPair.propertyChangeType = Object::PropertyChange::SET;
514   mConnectorTargetValues.push_back( connectorPair );
515
516   switch ( destinationType )
517   {
518     case Property::BOOLEAN:
519     {
520       AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
521                                                           targetPropertyIndex,
522                                                           componentIndex,
523                                                           new AnimateToBoolean( destinationValue.Get<bool>() ),
524                                                           alpha,
525                                                           period ) );
526       break;
527     }
528
529     case Property::INTEGER:
530     {
531       AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
532                                                          targetPropertyIndex,
533                                                          componentIndex,
534                                                          new AnimateToInteger( destinationValue.Get<int>() ),
535                                                          alpha,
536                                                          period ) );
537       break;
538     }
539
540     case Property::FLOAT:
541     {
542       AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
543                                                            targetPropertyIndex,
544                                                            componentIndex,
545                                                            new AnimateToFloat( destinationValue.Get<float>() ),
546                                                            alpha,
547                                                            period ) );
548       break;
549     }
550
551     case Property::VECTOR2:
552     {
553       AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
554                                                              targetPropertyIndex,
555                                                              componentIndex,
556                                                              new AnimateToVector2( destinationValue.Get<Vector2>() ),
557                                                              alpha,
558                                                              period ) );
559       break;
560     }
561
562     case Property::VECTOR3:
563     {
564       AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
565                                                              targetPropertyIndex,
566                                                              componentIndex,
567                                                              new AnimateToVector3( destinationValue.Get<Vector3>() ),
568                                                              alpha,
569                                                              period ) );
570       break;
571     }
572
573     case Property::VECTOR4:
574     {
575       AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
576                                                              targetPropertyIndex,
577                                                              componentIndex,
578                                                              new AnimateToVector4( destinationValue.Get<Vector4>() ),
579                                                              alpha,
580                                                              period ) );
581       break;
582     }
583
584     case Property::ROTATION:
585     {
586       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
587                                                                 targetPropertyIndex,
588                                                                 componentIndex,
589                                                                 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
590                                                                 alpha,
591                                                                 period ) );
592       break;
593     }
594
595     default:
596     {
597       // non animatable types handled already
598     }
599   }
600 }
601
602 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
603 {
604   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
605 }
606
607 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
608 {
609   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
610 }
611
612 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
613 {
614   AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
615 }
616
617 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
618 {
619   AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
620 }
621
622 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
623 {
624   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION);
625 }
626
627 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
628 {
629   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation);
630 }
631
632 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
633 {
634   AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
635 }
636
637 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
638 {
639   Object& object = GetImplementation( target.object );
640
641   ExtendDuration( period );
642
643   switch(keyFrames.GetType())
644   {
645     case Dali::Property::BOOLEAN:
646     {
647       const KeyFrameBoolean* kf;
648       GetSpecialization(keyFrames, kf);
649       KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
650       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
651                                                           target.propertyIndex,
652                                                           target.componentIndex,
653                                                           new KeyFrameBooleanFunctor(kfCopy),
654                                                           alpha,
655                                                           period ) );
656       break;
657     }
658
659     case Dali::Property::INTEGER:
660     {
661       const KeyFrameInteger* kf;
662       GetSpecialization(keyFrames, kf);
663       KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
664       AddAnimatorConnector( AnimatorConnector<int>::New( object,
665                                                          target.propertyIndex,
666                                                          target.componentIndex,
667                                                          new KeyFrameIntegerFunctor(kfCopy,interpolation),
668                                                          alpha,
669                                                          period ) );
670       break;
671     }
672
673     case Dali::Property::FLOAT:
674     {
675       const KeyFrameNumber* kf;
676       GetSpecialization(keyFrames, kf);
677       KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
678       AddAnimatorConnector( AnimatorConnector<float>::New( object,
679                                                            target.propertyIndex,
680                                                            target.componentIndex,
681                                                            new KeyFrameNumberFunctor(kfCopy,interpolation),
682                                                            alpha,
683                                                            period ) );
684       break;
685     }
686
687     case Dali::Property::VECTOR2:
688     {
689       const KeyFrameVector2* kf;
690       GetSpecialization(keyFrames, kf);
691       KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
692       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
693                                                              target.propertyIndex,
694                                                              target.componentIndex,
695                                                              new KeyFrameVector2Functor(kfCopy,interpolation),
696                                                              alpha,
697                                                              period ) );
698       break;
699     }
700
701     case Dali::Property::VECTOR3:
702     {
703       const KeyFrameVector3* kf;
704       GetSpecialization(keyFrames, kf);
705       KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
706       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
707                                                              target.propertyIndex,
708                                                              target.componentIndex,
709                                                              new KeyFrameVector3Functor(kfCopy,interpolation),
710                                                              alpha,
711                                                              period ) );
712       break;
713     }
714
715     case Dali::Property::VECTOR4:
716     {
717       const KeyFrameVector4* kf;
718       GetSpecialization(keyFrames, kf);
719       KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
720       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
721                                                              target.propertyIndex,
722                                                              target.componentIndex,
723                                                              new KeyFrameVector4Functor(kfCopy,interpolation),
724                                                              alpha,
725                                                              period ) );
726       break;
727     }
728
729     case Dali::Property::ROTATION:
730     {
731       const KeyFrameQuaternion* kf;
732       GetSpecialization(keyFrames, kf);
733       KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
734       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
735                                                                 target.propertyIndex,
736                                                                 target.componentIndex,
737                                                                 new KeyFrameQuaternionFunctor(kfCopy),
738                                                                 alpha,
739                                                                 period ) );
740       break;
741     }
742
743     default:
744     {
745       // non animatable types handled by keyframes
746     }
747   }
748 }
749
750 bool Animation::HasFinished()
751 {
752   bool hasFinished(false);
753   const int playedCount(mAnimation->GetPlayedCount());
754
755   // If the play count has been incremented, then another notification is required
756   mCurrentLoop = mAnimation->GetCurrentLoop();
757
758   if (playedCount > mNotificationCount)
759   {
760     // Note that only one signal is emitted, if the animation has been played repeatedly
761     mNotificationCount = playedCount;
762
763     hasFinished = true;
764
765     mState = Dali::Animation::STOPPED;
766   }
767
768   return hasFinished;
769 }
770
771 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
772 {
773   return mFinishedSignal;
774 }
775
776 void Animation::EmitSignalFinish()
777 {
778   if ( !mFinishedSignal.Empty() )
779   {
780     Dali::Animation handle( this );
781     mFinishedSignal.Emit( handle );
782   }
783 }
784
785 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
786 {
787   bool connected( true );
788   Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
789
790   if( 0 == signalName.compare( SIGNAL_FINISHED ) )
791   {
792     animation->FinishedSignal().Connect( tracker, functor );
793   }
794   else
795   {
796     // signalName does not match any signal
797     connected = false;
798   }
799
800   return connected;
801 }
802
803 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
804 {
805   DALI_ASSERT_DEBUG( NULL != connector );
806
807   connector->SetParent(*this);
808
809   mConnectors.PushBack( connector );
810 }
811
812 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
813 {
814   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
815 }
816
817 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
818 {
819   Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
820 }
821
822 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
823 {
824   Animate( actor, path, forward, mDefaultAlpha, period );
825 }
826
827 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
828 {
829   ExtendDuration( period );
830
831   PathPtr pathCopy = Path::Clone(path);
832
833   //Position animation
834   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
835                                                          Dali::Actor::Property::POSITION,
836                                                          Property::INVALID_COMPONENT_INDEX,
837                                                          new PathPositionFunctor( pathCopy ),
838                                                          alpha,
839                                                          period ) );
840
841   //If forward is zero, PathRotationFunctor will always return the unit quaternion
842   if( forward != Vector3::ZERO )
843   {
844     //Rotation animation
845     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
846                                                               Dali::Actor::Property::ORIENTATION,
847                                                               Property::INVALID_COMPONENT_INDEX,
848                                                               new PathRotationFunctor( pathCopy, forward ),
849                                                               alpha,
850                                                               period ) );
851   }
852 }
853
854 void Animation::Show(Actor& actor, float delaySeconds)
855 {
856   ExtendDuration( TimePeriod(delaySeconds, 0) );
857
858   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
859                                                       Dali::Actor::Property::VISIBLE,
860                                                       Property::INVALID_COMPONENT_INDEX,
861                                                       new AnimateToBoolean(SHOW_VALUE),
862                                                       mDefaultAlpha,
863                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
864 }
865
866 void Animation::Hide(Actor& actor, float delaySeconds)
867 {
868   ExtendDuration( TimePeriod(delaySeconds, 0) );
869
870   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
871                                                       Dali::Actor::Property::VISIBLE,
872                                                       Property::INVALID_COMPONENT_INDEX,
873                                                       new AnimateToBoolean(HIDE_VALUE),
874                                                       mDefaultAlpha,
875                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
876 }
877
878 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
879 {
880   bool done = false;
881   Animation* animation = dynamic_cast<Animation*>( object );
882
883   if( animation )
884   {
885     if( 0 == actionName.compare( ACTION_PLAY ) )
886     {
887       if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
888       {
889         animation->SetDuration( value->Get<float>() );
890       }
891
892       animation->Play();
893       done = true;
894     }
895     else if( 0 == actionName.compare( ACTION_STOP ) )
896     {
897       animation->Stop();
898       done = true;
899     }
900     else if( 0 == actionName.compare( ACTION_PAUSE ) )
901     {
902       animation->Pause();
903       done = true;
904     }
905   }
906
907   return done;
908 }
909
910 void Animation::SetCurrentProgress(float progress)
911 {
912   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
913   {
914     // mAnimation is being used in a separate thread; queue a message to set the current progress
915     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
916   }
917 }
918
919 float Animation::GetCurrentProgress()
920 {
921   if( mAnimation )
922   {
923     return mAnimation->GetCurrentProgress();
924   }
925
926   return 0.0f;
927 }
928
929 void Animation::ExtendDuration( const TimePeriod& timePeriod )
930 {
931   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
932
933   if( duration > mDurationSeconds )
934   {
935     SetDuration( duration );
936   }
937 }
938
939 void Animation::SetSpeedFactor( float factor )
940 {
941   if( mAnimation )
942   {
943     mSpeedFactor = factor;
944     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
945   }
946 }
947
948 float Animation::GetSpeedFactor() const
949 {
950   return mSpeedFactor;
951 }
952
953 void Animation::SetPlayRange( const Vector2& range)
954 {
955   //Make sure the range specified is between 0.0 and 1.0
956   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
957   {
958     Vector2 orderedRange( range );
959     //If the range is not in order swap values
960     if( range.x > range.y )
961     {
962       orderedRange = Vector2(range.y, range.x);
963     }
964
965     // Cache for public getters
966     mPlayRange = orderedRange;
967
968     // mAnimation is being used in a separate thread; queue a message to set play range
969     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
970   }
971 }
972
973 Vector2 Animation::GetPlayRange() const
974 {
975   return mPlayRange;
976 }
977
978 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
979 {
980   return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
981 }
982
983 } // namespace Internal
984
985 } // namespace Dali