Merge branch devel/master (1.0.49) into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / animation-impl.cpp
1 /*
2  * Copyright (c) 2014 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/event/effects/shader-effect-impl.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   mIsLooping( false ),
126   mPlayRange( Vector2(0.0f,1.0f)),
127   mEndAction( endAction ),
128   mDisconnectAction( disconnectAction ),
129   mDefaultAlpha( defaultAlpha )
130 {
131 }
132
133 void Animation::Initialize()
134 {
135   // Connect to the animation playlist
136   mPlaylist.AnimationCreated( *this );
137
138   CreateSceneObject();
139
140   RegisterObject();
141 }
142
143 Animation::~Animation()
144 {
145   // Guard to allow handle destruction after Core has been destroyed
146   if ( Stage::IsInstalled() )
147   {
148     // Disconnect from the animation playlist
149     mPlaylist.AnimationDestroyed( *this );
150
151     DestroySceneObject();
152
153     UnregisterObject();
154   }
155 }
156
157 void Animation::CreateSceneObject()
158 {
159   DALI_ASSERT_DEBUG( mAnimation == NULL );
160
161   // Create a new animation, temporarily owned
162   SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mIsLooping, mEndAction, mDisconnectAction );
163
164   // Keep a const pointer to the animation.
165   mAnimation = animation;
166
167   // Transfer animation ownership to the update manager through a message
168   AddAnimationMessage( mEventThreadServices.GetUpdateManager(), animation );
169 }
170
171 void Animation::DestroySceneObject()
172 {
173   if ( mAnimation != NULL )
174   {
175     // Remove animation using a message to the update manager
176     RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
177     mAnimation = NULL;
178   }
179 }
180
181 void Animation::SetDuration(float seconds)
182 {
183   if( seconds < 0.0f )
184   {
185     DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
186     seconds = 0.0f;
187   }
188
189   // Cache for public getters
190   mDurationSeconds = seconds;
191
192   // mAnimation is being used in a separate thread; queue a message to set the value
193   SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
194 }
195
196 float Animation::GetDuration() const
197 {
198   // This is not animatable; the cached value is up-to-date.
199   return mDurationSeconds;
200 }
201
202 void Animation::SetLooping(bool looping)
203 {
204   // Cache for public getters
205   mIsLooping = looping;
206
207   // mAnimation is being used in a separate thread; queue a message to set the value
208   SetLoopingMessage( mEventThreadServices, *mAnimation, looping );
209 }
210
211 bool Animation::IsLooping() const
212 {
213   // This is not animatable; the cached value is up-to-date.
214   return mIsLooping;
215 }
216
217 void Animation::SetEndAction(EndAction action)
218 {
219   // Cache for public getters
220   mEndAction = action;
221
222   // mAnimation is being used in a separate thread; queue a message to set the value
223   SetEndActionMessage( mEventThreadServices, *mAnimation, action );
224 }
225
226 Dali::Animation::EndAction Animation::GetEndAction() const
227 {
228   // This is not animatable; the cached value is up-to-date.
229   return mEndAction;
230 }
231
232 void Animation::SetDisconnectAction(EndAction action)
233 {
234   // Cache for public getters
235   mDisconnectAction = action;
236
237   // mAnimation is being used in a separate thread; queue a message to set the value
238   SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
239 }
240
241 Dali::Animation::EndAction Animation::GetDisconnectAction() const
242 {
243   // This is not animatable; the cached value is up-to-date.
244   return mDisconnectAction;
245 }
246
247 void Animation::Play()
248 {
249   // Update the current playlist
250   mPlaylist.OnPlay( *this );
251
252   // mAnimation is being used in a separate thread; queue a Play message
253   PlayAnimationMessage( mEventThreadServices, *mAnimation );
254 }
255
256 void Animation::PlayFrom( float progress )
257 {
258   if( progress >= mPlayRange.x && progress <= mPlayRange.y )
259   {
260     // Update the current playlist
261     mPlaylist.OnPlay( *this );
262
263     // mAnimation is being used in a separate thread; queue a Play message
264     PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
265   }
266 }
267
268 void Animation::Pause()
269 {
270   // mAnimation is being used in a separate thread; queue a Pause message
271   PauseAnimationMessage( mEventThreadServices, *mAnimation );
272 }
273
274 void Animation::Stop()
275 {
276   // mAnimation is being used in a separate thread; queue a Stop message
277   StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
278 }
279
280 void Animation::Clear()
281 {
282   DALI_ASSERT_DEBUG(mAnimation);
283
284   // Remove all the connectors
285   mConnectors.Clear();
286
287   // Replace the old scene-object with a new one
288   DestroySceneObject();
289   CreateSceneObject();
290
291   // Reset the notification count, since the new scene-object has never been played
292   mNotificationCount = 0;
293
294   // Update the current playlist
295   mPlaylist.OnClear( *this );
296 }
297
298 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
299 {
300   AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
301 }
302
303 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
304 {
305   AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds));
306 }
307
308 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
309 {
310   AnimateBy(target, relativeValue, mDefaultAlpha, period);
311 }
312
313 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
314 {
315   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
316
317   ExtendDuration( period );
318
319   switch ( relativeValue.GetType() )
320   {
321     case Property::BOOLEAN:
322     {
323       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
324                                                           target.propertyIndex,
325                                                           target.componentIndex,
326                                                           new AnimateByBoolean(relativeValue.Get<bool>()),
327                                                           alpha,
328                                                           period ) );
329       break;
330     }
331
332     case Property::INTEGER:
333     {
334       AddAnimatorConnector( AnimatorConnector<int>::New( object,
335                                                          target.propertyIndex,
336                                                          target.componentIndex,
337                                                          new AnimateByInteger(relativeValue.Get<int>()),
338                                                          alpha,
339                                                          period ) );
340       break;
341     }
342
343     case Property::FLOAT:
344     {
345       AddAnimatorConnector( AnimatorConnector<float>::New( object,
346                                                            target.propertyIndex,
347                                                            target.componentIndex,
348                                                            new AnimateByFloat(relativeValue.Get<float>()),
349                                                            alpha,
350                                                            period ) );
351       break;
352     }
353
354     case Property::VECTOR2:
355     {
356       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
357                                                              target.propertyIndex,
358                                                              target.componentIndex,
359                                                              new AnimateByVector2(relativeValue.Get<Vector2>()),
360                                                              alpha,
361                                                              period ) );
362       break;
363     }
364
365     case Property::VECTOR3:
366     {
367       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
368                                                              target.propertyIndex,
369                                                              target.componentIndex,
370                                                              new AnimateByVector3(relativeValue.Get<Vector3>()),
371                                                              alpha,
372                                                              period ) );
373       break;
374     }
375
376     case Property::VECTOR4:
377     {
378       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
379                                                              target.propertyIndex,
380                                                              target.componentIndex,
381                                                              new AnimateByVector4(relativeValue.Get<Vector4>()),
382                                                              alpha,
383                                                              period ) );
384       break;
385     }
386
387     case Property::ROTATION:
388     {
389       AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
390
391       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
392                                                                 target.propertyIndex,
393                                                                 target.componentIndex,
394                                                                 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
395                                                                 alpha,
396                                                                 period ) );
397       break;
398     }
399
400     default:
401       DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
402       break;
403   }
404 }
405
406 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
407 {
408   AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
409 }
410
411 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
412 {
413   AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
414 }
415
416 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
417 {
418   AnimateTo(target, destinationValue, mDefaultAlpha, period);
419 }
420
421 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
422 {
423   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
424
425   AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
426 }
427
428 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
429 {
430   Property::Type type = targetObject.GetPropertyType(targetPropertyIndex);
431   if(componentIndex != Property::INVALID_COMPONENT_INDEX)
432   {
433     if( type == Property::VECTOR2
434         || type == Property::VECTOR3
435         || type == Property::VECTOR4 )
436     {
437       type = Property::FLOAT;
438     }
439   }
440   DALI_ASSERT_ALWAYS( type == destinationValue.GetType() && "DestinationValue does not match Target Property type" );
441
442   ExtendDuration( period );
443
444   switch (destinationValue.GetType())
445   {
446     case Property::BOOLEAN:
447     {
448       AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
449                                                           targetPropertyIndex,
450                                                           componentIndex,
451                                                           new AnimateToBoolean( destinationValue.Get<bool>() ),
452                                                           alpha,
453                                                           period ) );
454       break;
455     }
456
457     case Property::INTEGER:
458     {
459       AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
460                                                          targetPropertyIndex,
461                                                          componentIndex,
462                                                          new AnimateToInteger( destinationValue.Get<int>() ),
463                                                          alpha,
464                                                          period ) );
465       break;
466     }
467
468     case Property::FLOAT:
469     {
470       if ( ( Dali::Actor::Property::SIZE_WIDTH == targetPropertyIndex )||
471            ( Dali::Actor::Property::SIZE_HEIGHT == targetPropertyIndex ) )
472       {
473         // Test whether this is actually an Actor
474         Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
475         if ( maybeActor )
476         {
477           // Notify the actor that its size is being animated
478           maybeActor->NotifySizeAnimation( *this, destinationValue.Get<float>(), targetPropertyIndex );
479         }
480       }
481       AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
482                                                            targetPropertyIndex,
483                                                            componentIndex,
484                                                            new AnimateToFloat( destinationValue.Get<float>() ),
485                                                            alpha,
486                                                            period ) );
487       break;
488     }
489
490     case Property::VECTOR2:
491     {
492       AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
493                                                              targetPropertyIndex,
494                                                              componentIndex,
495                                                              new AnimateToVector2( destinationValue.Get<Vector2>() ),
496                                                              alpha,
497                                                              period ) );
498       break;
499     }
500
501     case Property::VECTOR3:
502     {
503       if ( Dali::Actor::Property::SIZE == targetPropertyIndex )
504       {
505         // Test whether this is actually an Actor
506         Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
507         if ( maybeActor )
508         {
509           // Notify the actor that its size is being animated
510           maybeActor->NotifySizeAnimation( *this, destinationValue.Get<Vector3>() );
511         }
512       }
513
514       AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
515                                                              targetPropertyIndex,
516                                                              componentIndex,
517                                                              new AnimateToVector3( destinationValue.Get<Vector3>() ),
518                                                              alpha,
519                                                              period ) );
520       break;
521     }
522
523     case Property::VECTOR4:
524     {
525       AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
526                                                              targetPropertyIndex,
527                                                              componentIndex,
528                                                              new AnimateToVector4( destinationValue.Get<Vector4>() ),
529                                                              alpha,
530                                                              period ) );
531       break;
532     }
533
534     case Property::ROTATION:
535     {
536       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
537                                                                 targetPropertyIndex,
538                                                                 componentIndex,
539                                                                 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
540                                                                 alpha,
541                                                                 period ) );
542       break;
543     }
544
545     default:
546       DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
547       break;
548   }
549 }
550
551 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
552 {
553   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
554 }
555
556 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
557 {
558   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
559 }
560
561 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
562 {
563   AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
564 }
565
566 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
567 {
568   AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
569 }
570
571 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
572 {
573   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION);
574 }
575
576 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
577 {
578   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation);
579 }
580
581 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
582 {
583   AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
584 }
585
586 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
587 {
588   Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
589
590   ExtendDuration( period );
591
592   switch(keyFrames.GetType())
593   {
594     case Dali::Property::BOOLEAN:
595     {
596       const KeyFrameBoolean* kf;
597       GetSpecialization(keyFrames, kf);
598       KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
599       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
600                                                           target.propertyIndex,
601                                                           target.componentIndex,
602                                                           new KeyFrameBooleanFunctor(kfCopy),
603                                                           alpha,
604                                                           period ) );
605       break;
606     }
607
608     case Dali::Property::INTEGER:
609     {
610       const KeyFrameInteger* kf;
611       GetSpecialization(keyFrames, kf);
612       KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
613       AddAnimatorConnector( AnimatorConnector<int>::New( object,
614                                                          target.propertyIndex,
615                                                          target.componentIndex,
616                                                          new KeyFrameIntegerFunctor(kfCopy,interpolation),
617                                                          alpha,
618                                                          period ) );
619       break;
620     }
621
622     case Dali::Property::FLOAT:
623     {
624       const KeyFrameNumber* kf;
625       GetSpecialization(keyFrames, kf);
626       KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
627       AddAnimatorConnector( AnimatorConnector<float>::New( object,
628                                                            target.propertyIndex,
629                                                            target.componentIndex,
630                                                            new KeyFrameNumberFunctor(kfCopy,interpolation),
631                                                            alpha,
632                                                            period ) );
633       break;
634     }
635
636     case Dali::Property::VECTOR2:
637     {
638       const KeyFrameVector2* kf;
639       GetSpecialization(keyFrames, kf);
640       KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
641       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
642                                                              target.propertyIndex,
643                                                              target.componentIndex,
644                                                              new KeyFrameVector2Functor(kfCopy,interpolation),
645                                                              alpha,
646                                                              period ) );
647       break;
648     }
649
650     case Dali::Property::VECTOR3:
651     {
652       const KeyFrameVector3* kf;
653       GetSpecialization(keyFrames, kf);
654       KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
655       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
656                                                              target.propertyIndex,
657                                                              target.componentIndex,
658                                                              new KeyFrameVector3Functor(kfCopy,interpolation),
659                                                              alpha,
660                                                              period ) );
661       break;
662     }
663
664     case Dali::Property::VECTOR4:
665     {
666       const KeyFrameVector4* kf;
667       GetSpecialization(keyFrames, kf);
668       KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
669       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
670                                                              target.propertyIndex,
671                                                              target.componentIndex,
672                                                              new KeyFrameVector4Functor(kfCopy,interpolation),
673                                                              alpha,
674                                                              period ) );
675       break;
676     }
677
678     case Dali::Property::ROTATION:
679     {
680       const KeyFrameQuaternion* kf;
681       GetSpecialization(keyFrames, kf);
682       KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
683       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
684                                                                 target.propertyIndex,
685                                                                 target.componentIndex,
686                                                                 new KeyFrameQuaternionFunctor(kfCopy),
687                                                                 alpha,
688                                                                 period ) );
689       break;
690     }
691
692     default: // not all property types are animateable
693       break;
694   }
695 }
696
697 bool Animation::HasFinished()
698 {
699   bool hasFinished(false);
700   const int playCount(mAnimation->GetPlayCount());
701
702   // If the play count has been incremented, then another notification is required
703   if (playCount > mNotificationCount)
704   {
705     // Note that only one signal is emitted, if the animation has been played repeatedly
706     mNotificationCount = playCount;
707
708     hasFinished = true;
709   }
710
711   return hasFinished;
712 }
713
714 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
715 {
716   return mFinishedSignal;
717 }
718
719 void Animation::EmitSignalFinish()
720 {
721   if ( !mFinishedSignal.Empty() )
722   {
723     Dali::Animation handle( this );
724     mFinishedSignal.Emit( handle );
725   }
726
727   // This callback is used internally, to avoid the overhead of using a signal.
728   if ( mFinishedCallback )
729   {
730     mFinishedCallback( mFinishedCallbackObject );
731   }
732 }
733
734 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
735 {
736   bool connected( true );
737   Animation* animation = dynamic_cast<Animation*>(object);
738
739   if( 0 == signalName.compare( SIGNAL_FINISHED ) )
740   {
741     animation->FinishedSignal().Connect( tracker, functor );
742   }
743   else
744   {
745     // signalName does not match any signal
746     connected = false;
747   }
748
749   return connected;
750 }
751
752 void Animation::SetFinishedCallback( FinishedCallback callback, Object* object )
753 {
754   mFinishedCallback = callback;
755   mFinishedCallbackObject = object;
756 }
757
758 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
759 {
760   DALI_ASSERT_DEBUG( NULL != connector );
761
762   connector->SetParent(*this);
763
764   mConnectors.PushBack( connector );
765 }
766
767 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
768 {
769   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
770 }
771
772 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
773 {
774   Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
775 }
776
777 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
778 {
779   Animate( actor, path, forward, mDefaultAlpha, period );
780 }
781
782 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
783 {
784   ExtendDuration( period );
785
786   PathPtr pathCopy = Path::Clone(path);
787
788   //Position animation
789   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
790                                                          Dali::Actor::Property::POSITION,
791                                                          Property::INVALID_COMPONENT_INDEX,
792                                                          new PathPositionFunctor( pathCopy ),
793                                                          alpha,
794                                                          period ) );
795
796   //If forward is zero, PathRotationFunctor will always return the unit quaternion
797   if( forward != Vector3::ZERO )
798   {
799     //Rotation animation
800     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
801                                                               Dali::Actor::Property::ORIENTATION,
802                                                               Property::INVALID_COMPONENT_INDEX,
803                                                               new PathRotationFunctor( pathCopy, forward ),
804                                                               alpha,
805                                                               period ) );
806   }
807 }
808
809 void Animation::Show(Actor& actor, float delaySeconds)
810 {
811   ExtendDuration( TimePeriod(delaySeconds, 0) );
812
813   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
814                                                       Dali::Actor::Property::VISIBLE,
815                                                       Property::INVALID_COMPONENT_INDEX,
816                                                       new AnimateToBoolean(SHOW_VALUE),
817                                                       mDefaultAlpha,
818                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
819 }
820
821 void Animation::Hide(Actor& actor, float delaySeconds)
822 {
823   ExtendDuration( TimePeriod(delaySeconds, 0) );
824
825   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
826                                                       Dali::Actor::Property::VISIBLE,
827                                                       Property::INVALID_COMPONENT_INDEX,
828                                                       new AnimateToBoolean(HIDE_VALUE),
829                                                       mDefaultAlpha,
830                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
831 }
832
833 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
834 {
835   bool done = false;
836   Animation* animation = dynamic_cast<Animation*>( object );
837
838   if( animation )
839   {
840     if( 0 == actionName.compare( ACTION_PLAY ) )
841     {
842       if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
843       {
844         animation->SetDuration( value->Get<float>() );
845       }
846
847       animation->Play();
848       done = true;
849     }
850     else if( 0 == actionName.compare( ACTION_STOP ) )
851     {
852       animation->Stop();
853       done = true;
854     }
855     else if( 0 == actionName.compare( ACTION_PAUSE ) )
856     {
857       animation->Pause();
858       done = true;
859     }
860   }
861
862   return done;
863 }
864
865 void Animation::SetCurrentProgress(float progress)
866 {
867   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
868   {
869     // mAnimation is being used in a separate thread; queue a message to set the current progress
870     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
871   }
872 }
873
874 float Animation::GetCurrentProgress()
875 {
876   if( mAnimation )
877   {
878     return mAnimation->GetCurrentProgress();
879   }
880
881   return 0.0f;
882 }
883
884 void Animation::ExtendDuration( const TimePeriod& timePeriod )
885 {
886   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
887
888   if( duration > mDurationSeconds )
889   {
890     SetDuration( duration );
891   }
892 }
893
894 void Animation::SetSpeedFactor( float factor )
895 {
896   if( mAnimation )
897   {
898     mSpeedFactor = factor;
899     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
900   }
901 }
902
903 float Animation::GetSpeedFactor() const
904 {
905   return mSpeedFactor;
906 }
907
908 void Animation::SetPlayRange( const Vector2& range)
909 {
910   //Make sure the range specified is between 0.0 and 1.0
911   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
912   {
913     Vector2 orderedRange( range );
914     //If the range is not in order swap values
915     if( range.x > range.y )
916     {
917       orderedRange = Vector2(range.y, range.x);
918     }
919
920     // Cache for public getters
921     mPlayRange = orderedRange;
922
923     // mAnimation is being used in a separate thread; queue a message to set play range
924     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
925   }
926 }
927
928 Vector2 Animation::GetPlayRange() const
929 {
930   return mPlayRange;
931 }
932
933
934 } // namespace Internal
935
936 } // namespace Dali