X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fevent%2Fevents%2Fpan-gesture-processor.cpp;h=1762821611ea8af75e9a7abb16c074c70813e577;hb=cd0ce6e412df8961b1a5e28b496369fa49fd72d7;hp=8b3d2e370e8e0bb0aa5487d1ae784d820301e240;hpb=7dcb0a38005dd8c6d71e466c1ea0ec4d7d57239f;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/event/events/pan-gesture-processor.cpp b/dali/internal/event/events/pan-gesture-processor.cpp index 8b3d2e3..1762821 100644 --- a/dali/internal/event/events/pan-gesture-processor.cpp +++ b/dali/internal/event/events/pan-gesture-processor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 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. @@ -59,7 +59,7 @@ struct IsNotAttachedAndOutsideTouchesRangeFunctor * @param[in] touches The number of touches in the current pan event. * @param[in] outsideRangeEmitters Reference to container where emitters outside of the touches range should be added. */ - IsNotAttachedAndOutsideTouchesRangeFunctor(Actor* actor, unsigned int touches, PanGestureDetectorContainer& outsideRangeEmitters) + IsNotAttachedAndOutsideTouchesRangeFunctor(Actor* actor, unsigned int touches, GestureDetectorContainer& outsideRangeEmitters) : actorToCheck(actor), numberOfTouches(touches), outsideTouchesRangeEmitters(outsideRangeEmitters) @@ -73,16 +73,18 @@ struct IsNotAttachedAndOutsideTouchesRangeFunctor * @param[in] detector The detector to check. * @return true, if not attached, false otherwise. */ - bool operator()(PanGestureDetector* detector) const + bool operator()(GestureDetector* detector) const { bool remove(!detector->IsAttached(*actorToCheck)); if (!remove) { + PanGestureDetector* panDetector( static_cast< PanGestureDetector* >( detector ) ); + // Ensure number of touch points is within the range of our emitter. If it isn't then remove // this emitter and add it to the outsideTouchesRangeEmitters container - if ( (numberOfTouches < detector->GetMinimumTouchesRequired()) || - (numberOfTouches > detector->GetMaximumTouchesRequired()) ) + if ( (numberOfTouches < panDetector->GetMinimumTouchesRequired()) || + (numberOfTouches > panDetector->GetMaximumTouchesRequired()) ) { remove = true; outsideTouchesRangeEmitters.push_back(detector); @@ -94,126 +96,14 @@ struct IsNotAttachedAndOutsideTouchesRangeFunctor Actor* actorToCheck; ///< The actor to check whether it is attached or not. unsigned int numberOfTouches; ///< The number of touches in the pan event. - PanGestureDetectorContainer& outsideTouchesRangeEmitters; ///< Emitters that are outside of the range of current pan. + GestureDetectorContainer& outsideTouchesRangeEmitters; ///< Emitters that are outside of the range of current pan. }; } // unnamed namespace -struct PanGestureProcessor::PanEventFunctor : public GestureProcessor::Functor -{ - /** - * Constructor - * @param[in] panEvent The current gesture event. - * @param[in] processor Reference to the processor. - */ - PanEventFunctor( const Integration::PanGestureEvent& panEvent, PanGestureProcessor& processor ) - : panEvent( panEvent ), - processor( processor ) - { - } - - /** - * Check if the detector meets the current gesture event parameters. - */ - virtual bool operator() ( GestureDetector* detector, Actor* actor ) - { - bool retVal( false ); - - PanGestureDetector* panDetector( static_cast< PanGestureDetector* >( detector ) ); - - if ( ( panEvent.numberOfTouches >= panDetector->GetMinimumTouchesRequired() ) && - ( panEvent.numberOfTouches <= panDetector->GetMaximumTouchesRequired() ) ) - { - // Check if the detector requires directional panning. - if ( panDetector->RequiresDirectionalPan() && processor.mCurrentRenderTask ) - { - // It does, calculate the angle of the pan in local actor coordinates and ensures it fits - // the detector's criteria. - RenderTask& renderTaskImpl( GetImplementation( processor.mCurrentRenderTask ) ); - - Vector2 startPosition, currentPosition; - actor->ScreenToLocal( renderTaskImpl, startPosition.x, startPosition.y, processor.mPossiblePanPosition.x, processor.mPossiblePanPosition.y ); - actor->ScreenToLocal( renderTaskImpl, currentPosition.x, currentPosition.y, panEvent.currentPosition.x, panEvent.currentPosition.y ); - Vector2 displacement( currentPosition - startPosition ); - - Radian angle( atan( displacement.y / displacement.x ) ); - - ///////////////////////////// - // | // - // | // - // Q3 (-,-) | Q4 (+,-) // - // | // - // ----------------- +x // - // | // - // Q2 (-,+) | Q1 (+,+) // - // | // - // | // - // +y // - ///////////////////////////// - // Quadrant 1: As is - // Quadrant 2: 180 degrees + angle - // Quadrant 3: angle - 180 degrees - // Quadrant 4: As is - ///////////////////////////// - - if ( displacement.x < 0.0f ) - { - if ( displacement.y >= 0.0f ) - { - // Quadrant 2 - angle += Math::PI; - } - else - { - // Quadrant 3 - angle -= Math::PI; - } - } - - if ( panDetector->CheckAngleAllowed( angle ) ) - { - retVal = true; - } - } - else - { - // Directional panning not required so we can use this actor and gesture detector. - retVal = true; - } - } - - return retVal; - } - - /** - * Gestured actor and gesture detectors that meet the gesture's parameters found, emit and save required information. - */ - virtual void operator() ( Dali::Actor actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates ) - { - PanGestureDetectorContainer derivedContainer; - DownCastContainer( gestureDetectors, derivedContainer ); - - processor.mCurrentPanEmitters.clear(); - processor.ResetActor(); - - Actor* actorImpl( &GetImplementation( actor ) ); - actorImpl->ScreenToLocal( GetImplementation(processor.mCurrentRenderTask), actorCoordinates.x, actorCoordinates.y, panEvent.currentPosition.x, panEvent.currentPosition.y ); - - processor.EmitPanSignal( actor, derivedContainer, panEvent, actorCoordinates, panEvent.state, processor.mCurrentRenderTask ); - - if ( actorImpl->OnStage() ) - { - processor.mCurrentPanEmitters = derivedContainer; - processor.SetActor( actor ); - } - } - - const Integration::PanGestureEvent& panEvent; - PanGestureProcessor& processor; -}; - -PanGestureProcessor::PanGestureProcessor( Stage& stage, Integration::GestureManager& gestureManager ) -: mStage( stage ), +PanGestureProcessor::PanGestureProcessor( Stage& stage, Integration::GestureManager& gestureManager, SceneGraph::UpdateManager& updateManager ) +: GestureProcessor( Gesture::Pan ), + mStage( stage ), mGestureManager( gestureManager ), mGestureDetectors(), mCurrentPanEmitters(), @@ -221,19 +111,16 @@ PanGestureProcessor::PanGestureProcessor( Stage& stage, Integration::GestureMana mPossiblePanPosition(), mMinTouchesRequired( 1 ), mMaxTouchesRequired( 1 ), + mCurrentPanEvent( NULL ), mSceneObject( SceneGraph::PanGesture::New() ) // Create scene object to store pan information. { - // Pass ownership to scene-graph - AddGestureMessage( mStage.GetUpdateManager(), mSceneObject ); + // Pass ownership to scene-graph; scene object lives for the lifecycle of UpdateManager + updateManager.SetPanGestureProcessor( mSceneObject ); } PanGestureProcessor::~PanGestureProcessor() { - if( Stage::IsInstalled() && ( mSceneObject != NULL ) ) - { - RemoveGestureMessage( mStage.GetUpdateManager(), mSceneObject ); - mSceneObject = NULL; // mSceneObject is about to be destroyed - } + mSceneObject = NULL; // mSceneObject is owned and destroyed by update manager (there is only one of these for now) } void PanGestureProcessor::Process( const Integration::PanGestureEvent& panEvent ) @@ -248,7 +135,7 @@ void PanGestureProcessor::Process( const Integration::PanGestureEvent& panEvent HitTestAlgorithm::Results hitTestResults; if( HitTest( mStage, panEvent.currentPosition, hitTestResults ) ) { - SetActor( hitTestResults.actor ); + SetActor( &GetImplementation( hitTestResults.actor ) ); mPossiblePanPosition = panEvent.currentPosition; } @@ -263,17 +150,17 @@ void PanGestureProcessor::Process( const Integration::PanGestureEvent& panEvent // it can be told when the gesture ends as well. HitTestAlgorithm::Results hitTestResults; - HitTestAlgorithm::HitTest( mStage, mPossiblePanPosition, hitTestResults ); // Hit test original possible position... + HitTest( mStage, mPossiblePanPosition, hitTestResults ); // Hit test original possible position... if ( hitTestResults.actor && ( GetCurrentGesturedActor() == &GetImplementation( hitTestResults.actor ) ) ) { // Record the current render-task for Screen->Actor coordinate conversions mCurrentRenderTask = hitTestResults.renderTask; - PanEventFunctor functor( panEvent, *this ); - GestureDetectorContainer gestureDetectors; - UpCastContainer( mGestureDetectors, gestureDetectors ); - ProcessAndEmit( hitTestResults, gestureDetectors, functor ); + // Set mCurrentPanEvent to use inside overridden methods called in ProcessAndEmit() + mCurrentPanEvent = &panEvent; + ProcessAndEmit( hitTestResults ); + mCurrentPanEvent = NULL; } else { @@ -296,12 +183,12 @@ void PanGestureProcessor::Process( const Integration::PanGestureEvent& panEvent { if ( currentGesturedActor->IsHittable() && !mCurrentPanEmitters.empty() && mCurrentRenderTask ) { - PanGestureDetectorContainer outsideTouchesRangeEmitters; + GestureDetectorContainer outsideTouchesRangeEmitters; // Removes emitters that no longer have the actor attached // Also remove emitters whose touches are outside the range of the current pan event and add them to outsideTouchesRangeEmitters - PanGestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(), - IsNotAttachedAndOutsideTouchesRangeFunctor(currentGesturedActor, panEvent.numberOfTouches, outsideTouchesRangeEmitters) ); + GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(), + IsNotAttachedAndOutsideTouchesRangeFunctor(currentGesturedActor, panEvent.numberOfTouches, outsideTouchesRangeEmitters) ); mCurrentPanEmitters.erase( endIter, mCurrentPanEmitters.end() ); Vector2 actorCoords; @@ -311,8 +198,8 @@ void PanGestureProcessor::Process( const Integration::PanGestureEvent& panEvent currentGesturedActor->ScreenToLocal( GetImplementation( mCurrentRenderTask ), actorCoords.x, actorCoords.y, panEvent.currentPosition.x, panEvent.currentPosition.y ); // EmitPanSignal checks whether we have a valid actor and whether the container we are passing in has emitters before it emits the pan. - EmitPanSignal(Dali::Actor(currentGesturedActor), outsideTouchesRangeEmitters, panEvent, actorCoords, Gesture::Finished, mCurrentRenderTask); - EmitPanSignal(Dali::Actor(currentGesturedActor), mCurrentPanEmitters, panEvent, actorCoords, panEvent.state, mCurrentRenderTask); + EmitPanSignal( currentGesturedActor, outsideTouchesRangeEmitters, panEvent, actorCoords, Gesture::Finished, mCurrentRenderTask); + EmitPanSignal( currentGesturedActor, mCurrentPanEmitters, panEvent, actorCoords, panEvent.state, mCurrentRenderTask); } if ( mCurrentPanEmitters.empty() ) @@ -338,8 +225,10 @@ void PanGestureProcessor::Process( const Integration::PanGestureEvent& panEvent } case Gesture::Clear: - DALI_ASSERT_ALWAYS( false && "Incorrect state received from Integration layer: Clear\n" ); + { + DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" ); break; + } } } @@ -373,7 +262,7 @@ void PanGestureProcessor::RemoveGestureDetector( PanGestureDetector* gestureDete if (!mCurrentPanEmitters.empty()) { // Check if the removed detector was one that is currently being panned and remove it from emitters. - PanGestureDetectorContainer::iterator endIter = std::remove( mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(), gestureDetector ); + GestureDetectorContainer::iterator endIter = std::remove( mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(), gestureDetector ); mCurrentPanEmitters.erase( endIter, mCurrentPanEmitters.end() ); // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well @@ -435,6 +324,82 @@ void PanGestureProcessor::SetPredictionMode(int mode) mSceneObject->SetPredictionMode(modeEnum); } +void PanGestureProcessor::SetPredictionAmount(unsigned int amount) +{ + mSceneObject->SetPredictionAmount(amount); +} + +void PanGestureProcessor::SetMaximumPredictionAmount(unsigned int amount) +{ + mSceneObject->SetMaximumPredictionAmount(amount); +} + +void PanGestureProcessor::SetMinimumPredictionAmount(unsigned int amount) +{ + mSceneObject->SetMinimumPredictionAmount(amount); +} + +void PanGestureProcessor::SetPredictionAmountAdjustment(unsigned int amount) +{ + mSceneObject->SetPredictionAmountAdjustment(amount); +} + +void PanGestureProcessor::SetSmoothingMode(int mode) +{ + if( (mode < 0) + || (mode >= SceneGraph::PanGesture::NUM_SMOOTHING_MODES) ) + { + mode = SceneGraph::PanGesture::DEFAULT_SMOOTHING_MODE; + } + SceneGraph::PanGesture::SmoothingMode modeEnum = static_cast(mode); + mSceneObject->SetSmoothingMode(modeEnum); +} + +void PanGestureProcessor::SetSmoothingAmount(float amount) +{ + mSceneObject->SetSmoothingAmount(amount); +} + +void PanGestureProcessor::SetUseActualTimes( bool value ) +{ + mSceneObject->SetUseActualTimes( value ); +} + +void PanGestureProcessor::SetInterpolationTimeRange( int value ) +{ + mSceneObject->SetInterpolationTimeRange( value ); +} + +void PanGestureProcessor::SetScalarOnlyPredictionEnabled( bool value ) +{ + mSceneObject->SetScalarOnlyPredictionEnabled( value ); +} + +void PanGestureProcessor::SetTwoPointPredictionEnabled( bool value ) +{ + mSceneObject->SetTwoPointPredictionEnabled( value ); +} + +void PanGestureProcessor::SetTwoPointInterpolatePastTime( int value ) +{ + mSceneObject->SetTwoPointInterpolatePastTime( value ); +} + +void PanGestureProcessor::SetTwoPointVelocityBias( float value ) +{ + mSceneObject->SetTwoPointVelocityBias( value ); +} + +void PanGestureProcessor::SetTwoPointAccelerationBias( float value ) +{ + mSceneObject->SetTwoPointAccelerationBias( value ); +} + +void PanGestureProcessor::SetMultitapSmoothingRange( int value ) +{ + mSceneObject->SetMultitapSmoothingRange( value ); +} + void PanGestureProcessor::UpdateDetection() { DALI_ASSERT_DEBUG(!mGestureDetectors.empty()); @@ -446,16 +411,19 @@ void PanGestureProcessor::UpdateDetection() { PanGestureDetector* detector(*iter); - unsigned int minimum = detector->GetMinimumTouchesRequired(); - if (minimum < minimumRequired) + if( detector ) { - minimumRequired = minimum; - } + unsigned int minimum = detector->GetMinimumTouchesRequired(); + if (minimum < minimumRequired) + { + minimumRequired = minimum; + } - unsigned int maximum = detector->GetMaximumTouchesRequired(); - if (maximum > maximumRequired) - { - maximumRequired = maximum; + unsigned int maximum = detector->GetMaximumTouchesRequired(); + if (maximum > maximumRequired) + { + maximumRequired = maximum; + } } } @@ -471,17 +439,15 @@ void PanGestureProcessor::UpdateDetection() } } -void PanGestureProcessor::EmitPanSignal( Dali::Actor actorHandle, - PanGestureDetectorContainer& gestureDetectors, +void PanGestureProcessor::EmitPanSignal( Actor* actor, + const GestureDetectorContainer& gestureDetectors, const Integration::PanGestureEvent& panEvent, Vector2 localCurrent, Gesture::State state, Dali::RenderTask renderTask ) { - if ( actorHandle && !gestureDetectors.empty() ) + if ( actor && !gestureDetectors.empty() ) { - Actor& actor = GetImplementation(actorHandle); - PanGesture pan(state); pan.time = panEvent.time; @@ -492,7 +458,7 @@ void PanGestureProcessor::EmitPanSignal( Dali::Actor actorHandle, RenderTask& renderTaskImpl( GetImplementation( renderTask ) ); Vector2 localPrevious; - actor.ScreenToLocal( renderTaskImpl, localPrevious.x, localPrevious.y, panEvent.previousPosition.x, panEvent.previousPosition.y ); + actor->ScreenToLocal( renderTaskImpl, localPrevious.x, localPrevious.y, panEvent.previousPosition.x, panEvent.previousPosition.y ); pan.displacement = localCurrent - localPrevious; Vector2 previousPos( panEvent.previousPosition ); @@ -503,11 +469,15 @@ void PanGestureProcessor::EmitPanSignal( Dali::Actor actorHandle, pan.screenDisplacement = panEvent.currentPosition - previousPos; - pan.velocity.x = pan.displacement.x / panEvent.timeDelta; - pan.velocity.y = pan.displacement.y / panEvent.timeDelta; + // Avoid dividing by 0 + if ( panEvent.timeDelta > 0 ) + { + pan.velocity.x = pan.displacement.x / static_cast( panEvent.timeDelta ); + pan.velocity.y = pan.displacement.y / static_cast( panEvent.timeDelta ); - pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta; - pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta; + pan.screenVelocity.x = pan.screenDisplacement.x / static_cast( panEvent.timeDelta ); + pan.screenVelocity.y = pan.screenDisplacement.y / static_cast( panEvent.timeDelta ); + } // When the gesture ends, we may incorrectly get a ZERO velocity (as we have lifted our finger without any movement) // so we should use the last recorded velocity instead in this scenario. @@ -531,9 +501,11 @@ void PanGestureProcessor::EmitPanSignal( Dali::Actor actorHandle, mSceneObject->AddGesture( pan ); } - for ( PanGestureDetectorContainer::iterator iter = gestureDetectors.begin(), endIter = gestureDetectors.end(); iter != endIter; ++iter ) + Dali::Actor actorHandle( actor ); + const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end(); + for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter ) { - (*iter)->EmitPanGestureSignal(actorHandle, pan); + static_cast< PanGestureDetector* >( *iter )->EmitPanGestureSignal( actorHandle, pan ); } } } @@ -543,6 +515,94 @@ void PanGestureProcessor::OnGesturedActorStageDisconnection() mCurrentPanEmitters.clear(); } +bool PanGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor ) +{ + DALI_ASSERT_DEBUG( mCurrentPanEvent ); + + bool retVal( false ); + PanGestureDetector* panDetector( static_cast< PanGestureDetector* >( detector ) ); + + if ( ( mCurrentPanEvent->numberOfTouches >= panDetector->GetMinimumTouchesRequired() ) && + ( mCurrentPanEvent->numberOfTouches <= panDetector->GetMaximumTouchesRequired() ) ) + { + // Check if the detector requires directional panning. + if ( panDetector->RequiresDirectionalPan() && mCurrentRenderTask ) + { + // It does, calculate the angle of the pan in local actor coordinates and ensures it fits + // the detector's criteria. + RenderTask& renderTaskImpl( GetImplementation( mCurrentRenderTask ) ); + + Vector2 startPosition, currentPosition; + actor->ScreenToLocal( renderTaskImpl, startPosition.x, startPosition.y, mPossiblePanPosition.x, mPossiblePanPosition.y ); + actor->ScreenToLocal( renderTaskImpl, currentPosition.x, currentPosition.y, mCurrentPanEvent->currentPosition.x, mCurrentPanEvent->currentPosition.y ); + Vector2 displacement( currentPosition - startPosition ); + + Radian angle( atanf( displacement.y / displacement.x ) ); + + ///////////////////////////// + // | // + // | // + // Q3 (-,-) | Q4 (+,-) // + // | // + // ----------------- +x // + // | // + // Q2 (-,+) | Q1 (+,+) // + // | // + // | // + // +y // + ///////////////////////////// + // Quadrant 1: As is + // Quadrant 2: 180 degrees + angle + // Quadrant 3: angle - 180 degrees + // Quadrant 4: As is + ///////////////////////////// + + if ( displacement.x < 0.0f ) + { + if ( displacement.y >= 0.0f ) + { + // Quadrant 2 + angle.radian += Math::PI; + } + else + { + // Quadrant 3 + angle.radian -= Math::PI; + } + } + + if ( panDetector->CheckAngleAllowed( angle ) ) + { + retVal = true; + } + } + else + { + // Directional panning not required so we can use this actor and gesture detector. + retVal = true; + } + } + return retVal; +} + +void PanGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates ) +{ + DALI_ASSERT_DEBUG ( mCurrentPanEvent ); + + mCurrentPanEmitters.clear(); + ResetActor(); + + actor->ScreenToLocal( GetImplementation(mCurrentRenderTask), actorCoordinates.x, actorCoordinates.y, mCurrentPanEvent->currentPosition.x, mCurrentPanEvent->currentPosition.y ); + + EmitPanSignal( actor, gestureDetectors, *mCurrentPanEvent, actorCoordinates, mCurrentPanEvent->state, mCurrentRenderTask ); + + if ( actor->OnStage() ) + { + mCurrentPanEmitters = gestureDetectors; + SetActor( actor ); + } +} + } // namespace Internal } // namespace Dali