#include <dali/public-api/dali-core.h>
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali/integration-api/render-task-list-integ.h>
-#include <dali/internal/event/events/long-press-gesture-event.h>
#include <dali-test-suite-utils.h>
#include <test-touch-utils.h>
#include <dali/integration-api/render-task-list-integ.h>
#include <dali/integration-api/profiling.h>
#include <dali/integration-api/input-options.h>
-#include <dali/internal/event/events/pan-gesture-event.h>
#include <dali-test-suite-utils.h>
#include <test-touch-utils.h>
#include <dali/integration-api/input-options.h>
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali/integration-api/render-task-list-integ.h>
-#include <dali/internal/event/events/pan-gesture-event.h>
#include <dali-test-suite-utils.h>
#include <test-touch-utils.h>
#include <dali/integration-api/input-options.h>
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali/integration-api/render-task-list-integ.h>
-#include <dali/internal/event/events/pinch-gesture-event.h>
#include <dali-test-suite-utils.h>
#include <test-touch-utils.h>
#include <dali/public-api/dali-core.h>
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali/integration-api/render-task-list-integ.h>
-#include <dali/internal/event/events/tap-gesture-event.h>
#include <dali-test-suite-utils.h>
#include <test-touch-utils.h>
// INTERNAL INCLUDES
#include <dali/integration-api/render-controller.h>
#include <dali/internal/event/common/stage-impl.h>
-#include <dali/internal/event/events/pinch-gesture-detector-impl.h>
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.h>
#include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
#include <dali/public-api/events/pan-gesture.h>
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
#include <dali/public-api/actors/actor.h>
#include <dali/internal/event/events/gesture-detector-impl.h>
-#include <dali/internal/event/events/long-press-gesture-processor.h>
-#include <dali/internal/event/events/pan-gesture-processor.h>
-#include <dali/internal/event/events/pinch-gesture-processor.h>
-#include <dali/internal/event/events/tap-gesture-processor.h>
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-processor.h>
+#include <dali/internal/event/events/pan-gesture/pan-gesture-processor.h>
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-processor.h>
+#include <dali/internal/event/events/tap-gesture/tap-gesture-processor.h>
namespace Dali
{
+++ /dev/null
-/*
- * Copyright (c) 2016 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "long-press-gesture-detector-impl.h"
-
-// EXTERNAL INCLUDES
-#include <cstring> // for strcmp
-
-// INTERNAL INCLUDES
-#include <dali/public-api/events/long-press-gesture.h>
-#include <dali/public-api/object/type-registry.h>
-#include <dali/internal/event/events/gesture-event-processor.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-
-// Signals
-
-const char* const SIGNAL_LONG_PRESS_DETECTED = "longPressDetected";
-
-BaseHandle Create()
-{
- return Dali::LongPressGestureDetector::New();
-}
-
-TypeRegistration mType( typeid(Dali::LongPressGestureDetector), typeid(Dali::GestureDetector), Create );
-
-SignalConnectorType signalConnector1( mType, SIGNAL_LONG_PRESS_DETECTED, &LongPressGestureDetector::DoConnectSignal );
-
-}
-
-
-namespace
-{
-const unsigned int DEFAULT_TOUCHES_REQUIRED = 1;
-} // unnamed namespace
-
-LongPressGestureDetectorPtr LongPressGestureDetector::New()
-{
- return new LongPressGestureDetector;
-}
-
-LongPressGestureDetectorPtr LongPressGestureDetector::New(unsigned int touchesRequired)
-{
- return new LongPressGestureDetector(touchesRequired, touchesRequired);
-}
-
-LongPressGestureDetectorPtr LongPressGestureDetector::New(unsigned int minTouches, unsigned int maxTouches)
-{
- return new LongPressGestureDetector(minTouches, maxTouches);
-}
-
-LongPressGestureDetector::LongPressGestureDetector()
-: GestureDetector(Gesture::LongPress),
- mMinimumTouchesRequired(DEFAULT_TOUCHES_REQUIRED),
- mMaximumTouchesRequired(DEFAULT_TOUCHES_REQUIRED)
-{
-}
-
-LongPressGestureDetector::LongPressGestureDetector(unsigned int minTouches, unsigned int maxTouches)
-: GestureDetector(Gesture::LongPress),
- mMinimumTouchesRequired(minTouches),
- mMaximumTouchesRequired(maxTouches)
-{
-}
-
-LongPressGestureDetector::~LongPressGestureDetector()
-{
-}
-
-void LongPressGestureDetector::SetTouchesRequired(unsigned int touches)
-{
- DALI_ASSERT_ALWAYS( touches > 0 && "Can only set a positive number of required touches" );
-
- if (mMinimumTouchesRequired != touches || mMaximumTouchesRequired != touches)
- {
- mMinimumTouchesRequired = mMaximumTouchesRequired = touches;
-
- if (!mAttachedActors.empty())
- {
- mGestureEventProcessor.GestureDetectorUpdated(this);
- }
- }
-}
-
-void LongPressGestureDetector::SetTouchesRequired(unsigned int minTouches, unsigned int maxTouches)
-{
- DALI_ASSERT_ALWAYS(minTouches > 0 && "Can only set a positive number of minimum touches");
- DALI_ASSERT_ALWAYS(maxTouches > 0 && "Can only set a positive number of minimum touches");
- DALI_ASSERT_ALWAYS(minTouches <= maxTouches && "Number of minimum touches must be less than maximum");
-
- if (mMinimumTouchesRequired != minTouches || mMaximumTouchesRequired != maxTouches)
- {
- mMinimumTouchesRequired = minTouches;
- mMaximumTouchesRequired = maxTouches;
-
- if (!mAttachedActors.empty())
- {
- mGestureEventProcessor.GestureDetectorUpdated(this);
- }
- }
-}
-
-unsigned int LongPressGestureDetector::GetMinimumTouchesRequired() const
-{
- return mMinimumTouchesRequired;
-}
-
-unsigned int LongPressGestureDetector::GetMaximumTouchesRequired() const
-{
- return mMaximumTouchesRequired;
-}
-
-void LongPressGestureDetector::EmitLongPressGestureSignal(Dali::Actor pressedActor, const LongPressGesture& longPress)
-{
- // Guard against destruction during signal emission
- Dali::LongPressGestureDetector handle( this );
-
- mDetectedSignal.Emit( pressedActor, longPress );
-}
-
-bool LongPressGestureDetector::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
-{
- bool connected( true );
- LongPressGestureDetector* gesture = static_cast< LongPressGestureDetector* >(object); // TypeRegistry guarantees that this is the correct type.
-
- if ( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESS_DETECTED ) )
- {
- gesture->DetectedSignal().Connect( tracker, functor );
- }
- else
- {
- // signalName does not match any signal
- connected = false;
- }
-
- return connected;
-}
-
-void LongPressGestureDetector::OnActorAttach(Actor& actor)
-{
- // Do nothing
-}
-
-void LongPressGestureDetector::OnActorDetach(Actor& actor)
-{
- // Do nothing
-}
-
-void LongPressGestureDetector::OnActorDestroyed(Object& object)
-{
- // Do nothing
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_LONG_PRESS_GESTURE_DETECTOR_IMPL_H
-#define DALI_INTERNAL_LONG_PRESS_GESTURE_DETECTOR_IMPL_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/public-api/events/long-press-gesture-detector.h>
-#include <dali/internal/event/events/gesture-detector-impl.h>
-
-namespace Dali
-{
-
-struct LongPressGesture;
-
-namespace Internal
-{
-
-class LongPressGestureDetector;
-
-typedef IntrusivePtr<LongPressGestureDetector> LongPressGestureDetectorPtr;
-typedef DerivedGestureDetectorContainer<LongPressGestureDetector>::type LongPressGestureDetectorContainer;
-
-/**
- * @copydoc Dali::LongPressGestureDetector
- */
-class LongPressGestureDetector : public GestureDetector
-{
-public: // Creation
-
- /**
- * Create a new gesture detector.
- * @return A smart-pointer to the newly allocated detector.
- */
- static LongPressGestureDetectorPtr New();
-
- /**
- * Create a new gesture detector with the specified touches.
- * @param[in] touchesRequired The number of touches required.
- * @return A smart-pointer to the newly allocated detector.
- */
- static LongPressGestureDetectorPtr New(unsigned int touchesRequired);
-
- /**
- * Create a new gesture detector with the specified minimum and maximum touches.
- * @param[in] minTouches The minimum number of touches required.
- * @param[in] maxTouches The maximum number of touches required.
- * @return A smart-pointer to the newly allocated detector.
- */
- static LongPressGestureDetectorPtr New(unsigned int minTouches, unsigned int maxTouches);
-
- /**
- * Construct a new GestureDetector.
- */
- LongPressGestureDetector();
-
- /**
- * Create a new gesture detector with the specified minimum and maximum touches.
- * @param[in] minTouches The minimum number of touches required.
- * @param[in] maxTouches The maximum number of touches required.
- */
- LongPressGestureDetector(unsigned int minTouches, unsigned int maxTouches);
-
-public:
-
- /**
- * @copydoc Dali::LongPressGestureDetector::SetTouchesRequired(unsigned int)
- */
- void SetTouchesRequired(unsigned int touches);
-
- /**
- * @copydoc Dali::LongPressGestureDetector::SetTouchesRequired(unsigned int, unsigned int)
- */
- void SetTouchesRequired(unsigned int minTouches, unsigned int maxTouches);
-
- /**
- * @copydoc Dali::LongPressGestureDetector::GetMinimumTouchesRequired()
- */
- unsigned int GetMinimumTouchesRequired() const;
-
- /**
- * @copydoc Dali::LongPressGestureDetector::GetMaximumTouchesRequired()
- */
- unsigned int GetMaximumTouchesRequired() const;
-
-public:
-
- /**
- * Called by the LongPressGestureProcessor when a tap gesture event occurs within the bounds of our
- * attached actor.
- * @param[in] pressedActor The pressed actor.
- * @param[in] longPress The long press
- */
- void EmitLongPressGestureSignal(Dali::Actor pressedActor, const LongPressGesture& longPress);
-
-public: // Signals
-
- /**
- * @copydoc Dali::LongPressGestureDetector::DetectedSignal()
- */
- Dali::LongPressGestureDetector::DetectedSignalType& DetectedSignal()
- {
- return mDetectedSignal;
- }
-
- /**
- * Connects a callback function with the object's signals.
- * @param[in] object The object providing the signal.
- * @param[in] tracker Used to disconnect the signal.
- * @param[in] signalName The signal to connect to.
- * @param[in] functor A newly allocated FunctorDelegate.
- * @return True if the signal was connected.
- * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
- */
- static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
-
-protected:
-
- /**
- * A reference counted object may only be deleted by calling Unreference()
- */
- virtual ~LongPressGestureDetector();
-
-private:
-
- // Undefined
- LongPressGestureDetector(const LongPressGestureDetector&);
- LongPressGestureDetector& operator=(const LongPressGestureDetector& rhs);
-
-private: // GestureDetector overrides
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&)
- */
- virtual void OnActorAttach(Actor& actor);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorDetach(Actor&)
- */
- virtual void OnActorDetach(Actor& actor);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorDestroyed(Object&)
- */
- virtual void OnActorDestroyed(Object& object);
-
-private:
-
- Dali::LongPressGestureDetector::DetectedSignalType mDetectedSignal;
-
- unsigned int mMinimumTouchesRequired;
- unsigned int mMaximumTouchesRequired;
-};
-
-} // namespace Internal
-
-// Helpers for public-api forwarding methods
-
-inline Internal::LongPressGestureDetector& GetImplementation(Dali::LongPressGestureDetector& detector)
-{
- DALI_ASSERT_ALWAYS( detector && "LongPressGestureDetector handle is empty" );
-
- BaseObject& handle = detector.GetBaseObject();
-
- return static_cast<Internal::LongPressGestureDetector&>(handle);
-}
-
-inline const Internal::LongPressGestureDetector& GetImplementation(const Dali::LongPressGestureDetector& detector)
-{
- DALI_ASSERT_ALWAYS( detector && "LongPressGestureDetector handle is empty" );
-
- const BaseObject& handle = detector.GetBaseObject();
-
- return static_cast<const Internal::LongPressGestureDetector&>(handle);
-}
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_LONG_PRESS_GESTURE_DETECTOR_IMPL_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/long-press-gesture-event.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-LongPressGestureEvent::LongPressGestureEvent( Gesture::State state )
-: GestureEvent( Gesture::LongPress, state ),
- numberOfTouches(1)
-{
-}
-
-LongPressGestureEvent::~LongPressGestureEvent()
-{
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_EVENT_LONG_PRESS_GESTURE_H
-#define DALI_INTERNAL_EVENT_LONG_PRESS_GESTURE_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/gesture-event.h>
-#include <dali/public-api/math/vector2.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-/**
- * If the adaptor detects a long press gesture, then it should create an instance of this structure and
- * send it to the Core.
- *
- * This gesture can be in four states:
- * - Possible: When the user first puts their finger down - Core needs to hit test the down point.
- * - Started: When the long-press gesture is actually detected.
- * - Finished: When the user finally lifts all touches.
- * - Cancelled: If, after a down event, no long press is detected, or a system interruption.
- */
-struct LongPressGestureEvent : public GestureEvent
-{
- // Construction & Destruction
-
- /**
- * Default Constructor
- * @param[in] state Started, when we detect a long press.
- * Finished, when all touches are finished.
- */
- LongPressGestureEvent( Gesture::State state );
-
- /**
- * Virtual destructor
- */
- virtual ~LongPressGestureEvent();
-
- // Data
-
- /**
- * @copydoc Dali::LongPressGesture::numberOfTouches
- */
- unsigned int numberOfTouches;
-
- /**
- * This is the point, in screen coordinates, where the long press occurred.
- * If a multi-touch tap, then this should be the centroid of all the touch points.
- */
- Vector2 point;
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_EVENT_LONG_PRESS_GESTURE_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/long-press-gesture-processor.h>
-
-// EXTERNAL INCLUDES
-#include <algorithm>
-
-// INTERNAL INCLUDES
-#include <dali/public-api/actors/actor.h>
-#include <dali/public-api/common/dali-common.h>
-#include <dali/public-api/events/long-press-gesture.h>
-#include <dali/internal/event/events/long-press-gesture-event.h>
-#include <dali/integration-api/debug.h>
-#include <dali/internal/event/actors/actor-impl.h>
-#include <dali/internal/event/common/scene-impl.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
-#include <dali/internal/event/events/long-press-gesture-recognizer.h>
-#include <dali/internal/event/events/gesture-requests.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-
-/**
- * Creates a LongPressGesture and asks the specified detector to emit its detected signal.
- * @param[in] actor The actor on which the long press gesture has occurred.
- * @param[in] gestureDetectors A reference to gesture detectors that should emit the signal.
- * @param[in] longPressEvent The longPressEvent received from the adaptor.
- * @param[in] localPoint Relative to the actor attached to the detector.
- */
-void EmitLongPressSignal(
- Actor* actor,
- const GestureDetectorContainer& gestureDetectors,
- const LongPressGestureEvent& longPressEvent,
- Vector2 localPoint)
-{
- LongPressGesture longPress(longPressEvent.state);
- longPress.time = longPressEvent.time;
- longPress.numberOfTouches = longPressEvent.numberOfTouches;
- longPress.screenPoint = longPressEvent.point;
- longPress.localPoint = localPoint;
-
- Dali::Actor actorHandle( actor );
- const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
- for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
- {
- static_cast< LongPressGestureDetector* >( *iter )->EmitLongPressGestureSignal( actorHandle, longPress );
- }
-}
-
-/**
- * Functor which checks whether the specified actor is attached to the gesture detector.
- * It returns true if it is no longer attached. This can be used in remove_if functions.
- */
-struct IsNotAttachedFunctor
-{
- /**
- * Constructor
- * @param[in] actor The actor to check whether it is attached.
- */
- IsNotAttachedFunctor( Actor* actor )
- : actorToCheck( actor )
- {
- }
-
- /**
- * Returns true if not attached, false if it is still attached.
- * @param[in] detector The detector to check.
- * @return true, if not attached, false otherwise.
- */
- bool operator()( const GestureDetector* detector ) const
- {
- return !detector->IsAttached( *actorToCheck );
- }
-
- Actor* actorToCheck; ///< The actor to check whether it is attached or not.
-};
-
-} // unnamed namespace
-
-LongPressGestureProcessor::LongPressGestureProcessor()
-: GestureProcessor( Gesture::LongPress ),
- mLongPressGestureDetectors(),
- mCurrentEmitters(),
- mCurrentRenderTask(),
- mMinTouchesRequired( 1 ),
- mMaxTouchesRequired( 1 ),
- mCurrentLongPressEvent( NULL )
-{
-}
-
-LongPressGestureProcessor::~LongPressGestureProcessor()
-{
-}
-
-void LongPressGestureProcessor::Process( Scene& scene, const LongPressGestureEvent& longPressEvent )
-{
- switch ( longPressEvent.state )
- {
- case Gesture::Possible:
- {
- mCurrentEmitters.clear();
- ResetActor();
-
- HitTestAlgorithm::Results hitTestResults;
- if( HitTest( scene, longPressEvent.point, hitTestResults ) )
- {
- SetActor( &GetImplementation( hitTestResults.actor ) );
- }
- break;
- }
-
- case Gesture::Started:
- {
- Actor* currentGesturedActor = GetCurrentGesturedActor();
- if ( currentGesturedActor )
- {
- HitTestAlgorithm::Results hitTestResults;
- HitTest( scene, longPressEvent.point, hitTestResults );
-
- if ( hitTestResults.actor && ( currentGesturedActor == &GetImplementation( hitTestResults.actor ) ) )
- {
- // Record the current render-task for Screen->Actor coordinate conversions
- mCurrentRenderTask = hitTestResults.renderTask;
-
- // Set mCurrentLongPressEvent to use inside overridden methods called from ProcessAndEmit()
- mCurrentLongPressEvent = &longPressEvent;
- ProcessAndEmit( hitTestResults );
- mCurrentLongPressEvent = NULL;
- }
- else
- {
- mCurrentEmitters.clear();
- ResetActor();
- }
- }
- break;
- }
-
- case Gesture::Finished:
- {
- // The gesture should only be sent to the gesture detector which first received it so that it
- // can be told when the gesture ends as well.
-
- // Only send subsequent long press gesture signals if we processed the gesture when it started.
- // Check if actor is still touchable.
-
- Actor* currentGesturedActor = GetCurrentGesturedActor();
- if ( currentGesturedActor )
- {
- if ( currentGesturedActor->IsHittable() && !mCurrentEmitters.empty() && mCurrentRenderTask )
- {
- // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
- GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentEmitters.begin(), mCurrentEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
- mCurrentEmitters.erase( endIter, mCurrentEmitters.end() );
-
- if ( !mCurrentEmitters.empty() )
- {
- Vector2 actorCoords;
- RenderTask& renderTaskImpl = *mCurrentRenderTask.Get();
- currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, longPressEvent.point.x, longPressEvent.point.y );
-
- EmitLongPressSignal( currentGesturedActor, mCurrentEmitters, longPressEvent, actorCoords );
- }
- }
-
- // Clear current emitters and emitted actor
- mCurrentEmitters.clear();
- ResetActor();
- }
- break;
- }
-
- case Gesture::Cancelled:
- {
- mCurrentEmitters.clear();
- ResetActor();
- break;
- }
-
- case Gesture::Continuing:
- {
- DALI_ABORT( "Incorrect state received from Integration layer: Continuing\n" );
- break;
- }
-
- case Gesture::Clear:
- {
- DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
- break;
- }
- }
-}
-
-void LongPressGestureProcessor::AddGestureDetector( LongPressGestureDetector* gestureDetector, Scene& scene )
-{
- bool firstRegistration(mLongPressGestureDetectors.empty());
-
- mLongPressGestureDetectors.push_back(gestureDetector);
-
- if (firstRegistration)
- {
- mMinTouchesRequired = gestureDetector->GetMinimumTouchesRequired();
- mMaxTouchesRequired = gestureDetector->GetMaximumTouchesRequired();
-
- LongPressGestureRequest request;
- request.minTouches = mMinTouchesRequired;
- request.maxTouches = mMaxTouchesRequired;
-
- Size size = scene.GetSize();
-
- mGestureRecognizer = new LongPressGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const LongPressGestureRequest&>(request));
- }
- else
- {
- UpdateDetection();
- }
-}
-
-void LongPressGestureProcessor::RemoveGestureDetector( LongPressGestureDetector* gestureDetector )
-{
- // Find detector ...
- LongPressGestureDetectorContainer::iterator endIter = std::remove( mLongPressGestureDetectors.begin(), mLongPressGestureDetectors.end(), gestureDetector );
- DALI_ASSERT_DEBUG( endIter != mLongPressGestureDetectors.end() );
-
- // ... and remove it
- mLongPressGestureDetectors.erase( endIter, mLongPressGestureDetectors.end() );
-
- if ( mLongPressGestureDetectors.empty() )
- {
- mGestureRecognizer.Detach();
- }
- else
- {
- UpdateDetection();
- }
-}
-
-void LongPressGestureProcessor::GestureDetectorUpdated( LongPressGestureDetector* gestureDetector )
-{
- DALI_ASSERT_DEBUG( find( mLongPressGestureDetectors.begin(), mLongPressGestureDetectors.end(), gestureDetector ) != mLongPressGestureDetectors.end() );
-
- UpdateDetection();
-}
-
-void LongPressGestureProcessor::UpdateDetection()
-{
- DALI_ASSERT_DEBUG(!mLongPressGestureDetectors.empty());
-
- unsigned int minimumRequired = UINT_MAX;
- unsigned int maximumRequired = 0;
-
- for ( LongPressGestureDetectorContainer::iterator iter = mLongPressGestureDetectors.begin(), endIter = mLongPressGestureDetectors.end(); iter != endIter; ++iter )
- {
- LongPressGestureDetector* current(*iter);
-
- if( current )
- {
- unsigned int minimum = current->GetMinimumTouchesRequired();
- if (minimum < minimumRequired)
- {
- minimumRequired = minimum;
- }
-
- unsigned int maximum = current->GetMaximumTouchesRequired();
- if ( maximum > maximumRequired )
- {
- maximumRequired = maximum;
- }
- }
- }
-
- if ( (minimumRequired != mMinTouchesRequired) || (maximumRequired != mMaxTouchesRequired) )
- {
- mMinTouchesRequired = minimumRequired;
- mMaxTouchesRequired = maximumRequired;
-
- LongPressGestureRequest request;
- request.minTouches = mMinTouchesRequired;
- request.maxTouches = mMaxTouchesRequired;
- mGestureRecognizer->Update(request);
- }
-}
-
-void LongPressGestureProcessor::OnGesturedActorStageDisconnection()
-{
- mCurrentEmitters.clear();
-}
-
-bool LongPressGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
-{
- DALI_ASSERT_DEBUG( mCurrentLongPressEvent );
-
- LongPressGestureDetector* longPressDetector ( static_cast< LongPressGestureDetector* >( detector ) );
-
- return ( longPressDetector->GetMinimumTouchesRequired() <= mCurrentLongPressEvent->numberOfTouches ) &&
- ( longPressDetector->GetMaximumTouchesRequired() >= mCurrentLongPressEvent->numberOfTouches );
-}
-
-void LongPressGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
-{
- DALI_ASSERT_DEBUG( mCurrentLongPressEvent );
-
- mCurrentEmitters.clear();
- ResetActor();
-
- EmitLongPressSignal( actor, gestureDetectors, *mCurrentLongPressEvent, actorCoordinates );
-
- if ( actor->OnStage() )
- {
- mCurrentEmitters = gestureDetectors;
- SetActor( actor );
- }
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_LONG_PRESS_GESTURE_EVENT_PROCESSOR_H
-#define DALI_INTERNAL_LONG_PRESS_GESTURE_EVENT_PROCESSOR_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/long-press-gesture-detector-impl.h>
-#include <dali/internal/event/events/gesture-processor.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-class Stage;
-class Scene;
-
-struct GestureEvent;
-struct LongPressGestureEvent;
-
-/**
- * Long Press Gesture Event Processing:
- *
- * When we receive a long press gesture event, we do the following:
- * - Find the actor that requires a long-press at the long press position.
- * - Emit the gesture if the event satisfies the detector conditions.
- */
-class LongPressGestureProcessor : public GestureProcessor, public RecognizerObserver<LongPressGestureEvent>
-{
-public:
-
- /**
- * Create a long press gesture processor.
- */
- LongPressGestureProcessor();
-
- /**
- * Non-virtual destructor; LongPressGestureProcessor is not a base class
- */
- ~LongPressGestureProcessor();
-
-public: // To be called by GestureEventProcessor
-
- /**
- * This method is called whenever a long press gesture event occurs.
- * @param[in] scene The scene the long press gesture event occurs in.
- * @param[in] longPressEvent The event that has occurred.
- */
- void Process( Scene& scene, const LongPressGestureEvent& longPressEvent );
-
- /**
- * Adds a gesture detector to this gesture processor.
- * If this is the first gesture detector being added, then this method registers the required
- * gesture with the adaptor.
- * @param[in] gestureDetector The gesture detector being added.
- * @param[in] scene The scene the long press gesture event occurs in.
- */
- void AddGestureDetector( LongPressGestureDetector* gestureDetector, Scene& scene );
-
- /**
- * Removes the specified gesture detector from this gesture processor. If, after removing this
- * gesture detector, there are no more gesture detectors registered, then this method unregisters
- * the gesture from the adaptor.
- * @param[in] gestureDetector The gesture detector being removed.
- */
- void RemoveGestureDetector( LongPressGestureDetector* gestureDetector );
-
- /**
- * This method updates the gesture detection parameters.
- * @param[in] gestureDetector The gesture detector that has been updated.
- */
- void GestureDetectorUpdated(LongPressGestureDetector* gestureDetector);
-
-private:
-
- // Undefined
- LongPressGestureProcessor( const LongPressGestureProcessor& );
- LongPressGestureProcessor& operator=( const LongPressGestureProcessor& rhs );
-
-private:
-
- /**
- * Iterates through our GestureDetectors and determines if we need to ask the adaptor to update
- * its detection policy. If it does, it sends the appropriate gesture update request to adaptor.
- */
- void UpdateDetection();
-
- // GestureProcessor overrides
-
- /**
- * @copydoc GestureProcessor::OnGesturedActorStageDisconnection()
- */
- void OnGesturedActorStageDisconnection();
-
- /**
- * @copydoc GestureProcessor::CheckGestureDetector()
- */
- bool CheckGestureDetector( GestureDetector* detector, Actor* actor );
-
- /**
- * @copydoc GestureProcessor::EmitGestureSignal()
- */
- void EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates );
-
-private:
-
- LongPressGestureDetectorContainer mLongPressGestureDetectors;
-
- GestureDetectorContainer mCurrentEmitters;
- RenderTaskPtr mCurrentRenderTask;
-
- uint32_t mMinTouchesRequired;
- uint32_t mMaxTouchesRequired;
-
- const LongPressGestureEvent* mCurrentLongPressEvent; ///< Pointer to current longPressEvent, used when calling ProcessAndEmit()
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_LONG_PRESS_GESTURE_EVENT_PROCESSOR_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/long-press-gesture-recognizer.h>
-
-// EXTERNAL INCLUDES
-#include <cmath>
-
-#include <dali/public-api/events/touch-point.h>
-#include <dali/public-api/math/vector2.h>
-
-#include <dali/internal/event/common/thread-local-storage.h>
-#include <dali/internal/event/events/gesture-requests.h>
-#include <dali/integration-api/events/touch-event-integ.h>
-#include <dali/integration-api/platform-abstraction.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-// TODO: Set these according to DPI
-const float MAXIMUM_MOTION_ALLOWED = 60.0f;
-// TODO: Set this time according to system setting (vconf)
-const unsigned long LONG_PRESS_TIME = 500u;
-} // unnamed namespace
-
-LongPressGestureRecognizer::LongPressGestureRecognizer(Observer& observer, Vector2 screenSize, const LongPressGestureRequest& request )
-: GestureRecognizer( screenSize, Gesture::LongPress ),
- mObserver( observer ),
- mState( Clear ),
- mMinimumTouchesRequired( request.minTouches ),
- mMaximumTouchesRequired( request.maxTouches ),
- mTouchTime( 0 ),
- mTimerId( 0 )
-{
-}
-
-LongPressGestureRecognizer::~LongPressGestureRecognizer()
-{
-}
-
-void LongPressGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
-{
- unsigned int pointCount( event.GetPointCount() );
- Dali::Integration::PlatformAbstraction& platformAbstraction = ThreadLocalStorage::Get().GetPlatformAbstraction();
-
- switch (mState)
- {
- // Clear: Wait till one point touches the screen before starting timer.
- case Clear:
- {
- const Integration::Point& point = event.points[0];
-
- if ( point.GetState() == PointState::DOWN )
- {
- mTouchPositions.clear();
- mTouchPositions[point.GetDeviceId()] = point.GetScreenPosition();
-
- mTouchTime = event.time;
-
- mTimerId = platformAbstraction.StartTimer(GetSystemValue(), MakeCallback( this, &LongPressGestureRecognizer::TimerCallback));
-
- // A long press gesture may be possible, tell Core about this and change state to Touched.
- mState = Touched;
- EmitGesture( Gesture::Possible );
- }
-
- break;
- }
-
- // Touched: Monitor movement and addition/removal of points.
- case Touched:
- {
- if (pointCount > mMaximumTouchesRequired)
- {
- // A long press did not occur, tell Core that it was cancelled and change state to Failed.
- EmitGesture( Gesture::Cancelled );
- mTouchPositions.clear();
- platformAbstraction.CancelTimer(mTimerId);
- mState = Failed;
- break;
- }
-
- bool endLoop(false);
-
- for ( Integration::PointContainerConstIterator iter = event.points.begin(), endIter = event.points.end();
- iter != endIter && !endLoop; ++iter)
- {
- switch( iter->GetState() )
- {
- // add point.
- case PointState::DOWN:
- {
- mTouchPositions[iter->GetDeviceId()] = iter->GetScreenPosition();
- break;
- }
-
- // remove point.
- case PointState::UP:
- case PointState::INTERRUPTED:
- {
- // System has interrupted us, long press is not possible, inform Core
- EmitGesture( Gesture::Cancelled );
- mTouchPositions.clear();
- platformAbstraction.CancelTimer(mTimerId);
- mState = ( pointCount == 1 ) ? Clear : Failed; // Change state to Clear if only one point, Failed otherwise.
- endLoop = true;
- break;
- }
-
- case PointState::MOTION:
- {
- const Vector2 touchPosition( mTouchPositions[iter->GetDeviceId()] - iter->GetScreenPosition() );
- float distanceSquared = touchPosition.LengthSquared();
-
- if (distanceSquared > ( MAXIMUM_MOTION_ALLOWED * MAXIMUM_MOTION_ALLOWED ) )
- {
- // We have moved more than the allowable motion for a long press gesture. Inform Core and change state to Failed.
- EmitGesture( Gesture::Cancelled );
- platformAbstraction.CancelTimer(mTimerId);
- mState = Failed;
- endLoop = true;
- }
- break;
- }
-
- case PointState::STATIONARY:
- case PointState::LEAVE:
- {
- break;
- }
- }
- }
- break;
- }
-
- // Failed/Finished: Monitor the touches, waiting for all touches to be released.
- case Failed:
- case Finished:
- {
- // eventually the final touch point will be removed, marking the end of this gesture.
- if ( pointCount == 1 )
- {
- PointState::Type primaryPointState = event.points[0].GetState();
-
- if ( (primaryPointState == PointState::UP) || (primaryPointState == PointState::INTERRUPTED) )
- {
- if(mState == Finished)
- {
- // When the last touch point is lifted, we should inform the Core that the Long press has finished.
- EmitGesture(Gesture::Finished);
- }
- mTouchPositions.clear();
- mState = Clear; // Reset state to clear when last touch point is lifted.
- }
- }
- break;
- }
- }
-}
-
-void LongPressGestureRecognizer::Update(const GestureRequest& request)
-{
- const LongPressGestureRequest& longPress = static_cast<const LongPressGestureRequest&>(request);
-
- mMinimumTouchesRequired = longPress.minTouches;
- mMaximumTouchesRequired = longPress.maxTouches;
-}
-
-bool LongPressGestureRecognizer::TimerCallback()
-{
- EmitGesture(Gesture::Started);
-
- mState = Finished;
-
- return false;
-}
-
-void LongPressGestureRecognizer::EmitGesture(Gesture::State state)
-{
- unsigned int touchPoints ( static_cast<unsigned int>( mTouchPositions.size() ) );
-
- // We should tell Core about the Possible and Cancelled states regardless of whether we have satisfied long press requirements.
- if ( (state == Gesture::Possible) ||
- (state == Gesture::Cancelled) ||
- (touchPoints >= mMinimumTouchesRequired) )
- {
- LongPressGestureEvent longPress( state );
- longPress.numberOfTouches = touchPoints;
-
- for (std::map<int, Vector2>::iterator iter = mTouchPositions.begin(), endIter = mTouchPositions.end();
- iter != endIter; ++iter)
- {
- longPress.point += iter->second;
- }
- longPress.point /= static_cast<float>( touchPoints );
-
- longPress.time = mTouchTime;
- if ( state != Gesture::Possible )
- {
- longPress.time += GetSystemValue();
- }
-
- if( mScene )
- {
- // Create another handle so the recognizer cannot be destroyed during process function
- GestureRecognizerPtr recognizerHandle = this;
-
- mObserver.Process(*mScene, longPress);
- }
- }
-}
-
-int LongPressGestureRecognizer::GetSystemValue()
-{
- return LONG_PRESS_TIME;
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_LONG_PRESS_GESTURE_RECOGNIZER_H
-#define DALI_INTERNAL_LONG_PRESS_GESTURE_RECOGNIZER_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <map>
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/gesture-recognizer.h>
-#include <dali/internal/event/events/long-press-gesture-event.h>
-
-namespace Dali
-{
-
-namespace Integration
-{
-struct TouchEvent;
-
-}
-
-namespace Internal
-{
-
-struct LongPressGestureRequest;
-class CoreEventInterface;
-
-/**
- * When given a set of touch events, this detector attempts to determine if a long press gesture has taken place.
- * Emits a LongPressGestureEvent (state = Started) when a long press has been detected (Touch held down for more than duration).
- * Emits a further LongPressGestureEvent (state = Finished) when a long press has been completed (Touch Release).
- */
-class LongPressGestureRecognizer : public GestureRecognizer
-{
-public:
-
- using Observer = RecognizerObserver<LongPressGestureEvent>;
-
- /**
- * Constructor
- * @param[in] coreEventInterface Used to send events to Core.
- * @param[in] screenSize The size of the screen.
- * @param[in] request The long press gesture request.
- */
- LongPressGestureRecognizer( Observer& observer, Vector2 screenSize, const LongPressGestureRequest& request );
-
- /**
- * Virtual destructor.
- */
- virtual ~LongPressGestureRecognizer();
-
-public:
-
- /**
- * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
- */
- virtual void SendEvent(const Integration::TouchEvent& event);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
- */
- virtual void Update(const GestureRequest& request);
-
-private:
-
- /**
- * Timer Callback
- * @return will return false; one-shot timer.
- */
- bool TimerCallback();
-
- /**
- * Emits the long press gesture if all conditions are applicable.
- * @param[in] state The state of this gesture event.
- */
- void EmitGesture(Gesture::State state);
-
- /**
- * Get current system setting value for tap and hold gesture
- * @return system value for tap and hold gesture [ms]
- */
- int GetSystemValue();
-
-private:
-
- // Reference to the gesture processor for this recognizer
- Observer& mObserver;
-
- /**
- * Internal state machine.
- */
- enum State
- {
- Clear, ///< No gesture detected.
- Touched, ///< User is touching the screen.
- Failed, ///< Gesture has failed.
- Finished ///< Gesture has been detected and sent.
- };
-
- State mState; ///< The current state of the detector.
-
- unsigned int mMinimumTouchesRequired; ///< The minimum touches required before emitting a long press.
- unsigned int mMaximumTouchesRequired; ///< The maximum touches allowable. Any more and a long press is not emitted.
-
- std::map<int, Vector2> mTouchPositions; ///< A map with all the touch down positions.
- uint32_t mTouchTime; ///< The time we first pressed down.
-
- uint32_t mTimerId;
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_LONG_PRESS_GESTURE_RECOGNIZER_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "long-press-gesture-detector-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/long-press-gesture.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/internal/event/events/gesture-event-processor.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// Signals
+
+const char* const SIGNAL_LONG_PRESS_DETECTED = "longPressDetected";
+
+BaseHandle Create()
+{
+ return Dali::LongPressGestureDetector::New();
+}
+
+TypeRegistration mType( typeid(Dali::LongPressGestureDetector), typeid(Dali::GestureDetector), Create );
+
+SignalConnectorType signalConnector1( mType, SIGNAL_LONG_PRESS_DETECTED, &LongPressGestureDetector::DoConnectSignal );
+
+}
+
+
+namespace
+{
+const unsigned int DEFAULT_TOUCHES_REQUIRED = 1;
+} // unnamed namespace
+
+LongPressGestureDetectorPtr LongPressGestureDetector::New()
+{
+ return new LongPressGestureDetector;
+}
+
+LongPressGestureDetectorPtr LongPressGestureDetector::New(unsigned int touchesRequired)
+{
+ return new LongPressGestureDetector(touchesRequired, touchesRequired);
+}
+
+LongPressGestureDetectorPtr LongPressGestureDetector::New(unsigned int minTouches, unsigned int maxTouches)
+{
+ return new LongPressGestureDetector(minTouches, maxTouches);
+}
+
+LongPressGestureDetector::LongPressGestureDetector()
+: GestureDetector(Gesture::LongPress),
+ mMinimumTouchesRequired(DEFAULT_TOUCHES_REQUIRED),
+ mMaximumTouchesRequired(DEFAULT_TOUCHES_REQUIRED)
+{
+}
+
+LongPressGestureDetector::LongPressGestureDetector(unsigned int minTouches, unsigned int maxTouches)
+: GestureDetector(Gesture::LongPress),
+ mMinimumTouchesRequired(minTouches),
+ mMaximumTouchesRequired(maxTouches)
+{
+}
+
+LongPressGestureDetector::~LongPressGestureDetector()
+{
+}
+
+void LongPressGestureDetector::SetTouchesRequired(unsigned int touches)
+{
+ DALI_ASSERT_ALWAYS( touches > 0 && "Can only set a positive number of required touches" );
+
+ if (mMinimumTouchesRequired != touches || mMaximumTouchesRequired != touches)
+ {
+ mMinimumTouchesRequired = mMaximumTouchesRequired = touches;
+
+ if (!mAttachedActors.empty())
+ {
+ mGestureEventProcessor.GestureDetectorUpdated(this);
+ }
+ }
+}
+
+void LongPressGestureDetector::SetTouchesRequired(unsigned int minTouches, unsigned int maxTouches)
+{
+ DALI_ASSERT_ALWAYS(minTouches > 0 && "Can only set a positive number of minimum touches");
+ DALI_ASSERT_ALWAYS(maxTouches > 0 && "Can only set a positive number of minimum touches");
+ DALI_ASSERT_ALWAYS(minTouches <= maxTouches && "Number of minimum touches must be less than maximum");
+
+ if (mMinimumTouchesRequired != minTouches || mMaximumTouchesRequired != maxTouches)
+ {
+ mMinimumTouchesRequired = minTouches;
+ mMaximumTouchesRequired = maxTouches;
+
+ if (!mAttachedActors.empty())
+ {
+ mGestureEventProcessor.GestureDetectorUpdated(this);
+ }
+ }
+}
+
+unsigned int LongPressGestureDetector::GetMinimumTouchesRequired() const
+{
+ return mMinimumTouchesRequired;
+}
+
+unsigned int LongPressGestureDetector::GetMaximumTouchesRequired() const
+{
+ return mMaximumTouchesRequired;
+}
+
+void LongPressGestureDetector::EmitLongPressGestureSignal(Dali::Actor pressedActor, const LongPressGesture& longPress)
+{
+ // Guard against destruction during signal emission
+ Dali::LongPressGestureDetector handle( this );
+
+ mDetectedSignal.Emit( pressedActor, longPress );
+}
+
+bool LongPressGestureDetector::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+ bool connected( true );
+ LongPressGestureDetector* gesture = static_cast< LongPressGestureDetector* >(object); // TypeRegistry guarantees that this is the correct type.
+
+ if ( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESS_DETECTED ) )
+ {
+ gesture->DetectedSignal().Connect( tracker, functor );
+ }
+ else
+ {
+ // signalName does not match any signal
+ connected = false;
+ }
+
+ return connected;
+}
+
+void LongPressGestureDetector::OnActorAttach(Actor& actor)
+{
+ // Do nothing
+}
+
+void LongPressGestureDetector::OnActorDetach(Actor& actor)
+{
+ // Do nothing
+}
+
+void LongPressGestureDetector::OnActorDestroyed(Object& object)
+{
+ // Do nothing
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_LONG_PRESS_GESTURE_DETECTOR_IMPL_H
+#define DALI_INTERNAL_LONG_PRESS_GESTURE_DETECTOR_IMPL_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/long-press-gesture-detector.h>
+#include <dali/internal/event/events/gesture-detector-impl.h>
+
+namespace Dali
+{
+
+struct LongPressGesture;
+
+namespace Internal
+{
+
+class LongPressGestureDetector;
+
+typedef IntrusivePtr<LongPressGestureDetector> LongPressGestureDetectorPtr;
+typedef DerivedGestureDetectorContainer<LongPressGestureDetector>::type LongPressGestureDetectorContainer;
+
+/**
+ * @copydoc Dali::LongPressGestureDetector
+ */
+class LongPressGestureDetector : public GestureDetector
+{
+public: // Creation
+
+ /**
+ * Create a new gesture detector.
+ * @return A smart-pointer to the newly allocated detector.
+ */
+ static LongPressGestureDetectorPtr New();
+
+ /**
+ * Create a new gesture detector with the specified touches.
+ * @param[in] touchesRequired The number of touches required.
+ * @return A smart-pointer to the newly allocated detector.
+ */
+ static LongPressGestureDetectorPtr New(unsigned int touchesRequired);
+
+ /**
+ * Create a new gesture detector with the specified minimum and maximum touches.
+ * @param[in] minTouches The minimum number of touches required.
+ * @param[in] maxTouches The maximum number of touches required.
+ * @return A smart-pointer to the newly allocated detector.
+ */
+ static LongPressGestureDetectorPtr New(unsigned int minTouches, unsigned int maxTouches);
+
+ /**
+ * Construct a new GestureDetector.
+ */
+ LongPressGestureDetector();
+
+ /**
+ * Create a new gesture detector with the specified minimum and maximum touches.
+ * @param[in] minTouches The minimum number of touches required.
+ * @param[in] maxTouches The maximum number of touches required.
+ */
+ LongPressGestureDetector(unsigned int minTouches, unsigned int maxTouches);
+
+public:
+
+ /**
+ * @copydoc Dali::LongPressGestureDetector::SetTouchesRequired(unsigned int)
+ */
+ void SetTouchesRequired(unsigned int touches);
+
+ /**
+ * @copydoc Dali::LongPressGestureDetector::SetTouchesRequired(unsigned int, unsigned int)
+ */
+ void SetTouchesRequired(unsigned int minTouches, unsigned int maxTouches);
+
+ /**
+ * @copydoc Dali::LongPressGestureDetector::GetMinimumTouchesRequired()
+ */
+ unsigned int GetMinimumTouchesRequired() const;
+
+ /**
+ * @copydoc Dali::LongPressGestureDetector::GetMaximumTouchesRequired()
+ */
+ unsigned int GetMaximumTouchesRequired() const;
+
+public:
+
+ /**
+ * Called by the LongPressGestureProcessor when a tap gesture event occurs within the bounds of our
+ * attached actor.
+ * @param[in] pressedActor The pressed actor.
+ * @param[in] longPress The long press
+ */
+ void EmitLongPressGestureSignal(Dali::Actor pressedActor, const LongPressGesture& longPress);
+
+public: // Signals
+
+ /**
+ * @copydoc Dali::LongPressGestureDetector::DetectedSignal()
+ */
+ Dali::LongPressGestureDetector::DetectedSignalType& DetectedSignal()
+ {
+ return mDetectedSignal;
+ }
+
+ /**
+ * Connects a callback function with the object's signals.
+ * @param[in] object The object providing the signal.
+ * @param[in] tracker Used to disconnect the signal.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
+ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+protected:
+
+ /**
+ * A reference counted object may only be deleted by calling Unreference()
+ */
+ virtual ~LongPressGestureDetector();
+
+private:
+
+ // Undefined
+ LongPressGestureDetector(const LongPressGestureDetector&);
+ LongPressGestureDetector& operator=(const LongPressGestureDetector& rhs);
+
+private: // GestureDetector overrides
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&)
+ */
+ virtual void OnActorAttach(Actor& actor);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDetach(Actor&)
+ */
+ virtual void OnActorDetach(Actor& actor);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDestroyed(Object&)
+ */
+ virtual void OnActorDestroyed(Object& object);
+
+private:
+
+ Dali::LongPressGestureDetector::DetectedSignalType mDetectedSignal;
+
+ unsigned int mMinimumTouchesRequired;
+ unsigned int mMaximumTouchesRequired;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::LongPressGestureDetector& GetImplementation(Dali::LongPressGestureDetector& detector)
+{
+ DALI_ASSERT_ALWAYS( detector && "LongPressGestureDetector handle is empty" );
+
+ BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<Internal::LongPressGestureDetector&>(handle);
+}
+
+inline const Internal::LongPressGestureDetector& GetImplementation(const Dali::LongPressGestureDetector& detector)
+{
+ DALI_ASSERT_ALWAYS( detector && "LongPressGestureDetector handle is empty" );
+
+ const BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<const Internal::LongPressGestureDetector&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_LONG_PRESS_GESTURE_DETECTOR_IMPL_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+LongPressGestureEvent::LongPressGestureEvent( Gesture::State state )
+: GestureEvent( Gesture::LongPress, state ),
+ numberOfTouches(1)
+{
+}
+
+LongPressGestureEvent::~LongPressGestureEvent()
+{
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_LONG_PRESS_GESTURE_H
+#define DALI_INTERNAL_EVENT_LONG_PRESS_GESTURE_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/gesture-event.h>
+#include <dali/public-api/math/vector2.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+/**
+ * If the adaptor detects a long press gesture, then it should create an instance of this structure and
+ * send it to the Core.
+ *
+ * This gesture can be in four states:
+ * - Possible: When the user first puts their finger down - Core needs to hit test the down point.
+ * - Started: When the long-press gesture is actually detected.
+ * - Finished: When the user finally lifts all touches.
+ * - Cancelled: If, after a down event, no long press is detected, or a system interruption.
+ */
+struct LongPressGestureEvent : public GestureEvent
+{
+ // Construction & Destruction
+
+ /**
+ * Default Constructor
+ * @param[in] state Started, when we detect a long press.
+ * Finished, when all touches are finished.
+ */
+ LongPressGestureEvent( Gesture::State state );
+
+ /**
+ * Virtual destructor
+ */
+ virtual ~LongPressGestureEvent();
+
+ // Data
+
+ /**
+ * @copydoc Dali::LongPressGesture::numberOfTouches
+ */
+ unsigned int numberOfTouches;
+
+ /**
+ * This is the point, in screen coordinates, where the long press occurred.
+ * If a multi-touch tap, then this should be the centroid of all the touch points.
+ */
+ Vector2 point;
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_LONG_PRESS_GESTURE_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-processor.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/events/long-press-gesture.h>
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-event.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/event/actors/actor-impl.h>
+#include <dali/internal/event/common/scene-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.h>
+#include <dali/internal/event/events/gesture-requests.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+/**
+ * Creates a LongPressGesture and asks the specified detector to emit its detected signal.
+ * @param[in] actor The actor on which the long press gesture has occurred.
+ * @param[in] gestureDetectors A reference to gesture detectors that should emit the signal.
+ * @param[in] longPressEvent The longPressEvent received from the adaptor.
+ * @param[in] localPoint Relative to the actor attached to the detector.
+ */
+void EmitLongPressSignal(
+ Actor* actor,
+ const GestureDetectorContainer& gestureDetectors,
+ const LongPressGestureEvent& longPressEvent,
+ Vector2 localPoint)
+{
+ LongPressGesture longPress(longPressEvent.state);
+ longPress.time = longPressEvent.time;
+ longPress.numberOfTouches = longPressEvent.numberOfTouches;
+ longPress.screenPoint = longPressEvent.point;
+ longPress.localPoint = localPoint;
+
+ Dali::Actor actorHandle( actor );
+ const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
+ for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
+ {
+ static_cast< LongPressGestureDetector* >( *iter )->EmitLongPressGestureSignal( actorHandle, longPress );
+ }
+}
+
+/**
+ * Functor which checks whether the specified actor is attached to the gesture detector.
+ * It returns true if it is no longer attached. This can be used in remove_if functions.
+ */
+struct IsNotAttachedFunctor
+{
+ /**
+ * Constructor
+ * @param[in] actor The actor to check whether it is attached.
+ */
+ IsNotAttachedFunctor( Actor* actor )
+ : actorToCheck( actor )
+ {
+ }
+
+ /**
+ * Returns true if not attached, false if it is still attached.
+ * @param[in] detector The detector to check.
+ * @return true, if not attached, false otherwise.
+ */
+ bool operator()( const GestureDetector* detector ) const
+ {
+ return !detector->IsAttached( *actorToCheck );
+ }
+
+ Actor* actorToCheck; ///< The actor to check whether it is attached or not.
+};
+
+} // unnamed namespace
+
+LongPressGestureProcessor::LongPressGestureProcessor()
+: GestureProcessor( Gesture::LongPress ),
+ mLongPressGestureDetectors(),
+ mCurrentEmitters(),
+ mCurrentRenderTask(),
+ mMinTouchesRequired( 1 ),
+ mMaxTouchesRequired( 1 ),
+ mCurrentLongPressEvent( NULL )
+{
+}
+
+LongPressGestureProcessor::~LongPressGestureProcessor()
+{
+}
+
+void LongPressGestureProcessor::Process( Scene& scene, const LongPressGestureEvent& longPressEvent )
+{
+ switch ( longPressEvent.state )
+ {
+ case Gesture::Possible:
+ {
+ mCurrentEmitters.clear();
+ ResetActor();
+
+ HitTestAlgorithm::Results hitTestResults;
+ if( HitTest( scene, longPressEvent.point, hitTestResults ) )
+ {
+ SetActor( &GetImplementation( hitTestResults.actor ) );
+ }
+ break;
+ }
+
+ case Gesture::Started:
+ {
+ Actor* currentGesturedActor = GetCurrentGesturedActor();
+ if ( currentGesturedActor )
+ {
+ HitTestAlgorithm::Results hitTestResults;
+ HitTest( scene, longPressEvent.point, hitTestResults );
+
+ if ( hitTestResults.actor && ( currentGesturedActor == &GetImplementation( hitTestResults.actor ) ) )
+ {
+ // Record the current render-task for Screen->Actor coordinate conversions
+ mCurrentRenderTask = hitTestResults.renderTask;
+
+ // Set mCurrentLongPressEvent to use inside overridden methods called from ProcessAndEmit()
+ mCurrentLongPressEvent = &longPressEvent;
+ ProcessAndEmit( hitTestResults );
+ mCurrentLongPressEvent = NULL;
+ }
+ else
+ {
+ mCurrentEmitters.clear();
+ ResetActor();
+ }
+ }
+ break;
+ }
+
+ case Gesture::Finished:
+ {
+ // The gesture should only be sent to the gesture detector which first received it so that it
+ // can be told when the gesture ends as well.
+
+ // Only send subsequent long press gesture signals if we processed the gesture when it started.
+ // Check if actor is still touchable.
+
+ Actor* currentGesturedActor = GetCurrentGesturedActor();
+ if ( currentGesturedActor )
+ {
+ if ( currentGesturedActor->IsHittable() && !mCurrentEmitters.empty() && mCurrentRenderTask )
+ {
+ // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
+ GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentEmitters.begin(), mCurrentEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
+ mCurrentEmitters.erase( endIter, mCurrentEmitters.end() );
+
+ if ( !mCurrentEmitters.empty() )
+ {
+ Vector2 actorCoords;
+ RenderTask& renderTaskImpl = *mCurrentRenderTask.Get();
+ currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, longPressEvent.point.x, longPressEvent.point.y );
+
+ EmitLongPressSignal( currentGesturedActor, mCurrentEmitters, longPressEvent, actorCoords );
+ }
+ }
+
+ // Clear current emitters and emitted actor
+ mCurrentEmitters.clear();
+ ResetActor();
+ }
+ break;
+ }
+
+ case Gesture::Cancelled:
+ {
+ mCurrentEmitters.clear();
+ ResetActor();
+ break;
+ }
+
+ case Gesture::Continuing:
+ {
+ DALI_ABORT( "Incorrect state received from Integration layer: Continuing\n" );
+ break;
+ }
+
+ case Gesture::Clear:
+ {
+ DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
+ break;
+ }
+ }
+}
+
+void LongPressGestureProcessor::AddGestureDetector( LongPressGestureDetector* gestureDetector, Scene& scene )
+{
+ bool firstRegistration(mLongPressGestureDetectors.empty());
+
+ mLongPressGestureDetectors.push_back(gestureDetector);
+
+ if (firstRegistration)
+ {
+ mMinTouchesRequired = gestureDetector->GetMinimumTouchesRequired();
+ mMaxTouchesRequired = gestureDetector->GetMaximumTouchesRequired();
+
+ LongPressGestureRequest request;
+ request.minTouches = mMinTouchesRequired;
+ request.maxTouches = mMaxTouchesRequired;
+
+ Size size = scene.GetSize();
+
+ mGestureRecognizer = new LongPressGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const LongPressGestureRequest&>(request));
+ }
+ else
+ {
+ UpdateDetection();
+ }
+}
+
+void LongPressGestureProcessor::RemoveGestureDetector( LongPressGestureDetector* gestureDetector )
+{
+ // Find detector ...
+ LongPressGestureDetectorContainer::iterator endIter = std::remove( mLongPressGestureDetectors.begin(), mLongPressGestureDetectors.end(), gestureDetector );
+ DALI_ASSERT_DEBUG( endIter != mLongPressGestureDetectors.end() );
+
+ // ... and remove it
+ mLongPressGestureDetectors.erase( endIter, mLongPressGestureDetectors.end() );
+
+ if ( mLongPressGestureDetectors.empty() )
+ {
+ mGestureRecognizer.Detach();
+ }
+ else
+ {
+ UpdateDetection();
+ }
+}
+
+void LongPressGestureProcessor::GestureDetectorUpdated( LongPressGestureDetector* gestureDetector )
+{
+ DALI_ASSERT_DEBUG( find( mLongPressGestureDetectors.begin(), mLongPressGestureDetectors.end(), gestureDetector ) != mLongPressGestureDetectors.end() );
+
+ UpdateDetection();
+}
+
+void LongPressGestureProcessor::UpdateDetection()
+{
+ DALI_ASSERT_DEBUG(!mLongPressGestureDetectors.empty());
+
+ unsigned int minimumRequired = UINT_MAX;
+ unsigned int maximumRequired = 0;
+
+ for ( LongPressGestureDetectorContainer::iterator iter = mLongPressGestureDetectors.begin(), endIter = mLongPressGestureDetectors.end(); iter != endIter; ++iter )
+ {
+ LongPressGestureDetector* current(*iter);
+
+ if( current )
+ {
+ unsigned int minimum = current->GetMinimumTouchesRequired();
+ if (minimum < minimumRequired)
+ {
+ minimumRequired = minimum;
+ }
+
+ unsigned int maximum = current->GetMaximumTouchesRequired();
+ if ( maximum > maximumRequired )
+ {
+ maximumRequired = maximum;
+ }
+ }
+ }
+
+ if ( (minimumRequired != mMinTouchesRequired) || (maximumRequired != mMaxTouchesRequired) )
+ {
+ mMinTouchesRequired = minimumRequired;
+ mMaxTouchesRequired = maximumRequired;
+
+ LongPressGestureRequest request;
+ request.minTouches = mMinTouchesRequired;
+ request.maxTouches = mMaxTouchesRequired;
+ mGestureRecognizer->Update(request);
+ }
+}
+
+void LongPressGestureProcessor::OnGesturedActorStageDisconnection()
+{
+ mCurrentEmitters.clear();
+}
+
+bool LongPressGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
+{
+ DALI_ASSERT_DEBUG( mCurrentLongPressEvent );
+
+ LongPressGestureDetector* longPressDetector ( static_cast< LongPressGestureDetector* >( detector ) );
+
+ return ( longPressDetector->GetMinimumTouchesRequired() <= mCurrentLongPressEvent->numberOfTouches ) &&
+ ( longPressDetector->GetMaximumTouchesRequired() >= mCurrentLongPressEvent->numberOfTouches );
+}
+
+void LongPressGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
+{
+ DALI_ASSERT_DEBUG( mCurrentLongPressEvent );
+
+ mCurrentEmitters.clear();
+ ResetActor();
+
+ EmitLongPressSignal( actor, gestureDetectors, *mCurrentLongPressEvent, actorCoordinates );
+
+ if ( actor->OnStage() )
+ {
+ mCurrentEmitters = gestureDetectors;
+ SetActor( actor );
+ }
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_LONG_PRESS_GESTURE_EVENT_PROCESSOR_H
+#define DALI_INTERNAL_LONG_PRESS_GESTURE_EVENT_PROCESSOR_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.h>
+#include <dali/internal/event/events/gesture-processor.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+class Stage;
+class Scene;
+
+struct GestureEvent;
+struct LongPressGestureEvent;
+
+/**
+ * Long Press Gesture Event Processing:
+ *
+ * When we receive a long press gesture event, we do the following:
+ * - Find the actor that requires a long-press at the long press position.
+ * - Emit the gesture if the event satisfies the detector conditions.
+ */
+class LongPressGestureProcessor : public GestureProcessor, public RecognizerObserver<LongPressGestureEvent>
+{
+public:
+
+ /**
+ * Create a long press gesture processor.
+ */
+ LongPressGestureProcessor();
+
+ /**
+ * Non-virtual destructor; LongPressGestureProcessor is not a base class
+ */
+ ~LongPressGestureProcessor();
+
+public: // To be called by GestureEventProcessor
+
+ /**
+ * This method is called whenever a long press gesture event occurs.
+ * @param[in] scene The scene the long press gesture event occurs in.
+ * @param[in] longPressEvent The event that has occurred.
+ */
+ void Process( Scene& scene, const LongPressGestureEvent& longPressEvent );
+
+ /**
+ * Adds a gesture detector to this gesture processor.
+ * If this is the first gesture detector being added, then this method registers the required
+ * gesture with the adaptor.
+ * @param[in] gestureDetector The gesture detector being added.
+ * @param[in] scene The scene the long press gesture event occurs in.
+ */
+ void AddGestureDetector( LongPressGestureDetector* gestureDetector, Scene& scene );
+
+ /**
+ * Removes the specified gesture detector from this gesture processor. If, after removing this
+ * gesture detector, there are no more gesture detectors registered, then this method unregisters
+ * the gesture from the adaptor.
+ * @param[in] gestureDetector The gesture detector being removed.
+ */
+ void RemoveGestureDetector( LongPressGestureDetector* gestureDetector );
+
+ /**
+ * This method updates the gesture detection parameters.
+ * @param[in] gestureDetector The gesture detector that has been updated.
+ */
+ void GestureDetectorUpdated(LongPressGestureDetector* gestureDetector);
+
+private:
+
+ // Undefined
+ LongPressGestureProcessor( const LongPressGestureProcessor& );
+ LongPressGestureProcessor& operator=( const LongPressGestureProcessor& rhs );
+
+private:
+
+ /**
+ * Iterates through our GestureDetectors and determines if we need to ask the adaptor to update
+ * its detection policy. If it does, it sends the appropriate gesture update request to adaptor.
+ */
+ void UpdateDetection();
+
+ // GestureProcessor overrides
+
+ /**
+ * @copydoc GestureProcessor::OnGesturedActorStageDisconnection()
+ */
+ void OnGesturedActorStageDisconnection();
+
+ /**
+ * @copydoc GestureProcessor::CheckGestureDetector()
+ */
+ bool CheckGestureDetector( GestureDetector* detector, Actor* actor );
+
+ /**
+ * @copydoc GestureProcessor::EmitGestureSignal()
+ */
+ void EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates );
+
+private:
+
+ LongPressGestureDetectorContainer mLongPressGestureDetectors;
+
+ GestureDetectorContainer mCurrentEmitters;
+ RenderTaskPtr mCurrentRenderTask;
+
+ uint32_t mMinTouchesRequired;
+ uint32_t mMaxTouchesRequired;
+
+ const LongPressGestureEvent* mCurrentLongPressEvent; ///< Pointer to current longPressEvent, used when calling ProcessAndEmit()
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_LONG_PRESS_GESTURE_EVENT_PROCESSOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/math/vector2.h>
+
+#include <dali/internal/event/common/thread-local-storage.h>
+#include <dali/internal/event/events/gesture-requests.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/platform-abstraction.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+// TODO: Set these according to DPI
+const float MAXIMUM_MOTION_ALLOWED = 60.0f;
+// TODO: Set this time according to system setting (vconf)
+const unsigned long LONG_PRESS_TIME = 500u;
+} // unnamed namespace
+
+LongPressGestureRecognizer::LongPressGestureRecognizer(Observer& observer, Vector2 screenSize, const LongPressGestureRequest& request )
+: GestureRecognizer( screenSize, Gesture::LongPress ),
+ mObserver( observer ),
+ mState( Clear ),
+ mMinimumTouchesRequired( request.minTouches ),
+ mMaximumTouchesRequired( request.maxTouches ),
+ mTouchTime( 0 ),
+ mTimerId( 0 )
+{
+}
+
+LongPressGestureRecognizer::~LongPressGestureRecognizer()
+{
+}
+
+void LongPressGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
+{
+ unsigned int pointCount( event.GetPointCount() );
+ Dali::Integration::PlatformAbstraction& platformAbstraction = ThreadLocalStorage::Get().GetPlatformAbstraction();
+
+ switch (mState)
+ {
+ // Clear: Wait till one point touches the screen before starting timer.
+ case Clear:
+ {
+ const Integration::Point& point = event.points[0];
+
+ if ( point.GetState() == PointState::DOWN )
+ {
+ mTouchPositions.clear();
+ mTouchPositions[point.GetDeviceId()] = point.GetScreenPosition();
+
+ mTouchTime = event.time;
+
+ mTimerId = platformAbstraction.StartTimer(GetSystemValue(), MakeCallback( this, &LongPressGestureRecognizer::TimerCallback));
+
+ // A long press gesture may be possible, tell Core about this and change state to Touched.
+ mState = Touched;
+ EmitGesture( Gesture::Possible );
+ }
+
+ break;
+ }
+
+ // Touched: Monitor movement and addition/removal of points.
+ case Touched:
+ {
+ if (pointCount > mMaximumTouchesRequired)
+ {
+ // A long press did not occur, tell Core that it was cancelled and change state to Failed.
+ EmitGesture( Gesture::Cancelled );
+ mTouchPositions.clear();
+ platformAbstraction.CancelTimer(mTimerId);
+ mState = Failed;
+ break;
+ }
+
+ bool endLoop(false);
+
+ for ( Integration::PointContainerConstIterator iter = event.points.begin(), endIter = event.points.end();
+ iter != endIter && !endLoop; ++iter)
+ {
+ switch( iter->GetState() )
+ {
+ // add point.
+ case PointState::DOWN:
+ {
+ mTouchPositions[iter->GetDeviceId()] = iter->GetScreenPosition();
+ break;
+ }
+
+ // remove point.
+ case PointState::UP:
+ case PointState::INTERRUPTED:
+ {
+ // System has interrupted us, long press is not possible, inform Core
+ EmitGesture( Gesture::Cancelled );
+ mTouchPositions.clear();
+ platformAbstraction.CancelTimer(mTimerId);
+ mState = ( pointCount == 1 ) ? Clear : Failed; // Change state to Clear if only one point, Failed otherwise.
+ endLoop = true;
+ break;
+ }
+
+ case PointState::MOTION:
+ {
+ const Vector2 touchPosition( mTouchPositions[iter->GetDeviceId()] - iter->GetScreenPosition() );
+ float distanceSquared = touchPosition.LengthSquared();
+
+ if (distanceSquared > ( MAXIMUM_MOTION_ALLOWED * MAXIMUM_MOTION_ALLOWED ) )
+ {
+ // We have moved more than the allowable motion for a long press gesture. Inform Core and change state to Failed.
+ EmitGesture( Gesture::Cancelled );
+ platformAbstraction.CancelTimer(mTimerId);
+ mState = Failed;
+ endLoop = true;
+ }
+ break;
+ }
+
+ case PointState::STATIONARY:
+ case PointState::LEAVE:
+ {
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ // Failed/Finished: Monitor the touches, waiting for all touches to be released.
+ case Failed:
+ case Finished:
+ {
+ // eventually the final touch point will be removed, marking the end of this gesture.
+ if ( pointCount == 1 )
+ {
+ PointState::Type primaryPointState = event.points[0].GetState();
+
+ if ( (primaryPointState == PointState::UP) || (primaryPointState == PointState::INTERRUPTED) )
+ {
+ if(mState == Finished)
+ {
+ // When the last touch point is lifted, we should inform the Core that the Long press has finished.
+ EmitGesture(Gesture::Finished);
+ }
+ mTouchPositions.clear();
+ mState = Clear; // Reset state to clear when last touch point is lifted.
+ }
+ }
+ break;
+ }
+ }
+}
+
+void LongPressGestureRecognizer::Update(const GestureRequest& request)
+{
+ const LongPressGestureRequest& longPress = static_cast<const LongPressGestureRequest&>(request);
+
+ mMinimumTouchesRequired = longPress.minTouches;
+ mMaximumTouchesRequired = longPress.maxTouches;
+}
+
+bool LongPressGestureRecognizer::TimerCallback()
+{
+ EmitGesture(Gesture::Started);
+
+ mState = Finished;
+
+ return false;
+}
+
+void LongPressGestureRecognizer::EmitGesture(Gesture::State state)
+{
+ unsigned int touchPoints ( static_cast<unsigned int>( mTouchPositions.size() ) );
+
+ // We should tell Core about the Possible and Cancelled states regardless of whether we have satisfied long press requirements.
+ if ( (state == Gesture::Possible) ||
+ (state == Gesture::Cancelled) ||
+ (touchPoints >= mMinimumTouchesRequired) )
+ {
+ LongPressGestureEvent longPress( state );
+ longPress.numberOfTouches = touchPoints;
+
+ for (std::map<int, Vector2>::iterator iter = mTouchPositions.begin(), endIter = mTouchPositions.end();
+ iter != endIter; ++iter)
+ {
+ longPress.point += iter->second;
+ }
+ longPress.point /= static_cast<float>( touchPoints );
+
+ longPress.time = mTouchTime;
+ if ( state != Gesture::Possible )
+ {
+ longPress.time += GetSystemValue();
+ }
+
+ if( mScene )
+ {
+ // Create another handle so the recognizer cannot be destroyed during process function
+ GestureRecognizerPtr recognizerHandle = this;
+
+ mObserver.Process(*mScene, longPress);
+ }
+ }
+}
+
+int LongPressGestureRecognizer::GetSystemValue()
+{
+ return LONG_PRESS_TIME;
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_LONG_PRESS_GESTURE_RECOGNIZER_H
+#define DALI_INTERNAL_LONG_PRESS_GESTURE_RECOGNIZER_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <map>
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/gesture-recognizer.h>
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+
+}
+
+namespace Internal
+{
+
+struct LongPressGestureRequest;
+class CoreEventInterface;
+
+/**
+ * When given a set of touch events, this detector attempts to determine if a long press gesture has taken place.
+ * Emits a LongPressGestureEvent (state = Started) when a long press has been detected (Touch held down for more than duration).
+ * Emits a further LongPressGestureEvent (state = Finished) when a long press has been completed (Touch Release).
+ */
+class LongPressGestureRecognizer : public GestureRecognizer
+{
+public:
+
+ using Observer = RecognizerObserver<LongPressGestureEvent>;
+
+ /**
+ * Constructor
+ * @param[in] coreEventInterface Used to send events to Core.
+ * @param[in] screenSize The size of the screen.
+ * @param[in] request The long press gesture request.
+ */
+ LongPressGestureRecognizer( Observer& observer, Vector2 screenSize, const LongPressGestureRequest& request );
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~LongPressGestureRecognizer();
+
+public:
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
+ */
+ virtual void SendEvent(const Integration::TouchEvent& event);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
+ */
+ virtual void Update(const GestureRequest& request);
+
+private:
+
+ /**
+ * Timer Callback
+ * @return will return false; one-shot timer.
+ */
+ bool TimerCallback();
+
+ /**
+ * Emits the long press gesture if all conditions are applicable.
+ * @param[in] state The state of this gesture event.
+ */
+ void EmitGesture(Gesture::State state);
+
+ /**
+ * Get current system setting value for tap and hold gesture
+ * @return system value for tap and hold gesture [ms]
+ */
+ int GetSystemValue();
+
+private:
+
+ // Reference to the gesture processor for this recognizer
+ Observer& mObserver;
+
+ /**
+ * Internal state machine.
+ */
+ enum State
+ {
+ Clear, ///< No gesture detected.
+ Touched, ///< User is touching the screen.
+ Failed, ///< Gesture has failed.
+ Finished ///< Gesture has been detected and sent.
+ };
+
+ State mState; ///< The current state of the detector.
+
+ unsigned int mMinimumTouchesRequired; ///< The minimum touches required before emitting a long press.
+ unsigned int mMaximumTouchesRequired; ///< The maximum touches allowable. Any more and a long press is not emitted.
+
+ std::map<int, Vector2> mTouchPositions; ///< A map with all the touch down positions.
+ uint32_t mTouchTime; ///< The time we first pressed down.
+
+ uint32_t mTimerId;
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_LONG_PRESS_GESTURE_RECOGNIZER_H
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/pan-gesture-detector-impl.h>
-
-// EXTERNAL INCLUDES
-#include <cstring> // for strcmp
-
-// INTERNAL INCLUDES
-#include <dali/public-api/events/pan-gesture.h>
-#include <dali/public-api/object/type-registry.h>
-#include <dali/public-api/math/radian.h>
-#include <dali/public-api/math/degree.h>
-#include <dali/integration-api/debug.h>
-#include <dali/internal/event/actors/actor-impl.h>
-#include <dali/internal/event/common/property-helper.h>
-#include <dali/internal/event/common/thread-local-storage.h>
-#include <dali/internal/event/events/gesture-event-processor.h>
-#include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-
-// Properties
-
-// Name Type writable animatable constraint-input enum for index-checking
-DALI_PROPERTY_TABLE_BEGIN
-DALI_PROPERTY( "screenPosition", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::SCREEN_POSITION )
-DALI_PROPERTY( "screenDisplacement", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT )
-DALI_PROPERTY( "screenVelocity", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::SCREEN_VELOCITY )
-DALI_PROPERTY( "localPosition", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::LOCAL_POSITION )
-DALI_PROPERTY( "localDisplacement", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT )
-DALI_PROPERTY( "localVelocity", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::LOCAL_VELOCITY )
-DALI_PROPERTY( "panning", BOOLEAN, false, false, true, Dali::PanGestureDetector::Property::PANNING )
-DALI_PROPERTY_TABLE_END( DEFAULT_GESTURE_DETECTOR_PROPERTY_START_INDEX, PanGestureDetectorDefaultProperties )
-
-// Signals
-
-const char* const SIGNAL_PAN_DETECTED = "panDetected";
-
-BaseHandle Create()
-{
- return Dali::PanGestureDetector::New();
-}
-
-TypeRegistration mType( typeid(Dali::PanGestureDetector), typeid(Dali::GestureDetector), Create, PanGestureDetectorDefaultProperties );
-
-SignalConnectorType signalConnector1( mType, SIGNAL_PAN_DETECTED, &PanGestureDetector::DoConnectSignal );
-
-#if defined(DEBUG_ENABLED)
-Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_PAN_GESTURE_DETECTOR");
-#endif
-
-/**
- * Returns the angle going in the opposite direction to that specified by angle.
- */
-float GetOppositeAngle( float angle )
-{
- // Calculate the opposite angle so that we cover both directions.
- if ( angle <= 0.0f )
- {
- angle += Math::PI;
- }
- else
- {
- angle -= Math::PI;
- }
-
- return angle;
-}
-
-} // unnamed namespace
-
-PanGestureDetectorPtr PanGestureDetector::New()
-{
- const SceneGraph::PanGesture& sceneObject = ThreadLocalStorage::Get().GetGestureEventProcessor().GetPanGestureProcessor().GetSceneObject();
- return new PanGestureDetector( sceneObject );
-}
-
-void PanGestureDetector::SetMinimumTouchesRequired(unsigned int minimum)
-{
- DALI_ASSERT_ALWAYS( minimum > 0 && "Can only set a positive number of required touches" );
-
- if (mMinimumTouches != minimum)
- {
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "Minimum Touches Set: %d\n", minimum );
-
- mMinimumTouches = minimum;
-
- if (!mAttachedActors.empty())
- {
- DALI_LOG_INFO( gLogFilter, Debug::General, "Updating Gesture Detector\n");
-
- mGestureEventProcessor.GestureDetectorUpdated(this);
- }
- }
-}
-
-void PanGestureDetector::SetMaximumTouchesRequired(unsigned int maximum)
-{
- DALI_ASSERT_ALWAYS( maximum > 0 && "Can only set a positive number of maximum touches" );
-
- if (mMaximumTouches != maximum)
- {
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "Maximum Touches Set: %d\n", maximum );
-
- mMaximumTouches = maximum;
-
- if (!mAttachedActors.empty())
- {
- DALI_LOG_INFO( gLogFilter, Debug::General, "Updating Gesture Detector\n");
-
- mGestureEventProcessor.GestureDetectorUpdated(this);
- }
- }
-}
-
-uint32_t PanGestureDetector::GetMinimumTouchesRequired() const
-{
- return mMinimumTouches;
-}
-
-uint32_t PanGestureDetector::GetMaximumTouchesRequired() const
-{
- return mMaximumTouches;
-}
-
-void PanGestureDetector::AddAngle( Radian angle, Radian threshold )
-{
- threshold = fabsf( threshold ); // Ensure the threshold is positive.
-
- // If the threshold is greater than PI, then just use PI
- // This means that any panned angle will invoke the pan gesture. We should still add this angle as
- // an angle may have been added previously with a small threshold.
- if ( threshold > Math::PI )
- {
- threshold = Math::PI;
- }
-
- angle = WrapInDomain( angle, -Math::PI, Math::PI );
-
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "Angle Added: %.2f, Threshold: %.2f\n", Degree(angle), Degree(threshold) );
-
- AngleThresholdPair pair( angle, threshold );
- mAngleContainer.push_back( pair );
-}
-
-void PanGestureDetector::AddDirection( Radian direction, Radian threshold )
-{
- AddAngle( direction, threshold );
-
- // Calculate the opposite angle so that we cover the entire direction.
- direction = GetOppositeAngle( direction );
-
- AddAngle( direction, threshold );
-}
-
-uint32_t PanGestureDetector::GetAngleCount() const
-{
- return static_cast<uint32_t>( mAngleContainer.size() );
-}
-
-PanGestureDetector::AngleThresholdPair PanGestureDetector::GetAngle(uint32_t index) const
-{
- PanGestureDetector::AngleThresholdPair ret( Radian(0),Radian(0) );
-
- if( index < mAngleContainer.size() )
- {
- ret = mAngleContainer[index];
- }
-
- return ret;
-}
-
-
-void PanGestureDetector::ClearAngles()
-{
- mAngleContainer.clear();
-}
-
-void PanGestureDetector::RemoveAngle( Radian angle )
-{
- angle = WrapInDomain( angle, -Math::PI, Math::PI );
-
- for (AngleContainer::iterator iter = mAngleContainer.begin(), endIter = mAngleContainer.end(); iter != endIter; ++iter )
- {
- if ( iter->first == angle )
- {
- mAngleContainer.erase( iter );
- break;
- }
- }
-}
-
-void PanGestureDetector::RemoveDirection( Radian direction )
-{
- RemoveAngle( direction );
-
- // Calculate the opposite angle so that we cover the entire direction.
- direction = GetOppositeAngle( direction );
-
- RemoveAngle( direction );
-}
-
-bool PanGestureDetector::RequiresDirectionalPan() const
-{
- // If no directional angles have been added to the container then we do not require directional panning
- return !mAngleContainer.empty();
-}
-
-bool PanGestureDetector::CheckAngleAllowed( Radian angle ) const
-{
- bool allowed( false );
- if ( mAngleContainer.empty() )
- {
- allowed = true;
- }
- else
- {
- for ( AngleContainer::const_iterator iter = mAngleContainer.begin(), endIter = mAngleContainer.end(); iter != endIter; ++iter )
- {
- float angleAllowed( iter->first );
- float threshold ( iter->second );
-
- DALI_LOG_INFO( gLogFilter, Debug::General,
- "AngleToCheck: %.2f, CompareWith: %.2f, Threshold: %.2f\n",
- Degree(angle), Degree(angleAllowed), Degree(threshold) );
-
- float relativeAngle( fabsf( WrapInDomain( angle - angleAllowed, -Math::PI, Math::PI ) ) );
- if ( relativeAngle <= threshold )
- {
- allowed = true;
- break;
- }
- }
- }
-
- return allowed;
-}
-
-void PanGestureDetector::EmitPanGestureSignal(Dali::Actor actor, const PanGesture& pan)
-{
- if ( !mDetectedSignal.Empty() )
- {
- // Guard against destruction during signal emission
- Dali::PanGestureDetector handle( this );
-
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Emitting Signal (%p)\n", this );
-
- mDetectedSignal.Emit( actor, pan );
- }
-}
-
-bool PanGestureDetector::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
-{
- bool connected( true );
- PanGestureDetector* gesture = static_cast< PanGestureDetector* >(object); // TypeRegistry guarantees that this is the correct type.
-
- if ( 0 == strcmp( signalName.c_str(), SIGNAL_PAN_DETECTED ) )
- {
- gesture->DetectedSignal().Connect( tracker, functor );
- }
- else
- {
- // signalName does not match any signal
- connected = false;
- }
-
- return connected;
-}
-
-void PanGestureDetector::SetPanGestureProperties( const PanGesture& pan )
-{
- ThreadLocalStorage::Get().GetGestureEventProcessor().SetGestureProperties( pan );
-}
-
-PanGestureDetector::PanGestureDetector( const SceneGraph::PanGesture& sceneObject )
-: GestureDetector(Gesture::Pan, &sceneObject ),
- mMinimumTouches(1),
- mMaximumTouches(1)
-{
-}
-
-PanGestureDetector::~PanGestureDetector()
-{
-}
-
-const SceneGraph::PanGesture& PanGestureDetector::GetPanGestureSceneObject() const
-{
- return static_cast<const SceneGraph::PanGesture&>( GetSceneObject() );
-}
-
-void PanGestureDetector::OnActorAttach(Actor& actor)
-{
- // Do nothing
-}
-
-void PanGestureDetector::OnActorDetach(Actor& actor)
-{
- // Do nothing
-}
-
-void PanGestureDetector::OnActorDestroyed(Object& object)
-{
- // Do nothing
-}
-
-void PanGestureDetector::SetDefaultProperty( Property::Index index, const Property::Value& property )
-{
- // None of our properties should be settable from Public API
-}
-
-Property::Value PanGestureDetector::GetDefaultProperty( Property::Index index ) const
-{
- return GetDefaultPropertyCurrentValue( index ); // Scene-graph only properties
-}
-
-Property::Value PanGestureDetector::GetDefaultPropertyCurrentValue( Property::Index index ) const
-{
- Property::Value value;
-
- switch ( index )
- {
- case Dali::PanGestureDetector::Property::SCREEN_POSITION:
- {
- value = GetPanGestureSceneObject().GetScreenPositionProperty().Get();
- break;
- }
-
- case Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT:
- {
- value = GetPanGestureSceneObject().GetScreenDisplacementProperty().Get();
- break;
- }
-
- case Dali::PanGestureDetector::Property::SCREEN_VELOCITY:
- {
- value = GetPanGestureSceneObject().GetScreenVelocityProperty().Get();
- break;
- }
-
- case Dali::PanGestureDetector::Property::LOCAL_POSITION:
- {
- value = GetPanGestureSceneObject().GetLocalPositionProperty().Get();
- break;
- }
-
- case Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT:
- {
- value = GetPanGestureSceneObject().GetLocalDisplacementProperty().Get();
- break;
- }
-
- case Dali::PanGestureDetector::Property::LOCAL_VELOCITY:
- {
- value = GetPanGestureSceneObject().GetLocalVelocityProperty().Get();
- break;
- }
-
- case Dali::PanGestureDetector::Property::PANNING:
- {
- value = GetPanGestureSceneObject().GetPanningProperty().Get();
- break;
- }
-
- default:
- {
- DALI_ASSERT_ALWAYS(false && "PanGestureDetector Property index invalid" ); // should not come here
- break;
- }
- }
-
- return value;
-}
-
-const PropertyInputImpl* PanGestureDetector::GetSceneObjectInputProperty( Property::Index index ) const
-{
- const PropertyInputImpl* property = nullptr;
-
- switch ( index )
- {
- case Dali::PanGestureDetector::Property::SCREEN_POSITION:
- {
- property = &GetPanGestureSceneObject().GetScreenPositionProperty();
- break;
- }
-
- case Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT:
- {
- property = &GetPanGestureSceneObject().GetScreenDisplacementProperty();
- break;
- }
-
- case Dali::PanGestureDetector::Property::SCREEN_VELOCITY:
- {
- property = &GetPanGestureSceneObject().GetScreenVelocityProperty();
- break;
- }
-
- case Dali::PanGestureDetector::Property::LOCAL_POSITION:
- {
- property = &GetPanGestureSceneObject().GetLocalPositionProperty();
- break;
- }
-
- case Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT:
- {
- property = &GetPanGestureSceneObject().GetLocalDisplacementProperty();
- break;
- }
-
- case Dali::PanGestureDetector::Property::LOCAL_VELOCITY:
- {
- property = &GetPanGestureSceneObject().GetLocalVelocityProperty();
- break;
- }
-
- case Dali::PanGestureDetector::Property::PANNING:
- {
- property = &GetPanGestureSceneObject().GetPanningProperty();
- break;
- }
-
- default:
- break;
- }
- if( !property )
- {
- // not our property, ask base
- property = Object::GetSceneObjectInputProperty( index );
- }
-
- return property;
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_PAN_GESTURE_DETECTOR_H
-#define DALI_INTERNAL_PAN_GESTURE_DETECTOR_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/public-api/events/gesture.h>
-#include <dali/public-api/events/pan-gesture-detector.h>
-#include <dali/public-api/math/vector2.h>
-#include <dali/internal/event/events/gesture-detector-impl.h>
-
-namespace Dali
-{
-
-struct TouchEvent;
-struct Radian;
-
-namespace Internal
-{
-
-class PanGestureDetector;
-typedef IntrusivePtr<PanGestureDetector> PanGestureDetectorPtr;
-typedef DerivedGestureDetectorContainer<PanGestureDetector>::type PanGestureDetectorContainer;
-
-namespace SceneGraph
-{
-class PanGesture;
-}
-
-/**
- * @copydoc Dali::PanGestureDetector
- */
-class PanGestureDetector : public GestureDetector
-{
-public: // Typedefs
-
- typedef Dali::PanGestureDetector::AngleThresholdPair AngleThresholdPair;
- typedef std::vector<AngleThresholdPair> AngleContainer;
-
-public: // Creation
-
- /**
- * Create a new gesture detector.
- * @return A smart-pointer to the newly allocated detector.
- */
- static PanGestureDetectorPtr New();
-
-public:
-
- /**
- * @copydoc Dali::PanGestureDetector::SetMinimumTouchesRequired(unsigned int)
- */
- void SetMinimumTouchesRequired(unsigned int minimum);
-
- /**
- * @copydoc Dali::PanGestureDetector::SetMaximumTouchesRequired(unsigned int)
- */
- void SetMaximumTouchesRequired(unsigned int maximum);
-
- /**
- * @copydoc Dali::PanGestureDetector::GetMinimumTouchesRequired() const
- */
- uint32_t GetMinimumTouchesRequired() const;
-
- /**
- * @copydoc Dali::PanGestureDetector::GetMaximumTouchesRequired() const
- */
- uint32_t GetMaximumTouchesRequired() const;
-
- /**
- * @copydoc Dali::PanGestureDetector::AddAngle()
- */
- void AddAngle( Radian angle, Radian threshold );
-
- /**
- * @copydoc Dali::PanGestureDetector::AddDirection()
- */
- void AddDirection( Radian direction, Radian threshold );
-
- /**
- * @copydoc Dali::PanGestureDetector::GetAngleCount()
- */
- uint32_t GetAngleCount() const;
-
- /**
- * @copydoc Dali::PanGestureDetector::GetAngle()
- */
- AngleThresholdPair GetAngle(uint32_t index) const;
-
- /**
- * @copydoc Dali::PanGestureDetector::ClearAngles()
- */
- void ClearAngles();
-
- /**
- * @copydoc Dali::PanGestureDetector::RemoveAngle()
- */
- void RemoveAngle( Radian angle );
-
- /**
- * @copydoc Dali::PanGestureDetector::RemoveDirection()
- */
- void RemoveDirection( Radian direction );
-
- /**
- * Checks whether the pan gesture detector requires a directional pan for emission.
- * @return true, if directional panning required, false otherwise.
- */
- bool RequiresDirectionalPan() const;
-
- /**
- * Checks whether the given pan angle is allowed for this gesture detector.
- * @param[in] angle The angle to check.
- */
- bool CheckAngleAllowed( Radian angle ) const;
-
-public:
-
- /**
- * Called by the PanGestureProcessor when a pan gesture event occurs within the bounds of our
- * attached actor.
- * @param[in] actor The panned actor.
- * @param[in] pan The pan gesture.
- */
- void EmitPanGestureSignal(Dali::Actor actor, const PanGesture& pan);
-
-public: // Signals
-
- /**
- * @copydoc Dali::PanGestureDetector::DetectedSignal()
- */
- Dali::PanGestureDetector::DetectedSignalType& DetectedSignal()
- {
- return mDetectedSignal;
- }
-
- /**
- * Connects a callback function with the object's signals.
- * @param[in] object The object providing the signal.
- * @param[in] tracker Used to disconnect the signal.
- * @param[in] signalName The signal to connect to.
- * @param[in] functor A newly allocated FunctorDelegate.
- * @return True if the signal was connected.
- * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
- */
- static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
-
-public: // Override Pan Gesture
-
- /**
- * @copydoc Dali::PanGestureDetector::SetPanGestureProperties()
- */
- static void SetPanGestureProperties( const PanGesture& pan );
-
-protected:
-
- /**
- * Construct a new PanGestureDetector.
- * @param sceneObject the scene object
- */
- PanGestureDetector( const SceneGraph::PanGesture& sceneObject );
-
- /**
- * A reference counted object may only be deleted by calling Unreference()
- */
- virtual ~PanGestureDetector();
-
-private:
-
- // Undefined
- PanGestureDetector() = delete;
- PanGestureDetector(const PanGestureDetector&) = delete;
- PanGestureDetector& operator=(const PanGestureDetector& rhs) = delete;
-
- /**
- * @return the pan gesture scene object
- */
- const SceneGraph::PanGesture& GetPanGestureSceneObject() const;
-
- // From GestureDetector
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&)
- */
- virtual void OnActorAttach(Actor& actor);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorDetach(Actor&)
- */
- virtual void OnActorDetach(Actor& actor);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorDestroyed(Object&)
- */
- virtual void OnActorDestroyed(Object& object);
-
-
- // Default property extensions from Object
-
- /**
- * @copydoc Dali::Internal::Object::SetDefaultProperty()
- */
- virtual void SetDefaultProperty(Property::Index index, const Property::Value& propertyValue);
-
- /**
- * @copydoc Dali::Internal::Object::GetDefaultProperty()
- */
- virtual Property::Value GetDefaultProperty( Property::Index index ) const;
-
- /**
- * @copydoc Dali::Internal::Object::GetDefaultPropertyCurrentValue()
- */
- virtual Property::Value GetDefaultPropertyCurrentValue( Property::Index index ) const;
-
- /**
- * @copydoc Dali::Internal::Object::GetSceneObjectInputProperty()
- */
- virtual const PropertyInputImpl* GetSceneObjectInputProperty( Property::Index index ) const;
-
-private:
-
- Dali::PanGestureDetector::DetectedSignalType mDetectedSignal;
-
- unsigned int mMinimumTouches; ///< The minimum number of fingers required to be touching for pan.
- unsigned int mMaximumTouches; ///< The maximum number of fingers required to be touching for pan.
-
- AngleContainer mAngleContainer; ///< A container of all angles allowed for pan to occur.
-
-};
-
-} // namespace Internal
-
-// Helpers for public-api forwarding methods
-
-inline Internal::PanGestureDetector& GetImplementation(Dali::PanGestureDetector& detector)
-{
- DALI_ASSERT_ALWAYS( detector && "PanGestureDetector handle is empty" );
-
- BaseObject& handle = detector.GetBaseObject();
-
- return static_cast<Internal::PanGestureDetector&>(handle);
-}
-
-inline const Internal::PanGestureDetector& GetImplementation(const Dali::PanGestureDetector& detector)
-{
- DALI_ASSERT_ALWAYS( detector && "PanGestureDetector handle is empty" );
-
- const BaseObject& handle = detector.GetBaseObject();
-
- return static_cast<const Internal::PanGestureDetector&>(handle);
-}
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_PAN_GESTURE_DETECTOR_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/pan-gesture-event.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-
-PanGestureEvent::PanGestureEvent(Gesture::State state)
-: GestureEvent(Gesture::Pan, state),
- timeDelta(0),
- numberOfTouches(1)
-{
-}
-
-PanGestureEvent::~PanGestureEvent()
-{
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_H
-#define DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/gesture-event.h>
-#include <dali/public-api/math/vector2.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-/**
- * If the adaptor detects a pan gesture, then it should create an instance of this structure and
- * send it to the Core.
- *
- * A Pan Gesture event should be in one of five states:
- * - Possible: When the user first puts their finger down - Core needs to hit test the down point.
- * - Started: If a pan is detected.
- * - Continuing: If after a pan is detected, it continues.
- * - Finished: If after a pan, the user lifts their finger(s).
- * - Cancelled: If, after a down event, no pan is detected or a system interruption.
- *
- * A Started state will be ignored if a Possible state does not precede it.
- * Likewise, a Continuing or Finished state will be ignored if a Started state does not precede it.
- */
-struct PanGestureEvent: public GestureEvent
-{
- // Construction & Destruction
-
- /**
- * Default Constructor
- * @param[in] state The state of the gesture
- */
- PanGestureEvent(Gesture::State state);
-
- /**
- * Virtual destructor
- */
- virtual ~PanGestureEvent();
-
- // Data
-
- /**
- * The previous touch position of the primary touch point in screen coordinates.
- */
- Vector2 previousPosition;
-
- /**
- * This current touch position of the primary touch point in screen coordinates.
- */
- Vector2 currentPosition;
-
- /**
- * The time difference between the previous and latest touch motion events (in ms).
- */
- unsigned long timeDelta;
-
- /**
- * The total number of fingers touching the screen in a pan gesture.
- */
- unsigned int numberOfTouches;
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/pan-gesture-processor.h>
-
-#if defined(DEBUG_ENABLED)
-#include <sstream>
-#endif
-
-// EXTERNAL INCLUDES
-#include <algorithm>
-
-// INTERNAL INCLUDES
-#include <dali/public-api/actors/actor.h>
-#include <dali/public-api/common/dali-common.h>
-#include <dali/public-api/events/pan-gesture.h>
-#include <dali/public-api/math/vector2.h>
-#include <dali/internal/event/events/pan-gesture-event.h>
-#include <dali/integration-api/debug.h>
-#include <dali/internal/event/common/scene-impl.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
-#include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
-#include <dali/internal/event/events/multi-point-event-util.h>
-#include <dali/internal/event/events/pan-gesture-recognizer.h>
-#include <dali/internal/event/events/gesture-requests.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace // unnamed namespace
-{
-
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_PAN_PROCESSOR" );
-
-const char * GESTURE_STATES[ 6 ] =
-{
- "Clear",
- "Started",
- "Continuing",
- "Finished",
- "Cancelled",
- "Possible"
-};
-
-#endif // defined(DEBUG_ENABLED)
-
-const unsigned long MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY( 50u );
-
-/**
- * Functor which checks whether the specified actor is attached to the gesture detector.
- * If the actor is attached, it also checks whether the number of touches of the current pan event
- * are within the range of that expected by the detector.
- * It returns true if it is no longer attached or the touches are out of range.
- * This can be used in remove_if functions.
- */
-struct IsNotAttachedAndOutsideTouchesRangeFunctor
-{
- /**
- * Constructor
- * @param[in] actor The actor to check whether it is attached.
- * @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, GestureDetectorContainer& outsideRangeEmitters)
- : actorToCheck(actor),
- numberOfTouches(touches),
- outsideTouchesRangeEmitters(outsideRangeEmitters)
- {
- }
-
- /**
- * Returns true if not attached, false if it is still attached.
- * Additionally, checks if the number of touches has changed and stops sending the pan to a particular
- * detector if it exceeds the range of that detector.
- * @param[in] detector The detector to check.
- * @return true, if not attached, false otherwise.
- */
- 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 < panDetector->GetMinimumTouchesRequired()) ||
- (numberOfTouches > panDetector->GetMaximumTouchesRequired()) )
- {
- remove = true;
- outsideTouchesRangeEmitters.push_back(detector);
- }
- }
-
- return remove;
- }
-
- Actor* actorToCheck; ///< The actor to check whether it is attached or not.
- unsigned int numberOfTouches; ///< The number of touches in the pan event.
- GestureDetectorContainer& outsideTouchesRangeEmitters; ///< Emitters that are outside of the range of current pan.
-};
-
-} // unnamed namespace
-
-PanGestureProcessor::PanGestureProcessor( SceneGraph::UpdateManager& updateManager )
-: GestureProcessor( Gesture::Pan ),
- mPanGestureDetectors(),
- mCurrentPanEmitters(),
- mCurrentRenderTask(),
- mPossiblePanPosition(),
- mMinTouchesRequired( 1 ),
- mMaxTouchesRequired( 1 ),
- mCurrentPanEvent( nullptr ),
- mSceneObject( SceneGraph::PanGesture::New() ) // Create scene object to store pan information.
-{
- // Pass ownership to scene-graph; scene object lives for the lifecycle of UpdateManager
- updateManager.SetPanGestureProcessor( mSceneObject );
-}
-
-PanGestureProcessor::~PanGestureProcessor()
-{
- mSceneObject = nullptr; // mSceneObject is owned and destroyed by update manager (there is only one of these for now)
-}
-
-void PanGestureProcessor::Process( Scene& scene, const PanGestureEvent& panEvent )
-{
-#if defined(DEBUG_ENABLED)
- DALI_LOG_TRACE_METHOD( gLogFilter );
-
- DALI_LOG_INFO( gLogFilter, Debug::General, " Pan Event\n");
- DALI_LOG_INFO( gLogFilter, Debug::General, " State: %s Touches: %d Time: %d TimeDelta: %d\n",
- GESTURE_STATES[panEvent.state], panEvent.numberOfTouches, panEvent.time, panEvent.timeDelta);
- DALI_LOG_INFO( gLogFilter, Debug::General, " Positions: Current: (%.0f, %.0f), Previous: (%.0f, %.0f)\n",
- panEvent.currentPosition.x, panEvent.currentPosition.y, panEvent.previousPosition.x, panEvent.previousPosition.y);
-#endif
-
- switch( panEvent.state )
- {
- case Gesture::Possible:
- {
- mCurrentPanEmitters.clear();
- ResetActor();
-
- HitTestAlgorithm::Results hitTestResults;
- if( HitTest( scene, panEvent.currentPosition, hitTestResults ) )
- {
- SetActor( &GetImplementation( hitTestResults.actor ) );
- mPossiblePanPosition = panEvent.currentPosition;
- }
-
- break;
- }
-
- case Gesture::Started:
- {
- // Requires a core update
- mNeedsUpdate = true;
-
- if ( GetCurrentGesturedActor() )
- {
- // The pan gesture should only be sent to the gesture detector which first received it so that
- // it can be told when the gesture ends as well.
-
- HitTestAlgorithm::Results hitTestResults;
- HitTest( scene, 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;
-
- // Set mCurrentPanEvent to use inside overridden methods called in ProcessAndEmit()
- mCurrentPanEvent = &panEvent;
- ProcessAndEmit( hitTestResults );
- mCurrentPanEvent = nullptr;
- }
- else
- {
- ResetActor();
- mCurrentPanEmitters.clear();
- }
- }
- break;
- }
-
- case Gesture::Continuing:
- {
- // Requires a core update
- mNeedsUpdate = true;
- }
- // No break, Fallthrough
- case Gesture::Finished:
- case Gesture::Cancelled:
- {
- // Only send subsequent pan gesture signals if we processed the pan gesture when it started.
- // Check if actor is still touchable.
-
- Actor* currentGesturedActor = GetCurrentGesturedActor();
- if ( currentGesturedActor )
- {
- if ( currentGesturedActor->IsHittable() && !mCurrentPanEmitters.empty() && mCurrentRenderTask )
- {
- 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
- GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(),
- IsNotAttachedAndOutsideTouchesRangeFunctor(currentGesturedActor, panEvent.numberOfTouches, outsideTouchesRangeEmitters) );
- mCurrentPanEmitters.erase( endIter, mCurrentPanEmitters.end() );
-
- Vector2 actorCoords;
-
- if ( !outsideTouchesRangeEmitters.empty() || !mCurrentPanEmitters.empty() )
- {
- currentGesturedActor->ScreenToLocal( *mCurrentRenderTask.Get(), 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( currentGesturedActor, outsideTouchesRangeEmitters, panEvent, actorCoords, Gesture::Finished, mCurrentRenderTask);
- EmitPanSignal( currentGesturedActor, mCurrentPanEmitters, panEvent, actorCoords, panEvent.state, mCurrentRenderTask);
- }
-
- if ( mCurrentPanEmitters.empty() )
- {
- // If we have no emitters attached then clear pan actor as well.
- ResetActor();
- }
-
- // Clear current gesture detectors if pan gesture has ended or been cancelled.
- if ( ( panEvent.state == Gesture::Finished ) || ( panEvent.state == Gesture::Cancelled ) )
- {
- mCurrentPanEmitters.clear();
- ResetActor();
- }
- }
- else
- {
- mCurrentPanEmitters.clear();
- ResetActor();
- }
- }
- break;
- }
-
- case Gesture::Clear:
- {
- DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
- break;
- }
- }
-}
-
-void PanGestureProcessor::AddGestureDetector( PanGestureDetector* gestureDetector, Scene& scene, int32_t minDistance, int32_t minPanEvents )
-{
- bool firstRegistration(mPanGestureDetectors.empty());
-
- mPanGestureDetectors.push_back(gestureDetector);
-
- if (firstRegistration)
- {
- mMinTouchesRequired = gestureDetector->GetMinimumTouchesRequired();
- mMaxTouchesRequired = gestureDetector->GetMaximumTouchesRequired();
-
- PanGestureRequest request;
- request.minTouches = mMinTouchesRequired;
- request.maxTouches = mMaxTouchesRequired;
-
- Size size = scene.GetSize();
- mGestureRecognizer = new PanGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const PanGestureRequest&>(request), minDistance, minPanEvents);
- }
- else
- {
- UpdateDetection();
- }
-}
-
-void PanGestureProcessor::RemoveGestureDetector( PanGestureDetector* gestureDetector )
-{
- if (!mCurrentPanEmitters.empty())
- {
- // Check if the removed detector was one that is currently being panned and remove it from emitters.
- 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
- if ( mCurrentPanEmitters.empty() )
- {
- ResetActor();
- }
- }
-
- // Find the detector...
- PanGestureDetectorContainer::iterator endIter = std::remove( mPanGestureDetectors.begin(), mPanGestureDetectors.end(), gestureDetector );
- DALI_ASSERT_DEBUG( endIter != mPanGestureDetectors.end() );
-
- // ...and remove it
- mPanGestureDetectors.erase(endIter, mPanGestureDetectors.end());
-
- if (mPanGestureDetectors.empty())
- {
- mGestureRecognizer.Detach();
- }
- else
- {
- UpdateDetection();
- }
-}
-
-void PanGestureProcessor::GestureDetectorUpdated( PanGestureDetector* gestureDetector )
-{
- DALI_ASSERT_DEBUG(find(mPanGestureDetectors.begin(), mPanGestureDetectors.end(), gestureDetector) != mPanGestureDetectors.end());
-
- UpdateDetection();
-}
-
-bool PanGestureProcessor::SetPanGestureProperties( const PanGesture& pan )
-{
- // If we are currently processing a pan gesture then just ignore
- if ( mCurrentPanEmitters.empty() && mSceneObject )
- {
- // We update the scene object directly rather than sending a message.
- // Sending a message could cause unnecessary delays, the scene object ensure thread safe behaviour.
- mSceneObject->AddGesture( pan );
-
- if( Gesture::Started == pan.state || Gesture::Continuing == pan.state )
- {
- mNeedsUpdate = true;
- }
- }
-
- return mNeedsUpdate;
-}
-
-void PanGestureProcessor::EnableProfiling()
-{
- mSceneObject->EnableProfiling();
-}
-
-void PanGestureProcessor::SetPredictionMode(int mode)
-{
- if( (mode < 0)
- || (mode >= SceneGraph::PanGesture::NUM_PREDICTION_MODES) )
- {
- mode = SceneGraph::PanGesture::DEFAULT_PREDICTION_MODE;
- }
- SceneGraph::PanGesture::PredictionMode modeEnum = static_cast<SceneGraph::PanGesture::PredictionMode>(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<SceneGraph::PanGesture::SmoothingMode>(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 );
-}
-
-const SceneGraph::PanGesture& PanGestureProcessor::GetSceneObject() const
-{
- return *mSceneObject;
-}
-
-void PanGestureProcessor::UpdateDetection()
-{
- DALI_ASSERT_DEBUG(!mPanGestureDetectors.empty());
-
- unsigned int minimumRequired = UINT_MAX;
- unsigned int maximumRequired = 0;
-
- for ( PanGestureDetectorContainer::iterator iter = mPanGestureDetectors.begin(), endIter = mPanGestureDetectors.end(); iter != endIter; ++iter )
- {
- PanGestureDetector* detector(*iter);
-
- if( detector )
- {
- unsigned int minimum = detector->GetMinimumTouchesRequired();
- if (minimum < minimumRequired)
- {
- minimumRequired = minimum;
- }
-
- unsigned int maximum = detector->GetMaximumTouchesRequired();
- if (maximum > maximumRequired)
- {
- maximumRequired = maximum;
- }
- }
- }
-
- if ( (minimumRequired != mMinTouchesRequired)||(maximumRequired != mMaxTouchesRequired) )
- {
- mMinTouchesRequired = minimumRequired;
- mMaxTouchesRequired = maximumRequired;
-
- PanGestureRequest request;
- request.minTouches = mMinTouchesRequired;
- request.maxTouches = mMaxTouchesRequired;
- mGestureRecognizer->Update(request);
- }
-}
-
-void PanGestureProcessor::EmitPanSignal( Actor* actor,
- const GestureDetectorContainer& gestureDetectors,
- const PanGestureEvent& panEvent,
- Vector2 localCurrent,
- Gesture::State state,
- RenderTaskPtr renderTask )
-{
- if ( actor && !gestureDetectors.empty() )
- {
- PanGesture pan(state);
- pan.time = panEvent.time;
-
- pan.numberOfTouches = panEvent.numberOfTouches;
- pan.screenPosition = panEvent.currentPosition;
- pan.position = localCurrent;
-
- RenderTask& renderTaskImpl( *renderTask.Get() );
-
- Vector2 localPrevious;
- actor->ScreenToLocal( renderTaskImpl, localPrevious.x, localPrevious.y, panEvent.previousPosition.x, panEvent.previousPosition.y );
-
- pan.displacement = localCurrent - localPrevious;
- Vector2 previousPos( panEvent.previousPosition );
- if ( state == Gesture::Started )
- {
- previousPos = mPossiblePanPosition;
- }
-
- pan.screenDisplacement = panEvent.currentPosition - previousPos;
-
- // Avoid dividing by 0
- if ( panEvent.timeDelta > 0 )
- {
- pan.velocity.x = pan.displacement.x / static_cast<float>( panEvent.timeDelta );
- pan.velocity.y = pan.displacement.y / static_cast<float>( panEvent.timeDelta );
-
- pan.screenVelocity.x = pan.screenDisplacement.x / static_cast<float>( panEvent.timeDelta );
- pan.screenVelocity.y = pan.screenDisplacement.y / static_cast<float>( 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.
- if ( ( state == Gesture::Finished ) && ( pan.screenVelocity == Vector2::ZERO ) &&
- ( panEvent.timeDelta < MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY ) )
- {
- pan.velocity = mLastVelocity;
- pan.screenVelocity = mLastScreenVelocity;
- }
- else
- {
- // Store the current velocity for future iterations.
- mLastVelocity = pan.velocity;
- mLastScreenVelocity = pan.screenVelocity;
- }
-
- if ( mSceneObject )
- {
- // We update the scene object directly rather than sending a message.
- // Sending a message could cause unnecessary delays, the scene object ensure thread safe behaviour.
- mSceneObject->AddGesture( pan );
- }
-
- Dali::Actor actorHandle( actor );
-
- const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
- for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
- {
- static_cast< PanGestureDetector* >( *iter )->EmitPanGestureSignal( actorHandle, pan );
- }
- }
-}
-
-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 = *mCurrentRenderTask.Get();
-
- 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( *mCurrentRenderTask.Get(), 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
+++ /dev/null
-#ifndef DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_PROCESSOR_H
-#define DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_PROCESSOR_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/pan-gesture-detector-impl.h>
-#include <dali/internal/event/events/gesture-processor.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-class Stage;
-class Scene;
-struct GestureEvent;
-struct PanGestureEvent;
-
-namespace SceneGraph
-{
-class PanGesture;
-class UpdateManager;
-}
-
-/**
- * Pan Gesture Event Processing:
- *
- * When we receive a pan gesture event, we do the following:
- * - Find the actor that requires a pan where the pan started from (i.e. the down position).
- * - Emit the gesture if the event satisfies the detector conditions.
- *
- * The above is only checked when our gesture starts. We continue sending the pan gesture to the
- * same actor and detector until the pan ends or is cancelled.
- */
-class PanGestureProcessor : public GestureProcessor, public RecognizerObserver<PanGestureEvent>
-{
-public:
-
- /**
- * Create a pan gesture processor.
- * @param[in] updateManager The Update Manager
- */
- PanGestureProcessor( SceneGraph::UpdateManager& updateManager );
-
- /**
- * Destructor
- */
- virtual ~PanGestureProcessor();
-
-public: // To be called by GestureEventProcessor
-
- /**
- * This method is called whenever a pan gesture event occurs.
- * @param[in] scene The scene the pan gesture event occurs in.
- * @param[in] panEvent The event that has occurred.
- */
- void Process( Scene& scene, const PanGestureEvent& panEvent );
-
- /**
- * Adds a gesture detector to this gesture processor.
- * If this is the first gesture detector being added, then this method registers the required
- * gesture with the adaptor.
- * @param[in] gestureDetector The gesture detector being added.
- */
- void AddGestureDetector( PanGestureDetector* gestureDetector, Scene& scene, int32_t minDistance, int32_t minPanEvents );
-
- /**
- * Removes the specified gesture detector from this gesture processor. If, after removing this
- * gesture detector, there are no more gesture detectors registered, then this method unregisters
- * the gesture from the adaptor.
- * @param[in] gestureDetector The gesture detector being removed.
- */
- void RemoveGestureDetector( PanGestureDetector* gestureDetector );
-
- /**
- * This method updates the gesture detection parameters.
- * @param[in] gestureDetector The gesture detector that has been updated.
- */
- void GestureDetectorUpdated( PanGestureDetector* gestureDetector );
-
- /**
- * Sets the pan gesture properties stored in the scene object directly,
- * @param[in] pan The pan gesture to override the properties with.
- * @return true if Core::Update required
- * @note If we are already processing a normal pan, then this call is ignored.
- */
- bool SetPanGestureProperties( const PanGesture& pan );
-
- /**
- * Called to provide pan-gesture profiling information.
- */
- void EnableProfiling();
-
- /**
- * Called to set the prediction mode for pan gestures
- *
- * @param[in] mode The prediction mode
- *
- * Valid modes:
- * 0 - No prediction
- * 1 - Prediction using average acceleration
- */
- void SetPredictionMode(int mode);
-
- /**
- * @brief Sets the prediction amount of the pan gesture
- *
- * @param[in] amount The prediction amount in milliseconds
- */
- void SetPredictionAmount(unsigned int amount);
-
- /**
- * @brief Sets the upper bound of the prediction amount for clamping
- *
- * @param[in] amount The prediction amount in milliseconds
- */
- void SetMaximumPredictionAmount(unsigned int amount);
-
- /**
- * @brief Sets the lower bound of the prediction amount for clamping
- *
- * @param[in] amount The prediction amount in milliseconds
- */
- void SetMinimumPredictionAmount(unsigned int amount);
-
- /**
- * @brief Sets the amount of prediction interpolation to adjust when the pan velocity is changed
- *
- * @param[in] amount The prediction amount in milliseconds
- */
- void SetPredictionAmountAdjustment(unsigned int amount);
-
- /**
- * Called to set the prediction mode for pan gestures
- *
- * @param[in] mode The prediction mode
- *
- * Valid modes:
- * 0 - No smoothing
- * 1 - average between last 2 values
- */
- void SetSmoothingMode(int mode);
-
- /**
- * @brief Sets the smoothing amount of the pan gesture
- *
- * @param[in] amount The smotthing amount from 0.0f (none) to 1.0f (full)
- */
- void SetSmoothingAmount(float amount);
-
- /*
- * @brief Sets whether to use actual times of the real gesture and frames or not.
- *
- * @param[in] value True = use actual times, False = use perfect values
- */
- void SetUseActualTimes( bool value );
-
- /**
- * @brief Sets the interpolation time range (ms) of past points to use (with weights) when interpolating.
- *
- * @param[in] value Time range in ms
- */
- void SetInterpolationTimeRange( int value );
-
- /**
- * @brief Sets whether to use scalar only prediction, which when enabled, ignores acceleration.
- *
- * @param[in] value True = use scalar prediction only
- */
- void SetScalarOnlyPredictionEnabled( bool value );
-
- /**
- * @brief Sets whether to use two point prediction. This combines two interpolated points to get more steady acceleration and velocity values.
- *
- * @param[in] value True = use two point prediction
- */
- void SetTwoPointPredictionEnabled( bool value );
-
- /**
- * @brief Sets the time in the past to interpolate the second point when using two point interpolation.
- *
- * @param[in] value Time in past in ms
- */
- void SetTwoPointInterpolatePastTime( int value );
-
- /**
- * @brief Sets the two point velocity bias. This is the ratio of first and second points to use for velocity.
- *
- * @param[in] value 0.0f = 100% first point. 1.0f = 100% of second point.
- */
- void SetTwoPointVelocityBias( float value );
-
- /**
- * @brief Sets the two point acceleration bias. This is the ratio of first and second points to use for acceleration.
- *
- * @param[in] value 0.0f = 100% first point. 1.0f = 100% of second point.
- */
- void SetTwoPointAccelerationBias( float value );
-
- /**
- * @brief Sets the range of time (ms) of points in the history to perform multitap smoothing with (if enabled).
- *
- * @param[in] value Time in past in ms
- */
- void SetMultitapSmoothingRange( int value );
-
-public: // for PanGestureDetector
-
- /**
- * @return the pan gesture scene object
- */
- const SceneGraph::PanGesture& GetSceneObject() const;
-
-private:
-
- // Undefined
- PanGestureProcessor( const PanGestureProcessor& );
- PanGestureProcessor& operator=( const PanGestureProcessor& rhs );
-
- /**
- * Iterates through our GestureDetectors and determines if we need to ask the adaptor to update
- * its detection policy. If it does, it sends the appropriate gesture update request to adaptor.
- */
- void UpdateDetection();
-
- /**
- * Creates a PanGesture and asks the specified detector to emit its detected signal.
- * @param[in] actor The actor that has been panned.
- * @param[in] gestureDetectors The gesture detector container that should emit the signal.
- * @param[in] panEvent The panEvent received from the adaptor.
- * @param[in] localCurrent Current position relative to the actor attached to the detector.
- * @param[in] state The state of the gesture.
- * @param[in] renderTask The renderTask to use.
- */
- void EmitPanSignal( Actor* actor,
- const GestureDetectorContainer& gestureDetectors,
- const PanGestureEvent& panEvent,
- Vector2 localCurrent,
- Gesture::State state,
- RenderTaskPtr renderTask );
-
- // GestureProcessor overrides
-
- /**
- * @copydoc GestureProcessor::OnGesturedActorStageDisconnection()
- */
- void OnGesturedActorStageDisconnection();
-
- /**
- * @copydoc GestureProcessor::CheckGestureDetector()
- */
- bool CheckGestureDetector( GestureDetector* detector, Actor* actor );
-
- /**
- * @copydoc GestureProcessor::EmitGestureSignal()
- */
- void EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates );
-
-private:
-
- PanGestureDetectorContainer mPanGestureDetectors;
- GestureDetectorContainer mCurrentPanEmitters;
- RenderTaskPtr mCurrentRenderTask;
- Vector2 mPossiblePanPosition;
-
- uint32_t mMinTouchesRequired;
- uint32_t mMaxTouchesRequired;
-
- Vector2 mLastVelocity; ///< The last recorded velocity in local actor coordinates.
- Vector2 mLastScreenVelocity; ///< The last recorded velocity in screen coordinates.
-
- const PanGestureEvent* mCurrentPanEvent; ///< Pointer to current PanEvent, used when calling ProcessAndEmit()
- SceneGraph::PanGesture* mSceneObject; ///< Not owned, but we write to it directly
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_PROCESSOR_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/pan-gesture-recognizer.h>
-
-// EXTERNAL INCLUDES
-#include <cmath>
-
-#include <dali/public-api/events/touch-point.h>
-
-#include <dali/integration-api/events/touch-event-integ.h>
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/common/scene-impl.h>
-#include <dali/internal/event/events/pan-gesture-event.h>
-#include <dali/internal/event/events/gesture-requests.h>
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN( 15.0f );
-const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_BEFORE_PAN );
-const float MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO( 2.0f / 3.0f );
-const unsigned long MAXIMUM_TIME_DIFF_ALLOWED( 500 );
-const unsigned long MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS( 100 );
-const unsigned int MINIMUM_MOTION_EVENTS_BEFORE_PAN(2);
-} // unnamed namespace
-
-PanGestureRecognizer::PanGestureRecognizer( Observer& observer, Vector2 screenSize, const PanGestureRequest& request, int32_t minimumDistance, int32_t minimumPanEvents )
-: GestureRecognizer( screenSize, Gesture::Pan ),
- mObserver( observer ),
- mState( Clear ),
- mThresholdAdjustmentsRemaining( 0 ),
- mThresholdTotalAdjustments( static_cast<unsigned int>( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO ) ),
- mPrimaryTouchDownTime( 0 ),
- mMinimumTouchesRequired( request.minTouches ),
- mMaximumTouchesRequired( request.maxTouches ),
- mMinimumDistanceSquared( static_cast<unsigned int>( MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED ) ),
- mMinimumMotionEvents( MINIMUM_MOTION_EVENTS_BEFORE_PAN ),
- mMotionEvents( 0 )
-{
- if ( minimumDistance >= 0 )
- {
- mMinimumDistanceSquared = minimumDistance * minimumDistance;
-
- // Usually, we do not want to apply the threshold straight away, but phased over the first few pans
- // Set our distance to threshold adjustments ratio here.
- float fMinimumDistance = static_cast<float>( minimumDistance );
- mThresholdTotalAdjustments = static_cast<unsigned int>( fMinimumDistance * MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO );
- }
-
- if ( minimumPanEvents >= 1 )
- {
- mMinimumMotionEvents = minimumPanEvents - 1; // Down is the first event
- }
-}
-
-PanGestureRecognizer::~PanGestureRecognizer()
-{
-}
-
-void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
-{
- PointState::Type primaryPointState(event.points[0].GetState());
-
- if (primaryPointState == PointState::INTERRUPTED)
- {
- if ( ( mState == Started ) || ( mState == Possible ) )
- {
- // If our pan had started and we are interrupted, then tell Core that pan is cancelled.
- mTouchEvents.push_back(event);
- SendPan(Gesture::Cancelled, event);
- }
- mState = Clear; // We should change our state to Clear.
- mTouchEvents.clear();
- }
- else
- {
- switch (mState)
- {
- case Clear:
- {
- if ( ( primaryPointState == PointState::DOWN ) || ( primaryPointState == PointState::STATIONARY ) )
- {
- mPrimaryTouchDownLocation = event.points[0].GetScreenPosition();
- mPrimaryTouchDownTime = event.time;
- mMotionEvents = 0;
- if (event.GetPointCount() == mMinimumTouchesRequired)
- {
- // We have satisfied the minimum touches required for a pan, tell core that a gesture may be possible and change our state accordingly.
- mState = Possible;
- SendPan(Gesture::Possible, event);
- }
-
- mTouchEvents.push_back(event);
- }
- break;
- }
-
- case Possible:
- {
- unsigned int pointCount(event.GetPointCount());
- if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) )
- {
- if (primaryPointState == PointState::MOTION)
- {
- mTouchEvents.push_back(event);
- mMotionEvents++;
-
- Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation);
-
- if ( ( mMotionEvents >= mMinimumMotionEvents ) &&
- ( delta.LengthSquared() >= static_cast<float>( mMinimumDistanceSquared ) ) )
- {
- // If the touch point(s) have moved enough distance to be considered a pan, then tell Core that the pan gesture has started and change our state accordingly.
- mState = Started;
- SendPan(Gesture::Started, event);
- }
- }
- else if (primaryPointState == PointState::UP)
- {
- Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation);
- if (delta.LengthSquared() >= static_cast<float>( mMinimumDistanceSquared ) )
- {
- SendPan(Gesture::Started, event);
- mTouchEvents.push_back(event);
- SendPan(Gesture::Finished, event);
- }
- else
- {
- // If we have lifted the primary touch point then tell core the pan is cancelled and change our state to Clear.
- SendPan(Gesture::Cancelled, event);
- }
- mState = Clear;
- mTouchEvents.clear();
- }
- }
- else
- {
- // We do not satisfy pan conditions, tell Core our Gesture has been cancelled.
- SendPan(Gesture::Cancelled, event);
-
- if (pointCount == 1 && primaryPointState == PointState::UP)
- {
- // If we have lifted the primary touch point, then change our state to Clear...
- mState = Clear;
- mTouchEvents.clear();
- }
- else
- {
- // ...otherwise change it to Failed.
- mState = Failed;
- }
- }
- break;
- }
-
- case Started:
- {
- mTouchEvents.push_back(event);
-
- unsigned int pointCount(event.GetPointCount());
- if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) )
- {
- switch (primaryPointState)
- {
- case PointState::MOTION:
- // Pan is continuing, tell Core.
- SendPan(Gesture::Continuing, event);
- break;
-
- case PointState::UP:
- // Pan is finally finished when our primary point is lifted, tell Core and change our state to Clear.
- mState = Clear;
- SendPan(Gesture::Finished, event);
- mTouchEvents.clear();
- break;
-
- case PointState::STATIONARY:
- if (pointCount == mMinimumTouchesRequired)
- {
- Integration::PointContainerConstIterator iter = event.points.begin() + 1; // We already know the state of the first point
- for(; iter != event.points.end(); ++iter)
- {
- if(iter->GetState() == PointState::UP)
- {
- // The number of touch points will be less than the minimum required. Inform core and change our state to Finished.
- SendPan(Gesture::Finished, event);
- mState = Finished;
- break;
- }
- }
- }
- break;
-
- default:
- break;
- }
- }
- else
- {
- // We have gone outside of the pan requirements, inform Core that the gesture is finished.
- SendPan(Gesture::Finished, event);
-
- if (pointCount == 1 && primaryPointState == PointState::UP)
- {
- // If this was the primary point being released, then we change our state back to Clear...
- mState = Clear;
- mTouchEvents.clear();
- }
- else
- {
- // ...otherwise we change it to Finished.
- mState = Finished;
- }
- }
- break;
- }
-
- case Finished:
- case Failed:
- {
- if (primaryPointState == PointState::UP)
- {
- // Change our state back to clear when the primary touch point is released.
- mState = Clear;
- mTouchEvents.clear();
- }
- break;
- }
- }
- }
-}
-
-void PanGestureRecognizer::Update(const GestureRequest& request)
-{
- const PanGestureRequest& pan = static_cast<const PanGestureRequest&>(request);
-
- mMinimumTouchesRequired = pan.minTouches;
- mMaximumTouchesRequired = pan.maxTouches;
-}
-
-void PanGestureRecognizer::SendPan(Gesture::State state, const Integration::TouchEvent& currentEvent)
-{
- PanGestureEvent gesture(state);
- gesture.currentPosition = currentEvent.points[0].GetScreenPosition();
- gesture.numberOfTouches = currentEvent.GetPointCount();
-
- if ( mTouchEvents.size() > 1 )
- {
- // Get the second last event in the queue, the last one is the current event
- const Integration::TouchEvent& previousEvent( *( mTouchEvents.rbegin() + 1 ) );
-
- Vector2 previousPosition( mPreviousPosition );
- uint32_t previousTime( previousEvent.time );
-
- // If we've just started then we want to remove the threshold from Core calculations.
- if ( state == Gesture::Started )
- {
- previousPosition = mPrimaryTouchDownLocation;
- previousTime = mPrimaryTouchDownTime;
-
- // If it's a slow pan, we do not want to phase in the threshold over the first few pan-events
- // A slow pan is defined as one that starts the specified number of milliseconds after the down-event
- if ( ( currentEvent.time - previousTime ) > MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS )
- {
- mThresholdAdjustmentsRemaining = mThresholdTotalAdjustments;
- mThresholdAdjustmentPerFrame = ( gesture.currentPosition - previousPosition ) / static_cast<float>( mThresholdTotalAdjustments );
- }
- else
- {
- mThresholdAdjustmentsRemaining = 0;
- mThresholdAdjustmentPerFrame = Vector2::ZERO;
- }
- }
-
- gesture.previousPosition = previousPosition;
- gesture.timeDelta = currentEvent.time - previousTime;
-
- // Apply the threshold with a phased approach
- if ( mThresholdAdjustmentsRemaining > 0 )
- {
- --mThresholdAdjustmentsRemaining;
- gesture.currentPosition -= mThresholdAdjustmentPerFrame * static_cast<float>( mThresholdAdjustmentsRemaining );
- }
-
- mPreviousPosition = gesture.currentPosition;
- }
- else
- {
- gesture.previousPosition = gesture.currentPosition;
- gesture.timeDelta = 0;
- }
-
- gesture.time = currentEvent.time;
-
- if( mScene )
- {
- // Create another handle so the recognizer cannot be destroyed during process function
- GestureRecognizerPtr recognizerHandle = this;
-
- mObserver.Process(*mScene, gesture);
- }
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_EVENT_PAN_GESTURE_RECOGNIZER_H
-#define DALI_INTERNAL_EVENT_PAN_GESTURE_RECOGNIZER_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <cstdint> // uint32_t
-#include <dali/public-api/common/vector-wrapper.h>
-#include <dali/public-api/math/vector2.h>
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/gesture-recognizer.h>
-#include <dali/internal/event/events/pan-gesture-event.h>
-
-namespace Dali
-{
-
-namespace Integration
-{
-class Core;
-struct TouchEvent;
-
-}
-
-namespace Internal
-{
-
-struct PanGestureRequest;
-/**
- * When given a set of touch events, this detector attempts to determine if a pan gesture has taken place.
- */
-class PanGestureRecognizer : public GestureRecognizer
-{
-public:
-
- using Observer = RecognizerObserver<PanGestureEvent>;
-
- /**
- * Constructor
- * @param[in] screenSize The size of the screen.
- * @param[in] request The details of the request.
- */
- PanGestureRecognizer( Observer& observer, Vector2 screenSize, const PanGestureRequest& request, int32_t minimumDistance, int32_t minimumPanEvents);
-
- /**
- * Virtual destructor.
- */
- virtual ~PanGestureRecognizer();
-
-public:
-
- /**
- * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
- */
- virtual void SendEvent(const Integration::TouchEvent& event);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
- */
- virtual void Update(const GestureRequest& request);
-
-private:
-
- /**
- * Emits the pan gesture event (performs some smoothing operation).
- * @param[in] state The state of the pan.
- * @param[in] currentEvent The latest touch event.
- */
- void SendPan(Gesture::State state, const Integration::TouchEvent& currentEvent);
-
-private:
-
- // Reference to the gesture processor for this recognizer
- Observer& mObserver;
-
- /**
- * Internal state machine.
- */
- enum State
- {
- Clear, ///< No gesture detected.
- Possible, ///< The current touch event data suggests that a gesture is possible.
- Started, ///< A gesture has been detected.
- Finished, ///< A previously started pan gesture has finished.
- Failed, ///< Current touch event data suggests a pan gesture is not possible.
- };
-
- State mState; ///< The current state of the detector.
- std::vector<Integration::TouchEvent> mTouchEvents; ///< A container of all touch events after an initial down event.
-
- Vector2 mPrimaryTouchDownLocation; ///< The initial touch down point.
- Vector2 mThresholdAdjustmentPerFrame; ///< The adjustment per frame at the start of a slow pan.
- Vector2 mPreviousPosition; ///< The previous position.
-
- unsigned int mThresholdAdjustmentsRemaining; ///< No. of threshold adjustments still to apply (for a slow-pan).
- unsigned int mThresholdTotalAdjustments; ///< The total number of adjustments required.
-
- uint32_t mPrimaryTouchDownTime; ///< The initial touch down time.
- unsigned int mMinimumTouchesRequired; ///< The minimum touches required before a pan should be emitted.
- unsigned int mMaximumTouchesRequired; ///< The maximum touches after which a pan should not be emitted.
-
- unsigned int mMinimumDistanceSquared; ///< The minimum distance squared before pan should start.
- unsigned int mMinimumMotionEvents; ///< The minimum motion events before pan should start.
- unsigned int mMotionEvents; ///< The motion events received so far (before pan is emitted).
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_EVENT_PAN_GESTURE_RECOGNIZER_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/pan-gesture.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/math/radian.h>
+#include <dali/public-api/math/degree.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/event/actors/actor-impl.h>
+#include <dali/internal/event/common/property-helper.h>
+#include <dali/internal/event/common/thread-local-storage.h>
+#include <dali/internal/event/events/gesture-event-processor.h>
+#include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// Properties
+
+// Name Type writable animatable constraint-input enum for index-checking
+DALI_PROPERTY_TABLE_BEGIN
+DALI_PROPERTY( "screenPosition", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::SCREEN_POSITION )
+DALI_PROPERTY( "screenDisplacement", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT )
+DALI_PROPERTY( "screenVelocity", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::SCREEN_VELOCITY )
+DALI_PROPERTY( "localPosition", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::LOCAL_POSITION )
+DALI_PROPERTY( "localDisplacement", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT )
+DALI_PROPERTY( "localVelocity", VECTOR2, false, false, true, Dali::PanGestureDetector::Property::LOCAL_VELOCITY )
+DALI_PROPERTY( "panning", BOOLEAN, false, false, true, Dali::PanGestureDetector::Property::PANNING )
+DALI_PROPERTY_TABLE_END( DEFAULT_GESTURE_DETECTOR_PROPERTY_START_INDEX, PanGestureDetectorDefaultProperties )
+
+// Signals
+
+const char* const SIGNAL_PAN_DETECTED = "panDetected";
+
+BaseHandle Create()
+{
+ return Dali::PanGestureDetector::New();
+}
+
+TypeRegistration mType( typeid(Dali::PanGestureDetector), typeid(Dali::GestureDetector), Create, PanGestureDetectorDefaultProperties );
+
+SignalConnectorType signalConnector1( mType, SIGNAL_PAN_DETECTED, &PanGestureDetector::DoConnectSignal );
+
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_PAN_GESTURE_DETECTOR");
+#endif
+
+/**
+ * Returns the angle going in the opposite direction to that specified by angle.
+ */
+float GetOppositeAngle( float angle )
+{
+ // Calculate the opposite angle so that we cover both directions.
+ if ( angle <= 0.0f )
+ {
+ angle += Math::PI;
+ }
+ else
+ {
+ angle -= Math::PI;
+ }
+
+ return angle;
+}
+
+} // unnamed namespace
+
+PanGestureDetectorPtr PanGestureDetector::New()
+{
+ const SceneGraph::PanGesture& sceneObject = ThreadLocalStorage::Get().GetGestureEventProcessor().GetPanGestureProcessor().GetSceneObject();
+ return new PanGestureDetector( sceneObject );
+}
+
+void PanGestureDetector::SetMinimumTouchesRequired(unsigned int minimum)
+{
+ DALI_ASSERT_ALWAYS( minimum > 0 && "Can only set a positive number of required touches" );
+
+ if (mMinimumTouches != minimum)
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::Concise, "Minimum Touches Set: %d\n", minimum );
+
+ mMinimumTouches = minimum;
+
+ if (!mAttachedActors.empty())
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::General, "Updating Gesture Detector\n");
+
+ mGestureEventProcessor.GestureDetectorUpdated(this);
+ }
+ }
+}
+
+void PanGestureDetector::SetMaximumTouchesRequired(unsigned int maximum)
+{
+ DALI_ASSERT_ALWAYS( maximum > 0 && "Can only set a positive number of maximum touches" );
+
+ if (mMaximumTouches != maximum)
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::Concise, "Maximum Touches Set: %d\n", maximum );
+
+ mMaximumTouches = maximum;
+
+ if (!mAttachedActors.empty())
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::General, "Updating Gesture Detector\n");
+
+ mGestureEventProcessor.GestureDetectorUpdated(this);
+ }
+ }
+}
+
+uint32_t PanGestureDetector::GetMinimumTouchesRequired() const
+{
+ return mMinimumTouches;
+}
+
+uint32_t PanGestureDetector::GetMaximumTouchesRequired() const
+{
+ return mMaximumTouches;
+}
+
+void PanGestureDetector::AddAngle( Radian angle, Radian threshold )
+{
+ threshold = fabsf( threshold ); // Ensure the threshold is positive.
+
+ // If the threshold is greater than PI, then just use PI
+ // This means that any panned angle will invoke the pan gesture. We should still add this angle as
+ // an angle may have been added previously with a small threshold.
+ if ( threshold > Math::PI )
+ {
+ threshold = Math::PI;
+ }
+
+ angle = WrapInDomain( angle, -Math::PI, Math::PI );
+
+ DALI_LOG_INFO( gLogFilter, Debug::Concise, "Angle Added: %.2f, Threshold: %.2f\n", Degree(angle), Degree(threshold) );
+
+ AngleThresholdPair pair( angle, threshold );
+ mAngleContainer.push_back( pair );
+}
+
+void PanGestureDetector::AddDirection( Radian direction, Radian threshold )
+{
+ AddAngle( direction, threshold );
+
+ // Calculate the opposite angle so that we cover the entire direction.
+ direction = GetOppositeAngle( direction );
+
+ AddAngle( direction, threshold );
+}
+
+uint32_t PanGestureDetector::GetAngleCount() const
+{
+ return static_cast<uint32_t>( mAngleContainer.size() );
+}
+
+PanGestureDetector::AngleThresholdPair PanGestureDetector::GetAngle(uint32_t index) const
+{
+ PanGestureDetector::AngleThresholdPair ret( Radian(0),Radian(0) );
+
+ if( index < mAngleContainer.size() )
+ {
+ ret = mAngleContainer[index];
+ }
+
+ return ret;
+}
+
+
+void PanGestureDetector::ClearAngles()
+{
+ mAngleContainer.clear();
+}
+
+void PanGestureDetector::RemoveAngle( Radian angle )
+{
+ angle = WrapInDomain( angle, -Math::PI, Math::PI );
+
+ for (AngleContainer::iterator iter = mAngleContainer.begin(), endIter = mAngleContainer.end(); iter != endIter; ++iter )
+ {
+ if ( iter->first == angle )
+ {
+ mAngleContainer.erase( iter );
+ break;
+ }
+ }
+}
+
+void PanGestureDetector::RemoveDirection( Radian direction )
+{
+ RemoveAngle( direction );
+
+ // Calculate the opposite angle so that we cover the entire direction.
+ direction = GetOppositeAngle( direction );
+
+ RemoveAngle( direction );
+}
+
+bool PanGestureDetector::RequiresDirectionalPan() const
+{
+ // If no directional angles have been added to the container then we do not require directional panning
+ return !mAngleContainer.empty();
+}
+
+bool PanGestureDetector::CheckAngleAllowed( Radian angle ) const
+{
+ bool allowed( false );
+ if ( mAngleContainer.empty() )
+ {
+ allowed = true;
+ }
+ else
+ {
+ for ( AngleContainer::const_iterator iter = mAngleContainer.begin(), endIter = mAngleContainer.end(); iter != endIter; ++iter )
+ {
+ float angleAllowed( iter->first );
+ float threshold ( iter->second );
+
+ DALI_LOG_INFO( gLogFilter, Debug::General,
+ "AngleToCheck: %.2f, CompareWith: %.2f, Threshold: %.2f\n",
+ Degree(angle), Degree(angleAllowed), Degree(threshold) );
+
+ float relativeAngle( fabsf( WrapInDomain( angle - angleAllowed, -Math::PI, Math::PI ) ) );
+ if ( relativeAngle <= threshold )
+ {
+ allowed = true;
+ break;
+ }
+ }
+ }
+
+ return allowed;
+}
+
+void PanGestureDetector::EmitPanGestureSignal(Dali::Actor actor, const PanGesture& pan)
+{
+ if ( !mDetectedSignal.Empty() )
+ {
+ // Guard against destruction during signal emission
+ Dali::PanGestureDetector handle( this );
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Emitting Signal (%p)\n", this );
+
+ mDetectedSignal.Emit( actor, pan );
+ }
+}
+
+bool PanGestureDetector::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+ bool connected( true );
+ PanGestureDetector* gesture = static_cast< PanGestureDetector* >(object); // TypeRegistry guarantees that this is the correct type.
+
+ if ( 0 == strcmp( signalName.c_str(), SIGNAL_PAN_DETECTED ) )
+ {
+ gesture->DetectedSignal().Connect( tracker, functor );
+ }
+ else
+ {
+ // signalName does not match any signal
+ connected = false;
+ }
+
+ return connected;
+}
+
+void PanGestureDetector::SetPanGestureProperties( const PanGesture& pan )
+{
+ ThreadLocalStorage::Get().GetGestureEventProcessor().SetGestureProperties( pan );
+}
+
+PanGestureDetector::PanGestureDetector( const SceneGraph::PanGesture& sceneObject )
+: GestureDetector(Gesture::Pan, &sceneObject ),
+ mMinimumTouches(1),
+ mMaximumTouches(1)
+{
+}
+
+PanGestureDetector::~PanGestureDetector()
+{
+}
+
+const SceneGraph::PanGesture& PanGestureDetector::GetPanGestureSceneObject() const
+{
+ return static_cast<const SceneGraph::PanGesture&>( GetSceneObject() );
+}
+
+void PanGestureDetector::OnActorAttach(Actor& actor)
+{
+ // Do nothing
+}
+
+void PanGestureDetector::OnActorDetach(Actor& actor)
+{
+ // Do nothing
+}
+
+void PanGestureDetector::OnActorDestroyed(Object& object)
+{
+ // Do nothing
+}
+
+void PanGestureDetector::SetDefaultProperty( Property::Index index, const Property::Value& property )
+{
+ // None of our properties should be settable from Public API
+}
+
+Property::Value PanGestureDetector::GetDefaultProperty( Property::Index index ) const
+{
+ return GetDefaultPropertyCurrentValue( index ); // Scene-graph only properties
+}
+
+Property::Value PanGestureDetector::GetDefaultPropertyCurrentValue( Property::Index index ) const
+{
+ Property::Value value;
+
+ switch ( index )
+ {
+ case Dali::PanGestureDetector::Property::SCREEN_POSITION:
+ {
+ value = GetPanGestureSceneObject().GetScreenPositionProperty().Get();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT:
+ {
+ value = GetPanGestureSceneObject().GetScreenDisplacementProperty().Get();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::SCREEN_VELOCITY:
+ {
+ value = GetPanGestureSceneObject().GetScreenVelocityProperty().Get();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::LOCAL_POSITION:
+ {
+ value = GetPanGestureSceneObject().GetLocalPositionProperty().Get();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT:
+ {
+ value = GetPanGestureSceneObject().GetLocalDisplacementProperty().Get();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::LOCAL_VELOCITY:
+ {
+ value = GetPanGestureSceneObject().GetLocalVelocityProperty().Get();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::PANNING:
+ {
+ value = GetPanGestureSceneObject().GetPanningProperty().Get();
+ break;
+ }
+
+ default:
+ {
+ DALI_ASSERT_ALWAYS(false && "PanGestureDetector Property index invalid" ); // should not come here
+ break;
+ }
+ }
+
+ return value;
+}
+
+const PropertyInputImpl* PanGestureDetector::GetSceneObjectInputProperty( Property::Index index ) const
+{
+ const PropertyInputImpl* property = nullptr;
+
+ switch ( index )
+ {
+ case Dali::PanGestureDetector::Property::SCREEN_POSITION:
+ {
+ property = &GetPanGestureSceneObject().GetScreenPositionProperty();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::SCREEN_DISPLACEMENT:
+ {
+ property = &GetPanGestureSceneObject().GetScreenDisplacementProperty();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::SCREEN_VELOCITY:
+ {
+ property = &GetPanGestureSceneObject().GetScreenVelocityProperty();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::LOCAL_POSITION:
+ {
+ property = &GetPanGestureSceneObject().GetLocalPositionProperty();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::LOCAL_DISPLACEMENT:
+ {
+ property = &GetPanGestureSceneObject().GetLocalDisplacementProperty();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::LOCAL_VELOCITY:
+ {
+ property = &GetPanGestureSceneObject().GetLocalVelocityProperty();
+ break;
+ }
+
+ case Dali::PanGestureDetector::Property::PANNING:
+ {
+ property = &GetPanGestureSceneObject().GetPanningProperty();
+ break;
+ }
+
+ default:
+ break;
+ }
+ if( !property )
+ {
+ // not our property, ask base
+ property = Object::GetSceneObjectInputProperty( index );
+ }
+
+ return property;
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_PAN_GESTURE_DETECTOR_H
+#define DALI_INTERNAL_PAN_GESTURE_DETECTOR_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/gesture.h>
+#include <dali/public-api/events/pan-gesture-detector.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/internal/event/events/gesture-detector-impl.h>
+
+namespace Dali
+{
+
+struct TouchEvent;
+struct Radian;
+
+namespace Internal
+{
+
+class PanGestureDetector;
+typedef IntrusivePtr<PanGestureDetector> PanGestureDetectorPtr;
+typedef DerivedGestureDetectorContainer<PanGestureDetector>::type PanGestureDetectorContainer;
+
+namespace SceneGraph
+{
+class PanGesture;
+}
+
+/**
+ * @copydoc Dali::PanGestureDetector
+ */
+class PanGestureDetector : public GestureDetector
+{
+public: // Typedefs
+
+ typedef Dali::PanGestureDetector::AngleThresholdPair AngleThresholdPair;
+ typedef std::vector<AngleThresholdPair> AngleContainer;
+
+public: // Creation
+
+ /**
+ * Create a new gesture detector.
+ * @return A smart-pointer to the newly allocated detector.
+ */
+ static PanGestureDetectorPtr New();
+
+public:
+
+ /**
+ * @copydoc Dali::PanGestureDetector::SetMinimumTouchesRequired(unsigned int)
+ */
+ void SetMinimumTouchesRequired(unsigned int minimum);
+
+ /**
+ * @copydoc Dali::PanGestureDetector::SetMaximumTouchesRequired(unsigned int)
+ */
+ void SetMaximumTouchesRequired(unsigned int maximum);
+
+ /**
+ * @copydoc Dali::PanGestureDetector::GetMinimumTouchesRequired() const
+ */
+ uint32_t GetMinimumTouchesRequired() const;
+
+ /**
+ * @copydoc Dali::PanGestureDetector::GetMaximumTouchesRequired() const
+ */
+ uint32_t GetMaximumTouchesRequired() const;
+
+ /**
+ * @copydoc Dali::PanGestureDetector::AddAngle()
+ */
+ void AddAngle( Radian angle, Radian threshold );
+
+ /**
+ * @copydoc Dali::PanGestureDetector::AddDirection()
+ */
+ void AddDirection( Radian direction, Radian threshold );
+
+ /**
+ * @copydoc Dali::PanGestureDetector::GetAngleCount()
+ */
+ uint32_t GetAngleCount() const;
+
+ /**
+ * @copydoc Dali::PanGestureDetector::GetAngle()
+ */
+ AngleThresholdPair GetAngle(uint32_t index) const;
+
+ /**
+ * @copydoc Dali::PanGestureDetector::ClearAngles()
+ */
+ void ClearAngles();
+
+ /**
+ * @copydoc Dali::PanGestureDetector::RemoveAngle()
+ */
+ void RemoveAngle( Radian angle );
+
+ /**
+ * @copydoc Dali::PanGestureDetector::RemoveDirection()
+ */
+ void RemoveDirection( Radian direction );
+
+ /**
+ * Checks whether the pan gesture detector requires a directional pan for emission.
+ * @return true, if directional panning required, false otherwise.
+ */
+ bool RequiresDirectionalPan() const;
+
+ /**
+ * Checks whether the given pan angle is allowed for this gesture detector.
+ * @param[in] angle The angle to check.
+ */
+ bool CheckAngleAllowed( Radian angle ) const;
+
+public:
+
+ /**
+ * Called by the PanGestureProcessor when a pan gesture event occurs within the bounds of our
+ * attached actor.
+ * @param[in] actor The panned actor.
+ * @param[in] pan The pan gesture.
+ */
+ void EmitPanGestureSignal(Dali::Actor actor, const PanGesture& pan);
+
+public: // Signals
+
+ /**
+ * @copydoc Dali::PanGestureDetector::DetectedSignal()
+ */
+ Dali::PanGestureDetector::DetectedSignalType& DetectedSignal()
+ {
+ return mDetectedSignal;
+ }
+
+ /**
+ * Connects a callback function with the object's signals.
+ * @param[in] object The object providing the signal.
+ * @param[in] tracker Used to disconnect the signal.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
+ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+public: // Override Pan Gesture
+
+ /**
+ * @copydoc Dali::PanGestureDetector::SetPanGestureProperties()
+ */
+ static void SetPanGestureProperties( const PanGesture& pan );
+
+protected:
+
+ /**
+ * Construct a new PanGestureDetector.
+ * @param sceneObject the scene object
+ */
+ PanGestureDetector( const SceneGraph::PanGesture& sceneObject );
+
+ /**
+ * A reference counted object may only be deleted by calling Unreference()
+ */
+ virtual ~PanGestureDetector();
+
+private:
+
+ // Undefined
+ PanGestureDetector() = delete;
+ PanGestureDetector(const PanGestureDetector&) = delete;
+ PanGestureDetector& operator=(const PanGestureDetector& rhs) = delete;
+
+ /**
+ * @return the pan gesture scene object
+ */
+ const SceneGraph::PanGesture& GetPanGestureSceneObject() const;
+
+ // From GestureDetector
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&)
+ */
+ virtual void OnActorAttach(Actor& actor);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDetach(Actor&)
+ */
+ virtual void OnActorDetach(Actor& actor);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDestroyed(Object&)
+ */
+ virtual void OnActorDestroyed(Object& object);
+
+
+ // Default property extensions from Object
+
+ /**
+ * @copydoc Dali::Internal::Object::SetDefaultProperty()
+ */
+ virtual void SetDefaultProperty(Property::Index index, const Property::Value& propertyValue);
+
+ /**
+ * @copydoc Dali::Internal::Object::GetDefaultProperty()
+ */
+ virtual Property::Value GetDefaultProperty( Property::Index index ) const;
+
+ /**
+ * @copydoc Dali::Internal::Object::GetDefaultPropertyCurrentValue()
+ */
+ virtual Property::Value GetDefaultPropertyCurrentValue( Property::Index index ) const;
+
+ /**
+ * @copydoc Dali::Internal::Object::GetSceneObjectInputProperty()
+ */
+ virtual const PropertyInputImpl* GetSceneObjectInputProperty( Property::Index index ) const;
+
+private:
+
+ Dali::PanGestureDetector::DetectedSignalType mDetectedSignal;
+
+ unsigned int mMinimumTouches; ///< The minimum number of fingers required to be touching for pan.
+ unsigned int mMaximumTouches; ///< The maximum number of fingers required to be touching for pan.
+
+ AngleContainer mAngleContainer; ///< A container of all angles allowed for pan to occur.
+
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::PanGestureDetector& GetImplementation(Dali::PanGestureDetector& detector)
+{
+ DALI_ASSERT_ALWAYS( detector && "PanGestureDetector handle is empty" );
+
+ BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<Internal::PanGestureDetector&>(handle);
+}
+
+inline const Internal::PanGestureDetector& GetImplementation(const Dali::PanGestureDetector& detector)
+{
+ DALI_ASSERT_ALWAYS( detector && "PanGestureDetector handle is empty" );
+
+ const BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<const Internal::PanGestureDetector&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_PAN_GESTURE_DETECTOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/pan-gesture/pan-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+
+PanGestureEvent::PanGestureEvent(Gesture::State state)
+: GestureEvent(Gesture::Pan, state),
+ timeDelta(0),
+ numberOfTouches(1)
+{
+}
+
+PanGestureEvent::~PanGestureEvent()
+{
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_H
+#define DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/gesture-event.h>
+#include <dali/public-api/math/vector2.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+/**
+ * If the adaptor detects a pan gesture, then it should create an instance of this structure and
+ * send it to the Core.
+ *
+ * A Pan Gesture event should be in one of five states:
+ * - Possible: When the user first puts their finger down - Core needs to hit test the down point.
+ * - Started: If a pan is detected.
+ * - Continuing: If after a pan is detected, it continues.
+ * - Finished: If after a pan, the user lifts their finger(s).
+ * - Cancelled: If, after a down event, no pan is detected or a system interruption.
+ *
+ * A Started state will be ignored if a Possible state does not precede it.
+ * Likewise, a Continuing or Finished state will be ignored if a Started state does not precede it.
+ */
+struct PanGestureEvent: public GestureEvent
+{
+ // Construction & Destruction
+
+ /**
+ * Default Constructor
+ * @param[in] state The state of the gesture
+ */
+ PanGestureEvent(Gesture::State state);
+
+ /**
+ * Virtual destructor
+ */
+ virtual ~PanGestureEvent();
+
+ // Data
+
+ /**
+ * The previous touch position of the primary touch point in screen coordinates.
+ */
+ Vector2 previousPosition;
+
+ /**
+ * This current touch position of the primary touch point in screen coordinates.
+ */
+ Vector2 currentPosition;
+
+ /**
+ * The time difference between the previous and latest touch motion events (in ms).
+ */
+ unsigned long timeDelta;
+
+ /**
+ * The total number of fingers touching the screen in a pan gesture.
+ */
+ unsigned int numberOfTouches;
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/pan-gesture/pan-gesture-processor.h>
+
+#if defined(DEBUG_ENABLED)
+#include <sstream>
+#endif
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/events/pan-gesture.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/internal/event/events/pan-gesture/pan-gesture-event.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/event/common/scene-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+#include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
+#include <dali/internal/event/events/multi-point-event-util.h>
+#include <dali/internal/event/events/pan-gesture/pan-gesture-recognizer.h>
+#include <dali/internal/event/events/gesture-requests.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace // unnamed namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_PAN_PROCESSOR" );
+
+const char * GESTURE_STATES[ 6 ] =
+{
+ "Clear",
+ "Started",
+ "Continuing",
+ "Finished",
+ "Cancelled",
+ "Possible"
+};
+
+#endif // defined(DEBUG_ENABLED)
+
+const unsigned long MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY( 50u );
+
+/**
+ * Functor which checks whether the specified actor is attached to the gesture detector.
+ * If the actor is attached, it also checks whether the number of touches of the current pan event
+ * are within the range of that expected by the detector.
+ * It returns true if it is no longer attached or the touches are out of range.
+ * This can be used in remove_if functions.
+ */
+struct IsNotAttachedAndOutsideTouchesRangeFunctor
+{
+ /**
+ * Constructor
+ * @param[in] actor The actor to check whether it is attached.
+ * @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, GestureDetectorContainer& outsideRangeEmitters)
+ : actorToCheck(actor),
+ numberOfTouches(touches),
+ outsideTouchesRangeEmitters(outsideRangeEmitters)
+ {
+ }
+
+ /**
+ * Returns true if not attached, false if it is still attached.
+ * Additionally, checks if the number of touches has changed and stops sending the pan to a particular
+ * detector if it exceeds the range of that detector.
+ * @param[in] detector The detector to check.
+ * @return true, if not attached, false otherwise.
+ */
+ 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 < panDetector->GetMinimumTouchesRequired()) ||
+ (numberOfTouches > panDetector->GetMaximumTouchesRequired()) )
+ {
+ remove = true;
+ outsideTouchesRangeEmitters.push_back(detector);
+ }
+ }
+
+ return remove;
+ }
+
+ Actor* actorToCheck; ///< The actor to check whether it is attached or not.
+ unsigned int numberOfTouches; ///< The number of touches in the pan event.
+ GestureDetectorContainer& outsideTouchesRangeEmitters; ///< Emitters that are outside of the range of current pan.
+};
+
+} // unnamed namespace
+
+PanGestureProcessor::PanGestureProcessor( SceneGraph::UpdateManager& updateManager )
+: GestureProcessor( Gesture::Pan ),
+ mPanGestureDetectors(),
+ mCurrentPanEmitters(),
+ mCurrentRenderTask(),
+ mPossiblePanPosition(),
+ mMinTouchesRequired( 1 ),
+ mMaxTouchesRequired( 1 ),
+ mCurrentPanEvent( nullptr ),
+ mSceneObject( SceneGraph::PanGesture::New() ) // Create scene object to store pan information.
+{
+ // Pass ownership to scene-graph; scene object lives for the lifecycle of UpdateManager
+ updateManager.SetPanGestureProcessor( mSceneObject );
+}
+
+PanGestureProcessor::~PanGestureProcessor()
+{
+ mSceneObject = nullptr; // mSceneObject is owned and destroyed by update manager (there is only one of these for now)
+}
+
+void PanGestureProcessor::Process( Scene& scene, const PanGestureEvent& panEvent )
+{
+#if defined(DEBUG_ENABLED)
+ DALI_LOG_TRACE_METHOD( gLogFilter );
+
+ DALI_LOG_INFO( gLogFilter, Debug::General, " Pan Event\n");
+ DALI_LOG_INFO( gLogFilter, Debug::General, " State: %s Touches: %d Time: %d TimeDelta: %d\n",
+ GESTURE_STATES[panEvent.state], panEvent.numberOfTouches, panEvent.time, panEvent.timeDelta);
+ DALI_LOG_INFO( gLogFilter, Debug::General, " Positions: Current: (%.0f, %.0f), Previous: (%.0f, %.0f)\n",
+ panEvent.currentPosition.x, panEvent.currentPosition.y, panEvent.previousPosition.x, panEvent.previousPosition.y);
+#endif
+
+ switch( panEvent.state )
+ {
+ case Gesture::Possible:
+ {
+ mCurrentPanEmitters.clear();
+ ResetActor();
+
+ HitTestAlgorithm::Results hitTestResults;
+ if( HitTest( scene, panEvent.currentPosition, hitTestResults ) )
+ {
+ SetActor( &GetImplementation( hitTestResults.actor ) );
+ mPossiblePanPosition = panEvent.currentPosition;
+ }
+
+ break;
+ }
+
+ case Gesture::Started:
+ {
+ // Requires a core update
+ mNeedsUpdate = true;
+
+ if ( GetCurrentGesturedActor() )
+ {
+ // The pan gesture should only be sent to the gesture detector which first received it so that
+ // it can be told when the gesture ends as well.
+
+ HitTestAlgorithm::Results hitTestResults;
+ HitTest( scene, 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;
+
+ // Set mCurrentPanEvent to use inside overridden methods called in ProcessAndEmit()
+ mCurrentPanEvent = &panEvent;
+ ProcessAndEmit( hitTestResults );
+ mCurrentPanEvent = nullptr;
+ }
+ else
+ {
+ ResetActor();
+ mCurrentPanEmitters.clear();
+ }
+ }
+ break;
+ }
+
+ case Gesture::Continuing:
+ {
+ // Requires a core update
+ mNeedsUpdate = true;
+ }
+ // No break, Fallthrough
+ case Gesture::Finished:
+ case Gesture::Cancelled:
+ {
+ // Only send subsequent pan gesture signals if we processed the pan gesture when it started.
+ // Check if actor is still touchable.
+
+ Actor* currentGesturedActor = GetCurrentGesturedActor();
+ if ( currentGesturedActor )
+ {
+ if ( currentGesturedActor->IsHittable() && !mCurrentPanEmitters.empty() && mCurrentRenderTask )
+ {
+ 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
+ GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPanEmitters.begin(), mCurrentPanEmitters.end(),
+ IsNotAttachedAndOutsideTouchesRangeFunctor(currentGesturedActor, panEvent.numberOfTouches, outsideTouchesRangeEmitters) );
+ mCurrentPanEmitters.erase( endIter, mCurrentPanEmitters.end() );
+
+ Vector2 actorCoords;
+
+ if ( !outsideTouchesRangeEmitters.empty() || !mCurrentPanEmitters.empty() )
+ {
+ currentGesturedActor->ScreenToLocal( *mCurrentRenderTask.Get(), 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( currentGesturedActor, outsideTouchesRangeEmitters, panEvent, actorCoords, Gesture::Finished, mCurrentRenderTask);
+ EmitPanSignal( currentGesturedActor, mCurrentPanEmitters, panEvent, actorCoords, panEvent.state, mCurrentRenderTask);
+ }
+
+ if ( mCurrentPanEmitters.empty() )
+ {
+ // If we have no emitters attached then clear pan actor as well.
+ ResetActor();
+ }
+
+ // Clear current gesture detectors if pan gesture has ended or been cancelled.
+ if ( ( panEvent.state == Gesture::Finished ) || ( panEvent.state == Gesture::Cancelled ) )
+ {
+ mCurrentPanEmitters.clear();
+ ResetActor();
+ }
+ }
+ else
+ {
+ mCurrentPanEmitters.clear();
+ ResetActor();
+ }
+ }
+ break;
+ }
+
+ case Gesture::Clear:
+ {
+ DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
+ break;
+ }
+ }
+}
+
+void PanGestureProcessor::AddGestureDetector( PanGestureDetector* gestureDetector, Scene& scene, int32_t minDistance, int32_t minPanEvents )
+{
+ bool firstRegistration(mPanGestureDetectors.empty());
+
+ mPanGestureDetectors.push_back(gestureDetector);
+
+ if (firstRegistration)
+ {
+ mMinTouchesRequired = gestureDetector->GetMinimumTouchesRequired();
+ mMaxTouchesRequired = gestureDetector->GetMaximumTouchesRequired();
+
+ PanGestureRequest request;
+ request.minTouches = mMinTouchesRequired;
+ request.maxTouches = mMaxTouchesRequired;
+
+ Size size = scene.GetSize();
+ mGestureRecognizer = new PanGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const PanGestureRequest&>(request), minDistance, minPanEvents);
+ }
+ else
+ {
+ UpdateDetection();
+ }
+}
+
+void PanGestureProcessor::RemoveGestureDetector( PanGestureDetector* gestureDetector )
+{
+ if (!mCurrentPanEmitters.empty())
+ {
+ // Check if the removed detector was one that is currently being panned and remove it from emitters.
+ 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
+ if ( mCurrentPanEmitters.empty() )
+ {
+ ResetActor();
+ }
+ }
+
+ // Find the detector...
+ PanGestureDetectorContainer::iterator endIter = std::remove( mPanGestureDetectors.begin(), mPanGestureDetectors.end(), gestureDetector );
+ DALI_ASSERT_DEBUG( endIter != mPanGestureDetectors.end() );
+
+ // ...and remove it
+ mPanGestureDetectors.erase(endIter, mPanGestureDetectors.end());
+
+ if (mPanGestureDetectors.empty())
+ {
+ mGestureRecognizer.Detach();
+ }
+ else
+ {
+ UpdateDetection();
+ }
+}
+
+void PanGestureProcessor::GestureDetectorUpdated( PanGestureDetector* gestureDetector )
+{
+ DALI_ASSERT_DEBUG(find(mPanGestureDetectors.begin(), mPanGestureDetectors.end(), gestureDetector) != mPanGestureDetectors.end());
+
+ UpdateDetection();
+}
+
+bool PanGestureProcessor::SetPanGestureProperties( const PanGesture& pan )
+{
+ // If we are currently processing a pan gesture then just ignore
+ if ( mCurrentPanEmitters.empty() && mSceneObject )
+ {
+ // We update the scene object directly rather than sending a message.
+ // Sending a message could cause unnecessary delays, the scene object ensure thread safe behaviour.
+ mSceneObject->AddGesture( pan );
+
+ if( Gesture::Started == pan.state || Gesture::Continuing == pan.state )
+ {
+ mNeedsUpdate = true;
+ }
+ }
+
+ return mNeedsUpdate;
+}
+
+void PanGestureProcessor::EnableProfiling()
+{
+ mSceneObject->EnableProfiling();
+}
+
+void PanGestureProcessor::SetPredictionMode(int mode)
+{
+ if( (mode < 0)
+ || (mode >= SceneGraph::PanGesture::NUM_PREDICTION_MODES) )
+ {
+ mode = SceneGraph::PanGesture::DEFAULT_PREDICTION_MODE;
+ }
+ SceneGraph::PanGesture::PredictionMode modeEnum = static_cast<SceneGraph::PanGesture::PredictionMode>(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<SceneGraph::PanGesture::SmoothingMode>(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 );
+}
+
+const SceneGraph::PanGesture& PanGestureProcessor::GetSceneObject() const
+{
+ return *mSceneObject;
+}
+
+void PanGestureProcessor::UpdateDetection()
+{
+ DALI_ASSERT_DEBUG(!mPanGestureDetectors.empty());
+
+ unsigned int minimumRequired = UINT_MAX;
+ unsigned int maximumRequired = 0;
+
+ for ( PanGestureDetectorContainer::iterator iter = mPanGestureDetectors.begin(), endIter = mPanGestureDetectors.end(); iter != endIter; ++iter )
+ {
+ PanGestureDetector* detector(*iter);
+
+ if( detector )
+ {
+ unsigned int minimum = detector->GetMinimumTouchesRequired();
+ if (minimum < minimumRequired)
+ {
+ minimumRequired = minimum;
+ }
+
+ unsigned int maximum = detector->GetMaximumTouchesRequired();
+ if (maximum > maximumRequired)
+ {
+ maximumRequired = maximum;
+ }
+ }
+ }
+
+ if ( (minimumRequired != mMinTouchesRequired)||(maximumRequired != mMaxTouchesRequired) )
+ {
+ mMinTouchesRequired = minimumRequired;
+ mMaxTouchesRequired = maximumRequired;
+
+ PanGestureRequest request;
+ request.minTouches = mMinTouchesRequired;
+ request.maxTouches = mMaxTouchesRequired;
+ mGestureRecognizer->Update(request);
+ }
+}
+
+void PanGestureProcessor::EmitPanSignal( Actor* actor,
+ const GestureDetectorContainer& gestureDetectors,
+ const PanGestureEvent& panEvent,
+ Vector2 localCurrent,
+ Gesture::State state,
+ RenderTaskPtr renderTask )
+{
+ if ( actor && !gestureDetectors.empty() )
+ {
+ PanGesture pan(state);
+ pan.time = panEvent.time;
+
+ pan.numberOfTouches = panEvent.numberOfTouches;
+ pan.screenPosition = panEvent.currentPosition;
+ pan.position = localCurrent;
+
+ RenderTask& renderTaskImpl( *renderTask.Get() );
+
+ Vector2 localPrevious;
+ actor->ScreenToLocal( renderTaskImpl, localPrevious.x, localPrevious.y, panEvent.previousPosition.x, panEvent.previousPosition.y );
+
+ pan.displacement = localCurrent - localPrevious;
+ Vector2 previousPos( panEvent.previousPosition );
+ if ( state == Gesture::Started )
+ {
+ previousPos = mPossiblePanPosition;
+ }
+
+ pan.screenDisplacement = panEvent.currentPosition - previousPos;
+
+ // Avoid dividing by 0
+ if ( panEvent.timeDelta > 0 )
+ {
+ pan.velocity.x = pan.displacement.x / static_cast<float>( panEvent.timeDelta );
+ pan.velocity.y = pan.displacement.y / static_cast<float>( panEvent.timeDelta );
+
+ pan.screenVelocity.x = pan.screenDisplacement.x / static_cast<float>( panEvent.timeDelta );
+ pan.screenVelocity.y = pan.screenDisplacement.y / static_cast<float>( 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.
+ if ( ( state == Gesture::Finished ) && ( pan.screenVelocity == Vector2::ZERO ) &&
+ ( panEvent.timeDelta < MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY ) )
+ {
+ pan.velocity = mLastVelocity;
+ pan.screenVelocity = mLastScreenVelocity;
+ }
+ else
+ {
+ // Store the current velocity for future iterations.
+ mLastVelocity = pan.velocity;
+ mLastScreenVelocity = pan.screenVelocity;
+ }
+
+ if ( mSceneObject )
+ {
+ // We update the scene object directly rather than sending a message.
+ // Sending a message could cause unnecessary delays, the scene object ensure thread safe behaviour.
+ mSceneObject->AddGesture( pan );
+ }
+
+ Dali::Actor actorHandle( actor );
+
+ const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
+ for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
+ {
+ static_cast< PanGestureDetector* >( *iter )->EmitPanGestureSignal( actorHandle, pan );
+ }
+ }
+}
+
+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 = *mCurrentRenderTask.Get();
+
+ 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( *mCurrentRenderTask.Get(), 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
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_PROCESSOR_H
+#define DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_PROCESSOR_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.h>
+#include <dali/internal/event/events/gesture-processor.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+class Stage;
+class Scene;
+struct GestureEvent;
+struct PanGestureEvent;
+
+namespace SceneGraph
+{
+class PanGesture;
+class UpdateManager;
+}
+
+/**
+ * Pan Gesture Event Processing:
+ *
+ * When we receive a pan gesture event, we do the following:
+ * - Find the actor that requires a pan where the pan started from (i.e. the down position).
+ * - Emit the gesture if the event satisfies the detector conditions.
+ *
+ * The above is only checked when our gesture starts. We continue sending the pan gesture to the
+ * same actor and detector until the pan ends or is cancelled.
+ */
+class PanGestureProcessor : public GestureProcessor, public RecognizerObserver<PanGestureEvent>
+{
+public:
+
+ /**
+ * Create a pan gesture processor.
+ * @param[in] updateManager The Update Manager
+ */
+ PanGestureProcessor( SceneGraph::UpdateManager& updateManager );
+
+ /**
+ * Destructor
+ */
+ virtual ~PanGestureProcessor();
+
+public: // To be called by GestureEventProcessor
+
+ /**
+ * This method is called whenever a pan gesture event occurs.
+ * @param[in] scene The scene the pan gesture event occurs in.
+ * @param[in] panEvent The event that has occurred.
+ */
+ void Process( Scene& scene, const PanGestureEvent& panEvent );
+
+ /**
+ * Adds a gesture detector to this gesture processor.
+ * If this is the first gesture detector being added, then this method registers the required
+ * gesture with the adaptor.
+ * @param[in] gestureDetector The gesture detector being added.
+ */
+ void AddGestureDetector( PanGestureDetector* gestureDetector, Scene& scene, int32_t minDistance, int32_t minPanEvents );
+
+ /**
+ * Removes the specified gesture detector from this gesture processor. If, after removing this
+ * gesture detector, there are no more gesture detectors registered, then this method unregisters
+ * the gesture from the adaptor.
+ * @param[in] gestureDetector The gesture detector being removed.
+ */
+ void RemoveGestureDetector( PanGestureDetector* gestureDetector );
+
+ /**
+ * This method updates the gesture detection parameters.
+ * @param[in] gestureDetector The gesture detector that has been updated.
+ */
+ void GestureDetectorUpdated( PanGestureDetector* gestureDetector );
+
+ /**
+ * Sets the pan gesture properties stored in the scene object directly,
+ * @param[in] pan The pan gesture to override the properties with.
+ * @return true if Core::Update required
+ * @note If we are already processing a normal pan, then this call is ignored.
+ */
+ bool SetPanGestureProperties( const PanGesture& pan );
+
+ /**
+ * Called to provide pan-gesture profiling information.
+ */
+ void EnableProfiling();
+
+ /**
+ * Called to set the prediction mode for pan gestures
+ *
+ * @param[in] mode The prediction mode
+ *
+ * Valid modes:
+ * 0 - No prediction
+ * 1 - Prediction using average acceleration
+ */
+ void SetPredictionMode(int mode);
+
+ /**
+ * @brief Sets the prediction amount of the pan gesture
+ *
+ * @param[in] amount The prediction amount in milliseconds
+ */
+ void SetPredictionAmount(unsigned int amount);
+
+ /**
+ * @brief Sets the upper bound of the prediction amount for clamping
+ *
+ * @param[in] amount The prediction amount in milliseconds
+ */
+ void SetMaximumPredictionAmount(unsigned int amount);
+
+ /**
+ * @brief Sets the lower bound of the prediction amount for clamping
+ *
+ * @param[in] amount The prediction amount in milliseconds
+ */
+ void SetMinimumPredictionAmount(unsigned int amount);
+
+ /**
+ * @brief Sets the amount of prediction interpolation to adjust when the pan velocity is changed
+ *
+ * @param[in] amount The prediction amount in milliseconds
+ */
+ void SetPredictionAmountAdjustment(unsigned int amount);
+
+ /**
+ * Called to set the prediction mode for pan gestures
+ *
+ * @param[in] mode The prediction mode
+ *
+ * Valid modes:
+ * 0 - No smoothing
+ * 1 - average between last 2 values
+ */
+ void SetSmoothingMode(int mode);
+
+ /**
+ * @brief Sets the smoothing amount of the pan gesture
+ *
+ * @param[in] amount The smotthing amount from 0.0f (none) to 1.0f (full)
+ */
+ void SetSmoothingAmount(float amount);
+
+ /*
+ * @brief Sets whether to use actual times of the real gesture and frames or not.
+ *
+ * @param[in] value True = use actual times, False = use perfect values
+ */
+ void SetUseActualTimes( bool value );
+
+ /**
+ * @brief Sets the interpolation time range (ms) of past points to use (with weights) when interpolating.
+ *
+ * @param[in] value Time range in ms
+ */
+ void SetInterpolationTimeRange( int value );
+
+ /**
+ * @brief Sets whether to use scalar only prediction, which when enabled, ignores acceleration.
+ *
+ * @param[in] value True = use scalar prediction only
+ */
+ void SetScalarOnlyPredictionEnabled( bool value );
+
+ /**
+ * @brief Sets whether to use two point prediction. This combines two interpolated points to get more steady acceleration and velocity values.
+ *
+ * @param[in] value True = use two point prediction
+ */
+ void SetTwoPointPredictionEnabled( bool value );
+
+ /**
+ * @brief Sets the time in the past to interpolate the second point when using two point interpolation.
+ *
+ * @param[in] value Time in past in ms
+ */
+ void SetTwoPointInterpolatePastTime( int value );
+
+ /**
+ * @brief Sets the two point velocity bias. This is the ratio of first and second points to use for velocity.
+ *
+ * @param[in] value 0.0f = 100% first point. 1.0f = 100% of second point.
+ */
+ void SetTwoPointVelocityBias( float value );
+
+ /**
+ * @brief Sets the two point acceleration bias. This is the ratio of first and second points to use for acceleration.
+ *
+ * @param[in] value 0.0f = 100% first point. 1.0f = 100% of second point.
+ */
+ void SetTwoPointAccelerationBias( float value );
+
+ /**
+ * @brief Sets the range of time (ms) of points in the history to perform multitap smoothing with (if enabled).
+ *
+ * @param[in] value Time in past in ms
+ */
+ void SetMultitapSmoothingRange( int value );
+
+public: // for PanGestureDetector
+
+ /**
+ * @return the pan gesture scene object
+ */
+ const SceneGraph::PanGesture& GetSceneObject() const;
+
+private:
+
+ // Undefined
+ PanGestureProcessor( const PanGestureProcessor& );
+ PanGestureProcessor& operator=( const PanGestureProcessor& rhs );
+
+ /**
+ * Iterates through our GestureDetectors and determines if we need to ask the adaptor to update
+ * its detection policy. If it does, it sends the appropriate gesture update request to adaptor.
+ */
+ void UpdateDetection();
+
+ /**
+ * Creates a PanGesture and asks the specified detector to emit its detected signal.
+ * @param[in] actor The actor that has been panned.
+ * @param[in] gestureDetectors The gesture detector container that should emit the signal.
+ * @param[in] panEvent The panEvent received from the adaptor.
+ * @param[in] localCurrent Current position relative to the actor attached to the detector.
+ * @param[in] state The state of the gesture.
+ * @param[in] renderTask The renderTask to use.
+ */
+ void EmitPanSignal( Actor* actor,
+ const GestureDetectorContainer& gestureDetectors,
+ const PanGestureEvent& panEvent,
+ Vector2 localCurrent,
+ Gesture::State state,
+ RenderTaskPtr renderTask );
+
+ // GestureProcessor overrides
+
+ /**
+ * @copydoc GestureProcessor::OnGesturedActorStageDisconnection()
+ */
+ void OnGesturedActorStageDisconnection();
+
+ /**
+ * @copydoc GestureProcessor::CheckGestureDetector()
+ */
+ bool CheckGestureDetector( GestureDetector* detector, Actor* actor );
+
+ /**
+ * @copydoc GestureProcessor::EmitGestureSignal()
+ */
+ void EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates );
+
+private:
+
+ PanGestureDetectorContainer mPanGestureDetectors;
+ GestureDetectorContainer mCurrentPanEmitters;
+ RenderTaskPtr mCurrentRenderTask;
+ Vector2 mPossiblePanPosition;
+
+ uint32_t mMinTouchesRequired;
+ uint32_t mMaxTouchesRequired;
+
+ Vector2 mLastVelocity; ///< The last recorded velocity in local actor coordinates.
+ Vector2 mLastScreenVelocity; ///< The last recorded velocity in screen coordinates.
+
+ const PanGestureEvent* mCurrentPanEvent; ///< Pointer to current PanEvent, used when calling ProcessAndEmit()
+ SceneGraph::PanGesture* mSceneObject; ///< Not owned, but we write to it directly
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_PAN_GESTURE_EVENT_PROCESSOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/pan-gesture/pan-gesture-recognizer.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/events/touch-point.h>
+
+#include <dali/integration-api/events/touch-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/common/scene-impl.h>
+#include <dali/internal/event/events/pan-gesture/pan-gesture-event.h>
+#include <dali/internal/event/events/gesture-requests.h>
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN( 15.0f );
+const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_BEFORE_PAN );
+const float MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO( 2.0f / 3.0f );
+const unsigned long MAXIMUM_TIME_DIFF_ALLOWED( 500 );
+const unsigned long MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS( 100 );
+const unsigned int MINIMUM_MOTION_EVENTS_BEFORE_PAN(2);
+} // unnamed namespace
+
+PanGestureRecognizer::PanGestureRecognizer( Observer& observer, Vector2 screenSize, const PanGestureRequest& request, int32_t minimumDistance, int32_t minimumPanEvents )
+: GestureRecognizer( screenSize, Gesture::Pan ),
+ mObserver( observer ),
+ mState( Clear ),
+ mThresholdAdjustmentsRemaining( 0 ),
+ mThresholdTotalAdjustments( static_cast<unsigned int>( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO ) ),
+ mPrimaryTouchDownTime( 0 ),
+ mMinimumTouchesRequired( request.minTouches ),
+ mMaximumTouchesRequired( request.maxTouches ),
+ mMinimumDistanceSquared( static_cast<unsigned int>( MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED ) ),
+ mMinimumMotionEvents( MINIMUM_MOTION_EVENTS_BEFORE_PAN ),
+ mMotionEvents( 0 )
+{
+ if ( minimumDistance >= 0 )
+ {
+ mMinimumDistanceSquared = minimumDistance * minimumDistance;
+
+ // Usually, we do not want to apply the threshold straight away, but phased over the first few pans
+ // Set our distance to threshold adjustments ratio here.
+ float fMinimumDistance = static_cast<float>( minimumDistance );
+ mThresholdTotalAdjustments = static_cast<unsigned int>( fMinimumDistance * MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO );
+ }
+
+ if ( minimumPanEvents >= 1 )
+ {
+ mMinimumMotionEvents = minimumPanEvents - 1; // Down is the first event
+ }
+}
+
+PanGestureRecognizer::~PanGestureRecognizer()
+{
+}
+
+void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
+{
+ PointState::Type primaryPointState(event.points[0].GetState());
+
+ if (primaryPointState == PointState::INTERRUPTED)
+ {
+ if ( ( mState == Started ) || ( mState == Possible ) )
+ {
+ // If our pan had started and we are interrupted, then tell Core that pan is cancelled.
+ mTouchEvents.push_back(event);
+ SendPan(Gesture::Cancelled, event);
+ }
+ mState = Clear; // We should change our state to Clear.
+ mTouchEvents.clear();
+ }
+ else
+ {
+ switch (mState)
+ {
+ case Clear:
+ {
+ if ( ( primaryPointState == PointState::DOWN ) || ( primaryPointState == PointState::STATIONARY ) )
+ {
+ mPrimaryTouchDownLocation = event.points[0].GetScreenPosition();
+ mPrimaryTouchDownTime = event.time;
+ mMotionEvents = 0;
+ if (event.GetPointCount() == mMinimumTouchesRequired)
+ {
+ // We have satisfied the minimum touches required for a pan, tell core that a gesture may be possible and change our state accordingly.
+ mState = Possible;
+ SendPan(Gesture::Possible, event);
+ }
+
+ mTouchEvents.push_back(event);
+ }
+ break;
+ }
+
+ case Possible:
+ {
+ unsigned int pointCount(event.GetPointCount());
+ if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) )
+ {
+ if (primaryPointState == PointState::MOTION)
+ {
+ mTouchEvents.push_back(event);
+ mMotionEvents++;
+
+ Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation);
+
+ if ( ( mMotionEvents >= mMinimumMotionEvents ) &&
+ ( delta.LengthSquared() >= static_cast<float>( mMinimumDistanceSquared ) ) )
+ {
+ // If the touch point(s) have moved enough distance to be considered a pan, then tell Core that the pan gesture has started and change our state accordingly.
+ mState = Started;
+ SendPan(Gesture::Started, event);
+ }
+ }
+ else if (primaryPointState == PointState::UP)
+ {
+ Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation);
+ if (delta.LengthSquared() >= static_cast<float>( mMinimumDistanceSquared ) )
+ {
+ SendPan(Gesture::Started, event);
+ mTouchEvents.push_back(event);
+ SendPan(Gesture::Finished, event);
+ }
+ else
+ {
+ // If we have lifted the primary touch point then tell core the pan is cancelled and change our state to Clear.
+ SendPan(Gesture::Cancelled, event);
+ }
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ }
+ else
+ {
+ // We do not satisfy pan conditions, tell Core our Gesture has been cancelled.
+ SendPan(Gesture::Cancelled, event);
+
+ if (pointCount == 1 && primaryPointState == PointState::UP)
+ {
+ // If we have lifted the primary touch point, then change our state to Clear...
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ // ...otherwise change it to Failed.
+ mState = Failed;
+ }
+ }
+ break;
+ }
+
+ case Started:
+ {
+ mTouchEvents.push_back(event);
+
+ unsigned int pointCount(event.GetPointCount());
+ if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) )
+ {
+ switch (primaryPointState)
+ {
+ case PointState::MOTION:
+ // Pan is continuing, tell Core.
+ SendPan(Gesture::Continuing, event);
+ break;
+
+ case PointState::UP:
+ // Pan is finally finished when our primary point is lifted, tell Core and change our state to Clear.
+ mState = Clear;
+ SendPan(Gesture::Finished, event);
+ mTouchEvents.clear();
+ break;
+
+ case PointState::STATIONARY:
+ if (pointCount == mMinimumTouchesRequired)
+ {
+ Integration::PointContainerConstIterator iter = event.points.begin() + 1; // We already know the state of the first point
+ for(; iter != event.points.end(); ++iter)
+ {
+ if(iter->GetState() == PointState::UP)
+ {
+ // The number of touch points will be less than the minimum required. Inform core and change our state to Finished.
+ SendPan(Gesture::Finished, event);
+ mState = Finished;
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // We have gone outside of the pan requirements, inform Core that the gesture is finished.
+ SendPan(Gesture::Finished, event);
+
+ if (pointCount == 1 && primaryPointState == PointState::UP)
+ {
+ // If this was the primary point being released, then we change our state back to Clear...
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ // ...otherwise we change it to Finished.
+ mState = Finished;
+ }
+ }
+ break;
+ }
+
+ case Finished:
+ case Failed:
+ {
+ if (primaryPointState == PointState::UP)
+ {
+ // Change our state back to clear when the primary touch point is released.
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ break;
+ }
+ }
+ }
+}
+
+void PanGestureRecognizer::Update(const GestureRequest& request)
+{
+ const PanGestureRequest& pan = static_cast<const PanGestureRequest&>(request);
+
+ mMinimumTouchesRequired = pan.minTouches;
+ mMaximumTouchesRequired = pan.maxTouches;
+}
+
+void PanGestureRecognizer::SendPan(Gesture::State state, const Integration::TouchEvent& currentEvent)
+{
+ PanGestureEvent gesture(state);
+ gesture.currentPosition = currentEvent.points[0].GetScreenPosition();
+ gesture.numberOfTouches = currentEvent.GetPointCount();
+
+ if ( mTouchEvents.size() > 1 )
+ {
+ // Get the second last event in the queue, the last one is the current event
+ const Integration::TouchEvent& previousEvent( *( mTouchEvents.rbegin() + 1 ) );
+
+ Vector2 previousPosition( mPreviousPosition );
+ uint32_t previousTime( previousEvent.time );
+
+ // If we've just started then we want to remove the threshold from Core calculations.
+ if ( state == Gesture::Started )
+ {
+ previousPosition = mPrimaryTouchDownLocation;
+ previousTime = mPrimaryTouchDownTime;
+
+ // If it's a slow pan, we do not want to phase in the threshold over the first few pan-events
+ // A slow pan is defined as one that starts the specified number of milliseconds after the down-event
+ if ( ( currentEvent.time - previousTime ) > MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS )
+ {
+ mThresholdAdjustmentsRemaining = mThresholdTotalAdjustments;
+ mThresholdAdjustmentPerFrame = ( gesture.currentPosition - previousPosition ) / static_cast<float>( mThresholdTotalAdjustments );
+ }
+ else
+ {
+ mThresholdAdjustmentsRemaining = 0;
+ mThresholdAdjustmentPerFrame = Vector2::ZERO;
+ }
+ }
+
+ gesture.previousPosition = previousPosition;
+ gesture.timeDelta = currentEvent.time - previousTime;
+
+ // Apply the threshold with a phased approach
+ if ( mThresholdAdjustmentsRemaining > 0 )
+ {
+ --mThresholdAdjustmentsRemaining;
+ gesture.currentPosition -= mThresholdAdjustmentPerFrame * static_cast<float>( mThresholdAdjustmentsRemaining );
+ }
+
+ mPreviousPosition = gesture.currentPosition;
+ }
+ else
+ {
+ gesture.previousPosition = gesture.currentPosition;
+ gesture.timeDelta = 0;
+ }
+
+ gesture.time = currentEvent.time;
+
+ if( mScene )
+ {
+ // Create another handle so the recognizer cannot be destroyed during process function
+ GestureRecognizerPtr recognizerHandle = this;
+
+ mObserver.Process(*mScene, gesture);
+ }
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_PAN_GESTURE_RECOGNIZER_H
+#define DALI_INTERNAL_EVENT_PAN_GESTURE_RECOGNIZER_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <cstdint> // uint32_t
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/gesture-recognizer.h>
+#include <dali/internal/event/events/pan-gesture/pan-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class Core;
+struct TouchEvent;
+
+}
+
+namespace Internal
+{
+
+struct PanGestureRequest;
+/**
+ * When given a set of touch events, this detector attempts to determine if a pan gesture has taken place.
+ */
+class PanGestureRecognizer : public GestureRecognizer
+{
+public:
+
+ using Observer = RecognizerObserver<PanGestureEvent>;
+
+ /**
+ * Constructor
+ * @param[in] screenSize The size of the screen.
+ * @param[in] request The details of the request.
+ */
+ PanGestureRecognizer( Observer& observer, Vector2 screenSize, const PanGestureRequest& request, int32_t minimumDistance, int32_t minimumPanEvents);
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~PanGestureRecognizer();
+
+public:
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
+ */
+ virtual void SendEvent(const Integration::TouchEvent& event);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
+ */
+ virtual void Update(const GestureRequest& request);
+
+private:
+
+ /**
+ * Emits the pan gesture event (performs some smoothing operation).
+ * @param[in] state The state of the pan.
+ * @param[in] currentEvent The latest touch event.
+ */
+ void SendPan(Gesture::State state, const Integration::TouchEvent& currentEvent);
+
+private:
+
+ // Reference to the gesture processor for this recognizer
+ Observer& mObserver;
+
+ /**
+ * Internal state machine.
+ */
+ enum State
+ {
+ Clear, ///< No gesture detected.
+ Possible, ///< The current touch event data suggests that a gesture is possible.
+ Started, ///< A gesture has been detected.
+ Finished, ///< A previously started pan gesture has finished.
+ Failed, ///< Current touch event data suggests a pan gesture is not possible.
+ };
+
+ State mState; ///< The current state of the detector.
+ std::vector<Integration::TouchEvent> mTouchEvents; ///< A container of all touch events after an initial down event.
+
+ Vector2 mPrimaryTouchDownLocation; ///< The initial touch down point.
+ Vector2 mThresholdAdjustmentPerFrame; ///< The adjustment per frame at the start of a slow pan.
+ Vector2 mPreviousPosition; ///< The previous position.
+
+ unsigned int mThresholdAdjustmentsRemaining; ///< No. of threshold adjustments still to apply (for a slow-pan).
+ unsigned int mThresholdTotalAdjustments; ///< The total number of adjustments required.
+
+ uint32_t mPrimaryTouchDownTime; ///< The initial touch down time.
+ unsigned int mMinimumTouchesRequired; ///< The minimum touches required before a pan should be emitted.
+ unsigned int mMaximumTouchesRequired; ///< The maximum touches after which a pan should not be emitted.
+
+ unsigned int mMinimumDistanceSquared; ///< The minimum distance squared before pan should start.
+ unsigned int mMinimumMotionEvents; ///< The minimum motion events before pan should start.
+ unsigned int mMotionEvents; ///< The motion events received so far (before pan is emitted).
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_PAN_GESTURE_RECOGNIZER_H
+++ /dev/null
-/*
- * Copyright (c) 2016 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/pinch-gesture-detector-impl.h>
-
-// EXTERNAL INCLUDES
-#include <cstring> // for strcmp
-
-// INTERNAL INCLUDES
-#include <dali/public-api/events/pinch-gesture.h>
-#include <dali/public-api/object/type-registry.h>
-#include <dali/internal/event/events/gesture-event-processor.h>
-#include <dali/integration-api/debug.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-
-// Signals
-
-const char* const SIGNAL_PINCH_DETECTED = "pinchDetected";
-
-BaseHandle Create()
-{
- return Dali::PinchGestureDetector::New();
-}
-
-TypeRegistration mType( typeid(Dali::PinchGestureDetector), typeid(Dali::GestureDetector), Create );
-
-SignalConnectorType signalConnector1( mType, SIGNAL_PINCH_DETECTED, &PinchGestureDetector::DoConnectSignal );
-
-}
-
-
-PinchGestureDetectorPtr PinchGestureDetector::New()
-{
- return new PinchGestureDetector;
-}
-
-PinchGestureDetector::PinchGestureDetector()
-: GestureDetector(Gesture::Pinch)
-{
-}
-
-PinchGestureDetector::~PinchGestureDetector()
-{
-}
-
-void PinchGestureDetector::EmitPinchGestureSignal(Dali::Actor actor, const PinchGesture& pinch)
-{
- // Guard against destruction during signal emission
- Dali::PinchGestureDetector handle( this );
-
- mDetectedSignal.Emit( actor, pinch );
-}
-
-bool PinchGestureDetector::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
-{
- bool connected( true );
- PinchGestureDetector* gesture = static_cast< PinchGestureDetector* >(object); // TypeRegistry guarantees that this is the correct type.
-
- if ( 0 == strcmp( signalName.c_str(), SIGNAL_PINCH_DETECTED ) )
- {
- gesture->DetectedSignal().Connect( tracker, functor );
- }
- else
- {
- // signalName does not match any signal
- connected = false;
- }
-
- return connected;
-}
-
-void PinchGestureDetector::OnActorAttach(Actor& actor)
-{
- // Do nothing
-}
-
-void PinchGestureDetector::OnActorDetach(Actor& actor)
-{
- // Do nothing
-}
-
-void PinchGestureDetector::OnActorDestroyed(Object& object)
-{
- // Do nothing
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_PINCH_GESTURE_DETECTOR_H
-#define DALI_INTERNAL_PINCH_GESTURE_DETECTOR_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/public-api/events/pinch-gesture-detector.h>
-#include <dali/internal/event/events/gesture-detector-impl.h>
-
-namespace Dali
-{
-
-struct PinchGesture;
-
-namespace Internal
-{
-
-class PinchGestureDetector;
-
-typedef IntrusivePtr<PinchGestureDetector> PinchGestureDetectorPtr;
-typedef DerivedGestureDetectorContainer<PinchGestureDetector>::type PinchGestureDetectorContainer;
-
-/**
- * @copydoc Dali::PinchGestureDetector
- */
-class PinchGestureDetector : public GestureDetector
-{
-public: // Creation
-
- /**
- * Create a new gesture detector.
- * @return A smart-pointer to the newly allocated detector.
- */
- static PinchGestureDetectorPtr New();
-
- /**
- * Construct a new GestureDetector.
- */
- PinchGestureDetector();
-
-public:
-
- /**
- * Called by the PinchGestureProcessor when a pinch gesture event occurs within the bounds of our
- * attached actor.
- * @param[in] actor The pinched actor.
- * @param[in] pinch The pinch gesture.
- */
- void EmitPinchGestureSignal(Dali::Actor actor, const PinchGesture& pinch);
-
-public: // Signals
-
- /**
- * @copydoc Dali::PinchGestureDetector::DetectedSignal()
- */
- Dali::PinchGestureDetector::DetectedSignalType& DetectedSignal()
- {
- return mDetectedSignal;
- }
-
- /**
- * Connects a callback function with the object's signals.
- * @param[in] object The object providing the signal.
- * @param[in] tracker Used to disconnect the signal.
- * @param[in] signalName The signal to connect to.
- * @param[in] functor A newly allocated FunctorDelegate.
- * @return True if the signal was connected.
- * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
- */
- static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
-
-protected:
-
- /**
- * A reference counted object may only be deleted by calling Unreference()
- */
- virtual ~PinchGestureDetector();
-
-private:
-
- // Undefined
- PinchGestureDetector(const PinchGestureDetector&);
- PinchGestureDetector& operator=(const PinchGestureDetector& rhs);
-
-private: // GestureDetector overrides
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&)
- */
- virtual void OnActorAttach(Actor& actor);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorDetach(Actor&)
- */
- virtual void OnActorDetach(Actor& actor);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorDestroyed(Object&)
- */
- virtual void OnActorDestroyed(Object& object);
-
-private:
-
- Dali::PinchGestureDetector::DetectedSignalType mDetectedSignal;
-};
-
-} // namespace Internal
-
-// Helpers for public-api forwarding methods
-
-inline Internal::PinchGestureDetector& GetImplementation(Dali::PinchGestureDetector& detector)
-{
- DALI_ASSERT_ALWAYS( detector && "PinchGestureDetector handle is empty" );
-
- BaseObject& handle = detector.GetBaseObject();
-
- return static_cast<Internal::PinchGestureDetector&>(handle);
-}
-
-inline const Internal::PinchGestureDetector& GetImplementation(const Dali::PinchGestureDetector& detector)
-{
- DALI_ASSERT_ALWAYS( detector && "PinchGestureDetector handle is empty" );
-
- const BaseObject& handle = detector.GetBaseObject();
-
- return static_cast<const Internal::PinchGestureDetector&>(handle);
-}
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_PINCH_GESTURE_DETECTOR_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/pinch-gesture-event.h>
-
-// INTERNAL INCLUDES
-#include <dali/public-api/common/dali-common.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-PinchGestureEvent::PinchGestureEvent(Gesture::State state)
-: GestureEvent(Gesture::Pinch, state),
- scale(0.0f),
- speed(0.0f),
- centerPoint()
-{
-}
-
-PinchGestureEvent::~PinchGestureEvent()
-{
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_EVENT_PINCH_GESTURE_EVENT_H
-#define DALI_INTERNAL_EVENT_PINCH_GESTURE_EVENT_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/gesture-event.h>
-#include <dali/public-api/math/vector2.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-/**
- * If the adaptor detects a pinch gesture, then it should create an instance of this structure and
- * send it to the Core.
- *
- * A Pinch Gesture event should be in one of four states:
- * - Started: If a pinch is detected.
- * - Continuing: If after a pinch is detected, it continues.
- * - Finished: If after a pinch, the user lifts their finger(s).
- * - Cancelled: If there is a system interruption.
- */
-struct PinchGestureEvent : public GestureEvent
-{
- // Construction & Destruction
-
- /**
- * Default Constructor
- * @param[in] state The state of the gesture
- */
- PinchGestureEvent(Gesture::State state);
-
- /**
- * Virtual destructor
- */
- virtual ~PinchGestureEvent();
-
- // Data
-
- /**
- * @copydoc Dali::PinchGesture::scale
- */
- float scale;
-
- /**
- * @copydoc Dali::PinchGesture::speed
- */
- float speed;
-
- /**
- * The center point between the two touch points of the last touch event in the series of touch motion
- * event producing this gesture.
- */
- Vector2 centerPoint;
-};
-
-} // namespace Integration
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_EVENT_PINCH_GESTURE_EVENT_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/pinch-gesture-processor.h>
-
-// EXTERNAL INCLUDES
-#include <algorithm>
-
-// INTERNAL INCLUDES
-#include <dali/public-api/actors/actor.h>
-#include <dali/public-api/events/pinch-gesture.h>
-#include <dali/public-api/math/vector2.h>
-#include <dali/internal/event/events/pinch-gesture-event.h>
-#include <dali/integration-api/debug.h>
-#include <dali/internal/event/common/scene-impl.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
-#include <dali/internal/event/events/pinch-gesture-recognizer.h>
-#include <dali/internal/event/events/gesture-requests.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-
-/**
- * Creates a PinchGesture and asks the specified detector to emit its detected signal.
- * @param[in] actor The actor that has been pinched.
- * @param[in] gestureDetectors The gesture detector container that should emit the signal.
- * @param[in] pinchEvent The pinchEvent received from the adaptor.
- * @param[in] localCenter Relative to the actor attached to the detector.
- */
-void EmitPinchSignal(
- Actor* actor,
- const GestureDetectorContainer& gestureDetectors,
- const PinchGestureEvent& pinchEvent,
- Vector2 localCenter)
-{
- PinchGesture pinch(pinchEvent.state);
- pinch.time = pinchEvent.time;
-
- pinch.scale = pinchEvent.scale;
- pinch.speed = pinchEvent.speed;
- pinch.screenCenterPoint = pinchEvent.centerPoint;
-
- pinch.localCenterPoint = localCenter;
-
- Dali::Actor actorHandle( actor );
- const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
- for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
- {
- static_cast< PinchGestureDetector* >( *iter )->EmitPinchGestureSignal( actorHandle, pinch );
- }
-}
-
-/**
- * Functor which checks whether the specified actor is attached to the gesture detector.
- * It returns true if it is no longer attached. This can be used in remove_if functions.
- */
-struct IsNotAttachedFunctor
-{
- /**
- * Constructor
- * @param[in] actor The actor to check whether it is attached.
- */
- IsNotAttachedFunctor(Actor* actor)
- : actorToCheck(actor)
- {
- }
-
- /**
- * Returns true if not attached, false if it is still attached.
- * @param[in] detector The detector to check.
- * @return true, if not attached, false otherwise.
- */
- bool operator()(const GestureDetector* detector) const
- {
- return !detector->IsAttached(*actorToCheck);
- }
-
- Actor* actorToCheck; ///< The actor to check whether it is attached or not.
-};
-
-} // unnamed namespace
-
-PinchGestureProcessor::PinchGestureProcessor()
-: GestureProcessor( Gesture::Pinch ),
- mPinchGestureDetectors(),
- mCurrentPinchEmitters(),
- mCurrentPinchEvent(NULL),
- mMinimumPinchDistance(-1.0f)
-{
-}
-
-PinchGestureProcessor::~PinchGestureProcessor()
-{
-}
-
-void PinchGestureProcessor::SetMinimumPinchDistance( float value )
-{
- mMinimumPinchDistance = value;
-
- if( mGestureRecognizer )
- {
- PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>(mGestureRecognizer.Get());
- if( pinchRecognizer )
- {
- pinchRecognizer->SetMinimumPinchDistance(value);
- }
- }
-}
-
-void PinchGestureProcessor::Process( Scene& scene, const PinchGestureEvent& pinchEvent )
-{
- switch ( pinchEvent.state )
- {
- case Gesture::Started:
- {
- // The pinch gesture should only be sent to the gesture detector which first received it so that
- // it can be told when the gesture ends as well.
-
- mCurrentPinchEmitters.clear();
- ResetActor();
-
- HitTestAlgorithm::Results hitTestResults;
- if( HitTest( scene, pinchEvent.centerPoint, hitTestResults ) )
- {
- // Record the current render-task for Screen->Actor coordinate conversions
- mCurrentRenderTask = hitTestResults.renderTask;
-
- // Set mCurrentPinchEvent to use inside overridden methods called from ProcessAndEmit()
- mCurrentPinchEvent = &pinchEvent;
- ProcessAndEmit( hitTestResults );
- mCurrentPinchEvent = NULL;
- }
- break;
- }
-
- case Gesture::Continuing:
- case Gesture::Finished:
- case Gesture::Cancelled:
- {
- // Only send subsequent pinch gesture signals if we processed the pinch gesture when it started.
- // Check if actor is still touchable.
-
- Actor* currentGesturedActor = GetCurrentGesturedActor();
- if ( currentGesturedActor )
- {
- if ( currentGesturedActor->IsHittable() && !mCurrentPinchEmitters.empty() && mCurrentRenderTask )
- {
- // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
- GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
- mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
-
- if ( !mCurrentPinchEmitters.empty() )
- {
- Vector2 actorCoords;
- RenderTask& renderTaskImpl( *mCurrentRenderTask.Get() );
- currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, pinchEvent.centerPoint.x, pinchEvent.centerPoint.y );
-
- EmitPinchSignal( currentGesturedActor, mCurrentPinchEmitters, pinchEvent, actorCoords );
- }
- else
- {
- // If we have no current emitters then clear pinched actor as well.
- ResetActor();
- }
-
- // Clear current emitters if pinch gesture has ended or been cancelled.
- if ( pinchEvent.state == Gesture::Finished || pinchEvent.state == Gesture::Cancelled )
- {
- mCurrentPinchEmitters.clear();
- ResetActor();
- }
- }
- else
- {
- mCurrentPinchEmitters.clear();
- ResetActor();
- }
- }
- break;
- }
-
- case Gesture::Clear:
- {
- DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
- break;
- }
- case Gesture::Possible:
- {
- DALI_ABORT( "Incorrect state received from Integration layer: Possible\n" );
- break;
- }
- }
-}
-
-void PinchGestureProcessor::AddGestureDetector( PinchGestureDetector* gestureDetector, Scene& scene )
-{
- bool createRecognizer(mPinchGestureDetectors.empty());
-
- mPinchGestureDetectors.push_back(gestureDetector);
-
- if (createRecognizer)
- {
- Size size = scene.GetSize();
- mGestureRecognizer = new PinchGestureRecognizer( *this, Vector2(size.width, size.height), mMinimumPinchDistance);
- }
-}
-
-void PinchGestureProcessor::RemoveGestureDetector( PinchGestureDetector* gestureDetector )
-{
- if ( !mCurrentPinchEmitters.empty() )
- {
- // Check if the removed detector was one that is currently being pinched and remove it from emitters.
- GestureDetectorContainer::iterator endIter = std::remove( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), gestureDetector );
- mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
-
- // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
- if ( mCurrentPinchEmitters.empty() )
- {
- ResetActor();
- }
- }
-
- // Find the detector...
- PinchGestureDetectorContainer::iterator endIter = std::remove( mPinchGestureDetectors.begin(), mPinchGestureDetectors.end(), gestureDetector );
- DALI_ASSERT_DEBUG( endIter != mPinchGestureDetectors.end() );
-
- // ...and remove it
- mPinchGestureDetectors.erase(endIter, mPinchGestureDetectors.end());
-
- if (mPinchGestureDetectors.empty())
- {
- mGestureRecognizer.Detach();
- }
-}
-
-void PinchGestureProcessor::GestureDetectorUpdated( PinchGestureDetector* gestureDetector )
-{
- // Nothing to do as PinchGestureDetector does not have any specific parameters.
-}
-
-void PinchGestureProcessor::OnGesturedActorStageDisconnection()
-{
- mCurrentPinchEmitters.clear();
-}
-
-bool PinchGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
-{
- // No special case required for pinch.
- return true;
-}
-
-void PinchGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
-{
- DALI_ASSERT_DEBUG( mCurrentPinchEvent );
-
- EmitPinchSignal( actor, gestureDetectors, *mCurrentPinchEvent, actorCoordinates );
-
- if ( actor->OnStage() )
- {
- mCurrentPinchEmitters = gestureDetectors;
- SetActor( actor );
- }
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_PINCH_GESTURE_EVENT_PROCESSOR_H
-#define DALI_INTERNAL_PINCH_GESTURE_EVENT_PROCESSOR_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/pinch-gesture-detector-impl.h>
-#include <dali/internal/event/events/gesture-processor.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-class Scene;
-class Stage;
-
-struct PinchGestureEvent;
-
-/**
- * Pinch Gesture Event Processing:
- *
- * When we receive a pinch gesture event, we do the following:
- * - Find the hit actor that requires a pinch underneath the center-point of the pinch.
- * - Emit the gesture if the event satisfies the detector conditions.
- *
- * The above is only checked when our gesture starts. We continue sending the pinch gesture to this
- * detector until the pinch ends or is cancelled.
- */
-class PinchGestureProcessor : public GestureProcessor, public RecognizerObserver<PinchGestureEvent>
-{
-public:
-
- /**
- * Create a pinch gesture processor.
- */
- PinchGestureProcessor();
-
- /**
- * Non-virtual destructor; PinchGestureProcessor is not a base class
- */
- ~PinchGestureProcessor();
-
-public: // To be called by GestureEventProcessor
-
- /**
- * This method sets the minimum distance to start a pinch
- * @param[in] value The distance in pixels
- */
- void SetMinimumPinchDistance( float value );
-
- /**
- * This method is called whenever a pinch gesture event occurs.
- * @param[in] scene The scene the pinch gesture event occurs in.
- * @param[in] pinchEvent The event that has occurred.
- */
- void Process( Scene& scene, const PinchGestureEvent& pinchEvent );
-
- /**
- * Adds a gesture detector to this gesture processor.
- * If this is the first gesture detector being added, then this method registers the required
- * gesture with the adaptor.
- * @param[in] gestureDetector The gesture detector being added.
- */
- void AddGestureDetector(PinchGestureDetector* gestureDetector, Scene& scene);
-
- /**
- * Removes the specified gesture detector from this gesture processor. If, after removing this
- * gesture detector, there are no more gesture detectors registered, then this method unregisters
- * the gesture from the adaptor.
- * @param[in] gestureDetector The gesture detector being removed.
- */
- void RemoveGestureDetector(PinchGestureDetector* gestureDetector);
-
- /**
- * This method updates the gesture detection parameters.
- * @param[in] gestureDetector The gesture detector that has been updated.
- */
- void GestureDetectorUpdated(PinchGestureDetector* gestureDetector);
-
-private:
-
- // Undefined
- PinchGestureProcessor(const PinchGestureProcessor&);
- PinchGestureProcessor& operator=(const PinchGestureProcessor& rhs);
-
-private:
-
- // GestureProcessor overrides
-
- /**
- * @copydoc GestureProcessor::OnGesturedActorStageDisconnection()
- */
- void OnGesturedActorStageDisconnection();
-
- /**
- * @copydoc GestureProcessor::CheckGestureDetector()
- */
- bool CheckGestureDetector( GestureDetector* detector, Actor* actor );
-
- /**
- * @copydoc GestureProcessor::EmitGestureSignal()
- */
- void EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates );
-
-private:
-
- PinchGestureDetectorContainer mPinchGestureDetectors;
- GestureDetectorContainer mCurrentPinchEmitters;
- RenderTaskPtr mCurrentRenderTask;
-
- const PinchGestureEvent* mCurrentPinchEvent; ///< Pointer to current PinchEvent, used when calling ProcessAndEmit()
-
- float mMinimumPinchDistance;
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_PINCH_GESTURE_EVENT_PROCESSOR_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/pinch-gesture-recognizer.h>
-
-// EXTERNAL INCLUDES
-#include <cmath>
-
-#include <dali/public-api/events/touch-point.h>
-#include <dali/public-api/math/vector2.h>
-
-#include <dali/internal/event/events/pinch-gesture-event.h>
-#include <dali/integration-api/events/touch-event-integ.h>
-#include <dali/internal/event/common/scene-impl.h>
-
-// INTERNAL INCLUDES
-
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-const unsigned int MINIMUM_TOUCH_EVENTS_REQUIRED = 4;
-const unsigned int MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START = 4;
-
-const float MINIMUM_DISTANCE_DELTA_DIVISOR = 85.0f;
-
-inline float GetDistance(const Integration::Point& point1, const Integration::Point& point2)
-{
- Vector2 vector(point1.GetScreenPosition() - point2.GetScreenPosition());
- return vector.Length();
-}
-
-inline Vector2 GetCenterPoint(const Integration::Point& point1, const Integration::Point& point2)
-{
- return Vector2(point1.GetScreenPosition() + point2.GetScreenPosition()) * 0.5f;
-}
-
-} // unnamed namespace
-
-PinchGestureRecognizer::PinchGestureRecognizer( Observer& observer, Vector2 screenSize, float minimumPinchDistance )
-: GestureRecognizer( screenSize, Gesture::Pinch ),
- mObserver( observer ),
- mState( Clear ),
- mTouchEvents(),
- mStartingDistance( 0.0f )
-{
- SetMinimumPinchDistance( minimumPinchDistance );
-}
-
-PinchGestureRecognizer::~PinchGestureRecognizer()
-{
-}
-
-void PinchGestureRecognizer::SetMinimumPinchDistance(float value)
-{
- mMinimumDistanceDelta = value >= 0.0f ? value : (mScreenSize.height / MINIMUM_DISTANCE_DELTA_DIVISOR);
-}
-
-void PinchGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
-{
- int pointCount = event.GetPointCount();
-
- switch (mState)
- {
- case Clear:
- {
- if (pointCount == 2)
- {
- // Change state to possible as we have two touch points.
- mState = Possible;
- mTouchEvents.push_back(event);
- }
- break;
- }
-
- case Possible:
- {
- if (pointCount != 2)
- {
- // We no longer have two touch points so change state back to Clear.
- mState = Clear;
- mTouchEvents.clear();
- }
- else
- {
- const Integration::Point& currentPoint1 = event.points[0];
- const Integration::Point& currentPoint2 = event.points[1];
-
- if (currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP)
- {
- // One of our touch points has an Up event so change our state back to Clear.
- mState = Clear;
- mTouchEvents.clear();
- }
- else
- {
- mTouchEvents.push_back(event);
-
- // We can only determine a pinch after a certain number of touch points have been collected.
- if (mTouchEvents.size() >= MINIMUM_TOUCH_EVENTS_REQUIRED)
- {
- const Integration::Point& firstPoint1 = mTouchEvents[0].points[0];
- const Integration::Point& firstPoint2 = mTouchEvents[0].points[1];
-
- float firstDistance = GetDistance(firstPoint1, firstPoint2);
- float currentDistance = GetDistance(currentPoint1, currentPoint2);
- float distanceChanged = firstDistance - currentDistance;
-
- // Check if distance has changed enough
- if (fabsf(distanceChanged) > mMinimumDistanceDelta)
- {
- // Remove the first few events from the vector otherwise values are exaggerated
- mTouchEvents.erase(mTouchEvents.begin(), mTouchEvents.end() - MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START);
-
- if ( !mTouchEvents.empty() )
- {
- mStartingDistance = GetDistance(mTouchEvents.begin()->points[0], mTouchEvents.begin()->points[1]);
-
- // Send pinch started
- SendPinch(Gesture::Started, event);
-
- mState = Started;
- }
-
- mTouchEvents.clear();
- }
-
- if (mState == Possible)
- {
- // No pinch, so restart detection
- mState = Clear;
- mTouchEvents.clear();
- }
- }
- }
- }
- break;
- }
-
- case Started:
- {
- if (pointCount != 2)
- {
- // Send pinch finished event
- SendPinch(Gesture::Finished, event);
-
- mState = Clear;
- mTouchEvents.clear();
- }
- else
- {
- const Integration::Point& currentPoint1 = event.points[0];
- const Integration::Point& currentPoint2 = event.points[1];
-
- if (currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP)
- {
- mTouchEvents.push_back(event);
- // Send pinch finished event
- SendPinch(Gesture::Finished, event);
-
- mState = Clear;
- mTouchEvents.clear();
- }
- else
- {
- mTouchEvents.push_back(event);
-
- if (mTouchEvents.size() >= MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START)
- {
- // Send pinch continuing
- SendPinch(Gesture::Continuing, event);
-
- mTouchEvents.clear();
- }
- }
- }
- break;
- }
- }
-}
-
-void PinchGestureRecognizer::Update(const GestureRequest& request)
-{
- // Nothing to do.
-}
-
-void PinchGestureRecognizer::SendPinch(Gesture::State state, const Integration::TouchEvent& currentEvent)
-{
- PinchGestureEvent gesture(state);
-
- if ( !mTouchEvents.empty() )
- {
- const Integration::TouchEvent& firstEvent = mTouchEvents[0];
-
- // Assert if we have been holding TouchEvents that do not have 2 points
- DALI_ASSERT_DEBUG( firstEvent.GetPointCount() == 2 );
-
- // We should use the current event in our calculations unless it does not have two points.
- // If it does not have two points, then we should use the last point in mTouchEvents.
- Integration::TouchEvent event( currentEvent );
- if ( event.GetPointCount() != 2 )
- {
- event = *mTouchEvents.rbegin();
- }
-
- const Integration::Point& firstPoint1( firstEvent.points[0] );
- const Integration::Point& firstPoint2( firstEvent.points[1] );
- const Integration::Point& currentPoint1( event.points[0] );
- const Integration::Point& currentPoint2( event.points[1] );
-
- float firstDistance = GetDistance(firstPoint1, firstPoint2);
- float currentDistance = GetDistance(currentPoint1, currentPoint2);
- gesture.scale = currentDistance / mStartingDistance;
-
- float distanceDelta = fabsf(firstDistance - currentDistance);
- float timeDelta = static_cast<float> ( currentEvent.time - firstEvent.time );
- gesture.speed = ( distanceDelta / timeDelta ) * 1000.0f;
-
- gesture.centerPoint = GetCenterPoint(currentPoint1, currentPoint2);
- }
- else
- {
- // Something has gone wrong, just cancel the gesture.
- gesture.state = Gesture::Cancelled;
- }
-
- gesture.time = currentEvent.time;
-
- if( mScene )
- {
- // Create another handle so the recognizer cannot be destroyed during process function
- GestureRecognizerPtr recognizerHandle = this;
-
- mObserver.Process(*mScene, gesture);
- }
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_EVENT_PINCH_GESTURE_RECOGNIZER_H
-#define DALI_INTERNAL_EVENT_PINCH_GESTURE_RECOGNIZER_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/vector-wrapper.h>
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/gesture-recognizer.h>
-#include <dali/internal/event/events/pinch-gesture-event.h>
-
-namespace Dali
-{
-
-namespace Integration
-{
-struct TouchEvent;
-}
-
-namespace Internal
-{
-
-/**
- * When given a set of touch events, this detector attempts to determine if a pinch gesture has taken place.
- */
-class PinchGestureRecognizer : public GestureRecognizer
-{
-public:
-
- using Observer = RecognizerObserver<PinchGestureEvent>;
-
- /**
- * Constructor
- * @param[in] screenSize The size of the screen.
- * @param[in] minimumPinchDistance in pixels
- */
- PinchGestureRecognizer(Observer& observer, Vector2 screenSize, float minimumPinchDistance);
-
- /**
- * Virtual destructor.
- */
- virtual ~PinchGestureRecognizer();
-
-public:
-
- void SetMinimumPinchDistance(float value);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
- */
- virtual void SendEvent(const Integration::TouchEvent& event);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
- */
- virtual void Update(const GestureRequest& request);
-
-private:
-
- /**
- * Emits the pinch gesture event to the core.
- * @param[in] state The state of the pinch (whether it's starting, continuing or finished).
- * @param[in] currentEvent The latest touch event.
- */
- void SendPinch(Gesture::State state, const Integration::TouchEvent& currentEvent);
-
-private:
-
- // Reference to the gesture processor for this recognizer
- Observer& mObserver;
-
- /**
- * Internal state machine.
- */
- enum State
- {
- Clear, ///< No gesture detected.
- Possible, ///< The current touch event data suggests that a gesture is possible.
- Started, ///< A gesture has been detected.
- };
-
- State mState; ///< The current state of the detector.
- std::vector<Integration::TouchEvent> mTouchEvents; ///< The touch events since initial touch down.
-
- float mMinimumDistanceDelta; ///< The minimum distance before a pinch is applicable.
-
- float mStartingDistance; ///< The distance between the two touch points when the pinch is first detected.
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_EVENT_PINCH_GESTURE_RECOGNIZER_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/pinch-gesture.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/internal/event/events/gesture-event-processor.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// Signals
+
+const char* const SIGNAL_PINCH_DETECTED = "pinchDetected";
+
+BaseHandle Create()
+{
+ return Dali::PinchGestureDetector::New();
+}
+
+TypeRegistration mType( typeid(Dali::PinchGestureDetector), typeid(Dali::GestureDetector), Create );
+
+SignalConnectorType signalConnector1( mType, SIGNAL_PINCH_DETECTED, &PinchGestureDetector::DoConnectSignal );
+
+}
+
+
+PinchGestureDetectorPtr PinchGestureDetector::New()
+{
+ return new PinchGestureDetector;
+}
+
+PinchGestureDetector::PinchGestureDetector()
+: GestureDetector(Gesture::Pinch)
+{
+}
+
+PinchGestureDetector::~PinchGestureDetector()
+{
+}
+
+void PinchGestureDetector::EmitPinchGestureSignal(Dali::Actor actor, const PinchGesture& pinch)
+{
+ // Guard against destruction during signal emission
+ Dali::PinchGestureDetector handle( this );
+
+ mDetectedSignal.Emit( actor, pinch );
+}
+
+bool PinchGestureDetector::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+ bool connected( true );
+ PinchGestureDetector* gesture = static_cast< PinchGestureDetector* >(object); // TypeRegistry guarantees that this is the correct type.
+
+ if ( 0 == strcmp( signalName.c_str(), SIGNAL_PINCH_DETECTED ) )
+ {
+ gesture->DetectedSignal().Connect( tracker, functor );
+ }
+ else
+ {
+ // signalName does not match any signal
+ connected = false;
+ }
+
+ return connected;
+}
+
+void PinchGestureDetector::OnActorAttach(Actor& actor)
+{
+ // Do nothing
+}
+
+void PinchGestureDetector::OnActorDetach(Actor& actor)
+{
+ // Do nothing
+}
+
+void PinchGestureDetector::OnActorDestroyed(Object& object)
+{
+ // Do nothing
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_PINCH_GESTURE_DETECTOR_H
+#define DALI_INTERNAL_PINCH_GESTURE_DETECTOR_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/pinch-gesture-detector.h>
+#include <dali/internal/event/events/gesture-detector-impl.h>
+
+namespace Dali
+{
+
+struct PinchGesture;
+
+namespace Internal
+{
+
+class PinchGestureDetector;
+
+typedef IntrusivePtr<PinchGestureDetector> PinchGestureDetectorPtr;
+typedef DerivedGestureDetectorContainer<PinchGestureDetector>::type PinchGestureDetectorContainer;
+
+/**
+ * @copydoc Dali::PinchGestureDetector
+ */
+class PinchGestureDetector : public GestureDetector
+{
+public: // Creation
+
+ /**
+ * Create a new gesture detector.
+ * @return A smart-pointer to the newly allocated detector.
+ */
+ static PinchGestureDetectorPtr New();
+
+ /**
+ * Construct a new GestureDetector.
+ */
+ PinchGestureDetector();
+
+public:
+
+ /**
+ * Called by the PinchGestureProcessor when a pinch gesture event occurs within the bounds of our
+ * attached actor.
+ * @param[in] actor The pinched actor.
+ * @param[in] pinch The pinch gesture.
+ */
+ void EmitPinchGestureSignal(Dali::Actor actor, const PinchGesture& pinch);
+
+public: // Signals
+
+ /**
+ * @copydoc Dali::PinchGestureDetector::DetectedSignal()
+ */
+ Dali::PinchGestureDetector::DetectedSignalType& DetectedSignal()
+ {
+ return mDetectedSignal;
+ }
+
+ /**
+ * Connects a callback function with the object's signals.
+ * @param[in] object The object providing the signal.
+ * @param[in] tracker Used to disconnect the signal.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
+ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+protected:
+
+ /**
+ * A reference counted object may only be deleted by calling Unreference()
+ */
+ virtual ~PinchGestureDetector();
+
+private:
+
+ // Undefined
+ PinchGestureDetector(const PinchGestureDetector&);
+ PinchGestureDetector& operator=(const PinchGestureDetector& rhs);
+
+private: // GestureDetector overrides
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&)
+ */
+ virtual void OnActorAttach(Actor& actor);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDetach(Actor&)
+ */
+ virtual void OnActorDetach(Actor& actor);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDestroyed(Object&)
+ */
+ virtual void OnActorDestroyed(Object& object);
+
+private:
+
+ Dali::PinchGestureDetector::DetectedSignalType mDetectedSignal;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::PinchGestureDetector& GetImplementation(Dali::PinchGestureDetector& detector)
+{
+ DALI_ASSERT_ALWAYS( detector && "PinchGestureDetector handle is empty" );
+
+ BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<Internal::PinchGestureDetector&>(handle);
+}
+
+inline const Internal::PinchGestureDetector& GetImplementation(const Dali::PinchGestureDetector& detector)
+{
+ DALI_ASSERT_ALWAYS( detector && "PinchGestureDetector handle is empty" );
+
+ const BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<const Internal::PinchGestureDetector&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_PINCH_GESTURE_DETECTOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-event.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+PinchGestureEvent::PinchGestureEvent(Gesture::State state)
+: GestureEvent(Gesture::Pinch, state),
+ scale(0.0f),
+ speed(0.0f),
+ centerPoint()
+{
+}
+
+PinchGestureEvent::~PinchGestureEvent()
+{
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_PINCH_GESTURE_EVENT_H
+#define DALI_INTERNAL_EVENT_PINCH_GESTURE_EVENT_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/gesture-event.h>
+#include <dali/public-api/math/vector2.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+/**
+ * If the adaptor detects a pinch gesture, then it should create an instance of this structure and
+ * send it to the Core.
+ *
+ * A Pinch Gesture event should be in one of four states:
+ * - Started: If a pinch is detected.
+ * - Continuing: If after a pinch is detected, it continues.
+ * - Finished: If after a pinch, the user lifts their finger(s).
+ * - Cancelled: If there is a system interruption.
+ */
+struct PinchGestureEvent : public GestureEvent
+{
+ // Construction & Destruction
+
+ /**
+ * Default Constructor
+ * @param[in] state The state of the gesture
+ */
+ PinchGestureEvent(Gesture::State state);
+
+ /**
+ * Virtual destructor
+ */
+ virtual ~PinchGestureEvent();
+
+ // Data
+
+ /**
+ * @copydoc Dali::PinchGesture::scale
+ */
+ float scale;
+
+ /**
+ * @copydoc Dali::PinchGesture::speed
+ */
+ float speed;
+
+ /**
+ * The center point between the two touch points of the last touch event in the series of touch motion
+ * event producing this gesture.
+ */
+ Vector2 centerPoint;
+};
+
+} // namespace Integration
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_PINCH_GESTURE_EVENT_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-processor.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/events/pinch-gesture.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-event.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/event/common/scene-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.h>
+#include <dali/internal/event/events/gesture-requests.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+/**
+ * Creates a PinchGesture and asks the specified detector to emit its detected signal.
+ * @param[in] actor The actor that has been pinched.
+ * @param[in] gestureDetectors The gesture detector container that should emit the signal.
+ * @param[in] pinchEvent The pinchEvent received from the adaptor.
+ * @param[in] localCenter Relative to the actor attached to the detector.
+ */
+void EmitPinchSignal(
+ Actor* actor,
+ const GestureDetectorContainer& gestureDetectors,
+ const PinchGestureEvent& pinchEvent,
+ Vector2 localCenter)
+{
+ PinchGesture pinch(pinchEvent.state);
+ pinch.time = pinchEvent.time;
+
+ pinch.scale = pinchEvent.scale;
+ pinch.speed = pinchEvent.speed;
+ pinch.screenCenterPoint = pinchEvent.centerPoint;
+
+ pinch.localCenterPoint = localCenter;
+
+ Dali::Actor actorHandle( actor );
+ const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
+ for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
+ {
+ static_cast< PinchGestureDetector* >( *iter )->EmitPinchGestureSignal( actorHandle, pinch );
+ }
+}
+
+/**
+ * Functor which checks whether the specified actor is attached to the gesture detector.
+ * It returns true if it is no longer attached. This can be used in remove_if functions.
+ */
+struct IsNotAttachedFunctor
+{
+ /**
+ * Constructor
+ * @param[in] actor The actor to check whether it is attached.
+ */
+ IsNotAttachedFunctor(Actor* actor)
+ : actorToCheck(actor)
+ {
+ }
+
+ /**
+ * Returns true if not attached, false if it is still attached.
+ * @param[in] detector The detector to check.
+ * @return true, if not attached, false otherwise.
+ */
+ bool operator()(const GestureDetector* detector) const
+ {
+ return !detector->IsAttached(*actorToCheck);
+ }
+
+ Actor* actorToCheck; ///< The actor to check whether it is attached or not.
+};
+
+} // unnamed namespace
+
+PinchGestureProcessor::PinchGestureProcessor()
+: GestureProcessor( Gesture::Pinch ),
+ mPinchGestureDetectors(),
+ mCurrentPinchEmitters(),
+ mCurrentPinchEvent(NULL),
+ mMinimumPinchDistance(-1.0f)
+{
+}
+
+PinchGestureProcessor::~PinchGestureProcessor()
+{
+}
+
+void PinchGestureProcessor::SetMinimumPinchDistance( float value )
+{
+ mMinimumPinchDistance = value;
+
+ if( mGestureRecognizer )
+ {
+ PinchGestureRecognizer* pinchRecognizer = dynamic_cast<PinchGestureRecognizer*>(mGestureRecognizer.Get());
+ if( pinchRecognizer )
+ {
+ pinchRecognizer->SetMinimumPinchDistance(value);
+ }
+ }
+}
+
+void PinchGestureProcessor::Process( Scene& scene, const PinchGestureEvent& pinchEvent )
+{
+ switch ( pinchEvent.state )
+ {
+ case Gesture::Started:
+ {
+ // The pinch gesture should only be sent to the gesture detector which first received it so that
+ // it can be told when the gesture ends as well.
+
+ mCurrentPinchEmitters.clear();
+ ResetActor();
+
+ HitTestAlgorithm::Results hitTestResults;
+ if( HitTest( scene, pinchEvent.centerPoint, hitTestResults ) )
+ {
+ // Record the current render-task for Screen->Actor coordinate conversions
+ mCurrentRenderTask = hitTestResults.renderTask;
+
+ // Set mCurrentPinchEvent to use inside overridden methods called from ProcessAndEmit()
+ mCurrentPinchEvent = &pinchEvent;
+ ProcessAndEmit( hitTestResults );
+ mCurrentPinchEvent = NULL;
+ }
+ break;
+ }
+
+ case Gesture::Continuing:
+ case Gesture::Finished:
+ case Gesture::Cancelled:
+ {
+ // Only send subsequent pinch gesture signals if we processed the pinch gesture when it started.
+ // Check if actor is still touchable.
+
+ Actor* currentGesturedActor = GetCurrentGesturedActor();
+ if ( currentGesturedActor )
+ {
+ if ( currentGesturedActor->IsHittable() && !mCurrentPinchEmitters.empty() && mCurrentRenderTask )
+ {
+ // Ensure actor is still attached to the emitters, if it is not then remove the emitter.
+ GestureDetectorContainer::iterator endIter = std::remove_if( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), IsNotAttachedFunctor(currentGesturedActor) );
+ mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
+
+ if ( !mCurrentPinchEmitters.empty() )
+ {
+ Vector2 actorCoords;
+ RenderTask& renderTaskImpl( *mCurrentRenderTask.Get() );
+ currentGesturedActor->ScreenToLocal( renderTaskImpl, actorCoords.x, actorCoords.y, pinchEvent.centerPoint.x, pinchEvent.centerPoint.y );
+
+ EmitPinchSignal( currentGesturedActor, mCurrentPinchEmitters, pinchEvent, actorCoords );
+ }
+ else
+ {
+ // If we have no current emitters then clear pinched actor as well.
+ ResetActor();
+ }
+
+ // Clear current emitters if pinch gesture has ended or been cancelled.
+ if ( pinchEvent.state == Gesture::Finished || pinchEvent.state == Gesture::Cancelled )
+ {
+ mCurrentPinchEmitters.clear();
+ ResetActor();
+ }
+ }
+ else
+ {
+ mCurrentPinchEmitters.clear();
+ ResetActor();
+ }
+ }
+ break;
+ }
+
+ case Gesture::Clear:
+ {
+ DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
+ break;
+ }
+ case Gesture::Possible:
+ {
+ DALI_ABORT( "Incorrect state received from Integration layer: Possible\n" );
+ break;
+ }
+ }
+}
+
+void PinchGestureProcessor::AddGestureDetector( PinchGestureDetector* gestureDetector, Scene& scene )
+{
+ bool createRecognizer(mPinchGestureDetectors.empty());
+
+ mPinchGestureDetectors.push_back(gestureDetector);
+
+ if (createRecognizer)
+ {
+ Size size = scene.GetSize();
+ mGestureRecognizer = new PinchGestureRecognizer( *this, Vector2(size.width, size.height), mMinimumPinchDistance);
+ }
+}
+
+void PinchGestureProcessor::RemoveGestureDetector( PinchGestureDetector* gestureDetector )
+{
+ if ( !mCurrentPinchEmitters.empty() )
+ {
+ // Check if the removed detector was one that is currently being pinched and remove it from emitters.
+ GestureDetectorContainer::iterator endIter = std::remove( mCurrentPinchEmitters.begin(), mCurrentPinchEmitters.end(), gestureDetector );
+ mCurrentPinchEmitters.erase( endIter, mCurrentPinchEmitters.end() );
+
+ // If we no longer have any emitters, then we should clear mCurrentGesturedActor as well
+ if ( mCurrentPinchEmitters.empty() )
+ {
+ ResetActor();
+ }
+ }
+
+ // Find the detector...
+ PinchGestureDetectorContainer::iterator endIter = std::remove( mPinchGestureDetectors.begin(), mPinchGestureDetectors.end(), gestureDetector );
+ DALI_ASSERT_DEBUG( endIter != mPinchGestureDetectors.end() );
+
+ // ...and remove it
+ mPinchGestureDetectors.erase(endIter, mPinchGestureDetectors.end());
+
+ if (mPinchGestureDetectors.empty())
+ {
+ mGestureRecognizer.Detach();
+ }
+}
+
+void PinchGestureProcessor::GestureDetectorUpdated( PinchGestureDetector* gestureDetector )
+{
+ // Nothing to do as PinchGestureDetector does not have any specific parameters.
+}
+
+void PinchGestureProcessor::OnGesturedActorStageDisconnection()
+{
+ mCurrentPinchEmitters.clear();
+}
+
+bool PinchGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
+{
+ // No special case required for pinch.
+ return true;
+}
+
+void PinchGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
+{
+ DALI_ASSERT_DEBUG( mCurrentPinchEvent );
+
+ EmitPinchSignal( actor, gestureDetectors, *mCurrentPinchEvent, actorCoordinates );
+
+ if ( actor->OnStage() )
+ {
+ mCurrentPinchEmitters = gestureDetectors;
+ SetActor( actor );
+ }
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_PINCH_GESTURE_EVENT_PROCESSOR_H
+#define DALI_INTERNAL_PINCH_GESTURE_EVENT_PROCESSOR_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.h>
+#include <dali/internal/event/events/gesture-processor.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+class Scene;
+class Stage;
+
+struct PinchGestureEvent;
+
+/**
+ * Pinch Gesture Event Processing:
+ *
+ * When we receive a pinch gesture event, we do the following:
+ * - Find the hit actor that requires a pinch underneath the center-point of the pinch.
+ * - Emit the gesture if the event satisfies the detector conditions.
+ *
+ * The above is only checked when our gesture starts. We continue sending the pinch gesture to this
+ * detector until the pinch ends or is cancelled.
+ */
+class PinchGestureProcessor : public GestureProcessor, public RecognizerObserver<PinchGestureEvent>
+{
+public:
+
+ /**
+ * Create a pinch gesture processor.
+ */
+ PinchGestureProcessor();
+
+ /**
+ * Non-virtual destructor; PinchGestureProcessor is not a base class
+ */
+ ~PinchGestureProcessor();
+
+public: // To be called by GestureEventProcessor
+
+ /**
+ * This method sets the minimum distance to start a pinch
+ * @param[in] value The distance in pixels
+ */
+ void SetMinimumPinchDistance( float value );
+
+ /**
+ * This method is called whenever a pinch gesture event occurs.
+ * @param[in] scene The scene the pinch gesture event occurs in.
+ * @param[in] pinchEvent The event that has occurred.
+ */
+ void Process( Scene& scene, const PinchGestureEvent& pinchEvent );
+
+ /**
+ * Adds a gesture detector to this gesture processor.
+ * If this is the first gesture detector being added, then this method registers the required
+ * gesture with the adaptor.
+ * @param[in] gestureDetector The gesture detector being added.
+ */
+ void AddGestureDetector(PinchGestureDetector* gestureDetector, Scene& scene);
+
+ /**
+ * Removes the specified gesture detector from this gesture processor. If, after removing this
+ * gesture detector, there are no more gesture detectors registered, then this method unregisters
+ * the gesture from the adaptor.
+ * @param[in] gestureDetector The gesture detector being removed.
+ */
+ void RemoveGestureDetector(PinchGestureDetector* gestureDetector);
+
+ /**
+ * This method updates the gesture detection parameters.
+ * @param[in] gestureDetector The gesture detector that has been updated.
+ */
+ void GestureDetectorUpdated(PinchGestureDetector* gestureDetector);
+
+private:
+
+ // Undefined
+ PinchGestureProcessor(const PinchGestureProcessor&);
+ PinchGestureProcessor& operator=(const PinchGestureProcessor& rhs);
+
+private:
+
+ // GestureProcessor overrides
+
+ /**
+ * @copydoc GestureProcessor::OnGesturedActorStageDisconnection()
+ */
+ void OnGesturedActorStageDisconnection();
+
+ /**
+ * @copydoc GestureProcessor::CheckGestureDetector()
+ */
+ bool CheckGestureDetector( GestureDetector* detector, Actor* actor );
+
+ /**
+ * @copydoc GestureProcessor::EmitGestureSignal()
+ */
+ void EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates );
+
+private:
+
+ PinchGestureDetectorContainer mPinchGestureDetectors;
+ GestureDetectorContainer mCurrentPinchEmitters;
+ RenderTaskPtr mCurrentRenderTask;
+
+ const PinchGestureEvent* mCurrentPinchEvent; ///< Pointer to current PinchEvent, used when calling ProcessAndEmit()
+
+ float mMinimumPinchDistance;
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_PINCH_GESTURE_EVENT_PROCESSOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/math/vector2.h>
+
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-event.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/internal/event/common/scene-impl.h>
+
+// INTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+const unsigned int MINIMUM_TOUCH_EVENTS_REQUIRED = 4;
+const unsigned int MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START = 4;
+
+const float MINIMUM_DISTANCE_DELTA_DIVISOR = 85.0f;
+
+inline float GetDistance(const Integration::Point& point1, const Integration::Point& point2)
+{
+ Vector2 vector(point1.GetScreenPosition() - point2.GetScreenPosition());
+ return vector.Length();
+}
+
+inline Vector2 GetCenterPoint(const Integration::Point& point1, const Integration::Point& point2)
+{
+ return Vector2(point1.GetScreenPosition() + point2.GetScreenPosition()) * 0.5f;
+}
+
+} // unnamed namespace
+
+PinchGestureRecognizer::PinchGestureRecognizer( Observer& observer, Vector2 screenSize, float minimumPinchDistance )
+: GestureRecognizer( screenSize, Gesture::Pinch ),
+ mObserver( observer ),
+ mState( Clear ),
+ mTouchEvents(),
+ mStartingDistance( 0.0f )
+{
+ SetMinimumPinchDistance( minimumPinchDistance );
+}
+
+PinchGestureRecognizer::~PinchGestureRecognizer()
+{
+}
+
+void PinchGestureRecognizer::SetMinimumPinchDistance(float value)
+{
+ mMinimumDistanceDelta = value >= 0.0f ? value : (mScreenSize.height / MINIMUM_DISTANCE_DELTA_DIVISOR);
+}
+
+void PinchGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
+{
+ int pointCount = event.GetPointCount();
+
+ switch (mState)
+ {
+ case Clear:
+ {
+ if (pointCount == 2)
+ {
+ // Change state to possible as we have two touch points.
+ mState = Possible;
+ mTouchEvents.push_back(event);
+ }
+ break;
+ }
+
+ case Possible:
+ {
+ if (pointCount != 2)
+ {
+ // We no longer have two touch points so change state back to Clear.
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ const Integration::Point& currentPoint1 = event.points[0];
+ const Integration::Point& currentPoint2 = event.points[1];
+
+ if (currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP)
+ {
+ // One of our touch points has an Up event so change our state back to Clear.
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ mTouchEvents.push_back(event);
+
+ // We can only determine a pinch after a certain number of touch points have been collected.
+ if (mTouchEvents.size() >= MINIMUM_TOUCH_EVENTS_REQUIRED)
+ {
+ const Integration::Point& firstPoint1 = mTouchEvents[0].points[0];
+ const Integration::Point& firstPoint2 = mTouchEvents[0].points[1];
+
+ float firstDistance = GetDistance(firstPoint1, firstPoint2);
+ float currentDistance = GetDistance(currentPoint1, currentPoint2);
+ float distanceChanged = firstDistance - currentDistance;
+
+ // Check if distance has changed enough
+ if (fabsf(distanceChanged) > mMinimumDistanceDelta)
+ {
+ // Remove the first few events from the vector otherwise values are exaggerated
+ mTouchEvents.erase(mTouchEvents.begin(), mTouchEvents.end() - MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START);
+
+ if ( !mTouchEvents.empty() )
+ {
+ mStartingDistance = GetDistance(mTouchEvents.begin()->points[0], mTouchEvents.begin()->points[1]);
+
+ // Send pinch started
+ SendPinch(Gesture::Started, event);
+
+ mState = Started;
+ }
+
+ mTouchEvents.clear();
+ }
+
+ if (mState == Possible)
+ {
+ // No pinch, so restart detection
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ case Started:
+ {
+ if (pointCount != 2)
+ {
+ // Send pinch finished event
+ SendPinch(Gesture::Finished, event);
+
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ const Integration::Point& currentPoint1 = event.points[0];
+ const Integration::Point& currentPoint2 = event.points[1];
+
+ if (currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP)
+ {
+ mTouchEvents.push_back(event);
+ // Send pinch finished event
+ SendPinch(Gesture::Finished, event);
+
+ mState = Clear;
+ mTouchEvents.clear();
+ }
+ else
+ {
+ mTouchEvents.push_back(event);
+
+ if (mTouchEvents.size() >= MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START)
+ {
+ // Send pinch continuing
+ SendPinch(Gesture::Continuing, event);
+
+ mTouchEvents.clear();
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+void PinchGestureRecognizer::Update(const GestureRequest& request)
+{
+ // Nothing to do.
+}
+
+void PinchGestureRecognizer::SendPinch(Gesture::State state, const Integration::TouchEvent& currentEvent)
+{
+ PinchGestureEvent gesture(state);
+
+ if ( !mTouchEvents.empty() )
+ {
+ const Integration::TouchEvent& firstEvent = mTouchEvents[0];
+
+ // Assert if we have been holding TouchEvents that do not have 2 points
+ DALI_ASSERT_DEBUG( firstEvent.GetPointCount() == 2 );
+
+ // We should use the current event in our calculations unless it does not have two points.
+ // If it does not have two points, then we should use the last point in mTouchEvents.
+ Integration::TouchEvent event( currentEvent );
+ if ( event.GetPointCount() != 2 )
+ {
+ event = *mTouchEvents.rbegin();
+ }
+
+ const Integration::Point& firstPoint1( firstEvent.points[0] );
+ const Integration::Point& firstPoint2( firstEvent.points[1] );
+ const Integration::Point& currentPoint1( event.points[0] );
+ const Integration::Point& currentPoint2( event.points[1] );
+
+ float firstDistance = GetDistance(firstPoint1, firstPoint2);
+ float currentDistance = GetDistance(currentPoint1, currentPoint2);
+ gesture.scale = currentDistance / mStartingDistance;
+
+ float distanceDelta = fabsf(firstDistance - currentDistance);
+ float timeDelta = static_cast<float> ( currentEvent.time - firstEvent.time );
+ gesture.speed = ( distanceDelta / timeDelta ) * 1000.0f;
+
+ gesture.centerPoint = GetCenterPoint(currentPoint1, currentPoint2);
+ }
+ else
+ {
+ // Something has gone wrong, just cancel the gesture.
+ gesture.state = Gesture::Cancelled;
+ }
+
+ gesture.time = currentEvent.time;
+
+ if( mScene )
+ {
+ // Create another handle so the recognizer cannot be destroyed during process function
+ GestureRecognizerPtr recognizerHandle = this;
+
+ mObserver.Process(*mScene, gesture);
+ }
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_PINCH_GESTURE_RECOGNIZER_H
+#define DALI_INTERNAL_EVENT_PINCH_GESTURE_RECOGNIZER_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/gesture-recognizer.h>
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+}
+
+namespace Internal
+{
+
+/**
+ * When given a set of touch events, this detector attempts to determine if a pinch gesture has taken place.
+ */
+class PinchGestureRecognizer : public GestureRecognizer
+{
+public:
+
+ using Observer = RecognizerObserver<PinchGestureEvent>;
+
+ /**
+ * Constructor
+ * @param[in] screenSize The size of the screen.
+ * @param[in] minimumPinchDistance in pixels
+ */
+ PinchGestureRecognizer(Observer& observer, Vector2 screenSize, float minimumPinchDistance);
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~PinchGestureRecognizer();
+
+public:
+
+ void SetMinimumPinchDistance(float value);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
+ */
+ virtual void SendEvent(const Integration::TouchEvent& event);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
+ */
+ virtual void Update(const GestureRequest& request);
+
+private:
+
+ /**
+ * Emits the pinch gesture event to the core.
+ * @param[in] state The state of the pinch (whether it's starting, continuing or finished).
+ * @param[in] currentEvent The latest touch event.
+ */
+ void SendPinch(Gesture::State state, const Integration::TouchEvent& currentEvent);
+
+private:
+
+ // Reference to the gesture processor for this recognizer
+ Observer& mObserver;
+
+ /**
+ * Internal state machine.
+ */
+ enum State
+ {
+ Clear, ///< No gesture detected.
+ Possible, ///< The current touch event data suggests that a gesture is possible.
+ Started, ///< A gesture has been detected.
+ };
+
+ State mState; ///< The current state of the detector.
+ std::vector<Integration::TouchEvent> mTouchEvents; ///< The touch events since initial touch down.
+
+ float mMinimumDistanceDelta; ///< The minimum distance before a pinch is applicable.
+
+ float mStartingDistance; ///< The distance between the two touch points when the pinch is first detected.
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_PINCH_GESTURE_RECOGNIZER_H
+++ /dev/null
-/*
- * Copyright (c) 2016 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/tap-gesture-detector-impl.h>
-
-// EXTERNAL INCLUDES
-#include <cstring> // for strcmp
-
-// INTERNAL INCLUDES
-#include <dali/public-api/events/tap-gesture.h>
-#include <dali/public-api/object/type-registry.h>
-#include <dali/integration-api/debug.h>
-#include <dali/internal/event/events/gesture-event-processor.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-
-const unsigned int DEFAULT_TAPS_REQUIRED = 1u;
-const unsigned int DEFAULT_TOUCHES_REQUIRED = 1u;
-
-// Signals
-const char* const SIGNAL_TAP_DETECTED = "tapDetected";
-
-BaseHandle Create()
-{
- return Dali::TapGestureDetector::New();
-}
-
-TypeRegistration mType( typeid(Dali::TapGestureDetector), typeid(Dali::GestureDetector), Create );
-
-SignalConnectorType signalConnector1( mType, SIGNAL_TAP_DETECTED, &TapGestureDetector::DoConnectSignal );
-
-}
-
-TapGestureDetectorPtr TapGestureDetector::New()
-{
- return new TapGestureDetector;
-}
-
-TapGestureDetectorPtr TapGestureDetector::New( unsigned int tapsRequired )
-{
- return new TapGestureDetector( tapsRequired );
-}
-
-TapGestureDetector::TapGestureDetector()
-: GestureDetector( Gesture::Tap ),
- mMinimumTapsRequired( DEFAULT_TAPS_REQUIRED ),
- mMaximumTapsRequired( DEFAULT_TAPS_REQUIRED ),
- mTouchesRequired( DEFAULT_TOUCHES_REQUIRED )
-{
-}
-
-TapGestureDetector::TapGestureDetector( unsigned int tapsRequired )
-: GestureDetector( Gesture::Tap ),
- mMinimumTapsRequired( tapsRequired ),
- mMaximumTapsRequired( tapsRequired ),
- mTouchesRequired( DEFAULT_TOUCHES_REQUIRED )
-{
-}
-
-TapGestureDetector::~TapGestureDetector()
-{
-}
-
-void TapGestureDetector::SetMinimumTapsRequired(unsigned int taps)
-{
- if ( mMinimumTapsRequired != taps )
- {
- mMinimumTapsRequired = taps;
-
- if ( !mAttachedActors.empty() )
- {
- mGestureEventProcessor.GestureDetectorUpdated(this);
- }
- }
-}
-
-void TapGestureDetector::SetMaximumTapsRequired(unsigned int taps)
-{
- if ( mMaximumTapsRequired != taps )
- {
- mMaximumTapsRequired = taps;
-
- if ( !mAttachedActors.empty() )
- {
- mGestureEventProcessor.GestureDetectorUpdated(this);
- }
- }
-}
-
-void TapGestureDetector::SetTouchesRequired(unsigned int touches)
-{
- if (mTouchesRequired != touches)
- {
- mTouchesRequired = touches;
-
- if (!mAttachedActors.empty())
- {
- mGestureEventProcessor.GestureDetectorUpdated(this);
- }
- }
-}
-
-unsigned int TapGestureDetector::GetMinimumTapsRequired() const
-{
- return mMinimumTapsRequired;
-}
-
-unsigned int TapGestureDetector::GetMaximumTapsRequired() const
-{
- return mMaximumTapsRequired;
-}
-
-unsigned int TapGestureDetector::GetTouchesRequired() const
-{
- return mTouchesRequired;
-}
-
-void TapGestureDetector::EmitTapGestureSignal(Dali::Actor tappedActor, const TapGesture& tap)
-{
- // Guard against destruction during signal emission
- Dali::TapGestureDetector handle( this );
-
- mDetectedSignal.Emit( tappedActor, tap );
-}
-
-bool TapGestureDetector::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
-{
- bool connected( true );
- TapGestureDetector* gesture = static_cast< TapGestureDetector* >(object); // TypeRegistry guarantees that this is the correct type.
-
- if ( 0 == strcmp( signalName.c_str(), SIGNAL_TAP_DETECTED ) )
- {
- gesture->DetectedSignal().Connect( tracker, functor );
- }
- else
- {
- // signalName does not match any signal
- connected = false;
- }
-
- return connected;
-}
-
-void TapGestureDetector::OnActorAttach(Actor& actor)
-{
- // Do nothing
-}
-
-void TapGestureDetector::OnActorDetach(Actor& actor)
-{
- // Do nothing
-}
-
-void TapGestureDetector::OnActorDestroyed(Object& object)
-{
- // Do nothing
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_TAP_GESTURE_DETECTOR_H
-#define DALI_INTERNAL_TAP_GESTURE_DETECTOR_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/public-api/events/tap-gesture-detector.h>
-#include <dali/internal/event/events/gesture-detector-impl.h>
-
-namespace Dali
-{
-
-struct TapGesture;
-
-namespace Internal
-{
-
-class TapGestureDetector;
-
-typedef IntrusivePtr<TapGestureDetector> TapGestureDetectorPtr;
-typedef DerivedGestureDetectorContainer<TapGestureDetector>::type TapGestureDetectorContainer;
-
-/**
- * @copydoc Dali::TapGestureDetector
- */
-class TapGestureDetector : public GestureDetector
-{
-public: // Creation
-
- /**
- * Create a new gesture detector.
- * @return A smart-pointer to the newly allocated detector.
- */
- static TapGestureDetectorPtr New();
-
- /**
- * Create a new gesture detector with the specified parameters.
- * @param[in] tapsRequired The number of taps required.
- * @return A smart-pointer to the newly allocated detector.
- */
- static TapGestureDetectorPtr New( unsigned int tapsRequired );
-
- /**
- * Construct a new GestureDetector.
- */
- TapGestureDetector();
-
- /**
- * Construct a new GestureDetector with the specified parameters.
- * @param[in] tapsRequired The number of taps required.
- */
- TapGestureDetector( unsigned int tapsRequired );
-
-public:
-
- /**
- * @copydoc Dali::TapGestureDetector::SetTouchesRequired(unsigned int)
- */
- void SetTouchesRequired(unsigned int touches);
-
- /**
- * @copydoc Dali::TapGestureDetector::SetMinimumTapsRequired()
- */
- void SetMinimumTapsRequired( unsigned int minTaps );
-
- /**
- * @copydoc Dali::TapGestureDetector::SetMaximumTapsRequired()
- */
- void SetMaximumTapsRequired( unsigned int maxTaps );
-
- /**
- * @copydoc Dali::TapGestureDetector::GetMinimumTapsRequired()
- */
- unsigned int GetMinimumTapsRequired() const;
-
- /**
- * @copydoc Dali::TapGestureDetector::SetMaximumTapsRequired()
- */
- unsigned int GetMaximumTapsRequired() const;
-
- /**
- * @copydoc Dali::TapGestureDetector::GetTouchesRequired()
- */
- unsigned int GetTouchesRequired() const;
-
-public:
-
- /**
- * Called by the TapGestureProcessor when a tap gesture event occurs within the bounds of our
- * attached actor.
- * @param[in] tappedActor The tapped actor.
- * @param[in] tap The tap gesture.
- */
- void EmitTapGestureSignal(Dali::Actor tappedActor, const TapGesture& tap);
-
-public: // Signals
-
- /**
- * @copydoc Dali::TapGestureDetector::DetectedSignal()
- */
- Dali::TapGestureDetector::DetectedSignalType& DetectedSignal()
- {
- return mDetectedSignal;
- }
-
- /**
- * Connects a callback function with the object's signals.
- * @param[in] object The object providing the signal.
- * @param[in] tracker Used to disconnect the signal.
- * @param[in] signalName The signal to connect to.
- * @param[in] functor A newly allocated FunctorDelegate.
- * @return True if the signal was connected.
- * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
- */
- static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
-
-protected:
-
- /**
- * A reference counted object may only be deleted by calling Unreference()
- */
- virtual ~TapGestureDetector();
-
-private:
-
- // Undefined
- TapGestureDetector(const TapGestureDetector&);
- TapGestureDetector& operator=(const TapGestureDetector& rhs);
-
-private: // GestureDetector overrides
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&)
- */
- virtual void OnActorAttach(Actor& actor);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorDetach(Actor&)
- */
- virtual void OnActorDetach(Actor& actor);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::OnActorDestroyed(Object&)
- */
- virtual void OnActorDestroyed(Object& object);
-
-private:
-
- Dali::TapGestureDetector::DetectedSignalType mDetectedSignal;
-
- unsigned int mMinimumTapsRequired;
- unsigned int mMaximumTapsRequired;
- unsigned int mTouchesRequired;
-};
-
-} // namespace Internal
-
-// Helpers for public-api forwarding methods
-
-inline Internal::TapGestureDetector& GetImplementation(Dali::TapGestureDetector& detector)
-{
- DALI_ASSERT_ALWAYS( detector && "TapGestureDetector handle is empty" );
-
- BaseObject& handle = detector.GetBaseObject();
-
- return static_cast<Internal::TapGestureDetector&>(handle);
-}
-
-inline const Internal::TapGestureDetector& GetImplementation(const Dali::TapGestureDetector& detector)
-{
- DALI_ASSERT_ALWAYS( detector && "TapGestureDetector handle is empty" );
-
- const BaseObject& handle = detector.GetBaseObject();
-
- return static_cast<const Internal::TapGestureDetector&>(handle);
-}
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_TAP_GESTURE_DETECTOR_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/tap-gesture-event.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-TapGestureEvent::TapGestureEvent( Gesture::State state )
-: GestureEvent(Gesture::Tap, state),
- numberOfTaps(1),
- numberOfTouches(1)
-{
-}
-
-TapGestureEvent::~TapGestureEvent()
-{
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_EVENT_TAP_GESTURE_H
-#define DALI_INTERNAL_EVENT_TAP_GESTURE_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/public-api/math/vector2.h>
-#include <dali/internal/event/events/gesture-event.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-/**
- * If the adaptor detects a tap gesture, then it should create an instance of this structure and
- * send it to the Core.
- *
- * A Tap Gesture event should be in one of three states:
- * - Possible: When the user first puts their finger down - Core needs to hit test the down point so
- * that a tap (down and up quickly) is also on the same actor.
- * - Started: If a tap is detected (No Finished state is expected).
- * - Cancelled: If, after a down event, no tap is detected, or a system interruption.
- *
- * A Started state will be ignored if a Possible state does not precede it.
- */
-struct TapGestureEvent : public GestureEvent
-{
- // Construction & Destruction
-
- /**
- * Default Constructor
- * @param[in] state Possible, denotes down press;
- * Started, of a tap occurs; and
- * Cancelled, when tap does not occur.
- */
- TapGestureEvent( Gesture::State state );
-
- /**
- * Virtual destructor
- */
- virtual ~TapGestureEvent();
-
- // Data
-
- /**
- * @copydoc Dali::TapGesture::numberOfTaps
- */
- unsigned int numberOfTaps;
-
- /**
- * @copydoc Dali::TapGesture::numberOfTouches
- */
- unsigned int numberOfTouches;
-
- /**
- * This is the point, in screen coordinates, where the tap occurred.
- * If a multi-touch tap, then this should be the centroid of all the touch points.
- */
- Vector2 point;
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_EVENT_TAP_GESTURE_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/tap-gesture-processor.h>
-
-// EXTERNAL INCLUDES
-#include <algorithm>
-
-// INTERNAL INCLUDES
-#include <dali/public-api/actors/actor.h>
-#include <dali/public-api/common/dali-common.h>
-#include <dali/public-api/events/tap-gesture.h>
-#include <dali/public-api/math/vector2.h>
-#include <dali/integration-api/debug.h>
-#include <dali/internal/event/actors/actor-impl.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
-#include <dali/internal/event/common/scene-impl.h>
-#include <dali/internal/event/events/tap-gesture-recognizer.h>
-#include <dali/internal/event/events/gesture-requests.h>
-#include <dali/internal/event/events/tap-gesture-event.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-
-/**
- * Creates a TapGesture and asks the specified detector to emit its detected signal.
- * @param[in] actor The actor on which a tap has occurred.
- * @param[in] gestureDetectors A reference to gesture detectors that should emit the signal.
- * @param[in] tapEvent The tapEvent received from the adaptor.
- * @param[in] localPoint Relative to the actor attached to the detector.
- */
-void EmitTapSignal(
- Actor* actor,
- const GestureDetectorContainer& gestureDetectors,
- const TapGestureEvent& tapEvent,
- Vector2 localPoint)
-{
- TapGesture tap;
- tap.time = tapEvent.time;
- tap.numberOfTaps = tapEvent.numberOfTaps;
- tap.numberOfTouches = tapEvent.numberOfTouches;
- tap.screenPoint = tapEvent.point;
- tap.localPoint = localPoint;
-
- Dali::Actor actorHandle( actor );
- const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
- for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
- {
- static_cast< TapGestureDetector* >( *iter )->EmitTapGestureSignal( actorHandle, tap );
- }
-}
-
-} // unnamed namespace
-
-TapGestureProcessor::TapGestureProcessor()
-: GestureProcessor( Gesture::Tap ),
- mTapGestureDetectors(),
- mMinTapsRequired( 1 ),
- mMaxTapsRequired( 1 ),
- mMinTouchesRequired( 1 ),
- mMaxTouchesRequired( 1 ),
- mCurrentTapEvent( NULL ),
- mPossibleProcessed( false )
-{
-}
-
-TapGestureProcessor::~TapGestureProcessor()
-{
-}
-
-void TapGestureProcessor::Process( Scene& scene, const TapGestureEvent& tapEvent )
-{
- switch ( tapEvent.state )
- {
- case Gesture::Possible:
- {
- // Do a hit test and if an actor has been hit then save to see if tap event is still valid on a tap( same actor being hit )
- HitTestAlgorithm::Results hitTestResults;
- if ( HitTest( scene, tapEvent.point, hitTestResults ) )
- {
- SetActor( &GetImplementation( hitTestResults.actor ) );
- mCurrentTapActor.SetActor( GetCurrentGesturedActor() );
-
- // Indicate that we've processed a touch down. Bool should be sufficient as a change in actor will result in a cancellation
- mPossibleProcessed = true;
- }
- else
- {
- ResetActor();
- }
- break;
- }
-
- case Gesture::Started:
- {
- // Ensure that we're processing a hit on the current actor and that we've already processed a touch down
- HitTestAlgorithm::Results hitTestResults;
- if ( GetCurrentGesturedActor() && HitTest( scene, tapEvent.point, hitTestResults ) && mPossibleProcessed )
- {
- // Check that this actor is still the one that was used for the last touch down ?
- if ( mCurrentTapActor.GetActor() == &GetImplementation( hitTestResults.actor ) )
- {
- mCurrentTapEvent = &tapEvent;
- ProcessAndEmit( hitTestResults );
- }
- mCurrentTapEvent = NULL;
- mPossibleProcessed = false;
- }
- break;
- }
-
- case Gesture::Cancelled:
- {
- mPossibleProcessed = false;
- ResetActor();
- break;
- }
-
- case Gesture::Continuing:
- {
- DALI_ABORT( "Incorrect state received from Integration layer: Continuing\n" );
- break;
- }
- case Gesture::Finished:
- {
- DALI_ABORT( "Incorrect state received from Integration layer: Finished\n" );
- break;
- }
- case Gesture::Clear:
- {
- DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
- break;
- }
- }
-}
-
-void TapGestureProcessor::AddGestureDetector( TapGestureDetector* gestureDetector, Scene& scene )
-{
- bool firstRegistration(mTapGestureDetectors.empty());
-
- mTapGestureDetectors.push_back(gestureDetector);
-
- const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
- const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
- const unsigned int touchesRequired = gestureDetector->GetTouchesRequired();
-
- DALI_ASSERT_ALWAYS( minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested" );
-
- if (firstRegistration)
- {
- // If this is the first tap gesture detector that has been added, then our minimum and maximum
- // requirements are the same as each other.
-
- mMinTapsRequired = minTapsRequired;
- mMaxTapsRequired = maxTapsRequired;
- mMinTouchesRequired = mMaxTouchesRequired = touchesRequired;
-
- TapGestureRequest request;
- request.minTaps = mMinTapsRequired;
- request.maxTaps = mMaxTapsRequired;
- request.minTouches = mMinTouchesRequired;
- request.maxTouches = mMaxTouchesRequired;
-
- Size size = scene.GetSize();
- mGestureRecognizer = new TapGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const TapGestureRequest&>(request));
- }
- else
- {
- // If we have already registered for tap gesture detection before then we need to check our
- // minimum and maximums and see if our gesture detection requirements have changed, if they
- // have, then we should ask the adaptor to update its detection policy.
-
- // This is quicker than calling UpdateDetection as there is no need to iterate through the container
-
- unsigned int minTaps = mMinTapsRequired < minTapsRequired ? mMinTapsRequired : minTapsRequired;
- unsigned int maxTaps = mMaxTapsRequired > maxTapsRequired ? mMaxTapsRequired : maxTapsRequired;
- unsigned int minTouches = mMinTouchesRequired < touchesRequired ? mMinTouchesRequired : touchesRequired;
- unsigned int maxTouches = mMaxTouchesRequired > touchesRequired ? mMaxTouchesRequired : touchesRequired;
-
- if ( (minTaps != mMinTapsRequired)||(maxTaps != mMaxTapsRequired) ||
- (minTouches != mMinTouchesRequired)||(maxTouches != mMaxTouchesRequired) )
- {
- TapGestureRequest request;
- request.minTaps = mMinTapsRequired = minTaps;
- request.maxTaps = mMaxTapsRequired = maxTaps;
- request.minTouches = mMinTouchesRequired = minTouches;
- request.maxTouches = mMaxTouchesRequired = maxTouches;
-
- mGestureRecognizer->Update(request);
- }
- }
-}
-
-void TapGestureProcessor::RemoveGestureDetector( TapGestureDetector* gestureDetector )
-{
- // Find detector ...
- TapGestureDetectorContainer::iterator endIter = std::remove( mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector );
- DALI_ASSERT_DEBUG( endIter != mTapGestureDetectors.end() );
-
- // ... and remove it
- mTapGestureDetectors.erase( endIter, mTapGestureDetectors.end() );
-
- if ( mTapGestureDetectors.empty() )
- {
- mGestureRecognizer.Detach();
-
- ResetActor();
- }
- else
- {
- UpdateDetection();
- }
-}
-
-void TapGestureProcessor::GestureDetectorUpdated( TapGestureDetector* gestureDetector )
-{
- DALI_ASSERT_DEBUG(find(mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector) != mTapGestureDetectors.end());
-
- const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
- const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
-
- DALI_ASSERT_ALWAYS( minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested" );
-
- UpdateDetection();
-}
-
-void TapGestureProcessor::UpdateDetection()
-{
- DALI_ASSERT_DEBUG(!mTapGestureDetectors.empty());
-
- unsigned int minTaps = UINT_MAX;
- unsigned int maxTaps = 0;
- unsigned int minTouches = UINT_MAX;
- unsigned int maxTouches = 0;
-
- for ( TapGestureDetectorContainer::iterator iter = mTapGestureDetectors.begin(), endIter = mTapGestureDetectors.end(); iter != endIter; ++iter )
- {
- TapGestureDetector* detector(*iter);
-
- if( detector )
- {
- const unsigned int minTapsRequired = detector->GetMinimumTapsRequired();
- const unsigned int maxTapsRequired = detector->GetMaximumTapsRequired();
- const unsigned int touchesRequired = detector->GetTouchesRequired();
-
- minTaps = minTapsRequired < minTaps ? minTapsRequired : minTaps;
- maxTaps = maxTapsRequired > maxTaps ? maxTapsRequired : maxTaps;
- minTouches = touchesRequired < minTouches ? touchesRequired : minTouches;
- maxTouches = touchesRequired > maxTouches ? touchesRequired : maxTouches;
- }
- }
-
- if ( (minTaps != mMinTapsRequired)||(maxTaps != mMaxTapsRequired) ||
- (minTouches != mMinTouchesRequired)||(maxTouches != mMaxTouchesRequired) )
- {
- TapGestureRequest request;
- request.minTaps = mMinTapsRequired = minTaps;
- request.maxTaps = mMaxTapsRequired = maxTaps;
- request.minTouches = mMinTouchesRequired = minTouches;
- request.maxTouches = mMaxTouchesRequired = maxTouches;
-
- mGestureRecognizer->Update(request);
- }
-}
-
-bool TapGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
-{
- DALI_ASSERT_DEBUG( mCurrentTapEvent );
-
- TapGestureDetector* tapDetector ( static_cast< TapGestureDetector* >( detector ) );
-
- return ( ( tapDetector->GetMinimumTapsRequired() <= mCurrentTapEvent->numberOfTaps ) && ( tapDetector->GetMaximumTapsRequired() >= mCurrentTapEvent->numberOfTaps ) ) &&
- ( tapDetector->GetTouchesRequired() == mCurrentTapEvent->numberOfTouches );
-}
-
-void TapGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
-{
- DALI_ASSERT_DEBUG( mCurrentTapEvent );
-
- EmitTapSignal( actor, gestureDetectors, *mCurrentTapEvent, actorCoordinates );
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_TAP_GESTURE_EVENT_PROCESSOR_H
-#define DALI_INTERNAL_TAP_GESTURE_EVENT_PROCESSOR_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/tap-gesture-detector-impl.h>
-#include <dali/internal/event/events/gesture-processor.h>
-#include "actor-observer.h"
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-class Scene;
-class Stage;
-class Actor;
-
-struct GestureEvent;
-struct TapGestureEvent;
-
-/**
- * Tap Gesture Event Processing:
- *
- * When we receive a tap gesture event, we do the following:
- * - Find the actor that requires a tap where the tap occurred.
- * - Emit the gesture if the tap gesture event satisfies the detector conditions.
- */
-class TapGestureProcessor : public GestureProcessor, public RecognizerObserver<TapGestureEvent>
-{
-public:
-
- /**
- * Create a tap gesture processor.
- */
- TapGestureProcessor();
-
- /**
- * Non-virtual destructor; TapGestureProcessor is not a base class
- */
- ~TapGestureProcessor();
-
-public: // To be called by GestureEventProcessor
-
- /**
- * This method is called whenever a tap gesture event occurs.
- * @param[in] scene The scene the tap gesture event occurs in.
- * @param[in] tapEvent The event that has occurred.
- */
- void Process( Scene& scene, const TapGestureEvent& event);
-
- /**
- * Adds a gesture detector to this gesture processor.
- * If this is the first gesture detector being added, then this method registers the required
- * gesture with the adaptor.
- * @param[in] gestureDetector The gesture detector being added.
- */
- void AddGestureDetector(TapGestureDetector* gestureDetector, Scene& scene);
-
- /**
- * Removes the specified gesture detector from this gesture processor. If, after removing this
- * gesture detector, there are no more gesture detectors registered, then this method unregisters
- * the gesture from the adaptor.
- * @param[in] gestureDetector The gesture detector being removed.
- */
- void RemoveGestureDetector(TapGestureDetector* gestureDetector);
-
- /**
- * This method updates the gesture detection parameters.
- * @param[in] gestureDetector The gesture detector that has been updated.
- */
- void GestureDetectorUpdated(TapGestureDetector* gestureDetector);
-
-private:
-
- // Undefined
- TapGestureProcessor(const TapGestureProcessor&);
- TapGestureProcessor& operator=(const TapGestureProcessor& rhs);
-
-private:
-
- /**
- * Iterates through our GestureDetectors and determines if we need to ask the adaptor to update
- * its detection policy. If it does, it sends the appropriate gesture update request to adaptor.
- */
- void UpdateDetection();
-
- // GestureProcessor overrides
-
- /**
- * @copydoc GestureProcessor::OnGesturedActorStageDisconnection()
- */
- void OnGesturedActorStageDisconnection() { /* Nothing to do */ }
-
- /**
- * @copydoc GestureProcessor::CheckGestureDetector()
- */
- bool CheckGestureDetector( GestureDetector* detector, Actor* actor );
-
- /**
- * @copydoc GestureProcessor::EmitGestureSignal()
- */
- void EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates );
-
-private:
-
- TapGestureDetectorContainer mTapGestureDetectors;
-
- unsigned int mMinTapsRequired;
- unsigned int mMaxTapsRequired;
- unsigned int mMinTouchesRequired;
- unsigned int mMaxTouchesRequired;
-
- ActorObserver mCurrentTapActor; ///< Observer for the current gesture actor
- const TapGestureEvent* mCurrentTapEvent; ///< Pointer to current TapEvent, used when calling ProcessAndEmit()
- bool mPossibleProcessed; ///< Indication of whether we've processed a touch down for this gestuee
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_TAP_GESTURE_EVENT_PROCESSOR_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/event/events/tap-gesture-recognizer.h>
-
-// EXTERNAL INCLUDES
-#include <cmath>
-
-#include <dali/public-api/math/vector2.h>
-
-#include <dali/integration-api/events/touch-event-integ.h>
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/gesture-requests.h>
-#include <dali/internal/event/common/scene-impl.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace
-{
-// TODO: Set these according to DPI
-const float MAXIMUM_MOTION_ALLOWED = 20.0f;
-const unsigned long MAXIMUM_TIME_ALLOWED = 500u;
-} // unnamed namespace
-
-TapGestureRecognizer::TapGestureRecognizer( Observer& observer, Vector2 screenSize, const TapGestureRequest& request)
-: GestureRecognizer( screenSize, Gesture::Tap ),
- mObserver(observer),
- mState(Clear),
- mMinimumTapsRequired(request.minTaps),
- mMaximumTapsRequired(request.maxTaps),
- mTapsRegistered(0),
- mTouchPosition(),
- mTouchTime(0u),
- mLastTapTime(0u)
-{
-}
-
-TapGestureRecognizer::~TapGestureRecognizer()
-{
-}
-
-void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
-{
- if (event.GetPointCount() == 1)
- {
- const Integration::Point& point = event.points[0];
- PointState::Type pointState = point.GetState();
-
- switch (mState)
- {
- case Clear:
- {
- if (pointState == PointState::DOWN)
- {
- SetupForTouchDown( event, point );
- }
- break;
- }
-
- case Touched:
- {
- uint32_t deltaBetweenTouchDownTouchUp = event.time - mTouchTime;
-
- if ( pointState == PointState::UP )
- {
- if ( deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED )
- {
- mLastTapTime = mTouchTime;
- EmitSingleTap( event.time, point );
- mState = Registered;
- }
- else
- {
- mState = Clear;
- }
- }
- else if (pointState == PointState::INTERRUPTED)
- {
- mState = Clear;
- }
- break;
- }
-
- case Registered:
- {
- if ( pointState == PointState::UP )
- {
- uint32_t deltaBetweenTouchDownTouchUp = event.time - mTouchTime;
-
- if ( deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED )
- {
- // This is a possible multiple tap, so has it been quick enough?
- uint32_t timeDelta = event.time - mLastTapTime;
- if( timeDelta > MAXIMUM_TIME_ALLOWED ) // If exceeded time between taps then just a single tap
- {
- mLastTapTime = event.time;
- EmitSingleTap(event.time, point);
- mState = Registered;
- }
- else
- {
- ++mTapsRegistered;
- EmitGesture( Gesture::Started, event.time );
- mState = Clear;
- }
- }
- else // Delta between touch down and touch up too long to be considered a Tap event
- {
- mState = Clear;
- }
- }
- else if (pointState == PointState::DOWN)
- {
- const Vector2& screen( point.GetScreenPosition() );
- Vector2 distanceDelta(std::abs(mTouchPosition.x - screen.x),
- std::abs(mTouchPosition.y - screen.y));
-
- uint32_t timeDelta = event.time - mLastTapTime;
-
- if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
- distanceDelta.y > MAXIMUM_MOTION_ALLOWED ||
- timeDelta > MAXIMUM_TIME_ALLOWED )
- {
- SetupForTouchDown( event, point );
- }
- else
- {
- EmitPossibleState( event );
- }
- }
- break;
- }
-
- case Failed:
- default:
- {
- mState = Clear;
- break;
- }
- }
- }
- else
- {
- mState = Failed;
-
- // We have entered a multi-touch event so emit registered gestures if required.
- EmitGesture(Gesture::Started, event.time);
- }
-}
-
-void TapGestureRecognizer::SetupForTouchDown( const Integration::TouchEvent& event, const Integration::Point& point )
-{
- mTouchPosition = point.GetScreenPosition();
- mTouchTime = event.time;
- mLastTapTime = 0u;
- mTapsRegistered = 0;
- mState = Touched;
- EmitPossibleState( event );
-}
-
-void TapGestureRecognizer::EmitPossibleState( const Integration::TouchEvent& event )
-{
- TapGestureEvent tapEvent( Gesture::Possible );
- tapEvent.point = mTouchPosition;
- tapEvent.time = event.time;
-
- ProcessEvent( tapEvent );
-}
-
-
-void TapGestureRecognizer::Update(const GestureRequest& request)
-{
- const TapGestureRequest& tap = static_cast<const TapGestureRequest&>(request);
-
- mMinimumTapsRequired = tap.minTaps;
- mMaximumTapsRequired = tap.maxTaps;
-}
-
-void TapGestureRecognizer::EmitGesture( Gesture::State state, uint32_t time )
-{
- if ( (state == Gesture::Cancelled) ||
- (mTapsRegistered >= mMinimumTapsRequired && mTapsRegistered <= mMaximumTapsRequired) )
-
- {
- TapGestureEvent event( state );
- EmitTap( time, event );
- }
-}
-
-void TapGestureRecognizer::EmitSingleTap( uint32_t time, const Integration::Point& point )
-{
- TapGestureEvent event( Gesture::Started );
- const Vector2& screen( point.GetScreenPosition() );
- Vector2 distanceDelta(std::abs(mTouchPosition.x - screen.x),
- std::abs(mTouchPosition.y - screen.y));
-
- if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
- distanceDelta.y > MAXIMUM_MOTION_ALLOWED )
- {
- event.state = Gesture::Cancelled;
- }
- mTapsRegistered = 1u;
- EmitTap( time, event );
-}
-
-void TapGestureRecognizer::EmitTap( uint32_t time, TapGestureEvent& event )
-{
- event.numberOfTaps = mTapsRegistered;
- event.point = mTouchPosition;
- event.time = time;
-
- ProcessEvent( event );
-}
-
-void TapGestureRecognizer::ProcessEvent( TapGestureEvent& event )
-{
- if( mScene )
- {
- // Create another handle so the recognizer cannot be destroyed during process function
- GestureRecognizerPtr recognizerHandle = this;
- mObserver.Process(*mScene, event);
- }
-}
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_EVENT_EVENTS_TAP_GESTURE_RECOGNIZER_H
-#define DALI_INTERNAL_EVENT_EVENTS_TAP_GESTURE_RECOGNIZER_H
-
-/*
- * Copyright (c) 2019 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <cstdint>
-#include <dali/public-api/common/vector-wrapper.h>
-#include <dali/integration-api/events/point.h>
-
-
-// INTERNAL INCLUDES
-#include <dali/internal/event/events/gesture-recognizer.h>
-#include <dali/internal/event/events/tap-gesture-event.h>
-
-namespace Dali
-{
-
-namespace Integration
-{
-struct TouchEvent;
-}
-
-namespace Internal
-{
-struct TapGestureRequest;
-
-/**
- * When given a set of touch events, this detector attempts to determine if a tap gesture has taken place.
- */
-class TapGestureRecognizer : public GestureRecognizer
-{
-public:
-
- using Observer = RecognizerObserver<TapGestureEvent>;
-
- /**
- * Constructor
- * @param[in] coreEventInterface Used to send events to Core.
- * @param[in] screenSize The size of the screen.
- * @param[in] request The tap gesture request.
- */
- TapGestureRecognizer(Observer& observer, Vector2 screenSize, const TapGestureRequest& request);
-
- /**
- * Virtual destructor.
- */
- virtual ~TapGestureRecognizer();
-
-public:
-
- /**
- * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
- */
- virtual void SendEvent(const Integration::TouchEvent& event);
-
- /**
- * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
- */
- virtual void Update(const GestureRequest& request);
-
-private:
-
- /**
- * Checks if registered taps are within required bounds and emits tap gesture if they are.
- *
- * @param[in] state current state of incomplete gesture
- * @param[in] time time of this latest touch event
- */
- void EmitGesture( Gesture::State state, uint32_t time );
-
- /**
- * Initialises tap gesture detector for next tap sequence
- *
- * @param[in] event registered touch event
- * @param[in] point position touch event occurred
- */
- void SetupForTouchDown( const Integration::TouchEvent& event, const Integration::Point& point );
-
- /**
- * Emit a touch down event for hit testing
- *
- * @param[in] event registered touch event
- */
- void EmitPossibleState( const Integration::TouchEvent& event );
-
- /**
- * Force a touch event sequence to be treated as a single tap
- *
- * @param[in] time time of this latest touch event
- * @param[in] point position touch event occurred
- */
- void EmitSingleTap( uint32_t time, const Integration::Point& point );
-
- /**
- * Emit a tap event
- *
- * @param[in] time time of this latest touch event
- * @param[in] event registered touch event
- */
- void EmitTap( uint32_t time, TapGestureEvent& event );
-
- /**
- * Send the event for processing
- *
- * @param[in] tap event for processing
- */
- void ProcessEvent( TapGestureEvent& event );
-
-private:
-
- // Reference to the gesture processor for this recognizer
- Observer& mObserver;
-
- /**
- * Internal state machine.
- */
- enum State
- {
- Clear, ///< No gesture detected.
- Touched, ///< User is touching the screen.
- Registered, ///< At least one tap has been registered.
- Failed, ///< Gesture has failed.
- };
-
- State mState; ///< Current state of the detector.
-
- int mMinimumTapsRequired; ///< Minimum number of taps required.
- int mMaximumTapsRequired; ///< Maximum number of taps required.
- int mTapsRegistered; ///< In current detection, the number of taps registered.
-
- Vector2 mTouchPosition; ///< The initial touch down position.
- uint32_t mTouchTime; ///< The initial touch down time.
- uint32_t mLastTapTime; ///< Time last tap gesture was registered
-
-};
-
-} // namespace Internal
-
-} // namespace Dali
-
-
-#endif // DALI_INTERNAL_EVENT_EVENTS_TAP_GESTURE_RECOGNIZER_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/tap-gesture.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/event/events/gesture-event-processor.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const unsigned int DEFAULT_TAPS_REQUIRED = 1u;
+const unsigned int DEFAULT_TOUCHES_REQUIRED = 1u;
+
+// Signals
+const char* const SIGNAL_TAP_DETECTED = "tapDetected";
+
+BaseHandle Create()
+{
+ return Dali::TapGestureDetector::New();
+}
+
+TypeRegistration mType( typeid(Dali::TapGestureDetector), typeid(Dali::GestureDetector), Create );
+
+SignalConnectorType signalConnector1( mType, SIGNAL_TAP_DETECTED, &TapGestureDetector::DoConnectSignal );
+
+}
+
+TapGestureDetectorPtr TapGestureDetector::New()
+{
+ return new TapGestureDetector;
+}
+
+TapGestureDetectorPtr TapGestureDetector::New( unsigned int tapsRequired )
+{
+ return new TapGestureDetector( tapsRequired );
+}
+
+TapGestureDetector::TapGestureDetector()
+: GestureDetector( Gesture::Tap ),
+ mMinimumTapsRequired( DEFAULT_TAPS_REQUIRED ),
+ mMaximumTapsRequired( DEFAULT_TAPS_REQUIRED ),
+ mTouchesRequired( DEFAULT_TOUCHES_REQUIRED )
+{
+}
+
+TapGestureDetector::TapGestureDetector( unsigned int tapsRequired )
+: GestureDetector( Gesture::Tap ),
+ mMinimumTapsRequired( tapsRequired ),
+ mMaximumTapsRequired( tapsRequired ),
+ mTouchesRequired( DEFAULT_TOUCHES_REQUIRED )
+{
+}
+
+TapGestureDetector::~TapGestureDetector()
+{
+}
+
+void TapGestureDetector::SetMinimumTapsRequired(unsigned int taps)
+{
+ if ( mMinimumTapsRequired != taps )
+ {
+ mMinimumTapsRequired = taps;
+
+ if ( !mAttachedActors.empty() )
+ {
+ mGestureEventProcessor.GestureDetectorUpdated(this);
+ }
+ }
+}
+
+void TapGestureDetector::SetMaximumTapsRequired(unsigned int taps)
+{
+ if ( mMaximumTapsRequired != taps )
+ {
+ mMaximumTapsRequired = taps;
+
+ if ( !mAttachedActors.empty() )
+ {
+ mGestureEventProcessor.GestureDetectorUpdated(this);
+ }
+ }
+}
+
+void TapGestureDetector::SetTouchesRequired(unsigned int touches)
+{
+ if (mTouchesRequired != touches)
+ {
+ mTouchesRequired = touches;
+
+ if (!mAttachedActors.empty())
+ {
+ mGestureEventProcessor.GestureDetectorUpdated(this);
+ }
+ }
+}
+
+unsigned int TapGestureDetector::GetMinimumTapsRequired() const
+{
+ return mMinimumTapsRequired;
+}
+
+unsigned int TapGestureDetector::GetMaximumTapsRequired() const
+{
+ return mMaximumTapsRequired;
+}
+
+unsigned int TapGestureDetector::GetTouchesRequired() const
+{
+ return mTouchesRequired;
+}
+
+void TapGestureDetector::EmitTapGestureSignal(Dali::Actor tappedActor, const TapGesture& tap)
+{
+ // Guard against destruction during signal emission
+ Dali::TapGestureDetector handle( this );
+
+ mDetectedSignal.Emit( tappedActor, tap );
+}
+
+bool TapGestureDetector::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+ bool connected( true );
+ TapGestureDetector* gesture = static_cast< TapGestureDetector* >(object); // TypeRegistry guarantees that this is the correct type.
+
+ if ( 0 == strcmp( signalName.c_str(), SIGNAL_TAP_DETECTED ) )
+ {
+ gesture->DetectedSignal().Connect( tracker, functor );
+ }
+ else
+ {
+ // signalName does not match any signal
+ connected = false;
+ }
+
+ return connected;
+}
+
+void TapGestureDetector::OnActorAttach(Actor& actor)
+{
+ // Do nothing
+}
+
+void TapGestureDetector::OnActorDetach(Actor& actor)
+{
+ // Do nothing
+}
+
+void TapGestureDetector::OnActorDestroyed(Object& object)
+{
+ // Do nothing
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_TAP_GESTURE_DETECTOR_H
+#define DALI_INTERNAL_TAP_GESTURE_DETECTOR_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/events/tap-gesture-detector.h>
+#include <dali/internal/event/events/gesture-detector-impl.h>
+
+namespace Dali
+{
+
+struct TapGesture;
+
+namespace Internal
+{
+
+class TapGestureDetector;
+
+typedef IntrusivePtr<TapGestureDetector> TapGestureDetectorPtr;
+typedef DerivedGestureDetectorContainer<TapGestureDetector>::type TapGestureDetectorContainer;
+
+/**
+ * @copydoc Dali::TapGestureDetector
+ */
+class TapGestureDetector : public GestureDetector
+{
+public: // Creation
+
+ /**
+ * Create a new gesture detector.
+ * @return A smart-pointer to the newly allocated detector.
+ */
+ static TapGestureDetectorPtr New();
+
+ /**
+ * Create a new gesture detector with the specified parameters.
+ * @param[in] tapsRequired The number of taps required.
+ * @return A smart-pointer to the newly allocated detector.
+ */
+ static TapGestureDetectorPtr New( unsigned int tapsRequired );
+
+ /**
+ * Construct a new GestureDetector.
+ */
+ TapGestureDetector();
+
+ /**
+ * Construct a new GestureDetector with the specified parameters.
+ * @param[in] tapsRequired The number of taps required.
+ */
+ TapGestureDetector( unsigned int tapsRequired );
+
+public:
+
+ /**
+ * @copydoc Dali::TapGestureDetector::SetTouchesRequired(unsigned int)
+ */
+ void SetTouchesRequired(unsigned int touches);
+
+ /**
+ * @copydoc Dali::TapGestureDetector::SetMinimumTapsRequired()
+ */
+ void SetMinimumTapsRequired( unsigned int minTaps );
+
+ /**
+ * @copydoc Dali::TapGestureDetector::SetMaximumTapsRequired()
+ */
+ void SetMaximumTapsRequired( unsigned int maxTaps );
+
+ /**
+ * @copydoc Dali::TapGestureDetector::GetMinimumTapsRequired()
+ */
+ unsigned int GetMinimumTapsRequired() const;
+
+ /**
+ * @copydoc Dali::TapGestureDetector::SetMaximumTapsRequired()
+ */
+ unsigned int GetMaximumTapsRequired() const;
+
+ /**
+ * @copydoc Dali::TapGestureDetector::GetTouchesRequired()
+ */
+ unsigned int GetTouchesRequired() const;
+
+public:
+
+ /**
+ * Called by the TapGestureProcessor when a tap gesture event occurs within the bounds of our
+ * attached actor.
+ * @param[in] tappedActor The tapped actor.
+ * @param[in] tap The tap gesture.
+ */
+ void EmitTapGestureSignal(Dali::Actor tappedActor, const TapGesture& tap);
+
+public: // Signals
+
+ /**
+ * @copydoc Dali::TapGestureDetector::DetectedSignal()
+ */
+ Dali::TapGestureDetector::DetectedSignalType& DetectedSignal()
+ {
+ return mDetectedSignal;
+ }
+
+ /**
+ * Connects a callback function with the object's signals.
+ * @param[in] object The object providing the signal.
+ * @param[in] tracker Used to disconnect the signal.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
+ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+protected:
+
+ /**
+ * A reference counted object may only be deleted by calling Unreference()
+ */
+ virtual ~TapGestureDetector();
+
+private:
+
+ // Undefined
+ TapGestureDetector(const TapGestureDetector&);
+ TapGestureDetector& operator=(const TapGestureDetector& rhs);
+
+private: // GestureDetector overrides
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&)
+ */
+ virtual void OnActorAttach(Actor& actor);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDetach(Actor&)
+ */
+ virtual void OnActorDetach(Actor& actor);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::OnActorDestroyed(Object&)
+ */
+ virtual void OnActorDestroyed(Object& object);
+
+private:
+
+ Dali::TapGestureDetector::DetectedSignalType mDetectedSignal;
+
+ unsigned int mMinimumTapsRequired;
+ unsigned int mMaximumTapsRequired;
+ unsigned int mTouchesRequired;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::TapGestureDetector& GetImplementation(Dali::TapGestureDetector& detector)
+{
+ DALI_ASSERT_ALWAYS( detector && "TapGestureDetector handle is empty" );
+
+ BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<Internal::TapGestureDetector&>(handle);
+}
+
+inline const Internal::TapGestureDetector& GetImplementation(const Dali::TapGestureDetector& detector)
+{
+ DALI_ASSERT_ALWAYS( detector && "TapGestureDetector handle is empty" );
+
+ const BaseObject& handle = detector.GetBaseObject();
+
+ return static_cast<const Internal::TapGestureDetector&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TAP_GESTURE_DETECTOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/tap-gesture/tap-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+TapGestureEvent::TapGestureEvent( Gesture::State state )
+: GestureEvent(Gesture::Tap, state),
+ numberOfTaps(1),
+ numberOfTouches(1)
+{
+}
+
+TapGestureEvent::~TapGestureEvent()
+{
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_TAP_GESTURE_H
+#define DALI_INTERNAL_EVENT_TAP_GESTURE_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/math/vector2.h>
+#include <dali/internal/event/events/gesture-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+/**
+ * If the adaptor detects a tap gesture, then it should create an instance of this structure and
+ * send it to the Core.
+ *
+ * A Tap Gesture event should be in one of three states:
+ * - Possible: When the user first puts their finger down - Core needs to hit test the down point so
+ * that a tap (down and up quickly) is also on the same actor.
+ * - Started: If a tap is detected (No Finished state is expected).
+ * - Cancelled: If, after a down event, no tap is detected, or a system interruption.
+ *
+ * A Started state will be ignored if a Possible state does not precede it.
+ */
+struct TapGestureEvent : public GestureEvent
+{
+ // Construction & Destruction
+
+ /**
+ * Default Constructor
+ * @param[in] state Possible, denotes down press;
+ * Started, of a tap occurs; and
+ * Cancelled, when tap does not occur.
+ */
+ TapGestureEvent( Gesture::State state );
+
+ /**
+ * Virtual destructor
+ */
+ virtual ~TapGestureEvent();
+
+ // Data
+
+ /**
+ * @copydoc Dali::TapGesture::numberOfTaps
+ */
+ unsigned int numberOfTaps;
+
+ /**
+ * @copydoc Dali::TapGesture::numberOfTouches
+ */
+ unsigned int numberOfTouches;
+
+ /**
+ * This is the point, in screen coordinates, where the tap occurred.
+ * If a multi-touch tap, then this should be the centroid of all the touch points.
+ */
+ Vector2 point;
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_TAP_GESTURE_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/tap-gesture/tap-gesture-processor.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/events/tap-gesture.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/event/actors/actor-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+#include <dali/internal/event/common/scene-impl.h>
+#include <dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h>
+#include <dali/internal/event/events/gesture-requests.h>
+#include <dali/internal/event/events/tap-gesture/tap-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+/**
+ * Creates a TapGesture and asks the specified detector to emit its detected signal.
+ * @param[in] actor The actor on which a tap has occurred.
+ * @param[in] gestureDetectors A reference to gesture detectors that should emit the signal.
+ * @param[in] tapEvent The tapEvent received from the adaptor.
+ * @param[in] localPoint Relative to the actor attached to the detector.
+ */
+void EmitTapSignal(
+ Actor* actor,
+ const GestureDetectorContainer& gestureDetectors,
+ const TapGestureEvent& tapEvent,
+ Vector2 localPoint)
+{
+ TapGesture tap;
+ tap.time = tapEvent.time;
+ tap.numberOfTaps = tapEvent.numberOfTaps;
+ tap.numberOfTouches = tapEvent.numberOfTouches;
+ tap.screenPoint = tapEvent.point;
+ tap.localPoint = localPoint;
+
+ Dali::Actor actorHandle( actor );
+ const GestureDetectorContainer::const_iterator endIter = gestureDetectors.end();
+ for ( GestureDetectorContainer::const_iterator iter = gestureDetectors.begin(); iter != endIter; ++iter )
+ {
+ static_cast< TapGestureDetector* >( *iter )->EmitTapGestureSignal( actorHandle, tap );
+ }
+}
+
+} // unnamed namespace
+
+TapGestureProcessor::TapGestureProcessor()
+: GestureProcessor( Gesture::Tap ),
+ mTapGestureDetectors(),
+ mMinTapsRequired( 1 ),
+ mMaxTapsRequired( 1 ),
+ mMinTouchesRequired( 1 ),
+ mMaxTouchesRequired( 1 ),
+ mCurrentTapEvent( NULL ),
+ mPossibleProcessed( false )
+{
+}
+
+TapGestureProcessor::~TapGestureProcessor()
+{
+}
+
+void TapGestureProcessor::Process( Scene& scene, const TapGestureEvent& tapEvent )
+{
+ switch ( tapEvent.state )
+ {
+ case Gesture::Possible:
+ {
+ // Do a hit test and if an actor has been hit then save to see if tap event is still valid on a tap( same actor being hit )
+ HitTestAlgorithm::Results hitTestResults;
+ if ( HitTest( scene, tapEvent.point, hitTestResults ) )
+ {
+ SetActor( &GetImplementation( hitTestResults.actor ) );
+ mCurrentTapActor.SetActor( GetCurrentGesturedActor() );
+
+ // Indicate that we've processed a touch down. Bool should be sufficient as a change in actor will result in a cancellation
+ mPossibleProcessed = true;
+ }
+ else
+ {
+ ResetActor();
+ }
+ break;
+ }
+
+ case Gesture::Started:
+ {
+ // Ensure that we're processing a hit on the current actor and that we've already processed a touch down
+ HitTestAlgorithm::Results hitTestResults;
+ if ( GetCurrentGesturedActor() && HitTest( scene, tapEvent.point, hitTestResults ) && mPossibleProcessed )
+ {
+ // Check that this actor is still the one that was used for the last touch down ?
+ if ( mCurrentTapActor.GetActor() == &GetImplementation( hitTestResults.actor ) )
+ {
+ mCurrentTapEvent = &tapEvent;
+ ProcessAndEmit( hitTestResults );
+ }
+ mCurrentTapEvent = NULL;
+ mPossibleProcessed = false;
+ }
+ break;
+ }
+
+ case Gesture::Cancelled:
+ {
+ mPossibleProcessed = false;
+ ResetActor();
+ break;
+ }
+
+ case Gesture::Continuing:
+ {
+ DALI_ABORT( "Incorrect state received from Integration layer: Continuing\n" );
+ break;
+ }
+ case Gesture::Finished:
+ {
+ DALI_ABORT( "Incorrect state received from Integration layer: Finished\n" );
+ break;
+ }
+ case Gesture::Clear:
+ {
+ DALI_ABORT( "Incorrect state received from Integration layer: Clear\n" );
+ break;
+ }
+ }
+}
+
+void TapGestureProcessor::AddGestureDetector( TapGestureDetector* gestureDetector, Scene& scene )
+{
+ bool firstRegistration(mTapGestureDetectors.empty());
+
+ mTapGestureDetectors.push_back(gestureDetector);
+
+ const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
+ const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
+ const unsigned int touchesRequired = gestureDetector->GetTouchesRequired();
+
+ DALI_ASSERT_ALWAYS( minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested" );
+
+ if (firstRegistration)
+ {
+ // If this is the first tap gesture detector that has been added, then our minimum and maximum
+ // requirements are the same as each other.
+
+ mMinTapsRequired = minTapsRequired;
+ mMaxTapsRequired = maxTapsRequired;
+ mMinTouchesRequired = mMaxTouchesRequired = touchesRequired;
+
+ TapGestureRequest request;
+ request.minTaps = mMinTapsRequired;
+ request.maxTaps = mMaxTapsRequired;
+ request.minTouches = mMinTouchesRequired;
+ request.maxTouches = mMaxTouchesRequired;
+
+ Size size = scene.GetSize();
+ mGestureRecognizer = new TapGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const TapGestureRequest&>(request));
+ }
+ else
+ {
+ // If we have already registered for tap gesture detection before then we need to check our
+ // minimum and maximums and see if our gesture detection requirements have changed, if they
+ // have, then we should ask the adaptor to update its detection policy.
+
+ // This is quicker than calling UpdateDetection as there is no need to iterate through the container
+
+ unsigned int minTaps = mMinTapsRequired < minTapsRequired ? mMinTapsRequired : minTapsRequired;
+ unsigned int maxTaps = mMaxTapsRequired > maxTapsRequired ? mMaxTapsRequired : maxTapsRequired;
+ unsigned int minTouches = mMinTouchesRequired < touchesRequired ? mMinTouchesRequired : touchesRequired;
+ unsigned int maxTouches = mMaxTouchesRequired > touchesRequired ? mMaxTouchesRequired : touchesRequired;
+
+ if ( (minTaps != mMinTapsRequired)||(maxTaps != mMaxTapsRequired) ||
+ (minTouches != mMinTouchesRequired)||(maxTouches != mMaxTouchesRequired) )
+ {
+ TapGestureRequest request;
+ request.minTaps = mMinTapsRequired = minTaps;
+ request.maxTaps = mMaxTapsRequired = maxTaps;
+ request.minTouches = mMinTouchesRequired = minTouches;
+ request.maxTouches = mMaxTouchesRequired = maxTouches;
+
+ mGestureRecognizer->Update(request);
+ }
+ }
+}
+
+void TapGestureProcessor::RemoveGestureDetector( TapGestureDetector* gestureDetector )
+{
+ // Find detector ...
+ TapGestureDetectorContainer::iterator endIter = std::remove( mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector );
+ DALI_ASSERT_DEBUG( endIter != mTapGestureDetectors.end() );
+
+ // ... and remove it
+ mTapGestureDetectors.erase( endIter, mTapGestureDetectors.end() );
+
+ if ( mTapGestureDetectors.empty() )
+ {
+ mGestureRecognizer.Detach();
+
+ ResetActor();
+ }
+ else
+ {
+ UpdateDetection();
+ }
+}
+
+void TapGestureProcessor::GestureDetectorUpdated( TapGestureDetector* gestureDetector )
+{
+ DALI_ASSERT_DEBUG(find(mTapGestureDetectors.begin(), mTapGestureDetectors.end(), gestureDetector) != mTapGestureDetectors.end());
+
+ const unsigned int minTapsRequired = gestureDetector->GetMinimumTapsRequired();
+ const unsigned int maxTapsRequired = gestureDetector->GetMaximumTapsRequired();
+
+ DALI_ASSERT_ALWAYS( minTapsRequired <= maxTapsRequired && "Minimum taps requested is greater than the maximum requested" );
+
+ UpdateDetection();
+}
+
+void TapGestureProcessor::UpdateDetection()
+{
+ DALI_ASSERT_DEBUG(!mTapGestureDetectors.empty());
+
+ unsigned int minTaps = UINT_MAX;
+ unsigned int maxTaps = 0;
+ unsigned int minTouches = UINT_MAX;
+ unsigned int maxTouches = 0;
+
+ for ( TapGestureDetectorContainer::iterator iter = mTapGestureDetectors.begin(), endIter = mTapGestureDetectors.end(); iter != endIter; ++iter )
+ {
+ TapGestureDetector* detector(*iter);
+
+ if( detector )
+ {
+ const unsigned int minTapsRequired = detector->GetMinimumTapsRequired();
+ const unsigned int maxTapsRequired = detector->GetMaximumTapsRequired();
+ const unsigned int touchesRequired = detector->GetTouchesRequired();
+
+ minTaps = minTapsRequired < minTaps ? minTapsRequired : minTaps;
+ maxTaps = maxTapsRequired > maxTaps ? maxTapsRequired : maxTaps;
+ minTouches = touchesRequired < minTouches ? touchesRequired : minTouches;
+ maxTouches = touchesRequired > maxTouches ? touchesRequired : maxTouches;
+ }
+ }
+
+ if ( (minTaps != mMinTapsRequired)||(maxTaps != mMaxTapsRequired) ||
+ (minTouches != mMinTouchesRequired)||(maxTouches != mMaxTouchesRequired) )
+ {
+ TapGestureRequest request;
+ request.minTaps = mMinTapsRequired = minTaps;
+ request.maxTaps = mMaxTapsRequired = maxTaps;
+ request.minTouches = mMinTouchesRequired = minTouches;
+ request.maxTouches = mMaxTouchesRequired = maxTouches;
+
+ mGestureRecognizer->Update(request);
+ }
+}
+
+bool TapGestureProcessor::CheckGestureDetector( GestureDetector* detector, Actor* actor )
+{
+ DALI_ASSERT_DEBUG( mCurrentTapEvent );
+
+ TapGestureDetector* tapDetector ( static_cast< TapGestureDetector* >( detector ) );
+
+ return ( ( tapDetector->GetMinimumTapsRequired() <= mCurrentTapEvent->numberOfTaps ) && ( tapDetector->GetMaximumTapsRequired() >= mCurrentTapEvent->numberOfTaps ) ) &&
+ ( tapDetector->GetTouchesRequired() == mCurrentTapEvent->numberOfTouches );
+}
+
+void TapGestureProcessor::EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates )
+{
+ DALI_ASSERT_DEBUG( mCurrentTapEvent );
+
+ EmitTapSignal( actor, gestureDetectors, *mCurrentTapEvent, actorCoordinates );
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_TAP_GESTURE_EVENT_PROCESSOR_H
+#define DALI_INTERNAL_TAP_GESTURE_EVENT_PROCESSOR_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h>
+#include <dali/internal/event/events/gesture-processor.h>
+#include <dali/internal/event/events/actor-observer.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+class Scene;
+class Stage;
+class Actor;
+
+struct GestureEvent;
+struct TapGestureEvent;
+
+/**
+ * Tap Gesture Event Processing:
+ *
+ * When we receive a tap gesture event, we do the following:
+ * - Find the actor that requires a tap where the tap occurred.
+ * - Emit the gesture if the tap gesture event satisfies the detector conditions.
+ */
+class TapGestureProcessor : public GestureProcessor, public RecognizerObserver<TapGestureEvent>
+{
+public:
+
+ /**
+ * Create a tap gesture processor.
+ */
+ TapGestureProcessor();
+
+ /**
+ * Non-virtual destructor; TapGestureProcessor is not a base class
+ */
+ ~TapGestureProcessor();
+
+public: // To be called by GestureEventProcessor
+
+ /**
+ * This method is called whenever a tap gesture event occurs.
+ * @param[in] scene The scene the tap gesture event occurs in.
+ * @param[in] tapEvent The event that has occurred.
+ */
+ void Process( Scene& scene, const TapGestureEvent& event);
+
+ /**
+ * Adds a gesture detector to this gesture processor.
+ * If this is the first gesture detector being added, then this method registers the required
+ * gesture with the adaptor.
+ * @param[in] gestureDetector The gesture detector being added.
+ */
+ void AddGestureDetector(TapGestureDetector* gestureDetector, Scene& scene);
+
+ /**
+ * Removes the specified gesture detector from this gesture processor. If, after removing this
+ * gesture detector, there are no more gesture detectors registered, then this method unregisters
+ * the gesture from the adaptor.
+ * @param[in] gestureDetector The gesture detector being removed.
+ */
+ void RemoveGestureDetector(TapGestureDetector* gestureDetector);
+
+ /**
+ * This method updates the gesture detection parameters.
+ * @param[in] gestureDetector The gesture detector that has been updated.
+ */
+ void GestureDetectorUpdated(TapGestureDetector* gestureDetector);
+
+private:
+
+ // Undefined
+ TapGestureProcessor(const TapGestureProcessor&);
+ TapGestureProcessor& operator=(const TapGestureProcessor& rhs);
+
+private:
+
+ /**
+ * Iterates through our GestureDetectors and determines if we need to ask the adaptor to update
+ * its detection policy. If it does, it sends the appropriate gesture update request to adaptor.
+ */
+ void UpdateDetection();
+
+ // GestureProcessor overrides
+
+ /**
+ * @copydoc GestureProcessor::OnGesturedActorStageDisconnection()
+ */
+ void OnGesturedActorStageDisconnection() { /* Nothing to do */ }
+
+ /**
+ * @copydoc GestureProcessor::CheckGestureDetector()
+ */
+ bool CheckGestureDetector( GestureDetector* detector, Actor* actor );
+
+ /**
+ * @copydoc GestureProcessor::EmitGestureSignal()
+ */
+ void EmitGestureSignal( Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates );
+
+private:
+
+ TapGestureDetectorContainer mTapGestureDetectors;
+
+ unsigned int mMinTapsRequired;
+ unsigned int mMaxTapsRequired;
+ unsigned int mMinTouchesRequired;
+ unsigned int mMaxTouchesRequired;
+
+ ActorObserver mCurrentTapActor; ///< Observer for the current gesture actor
+ const TapGestureEvent* mCurrentTapEvent; ///< Pointer to current TapEvent, used when calling ProcessAndEmit()
+ bool mPossibleProcessed; ///< Indication of whether we've processed a touch down for this gestuee
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TAP_GESTURE_EVENT_PROCESSOR_H
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/math/vector2.h>
+
+#include <dali/integration-api/events/touch-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/gesture-requests.h>
+#include <dali/internal/event/common/scene-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+// TODO: Set these according to DPI
+const float MAXIMUM_MOTION_ALLOWED = 20.0f;
+const unsigned long MAXIMUM_TIME_ALLOWED = 500u;
+} // unnamed namespace
+
+TapGestureRecognizer::TapGestureRecognizer( Observer& observer, Vector2 screenSize, const TapGestureRequest& request)
+: GestureRecognizer( screenSize, Gesture::Tap ),
+ mObserver(observer),
+ mState(Clear),
+ mMinimumTapsRequired(request.minTaps),
+ mMaximumTapsRequired(request.maxTaps),
+ mTapsRegistered(0),
+ mTouchPosition(),
+ mTouchTime(0u),
+ mLastTapTime(0u)
+{
+}
+
+TapGestureRecognizer::~TapGestureRecognizer()
+{
+}
+
+void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
+{
+ if (event.GetPointCount() == 1)
+ {
+ const Integration::Point& point = event.points[0];
+ PointState::Type pointState = point.GetState();
+
+ switch (mState)
+ {
+ case Clear:
+ {
+ if (pointState == PointState::DOWN)
+ {
+ SetupForTouchDown( event, point );
+ }
+ break;
+ }
+
+ case Touched:
+ {
+ uint32_t deltaBetweenTouchDownTouchUp = event.time - mTouchTime;
+
+ if ( pointState == PointState::UP )
+ {
+ if ( deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED )
+ {
+ mLastTapTime = mTouchTime;
+ EmitSingleTap( event.time, point );
+ mState = Registered;
+ }
+ else
+ {
+ mState = Clear;
+ }
+ }
+ else if (pointState == PointState::INTERRUPTED)
+ {
+ mState = Clear;
+ }
+ break;
+ }
+
+ case Registered:
+ {
+ if ( pointState == PointState::UP )
+ {
+ uint32_t deltaBetweenTouchDownTouchUp = event.time - mTouchTime;
+
+ if ( deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED )
+ {
+ // This is a possible multiple tap, so has it been quick enough?
+ uint32_t timeDelta = event.time - mLastTapTime;
+ if( timeDelta > MAXIMUM_TIME_ALLOWED ) // If exceeded time between taps then just a single tap
+ {
+ mLastTapTime = event.time;
+ EmitSingleTap(event.time, point);
+ mState = Registered;
+ }
+ else
+ {
+ ++mTapsRegistered;
+ EmitGesture( Gesture::Started, event.time );
+ mState = Clear;
+ }
+ }
+ else // Delta between touch down and touch up too long to be considered a Tap event
+ {
+ mState = Clear;
+ }
+ }
+ else if (pointState == PointState::DOWN)
+ {
+ const Vector2& screen( point.GetScreenPosition() );
+ Vector2 distanceDelta(std::abs(mTouchPosition.x - screen.x),
+ std::abs(mTouchPosition.y - screen.y));
+
+ uint32_t timeDelta = event.time - mLastTapTime;
+
+ if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
+ distanceDelta.y > MAXIMUM_MOTION_ALLOWED ||
+ timeDelta > MAXIMUM_TIME_ALLOWED )
+ {
+ SetupForTouchDown( event, point );
+ }
+ else
+ {
+ EmitPossibleState( event );
+ }
+ }
+ break;
+ }
+
+ case Failed:
+ default:
+ {
+ mState = Clear;
+ break;
+ }
+ }
+ }
+ else
+ {
+ mState = Failed;
+
+ // We have entered a multi-touch event so emit registered gestures if required.
+ EmitGesture(Gesture::Started, event.time);
+ }
+}
+
+void TapGestureRecognizer::SetupForTouchDown( const Integration::TouchEvent& event, const Integration::Point& point )
+{
+ mTouchPosition = point.GetScreenPosition();
+ mTouchTime = event.time;
+ mLastTapTime = 0u;
+ mTapsRegistered = 0;
+ mState = Touched;
+ EmitPossibleState( event );
+}
+
+void TapGestureRecognizer::EmitPossibleState( const Integration::TouchEvent& event )
+{
+ TapGestureEvent tapEvent( Gesture::Possible );
+ tapEvent.point = mTouchPosition;
+ tapEvent.time = event.time;
+
+ ProcessEvent( tapEvent );
+}
+
+
+void TapGestureRecognizer::Update(const GestureRequest& request)
+{
+ const TapGestureRequest& tap = static_cast<const TapGestureRequest&>(request);
+
+ mMinimumTapsRequired = tap.minTaps;
+ mMaximumTapsRequired = tap.maxTaps;
+}
+
+void TapGestureRecognizer::EmitGesture( Gesture::State state, uint32_t time )
+{
+ if ( (state == Gesture::Cancelled) ||
+ (mTapsRegistered >= mMinimumTapsRequired && mTapsRegistered <= mMaximumTapsRequired) )
+
+ {
+ TapGestureEvent event( state );
+ EmitTap( time, event );
+ }
+}
+
+void TapGestureRecognizer::EmitSingleTap( uint32_t time, const Integration::Point& point )
+{
+ TapGestureEvent event( Gesture::Started );
+ const Vector2& screen( point.GetScreenPosition() );
+ Vector2 distanceDelta(std::abs(mTouchPosition.x - screen.x),
+ std::abs(mTouchPosition.y - screen.y));
+
+ if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
+ distanceDelta.y > MAXIMUM_MOTION_ALLOWED )
+ {
+ event.state = Gesture::Cancelled;
+ }
+ mTapsRegistered = 1u;
+ EmitTap( time, event );
+}
+
+void TapGestureRecognizer::EmitTap( uint32_t time, TapGestureEvent& event )
+{
+ event.numberOfTaps = mTapsRegistered;
+ event.point = mTouchPosition;
+ event.time = time;
+
+ ProcessEvent( event );
+}
+
+void TapGestureRecognizer::ProcessEvent( TapGestureEvent& event )
+{
+ if( mScene )
+ {
+ // Create another handle so the recognizer cannot be destroyed during process function
+ GestureRecognizerPtr recognizerHandle = this;
+ mObserver.Process(*mScene, event);
+ }
+}
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_EVENT_EVENTS_TAP_GESTURE_RECOGNIZER_H
+#define DALI_INTERNAL_EVENT_EVENTS_TAP_GESTURE_RECOGNIZER_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <cstdint>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/events/point.h>
+
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/events/gesture-recognizer.h>
+#include <dali/internal/event/events/tap-gesture/tap-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+}
+
+namespace Internal
+{
+struct TapGestureRequest;
+
+/**
+ * When given a set of touch events, this detector attempts to determine if a tap gesture has taken place.
+ */
+class TapGestureRecognizer : public GestureRecognizer
+{
+public:
+
+ using Observer = RecognizerObserver<TapGestureEvent>;
+
+ /**
+ * Constructor
+ * @param[in] coreEventInterface Used to send events to Core.
+ * @param[in] screenSize The size of the screen.
+ * @param[in] request The tap gesture request.
+ */
+ TapGestureRecognizer(Observer& observer, Vector2 screenSize, const TapGestureRequest& request);
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~TapGestureRecognizer();
+
+public:
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
+ */
+ virtual void SendEvent(const Integration::TouchEvent& event);
+
+ /**
+ * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
+ */
+ virtual void Update(const GestureRequest& request);
+
+private:
+
+ /**
+ * Checks if registered taps are within required bounds and emits tap gesture if they are.
+ *
+ * @param[in] state current state of incomplete gesture
+ * @param[in] time time of this latest touch event
+ */
+ void EmitGesture( Gesture::State state, uint32_t time );
+
+ /**
+ * Initialises tap gesture detector for next tap sequence
+ *
+ * @param[in] event registered touch event
+ * @param[in] point position touch event occurred
+ */
+ void SetupForTouchDown( const Integration::TouchEvent& event, const Integration::Point& point );
+
+ /**
+ * Emit a touch down event for hit testing
+ *
+ * @param[in] event registered touch event
+ */
+ void EmitPossibleState( const Integration::TouchEvent& event );
+
+ /**
+ * Force a touch event sequence to be treated as a single tap
+ *
+ * @param[in] time time of this latest touch event
+ * @param[in] point position touch event occurred
+ */
+ void EmitSingleTap( uint32_t time, const Integration::Point& point );
+
+ /**
+ * Emit a tap event
+ *
+ * @param[in] time time of this latest touch event
+ * @param[in] event registered touch event
+ */
+ void EmitTap( uint32_t time, TapGestureEvent& event );
+
+ /**
+ * Send the event for processing
+ *
+ * @param[in] tap event for processing
+ */
+ void ProcessEvent( TapGestureEvent& event );
+
+private:
+
+ // Reference to the gesture processor for this recognizer
+ Observer& mObserver;
+
+ /**
+ * Internal state machine.
+ */
+ enum State
+ {
+ Clear, ///< No gesture detected.
+ Touched, ///< User is touching the screen.
+ Registered, ///< At least one tap has been registered.
+ Failed, ///< Gesture has failed.
+ };
+
+ State mState; ///< Current state of the detector.
+
+ int mMinimumTapsRequired; ///< Minimum number of taps required.
+ int mMaximumTapsRequired; ///< Maximum number of taps required.
+ int mTapsRegistered; ///< In current detection, the number of taps registered.
+
+ Vector2 mTouchPosition; ///< The initial touch down position.
+ uint32_t mTouchTime; ///< The initial touch down time.
+ uint32_t mLastTapTime; ///< Time last tap gesture was registered
+
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+
+#endif // DALI_INTERNAL_EVENT_EVENTS_TAP_GESTURE_RECOGNIZER_H
${internal_src_dir}/event/events/gesture-processor.cpp
${internal_src_dir}/event/events/hit-test-algorithm-impl.cpp
${internal_src_dir}/event/events/hover-event-processor.cpp
- ${internal_src_dir}/event/events/long-press-gesture-detector-impl.cpp
- ${internal_src_dir}/event/events/long-press-gesture-event.cpp
- ${internal_src_dir}/event/events/long-press-gesture-processor.cpp
- ${internal_src_dir}/event/events/long-press-gesture-recognizer.cpp
${internal_src_dir}/event/events/wheel-event-processor.cpp
${internal_src_dir}/event/events/multi-point-event-util.cpp
- ${internal_src_dir}/event/events/pan-gesture-detector-impl.cpp
- ${internal_src_dir}/event/events/pan-gesture-event.cpp
- ${internal_src_dir}/event/events/pan-gesture-processor.cpp
- ${internal_src_dir}/event/events/pan-gesture-recognizer.cpp
- ${internal_src_dir}/event/events/pinch-gesture-detector-impl.cpp
- ${internal_src_dir}/event/events/pinch-gesture-event.cpp
- ${internal_src_dir}/event/events/pinch-gesture-processor.cpp
- ${internal_src_dir}/event/events/pinch-gesture-recognizer.cpp
- ${internal_src_dir}/event/events/tap-gesture-detector-impl.cpp
- ${internal_src_dir}/event/events/tap-gesture-event.cpp
- ${internal_src_dir}/event/events/tap-gesture-processor.cpp
- ${internal_src_dir}/event/events/tap-gesture-recognizer.cpp
${internal_src_dir}/event/events/touch-data-impl.cpp
${internal_src_dir}/event/events/touch-event-processor.cpp
+ ${internal_src_dir}/event/events/long-press-gesture/long-press-gesture-detector-impl.cpp
+ ${internal_src_dir}/event/events/long-press-gesture/long-press-gesture-event.cpp
+ ${internal_src_dir}/event/events/long-press-gesture/long-press-gesture-processor.cpp
+ ${internal_src_dir}/event/events/long-press-gesture/long-press-gesture-recognizer.cpp
+ ${internal_src_dir}/event/events/pan-gesture/pan-gesture-detector-impl.cpp
+ ${internal_src_dir}/event/events/pan-gesture/pan-gesture-event.cpp
+ ${internal_src_dir}/event/events/pan-gesture/pan-gesture-processor.cpp
+ ${internal_src_dir}/event/events/pan-gesture/pan-gesture-recognizer.cpp
+ ${internal_src_dir}/event/events/pinch-gesture/pinch-gesture-detector-impl.cpp
+ ${internal_src_dir}/event/events/pinch-gesture/pinch-gesture-event.cpp
+ ${internal_src_dir}/event/events/pinch-gesture/pinch-gesture-processor.cpp
+ ${internal_src_dir}/event/events/pinch-gesture/pinch-gesture-recognizer.cpp
+ ${internal_src_dir}/event/events/tap-gesture/tap-gesture-detector-impl.cpp
+ ${internal_src_dir}/event/events/tap-gesture/tap-gesture-event.cpp
+ ${internal_src_dir}/event/events/tap-gesture/tap-gesture-processor.cpp
+ ${internal_src_dir}/event/events/tap-gesture/tap-gesture-recognizer.cpp
${internal_src_dir}/event/images/bitmap-packed-pixel.cpp
${internal_src_dir}/event/images/bitmap-compressed.cpp
${internal_src_dir}/event/images/image-impl.cpp
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
#include <dali/public-api/events/long-press-gesture-detector.h>
// INTERNAL INCLUDES
-#include <dali/internal/event/events/long-press-gesture-detector-impl.h>
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.h>
namespace Dali
{
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
#include <dali/public-api/events/pan-gesture-detector.h>
// INTERNAL INCLUDES
-#include <dali/internal/event/events/pan-gesture-detector-impl.h>
+#include <dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.h>
namespace Dali
{
/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
#include <dali/public-api/events/pinch-gesture-detector.h>
// INTERNAL INCLUDES
-#include <dali/internal/event/events/pinch-gesture-detector-impl.h>
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.h>
namespace Dali
{
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
#include <dali/public-api/events/tap-gesture-detector.h>
// INTERNAL INCLUDES
-#include <dali/internal/event/events/tap-gesture-detector-impl.h>
+#include <dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h>
namespace Dali
{