2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/animation/animation-impl.h>
20 #include <dali/public-api/object/property-map.h>
25 #include <dali/public-api/animation/alpha-function.h>
26 #include <dali/public-api/animation/time-period.h>
27 #include <dali/public-api/common/dali-common.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/public-api/math/vector2.h>
30 #include <dali/public-api/math/radian.h>
31 #include <dali/internal/event/animation/animation-playlist.h>
32 #include <dali/internal/event/animation/animator-connector.h>
33 #include <dali/internal/event/animation/path-impl.h>
34 #include <dali/internal/event/common/notification-manager.h>
35 #include <dali/internal/event/common/property-helper.h>
36 #include <dali/internal/event/common/stage-impl.h>
37 #include <dali/internal/event/common/thread-local-storage.h>
38 #include <dali/internal/update/animation/scene-graph-animator.h>
39 #include <dali/internal/update/manager/update-manager.h>
41 using Dali::Internal::SceneGraph::UpdateManager;
42 using Dali::Internal::SceneGraph::AnimatorBase;
43 using Dali::Internal::SceneGraph::Shader;
51 static bool SHOW_VALUE = true;
52 static bool HIDE_VALUE = false;
59 const char* const SIGNAL_FINISHED = "finished";
63 const char* const ACTION_PLAY = "play";
64 const char* const ACTION_STOP = "stop";
65 const char* const ACTION_PAUSE = "pause";
69 return Dali::Animation::New(0.f);
72 TypeRegistration mType( typeid( Dali::Animation ), typeid( Dali::BaseHandle ), Create );
74 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &Animation::DoConnectSignal );
76 TypeAction action1( mType, ACTION_PLAY, &Animation::DoAction );
77 TypeAction action2( mType, ACTION_STOP, &Animation::DoAction );
78 TypeAction action3( mType, ACTION_PAUSE, &Animation::DoAction );
80 const Dali::Animation::EndAction DEFAULT_END_ACTION( Dali::Animation::Bake );
81 const Dali::Animation::EndAction DEFAULT_DISCONNECT_ACTION( Dali::Animation::BakeFinal );
82 const Dali::Animation::Interpolation DEFAULT_INTERPOLATION( Dali::Animation::Linear );
83 const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION( Dali::AlphaFunction::DEFAULT );
86 * Helper to tell if a property is animatable (if we have animators for it)
88 * @param type type to check
89 * @return true if animatable
91 inline bool IsAnimatable( Property::Type type )
93 bool animatable = false;
96 case Property::BOOLEAN :
97 case Property::FLOAT :
98 case Property::INTEGER :
99 case Property::VECTOR2 :
100 case Property::VECTOR3 :
101 case Property::VECTOR4 :
102 case Property::ROTATION :
107 case Property::MATRIX : // matrix is allowed as a scene graph property but there's no animators for it
108 case Property::MATRIX3 : // matrix3 is allowed as a scene graph property but there's no animators for it
109 case Property::NONE :
110 case Property::RECTANGLE :
111 case Property::STRING :
112 case Property::ARRAY :
114 case Property::EXTENTS :
123 * Helper to validate animation input values
125 * @param propertyType type of the property that is being animated
126 * @param destinationType type of the target
127 * @param period time period of the animation
129 void ValidateParameters( Property::Type propertyType, Property::Type destinationType, const TimePeriod& period )
131 // destination value has to be animatable
132 DALI_ASSERT_ALWAYS( IsAnimatable( propertyType ) && "Property type is not animatable" );
133 DALI_ASSERT_ALWAYS( IsAnimatable( destinationType ) && "Target value is not animatable" );
134 DALI_ASSERT_ALWAYS( propertyType == destinationType && "Property and target types don't match" );
135 DALI_ASSERT_ALWAYS( period.durationSeconds >= 0 && "Duration must be >=0" );
138 } // anonymous namespace
141 AnimationPtr Animation::New(float durationSeconds)
143 if( durationSeconds < 0.0f )
145 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
146 durationSeconds = 0.0f;
149 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
150 AnimationPtr animation = new Animation( tls.GetEventThreadServices(), tls.GetAnimationPlaylist(), durationSeconds, DEFAULT_END_ACTION, DEFAULT_DISCONNECT_ACTION, DEFAULT_ALPHA_FUNCTION );
152 // Second-phase construction
153 animation->Initialize();
158 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
159 : mAnimation( NULL ),
160 mEventThreadServices( eventThreadServices ),
161 mPlaylist( playlist ),
164 mConnectorTargetValues(),
165 mPlayRange( Vector2(0.0f,1.0f)),
166 mDurationSeconds( durationSeconds ),
168 mNotificationCount( 0 ),
171 mEndAction( endAction ),
172 mDisconnectAction( disconnectAction ),
173 mDefaultAlpha( defaultAlpha ),
174 mState(Dali::Animation::STOPPED),
175 mProgressReachedMarker( 0.0f ),
176 mDelaySeconds( 0.0f ),
177 mAutoReverseEnabled( false )
181 void Animation::Initialize()
183 // Connect to the animation playlist
184 mPlaylist.AnimationCreated( *this );
191 Animation::~Animation()
193 // Guard to allow handle destruction after Core has been destroyed
194 if ( Stage::IsInstalled() )
196 // Disconnect from the animation playlist
197 mPlaylist.AnimationDestroyed( *this );
199 DestroySceneObject();
205 void Animation::CreateSceneObject()
207 DALI_ASSERT_DEBUG( mAnimation == NULL );
209 // Create a new animation, Keep a const pointer to the animation.
210 mAnimation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction );
211 OwnerPointer< SceneGraph::Animation > transferOwnership( const_cast< SceneGraph::Animation* >( mAnimation ) );
212 AddAnimationMessage( mEventThreadServices.GetUpdateManager(), transferOwnership );
215 void Animation::DestroySceneObject()
217 if ( mAnimation != NULL )
219 // Remove animation using a message to the update manager
220 RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
225 void Animation::SetDuration(float seconds)
229 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
233 mDurationSeconds = seconds;
235 // mAnimation is being used in a separate thread; queue a message to set the value
236 SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
239 void Animation::SetProgressNotification( float progress )
241 // mAnimation is being used in a separate thread; queue a message to set the value
242 mProgressReachedMarker = progress;
245 float Animation::GetProgressNotification()
247 return mProgressReachedMarker;
250 float Animation::GetDuration() const
252 // This is not animatable; the cached value is up-to-date.
253 return mDurationSeconds;
256 void Animation::SetLooping(bool on)
258 SetLoopCount( on ? 0 : 1 );
261 void Animation::SetLoopCount(int32_t count)
263 // Cache for public getters
266 // mAnimation is being used in a separate thread; queue a message to set the value
267 SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount );
270 int32_t Animation::GetLoopCount()
275 int32_t Animation::GetCurrentLoop()
280 bool Animation::IsLooping() const
282 return mLoopCount != 1;
285 void Animation::SetEndAction(EndAction action)
287 // Cache for public getters
290 // mAnimation is being used in a separate thread; queue a message to set the value
291 SetEndActionMessage( mEventThreadServices, *mAnimation, action );
294 Dali::Animation::EndAction Animation::GetEndAction() const
296 // This is not animatable; the cached value is up-to-date.
300 void Animation::SetDisconnectAction(EndAction action)
302 // Cache for public getters
303 mDisconnectAction = action;
305 // mAnimation is being used in a separate thread; queue a message to set the value
306 SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
309 Dali::Animation::EndAction Animation::GetDisconnectAction() const
311 // This is not animatable; the cached value is up-to-date.
312 return mDisconnectAction;
315 void Animation::Play()
317 // Update the current playlist
318 mPlaylist.OnPlay( *this );
320 mState = Dali::Animation::PLAYING;
322 NotifyObjects( Notify::USE_TARGET_VALUE );
324 SendFinalProgressNotificationMessage();
326 // mAnimation is being used in a separate thread; queue a Play message
327 PlayAnimationMessage( mEventThreadServices, *mAnimation );
330 void Animation::PlayFrom( float progress )
332 if( progress >= mPlayRange.x && progress <= mPlayRange.y )
334 // Update the current playlist
335 mPlaylist.OnPlay( *this );
337 mState = Dali::Animation::PLAYING;
339 NotifyObjects( Notify::USE_TARGET_VALUE );
341 SendFinalProgressNotificationMessage();
343 // mAnimation is being used in a separate thread; queue a Play message
344 PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
348 void Animation::PlayAfter( float delaySeconds )
350 // The negative delay means play immediately.
351 delaySeconds = std::max( 0.f, delaySeconds );
353 mDelaySeconds = delaySeconds;
355 // Update the current playlist
356 mPlaylist.OnPlay( *this );
358 mState = Dali::Animation::PLAYING;
360 NotifyObjects( Notify::USE_TARGET_VALUE );
362 SendFinalProgressNotificationMessage();
364 // mAnimation is being used in a separate thread; queue a message to set the value
365 PlayAfterMessage( mEventThreadServices, *mAnimation, delaySeconds );
368 void Animation::Pause()
370 mState = Dali::Animation::PAUSED;
372 // mAnimation is being used in a separate thread; queue a Pause message
373 PauseAnimationMessage( mEventThreadServices, *mAnimation );
375 // Notify the objects with the _paused_, i.e. current values
376 NotifyObjects( Notify::FORCE_CURRENT_VALUE );
379 Dali::Animation::State Animation::GetState() const
384 void Animation::Stop()
386 mState = Dali::Animation::STOPPED;
388 // mAnimation is being used in a separate thread; queue a Stop message
389 StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
391 // Only notify the objects with the _stopped_, i.e. current values if the end action is set to BAKE
392 if( mEndAction == EndAction::Bake )
394 NotifyObjects( Notify::USE_CURRENT_VALUE );
398 void Animation::Clear()
400 DALI_ASSERT_DEBUG(mAnimation);
402 // Only notify the objects with the current values if the end action is set to BAKE
403 if( mEndAction == EndAction::Bake )
405 NotifyObjects( Notify::USE_CURRENT_VALUE );
408 // Remove all the connectors
411 // Reset the connector target values
412 mConnectorTargetValues.clear();
414 // Replace the old scene-object with a new one
415 DestroySceneObject();
418 // Reset the notification count, since the new scene-object has never been played
419 mNotificationCount = 0;
421 // Update the current playlist
422 mPlaylist.OnClear( *this );
425 void Animation::AnimateBy( Property& target, Property::Value& relativeValue )
427 AnimateBy( target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds) );
430 void Animation::AnimateBy( Property& target, Property::Value& relativeValue, AlphaFunction alpha )
432 AnimateBy( target, relativeValue, alpha, TimePeriod(mDurationSeconds) );
435 void Animation::AnimateBy( Property& target, Property::Value& relativeValue, TimePeriod period )
437 AnimateBy( target, relativeValue, mDefaultAlpha, period );
440 void Animation::AnimateBy( Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period )
442 Object& object = GetImplementation(target.object);
443 const Property::Type propertyType = object.GetPropertyType( target.propertyIndex );
444 const Property::Type destinationType = relativeValue.GetType();
446 // validate animation parameters, if component index is set then use float as checked type
447 ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT,
448 destinationType, period );
450 ExtendDuration(period);
452 // Store data to later notify the object that its property is being animated
453 ConnectorTargetValues connectorPair;
454 connectorPair.targetValue = relativeValue;
455 connectorPair.connectorIndex = mConnectors.Count();
456 connectorPair.timePeriod = period;
457 connectorPair.animatorType = Animation::BY;
458 mConnectorTargetValues.push_back( connectorPair );
460 // using destination type so component animation gets correct type
461 switch ( destinationType )
463 case Property::BOOLEAN:
465 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
466 target.propertyIndex,
467 target.componentIndex,
468 new AnimateByBoolean(relativeValue.Get<bool>()),
474 case Property::INTEGER:
476 AddAnimatorConnector( AnimatorConnector<int32_t>::New( object,
477 target.propertyIndex,
478 target.componentIndex,
479 new AnimateByInteger(relativeValue.Get<int32_t>()),
485 case Property::FLOAT:
487 AddAnimatorConnector( AnimatorConnector<float>::New( object,
488 target.propertyIndex,
489 target.componentIndex,
490 new AnimateByFloat(relativeValue.Get<float>()),
496 case Property::VECTOR2:
498 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
499 target.propertyIndex,
500 target.componentIndex,
501 new AnimateByVector2(relativeValue.Get<Vector2>()),
507 case Property::VECTOR3:
509 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
510 target.propertyIndex,
511 target.componentIndex,
512 new AnimateByVector3(relativeValue.Get<Vector3>()),
518 case Property::VECTOR4:
520 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
521 target.propertyIndex,
522 target.componentIndex,
523 new AnimateByVector4(relativeValue.Get<Vector4>()),
529 case Property::ROTATION:
531 AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
533 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
534 target.propertyIndex,
535 target.componentIndex,
536 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
544 // non animatable types handled already
549 void Animation::AnimateTo( Property& target, Property::Value& destinationValue )
551 AnimateTo( target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds) );
554 void Animation::AnimateTo( Property& target, Property::Value& destinationValue, AlphaFunction alpha )
556 AnimateTo( target, destinationValue, alpha, TimePeriod(mDurationSeconds));
559 void Animation::AnimateTo( Property& target, Property::Value& destinationValue, TimePeriod period )
561 AnimateTo( target, destinationValue, mDefaultAlpha, period );
564 void Animation::AnimateTo( Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period )
566 Object& object = GetImplementation( target.object );
567 const Property::Type propertyType = object.GetPropertyType( target.propertyIndex );
568 const Property::Type destinationType = destinationValue.GetType();
570 // validate animation parameters, if component index is set then use float as checked type
571 ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT,
572 destinationType, period );
574 ExtendDuration( period );
576 // Store data to later notify the object that its property is being animated
577 ConnectorTargetValues connectorPair;
578 connectorPair.targetValue = destinationValue;
579 connectorPair.connectorIndex = mConnectors.Count();
580 connectorPair.timePeriod = period;
581 connectorPair.animatorType = Animation::TO;
582 mConnectorTargetValues.push_back( connectorPair );
584 // using destination type so component animation gets correct type
585 switch ( destinationType )
587 case Property::BOOLEAN:
589 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
590 target.propertyIndex,
591 target.componentIndex,
592 new AnimateToBoolean( destinationValue.Get<bool>() ),
598 case Property::INTEGER:
600 AddAnimatorConnector( AnimatorConnector<int32_t>::New( object,
601 target.propertyIndex,
602 target.componentIndex,
603 new AnimateToInteger( destinationValue.Get<int32_t>() ),
609 case Property::FLOAT:
611 AddAnimatorConnector( AnimatorConnector<float>::New( object,
612 target.propertyIndex,
613 target.componentIndex,
614 new AnimateToFloat( destinationValue.Get<float>() ),
620 case Property::VECTOR2:
622 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
623 target.propertyIndex,
624 target.componentIndex,
625 new AnimateToVector2( destinationValue.Get<Vector2>() ),
631 case Property::VECTOR3:
633 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
634 target.propertyIndex,
635 target.componentIndex,
636 new AnimateToVector3( destinationValue.Get<Vector3>() ),
642 case Property::VECTOR4:
644 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
645 target.propertyIndex,
646 target.componentIndex,
647 new AnimateToVector4( destinationValue.Get<Vector4>() ),
653 case Property::ROTATION:
655 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
656 target.propertyIndex,
657 target.componentIndex,
658 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
666 // non animatable types handled already
671 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames )
673 AnimateBetween( target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
676 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, Interpolation interpolation )
678 AnimateBetween( target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
681 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, TimePeriod period )
683 AnimateBetween( target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION );
686 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation )
688 AnimateBetween( target, keyFrames, mDefaultAlpha, period, interpolation );
691 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha )
693 AnimateBetween( target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
696 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation )
698 AnimateBetween( target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation );
701 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period )
703 AnimateBetween( target, keyFrames, alpha, period, DEFAULT_INTERPOLATION );
706 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation )
708 Object& object = GetImplementation( target.object );
709 const Property::Type propertyType = object.GetPropertyType( target.propertyIndex );
710 const Property::Type destinationType = keyFrames.GetType();
712 // validate animation parameters, if component index is set then use float as checked type
713 ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT,
714 destinationType, period );
716 ExtendDuration( period );
718 // Store data to later notify the object that its property is being animated
719 ConnectorTargetValues connectorPair;
720 connectorPair.targetValue = keyFrames.GetLastKeyFrameValue();
721 connectorPair.connectorIndex = mConnectors.Count();
722 connectorPair.timePeriod = period;
723 connectorPair.animatorType = BETWEEN;
724 mConnectorTargetValues.push_back( connectorPair );
726 // using destination type so component animation gets correct type
727 switch( destinationType )
729 case Dali::Property::BOOLEAN:
731 const KeyFrameBoolean* kf;
732 GetSpecialization(keyFrames, kf);
733 KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
734 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
735 target.propertyIndex,
736 target.componentIndex,
737 new KeyFrameBooleanFunctor(kfCopy),
743 case Dali::Property::INTEGER:
745 const KeyFrameInteger* kf;
746 GetSpecialization(keyFrames, kf);
747 KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
748 AddAnimatorConnector( AnimatorConnector<int32_t>::New( object,
749 target.propertyIndex,
750 target.componentIndex,
751 new KeyFrameIntegerFunctor(kfCopy,interpolation),
757 case Dali::Property::FLOAT:
759 const KeyFrameNumber* kf;
760 GetSpecialization(keyFrames, kf);
761 KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
762 AddAnimatorConnector( AnimatorConnector<float>::New( object,
763 target.propertyIndex,
764 target.componentIndex,
765 new KeyFrameNumberFunctor(kfCopy,interpolation),
771 case Dali::Property::VECTOR2:
773 const KeyFrameVector2* kf;
774 GetSpecialization(keyFrames, kf);
775 KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
776 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
777 target.propertyIndex,
778 target.componentIndex,
779 new KeyFrameVector2Functor(kfCopy,interpolation),
785 case Dali::Property::VECTOR3:
787 const KeyFrameVector3* kf;
788 GetSpecialization(keyFrames, kf);
789 KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
790 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
791 target.propertyIndex,
792 target.componentIndex,
793 new KeyFrameVector3Functor(kfCopy,interpolation),
799 case Dali::Property::VECTOR4:
801 const KeyFrameVector4* kf;
802 GetSpecialization(keyFrames, kf);
803 KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
804 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
805 target.propertyIndex,
806 target.componentIndex,
807 new KeyFrameVector4Functor(kfCopy,interpolation),
813 case Dali::Property::ROTATION:
815 const KeyFrameQuaternion* kf;
816 GetSpecialization(keyFrames, kf);
817 KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
818 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
819 target.propertyIndex,
820 target.componentIndex,
821 new KeyFrameQuaternionFunctor(kfCopy),
829 // non animatable types handled by keyframes
834 bool Animation::HasFinished()
836 bool hasFinished(false);
837 const int32_t playedCount(mAnimation->GetPlayedCount());
839 // If the play count has been incremented, then another notification is required
840 mCurrentLoop = mAnimation->GetCurrentLoop();
842 if (playedCount > mNotificationCount)
844 // Note that only one signal is emitted, if the animation has been played repeatedly
845 mNotificationCount = playedCount;
849 mState = Dali::Animation::STOPPED;
855 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
857 return mFinishedSignal;
860 Dali::Animation::AnimationSignalType& Animation::ProgressReachedSignal()
862 return mProgressReachedSignal;
865 void Animation::EmitSignalFinish()
867 if ( !mFinishedSignal.Empty() )
869 Dali::Animation handle( this );
870 mFinishedSignal.Emit( handle );
874 void Animation::EmitSignalProgressReached()
876 if ( !mProgressReachedSignal.Empty() )
878 Dali::Animation handle( this );
879 mProgressReachedSignal.Emit( handle );
883 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
885 bool connected( false );
886 Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
888 if( 0 == signalName.compare( SIGNAL_FINISHED ) )
890 animation->FinishedSignal().Connect( tracker, functor );
897 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
899 DALI_ASSERT_DEBUG( NULL != connector );
901 connector->SetParent(*this);
903 mConnectors.PushBack( connector );
906 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
908 Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
911 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
913 Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
916 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
918 Animate( actor, path, forward, mDefaultAlpha, period );
921 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
923 ExtendDuration( period );
925 PathPtr pathCopy = Path::Clone(path);
928 AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
929 Dali::Actor::Property::POSITION,
930 Property::INVALID_COMPONENT_INDEX,
931 new PathPositionFunctor( pathCopy ),
935 //If forward is zero, PathRotationFunctor will always return the unit quaternion
936 if( forward != Vector3::ZERO )
939 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
940 Dali::Actor::Property::ORIENTATION,
941 Property::INVALID_COMPONENT_INDEX,
942 new PathRotationFunctor( pathCopy, forward ),
948 void Animation::Show(Actor& actor, float delaySeconds)
950 ExtendDuration( TimePeriod(delaySeconds, 0) );
952 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
953 Dali::Actor::Property::VISIBLE,
954 Property::INVALID_COMPONENT_INDEX,
955 new AnimateToBoolean(SHOW_VALUE),
957 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
960 void Animation::Hide(Actor& actor, float delaySeconds)
962 ExtendDuration( TimePeriod(delaySeconds, 0) );
964 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
965 Dali::Actor::Property::VISIBLE,
966 Property::INVALID_COMPONENT_INDEX,
967 new AnimateToBoolean(HIDE_VALUE),
969 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
972 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
975 Animation* animation = dynamic_cast<Animation*>( object );
979 if( 0 == actionName.compare( ACTION_PLAY ) )
981 if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
983 animation->SetDuration( value->Get<float>() );
989 else if( 0 == actionName.compare( ACTION_STOP ) )
994 else if( 0 == actionName.compare( ACTION_PAUSE ) )
1004 void Animation::SetCurrentProgress(float progress)
1006 if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
1008 // mAnimation is being used in a separate thread; queue a message to set the current progress
1009 SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
1013 float Animation::GetCurrentProgress()
1015 float progress = 0.f;
1016 if( mAnimation ) // always exists in practice
1018 progress = mAnimation->GetCurrentProgress();
1024 void Animation::ExtendDuration( const TimePeriod& timePeriod )
1026 float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
1028 if( duration > mDurationSeconds )
1030 SetDuration( duration );
1034 void Animation::SetSpeedFactor( float factor )
1038 mSpeedFactor = factor;
1039 SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
1043 float Animation::GetSpeedFactor() const
1045 return mSpeedFactor;
1048 void Animation::SetPlayRange( const Vector2& range)
1050 //Make sure the range specified is between 0.0 and 1.0
1051 if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
1053 Vector2 orderedRange( range );
1054 //If the range is not in order swap values
1055 if( range.x > range.y )
1057 orderedRange = Vector2(range.y, range.x);
1060 // Cache for public getters
1061 mPlayRange = orderedRange;
1063 // mAnimation is being used in a separate thread; queue a message to set play range
1064 SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
1068 Vector2 Animation::GetPlayRange() const
1073 void Animation::SetLoopingMode( Dali::Animation::LoopingMode loopingMode )
1075 mAutoReverseEnabled = ( loopingMode == Dali::Animation::LoopingMode::AUTO_REVERSE );
1077 // mAnimation is being used in a separate thread; queue a message to set play range
1078 SetLoopingModeMessage( mEventThreadServices, *mAnimation, mAutoReverseEnabled );
1081 Dali::Animation::LoopingMode Animation::GetLoopingMode() const
1083 return mAutoReverseEnabled ? Dali::Animation::AUTO_REVERSE : Dali::Animation::RESTART;
1086 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
1088 return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
1091 void Animation::NotifyObjects( Animation::Notify notifyValueType )
1093 // If the animation is discarded, then we do not want to change the target values unless we want to force the current values
1094 if( mEndAction != EndAction::Discard || notifyValueType == Notify::FORCE_CURRENT_VALUE )
1096 // Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
1097 // Only do this if we're using the target value
1098 if( notifyValueType == Notify::USE_TARGET_VALUE )
1100 std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
1103 // Loop through all connector target values sorted by increasing end time
1104 ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
1105 const ConnectorTargetValuesContainer::const_iterator endIter = mConnectorTargetValues.end();
1106 for( ; iter != endIter; ++iter )
1108 AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ];
1110 Object* object = connector->GetObject();
1113 const auto propertyIndex = connector->GetPropertyIndex();
1114 object->NotifyPropertyAnimation(
1117 ( notifyValueType == Notify::USE_TARGET_VALUE ) ? iter->targetValue : object->GetCurrentProperty( propertyIndex ),
1118 ( notifyValueType == Notify::USE_TARGET_VALUE ) ? iter->animatorType : Animation::TO ); // If we're setting the current value, then use TO as we want to set, not adjust, the current value
1125 void Animation::SendFinalProgressNotificationMessage()
1127 if ( mProgressReachedMarker > 0.0f )
1129 float progressMarkerSeconds = mDurationSeconds * mProgressReachedMarker;
1130 SetProgressNotificationMessage( mEventThreadServices, *mAnimation, progressMarkerSeconds );
1134 } // namespace Internal