X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fevent%2Fanimation%2Fanimation-impl.cpp;h=c61b1e3143825bbdfd24ab652c9d40ae1e5aae3e;hb=41e9a0ad46f71f270f69e75a08098f5105275cd3;hp=ec1a6ca4104ebf95f06fb34892286c11a76efafb;hpb=8580a4d8cac9e232d55d8d332af0822c3449727f;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/event/animation/animation-impl.cpp b/dali/internal/event/animation/animation-impl.cpp index ec1a6ca..c61b1e3 100644 --- a/dali/internal/event/animation/animation-impl.cpp +++ b/dali/internal/event/animation/animation-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,20 +22,20 @@ // EXTERNAL INCLUDES // INTERNAL INCLUDES -#include #include #include #include #include #include #include -#include #include #include +#include #include #include #include #include +#include #include using Dali::Internal::SceneGraph::UpdateManager; @@ -82,7 +82,60 @@ const Dali::Animation::EndAction DEFAULT_DISCONNECT_ACTION( Dali::Animation::Bak const Dali::Animation::Interpolation DEFAULT_INTERPOLATION( Dali::Animation::Linear ); const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION( Dali::AlphaFunction::DEFAULT ); -} // anon namespace +/** + * Helper to tell if a property is animatable (if we have animators for it) + * + * @param type type to check + * @return true if animatable + */ +inline bool IsAnimatable( Property::Type type ) +{ + bool animatable = false; + switch( type ) + { + case Property::BOOLEAN : + case Property::FLOAT : + case Property::INTEGER : + case Property::VECTOR2 : + case Property::VECTOR3 : + case Property::VECTOR4 : + case Property::ROTATION : + { + animatable = true; + break; + } + case Property::MATRIX : // matrix is allowed as a scene graph property but there's no animators for it + case Property::MATRIX3 : // matrix3 is allowed as a scene graph property but there's no animators for it + case Property::NONE : + case Property::RECTANGLE : + case Property::STRING : + case Property::ARRAY : + case Property::MAP : + case Property::EXTENTS : + { + break; + } + } + return animatable; +} + +/** + * Helper to validate animation input values + * + * @param propertyType type of the property that is being animated + * @param destinationType type of the target + * @param period time period of the animation + */ +void ValidateParameters( Property::Type propertyType, Property::Type destinationType, const TimePeriod& period ) +{ + // destination value has to be animatable + DALI_ASSERT_ALWAYS( IsAnimatable( propertyType ) && "Property type is not animatable" ); + DALI_ASSERT_ALWAYS( IsAnimatable( destinationType ) && "Target value is not animatable" ); + DALI_ASSERT_ALWAYS( propertyType == destinationType && "Property and target types don't match" ); + DALI_ASSERT_ALWAYS( period.durationSeconds >= 0 && "Duration must be >=0" ); +} + +} // anonymous namespace AnimationPtr Animation::New(float durationSeconds) @@ -113,21 +166,25 @@ AnimationPtr Animation::New(float durationSeconds) } Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha ) -: mEventThreadServices( eventThreadServices ), +: mAnimation( NULL ), + mEventThreadServices( eventThreadServices ), mPlaylist( playlist ), - mAnimation( NULL ), - mNotificationCount( 0 ), - mFinishedCallback( NULL ), - mFinishedCallbackObject( NULL ), + mFinishedSignal(), + mConnectors(), + mConnectorTargetValues(), + mPlayRange( Vector2(0.0f,1.0f)), mDurationSeconds( durationSeconds ), mSpeedFactor(1.0f), + mNotificationCount( 0 ), mLoopCount(1), mCurrentLoop(0), - mPlayRange( Vector2(0.0f,1.0f)), mEndAction( endAction ), mDisconnectAction( disconnectAction ), mDefaultAlpha( defaultAlpha ), - mState(Dali::Animation::STOPPED) + mState(Dali::Animation::STOPPED), + mProgressReachedMarker( 0.0f ), + mDelaySeconds( 0.0f ), + mAutoReverseEnabled( false ) { } @@ -159,14 +216,10 @@ void Animation::CreateSceneObject() { DALI_ASSERT_DEBUG( mAnimation == NULL ); - // Create a new animation, temporarily owned - SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction ); - - // Keep a const pointer to the animation. - mAnimation = animation; - - // Transfer animation ownership to the update manager through a message - AddAnimationMessage( mEventThreadServices.GetUpdateManager(), animation ); + // Create a new animation, Keep a const pointer to the animation. + mAnimation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction ); + OwnerPointer< SceneGraph::Animation > transferOwnership( const_cast< SceneGraph::Animation* >( mAnimation ) ); + AddAnimationMessage( mEventThreadServices.GetUpdateManager(), transferOwnership ); } void Animation::DestroySceneObject() @@ -187,13 +240,23 @@ void Animation::SetDuration(float seconds) seconds = 0.0f; } - // Cache for public getters mDurationSeconds = seconds; // mAnimation is being used in a separate thread; queue a message to set the value SetDurationMessage( mEventThreadServices, *mAnimation, seconds ); } +void Animation::SetProgressNotification( float progress ) +{ + // mAnimation is being used in a separate thread; queue a message to set the value + mProgressReachedMarker = progress; +} + +float Animation::GetProgressNotification() +{ + return mProgressReachedMarker; +} + float Animation::GetDuration() const { // This is not animatable; the cached value is up-to-date. @@ -205,7 +268,7 @@ void Animation::SetLooping(bool on) SetLoopCount( on ? 0 : 1 ); } -void Animation::SetLoopCount(int count) +void Animation::SetLoopCount(int32_t count) { // Cache for public getters mLoopCount = count; @@ -214,12 +277,12 @@ void Animation::SetLoopCount(int count) SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount ); } -int Animation::GetLoopCount() +int32_t Animation::GetLoopCount() { return mLoopCount; } -int Animation::GetCurrentLoop() +int32_t Animation::GetCurrentLoop() { return mCurrentLoop; } @@ -266,6 +329,10 @@ void Animation::Play() mState = Dali::Animation::PLAYING; + NotifyObjects(); + + SendFinalProgressNotificationMessage(); + // mAnimation is being used in a separate thread; queue a Play message PlayAnimationMessage( mEventThreadServices, *mAnimation ); } @@ -279,11 +346,35 @@ void Animation::PlayFrom( float progress ) mState = Dali::Animation::PLAYING; + NotifyObjects(); + + SendFinalProgressNotificationMessage(); + // mAnimation is being used in a separate thread; queue a Play message PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress ); } } +void Animation::PlayAfter( float delaySeconds ) +{ + // The negative delay means play immediately. + delaySeconds = std::max( 0.f, delaySeconds ); + + mDelaySeconds = delaySeconds; + + // Update the current playlist + mPlaylist.OnPlay( *this ); + + mState = Dali::Animation::PLAYING; + + NotifyObjects(); + + SendFinalProgressNotificationMessage(); + + // mAnimation is being used in a separate thread; queue a message to set the value + PlayAfterMessage( mEventThreadServices, *mAnimation, delaySeconds ); +} + void Animation::Pause() { mState = Dali::Animation::PAUSED; @@ -312,6 +403,9 @@ void Animation::Clear() // Remove all the connectors mConnectors.Clear(); + // Reset the connector target values + mConnectorTargetValues.clear(); + // Replace the old scene-object with a new one DestroySceneObject(); CreateSceneObject(); @@ -323,31 +417,43 @@ void Animation::Clear() mPlaylist.OnClear( *this ); } -void Animation::AnimateBy(Property& target, Property::Value& relativeValue) +void Animation::AnimateBy( Property& target, Property::Value& relativeValue ) { - AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds)); + AnimateBy( target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds) ); } -void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha) +void Animation::AnimateBy( Property& target, Property::Value& relativeValue, AlphaFunction alpha ) { - AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds)); + AnimateBy( target, relativeValue, alpha, TimePeriod(mDurationSeconds) ); } -void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period) +void Animation::AnimateBy( Property& target, Property::Value& relativeValue, TimePeriod period ) { - AnimateBy(target, relativeValue, mDefaultAlpha, period); + AnimateBy( target, relativeValue, mDefaultAlpha, period ); } -void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period) +void Animation::AnimateBy( Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period ) { - Object& object = GetImplementation( target.object ); - const Property::Type targetType = object.GetPropertyType( target.propertyIndex ); + Object& object = GetImplementation(target.object); + const Property::Type propertyType = object.GetPropertyType( target.propertyIndex ); const Property::Type destinationType = relativeValue.GetType(); - DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" ); - ExtendDuration( period ); + // validate animation parameters, if component index is set then use float as checked type + ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT, + destinationType, period ); + + ExtendDuration(period); - switch ( targetType ) + // Store data to later notify the object that its property is being animated + ConnectorTargetValues connectorPair; + connectorPair.targetValue = relativeValue; + connectorPair.connectorIndex = mConnectors.Count(); + connectorPair.timePeriod = period; + connectorPair.animatorType = Animation::BY; + mConnectorTargetValues.push_back( connectorPair ); + + // using destination type so component animation gets correct type + switch ( destinationType ) { case Property::BOOLEAN: { @@ -362,12 +468,12 @@ void Animation::AnimateBy(Property& target, Property::Value& relativeValue, Alph case Property::INTEGER: { - AddAnimatorConnector( AnimatorConnector::New( object, - target.propertyIndex, - target.componentIndex, - new AnimateByInteger(relativeValue.Get()), - alpha, - period ) ); + AddAnimatorConnector( AnimatorConnector::New( object, + target.propertyIndex, + target.componentIndex, + new AnimateByInteger(relativeValue.Get()), + alpha, + period ) ); break; } @@ -435,52 +541,49 @@ void Animation::AnimateBy(Property& target, Property::Value& relativeValue, Alph } } -void Animation::AnimateTo(Property& target, Property::Value& destinationValue) -{ - AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds)); -} - -void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha) +void Animation::AnimateTo( Property& target, Property::Value& destinationValue ) { - AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds)); + AnimateTo( target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds) ); } -void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period) +void Animation::AnimateTo( Property& target, Property::Value& destinationValue, AlphaFunction alpha ) { - AnimateTo(target, destinationValue, mDefaultAlpha, period); + AnimateTo( target, destinationValue, alpha, TimePeriod(mDurationSeconds)); } -void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period) +void Animation::AnimateTo( Property& target, Property::Value& destinationValue, TimePeriod period ) { - Object& object = GetImplementation(target.object); - - AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period ); + AnimateTo( target, destinationValue, mDefaultAlpha, period ); } -void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period) +void Animation::AnimateTo( Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period ) { - Property::Type targetType = targetObject.GetPropertyType(targetPropertyIndex); - if( componentIndex != Property::INVALID_COMPONENT_INDEX ) - { - if( ( targetType == Property::VECTOR2 ) || - ( targetType == Property::VECTOR3 ) || - ( targetType == Property::VECTOR4 ) ) - { - targetType = Property::FLOAT; - } - } + Object& object = GetImplementation( target.object ); + const Property::Type propertyType = object.GetPropertyType( target.propertyIndex ); const Property::Type destinationType = destinationValue.GetType(); - DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" ); + + // validate animation parameters, if component index is set then use float as checked type + ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT, + destinationType, period ); ExtendDuration( period ); + // Store data to later notify the object that its property is being animated + ConnectorTargetValues connectorPair; + connectorPair.targetValue = destinationValue; + connectorPair.connectorIndex = mConnectors.Count(); + connectorPair.timePeriod = period; + connectorPair.animatorType = Animation::TO; + mConnectorTargetValues.push_back( connectorPair ); + + // using destination type so component animation gets correct type switch ( destinationType ) { case Property::BOOLEAN: { - AddAnimatorConnector( AnimatorConnector::New( targetObject, - targetPropertyIndex, - componentIndex, + AddAnimatorConnector( AnimatorConnector::New( object, + target.propertyIndex, + target.componentIndex, new AnimateToBoolean( destinationValue.Get() ), alpha, period ) ); @@ -489,45 +592,20 @@ void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIn case Property::INTEGER: { - AddAnimatorConnector( AnimatorConnector::New( targetObject, - targetPropertyIndex, - componentIndex, - new AnimateToInteger( destinationValue.Get() ), - alpha, - period ) ); + AddAnimatorConnector( AnimatorConnector::New( object, + target.propertyIndex, + target.componentIndex, + new AnimateToInteger( destinationValue.Get() ), + alpha, + period ) ); break; } case Property::FLOAT: { - if ( ( Dali::Actor::Property::SIZE_WIDTH == targetPropertyIndex ) || - ( Dali::Actor::Property::SIZE_HEIGHT == targetPropertyIndex ) || - ( Dali::Actor::Property::SIZE_DEPTH == targetPropertyIndex ) ) - { - // Test whether this is actually an Actor - Actor* maybeActor = dynamic_cast( &targetObject ); - if ( maybeActor ) - { - // Notify the actor that its size is being animated - maybeActor->NotifySizeAnimation( *this, destinationValue.Get(), targetPropertyIndex ); - } - } - else if ( ( Dali::Actor::Property::POSITION_X == targetPropertyIndex ) || - ( Dali::Actor::Property::POSITION_Y == targetPropertyIndex ) || - ( Dali::Actor::Property::POSITION_Z == targetPropertyIndex ) ) - { - // Test whether this is actually an Actor - Actor* maybeActor = dynamic_cast( &targetObject ); - if ( maybeActor ) - { - // Notify the actor that its position is being animated - maybeActor->NotifyPositionAnimation( *this, destinationValue.Get(), targetPropertyIndex ); - } - } - - AddAnimatorConnector( AnimatorConnector::New( targetObject, - targetPropertyIndex, - componentIndex, + AddAnimatorConnector( AnimatorConnector::New( object, + target.propertyIndex, + target.componentIndex, new AnimateToFloat( destinationValue.Get() ), alpha, period ) ); @@ -536,9 +614,9 @@ void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIn case Property::VECTOR2: { - AddAnimatorConnector( AnimatorConnector::New( targetObject, - targetPropertyIndex, - componentIndex, + AddAnimatorConnector( AnimatorConnector::New( object, + target.propertyIndex, + target.componentIndex, new AnimateToVector2( destinationValue.Get() ), alpha, period ) ); @@ -547,30 +625,9 @@ void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIn case Property::VECTOR3: { - if ( Dali::Actor::Property::SIZE == targetPropertyIndex ) - { - // Test whether this is actually an Actor - Actor* maybeActor = dynamic_cast( &targetObject ); - if ( maybeActor ) - { - // Notify the actor that its size is being animated - maybeActor->NotifySizeAnimation( *this, destinationValue.Get() ); - } - } - else if ( Dali::Actor::Property::POSITION == targetPropertyIndex ) - { - // Test whether this is actually an Actor - Actor* maybeActor = dynamic_cast( &targetObject ); - if ( maybeActor ) - { - // Notify the actor that its position is being animated - maybeActor->NotifyPositionAnimation( *this, destinationValue.Get() ); - } - } - - AddAnimatorConnector( AnimatorConnector::New( targetObject, - targetPropertyIndex, - componentIndex, + AddAnimatorConnector( AnimatorConnector::New( object, + target.propertyIndex, + target.componentIndex, new AnimateToVector3( destinationValue.Get() ), alpha, period ) ); @@ -579,9 +636,9 @@ void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIn case Property::VECTOR4: { - AddAnimatorConnector( AnimatorConnector::New( targetObject, - targetPropertyIndex, - componentIndex, + AddAnimatorConnector( AnimatorConnector::New( object, + target.propertyIndex, + target.componentIndex, new AnimateToVector4( destinationValue.Get() ), alpha, period ) ); @@ -590,9 +647,9 @@ void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIn case Property::ROTATION: { - AddAnimatorConnector( AnimatorConnector::New( targetObject, - targetPropertyIndex, - componentIndex, + AddAnimatorConnector( AnimatorConnector::New( object, + target.propertyIndex, + target.componentIndex, new RotateToQuaternion( destinationValue.Get() ), alpha, period ) ); @@ -606,48 +663,63 @@ void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIn } } -void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames) +void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames ) { - AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION ); + AnimateBetween( target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION ); } -void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation ) +void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, Interpolation interpolation ) { - AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation ); + AnimateBetween( target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation ); } -void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period) +void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, TimePeriod period ) { - AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION); + AnimateBetween( target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION ); } -void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation) +void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation ) { - AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation); + AnimateBetween( target, keyFrames, mDefaultAlpha, period, interpolation ); } -void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha) +void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha ) { - AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION); + AnimateBetween( target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION ); } -void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation) +void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation ) { - AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation); + AnimateBetween( target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation ); } -void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period) +void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period ) { - AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION); + AnimateBetween( target, keyFrames, alpha, period, DEFAULT_INTERPOLATION ); } -void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation) +void Animation::AnimateBetween( Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation ) { Object& object = GetImplementation( target.object ); + const Property::Type propertyType = object.GetPropertyType( target.propertyIndex ); + const Property::Type destinationType = keyFrames.GetType(); + + // validate animation parameters, if component index is set then use float as checked type + ValidateParameters( (target.componentIndex == Property::INVALID_COMPONENT_INDEX) ? propertyType : Property::FLOAT, + destinationType, period ); ExtendDuration( period ); - switch(keyFrames.GetType()) + // Store data to later notify the object that its property is being animated + ConnectorTargetValues connectorPair; + connectorPair.targetValue = keyFrames.GetLastKeyFrameValue(); + connectorPair.connectorIndex = mConnectors.Count(); + connectorPair.timePeriod = period; + connectorPair.animatorType = BETWEEN; + mConnectorTargetValues.push_back( connectorPair ); + + // using destination type so component animation gets correct type + switch( destinationType ) { case Dali::Property::BOOLEAN: { @@ -668,7 +740,7 @@ void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Alph const KeyFrameInteger* kf; GetSpecialization(keyFrames, kf); KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf); - AddAnimatorConnector( AnimatorConnector::New( object, + AddAnimatorConnector( AnimatorConnector::New( object, target.propertyIndex, target.componentIndex, new KeyFrameIntegerFunctor(kfCopy,interpolation), @@ -757,7 +829,7 @@ void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Alph bool Animation::HasFinished() { bool hasFinished(false); - const int playedCount(mAnimation->GetPlayedCount()); + const int32_t playedCount(mAnimation->GetPlayedCount()); // If the play count has been incremented, then another notification is required mCurrentLoop = mAnimation->GetCurrentLoop(); @@ -780,6 +852,11 @@ Dali::Animation::AnimationSignalType& Animation::FinishedSignal() return mFinishedSignal; } +Dali::Animation::AnimationSignalType& Animation::ProgressReachedSignal() +{ + return mProgressReachedSignal; +} + void Animation::EmitSignalFinish() { if ( !mFinishedSignal.Empty() ) @@ -787,11 +864,14 @@ void Animation::EmitSignalFinish() Dali::Animation handle( this ); mFinishedSignal.Emit( handle ); } +} - // This callback is used internally, to avoid the overhead of using a signal. - if ( mFinishedCallback ) +void Animation::EmitSignalProgressReached() +{ + if ( !mProgressReachedSignal.Empty() ) { - mFinishedCallback( mFinishedCallbackObject ); + Dali::Animation handle( this ); + mProgressReachedSignal.Emit( handle ); } } @@ -813,12 +893,6 @@ bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* return connected; } -void Animation::SetFinishedCallback( FinishedCallback callback, Object* object ) -{ - mFinishedCallback = callback; - mFinishedCallbackObject = object; -} - void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector ) { DALI_ASSERT_DEBUG( NULL != connector ); @@ -994,6 +1068,56 @@ Vector2 Animation::GetPlayRange() const return mPlayRange; } +void Animation::SetLoopingMode( Dali::Animation::LoopingMode loopingMode ) +{ + mAutoReverseEnabled = ( loopingMode == Dali::Animation::LoopingMode::AUTO_REVERSE ); + + // mAnimation is being used in a separate thread; queue a message to set play range + SetLoopingModeMessage( mEventThreadServices, *mAnimation, mAutoReverseEnabled ); +} + +Dali::Animation::LoopingMode Animation::GetLoopingMode() const +{ + return mAutoReverseEnabled ? Dali::Animation::AUTO_REVERSE : Dali::Animation::RESTART; +} + +bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs ) +{ + return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) ); +} + +void Animation::NotifyObjects() +{ + if( mEndAction != EndAction::Discard ) // If the animation is discarded, then we do not want to change the target values + { + // Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved + std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes ); + + // Loop through all connector target values sorted by increasing end time + ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin(); + const ConnectorTargetValuesContainer::const_iterator endIter = mConnectorTargetValues.end(); + for( ; iter != endIter; ++iter ) + { + AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ]; + + Object* object = connector->GetObject(); + if( object ) + { + object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), iter->targetValue, iter->animatorType ); + } + } + } +} + + +void Animation::SendFinalProgressNotificationMessage() +{ + if ( mProgressReachedMarker > 0.0f ) + { + float progressMarkerSeconds = mDurationSeconds * mProgressReachedMarker; + SetProgressNotificationMessage( mEventThreadServices, *mAnimation, progressMarkerSeconds ); + } +} } // namespace Internal