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