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 static constexpr std::string_view SIGNAL_FINISHED = "finished";
63 static constexpr std::string_view ACTION_PLAY = "play";
64 static constexpr std::string_view ACTION_STOP = "stop";
65 static constexpr std::string_view ACTION_PAUSE = "pause";
69 return Dali::Animation::New(0.f);
72 TypeRegistration mType( typeid( Dali::Animation ), typeid( Dali::BaseHandle ), Create );
74 SignalConnectorType signalConnector1(mType, std::string(SIGNAL_FINISHED), &Animation::DoConnectSignal);
76 TypeAction action1(mType, std::string(ACTION_PLAY), &Animation::DoAction);
77 TypeAction action2(mType, std::string(ACTION_STOP), &Animation::DoAction);
78 TypeAction action3(mType, std::string(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::BAKE_FINAL );
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
140 AnimationPtr Animation::New(float durationSeconds)
142 if( durationSeconds < 0.0f )
144 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
145 durationSeconds = 0.0f;
148 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
149 AnimationPtr animation = new Animation( tls.GetEventThreadServices(), tls.GetAnimationPlaylist(), durationSeconds, DEFAULT_END_ACTION, DEFAULT_DISCONNECT_ACTION, DEFAULT_ALPHA_FUNCTION );
151 // Second-phase construction
152 animation->Initialize();
157 Animation::Animation(EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha)
158 : mEventThreadServices(eventThreadServices),
160 mDefaultAlpha(defaultAlpha),
161 mDurationSeconds(durationSeconds),
162 mEndAction(endAction),
163 mDisconnectAction(disconnectAction)
167 void Animation::Initialize()
169 // Connect to the animation playlist
170 mPlaylist.AnimationCreated( *this );
177 Animation::~Animation()
179 // Guard to allow handle destruction after Core has been destroyed
180 if ( Stage::IsInstalled() )
182 // Disconnect from the animation playlist
183 mPlaylist.AnimationDestroyed( *this );
185 DestroySceneObject();
191 void Animation::CreateSceneObject()
193 DALI_ASSERT_DEBUG( mAnimation == NULL );
195 // Create a new animation, Keep a const pointer to the animation.
196 mAnimation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction );
197 OwnerPointer< SceneGraph::Animation > transferOwnership( const_cast< SceneGraph::Animation* >( mAnimation ) );
198 AddAnimationMessage( mEventThreadServices.GetUpdateManager(), transferOwnership );
201 void Animation::DestroySceneObject()
203 if ( mAnimation != nullptr )
205 // Remove animation using a message to the update manager
206 RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
207 mAnimation = nullptr;
211 void Animation::SetDuration(float seconds)
215 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
219 mDurationSeconds = seconds;
221 // mAnimation is being used in a separate thread; queue a message to set the value
222 SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
225 void Animation::SetProgressNotification( float progress )
227 // mAnimation is being used in a separate thread; queue a message to set the value
228 mProgressReachedMarker = progress;
231 float Animation::GetProgressNotification()
233 return mProgressReachedMarker;
236 float Animation::GetDuration() const
238 // This is not animatable; the cached value is up-to-date.
239 return mDurationSeconds;
242 void Animation::SetLooping(bool on)
244 SetLoopCount( on ? 0 : 1 );
247 void Animation::SetLoopCount(int32_t count)
249 // Cache for public getters
252 // mAnimation is being used in a separate thread; queue a message to set the value
253 SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount );
256 int32_t Animation::GetLoopCount()
261 int32_t Animation::GetCurrentLoop()
266 bool Animation::IsLooping() const
268 return mLoopCount != 1;
271 void Animation::SetEndAction(EndAction action)
273 // Cache for public getters
276 // mAnimation is being used in a separate thread; queue a message to set the value
277 SetEndActionMessage( mEventThreadServices, *mAnimation, action );
280 Dali::Animation::EndAction Animation::GetEndAction() const
282 // This is not animatable; the cached value is up-to-date.
286 void Animation::SetDisconnectAction(EndAction action)
288 // Cache for public getters
289 mDisconnectAction = action;
291 // mAnimation is being used in a separate thread; queue a message to set the value
292 SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
295 Dali::Animation::EndAction Animation::GetDisconnectAction() const
297 // This is not animatable; the cached value is up-to-date.
298 return mDisconnectAction;
301 void Animation::Play()
303 // Update the current playlist
304 mPlaylist.OnPlay( *this );
306 mState = Dali::Animation::PLAYING;
308 NotifyObjects( Notify::USE_TARGET_VALUE );
310 SendFinalProgressNotificationMessage();
312 // mAnimation is being used in a separate thread; queue a Play message
313 PlayAnimationMessage( mEventThreadServices, *mAnimation );
316 void Animation::PlayFrom( float progress )
318 if( progress >= mPlayRange.x && progress <= mPlayRange.y )
320 // Update the current playlist
321 mPlaylist.OnPlay( *this );
323 mState = Dali::Animation::PLAYING;
325 NotifyObjects( Notify::USE_TARGET_VALUE );
327 SendFinalProgressNotificationMessage();
329 // mAnimation is being used in a separate thread; queue a Play message
330 PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
334 void Animation::PlayAfter( float delaySeconds )
336 // The negative delay means play immediately.
337 delaySeconds = std::max( 0.f, delaySeconds );
339 mDelaySeconds = delaySeconds;
341 // Update the current playlist
342 mPlaylist.OnPlay( *this );
344 mState = Dali::Animation::PLAYING;
346 NotifyObjects( Notify::USE_TARGET_VALUE );
348 SendFinalProgressNotificationMessage();
350 // mAnimation is being used in a separate thread; queue a message to set the value
351 PlayAfterMessage( mEventThreadServices, *mAnimation, delaySeconds );
354 void Animation::Pause()
356 mState = Dali::Animation::PAUSED;
358 // mAnimation is being used in a separate thread; queue a Pause message
359 PauseAnimationMessage( mEventThreadServices, *mAnimation );
361 // Notify the objects with the _paused_, i.e. current values
362 NotifyObjects( Notify::FORCE_CURRENT_VALUE );
365 Dali::Animation::State Animation::GetState() const
370 void Animation::Stop()
372 mState = Dali::Animation::STOPPED;
374 // mAnimation is being used in a separate thread; queue a Stop message
375 StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
377 // Only notify the objects with the _stopped_, i.e. current values if the end action is set to BAKE
378 if( mEndAction == EndAction::BAKE )
380 NotifyObjects( Notify::USE_CURRENT_VALUE );
384 void Animation::Clear()
386 DALI_ASSERT_DEBUG(mAnimation);
388 // Only notify the objects with the current values if the end action is set to BAKE
389 if( mEndAction == EndAction::BAKE )
391 NotifyObjects( Notify::USE_CURRENT_VALUE );
394 // Remove all the connectors
397 // Reset the connector target values
398 mConnectorTargetValues.clear();
400 // Replace the old scene-object with a new one
401 DestroySceneObject();
404 // Reset the notification count, since the new scene-object has never been played
405 mNotificationCount = 0;
407 // Update the current playlist
408 mPlaylist.OnClear( *this );
411 void Animation::AnimateBy(Property& target, Property::Value relativeValue)
413 AnimateBy(target, std::move(relativeValue), mDefaultAlpha, TimePeriod(mDurationSeconds));
416 void Animation::AnimateBy(Property& target, Property::Value relativeValue, AlphaFunction alpha)
418 AnimateBy(target, std::move(relativeValue), alpha, TimePeriod(mDurationSeconds));
421 void Animation::AnimateBy(Property& target, Property::Value relativeValue, TimePeriod period)
423 AnimateBy(target, std::move(relativeValue), mDefaultAlpha, period);
426 void Animation::AnimateBy(Property& target, Property::Value relativeValue, AlphaFunction alpha, TimePeriod period)
428 Object& object = GetImplementation(target.object);
429 const Property::Type propertyType = object.GetPropertyType( target.propertyIndex );
430 const Property::Type destinationType = relativeValue.GetType();
432 // validate animation parameters, if component index is set then use float as checked type
433 ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT,
434 destinationType, period );
436 ExtendDuration(period);
438 // keep the current count.
439 auto connectorIndex = mConnectors.Count();
441 // using destination type so component animation gets correct type
442 switch ( destinationType )
444 case Property::BOOLEAN:
446 AddAnimatorConnector(AnimatorConnector<bool>::New(object,
447 target.propertyIndex,
448 target.componentIndex,
449 AnimateByBoolean(relativeValue.Get<bool>()),
455 case Property::INTEGER:
457 AddAnimatorConnector(AnimatorConnector<int32_t>::New(object,
458 target.propertyIndex,
459 target.componentIndex,
460 AnimateByInteger(relativeValue.Get<int32_t>()),
466 case Property::FLOAT:
468 AddAnimatorConnector(AnimatorConnector<float>::New(object,
469 target.propertyIndex,
470 target.componentIndex,
471 AnimateByFloat(relativeValue.Get<float>()),
477 case Property::VECTOR2:
479 AddAnimatorConnector(AnimatorConnector<Vector2>::New(object,
480 target.propertyIndex,
481 target.componentIndex,
482 AnimateByVector2(relativeValue.Get<Vector2>()),
488 case Property::VECTOR3:
490 AddAnimatorConnector(AnimatorConnector<Vector3>::New(object,
491 target.propertyIndex,
492 target.componentIndex,
493 AnimateByVector3(relativeValue.Get<Vector3>()),
499 case Property::VECTOR4:
501 AddAnimatorConnector(AnimatorConnector<Vector4>::New(object,
502 target.propertyIndex,
503 target.componentIndex,
504 AnimateByVector4(relativeValue.Get<Vector4>()),
510 case Property::ROTATION:
512 AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
514 AddAnimatorConnector(AnimatorConnector<Quaternion>::New(object,
515 target.propertyIndex,
516 target.componentIndex,
517 RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
525 DALI_ASSERT_DEBUG(false && "Property not supported");
528 // Store data to later notify the object that its property is being animated
529 mConnectorTargetValues.push_back({std::move(relativeValue), period, connectorIndex, Animation::BY});
532 void Animation::AnimateTo(Property& target, Property::Value destinationValue)
534 AnimateTo(target, std::move(destinationValue), mDefaultAlpha, TimePeriod(mDurationSeconds));
537 void Animation::AnimateTo(Property& target, Property::Value destinationValue, AlphaFunction alpha)
539 AnimateTo(target, std::move(destinationValue), alpha, TimePeriod(mDurationSeconds));
542 void Animation::AnimateTo(Property& target, Property::Value destinationValue, TimePeriod period)
544 AnimateTo(target, std::move(destinationValue), mDefaultAlpha, period);
547 void Animation::AnimateTo(Property& target, Property::Value destinationValue, AlphaFunction alpha, TimePeriod period)
549 Object& object = GetImplementation( target.object );
550 const Property::Type propertyType = object.GetPropertyType( target.propertyIndex );
551 const Property::Type destinationType = destinationValue.GetType();
553 // validate animation parameters, if component index is set then use float as checked type
554 ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT,
555 destinationType, period );
557 ExtendDuration( period );
559 // keep the current count.
560 auto connectorIndex = mConnectors.Count();
562 // using destination type so component animation gets correct type
563 switch ( destinationType )
565 case Property::BOOLEAN:
567 AddAnimatorConnector(AnimatorConnector<bool>::New(object,
568 target.propertyIndex,
569 target.componentIndex,
570 AnimateToBoolean(destinationValue.Get<bool>()),
576 case Property::INTEGER:
578 AddAnimatorConnector(AnimatorConnector<int32_t>::New(object,
579 target.propertyIndex,
580 target.componentIndex,
581 AnimateToInteger(destinationValue.Get<int32_t>()),
587 case Property::FLOAT:
589 AddAnimatorConnector(AnimatorConnector<float>::New(object,
590 target.propertyIndex,
591 target.componentIndex,
592 AnimateToFloat(destinationValue.Get<float>()),
598 case Property::VECTOR2:
600 AddAnimatorConnector(AnimatorConnector<Vector2>::New(object,
601 target.propertyIndex,
602 target.componentIndex,
603 AnimateToVector2(destinationValue.Get<Vector2>()),
609 case Property::VECTOR3:
611 AddAnimatorConnector(AnimatorConnector<Vector3>::New(object,
612 target.propertyIndex,
613 target.componentIndex,
614 AnimateToVector3(destinationValue.Get<Vector3>()),
620 case Property::VECTOR4:
622 AddAnimatorConnector(AnimatorConnector<Vector4>::New(object,
623 target.propertyIndex,
624 target.componentIndex,
625 AnimateToVector4(destinationValue.Get<Vector4>()),
631 case Property::ROTATION:
633 AddAnimatorConnector(AnimatorConnector<Quaternion>::New(object,
634 target.propertyIndex,
635 target.componentIndex,
636 RotateToQuaternion(destinationValue.Get<Quaternion>()),
644 DALI_ASSERT_DEBUG(false && "Property not supported");
647 // Store data to later notify the object that its property is being animated
648 mConnectorTargetValues.push_back({std::move(destinationValue), period, connectorIndex, Animation::TO});
651 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames )
653 AnimateBetween( target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
656 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, Interpolation interpolation )
658 AnimateBetween( target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
661 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, TimePeriod period )
663 AnimateBetween( target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION );
666 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation )
668 AnimateBetween( target, keyFrames, mDefaultAlpha, period, interpolation );
671 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha )
673 AnimateBetween( target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
676 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation )
678 AnimateBetween( target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation );
681 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period )
683 AnimateBetween( target, keyFrames, alpha, period, DEFAULT_INTERPOLATION );
686 void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation )
688 Object& object = GetImplementation( target.object );
689 const Property::Type propertyType = object.GetPropertyType( target.propertyIndex );
690 const Property::Type destinationType = keyFrames.GetType();
692 // validate animation parameters, if component index is set then use float as checked type
693 ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT,
694 destinationType, period );
696 ExtendDuration( period );
698 // Store data to later notify the object that its property is being animated
699 mConnectorTargetValues.push_back({keyFrames.GetLastKeyFrameValue(), period, mConnectors.Count(), BETWEEN});
701 // using destination type so component animation gets correct type
702 switch( destinationType )
704 case Dali::Property::BOOLEAN:
706 auto kf = GetSpecialization<const KeyFrameBoolean*>(keyFrames);
707 AddAnimatorConnector(AnimatorConnector<bool>::New(object,
708 target.propertyIndex,
709 target.componentIndex,
710 KeyFrameBooleanFunctor(*kf), // takes a copy of the keyframe
716 case Dali::Property::INTEGER:
718 auto kf = GetSpecialization<const KeyFrameInteger*>(keyFrames);
719 AddAnimatorConnector(AnimatorConnector<int32_t>::New(object,
720 target.propertyIndex,
721 target.componentIndex,
722 KeyFrameIntegerFunctor(*kf, interpolation), // takes a copy of the keyframe
728 case Dali::Property::FLOAT:
730 auto kf = GetSpecialization<const KeyFrameNumber*>(keyFrames);
731 AddAnimatorConnector(AnimatorConnector<float>::New(object,
732 target.propertyIndex,
733 target.componentIndex,
734 KeyFrameNumberFunctor(*kf, interpolation), // takes a copy of the keyframe
740 case Dali::Property::VECTOR2:
742 auto kf = GetSpecialization<const KeyFrameVector2*>(keyFrames);
743 AddAnimatorConnector(AnimatorConnector<Vector2>::New(object,
744 target.propertyIndex,
745 target.componentIndex,
746 KeyFrameVector2Functor(*kf, interpolation), // takes a copy of the keyframe
752 case Dali::Property::VECTOR3:
754 auto kf = GetSpecialization<const KeyFrameVector3*>(keyFrames);
755 AddAnimatorConnector(AnimatorConnector<Vector3>::New(object,
756 target.propertyIndex,
757 target.componentIndex,
758 KeyFrameVector3Functor(*kf, interpolation), // takes a copy of the keyframe
764 case Dali::Property::VECTOR4:
766 auto kf = GetSpecialization<const KeyFrameVector4*>(keyFrames);
767 AddAnimatorConnector(AnimatorConnector<Vector4>::New(object,
768 target.propertyIndex,
769 target.componentIndex,
770 KeyFrameVector4Functor(*kf, interpolation), // takes a copy of the keyframe
776 case Dali::Property::ROTATION:
778 auto kf = GetSpecialization<const KeyFrameQuaternion*>(keyFrames);
779 AddAnimatorConnector(AnimatorConnector<Quaternion>::New(object,
780 target.propertyIndex,
781 target.componentIndex,
782 KeyFrameQuaternionFunctor(*kf), // takes a copy of the keyframe
790 DALI_ASSERT_DEBUG(false && "Property not supported");
795 bool Animation::HasFinished()
797 bool hasFinished(false);
798 const int32_t playedCount(mAnimation->GetPlayedCount());
800 // If the play count has been incremented, then another notification is required
801 mCurrentLoop = mAnimation->GetCurrentLoop();
803 if (playedCount > mNotificationCount)
805 // Note that only one signal is emitted, if the animation has been played repeatedly
806 mNotificationCount = playedCount;
810 mState = Dali::Animation::STOPPED;
816 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
818 return mFinishedSignal;
821 Dali::Animation::AnimationSignalType& Animation::ProgressReachedSignal()
823 return mProgressReachedSignal;
826 void Animation::EmitSignalFinish()
828 if ( !mFinishedSignal.Empty() )
830 Dali::Animation handle( this );
831 mFinishedSignal.Emit( handle );
835 void Animation::EmitSignalProgressReached()
837 if ( !mProgressReachedSignal.Empty() )
839 Dali::Animation handle( this );
840 mProgressReachedSignal.Emit( handle );
844 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
846 bool connected( false );
847 Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
849 if(SIGNAL_FINISHED == signalName)
851 animation->FinishedSignal().Connect( tracker, functor );
858 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
860 DALI_ASSERT_DEBUG( NULL != connector );
862 connector->SetParent(*this);
864 mConnectors.PushBack( connector );
867 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
869 Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
872 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
874 Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
877 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
879 Animate( actor, path, forward, mDefaultAlpha, period );
882 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
884 ExtendDuration( period );
886 PathPtr pathCopy = Path::Clone(path);
889 AddAnimatorConnector(AnimatorConnector<Vector3>::New(actor,
890 Dali::Actor::Property::POSITION,
891 Property::INVALID_COMPONENT_INDEX,
892 PathPositionFunctor(pathCopy),
896 //If forward is zero, PathRotationFunctor will always return the unit quaternion
897 if( forward != Vector3::ZERO )
900 AddAnimatorConnector(AnimatorConnector<Quaternion>::New(actor,
901 Dali::Actor::Property::ORIENTATION,
902 Property::INVALID_COMPONENT_INDEX,
903 PathRotationFunctor(pathCopy, forward),
909 void Animation::Show(Actor& actor, float delaySeconds)
911 ExtendDuration( TimePeriod(delaySeconds, 0) );
913 AddAnimatorConnector(AnimatorConnector<bool>::New(actor,
914 Dali::Actor::Property::VISIBLE,
915 Property::INVALID_COMPONENT_INDEX,
916 AnimateToBoolean(SHOW_VALUE),
918 TimePeriod(delaySeconds, 0.0f /*immediate*/)));
921 void Animation::Hide(Actor& actor, float delaySeconds)
923 ExtendDuration( TimePeriod(delaySeconds, 0) );
925 AddAnimatorConnector(AnimatorConnector<bool>::New(actor,
926 Dali::Actor::Property::VISIBLE,
927 Property::INVALID_COMPONENT_INDEX,
928 AnimateToBoolean(HIDE_VALUE),
930 TimePeriod(delaySeconds, 0.0f /*immediate*/)));
933 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
936 Animation* animation = dynamic_cast<Animation*>( object );
940 std::string_view name(actionName);
942 if(name == ACTION_PLAY)
944 if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
946 animation->SetDuration( value->Get<float>() );
952 else if(name == ACTION_STOP)
957 else if(name == ACTION_PAUSE)
967 void Animation::SetCurrentProgress(float progress)
969 if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
971 // mAnimation is being used in a separate thread; queue a message to set the current progress
972 SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
976 float Animation::GetCurrentProgress()
978 float progress = 0.f;
979 if( mAnimation ) // always exists in practice
981 progress = mAnimation->GetCurrentProgress();
987 void Animation::ExtendDuration( const TimePeriod& timePeriod )
989 float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
991 if( duration > mDurationSeconds )
993 SetDuration( duration );
997 void Animation::SetSpeedFactor( float factor )
1001 mSpeedFactor = factor;
1002 SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
1006 float Animation::GetSpeedFactor() const
1008 return mSpeedFactor;
1011 void Animation::SetPlayRange( const Vector2& range)
1013 //Make sure the range specified is between 0.0 and 1.0
1014 if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
1016 Vector2 orderedRange( range );
1017 //If the range is not in order swap values
1018 if( range.x > range.y )
1020 orderedRange = Vector2(range.y, range.x);
1023 // Cache for public getters
1024 mPlayRange = orderedRange;
1026 // mAnimation is being used in a separate thread; queue a message to set play range
1027 SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
1031 Vector2 Animation::GetPlayRange() const
1036 void Animation::SetLoopingMode( Dali::Animation::LoopingMode loopingMode )
1038 mAutoReverseEnabled = ( loopingMode == Dali::Animation::LoopingMode::AUTO_REVERSE );
1040 // mAnimation is being used in a separate thread; queue a message to set play range
1041 SetLoopingModeMessage( mEventThreadServices, *mAnimation, mAutoReverseEnabled );
1044 Dali::Animation::LoopingMode Animation::GetLoopingMode() const
1046 return mAutoReverseEnabled ? Dali::Animation::AUTO_REVERSE : Dali::Animation::RESTART;
1049 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
1051 return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
1054 void Animation::NotifyObjects( Animation::Notify notifyValueType )
1056 // If the animation is discarded, then we do not want to change the target values unless we want to force the current values
1057 if( mEndAction != EndAction::DISCARD || notifyValueType == Notify::FORCE_CURRENT_VALUE )
1059 // Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
1060 // Only do this if we're using the target value
1061 if( notifyValueType == Notify::USE_TARGET_VALUE )
1063 std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
1066 // Loop through all connector target values sorted by increasing end time
1067 ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
1068 const ConnectorTargetValuesContainer::const_iterator endIter = mConnectorTargetValues.end();
1069 for( ; iter != endIter; ++iter )
1071 AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ];
1073 Object* object = connector->GetObject();
1074 if(object && object->IsAnimationPossible())
1076 const auto propertyIndex = connector->GetPropertyIndex();
1077 object->NotifyPropertyAnimation(
1080 ( notifyValueType == Notify::USE_TARGET_VALUE ) ? iter->targetValue : object->GetCurrentProperty( propertyIndex ),
1081 ( 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
1088 void Animation::SendFinalProgressNotificationMessage()
1090 if ( mProgressReachedMarker > 0.0f )
1092 float progressMarkerSeconds = mDurationSeconds * mProgressReachedMarker;
1093 SetProgressNotificationMessage( mEventThreadServices, *mAnimation, progressMarkerSeconds );
1097 } // namespace Internal