From: joogab.yun Date: Mon, 15 Apr 2024 07:02:41 +0000 (+0900) Subject: [Tizen] A new gesture recognition method. X-Git-Tag: accepted/tizen/8.0/unified/20240704.174815~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=cfc9f66316355f0c17192313ed138d41de0255b5;p=platform%2Fcore%2Fuifw%2Fdali-core.git [Tizen] A new gesture recognition method. 1. Add HandleEvent(actor, touch) api at GestureDetector This is an API that recognizes gestures by passing the actor for which the gesture should be recognized and the touch event to GestureDetector. You can use it in the touch event callback. This should be used with SetGeometryHittestEnabled(true). 2. To support multi-gesture, we hit-test each multi-touch Change-Id: I6ea2d42fe54d1ebd7ce8a1844f91434765f9b478 --- diff --git a/automated-tests/src/dali/utc-Dali-GeoHitTestAlgorithm.cpp b/automated-tests/src/dali/utc-Dali-GeoHitTestAlgorithm.cpp index bc7d30b..e122a5b 100644 --- a/automated-tests/src/dali/utc-Dali-GeoHitTestAlgorithm.cpp +++ b/automated-tests/src/dali/utc-Dali-GeoHitTestAlgorithm.cpp @@ -480,11 +480,11 @@ int UtcDaliGeoHitTestAlgorithmOverlay(void) DALI_TEST_CHECK(results.actor == red); DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 1.0f / 12.0f, actorSize.y * 9.0f / 12.0f), TEST_LOCATION); - //Hit in the intersection red, green. Should pick the green actor since red is outside the scope of its parent. + //Hit in the intersection red, green. Should pick the red actor since it is an child of overlay. HitTest(stage, Vector2(stageSize.x * 15.0f / 24.0f, stageSize.y * 11.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true); tet_printf("%d %d %d , %f %f\n", results.actor == red ? 1 : 0, results.actor == green ? 1 : 0, results.actor == blue ? 1 : 0, results.actorCoordinates.x, results.actorCoordinates.y); - DALI_TEST_CHECK(results.actor == green); - DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 5.0f / 12.0f, actorSize.y * 1.0f / 12.0f), TEST_LOCATION); + DALI_TEST_CHECK(results.actor == red); + DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 3.0f / 12.0f, actorSize.y * 11.0f / 12.0f), TEST_LOCATION); //Hit in the intersection blue, green. Should pick the blue actor since it is an overlay. HitTest(stage, Vector2(stageSize.x * 11.0f / 24.0f, stageSize.y * 13.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true); diff --git a/automated-tests/src/dali/utc-Dali-GeoTouchProcessing.cpp b/automated-tests/src/dali/utc-Dali-GeoTouchProcessing.cpp index 4d02050..40f4afc 100644 --- a/automated-tests/src/dali/utc-Dali-GeoTouchProcessing.cpp +++ b/automated-tests/src/dali/utc-Dali-GeoTouchProcessing.cpp @@ -510,13 +510,13 @@ int UtcDaliGeoTouchEventEmitEmpty(void) try { // Emit an empty TouchEvent - Integration::TouchEvent event; - application.ProcessEvent(event); + Integration::TouchEvent touchEvent; + application.ProcessEvent(touchEvent); tet_result(TET_FAIL); } catch(Dali::DaliException& e) { - DALI_TEST_ASSERT(e, "!event.points.empty()", TEST_LOCATION); + DALI_TEST_ASSERT(e, "!touchEvent.points.empty()", TEST_LOCATION); } END_TEST; } @@ -636,7 +636,7 @@ int UtcDaliGeoTouchEventParentConsumer(void) DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION); DALI_TEST_EQUALS(1u, data.receivedTouch.GetPointCount(), TEST_LOCATION); DALI_TEST_EQUALS(1u, rootData.receivedTouch.GetPointCount(), TEST_LOCATION); - DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION); + DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION); DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION); DALI_TEST_EQUALS(screenCoordinates, data.receivedTouch.points[0].screen, TEST_LOCATION); DALI_TEST_EQUALS(screenCoordinates, rootData.receivedTouch.points[0].screen, TEST_LOCATION); @@ -722,7 +722,7 @@ int UtcDaliGeoTouchEventInterruptedParentConsumer(void) application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f))); DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION); - DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION); + DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION); DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION); DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor); DALI_TEST_CHECK(actor == rootData.receivedTouch.points[0].hitActor); @@ -742,7 +742,7 @@ int UtcDaliGeoTouchEventInterruptedParentConsumer(void) application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f))); DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION); - DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION); + DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION); DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION); data.Reset(); rootData.Reset(); @@ -840,7 +840,7 @@ int UtcDaliGeoTouchEventActorBecomesInsensitiveParentConsumer(void) application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f))); DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION); - DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION); + DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION); DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION); DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor); DALI_TEST_CHECK(actor == rootData.receivedTouch.points[0].hitActor); @@ -1612,7 +1612,7 @@ int UtcDaliGeoTouchEventActorRemovedFromSceneDifferentConsumer(void) // Emit a down signal application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f))); DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); - DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION); + DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION); DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor); DALI_TEST_CHECK(actor == data.touchedActor); DALI_TEST_EQUALS(true, parentData.functorCalled, TEST_LOCATION); @@ -1708,12 +1708,12 @@ int UtcDaliGeoTouchEventInterruptedDifferentConsumer(void) // Emit a down signal application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f))); DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); - DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION); + DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION); DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor); DALI_TEST_CHECK(actor == data.touchedActor); DALI_TEST_EQUALS(true, parentData.functorCalled, TEST_LOCATION); - DALI_TEST_EQUALS(PointState::DOWN, parentData.receivedTouch.points[0].state, TEST_LOCATION); - DALI_TEST_CHECK(actor == parentData.receivedTouch.points[0].hitActor); + DALI_TEST_EQUALS(PointState::INTERRUPTED, parentData.receivedTouch.points[0].state, TEST_LOCATION); + DALI_TEST_CHECK(parent == parentData.receivedTouch.points[0].hitActor); DALI_TEST_CHECK(parent == parentData.touchedActor); DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION); DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION); @@ -2569,44 +2569,3 @@ int UtcDaliGeoTouchEventDispatchTouchMotionPropertySet(void) END_TEST; } - -int UtcDaliGeoTouchDownDifferentUp(void) -{ - TestApplication application; - - Actor actor = Actor::New(); - actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); - actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); - application.GetScene().Add(actor); - - // Render and notify - application.SendNotification(); - application.Render(); - - // Connect to actor's touched signal - SignalData data; - TouchEventFunctor functor(data); - actor.TouchedSignal().Connect(&application, functor); - - // Emit a down signal - application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f))); - DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); - DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION); - data.Reset(); - - // Emit a signal outside the actor, we should NOT be signalled. - application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(200.0f, 200.0f /* Outside actor */))); - application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(210.0f, 200.0f /* Outside actor */))); - application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(220.0f, 200.0f /* Outside actor */))); - DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); - data.Reset(); - - // Set the geometry hit test on - application.GetScene().SetGeometryHittestEnabled(true); - - // ...and emit an up event outside of the actor's bounds, we should get an interrupted signal - application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(200.0f, 200.0f))); - DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); - DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION); - END_TEST; -} \ No newline at end of file diff --git a/automated-tests/src/dali/utc-Dali-GestureDetector.cpp b/automated-tests/src/dali/utc-Dali-GestureDetector.cpp index 5221435..e12bbdb 100644 --- a/automated-tests/src/dali/utc-Dali-GestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-GestureDetector.cpp @@ -17,6 +17,12 @@ #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -34,6 +40,94 @@ void utc_dali_gesture_detector_cleanup(void) test_return_value = TET_PASS; } +namespace +{ +// Stores data that is populated in the callback and will be read by the TET cases +struct SignalData +{ + SignalData() + : functorCalled(false), + voidFunctorCalled(false), + receivedGesture(), + pressedActor() + { + } + + void Reset() + { + functorCalled = false; + voidFunctorCalled = false; + + receivedGesture.Reset(); + + pressedActor.Reset(); + } + + bool functorCalled; + bool voidFunctorCalled; + Gesture receivedGesture; + Actor pressedActor; +}; + +// Functor that sets the data when called +struct GestureReceivedFunctor +{ + GestureReceivedFunctor(SignalData& data) + : signalData(data) + { + } + + void operator()(Actor actor, const Gesture& gesture) + { + signalData.functorCalled = true; + signalData.receivedGesture = gesture; + signalData.pressedActor = actor; + } + + void operator()() + { + signalData.voidFunctorCalled = true; + } + + SignalData& signalData; +}; + +Integration::TouchEvent GenerateSingleTouch(PointState::Type state, const Vector2& screenPosition, int source, uint32_t time) +{ + Integration::TouchEvent touchEvent; + Integration::Point point; + point.SetState(state); + point.SetDeviceId(4); + point.SetScreenPosition(screenPosition); + point.SetDeviceClass(Device::Class::TOUCH); + point.SetDeviceSubclass(Device::Subclass::NONE); + point.SetMouseButton(static_cast(source)); + touchEvent.points.push_back(point); + touchEvent.time = time; + return touchEvent; +} + +Integration::TouchEvent GenerateDoubleTouch(PointState::Type stateA, const Vector2& screenPositionA, PointState::Type stateB, const Vector2& screenPositionB, uint32_t time) +{ + Integration::TouchEvent touchEvent; + Integration::Point point; + point.SetState(stateA); + point.SetDeviceId(4); + point.SetScreenPosition(screenPositionA); + point.SetDeviceClass(Device::Class::TOUCH); + point.SetDeviceSubclass(Device::Subclass::NONE); + touchEvent.points.push_back(point); + point.SetScreenPosition(screenPositionB); + point.SetState(stateB); + point.SetDeviceId(7); + touchEvent.points.push_back(point); + touchEvent.time = time; + return touchEvent; +} + +} + + int UtcDaliGestureDetectorConstructorN(void) { TestApplication application; @@ -501,3 +595,165 @@ int UtcDaliGestureDetectorRegisterProperty(void) END_TEST; } + +int UtcDaliGestureDetectorCancelProcessing(void) +{ + TestApplication application; + Integration::Scene scene = application.GetScene(); + RenderTaskList taskList = scene.GetRenderTaskList(); + Dali::RenderTask task = taskList.GetTask(0); + + LongPressGestureDetector longDetector = LongPressGestureDetector::New(); + TapGestureDetector tapDetector = TapGestureDetector::New(); + PanGestureDetector panDetector = PanGestureDetector::New(); + PinchGestureDetector pinchDetector = PinchGestureDetector::New(); + RotationGestureDetector rotationDetector = RotationGestureDetector::New(); + + Actor actor = Actor::New(); + actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + application.GetScene().Add(actor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + SignalData tData; + GestureReceivedFunctor tFunctor(tData); + + SignalData pData; + GestureReceivedFunctor pFunctor(pData); + + longDetector.DetectedSignal().Connect(&application, functor); + tapDetector.DetectedSignal().Connect(&application, tFunctor); + pinchDetector.DetectedSignal().Connect(&application, pFunctor); + + Integration::TouchEvent tp = GenerateSingleTouch(PointState::DOWN, Vector2(50.0f, 50.0f), 1, 100); + Internal::TouchEventPtr touchEventImpl(new Internal::TouchEvent(100)); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + Dali::TouchEvent touchEventHandle(touchEventImpl.Get()); + longDetector.HandleEvent(actor, touchEventHandle); + tapDetector.HandleEvent(actor, touchEventHandle); + panDetector.HandleEvent(actor, touchEventHandle); + pinchDetector.HandleEvent(actor, touchEventHandle); + rotationDetector.HandleEvent(actor, touchEventHandle); + + TestTriggerLongPress(application); + longDetector.CancelAllOtherGestureDetectors(); + + + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(false, tData.functorCalled, TEST_LOCATION); + data.Reset(); + tData.Reset(); + + tp = GenerateSingleTouch(PointState::UP, Vector2(50.0f, 50.0f), 1, 650); + touchEventImpl = new Internal::TouchEvent(650); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + longDetector.HandleEvent(actor, touchEventHandle); + tapDetector.HandleEvent(actor, touchEventHandle); + panDetector.HandleEvent(actor, touchEventHandle); + pinchDetector.HandleEvent(actor, touchEventHandle); + rotationDetector.HandleEvent(actor, touchEventHandle); + + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(false, tData.functorCalled, TEST_LOCATION); + data.Reset(); + tData.Reset(); + + longDetector.SetTouchesRequired(2, 2); + + tp = GenerateDoubleTouch(PointState::DOWN, Vector2(2.0f, 20.0f), PointState::DOWN, Vector2(38.0f, 20.0f), 100); + touchEventImpl = new Internal::TouchEvent(100); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + longDetector.HandleEvent(actor, touchEventHandle); + tapDetector.HandleEvent(actor, touchEventHandle); + panDetector.HandleEvent(actor, touchEventHandle); + pinchDetector.HandleEvent(actor, touchEventHandle); + rotationDetector.HandleEvent(actor, touchEventHandle); + + pinchDetector.CancelAllOtherGestureDetectors(); + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 150); + touchEventImpl = new Internal::TouchEvent(150); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + longDetector.HandleEvent(actor, touchEventHandle); + tapDetector.HandleEvent(actor, touchEventHandle); + panDetector.HandleEvent(actor, touchEventHandle); + pinchDetector.HandleEvent(actor, touchEventHandle); + rotationDetector.HandleEvent(actor, touchEventHandle); + + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 200); + touchEventImpl = new Internal::TouchEvent(200); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + longDetector.HandleEvent(actor, touchEventHandle); + tapDetector.HandleEvent(actor, touchEventHandle); + panDetector.HandleEvent(actor, touchEventHandle); + pinchDetector.HandleEvent(actor, touchEventHandle); + rotationDetector.HandleEvent(actor, touchEventHandle); + + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 250); + touchEventImpl = new Internal::TouchEvent(250); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + longDetector.HandleEvent(actor, touchEventHandle); + tapDetector.HandleEvent(actor, touchEventHandle); + panDetector.HandleEvent(actor, touchEventHandle); + pinchDetector.HandleEvent(actor, touchEventHandle); + rotationDetector.HandleEvent(actor, touchEventHandle); + + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 300); + touchEventImpl = new Internal::TouchEvent(300); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + longDetector.HandleEvent(actor, touchEventHandle); + tapDetector.HandleEvent(actor, touchEventHandle); + panDetector.HandleEvent(actor, touchEventHandle); + pinchDetector.HandleEvent(actor, touchEventHandle); + rotationDetector.HandleEvent(actor, touchEventHandle); + + + tp = GenerateDoubleTouch(PointState::UP, Vector2(10.0f, 20.0f), PointState::UP, Vector2(30.0f, 20.0f), 350); + touchEventImpl = new Internal::TouchEvent(350); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + longDetector.HandleEvent(actor, touchEventHandle); + tapDetector.HandleEvent(actor, touchEventHandle); + panDetector.HandleEvent(actor, touchEventHandle); + pinchDetector.HandleEvent(actor, touchEventHandle); + rotationDetector.HandleEvent(actor, touchEventHandle); + + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(false, tData.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(true, pData.functorCalled, TEST_LOCATION); + data.Reset(); + tData.Reset(); + pData.Reset(); + + END_TEST; +} diff --git a/automated-tests/src/dali/utc-Dali-LongPressGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-LongPressGestureDetector.cpp index 3ed67dd..31262cf 100644 --- a/automated-tests/src/dali/utc-Dali-LongPressGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-LongPressGestureDetector.cpp @@ -19,8 +19,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -131,6 +134,19 @@ struct TouchEventFunctor } }; +Integration::TouchEvent GenerateSingleTouch(PointState::Type state, const Vector2& screenPosition, uint32_t time) +{ + Integration::TouchEvent touchEvent; + Integration::Point point; + point.SetState(state); + point.SetDeviceId(4); + point.SetScreenPosition(screenPosition); + point.SetDeviceClass(Device::Class::TOUCH); + point.SetDeviceSubclass(Device::Subclass::NONE); + touchEvent.points.push_back(point); + touchEvent.time = time; + return touchEvent; +} } // namespace /////////////////////////////////////////////////////////////////////////////// @@ -1121,3 +1137,93 @@ int UtcDaliLongPressGestureWhenGesturePropargation(void) END_TEST; } + +int UtcDaliLongPressGestureSignalWithGeometryHittest(void) +{ + TestApplication application; + application.GetScene().SetGeometryHittestEnabled(true); + + Actor actor = Actor::New(); + actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + LongPressGestureDetector detector = LongPressGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Do a long press inside actor's area + TestGenerateLongPress(application, 50.0f, 50.0f); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(1u, data.receivedGesture.GetNumberOfTouches(), TEST_LOCATION); + DALI_TEST_EQUALS(Vector2(50.0f, 50.0f), data.receivedGesture.GetLocalPoint(), 0.1, TEST_LOCATION); + TestEndLongPress(application, 50.0f, 50.0f); + + // Detach actor + detector.DetachAll(); + + // Ensure we are no longer signalled + data.Reset(); + TestGenerateLongPress(application, 20.0f, 20.0f); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + TestEndLongPress(application, 50.0f, 50.0f); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + END_TEST; +} + +int UtcDaliLongPressGestureHandleEvent(void) +{ + TestApplication application; + Integration::Scene scene = application.GetScene(); + RenderTaskList taskList = scene.GetRenderTaskList(); + Dali::RenderTask task = taskList.GetTask(0); + + Actor parentActor = Actor::New(); + parentActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + parentActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + Actor childActor = Actor::New(); + childActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + parentActor.Add(childActor); + application.GetScene().Add(parentActor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData pData; + GestureReceivedFunctor pFunctor(pData); + + LongPressGestureDetector parentDetector = LongPressGestureDetector::New(); + parentDetector.DetectedSignal().Connect(&application, pFunctor); + + Integration::TouchEvent tp = GenerateSingleTouch(PointState::DOWN, Vector2(50.0f, 50.0f), 100); + Internal::TouchEventPtr touchEventImpl(new Internal::TouchEvent(100)); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + Dali::TouchEvent touchEventHandle(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + TestTriggerLongPress(application); + + tp = GenerateSingleTouch(PointState::UP, Vector2(50.0f, 50.0f), 150); + touchEventImpl = new Internal::TouchEvent(150); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + DALI_TEST_EQUALS(true, pData.functorCalled, TEST_LOCATION); + pData.Reset(); + + END_TEST; +} diff --git a/automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp index a1d4483..3d6a332 100644 --- a/automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp @@ -19,9 +19,12 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -120,6 +123,25 @@ struct UnstageActorFunctor : public GestureReceivedFunctor Integration::Scene scene; }; +// Functor that removes the gestured actor from stage +struct PropagationActorFunctor : public GestureReceivedFunctor +{ + PropagationActorFunctor(SignalData& data, bool propagation) + : GestureReceivedFunctor(data), + propagation(propagation) + { + } + + void operator()(Actor actor, const PanGesture& pan) + { + GestureReceivedFunctor::operator()(actor, pan); + Dali::DevelActor::SetNeedGesturePropagation(actor, propagation); + } + + bool propagation; +}; + + // Data for constraints struct ConstraintData { @@ -199,6 +221,19 @@ PanGesture GeneratePan(unsigned int time, return pan; } +Integration::TouchEvent GenerateSingleTouch(PointState::Type state, const Vector2& screenPosition, uint32_t time) +{ + Integration::TouchEvent touchEvent; + Integration::Point point; + point.SetState(state); + point.SetDeviceId(4); + point.SetScreenPosition(screenPosition); + point.SetDeviceClass(Device::Class::TOUCH); + point.SetDeviceSubclass(Device::Subclass::NONE); + touchEvent.points.push_back(point); + touchEvent.time = time; + return touchEvent; +} } // namespace /////////////////////////////////////////////////////////////////////////////// @@ -3042,3 +3077,281 @@ int UtcDaliPanGestureWhenGesturePropargation(void) END_TEST; } + +int UtcDaliPanGestureHandleEvent(void) +{ + TestApplication application; + Integration::Scene scene = application.GetScene(); + RenderTaskList taskList = scene.GetRenderTaskList(); + Dali::RenderTask task = taskList.GetTask(0); + + Actor parentActor = Actor::New(); + parentActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + parentActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + Actor childActor = Actor::New(); + childActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + parentActor.Add(childActor); + application.GetScene().Add(parentActor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData pData; + GestureReceivedFunctor pFunctor(pData); + + PanGestureDetector parentDetector = PanGestureDetector::New(); + parentDetector.DetectedSignal().Connect(&application, pFunctor); + + + Integration::TouchEvent tp = GenerateSingleTouch(PointState::DOWN, Vector2(50.0f, 50.0f), 100); + Internal::TouchEventPtr touchEventImpl(new Internal::TouchEvent(100)); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + Dali::TouchEvent touchEventHandle(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + + tp = GenerateSingleTouch(PointState::MOTION, Vector2(70.0f, 70.0f), 150); + touchEventImpl = new Internal::TouchEvent(150); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + + tp = GenerateSingleTouch(PointState::MOTION, Vector2(90.0f, 90.0f), 200); + touchEventImpl = new Internal::TouchEvent(200); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateSingleTouch(PointState::UP, Vector2(100.0f, 100.0f), 250); + touchEventImpl = new Internal::TouchEvent(250); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + + DALI_TEST_EQUALS(true, pData.functorCalled, TEST_LOCATION); + pData.Reset(); + + END_TEST; +} + +int UtcDaliPanGestureSignalReceptionWithGeometryHittest(void) +{ + TestApplication application; + application.GetScene().SetGeometryHittestEnabled(true); + + Actor actor = Actor::New(); + actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + PanGestureDetector detector = PanGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Start pan within the actor's area + uint32_t time = 100; + TestStartPan(application, Vector2(10.0f, 20.0f), Vector2(26.0f, 20.0f), time); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + + // Continue the pan within the actor's area - we should still receive the signal + data.Reset(); + + TestMovePan(application, Vector2(26.0f, 4.0f), time); + time += TestGetFrameInterval(); + + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + + // Gesture ends within actor's area + data.Reset(); + + TestEndPan(application, Vector2(10.0f, 4.0f), time); + time += TestGetFrameInterval(); + + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + + // Detach actor + detector.DetachAll(); + + // Ensure we are no longer signalled + data.Reset(); + + TestStartPan(application, Vector2(10.0f, 20.0f), Vector2(26.0f, 20.0f), time); + TestMovePan(application, Vector2(26.0f, 4.0f), time); + time += TestGetFrameInterval(); + TestEndPan(application, Vector2(10.0f, 4.0f), time); + + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + END_TEST; +} + +int UtcDaliPanGestureFeedTouchWhenGesturePropagation(void) +{ + TestApplication application; + Integration::Scene scene = application.GetScene(); + RenderTaskList taskList = scene.GetRenderTaskList(); + Dali::RenderTask task = taskList.GetTask(0); + + Actor parentActor = Actor::New(); + parentActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + parentActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + Actor childActor = Actor::New(); + childActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + parentActor.Add(childActor); + application.GetScene().Add(parentActor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData pData; + GestureReceivedFunctor pFunctor(pData); + + PanGestureDetector parentDetector = PanGestureDetector::New(); + parentDetector.DetectedSignal().Connect(&application, pFunctor); + + SignalData cData; + GestureReceivedFunctor cFunctor(cData); + + PanGestureDetector childDetector = PanGestureDetector::New(); + childDetector.DetectedSignal().Connect(&application, cFunctor); + + // Start gesture within the actor's area, we receive the gesture not parent actor but child actor. + Integration::TouchEvent tp = GenerateSingleTouch(PointState::DOWN, Vector2(50.0f, 50.0f), 100); + Internal::TouchEventPtr touchEventImpl(new Internal::TouchEvent(100)); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + Dali::TouchEvent touchEventHandle(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + tp = GenerateSingleTouch(PointState::MOTION, Vector2(60.0f, 60.0f), 150); + touchEventImpl = new Internal::TouchEvent(150); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + tp = GenerateSingleTouch(PointState::MOTION, Vector2(70.0f, 70.0f), 200); + touchEventImpl = new Internal::TouchEvent(200); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + tp = GenerateSingleTouch(PointState::MOTION, Vector2(80.0f, 80.0f), 250); + touchEventImpl = new Internal::TouchEvent(200); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + tp = GenerateSingleTouch(PointState::UP, Vector2(100.0f, 100.0f), 300); + touchEventImpl = new Internal::TouchEvent(250); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + DALI_TEST_EQUALS(true, cData.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(false, pData.functorCalled, TEST_LOCATION); + cData.Reset(); + pData.Reset(); + + + // If GesturePropargation is set, a gesture event is to pass over to the parent. + SignalData cPData; + PropagationActorFunctor cPFunctor(cPData, true); + childDetector.DetectedSignal().Connect(&application, cPFunctor); + + // So now the parent got the gesture event. + tp = GenerateSingleTouch(PointState::DOWN, Vector2(50.0f, 50.0f), 100); + touchEventImpl = new Internal::TouchEvent(100); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + tp = GenerateSingleTouch(PointState::MOTION, Vector2(60.0f, 60.0f), 150); + touchEventImpl = new Internal::TouchEvent(150); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + tp = GenerateSingleTouch(PointState::MOTION, Vector2(70.0f, 70.0f), 200); + touchEventImpl = new Internal::TouchEvent(200); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + tp = GenerateSingleTouch(PointState::MOTION, Vector2(80.0f, 80.0f), 250); + touchEventImpl = new Internal::TouchEvent(250); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + tp = GenerateSingleTouch(PointState::UP, Vector2(100.0f, 100.0f), 300); + touchEventImpl = new Internal::TouchEvent(300); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + if(!childDetector.HandleEvent(childActor, touchEventHandle)) + { + parentDetector.HandleEvent(parentActor, touchEventHandle); + } + + DALI_TEST_EQUALS(true, cPData.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(true, pData.functorCalled, TEST_LOCATION); + cPData.Reset(); + pData.Reset(); + + END_TEST; +} diff --git a/automated-tests/src/dali/utc-Dali-PinchGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-PinchGestureDetector.cpp index 2c45979..a6215f2 100644 --- a/automated-tests/src/dali/utc-Dali-PinchGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-PinchGestureDetector.cpp @@ -18,7 +18,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -113,6 +116,23 @@ struct UnstageActorFunctor : public GestureReceivedFunctor Integration::Scene scene; }; + +Integration::TouchEvent GenerateDoubleTouch(PointState::Type stateA, const Vector2& screenPositionA, PointState::Type stateB, const Vector2& screenPositionB, uint32_t time) +{ + Integration::TouchEvent touchEvent; + Integration::Point point; + point.SetState(stateA); + point.SetScreenPosition(screenPositionA); + point.SetDeviceClass(Device::Class::TOUCH); + point.SetDeviceSubclass(Device::Subclass::NONE); + touchEvent.points.push_back(point); + point.SetScreenPosition(screenPositionB); + point.SetState(stateB); + touchEvent.points.push_back(point); + touchEvent.time = time; + return touchEvent; +} + } // namespace /////////////////////////////////////////////////////////////////////////////// @@ -1205,4 +1225,135 @@ int UtcDaliPinchGestureWhenGesturePropargation(void) pData.Reset(); END_TEST; -} \ No newline at end of file +} + +int UtcDaliPinchGestureSignalReceptionWithGeometryHittest(void) +{ + TestApplication application; + application.GetScene().SetGeometryHittestEnabled(true); + + Actor actor = Actor::New(); + actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + PinchGestureDetector detector = PinchGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Start pinch within the actor's area + TestStartPinch(application, Vector2(2.0f, 20.0f), Vector2(38.0f, 20.0f), Vector2(10.0f, 20.0f), Vector2(30.0f, 20.0f), 100); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(GestureState::STARTED, data.receivedGesture.GetState(), TEST_LOCATION); + + // Continue the pinch within the actor's area - we should still receive the signal + data.Reset(); + TestContinuePinch(application, Vector2(10.0f, 20.0f), Vector2(30.0f, 20.0f), Vector2(15.0f, 20.0f), Vector2(25.0f, 20.0f), 500); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(GestureState::CONTINUING, data.receivedGesture.GetState(), TEST_LOCATION); + + // Gesture ends within actor's area + data.Reset(); + TestEndPinch(application, Vector2(15.0f, 20.0f), Vector2(25.0f, 20.0f), Vector2(19.0f, 20.0f), Vector2(21.0f, 20.0f), 1000); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(GestureState::FINISHED, data.receivedGesture.GetState(), TEST_LOCATION); + + // Detach actor + detector.DetachAll(); + + // Ensure we are no longer signalled + data.Reset(); + TestGeneratePinch(application); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + END_TEST; +} + +int UtcDaliPinchGestureHandleEvent(void) +{ + TestApplication application; + Integration::Scene scene = application.GetScene(); + RenderTaskList taskList = scene.GetRenderTaskList(); + Dali::RenderTask task = taskList.GetTask(0); + + Actor parentActor = Actor::New(); + parentActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + parentActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + Actor childActor = Actor::New(); + childActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + parentActor.Add(childActor); + application.GetScene().Add(parentActor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData pData; + GestureReceivedFunctor pFunctor(pData); + + PinchGestureDetector parentDetector = PinchGestureDetector::New(); + parentDetector.DetectedSignal().Connect(&application, pFunctor); + + Integration::TouchEvent tp = GenerateDoubleTouch(PointState::DOWN, Vector2(2.0f, 20.0f), PointState::DOWN, Vector2(38.0f, 20.0f), 100); + Internal::TouchEventPtr touchEventImpl(new Internal::TouchEvent(100)); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + Dali::TouchEvent touchEventHandle(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 150); + touchEventImpl = new Internal::TouchEvent(150); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 200); + touchEventImpl = new Internal::TouchEvent(200); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 250); + touchEventImpl = new Internal::TouchEvent(250); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 300); + touchEventImpl = new Internal::TouchEvent(300); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::UP, Vector2(10.0f, 20.0f), PointState::UP, Vector2(30.0f, 20.0f), 350); + touchEventImpl = new Internal::TouchEvent(350); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + + DALI_TEST_EQUALS(true, pData.functorCalled, TEST_LOCATION); + pData.Reset(); + + END_TEST; +} diff --git a/automated-tests/src/dali/utc-Dali-RotationGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-RotationGestureDetector.cpp index 8c1d929..f474ff7 100644 --- a/automated-tests/src/dali/utc-Dali-RotationGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-RotationGestureDetector.cpp @@ -18,7 +18,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -113,6 +116,21 @@ struct UnstageActorFunctor : public GestureReceivedFunctor Integration::Scene scene; }; +Integration::TouchEvent GenerateDoubleTouch(PointState::Type stateA, const Vector2& screenPositionA, PointState::Type stateB, const Vector2& screenPositionB, uint32_t time) +{ + Integration::TouchEvent touchEvent; + Integration::Point point; + point.SetState(stateA); + point.SetScreenPosition(screenPositionA); + point.SetDeviceClass(Device::Class::TOUCH); + point.SetDeviceSubclass(Device::Subclass::NONE); + touchEvent.points.push_back(point); + point.SetScreenPosition(screenPositionB); + point.SetState(stateB); + touchEvent.points.push_back(point); + touchEvent.time = time; + return touchEvent; +} } // namespace /////////////////////////////////////////////////////////////////////////////// @@ -1171,4 +1189,135 @@ int UtcDaliRotationGestureWhenGesturePropargation(void) pData.Reset(); END_TEST; -} \ No newline at end of file +} + +int UtcDaliRotationGestureSignalReceptionWithGeometryHittest(void) +{ + TestApplication application; + application.GetScene().SetGeometryHittestEnabled(true); + + Actor actor = Actor::New(); + actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + RotationGestureDetector detector = RotationGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Start rotation within the actor's area + TestStartRotation(application, Vector2(2.0f, 20.0f), Vector2(38.0f, 20.0f), Vector2(10.0f, 20.0f), Vector2(30.0f, 20.0f), 100); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(GestureState::STARTED, data.receivedGesture.GetState(), TEST_LOCATION); + + // Continue the rotation within the actor's area - we should still receive the signal + data.Reset(); + TestContinueRotation(application, Vector2(10.0f, 20.0f), Vector2(30.0f, 20.0f), Vector2(15.0f, 20.0f), Vector2(25.0f, 20.0f), 500); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(GestureState::CONTINUING, data.receivedGesture.GetState(), TEST_LOCATION); + + // Gesture ends within actor's area + data.Reset(); + TestEndRotation(application, Vector2(15.0f, 20.0f), Vector2(25.0f, 20.0f), Vector2(19.0f, 20.0f), Vector2(21.0f, 20.0f), 1000); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(GestureState::FINISHED, data.receivedGesture.GetState(), TEST_LOCATION); + + // Detach actor + detector.DetachAll(); + + // Ensure we are no longer signalled + data.Reset(); + TestGenerateRotation(application); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + END_TEST; +} + +int UtcDaliRotationGestureHandleEvent(void) +{ + TestApplication application; + Integration::Scene scene = application.GetScene(); + RenderTaskList taskList = scene.GetRenderTaskList(); + Dali::RenderTask task = taskList.GetTask(0); + + Actor parentActor = Actor::New(); + parentActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + parentActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + Actor childActor = Actor::New(); + childActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + parentActor.Add(childActor); + application.GetScene().Add(parentActor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData pData; + GestureReceivedFunctor pFunctor(pData); + + RotationGestureDetector parentDetector = RotationGestureDetector::New(); + parentDetector.DetectedSignal().Connect(&application, pFunctor); + + Integration::TouchEvent tp = GenerateDoubleTouch(PointState::DOWN, Vector2(2.0f, 20.0f), PointState::DOWN, Vector2(38.0f, 20.0f), 100); + Internal::TouchEventPtr touchEventImpl(new Internal::TouchEvent(100)); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + Dali::TouchEvent touchEventHandle(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 150); + touchEventImpl = new Internal::TouchEvent(150); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 200); + touchEventImpl = new Internal::TouchEvent(200); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(10.0f, 20.0f), PointState::MOTION, Vector2(30.0f, 20.0f), 250); + touchEventImpl = new Internal::TouchEvent(250); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::MOTION, Vector2(6.0f, 6.0f), PointState::MOTION, Vector2(18.0f, 18.0f), 300); + touchEventImpl = new Internal::TouchEvent(300); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateDoubleTouch(PointState::UP, Vector2(10.0f, 8.0f), PointState::UP, Vector2(14.0f, 16.0f), 350); + touchEventImpl = new Internal::TouchEvent(350); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->AddPoint(tp.GetPoint(1)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + + DALI_TEST_EQUALS(true, pData.functorCalled, TEST_LOCATION); + pData.Reset(); + + END_TEST; +} diff --git a/automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp index 5c15b92..d09d3f6 100644 --- a/automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp @@ -18,7 +18,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -1331,3 +1334,99 @@ int UtcDaliTapGestureDetectorCheck(void) END_TEST; } + +int UtcDaliTapGestureSignalReceptionWithGeometryHittest(void) +{ + TestApplication application; + application.GetScene().SetGeometryHittestEnabled(true); + + Actor actor = Actor::New(); + actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + TapGestureDetector detector = TapGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Start tap within the actor's area + TestGenerateTap(application, 20.0f, 20.0f, 100); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(1u, data.receivedGesture.GetNumberOfTaps(), TEST_LOCATION); + DALI_TEST_EQUALS(1u, data.receivedGesture.GetNumberOfTouches(), TEST_LOCATION); + DALI_TEST_EQUALS(Vector2(20.0f, 20.0f), data.receivedGesture.GetLocalPoint(), 0.1, TEST_LOCATION); + + // repeat the tap within the actor's area - we should still receive the signal + data.Reset(); + TestGenerateTap(application, 50.0f, 50.0f, 700); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(1u, data.receivedGesture.GetNumberOfTaps(), TEST_LOCATION); + DALI_TEST_EQUALS(1u, data.receivedGesture.GetNumberOfTouches(), TEST_LOCATION); + DALI_TEST_EQUALS(Vector2(50.0f, 50.0f), data.receivedGesture.GetLocalPoint(), 0.1, TEST_LOCATION); + + // Detach actor + detector.DetachAll(); + + // Ensure we are no longer signalled + data.Reset(); + TestGenerateTap(application, 20.0f, 20.0f, 1300); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + TestGenerateTap(application, 50.0f, 50.0f, 1900); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + END_TEST; +} + +int UtcDaliTapGestureHandleEvent(void) +{ + TestApplication application; + Integration::Scene scene = application.GetScene(); + RenderTaskList taskList = scene.GetRenderTaskList(); + Dali::RenderTask task = taskList.GetTask(0); + + Actor parentActor = Actor::New(); + parentActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + parentActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + Actor childActor = Actor::New(); + childActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + parentActor.Add(childActor); + application.GetScene().Add(parentActor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData pData; + GestureReceivedFunctor pFunctor(pData); + + TapGestureDetector parentDetector = TapGestureDetector::New(); + parentDetector.DetectedSignal().Connect(&application, pFunctor); + + Integration::TouchEvent tp = GenerateSingleTouch(PointState::DOWN, Vector2(50.0f, 50.0f), 1, 100); + Internal::TouchEventPtr touchEventImpl(new Internal::TouchEvent(100)); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + Dali::TouchEvent touchEventHandle(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + tp = GenerateSingleTouch(PointState::UP, Vector2(50.0f, 50.0f), 1, 150); + touchEventImpl = new Internal::TouchEvent(150); + touchEventImpl->AddPoint(tp.GetPoint(0)); + touchEventImpl->SetRenderTask(task); + touchEventHandle = Dali::TouchEvent(touchEventImpl.Get()); + parentDetector.HandleEvent(parentActor, touchEventHandle); + + DALI_TEST_EQUALS(true, pData.functorCalled, TEST_LOCATION); + pData.Reset(); + + END_TEST; +} diff --git a/dali/internal/event/actors/actor-impl.cpp b/dali/internal/event/actors/actor-impl.cpp index 2aafb89..92ac85c 100644 --- a/dali/internal/event/actors/actor-impl.cpp +++ b/dali/internal/event/actors/actor-impl.cpp @@ -303,7 +303,21 @@ bool EmitConsumingSignal(Actor& actor, Signal& signal, const Event& event) Dali::Actor handle(&actor); consumed = signal.Emit(handle, event); } + return consumed; +} + +/// Helper for emitting a signal +/// If any one of the multiple callbacks returns true, the entire callback is consumed. +template +bool EmitConsumingSignalOr(Actor& actor, Signal& signal, const Event& event) +{ + bool consumed = false; + if(!signal.Empty()) + { + Dali::Actor handle(&actor); + consumed = signal.EmitOr(handle, event); + } return consumed; } @@ -995,11 +1009,19 @@ bool Actor::IsGestureRequired(GestureType::Value type) const bool Actor::EmitInterceptTouchEventSignal(const Dali::TouchEvent& touch) { + if(mScene && mScene->IsGeometryHittestEnabled()) + { + return EmitConsumingSignalOr(*this, mInterceptTouchedSignal, touch); + } return EmitConsumingSignal(*this, mInterceptTouchedSignal, touch); } bool Actor::EmitTouchEventSignal(const Dali::TouchEvent& touch) { + if(mScene && mScene->IsGeometryHittestEnabled()) + { + return EmitConsumingSignalOr(*this, mTouchedSignal, touch); + } return EmitConsumingSignal(*this, mTouchedSignal, touch); } diff --git a/dali/internal/event/events/event-processor.cpp b/dali/internal/event/events/event-processor.cpp index 442626e..abc3956 100644 --- a/dali/internal/event/events/event-processor.cpp +++ b/dali/internal/event/events/event-processor.cpp @@ -55,7 +55,10 @@ EventProcessor::EventProcessor(Scene& scene, GestureEventProcessor& gestureEvent mWheelEventProcessor(scene), mEventQueue0(INITIAL_BUFFER_SIZE), mEventQueue1(INITIAL_BUFFER_SIZE), - mCurrentEventQueue(&mEventQueue0) + mCurrentEventQueue(&mEventQueue0), + mTouchEventProcessors(), + mActorTouchPoints(), + mActorIdDeviceId() { } @@ -150,9 +153,73 @@ void EventProcessor::ProcessEvents() case Event::Touch: { Integration::TouchEvent& touchEvent = static_cast(*event); - mTouchEventProcessor.ProcessTouchEvent(touchEvent); - mGestureEventProcessor.ProcessTouchEvent(mScene, touchEvent); + if(mScene.IsGeometryHittestEnabled()) + { + DALI_ASSERT_ALWAYS(!touchEvent.points.empty() && "Empty TouchEvent sent from Integration\n"); + + mActorTouchPoints.clear(); + for(uint i = 0; i < touchEvent.GetPointCount(); i++) + { + // Perform hittest only for downloads and save points. This is to remember the actor that was first hit for each point. + // So, even if you leave the actor or move and climb on top of another actor, you can only proceed with the touch event process for the actor that was first down. + if(touchEvent.GetPoint(i).GetState() == PointState::DOWN) + { + HitTestAlgorithm::Results hitTestResults; + hitTestResults.point = touchEvent.GetPoint(i); + hitTestResults.eventTime = touchEvent.time; + + HitTestAlgorithm::HitTest(mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), touchEvent.GetPoint(i).GetScreenPosition(), hitTestResults, nullptr, false); + + if(hitTestResults.actor) + { + // Stores which actor the touch event hit. + mActorIdDeviceId[touchEvent.GetPoint(i).GetDeviceId()] = (&GetImplementation(hitTestResults.actor))->GetId(); + } + } + // You can see which actor the touch event hit. + auto actorId = mActorIdDeviceId.find(touchEvent.GetPoint(i).GetDeviceId()); + if(actorId != mActorIdDeviceId.end()) + { + // Store the touch point in the actor to which the touch event should be delivered. + mActorTouchPoints[actorId->second].push_back(touchEvent.GetPoint(i)); + } + } + + // For each actor, the stored touch points are collected and the TouchEventProcessor is executed for each actor + for(ActorTouchPointsContainer::iterator aItr = mActorTouchPoints.begin(); aItr != mActorTouchPoints.end(); aItr++) + { + uint32_t actorId = aItr->first; + TouchPointsContainer& touchPoints = aItr->second; + Integration::TouchEvent touchEventInternal(touchEvent.time); + + for(TouchPointsContainer::iterator tItr = touchPoints.begin(); tItr != touchPoints.end(); tItr++) + { + touchEventInternal.AddPoint(*tItr); + } + + auto processor = mTouchEventProcessors.find(actorId); + if(processor == mTouchEventProcessors.end()) + { + mTouchEventProcessors[actorId] = new TouchEventProcessor(mScene); + } + + mTouchEventProcessors[actorId]->ProcessTouchEvent(touchEventInternal); + } + + // All touch events have been processed, it should be cleared. + if(touchEvent.GetPointCount() == 1 && (touchEvent.GetPoint(0).GetState() == PointState::UP || touchEvent.GetPoint(0).GetState() == PointState::INTERRUPTED)) + { + mActorIdDeviceId.clear(); + mTouchEventProcessors.clear(); + } + } + else + { + mTouchEventProcessor.ProcessTouchEvent(touchEvent); + mGestureEventProcessor.ProcessTouchEvent(mScene, touchEvent); + } + break; } diff --git a/dali/internal/event/events/event-processor.h b/dali/internal/event/events/event-processor.h index 6936898..d8f3b7c 100644 --- a/dali/internal/event/events/event-processor.h +++ b/dali/internal/event/events/event-processor.h @@ -18,7 +18,11 @@ * */ +// EXTERNAL INCLUDES +#include + // INTERNAL INCLUDES +#include #include #include #include @@ -38,6 +42,11 @@ class Scene; class GestureEventProcessor; class NotificationManager; +using TouchPointsContainer = std::list; +using ActorTouchPointsContainer = std::unordered_map; + +using TouchEventProcessorsContainer = std::unordered_map>; +using ActorIdDeviceIdContainer = std::unordered_map; /** * The EventProcessor processes any events that are received by Dali. Such events include * touch events, key events, wheel events, and notification events. @@ -79,17 +88,21 @@ public: void SendInterruptedEvents(Dali::Internal::Actor *actor); private: - Scene& mScene; ///< The Scene events are processed for. - TouchEventProcessor mTouchEventProcessor; ///< Processes touch events. - HoverEventProcessor mHoverEventProcessor; ///< Processes hover events. - GestureEventProcessor& mGestureEventProcessor; ///< Processes gesture events. - KeyEventProcessor mKeyEventProcessor; ///< Processes key events. - WheelEventProcessor mWheelEventProcessor; ///< Processes wheel events. + Scene& mScene; ///< The Scene events are processed for. + TouchEventProcessor mTouchEventProcessor; ///< Processes touch events. + HoverEventProcessor mHoverEventProcessor; ///< Processes hover events. + GestureEventProcessor& mGestureEventProcessor; ///< Processes gesture events. + KeyEventProcessor mKeyEventProcessor; ///< Processes key events. + WheelEventProcessor mWheelEventProcessor; ///< Processes wheel events. // Allow messages to be added safely to one queue, while processing (iterating through) the second queue. - MessageBuffer mEventQueue0; ///< An event queue. - MessageBuffer mEventQueue1; ///< Another event queue. - MessageBuffer* mCurrentEventQueue; ///< QueueEvent() will queue here. + MessageBuffer mEventQueue0; ///< An event queue. + MessageBuffer mEventQueue1; ///< Another event queue. + MessageBuffer* mCurrentEventQueue; ///< QueueEvent() will queue here. + + TouchEventProcessorsContainer mTouchEventProcessors; ///< List of touch processors by actor + ActorTouchPointsContainer mActorTouchPoints; ///< List of touch events by actor + ActorIdDeviceIdContainer mActorIdDeviceId; ///< List of actor id by touch device id }; } // namespace Internal diff --git a/dali/internal/event/events/gesture-detector-impl.cpp b/dali/internal/event/events/gesture-detector-impl.cpp index 1e98cb7..fc6f510 100644 --- a/dali/internal/event/events/gesture-detector-impl.cpp +++ b/dali/internal/event/events/gesture-detector-impl.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include namespace Dali { @@ -36,6 +38,9 @@ GestureDetector::GestureDetector(GestureType::Value type, const SceneGraph::Prop : Object(sceneObject), mType(type), mGestureEventProcessor(ThreadLocalStorage::Get().GetGestureEventProcessor()), + mFeededActor(), + mRenderTask(nullptr), + mGestureRecognizer(), mIsDetected(false) { } @@ -258,10 +263,63 @@ Dali::Actor GestureDetector::GetAttachedActor(size_t index) const return actor; } -bool GestureDetector::FeedTouch(Dali::Actor& actor, Dali::TouchEvent& touch) +bool GestureDetector::HandleEvent(Dali::Actor& actor, Dali::TouchEvent& touch) { - //TODO - return false; + bool ret = false; + Dali::Internal::Actor& actorImpl(GetImplementation(actor)); + if(touch.GetPointCount() > 0 && actorImpl.OnScene()) + { + const PointState::Type state = touch.GetState(0); + if(state == PointState::DOWN) + { + CancelProcessing(); + Clear(); + actorImpl.SetNeedGesturePropagation(false); + mGestureEventProcessor.RegisterGestureDetector(this); + } + + Integration::TouchEvent touchEvent(touch.GetTime()); + for(std::size_t i = 0; i< touch.GetPointCount(); i++) + { + Integration::Point point; + point.SetState(touch.GetState(i)); + point.SetDeviceId(touch.GetDeviceId(i)); + point.SetScreenPosition(touch.GetScreenPosition(i)); + point.SetRadius(touch.GetRadius(i)); + point.SetPressure(touch.GetPressure(i)); + point.SetAngle(touch.GetAngle(i)); + point.SetDeviceClass(touch.GetDeviceClass(i)); + point.SetDeviceSubclass(touch.GetDeviceSubclass(i)); + point.SetMouseButton(touch.GetMouseButton(i)); + point.SetHitActor(touch.GetHitActor(i)); + point.SetLocalPosition(touch.GetLocalPosition(i)); + touchEvent.points.push_back(point); + } + + + Dali::Internal::TouchEvent& touchEventImpl(GetImplementation(touch)); + mFeededActor.SetActor(&actorImpl); + mRenderTask = &GetImplementation(touchEventImpl.GetRenderTaskPtr()); + + if(!actorImpl.NeedGesturePropagation()) + { + ProcessTouchEvent(actorImpl.GetScene(), touchEvent); + } + + ret = IsDetected() && !actorImpl.NeedGesturePropagation(); + actorImpl.SetNeedGesturePropagation(false); + + if(state == PointState::FINISHED || state == PointState::INTERRUPTED) + { + Clear(); + } + } + return ret; +} + +void GestureDetector::CancelAllOtherGestureDetectors() +{ + mGestureEventProcessor.CancelAllOtherGestureDetectors(this); } bool GestureDetector::IsDetected() const @@ -274,6 +332,13 @@ void GestureDetector::SetDetected(bool detected) mIsDetected = detected; } +void GestureDetector::Clear() +{ + mGestureRecognizer = nullptr; + mGestureEventProcessor.UnregisterGestureDetector(this); + SetDetected(false); +} + bool GestureDetector::IsAttached(Actor& actor) const { return (find(mPendingAttachActors.begin(), mPendingAttachActors.end(), &actor) != mPendingAttachActors.end()) || diff --git a/dali/internal/event/events/gesture-detector-impl.h b/dali/internal/event/events/gesture-detector-impl.h index b7953ce..d58e581 100644 --- a/dali/internal/event/events/gesture-detector-impl.h +++ b/dali/internal/event/events/gesture-detector-impl.h @@ -20,6 +20,10 @@ // INTERNAL INCLUDES #include +#include +#include +#include +#include #include #include #include @@ -41,6 +45,7 @@ class GestureEventProcessor; using GestureDetectorPtr = IntrusivePtr; using GestureDetectorContainer = std::vector; using GestureDetectorActorContainer = std::vector; +using GestureRecognizerPtr = IntrusivePtr; /** * This is a type trait that should be used by deriving gesture detectors for their container type. @@ -54,7 +59,7 @@ struct DerivedGestureDetectorContainer /** * @copydoc Dali::GestureDetector */ -class GestureDetector : public Object, public Object::Observer +class GestureDetector : public Object, public Object::Observer, public ConnectionTracker { public: /** @@ -83,9 +88,9 @@ public: Dali::Actor GetAttachedActor(size_t index) const; /** - * @copydoc Dali::GestureDetector::FeedTouch() + * @copydoc Dali::GestureDetector::HandleEvent() */ - bool FeedTouch(Dali::Actor& actor, Dali::TouchEvent& touch); + bool HandleEvent(Dali::Actor& actor, Dali::TouchEvent& touch); /** * Returns a const reference to the container of attached actor pointers. @@ -113,6 +118,11 @@ public: bool IsAttached(Actor& actor) const; /** + * @brief This method that cancels all other gesture detectors except the current gesture detector + */ + void CancelAllOtherGestureDetectors(); + + /** * @brief Returns whether the gesture was detected. * @return true, if the gesture was detected, false otherwise. */ @@ -124,6 +134,22 @@ public: */ void SetDetected(bool detected); + /** + * gesture-detector meets the parameters of the current gesture. + * + * @param[in] gestureEvent The gesture event. + * @param[in] actor The actor that has been gestured. + * @param[in] renderTask The renderTask. + * + * @return true, if the detector meets the parameters, false otherwise. + */ + virtual bool CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask) = 0; + + /** + * @brief This is canceling the ongoing gesture recognition process. + */ + virtual void CancelProcessing() = 0; + protected: // Creation & Destruction /** * Construct a new GestureDetector. @@ -181,12 +207,37 @@ private: */ virtual void OnActorDestroyed(Object& object) = 0; + /** + * @brief Callback for TouchedSignal signal + * + * @param actor The actor + * @param touch The touch event that has occurred + */ + virtual bool OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) = 0; + + /** + * @brief Delivers touch events to each detector. + * This is an API that is called by FeedTouch and recognizes gestures directly from the Detector without going through the Reconizer. + * + * @param scene The scene + * @param event The touch event that has occurred + */ + virtual void ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) = 0; + + /** + * @brief Clears the detector. + */ + void Clear(); + protected: GestureType::Value mType; ///< The gesture detector will detect this type of gesture. GestureDetectorActorContainer mAttachedActors; ///< Object::Observer is used to provide weak-pointer behaviour GestureDetectorActorContainer mPendingAttachActors; ///< Object::Observer is used to provide weak-pointer behaviour GestureEventProcessor& mGestureEventProcessor; ///< A reference to the gesture event processor. - bool mIsDetected : 1; ///< Whether gesture detected. + ActorObserver mFeededActor; ///< The Actor that feeds touch events + RenderTaskPtr mRenderTask; ///< The render task used to generate this touch event. + GestureRecognizerPtr mGestureRecognizer; ///< The gesture recognizer + bool mIsDetected : 1; ///< Whether gesture detected. }; } // namespace Internal diff --git a/dali/internal/event/events/gesture-event-processor.cpp b/dali/internal/event/events/gesture-event-processor.cpp index 1240148..350abc2 100644 --- a/dali/internal/event/events/gesture-event-processor.cpp +++ b/dali/internal/event/events/gesture-event-processor.cpp @@ -41,6 +41,7 @@ GestureEventProcessor::GestureEventProcessor(SceneGraph::UpdateManager& updateMa mTapGestureProcessor(), mRotationGestureProcessor(), mRenderController(renderController), + mGestureDetectors(), envOptionMinimumPanDistance(-1), envOptionMinimumPanEvents(-1) { @@ -57,6 +58,44 @@ void GestureEventProcessor::ProcessTouchEvent(Scene& scene, const Integration::T mRotationGestureProcessor.ProcessTouch(scene, event); } +bool GestureEventProcessor::IsRegisterGestureDetector(GestureDetector* gestureDetector) +{ + return (find(mGestureDetectors.begin(), mGestureDetectors.end(), gestureDetector) != mGestureDetectors.end()); +} + +void GestureEventProcessor::RegisterGestureDetector(GestureDetector* gestureDetector) +{ + if(!IsRegisterGestureDetector(gestureDetector)) + { + mGestureDetectors.push_back(gestureDetector); + } +} + +void GestureEventProcessor::CancelAllOtherGestureDetectors(GestureDetector* gestureDetector) +{ + for(auto itr = mGestureDetectors.begin(); itr != mGestureDetectors.end(); itr++) + { + if((*itr) && (*itr) != gestureDetector) + { + (*itr)->CancelProcessing(); + (*itr)->SetDetected(false); + } + } + mGestureDetectors.clear(); + mGestureDetectors.push_back(gestureDetector); +} + +void GestureEventProcessor::UnregisterGestureDetector(GestureDetector* gestureDetector) +{ + // Find detector ... + GestureDetectorContainer::iterator endIter = std::remove(mGestureDetectors.begin(), mGestureDetectors.end(), gestureDetector); + if(endIter != mGestureDetectors.end()) + { + // ... and remove it + mGestureDetectors.erase(endIter, mGestureDetectors.end()); + } +} + void GestureEventProcessor::AddGestureDetector(GestureDetector* gestureDetector, Scene& scene) { switch(gestureDetector->GetType()) @@ -356,6 +395,16 @@ const TapGestureProcessor& GestureEventProcessor::GetTapGestureProcessor() return mTapGestureProcessor; } +const PinchGestureProcessor& GestureEventProcessor::GetPinchGestureProcessor() +{ + return mPinchGestureProcessor; +} + +const RotationGestureProcessor& GestureEventProcessor::GetRotationGestureProcessor() +{ + return mRotationGestureProcessor; +} + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/events/gesture-event-processor.h b/dali/internal/event/events/gesture-event-processor.h index b54ea9d..2cf6346 100644 --- a/dali/internal/event/events/gesture-event-processor.h +++ b/dali/internal/event/events/gesture-event-processor.h @@ -45,6 +45,8 @@ namespace Internal class Stage; class Scene; +using GestureDetectorContainer = std::vector; + /** * Gesture Event Processing: * @@ -100,6 +102,32 @@ public: // To be called by gesture detectors */ void SetGestureProperties(const Dali::Gesture& gesture); + /** + * @brief This method checks whether GestureDetector is in the list of detectors currently processing gestures. + * + * @param gestureDetector + * @return true + */ + bool IsRegisterGestureDetector(GestureDetector* gestureDetector); + + /** + * @brief This method adds a GestureDetector to the list of detectors currently processing gestures. + * @param gestureDetector The gesture detector to add + */ + void RegisterGestureDetector(GestureDetector* gestureDetector); + + /** + * @brief This method that cancels all other gesture detectors except the current gesture detector + * @param gestureDetector The current gesture detector + */ + void CancelAllOtherGestureDetectors(GestureDetector* gestureDetector); + + /** + * @brief This method clears all processing desture detectors + * @param gestureDetector The gesture detector to remove + */ + void UnregisterGestureDetector(GestureDetector* gestureDetector); + public: // Called by Core /** * Returns true if any GestureDetector requires a Core::Update. Clears @@ -320,6 +348,16 @@ public: // needed for PanGesture */ const TapGestureProcessor& GetTapGestureProcessor(); + /** + * @return the pinch gesture processor + */ + const PinchGestureProcessor& GetPinchGestureProcessor(); + + /** + * @return the rotation gesture processor + */ + const RotationGestureProcessor& GetRotationGestureProcessor(); + private: // Undefined GestureEventProcessor(const GestureEventProcessor&); @@ -332,6 +370,7 @@ private: TapGestureProcessor mTapGestureProcessor; RotationGestureProcessor mRotationGestureProcessor; Integration::RenderController& mRenderController; + GestureDetectorContainer mGestureDetectors; int32_t envOptionMinimumPanDistance; int32_t envOptionMinimumPanEvents; diff --git a/dali/internal/event/events/gesture-recognizer.h b/dali/internal/event/events/gesture-recognizer.h index 0bc013d..fe4253d 100644 --- a/dali/internal/event/events/gesture-recognizer.h +++ b/dali/internal/event/events/gesture-recognizer.h @@ -65,6 +65,12 @@ public: virtual void SendEvent(const Integration::TouchEvent& event) = 0; /** + * @brief This is canceling the ongoing gesture recognition process. + * If the gesture recognition was in progress, it will be stopped immediately after calling this function. + */ + virtual void CancelEvent() = 0; + + /** * Called when Core updates the gesture's detection requirements. * @param[in] request The updated detection requirements. */ diff --git a/dali/internal/event/events/hit-test-algorithm-impl.cpp b/dali/internal/event/events/hit-test-algorithm-impl.cpp index 578f5fe..9f566d3 100644 --- a/dali/internal/event/events/hit-test-algorithm-impl.cpp +++ b/dali/internal/event/events/hit-test-algorithm-impl.cpp @@ -195,7 +195,7 @@ inline bool IsOnOverlay(Actor* actor, Actor* currentActor) /** * Hit tests the given actor and updates the in/out variables appropriately */ -void HitTestActor(const RenderTask& renderTask, +bool HitTestActor(const RenderTask& renderTask, const Vector4& rayOrigin, const Vector4& rayDir, const float& nearClippingPlane, @@ -211,7 +211,8 @@ void HitTestActor(const RenderTask& renderTask, HitActor& hit, bool isGeometry) { - if(clippingActor || hitCheck.IsActorHittable(&actor)) + bool isClippingOrHittable = clippingActor || hitCheck.IsActorHittable(&actor); + if(isClippingOrHittable || isGeometry) { Vector3 size(actor.GetCurrentSize()); @@ -233,6 +234,21 @@ void HitTestActor(const RenderTask& renderTask, // Check if cameraDepthDistance is between clipping plane if(cameraDepthDistance >= nearClippingPlane && cameraDepthDistance <= farClippingPlane) { + if(isGeometry && actor.GetParent()) + { + // If the child touches outside the parent's size boundary, it should not be hit. + if(!overlayedActor && !clippingActor && !actor.GetParent()->IsLayer()) + { + Vector2 hitPointLocal; + float distance; + if(!(rayTest.SphereTest(*actor.GetParent(), rayOrigin, rayDir) && + rayTest.ActorTest(*actor.GetParent(), rayOrigin, rayDir, hitPointLocal, distance))) + { + return false; + } + } + } + if(overlayHit && !overlayedActor) { // If we have already hit an overlay and current actor is not an overlay ignore current actor. @@ -245,7 +261,7 @@ void HitTestActor(const RenderTask& renderTask, } // If the hit actor does not want to hit, the hit-test continues. - if(hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime, isGeometry)) + if(isClippingOrHittable && hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime, isGeometry)) { hit.actor = &actor; hit.hitPosition = hitPointLocal; @@ -272,6 +288,7 @@ void HitTestActor(const RenderTask& renderTask, } } } + return true; } /** @@ -344,7 +361,10 @@ HitActor HitTestWithinLayer(Actor& actor, bool overlayedActor = overlayed || actor.IsOverlay(); // If we are a clipping actor or hittable... - HitTestActor(renderTask, rayOrigin, rayDir, nearClippingPlane, farClippingPlane, hitCheck, rayTest, point, eventTime, clippingActor, overlayedActor, actor, overlayHit, hit, isGeometry); + if(!HitTestActor(renderTask, rayOrigin, rayDir, nearClippingPlane, farClippingPlane, hitCheck, rayTest, point, eventTime, clippingActor, overlayedActor, actor, overlayHit, hit, isGeometry)) + { + return hit; + } // If current actor is clipping, and hit failed, We should not checkup child actors. Fast return // Only do this if we're using CLIP_CHILDREN though, as children whose drawing mode is OVERLAY_2D are not clipped when CLIP_TO_BOUNDING_BOX is selected. @@ -362,18 +382,6 @@ HitActor HitTestWithinLayer(Actor& actor, HitActor childHit; if(actor.GetChildCount() > 0) { - // If the child touches outside the parent's size boundary, it should not be hit. - if(isGeometry && !actor.IsLayer()) - { - Vector2 hitPointLocal; - float distance; - if(!(rayTest.SphereTest(actor, rayOrigin, rayDir) && - rayTest.ActorTest(actor, rayOrigin, rayDir, hitPointLocal, distance))) - { - return hit; - } - } - childHit.distance = std::numeric_limits::max(); childHit.depth = std::numeric_limits::min(); ActorContainer& children = actor.GetChildrenInternal(); diff --git a/dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.cpp b/dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.cpp index 52c315e..b31307d 100644 --- a/dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.cpp +++ b/dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.cpp @@ -22,8 +22,11 @@ #include // for strcmp // INTERNAL INCLUDES - +#include +#include #include +#include +#include #include namespace Dali @@ -53,7 +56,7 @@ SignalConnectorType signalConnector1(mType, SIGNAL_LONG_PRESS_DETECTED, &LongPre namespace { -const unsigned int DEFAULT_TOUCHES_REQUIRED = 1; +const uint32_t DEFAULT_TOUCHES_REQUIRED = 1; } // unnamed namespace LongPressGestureDetectorPtr LongPressGestureDetector::New() @@ -159,11 +162,19 @@ bool LongPressGestureDetector::DoConnectSignal(BaseObject* object, ConnectionTra void LongPressGestureDetector::OnActorAttach(Actor& actor) { DALI_LOG_INFO(gLogFilter, Debug::General, "LongPressGestureDetector attach actor(%d)\n", actor.GetId()); + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Connect(this, &LongPressGestureDetector::OnTouchEvent); + } } void LongPressGestureDetector::OnActorDetach(Actor& actor) { DALI_LOG_INFO(gLogFilter, Debug::General, "LongPressGestureDetector detach actor(%d)\n", actor.GetId()); + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Disconnect(this, &LongPressGestureDetector::OnTouchEvent); + } } void LongPressGestureDetector::OnActorDestroyed(Object& object) @@ -171,11 +182,127 @@ void LongPressGestureDetector::OnActorDestroyed(Object& object) // Do nothing } +bool LongPressGestureDetector::OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) +{ + Dali::TouchEvent touchEvent(touch); + return HandleEvent(actor, touchEvent); +} + uint32_t LongPressGestureDetector::GetMinimumHoldingTime() const { return mGestureEventProcessor.GetLongPressMinimumHoldingTime(); } +bool LongPressGestureDetector::CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask) +{ + const LongPressGestureEvent* longPressEvent(static_cast(gestureEvent)); + + return (GetMinimumTouchesRequired() <= longPressEvent->numberOfTouches) && + (GetMaximumTouchesRequired() >= longPressEvent->numberOfTouches); +} + +void LongPressGestureDetector::CancelProcessing() +{ + if(mGestureRecognizer) + { + mGestureRecognizer->CancelEvent(); + } +} + +void LongPressGestureDetector::ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) +{ + if(!mGestureRecognizer) + { + LongPressGestureRequest request; + request.minTouches = GetMinimumTouchesRequired(); + request.maxTouches = GetMaximumTouchesRequired(); + + Size size = scene.GetSize(); + uint32_t minimumHoldingTime = GetMinimumHoldingTime(); + mGestureRecognizer = new LongPressGestureRecognizer(*this, Vector2(size.width, size.height), static_cast(request), minimumHoldingTime); + } + mGestureRecognizer->SendEvent(scene, event); +} + +void LongPressGestureDetector::Process(Scene& scene, const LongPressGestureEvent& longPressEvent) +{ + switch(longPressEvent.state) + { + case GestureState::POSSIBLE: + { + mCurrentLongPressActor.SetActor(mFeededActor.GetActor()); + break; + } + + case GestureState::STARTED: + { + Actor* currentGesturedActor = mCurrentLongPressActor.GetActor(); + if(currentGesturedActor && CheckGestureDetector(&longPressEvent, currentGesturedActor, mRenderTask)) + { + Vector2 actorCoords; + currentGesturedActor->ScreenToLocal(*mRenderTask.Get(), actorCoords.x, actorCoords.y, longPressEvent.point.x, longPressEvent.point.y); + EmitLongPressSignal(currentGesturedActor, longPressEvent, actorCoords); + } + break; + } + + case GestureState::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 = mCurrentLongPressActor.GetActor(); + if(currentGesturedActor) + { + if(currentGesturedActor->IsHittable() && mRenderTask) + { + Vector2 actorCoords; + RenderTask& renderTaskImpl = *mRenderTask.Get(); + currentGesturedActor->ScreenToLocal(renderTaskImpl, actorCoords.x, actorCoords.y, longPressEvent.point.x, longPressEvent.point.y); + + EmitLongPressSignal(currentGesturedActor, longPressEvent, actorCoords); + } + } + break; + } + case GestureState::CANCELLED: + { + mCurrentLongPressActor.SetActor(nullptr); + break; + } + + case GestureState::CONTINUING: + { + DALI_ABORT("Incorrect state received from Integration layer: CONTINUING\n"); + break; + } + + case GestureState::CLEAR: + { + DALI_ABORT("Incorrect state received from Integration layer: CLEAR\n"); + break; + } + } +} + +void LongPressGestureDetector::EmitLongPressSignal(Actor* actor, const LongPressGestureEvent& longPressEvent, Vector2 localPoint) +{ + SetDetected(true); + Internal::LongPressGesturePtr longPress(new Internal::LongPressGesture(longPressEvent.state)); + longPress->SetTime(longPressEvent.time); + longPress->SetNumberOfTouches(longPressEvent.numberOfTouches); + longPress->SetScreenPoint(longPressEvent.point); + longPress->SetLocalPoint(localPoint); + longPress->SetSourceType(longPressEvent.sourceType); + longPress->SetSourceData(longPressEvent.sourceData); + + Dali::Actor actorHandle(actor); + EmitLongPressGestureSignal(actorHandle, Dali::LongPressGesture(longPress.Get())); +} + + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.h b/dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.h index 449b5d7..871b248 100644 --- a/dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.h +++ b/dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.h @@ -21,6 +21,7 @@ // INTERNAL INCLUDES #include #include +#include namespace Dali { @@ -34,7 +35,7 @@ using LongPressGestureDetectorContainer = DerivedGestureDetectorContainer { public: // Creation /** @@ -136,6 +137,15 @@ private: LongPressGestureDetector(const LongPressGestureDetector&); LongPressGestureDetector& operator=(const LongPressGestureDetector& rhs); + /** + * 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 LongPressGestureEvent& longPressEvent, Vector2 localPoint); + private: // GestureDetector overrides /** * @copydoc Dali::Internal::GestureDetector::OnActorAttach(Actor&) @@ -152,11 +162,40 @@ private: // GestureDetector overrides */ void OnActorDestroyed(Object& object) override; + /** + * @copydoc Dali::Internal::GestureDetector::OnTouchEvent(Dali::Actor, const Dali::TouchEvent&) + */ + bool OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) override; + + /** + * @copydoc Dali::Internal::GestureDetector::ProcessTouchEvent(Scene&, const Integration::TouchEvent&) + */ + void ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) override; + + /** + * @copydoc Dali::Internal::GestureDetector::CheckGestureDetector(const GestureEvent*, Actor*, RenderTaskPtr) + */ + bool CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask) override; + + /** + * @copydoc Dali::Internal::GestureDetector::CancelProcessing() + */ + void CancelProcessing() override; + + /** + * 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) override; + private: Dali::LongPressGestureDetector::DetectedSignalType mDetectedSignal; unsigned int mMinimumTouchesRequired; unsigned int mMaximumTouchesRequired; + + ActorObserver mCurrentLongPressActor; ///< Current actor for which the long press gesture has been recognized. }; } // namespace Internal diff --git a/dali/internal/event/events/long-press-gesture/long-press-gesture-processor.cpp b/dali/internal/event/events/long-press-gesture/long-press-gesture-processor.cpp index 6b680ae..32535ec 100644 --- a/dali/internal/event/events/long-press-gesture/long-press-gesture-processor.cpp +++ b/dali/internal/event/events/long-press-gesture/long-press-gesture-processor.cpp @@ -344,11 +344,12 @@ void LongPressGestureProcessor::OnGesturedActorStageDisconnection() bool LongPressGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor) { DALI_ASSERT_DEBUG(mCurrentLongPressEvent); - - LongPressGestureDetector* longPressDetector(static_cast(detector)); - - return (longPressDetector->GetMinimumTouchesRequired() <= mCurrentLongPressEvent->numberOfTouches) && - (longPressDetector->GetMaximumTouchesRequired() >= mCurrentLongPressEvent->numberOfTouches); + bool ret = false; + if(detector) + { + ret = detector->CheckGestureDetector(mCurrentLongPressEvent, actor, mCurrentRenderTask); + } + return ret; } void LongPressGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates) diff --git a/dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.cpp b/dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.cpp index eac654b..79c7188 100644 --- a/dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.cpp +++ b/dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.cpp @@ -190,6 +190,29 @@ void LongPressGestureRecognizer::SendEvent(const Integration::TouchEvent& event) } } +void LongPressGestureRecognizer::CancelEvent() +{ + if(mState != CLEAR) + { + if(mTimerId != 0 && ThreadLocalStorage::Created()) + { + Dali::Integration::PlatformAbstraction& platformAbstraction = ThreadLocalStorage::Get().GetPlatformAbstraction(); + platformAbstraction.CancelTimer(mTimerId); + } + if(mState == FINISHED) + { + EmitGesture(GestureState::FINISHED); + } + else + { + EmitGesture(GestureState::CANCELLED); + } + mTouchPositions.clear(); + mTimerId = 0; + mState = CLEAR; + } +} + void LongPressGestureRecognizer::Update(const GestureRequest& request) { const LongPressGestureRequest& longPress = static_cast(request); diff --git a/dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.h b/dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.h index 9d60f38..ec6f3ad 100644 --- a/dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.h +++ b/dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.h @@ -69,6 +69,11 @@ public: void SendEvent(const Integration::TouchEvent& event) override; /** + * @copydoc Dali::Internal::GestureDetector::CancelEvent() + */ + void CancelEvent() override; + + /** * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&) */ void Update(const GestureRequest& request) override; diff --git a/dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.cpp b/dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.cpp index 93afaa5..4707ef3 100644 --- a/dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.cpp +++ b/dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,6 +41,7 @@ namespace Internal { namespace { +const unsigned long MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY(50u); // Properties // Name Type writable animatable constraint-input enum for index-checking @@ -318,7 +321,9 @@ PanGestureDetector::PanGestureDetector(const SceneGraph::PanGesture& sceneObject : GestureDetector(GestureType::PAN, &sceneObject), mMinimumTouches(1), mMaximumTouches(1), - mMaximumMotionEventAge(std::numeric_limits::max()) + mMaximumMotionEventAge(std::numeric_limits::max()), + mPossiblePanPosition(0.f, 0.f), + mSceneObject(SceneGraph::PanGesture::New()) { } @@ -332,11 +337,19 @@ const SceneGraph::PanGesture& PanGestureDetector::GetPanGestureSceneObject() con void PanGestureDetector::OnActorAttach(Actor& actor) { DALI_LOG_INFO(gLogFilter, Debug::General, "PanGestureDetector attach actor(%d)\n", actor.GetId()); + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Connect(this, &PanGestureDetector::OnTouchEvent); + } } void PanGestureDetector::OnActorDetach(Actor& actor) { DALI_LOG_INFO(gLogFilter, Debug::General, "PanGestureDetector detach actor(%d)\n", actor.GetId()); + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Disconnect(this, &PanGestureDetector::OnTouchEvent); + } } void PanGestureDetector::OnActorDestroyed(Object& object) @@ -344,6 +357,13 @@ void PanGestureDetector::OnActorDestroyed(Object& object) // Do nothing } +bool PanGestureDetector::OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) +{ + Dali::TouchEvent touchEvent(touch); + return HandleEvent(actor, touchEvent); +} + + void PanGestureDetector::SetDefaultProperty(Property::Index index, const Property::Value& property) { // None of our properties should be settable from Public API @@ -472,6 +492,258 @@ const PropertyInputImpl* PanGestureDetector::GetSceneObjectInputProperty(Propert return property; } +void PanGestureDetector::ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) +{ + if(!mGestureRecognizer) + { + const PanGestureProcessor& panGestureProcessor = mGestureEventProcessor.GetPanGestureProcessor(); + int32_t minDistance = panGestureProcessor.GetMinimumDistance(); + int32_t minPanEvents = panGestureProcessor.GetMinimumPanEvents(); + + PanGestureRequest request; + request.minTouches = GetMinimumTouchesRequired(); + request.maxTouches = GetMaximumTouchesRequired(); + request.maxMotionEventAge = GetMaximumMotionEventAge(); + + Size size = scene.GetSize(); + mGestureRecognizer = new PanGestureRecognizer(*this, Vector2(size.width, size.height), static_cast(request), minDistance, minPanEvents); + } + mGestureRecognizer->SendEvent(scene, event); +} + +void PanGestureDetector::Process(Scene& scene, const PanGestureEvent& panEvent) +{ + switch(panEvent.state) + { + case GestureState::POSSIBLE: + { + mCurrentPanActor.SetActor(mFeededActor.GetActor()); + mPossiblePanPosition = panEvent.currentPosition; + break; + } + + case GestureState::STARTED: + { + // 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. + Actor* feededActor = mFeededActor.GetActor(); + if(feededActor && CheckGestureDetector(&panEvent, feededActor, mRenderTask, mPossiblePanPosition)) + { + Vector2 actorCoords; + feededActor->ScreenToLocal(*mRenderTask.Get(), actorCoords.x, actorCoords.y, panEvent.currentPosition.x, panEvent.currentPosition.y); + if(mCurrentPanActor.GetActor() == feededActor) + { + EmitPanSignal(feededActor, panEvent, actorCoords, panEvent.state, mRenderTask); + } + else + { + mPossiblePanPosition = panEvent.previousPosition; + mCurrentPanActor.SetActor(feededActor); + EmitPanSignal(feededActor, panEvent, actorCoords, panEvent.state, mRenderTask); + } + } + break; + } + + case GestureState::CONTINUING: + { + Actor* currentGesturedActor = mCurrentPanActor.GetActor(); + Actor* feededActor = mFeededActor.GetActor(); + if(currentGesturedActor && currentGesturedActor->NeedGesturePropagation() && feededActor && feededActor != currentGesturedActor) + { + if(feededActor->IsHittable() && CheckGestureDetector(&panEvent, feededActor, mRenderTask, mPossiblePanPosition)) + { + Vector2 actorCoords; + feededActor->ScreenToLocal(*mRenderTask.Get(), actorCoords.x, actorCoords.y, panEvent.currentPosition.x, panEvent.currentPosition.y); + + mPossiblePanPosition = panEvent.currentPosition; + mCurrentPanActor.SetActor(feededActor); + EmitPanSignal(feededActor, panEvent, actorCoords, GestureState::STARTED, mRenderTask); + } + break; + } + DALI_FALLTHROUGH; + } + + case GestureState::FINISHED: + case GestureState::CANCELLED: + { + // Only send subsequent pan gesture signals if we processed the pan gesture when it started. + // Check if actor is still touchable. + Actor* currentGesturedActor = mCurrentPanActor.GetActor(); + if(currentGesturedActor && currentGesturedActor->IsHittable() && mRenderTask && IsDetected()) + { + Vector2 actorCoords; + currentGesturedActor->ScreenToLocal(*mRenderTask.Get(), actorCoords.x, actorCoords.y, panEvent.currentPosition.x, panEvent.currentPosition.y); + EmitPanSignal(currentGesturedActor, panEvent, actorCoords, panEvent.state, mRenderTask); + } + + if((panEvent.state == GestureState::FINISHED) || (panEvent.state == GestureState::CANCELLED)) + { + mCurrentPanActor.SetActor(nullptr); + } + break; + } + + case GestureState::CLEAR: + { + DALI_ABORT("Incorrect state received from Integration layer: CLEAR\n"); + break; + } + } +} + +bool PanGestureDetector::CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask, Vector2 possiblePanPosition) +{ + CheckGestureDetector(gestureEvent, actor, renderTask); + const PanGestureEvent* panEvent(static_cast(gestureEvent)); + + bool retVal(false); + + if((panEvent->numberOfTouches >= GetMinimumTouchesRequired()) && + (panEvent->numberOfTouches <= GetMaximumTouchesRequired())) + { + // Check if the detector requires directional panning. + if(RequiresDirectionalPan() && renderTask) + { + // It does, calculate the angle of the pan in local actor coordinates and ensures it fits + // the detector's criteria. + RenderTask& renderTaskImpl = *renderTask.Get(); + + Vector2 startPosition, currentPosition; + actor->ScreenToLocal(renderTaskImpl, startPosition.x, startPosition.y, possiblePanPosition.x, possiblePanPosition.y); + actor->ScreenToLocal(renderTaskImpl, currentPosition.x, currentPosition.y, panEvent->currentPosition.x, panEvent->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(CheckAngleAllowed(angle)) + { + retVal = true; + } + } + else + { + // Directional panning not required so we can use this actor and gesture detector. + retVal = true; + } + } + return retVal; +} + +void PanGestureDetector::CancelProcessing() +{ + if(mGestureRecognizer) + { + mGestureRecognizer->CancelEvent(); + } +} + + +void PanGestureDetector::EmitPanSignal(Actor* actor, + const PanGestureEvent& panEvent, + Vector2 localCurrent, + GestureState state, + RenderTaskPtr renderTask) +{ + SetDetected(true); + Internal::PanGesturePtr pan(new Internal::PanGesture(panEvent.state)); + + pan->SetTime(panEvent.time); + + pan->SetNumberOfTouches(panEvent.numberOfTouches); + pan->SetScreenPosition(panEvent.currentPosition); + pan->SetPosition(localCurrent); + pan->SetSourceType(panEvent.sourceType); + pan->SetSourceData(panEvent.sourceData); + + RenderTask& renderTaskImpl(*renderTask.Get()); + + Vector2 localPrevious; + actor->ScreenToLocal(renderTaskImpl, localPrevious.x, localPrevious.y, panEvent.previousPosition.x, panEvent.previousPosition.y); + + pan->SetDisplacement(localCurrent - localPrevious); + Vector2 previousPos(panEvent.previousPosition); + if(panEvent.state == GestureState::STARTED) + { + previousPos = mPossiblePanPosition; + } + + pan->SetScreenDisplacement(panEvent.currentPosition - previousPos); + + // Avoid dividing by 0 + if(panEvent.timeDelta > 0) + { + Vector2 velocity; + velocity.x = pan->GetDisplacement().x / static_cast(panEvent.timeDelta); + velocity.y = pan->GetDisplacement().y / static_cast(panEvent.timeDelta); + pan->SetVelocity(velocity); + + Vector2 screenVelocity; + screenVelocity.x = pan->GetScreenDisplacement().x / static_cast(panEvent.timeDelta); + screenVelocity.y = pan->GetScreenDisplacement().y / static_cast(panEvent.timeDelta); + pan->SetScreenVelocity(screenVelocity); + } + + // 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((panEvent.state == GestureState::FINISHED) && (pan->GetScreenVelocity() == Vector2::ZERO) && + (panEvent.timeDelta < MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY)) + { + pan->SetVelocity(mLastVelocity); + pan->SetScreenVelocity(mLastScreenVelocity); + } + else + { + // Store the current velocity for future iterations. + mLastVelocity = pan->GetVelocity(); + mLastScreenVelocity = pan->GetScreenVelocity(); + } + + 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.Get()); + } + + Dali::Actor actorHandle(actor); + + EmitPanGestureSignal(actorHandle, Dali::PanGesture(pan.Get())); +} + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.h b/dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.h index a03f681..e84e24d 100644 --- a/dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.h +++ b/dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.h @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include +#include #include #include #include @@ -44,7 +45,7 @@ class PanGesture; /** * @copydoc Dali::PanGestureDetector */ -class PanGestureDetector : public GestureDetector +class PanGestureDetector : public GestureDetector, public RecognizerObserver { public: // Typedefs using AngleThresholdPair = Dali::PanGestureDetector::AngleThresholdPair; @@ -135,6 +136,18 @@ public: */ bool CheckAngleAllowed(Radian angle) const; + /** + * pan gesture-detector meets the parameters of the current gesture. + * + * @param[in] gestureEvent The gesture event. + * @param[in] actor The actor that has been gestured. + * @param[in] renderTask The renderTask. + * @param[in] possiblePanPosition The possiblePanPosition. + * + * @return true, if the detector meets the parameters, false otherwise. + */ + bool CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask, Vector2 possiblePanPosition); + public: /** * Called by the PanGestureProcessor when a pan gesture event occurs within the bounds of our @@ -210,6 +223,48 @@ private: */ void OnActorDestroyed(Object& object) override; + /** + * @copydoc Dali::Internal::GestureDetector::OnTouchEvent(Dali::Actor, const Dali::TouchEvent&) + */ + bool OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) override; + + /** + * @copydoc Dali::Internal::GestureDetector::ProcessTouchEvent(Scene&, const Integration::TouchEvent&) + */ + void ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) override; + + /** + * @copydoc Dali::Internal::GestureDetector::CheckGestureDetector(const GestureEvent*, Actor*, RenderTaskPtr) + */ + bool CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask) override + { + // pan gesture use CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask, Vector2 possiblePanPosition) api + return true; + } + + /** + * @copydoc Dali::Internal::GestureDetector::CancelProcessing() + */ + void CancelProcessing() override; + + /** + * 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) override; + + /** + * Creates a PanGesture and emit its detected signal. + * @param[in] actor The actor that has been panned. + * @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 PanGestureEvent& panEvent, Vector2 localCurrent, GestureState state, RenderTaskPtr renderTask); + + // Default property extensions from Object /** @@ -235,11 +290,19 @@ private: private: Dali::PanGestureDetector::DetectedSignalType mDetectedSignal; - uint32_t mMinimumTouches; ///< The minimum number of fingers required to be touching for pan. - uint32_t mMaximumTouches; ///< The maximum number of fingers required to be touching for pan. - uint32_t mMaximumMotionEventAge; ///< The maximum age of motion events as milliseconds. + uint32_t mMinimumTouches; ///< The minimum number of fingers required to be touching for pan. + uint32_t mMaximumTouches; ///< The maximum number of fingers required to be touching for pan. + uint32_t mMaximumMotionEventAge; ///< The maximum age of motion events as milliseconds. + + AngleContainer mAngleContainer; ///< A container of all angles allowed for pan to occur. + + Vector2 mPossiblePanPosition; ///< The Position when possible state. + Vector2 mLastVelocity; ///< The last recorded velocity in local actor coordinates. + Vector2 mLastScreenVelocity; ///< The last recorded velocity in screen coordinates. + ActorObserver mCurrentPanActor; ///< The current actor that has been gestured. + SceneGraph::PanGesture* mSceneObject; ///< Not owned, but we write to it directly + - AngleContainer mAngleContainer; ///< A container of all angles allowed for pan to occur. }; } // namespace Internal diff --git a/dali/internal/event/events/pan-gesture/pan-gesture-processor.cpp b/dali/internal/event/events/pan-gesture/pan-gesture-processor.cpp index 4df4ee7..d9667f7 100644 --- a/dali/internal/event/events/pan-gesture/pan-gesture-processor.cpp +++ b/dali/internal/event/events/pan-gesture/pan-gesture-processor.cpp @@ -131,6 +131,8 @@ PanGestureProcessor::PanGestureProcessor(SceneGraph::UpdateManager& updateManage mMinTouchesRequired(1), mMaxTouchesRequired(1), mMaxMotionEventAge(std::numeric_limits::max()), + mMinimumDistance(-1), + mMinimumPanEvents(-1), mCurrentPanEvent(nullptr), mSceneObject(SceneGraph::PanGesture::New()) // Create scene object to store pan information. { @@ -453,6 +455,7 @@ void PanGestureProcessor::SetMinimumDistance(int32_t value) { if(mGestureRecognizer) { + mMinimumDistance = value; PanGestureRecognizer* panRecognizer = dynamic_cast(mGestureRecognizer.Get()); if(panRecognizer) { @@ -465,6 +468,7 @@ void PanGestureProcessor::SetMinimumPanEvents(int32_t value) { if(mGestureRecognizer) { + mMinimumPanEvents = value; PanGestureRecognizer* panRecognizer = dynamic_cast(mGestureRecognizer.Get()); if(panRecognizer) { @@ -473,6 +477,16 @@ void PanGestureProcessor::SetMinimumPanEvents(int32_t value) } } +int32_t PanGestureProcessor::GetMinimumDistance() const +{ + return mMinimumDistance; +} + +int32_t PanGestureProcessor::GetMinimumPanEvents() const +{ + return mMinimumPanEvents; +} + const SceneGraph::PanGesture& PanGestureProcessor::GetSceneObject() const { @@ -622,71 +636,13 @@ void PanGestureProcessor::OnGesturedActorStageDisconnection() bool PanGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor) { DALI_ASSERT_DEBUG(mCurrentPanEvent); - - bool retVal(false); - PanGestureDetector* panDetector(static_cast(detector)); - - if((mCurrentPanEvent->numberOfTouches >= panDetector->GetMinimumTouchesRequired()) && - (mCurrentPanEvent->numberOfTouches <= panDetector->GetMaximumTouchesRequired())) + bool ret = false; + if(detector) { - // 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; - } + PanGestureDetector* panDetector(static_cast(detector)); + ret = panDetector->CheckGestureDetector(mCurrentPanEvent, actor, mCurrentRenderTask, mPossiblePanPosition); } - return retVal; + return ret; } void PanGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates) diff --git a/dali/internal/event/events/pan-gesture/pan-gesture-processor.h b/dali/internal/event/events/pan-gesture/pan-gesture-processor.h index c9f60c3..bcb870f 100644 --- a/dali/internal/event/events/pan-gesture/pan-gesture-processor.h +++ b/dali/internal/event/events/pan-gesture/pan-gesture-processor.h @@ -239,6 +239,18 @@ public: // for PanGestureDetector */ const SceneGraph::PanGesture& GetSceneObject() const; + /** + * Gets the minimum distance to start a pan + * @return The distance in pixels + */ + int32_t GetMinimumDistance() const; + + /** + * Gets the minimum touch events required before a pan can be started + * @return The number of touch events + */ + int32_t GetMinimumPanEvents() const; + private: // Undefined PanGestureProcessor(const PanGestureProcessor&); @@ -296,6 +308,9 @@ private: Vector2 mLastVelocity; ///< The last recorded velocity in local actor coordinates. Vector2 mLastScreenVelocity; ///< The last recorded velocity in screen coordinates. + int32_t mMinimumDistance; + int32_t mMinimumPanEvents; + const PanGestureEvent* mCurrentPanEvent; ///< Pointer to current PanEvent, used when calling ProcessAndEmit() SceneGraph::PanGesture* mSceneObject; ///< Not owned, but we write to it directly }; diff --git a/dali/internal/event/events/pan-gesture/pan-gesture-recognizer.cpp b/dali/internal/event/events/pan-gesture/pan-gesture-recognizer.cpp index d5b40d0..1494096 100644 --- a/dali/internal/event/events/pan-gesture/pan-gesture-recognizer.cpp +++ b/dali/internal/event/events/pan-gesture/pan-gesture-recognizer.cpp @@ -65,7 +65,8 @@ PanGestureRecognizer::PanGestureRecognizer(Observer& observer, Vector2 screenSiz mMinimumDistanceSquared(static_cast(MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED)), mMinimumMotionEvents(MINIMUM_MOTION_EVENTS_BEFORE_PAN), mMotionEvents(0), - mMaximumMotionEventAge(request.maxMotionEventAge) + mMaximumMotionEventAge(request.maxMotionEventAge), + mPrimaryDeviceId(-1) { if(minimumDistance >= 0) { @@ -100,6 +101,7 @@ void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event) } mState = CLEAR; // We should change our state to CLEAR. mTouchEvents.clear(); + mPrimaryDeviceId = -1; } else { @@ -109,14 +111,18 @@ void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event) { if((primaryPointState == PointState::DOWN) || (primaryPointState == PointState::STATIONARY) || (primaryPointState == PointState::MOTION)) { - mPrimaryTouchDownLocation = event.points[0].GetScreenPosition(); + mPrimaryTouchDownLocation = mPreviousPosition = event.points[0].GetScreenPosition(); mPrimaryTouchDownTime = event.time; mMotionEvents = 0; - if(event.GetPointCount() == mMinimumTouchesRequired) + + uint32_t pointCount(event.GetPointCount()); + if(pointCount == 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(GestureState::POSSIBLE, event); + if(SendPan(GestureState::POSSIBLE, event)) + { + mState = POSSIBLE; + } } mTouchEvents.push_back(event); @@ -126,7 +132,7 @@ void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event) case POSSIBLE: { - unsigned int pointCount(event.GetPointCount()); + uint32_t pointCount(event.GetPointCount()); if((pointCount >= mMinimumTouchesRequired) && (pointCount <= mMaximumTouchesRequired)) { if(primaryPointState == PointState::MOTION) @@ -140,8 +146,11 @@ void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event) (delta.LengthSquared() >= static_cast(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(GestureState::STARTED, event); + if(SendPan(GestureState::STARTED, event)) + { + mState = STARTED; + } + } } else if(primaryPointState == PointState::UP) @@ -210,9 +219,11 @@ void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event) case PointState::UP: // Pan is finally finished when our primary point is lifted, tell Core and change our state to CLEAR. - mState = CLEAR; - SendPan(GestureState::FINISHED, event); - mTouchEvents.clear(); + if(SendPan(GestureState::FINISHED, event)) + { + mState = CLEAR; + mTouchEvents.clear(); + } break; case PointState::STATIONARY: @@ -224,8 +235,10 @@ void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event) 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(GestureState::FINISHED, event); - mState = FINISHED; + if(SendPan(GestureState::FINISHED, event)) + { + mState = FINISHED; + } break; } } @@ -246,6 +259,7 @@ void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event) // If this was the primary point being released, then we change our state back to CLEAR... mState = CLEAR; mTouchEvents.clear(); + mPrimaryDeviceId = -1; } else { @@ -264,6 +278,7 @@ void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event) // Change our state back to clear when the primary touch point is released. mState = CLEAR; mTouchEvents.clear(); + mPrimaryDeviceId = -1; } break; } @@ -271,6 +286,18 @@ void PanGestureRecognizer::SendEvent(const Integration::TouchEvent& event) } } +void PanGestureRecognizer::CancelEvent() +{ + if(mState != CLEAR && mTouchEvents.size() > 0) + { + const Integration::TouchEvent& previousEvent(*(mTouchEvents.rbegin())); + SendPan(GestureState::CANCELLED, previousEvent); + mState = CLEAR; + mTouchEvents.clear(); + mPrimaryDeviceId = -1; + } +} + void PanGestureRecognizer::Update(const GestureRequest& request) { const PanGestureRequest& pan = static_cast(request); @@ -280,7 +307,7 @@ void PanGestureRecognizer::Update(const GestureRequest& request) mMaximumMotionEventAge = pan.maxMotionEventAge; } -void PanGestureRecognizer::SendPan(GestureState state, const Integration::TouchEvent& currentEvent) +bool PanGestureRecognizer::SendPan(GestureState state, const Integration::TouchEvent& currentEvent) { PanGestureEvent gesture(state); gesture.currentPosition = currentEvent.points[0].GetScreenPosition(); @@ -299,6 +326,7 @@ void PanGestureRecognizer::SendPan(GestureState state, const Integration::TouchE { previousPosition = mPrimaryTouchDownLocation; previousTime = mPrimaryTouchDownTime; + mPrimaryDeviceId = currentEvent.points[0].GetDeviceId(); // 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 @@ -313,6 +341,10 @@ void PanGestureRecognizer::SendPan(GestureState state, const Integration::TouchE mThresholdAdjustmentPerFrame = Vector2::ZERO; } } + else if (state == GestureState::CONTINUING && mPrimaryDeviceId != currentEvent.points[0].GetDeviceId()) + { + return false; + } gesture.previousPosition = previousPosition; gesture.timeDelta = currentEvent.time - previousTime; @@ -343,6 +375,7 @@ void PanGestureRecognizer::SendPan(GestureState state, const Integration::TouchE mObserver.Process(*mScene, gesture); } + return true; } void PanGestureRecognizer::SetMinimumDistance(int32_t minimumDistance) diff --git a/dali/internal/event/events/pan-gesture/pan-gesture-recognizer.h b/dali/internal/event/events/pan-gesture/pan-gesture-recognizer.h index c1b1f30..812409e 100644 --- a/dali/internal/event/events/pan-gesture/pan-gesture-recognizer.h +++ b/dali/internal/event/events/pan-gesture/pan-gesture-recognizer.h @@ -80,6 +80,11 @@ public: void SendEvent(const Integration::TouchEvent& event) override; /** + * @copydoc Dali::Internal::GestureDetector::CancelEvent() + */ + void CancelEvent() override; + + /** * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&) */ void Update(const GestureRequest& request) override; @@ -89,8 +94,9 @@ 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. + * @return bool true if send a pan event is successful */ - void SendPan(GestureState state, const Integration::TouchEvent& currentEvent); + bool SendPan(GestureState state, const Integration::TouchEvent& currentEvent); private: // Reference to the gesture processor for this recognizer @@ -127,6 +133,8 @@ private: uint32_t mMotionEvents; ///< The motion events received so far (before pan is emitted). uint32_t mMaximumMotionEventAge; ///< The maximum acceptable motion event age as Milliseconds. + + int mPrimaryDeviceId; }; } // namespace Internal diff --git a/dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.cpp b/dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.cpp index 9aa9652..c112d50 100644 --- a/dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.cpp +++ b/dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.cpp @@ -24,8 +24,12 @@ // INTERNAL INCLUDES #include #include +#include +#include #include #include +#include +#include namespace Dali { @@ -96,11 +100,19 @@ bool PinchGestureDetector::DoConnectSignal(BaseObject* object, ConnectionTracker void PinchGestureDetector::OnActorAttach(Actor& actor) { DALI_LOG_INFO(gLogFilter, Debug::General, "PinchGestureDetector attach actor(%d)\n", actor.GetId()); + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Connect(this, &PinchGestureDetector::OnTouchEvent); + } } void PinchGestureDetector::OnActorDetach(Actor& actor) { DALI_LOG_INFO(gLogFilter, Debug::General, "PinchGestureDetector detach actor(%d)\n", actor.GetId()); + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Disconnect(this, &PinchGestureDetector::OnTouchEvent); + } } void PinchGestureDetector::OnActorDestroyed(Object& object) @@ -108,6 +120,102 @@ void PinchGestureDetector::OnActorDestroyed(Object& object) // Do nothing } +bool PinchGestureDetector::OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) +{ + Dali::TouchEvent touchEvent(touch); + return HandleEvent(actor, touchEvent); +} + +void PinchGestureDetector::CancelProcessing() +{ + if(mGestureRecognizer) + { + mGestureRecognizer->CancelEvent(); + } +} + +void PinchGestureDetector::ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) +{ + if(!mGestureRecognizer) + { + const PinchGestureProcessor& mPinchGestureProcessor = mGestureEventProcessor.GetPinchGestureProcessor(); + float minimumPinchDistance = mPinchGestureProcessor.GetMinimumPinchDistance(); + uint32_t minimumTouchEvents = mPinchGestureProcessor.GetMinimumTouchEvents(); + uint32_t minimumTouchEventsAfterStart = mPinchGestureProcessor.GetMinimumTouchEventsAfterStart(); + + + Size size = scene.GetSize(); + mGestureRecognizer = new PinchGestureRecognizer(*this, Vector2(size.width, size.height), scene.GetDpi(), minimumPinchDistance, minimumTouchEvents, minimumTouchEventsAfterStart); + } + mGestureRecognizer->SendEvent(scene, event); +} + +void PinchGestureDetector::EmitPinchSignal(Actor* actor, const PinchGestureEvent& pinchEvent, Vector2 localCenter) +{ + SetDetected(true); + Internal::PinchGesturePtr pinch(new Internal::PinchGesture(pinchEvent.state)); + pinch->SetTime(pinchEvent.time); + + pinch->SetScale(pinchEvent.scale); + pinch->SetSpeed(pinchEvent.speed); + pinch->SetScreenCenterPoint(pinchEvent.centerPoint); + + pinch->SetLocalCenterPoint(localCenter); + pinch->SetSourceType(pinchEvent.sourceType); + pinch->SetSourceData(pinchEvent.sourceData); + + + Dali::Actor actorHandle(actor); + EmitPinchGestureSignal(actorHandle, Dali::PinchGesture(pinch.Get())); +} + +void PinchGestureDetector::Process(Scene& scene, const PinchGestureEvent& pinchEvent) +{ + switch(pinchEvent.state) + { + case GestureState::STARTED: + { + Actor* feededActor = mFeededActor.GetActor(); + if(feededActor && CheckGestureDetector(&pinchEvent, feededActor, mRenderTask)) + { + Vector2 actorCoords; + RenderTask& renderTaskImpl(*mRenderTask.Get()); + feededActor->ScreenToLocal(renderTaskImpl, actorCoords.x, actorCoords.y, pinchEvent.centerPoint.x, pinchEvent.centerPoint.y); + EmitPinchSignal(feededActor, pinchEvent, actorCoords); + } + break; + } + + case GestureState::CONTINUING: + case GestureState::FINISHED: + case GestureState::CANCELLED: + { + Actor* feededActor = mFeededActor.GetActor(); + if(feededActor && feededActor->IsHittable() && mRenderTask) + { + Vector2 actorCoords; + RenderTask& renderTaskImpl(*mRenderTask.Get()); + feededActor->ScreenToLocal(renderTaskImpl, actorCoords.x, actorCoords.y, pinchEvent.centerPoint.x, pinchEvent.centerPoint.y); + + EmitPinchSignal(feededActor, pinchEvent, actorCoords); + } + break; + } + + case GestureState::CLEAR: + { + DALI_ABORT("Incorrect state received from Integration layer: CLEAR\n"); + break; + } + case GestureState::POSSIBLE: + { + DALI_ABORT("Incorrect state received from Integration layer: POSSIBLE\n"); + break; + } + } +} + + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.h b/dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.h index bc52950..f7987c2 100644 --- a/dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.h +++ b/dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace Dali { @@ -35,7 +36,7 @@ using PinchGestureDetectorContainer = DerivedGestureDetectorContainer { public: // Creation /** @@ -105,6 +106,45 @@ private: // GestureDetector overrides */ void OnActorDestroyed(Object& object) override; + /** + * @copydoc Dali::Internal::GestureDetector::OnTouchEvent(Dali::Actor, const Dali::TouchEvent&) + */ + bool OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) override; + + /** + * @copydoc Dali::Internal::GestureDetector::ProcessTouchEvent(Scene&, const Integration::TouchEvent&) + */ + void ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) override; + + /** + * @copydoc Dali::Internal::GestureDetector::CheckGestureDetector(const GestureEvent*, Actor*, RenderTaskPtr) + */ + bool CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask) override + { + // No special case required for pinch. + return true; + } + + /** + * @copydoc Dali::Internal::GestureDetector::CancelProcessing() + */ + void CancelProcessing() override; + + /** + * This method is called whenever a pinch gesture event occurs. + * @param[in] scene The scene the tap gesture event occurs in. + * @param[in] pinchEvent The event that has occurred. + */ + void Process(Scene& scene, const PinchGestureEvent& pinchEvent) override; + + /** + * Creates a PinchGesture and asks the specified detector to emit its detected signal. + * @param[in] actor The actor that has been pinched. + * @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 PinchGestureEvent& pinchEvent, Vector2 localCenter); + private: Dali::PinchGestureDetector::DetectedSignalType mDetectedSignal; }; diff --git a/dali/internal/event/events/pinch-gesture/pinch-gesture-processor.cpp b/dali/internal/event/events/pinch-gesture/pinch-gesture-processor.cpp index 73e8dcd..9d7792e 100644 --- a/dali/internal/event/events/pinch-gesture/pinch-gesture-processor.cpp +++ b/dali/internal/event/events/pinch-gesture/pinch-gesture-processor.cpp @@ -175,6 +175,21 @@ void PinchGestureProcessor::SetMinimumTouchEventsAfterStart(uint32_t value) } } +float PinchGestureProcessor::GetMinimumPinchDistance() const +{ + return mMinimumPinchDistance; +} + +uint32_t PinchGestureProcessor::GetMinimumTouchEvents() const +{ + return mMinimumTouchEvents; +} + +uint32_t PinchGestureProcessor::GetMinimumTouchEventsAfterStart() const +{ + return mMinimumTouchEventsAfterStart; +} + void PinchGestureProcessor::Process(Scene& scene, const PinchGestureEvent& pinchEvent) { DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_PINCH_GESTURE"); @@ -314,8 +329,12 @@ void PinchGestureProcessor::OnGesturedActorStageDisconnection() bool PinchGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor) { - // No special case required for pinch. - return true; + bool ret = false; + if(detector) + { + ret = detector->CheckGestureDetector(mCurrentPinchEvent, actor, mCurrentRenderTask); + } + return ret; } void PinchGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates) diff --git a/dali/internal/event/events/pinch-gesture/pinch-gesture-processor.h b/dali/internal/event/events/pinch-gesture/pinch-gesture-processor.h index 9d7acf0..b5ea1a4 100644 --- a/dali/internal/event/events/pinch-gesture/pinch-gesture-processor.h +++ b/dali/internal/event/events/pinch-gesture/pinch-gesture-processor.h @@ -103,6 +103,24 @@ public: // To be called by GestureEventProcessor */ void GestureDetectorUpdated(PinchGestureDetector* gestureDetector); + /** + * @brief Gets the minimum distance to start a pinch + * @return The distance in pixels + */ + float GetMinimumPinchDistance() const; + + /** + * @brief Gets the minimum touch events required before a pinch can be started + * @return The number of touch events + */ + uint32_t GetMinimumTouchEvents() const; + + /** + * @brief Gets the minimum touch events required after a pinch started + * @return The number of touch events + */ + uint32_t GetMinimumTouchEventsAfterStart() const; + private: // Undefined PinchGestureProcessor(const PinchGestureProcessor&); diff --git a/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.cpp b/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.cpp index 9ab75a2..4409b9c 100644 --- a/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.cpp +++ b/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.cpp @@ -214,6 +214,17 @@ void PinchGestureRecognizer::SendEvent(const Integration::TouchEvent& event) } } +void PinchGestureRecognizer::CancelEvent() +{ + if(mState != CLEAR && mTouchEvents.size() > 0) + { + const Integration::TouchEvent& previousEvent(*(mTouchEvents.rbegin())); + SendPinch(GestureState::CANCELLED, previousEvent); + mState = CLEAR; + mTouchEvents.clear(); + } +} + void PinchGestureRecognizer::Update(const GestureRequest& request) { // Nothing to do. diff --git a/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.h b/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.h index 6343481..1f046da 100644 --- a/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.h +++ b/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.h @@ -78,6 +78,11 @@ public: void SendEvent(const Integration::TouchEvent& event) override; /** + * @copydoc Dali::Internal::GestureDetector::CancelEvent() + */ + void CancelEvent() override; + + /** * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&) */ void Update(const GestureRequest& request) override; diff --git a/dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.cpp b/dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.cpp index 07d6776..d29fa85 100644 --- a/dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.cpp +++ b/dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.cpp @@ -24,8 +24,11 @@ // INTERNAL INCLUDES #include #include +#include #include #include +#include +#include namespace Dali { @@ -94,11 +97,116 @@ bool RotationGestureDetector::DoConnectSignal(BaseObject* object, ConnectionTrac void RotationGestureDetector::OnActorAttach(Actor& actor) { DALI_LOG_INFO(gLogFilter, Debug::General, "RotationGestureDetector attach actor(%d)\n", actor.GetId()); + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Connect(this, &RotationGestureDetector::OnTouchEvent); + } } void RotationGestureDetector::OnActorDetach(Actor& actor) { DALI_LOG_INFO(gLogFilter, Debug::General, "RotationGestureDetector detach actor(%d)\n", actor.GetId()); + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Disconnect(this, &RotationGestureDetector::OnTouchEvent); + } +} + + +bool RotationGestureDetector::OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) +{ + Dali::TouchEvent touchEvent(touch); + return HandleEvent(actor, touchEvent); +} + +void RotationGestureDetector::CancelProcessing() +{ + if(mGestureRecognizer) + { + mGestureRecognizer->CancelEvent(); + } +} + +void RotationGestureDetector::ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) +{ + if(!mGestureRecognizer) + { + const RotationGestureProcessor& rotationGestureProcessor = mGestureEventProcessor.GetRotationGestureProcessor(); + uint32_t minimumTouchEvents = rotationGestureProcessor.GetMinimumTouchEvents(); + uint32_t minimumTouchEventsAfterStart = rotationGestureProcessor.GetMinimumTouchEventsAfterStart(); + + mGestureRecognizer = new RotationGestureRecognizer(*this, minimumTouchEvents, minimumTouchEventsAfterStart); + } + mGestureRecognizer->SendEvent(scene, event); +} + +/** + * Creates a RotationGesture and asks the specified detector to emit its detected signal. + * @param[in] actor The actor that has been rotationed. + * @param[in] gestureDetectors The gesture detector container that should emit the signal. + * @param[in] rotationEvent The rotationEvent received from the adaptor. + * @param[in] localCenter Relative to the actor attached to the detector. + */ +void RotationGestureDetector::EmitRotationSignal( + Actor* actor, + const RotationGestureEvent& rotationEvent, + Vector2 localCenter) +{ + SetDetected(true); + Internal::RotationGesturePtr rotation(new Internal::RotationGesture(rotationEvent.state)); + rotation->SetTime(rotationEvent.time); + rotation->SetRotation(rotationEvent.rotation); + rotation->SetScreenCenterPoint(rotationEvent.centerPoint); + rotation->SetLocalCenterPoint(localCenter); + rotation->SetSourceType(rotationEvent.sourceType); + rotation->SetSourceData(rotationEvent.sourceData); + + Dali::Actor actorHandle(actor); + EmitRotationGestureSignal(actorHandle, Dali::RotationGesture(rotation.Get())); +} + +void RotationGestureDetector::Process(Scene& scene, const RotationGestureEvent& rotationEvent) +{ + switch(rotationEvent.state) + { + case GestureState::STARTED: + { + Actor* feededActor = mFeededActor.GetActor(); + if(feededActor && CheckGestureDetector(&rotationEvent, feededActor, mRenderTask)) + { + Vector2 actorCoords; + RenderTask& renderTaskImpl(*mRenderTask.Get()); + feededActor->ScreenToLocal(renderTaskImpl, actorCoords.x, actorCoords.y, rotationEvent.centerPoint.x, rotationEvent.centerPoint.y); + EmitRotationSignal(feededActor, rotationEvent, actorCoords); + } + break; + } + + case GestureState::CONTINUING: + case GestureState::FINISHED: + case GestureState::CANCELLED: + { + // Only send subsequent rotation gesture signals if we processed the rotation gesture when it started. + // Check if actor is still touchable. + Actor* feededActor = mFeededActor.GetActor(); + if(feededActor && feededActor->IsHittable() && mRenderTask) + { + Vector2 actorCoords; + RenderTask& renderTaskImpl(*mRenderTask.Get()); + feededActor->ScreenToLocal(renderTaskImpl, actorCoords.x, actorCoords.y, rotationEvent.centerPoint.x, rotationEvent.centerPoint.y); + + EmitRotationSignal(feededActor, rotationEvent, actorCoords); + } + break; + } + + case GestureState::CLEAR: + case GestureState::POSSIBLE: + { + // Nothing to do + break; + } + } } } // namespace Internal diff --git a/dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.h b/dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.h index 2e0eb9e..4235866 100644 --- a/dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.h +++ b/dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace Dali { @@ -35,7 +36,7 @@ using RotationGestureDetectorContainer = DerivedGestureDetectorContainer { public: // Creation /** @@ -107,6 +108,45 @@ private: // GestureDetector overrides { /* Nothing to do */ } + /** + * @copydoc Dali::Internal::GestureDetector::OnTouchEvent(Dali::Actor, const Dali::TouchEvent&) + */ + bool OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) override; + + /** + * @copydoc Dali::Internal::GestureDetector::ProcessTouchEvent(Scene&, const Integration::TouchEvent&) + */ + void ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) override; + + /** + * @copydoc Dali::Internal::GestureDetector::CheckGestureDetector(const GestureEvent*, Actor*, RenderTaskPtr) + */ + bool CheckGestureDetector(const GestureEvent* longPressEvent, Actor* actor, RenderTaskPtr renderTask) override + { + // No special case required for rotation. + return true; + } + + /** + * @copydoc Dali::Internal::GestureDetector::CancelProcessing() + */ + void CancelProcessing() override; + + /** + * 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 RotationGestureEvent& tapEvent) override; + + /** + * Creates a RotationGesture emit its detected signal. + * @param[in] actor The actor that has been rotationed. + * @param[in] rotationEvent The rotationEvent received from the adaptor. + * @param[in] localCenter Relative to the actor attached to the detector. + */ + void EmitRotationSignal(Actor* actor, const RotationGestureEvent& rotationEvent, Vector2 localCenter); + private: Dali::RotationGestureDetector::DetectedSignalType mDetectedSignal; }; diff --git a/dali/internal/event/events/rotation-gesture/rotation-gesture-processor.cpp b/dali/internal/event/events/rotation-gesture/rotation-gesture-processor.cpp index a83b1b2..5809119 100644 --- a/dali/internal/event/events/rotation-gesture/rotation-gesture-processor.cpp +++ b/dali/internal/event/events/rotation-gesture/rotation-gesture-processor.cpp @@ -277,6 +277,16 @@ void RotationGestureProcessor::SetMinimumTouchEventsAfterStart(uint32_t value) } } +uint32_t RotationGestureProcessor::GetMinimumTouchEvents() const +{ + return mMinimumTouchEvents; +} + +uint32_t RotationGestureProcessor::GetMinimumTouchEventsAfterStart() const +{ + return mMinimumTouchEventsAfterStart; +} + void RotationGestureProcessor::OnGesturedActorStageDisconnection() { mCurrentRotationEmitters.clear(); @@ -284,8 +294,12 @@ void RotationGestureProcessor::OnGesturedActorStageDisconnection() bool RotationGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor) { - // No special case required for rotation. - return true; + bool ret = false; + if(detector) + { + ret = detector->CheckGestureDetector(mCurrentRotationEvent, actor, mCurrentRenderTask); + } + return ret; } void RotationGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates) diff --git a/dali/internal/event/events/rotation-gesture/rotation-gesture-processor.h b/dali/internal/event/events/rotation-gesture/rotation-gesture-processor.h index f1459bc..7be07d8 100644 --- a/dali/internal/event/events/rotation-gesture/rotation-gesture-processor.h +++ b/dali/internal/event/events/rotation-gesture/rotation-gesture-processor.h @@ -95,6 +95,18 @@ public: // To be called by GestureEventProcessor */ void SetMinimumTouchEventsAfterStart(uint32_t value); + /** + * @brief Gets the minimum touch events required before a rotation can be started + * @return The number of touch events + */ + uint32_t GetMinimumTouchEvents() const; + + /** + * @brief Gets the minimum touch events required after a rotation started + * @return The number of touch events + */ + uint32_t GetMinimumTouchEventsAfterStart() const; + private: // GestureProcessor overrides diff --git a/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.cpp b/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.cpp index dc10844..2e57e40 100644 --- a/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.cpp +++ b/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.cpp @@ -183,6 +183,17 @@ void RotationGestureRecognizer::SendEvent(const Integration::TouchEvent& event) } } +void RotationGestureRecognizer::CancelEvent() +{ + if(mState != CLEAR && mTouchEvents.size() > 0) + { + const Integration::TouchEvent& previousEvent(*(mTouchEvents.rbegin())); + SendRotation(GestureState::CANCELLED, previousEvent); + mState = CLEAR; + mTouchEvents.clear(); + } +} + void RotationGestureRecognizer::SetMinimumTouchEvents(uint32_t value) { mMinimumTouchEvents = value; diff --git a/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h b/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h index 886d2fc..a3aa2f8 100644 --- a/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h +++ b/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h @@ -62,6 +62,11 @@ public: void SendEvent(const Integration::TouchEvent& event) override; /** + * @copydoc Dali::Internal::GestureDetector::CancelEvent() + */ + void CancelEvent() override; + + /** * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&) */ void Update(const GestureRequest& request) override diff --git a/dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.cpp b/dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.cpp index 902f4d3..3a34a57 100644 --- a/dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.cpp +++ b/dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.cpp @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include #include @@ -77,7 +79,9 @@ TapGestureDetector::TapGestureDetector(uint32_t tapsRequired) mWaitTime(DEFAULT_TAP_WAIT_TIME), mTappedActor(), mTap(), - mReceiveAllTapEvents(false) + mCurrentTapActor(), + mReceiveAllTapEvents(false), + mPossibleProcessed(false) { } @@ -203,6 +207,7 @@ void TapGestureDetector::EmitTapGestureSignal(Dali::Actor tappedActor, const Dal else { mTappedActor = tappedActor; + mWaitTime = mGestureEventProcessor.GetTapGestureProcessor().GetMaximumAllowedTime(); mTimerId = platformAbstraction.StartTimer(mWaitTime, MakeCallback(this, &TapGestureDetector::TimerCallback)); } } @@ -241,13 +246,21 @@ bool TapGestureDetector::DoConnectSignal(BaseObject* object, ConnectionTrackerIn void TapGestureDetector::OnActorAttach(Actor& actor) { CheckMinMaxTapsRequired(); - mWaitTime = mGestureEventProcessor.GetTapGestureProcessor().GetMaximumAllowedTime(); DALI_LOG_INFO(gLogFilter, Debug::General, "TapGestureDetector attach actor(%d)\n", actor.GetId()); + + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Connect(this, &TapGestureDetector::OnTouchEvent); + } } void TapGestureDetector::OnActorDetach(Actor& actor) { DALI_LOG_INFO(gLogFilter, Debug::General, "TapGestureDetector detach actor(%d)\n", actor.GetId()); + if(actor.OnScene() && actor.GetScene().IsGeometryHittestEnabled()) + { + actor.TouchedSignal().Disconnect(this, &TapGestureDetector::OnTouchEvent); + } } void TapGestureDetector::OnActorDestroyed(Object& object) @@ -255,6 +268,104 @@ void TapGestureDetector::OnActorDestroyed(Object& object) // Do nothing } +bool TapGestureDetector::OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) +{ + Dali::TouchEvent touchEvent(touch); + return HandleEvent(actor, touchEvent); +} + +bool TapGestureDetector::CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask) +{ + const TapGestureEvent* tapEvent(static_cast(gestureEvent)); + + return (GetMinimumTapsRequired() <= tapEvent->numberOfTaps) && (GetTouchesRequired() == tapEvent->numberOfTouches); +} + +void TapGestureDetector::CancelProcessing() +{ + if(mGestureRecognizer) + { + mGestureRecognizer->CancelEvent(); + } +} + +// This is an API that is called by FeedTouch and recognizes gestures directly from the Detector without going through the Reconizer. +void TapGestureDetector::ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) +{ + if(!mGestureRecognizer) + { + TapGestureRequest request; + request.minTouches = GetMinimumTapsRequired(); + request.maxTouches = GetMaximumTapsRequired(); + + Size size = scene.GetSize(); + const TapGestureProcessor& mTapGestureProcessor = mGestureEventProcessor.GetTapGestureProcessor(); + + uint32_t maximumAllowedTime = mTapGestureProcessor.GetMaximumAllowedTime(); + uint32_t recognizerTime = mTapGestureProcessor.GetRecognizerTime(); + float maximumMotionAllowedDistance = mTapGestureProcessor.GetMaximumMotionAllowedDistance(); + + mGestureRecognizer = new TapGestureRecognizer(*this, Vector2(size.width, size.height), static_cast(request), maximumAllowedTime, recognizerTime, maximumMotionAllowedDistance); + } + mGestureRecognizer->SendEvent(scene, event); +} + +void TapGestureDetector::Process(Scene& scene, const TapGestureEvent& tapEvent) +{ + switch(tapEvent.state) + { + case GestureState::POSSIBLE: + { + mPossibleProcessed = true; + break; + } + case GestureState::STARTED: + { + Actor* feededActor = mFeededActor.GetActor(); + if(feededActor && CheckGestureDetector(&tapEvent, feededActor, mRenderTask) && mPossibleProcessed) + { + Vector2 actorCoords; + feededActor->ScreenToLocal(*mRenderTask.Get(), actorCoords.x, actorCoords.y, tapEvent.point.x, tapEvent.point.y); + + SetDetected(true); + Internal::TapGesturePtr tap(new Internal::TapGesture(tapEvent.state)); + tap->SetTime(tapEvent.time); + tap->SetNumberOfTaps(tapEvent.numberOfTaps); + tap->SetNumberOfTouches(tapEvent.numberOfTouches); + tap->SetScreenPoint(tapEvent.point); + tap->SetLocalPoint(actorCoords); + tap->SetSourceType(tapEvent.sourceType); + tap->SetSourceData(tapEvent.sourceData); + + Dali::Actor actorHandle(feededActor); + EmitTapGestureSignal(actorHandle, Dali::TapGesture(tap.Get())); + mPossibleProcessed = false; + } + break; + } + case GestureState::CANCELLED: + { + mPossibleProcessed = false; + break; + } + case GestureState::CONTINUING: + { + DALI_ABORT("Incorrect state received from Integration layer: CONTINUING\n"); + break; + } + case GestureState::FINISHED: + { + DALI_ABORT("Incorrect state received from Integration layer: FINISHED\n"); + break; + } + case GestureState::CLEAR: + { + DALI_ABORT("Incorrect state received from Integration layer: CLEAR\n"); + break; + } + } +} + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h b/dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h index 0f4b8b6..97d8a6f 100644 --- a/dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h +++ b/dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace Dali { @@ -35,7 +36,7 @@ using TapGestureDetectorContainer = DerivedGestureDetectorContainer { public: // Creation /** @@ -161,6 +162,33 @@ private: // GestureDetector overrides */ void OnActorDestroyed(Object& object) override; + /** + * @copydoc Dali::Internal::GestureDetector::OnTouchEvent(Dali::Actor, const Dali::TouchEvent&) + */ + bool OnTouchEvent(Dali::Actor actor, const Dali::TouchEvent& touch) override; + + /** + * @copydoc Dali::Internal::GestureDetector::ProcessTouchEvent(Scene&, const Integration::TouchEvent&) + */ + void ProcessTouchEvent(Scene& scene, const Integration::TouchEvent& event) override; + + /** + * @copydoc Dali::Internal::GestureDetector::CheckGestureDetector(const GestureEvent*, Actor*, RenderTaskPtr) + */ + bool CheckGestureDetector(const GestureEvent* gestureEvent, Actor* actor, RenderTaskPtr renderTask) override; + + /** + * @copydoc Dali::Internal::GestureDetector::CancelProcessing() + */ + void CancelProcessing() override; + + /** + * 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& tapEvent) override; + private: Dali::TapGestureDetector::DetectedSignalType mDetectedSignal; @@ -171,7 +199,9 @@ private: uint32_t mWaitTime; Dali::Actor mTappedActor; Dali::TapGesture mTap; - bool mReceiveAllTapEvents; + ActorObserver mCurrentTapActor; ///< The current actor that has been gestured. + bool mReceiveAllTapEvents : 1; + bool mPossibleProcessed : 1; ///< Indication of whether we've processed a touch down for this gestuee }; } // namespace Internal diff --git a/dali/internal/event/events/tap-gesture/tap-gesture-processor.cpp b/dali/internal/event/events/tap-gesture/tap-gesture-processor.cpp index e15e4c7..30a2dbd 100644 --- a/dali/internal/event/events/tap-gesture/tap-gesture-processor.cpp +++ b/dali/internal/event/events/tap-gesture/tap-gesture-processor.cpp @@ -110,6 +110,7 @@ void TapGestureProcessor::Process(Scene& scene, const TapGestureEvent& tapEvent) { case GestureState::POSSIBLE: { + ResetActor(); // 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)) @@ -120,10 +121,6 @@ void TapGestureProcessor::Process(Scene& scene, const TapGestureEvent& tapEvent) // 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; } @@ -289,6 +286,11 @@ void TapGestureProcessor::SetRecognizerTime(uint32_t time) } } +uint32_t TapGestureProcessor::GetRecognizerTime() const +{ + return mRecognizerTime; +} + void TapGestureProcessor::SetMaximumMotionAllowedDistance(float distance) { if(distance < 0.0f) @@ -309,6 +311,11 @@ void TapGestureProcessor::SetMaximumMotionAllowedDistance(float distance) } } +float TapGestureProcessor::GetMaximumMotionAllowedDistance() const +{ + return mMaximumMotionAllowedDistance; +} + void TapGestureProcessor::UpdateDetection() { DALI_ASSERT_DEBUG(!mTapGestureDetectors.empty()); @@ -342,17 +349,24 @@ void TapGestureProcessor::UpdateDetection() bool TapGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor) { DALI_ASSERT_DEBUG(mCurrentTapEvent); - - TapGestureDetector* tapDetector(static_cast(detector)); - - return (tapDetector->GetMinimumTapsRequired() <= mCurrentTapEvent->numberOfTaps) && (tapDetector->GetTouchesRequired() == mCurrentTapEvent->numberOfTouches); + bool ret = false; + if(detector) + { + ret = detector->CheckGestureDetector(mCurrentTapEvent, actor, nullptr); + } + return ret; } void TapGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates) { DALI_ASSERT_DEBUG(mCurrentTapEvent); + ResetActor(); EmitTapSignal(actor, gestureDetectors, *mCurrentTapEvent, actorCoordinates); + if(actor->OnScene()) + { + SetActor(actor); + } } } // namespace Internal diff --git a/dali/internal/event/events/tap-gesture/tap-gesture-processor.h b/dali/internal/event/events/tap-gesture/tap-gesture-processor.h index 5296942..e5eb3b9 100644 --- a/dali/internal/event/events/tap-gesture/tap-gesture-processor.h +++ b/dali/internal/event/events/tap-gesture/tap-gesture-processor.h @@ -108,6 +108,13 @@ public: // To be called by GestureEventProcessor void SetRecognizerTime(uint32_t time); /** + * @brief This method gets the recognizer time required to be recognized as a tap gesture (millisecond) + * + * @return The time value in milliseconds + */ + uint32_t GetRecognizerTime() const; + + /** * @brief This method sets the recognizer distance required to be recognized as a tap gesture * * This distance is from touch down to touch up to recognize the tap gesture. @@ -116,6 +123,13 @@ public: // To be called by GestureEventProcessor */ void SetMaximumMotionAllowedDistance(float distance); + /** + * @brief This method gets the recognizer distance required to be recognized as a tap gesture + * + * @return The distance value + */ + float GetMaximumMotionAllowedDistance() const; + private: // Undefined TapGestureProcessor(const TapGestureProcessor&); diff --git a/dali/internal/event/events/tap-gesture/tap-gesture-recognizer.cpp b/dali/internal/event/events/tap-gesture/tap-gesture-recognizer.cpp index c624a8e..1938268 100644 --- a/dali/internal/event/events/tap-gesture/tap-gesture-recognizer.cpp +++ b/dali/internal/event/events/tap-gesture/tap-gesture-recognizer.cpp @@ -157,6 +157,11 @@ void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event) } } +void TapGestureRecognizer::CancelEvent() +{ + mState = CLEAR; +} + void TapGestureRecognizer::SetupForTouchDown(const Integration::TouchEvent& event, const Integration::Point& point) { mTouchPosition = point.GetScreenPosition(); @@ -233,6 +238,7 @@ void TapGestureRecognizer::ProcessEvent(TapGestureEvent& event) { event.sourceType = mSourceType; event.sourceData = mSourceData; + if(mScene) { // Create another handle so the recognizer cannot be destroyed during process function diff --git a/dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h b/dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h index b36406c..bc7311c 100644 --- a/dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h +++ b/dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h @@ -69,6 +69,11 @@ public: void SendEvent(const Integration::TouchEvent& event) override; /** + * @copydoc Dali::Internal::GestureDetector::CancelEvent() + */ + void CancelEvent() override; + + /** * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&) */ void Update(const GestureRequest& request) override; diff --git a/dali/internal/event/events/touch-event-impl.h b/dali/internal/event/events/touch-event-impl.h index 6c1abf3..7e2c472 100644 --- a/dali/internal/event/events/touch-event-impl.h +++ b/dali/internal/event/events/touch-event-impl.h @@ -183,6 +183,11 @@ public: return mRenderTask; } + Dali::RenderTask& GetRenderTaskPtr() + { + return mRenderTask; + } + // Setters /** diff --git a/dali/internal/event/events/touch-event-processor.cpp b/dali/internal/event/events/touch-event-processor.cpp index 0222fcf..44792ef 100644 --- a/dali/internal/event/events/touch-event-processor.cpp +++ b/dali/internal/event/events/touch-event-processor.cpp @@ -486,6 +486,10 @@ struct TouchEventProcessor::Impl for(; rIter != processor.mCandidateActorLists.rend(); rIter++) { Actor* actorImpl(*rIter); + if(actorImpl == interceptedActor) + { + break; + } EmitTouchSignals(actorImpl, *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); } } @@ -502,14 +506,32 @@ struct TouchEventProcessor::Impl // Let's propagate touch events from the intercepted actor or start propagating touch events from the leaf actor. localVars.consumedActor = EmitGeoTouchSignals(interceptedActor ? processor.mInterceptedActorLists : processor.mCandidateActorLists, localVars.touchEventHandle); - // If consumed, the actors who previously received the touch are interrupted, indicating that the touch has been consumed by another actor. - if(localVars.consumedActor && localVars.primaryPointState != PointState::DOWN) + if(localVars.consumedActor) { - std::list::reverse_iterator rIter = std::find(processor.mCandidateActorLists.rbegin(), processor.mCandidateActorLists.rend(), localVars.consumedActor); - for(++rIter; rIter != processor.mCandidateActorLists.rend(); ++rIter) + // If consumed, the actors who previously received the touch are interrupted, indicating that the touch has been consumed by another actor. + // backworkd + if(localVars.primaryPointState != PointState::DOWN) { - Actor* actorImpl(*rIter); - EmitTouchSignals(actorImpl, *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); + std::list::reverse_iterator rIter = std::find(processor.mCandidateActorLists.rbegin(), processor.mCandidateActorLists.rend(), localVars.consumedActor); + if(rIter != processor.mCandidateActorLists.rend()) + { + for(++rIter; rIter != processor.mCandidateActorLists.rend(); ++rIter) + { + Actor* actorImpl(*rIter); + EmitTouchSignals(actorImpl, *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); + } + } + } + + //forward + std::list::iterator iter = std::find(processor.mCandidateActorLists.begin(), processor.mCandidateActorLists.end(), localVars.consumedActor); + if(iter != processor.mCandidateActorLists.end()) + { + for(++iter; iter != processor.mCandidateActorLists.end(); ++iter) + { + Actor* actorImpl(*iter); + EmitTouchSignals(actorImpl, *localVars.currentRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); + } } } } diff --git a/dali/internal/event/events/touch-event-processor.h b/dali/internal/event/events/touch-event-processor.h index c128c42..0230993 100644 --- a/dali/internal/event/events/touch-event-processor.h +++ b/dali/internal/event/events/touch-event-processor.h @@ -48,7 +48,7 @@ struct ActorObserver; * * - Hit Testing & Touch Event Delivery are described in Dali::Actor. */ -class TouchEventProcessor +class TouchEventProcessor : public RefObject { public: /** diff --git a/dali/public-api/events/gesture-detector.cpp b/dali/public-api/events/gesture-detector.cpp index a9cc55a..280697a 100644 --- a/dali/public-api/events/gesture-detector.cpp +++ b/dali/public-api/events/gesture-detector.cpp @@ -70,9 +70,14 @@ Actor GestureDetector::GetAttachedActor(size_t index) const return GetImplementation(*this).GetAttachedActor(index); } -bool GestureDetector::FeedTouch(Dali::Actor& actor, Dali::TouchEvent& touch) +bool GestureDetector::HandleEvent(Dali::Actor& actor, Dali::TouchEvent& touch) { - return GetImplementation(*this).FeedTouch(actor, touch); + return GetImplementation(*this).HandleEvent(actor, touch); +} + +void GestureDetector::CancelAllOtherGestureDetectors() +{ + GetImplementation(*this).CancelAllOtherGestureDetectors(); } } // namespace Dali diff --git a/dali/public-api/events/gesture-detector.h b/dali/public-api/events/gesture-detector.h index e94959d..72dc3ac 100644 --- a/dali/public-api/events/gesture-detector.h +++ b/dali/public-api/events/gesture-detector.h @@ -172,7 +172,12 @@ public: // Actor related * @param touch The thouch event * @return If true , the gesture is being recognized. */ - bool FeedTouch(Dali::Actor& actor, Dali::TouchEvent& touch); + bool HandleEvent(Dali::Actor& actor, Dali::TouchEvent& touch); + + /** + * @brief This method that cancels all other gesture detectors except the current gesture detector + */ + void CancelAllOtherGestureDetectors(); protected: /// @cond internal diff --git a/dali/public-api/signals/base-signal.h b/dali/public-api/signals/base-signal.h index 5420952..98a0a86 100644 --- a/dali/public-api/signals/base-signal.h +++ b/dali/public-api/signals/base-signal.h @@ -197,6 +197,46 @@ public: return returnVal; } + template + Ret EmitReturnOr(Args... args) + { + Ret returnVal = Ret(); + + // Guards against nested Emit() calls + EmitGuard guard(mEmittingFlag); + if(guard.ErrorOccurred()) + { + return returnVal; + } + + // Guards against calling CleanupConnections if the signal is deleted during emission + bool signalDeleted{false}; + mSignalDeleted = &signalDeleted; + + // If more connections are added by callbacks, these are ignore until the next Emit() + // Note that count cannot be reduced while iterating + auto count = mSignalConnections.size(); + auto iter = mSignalConnections.begin(); + while(count--) + { + CallbackBase* callback((*iter) ? iter->GetCallback() : nullptr); + ++iter; + if(callback) + { + returnVal |= CallbackBase::ExecuteReturn(*callback, args...); + } + } + + if(!signalDeleted) + { + // Cleanup NULL values from Connection container + CleanupConnections(); + mSignalDeleted = nullptr; + } + + return returnVal; + } + /** * @brief Emits a signal with parameter pack. * diff --git a/dali/public-api/signals/dali-signal.h b/dali/public-api/signals/dali-signal.h index 6401134..febabe2 100644 --- a/dali/public-api/signals/dali-signal.h +++ b/dali/public-api/signals/dali-signal.h @@ -893,6 +893,20 @@ public: { return Impl().template EmitReturn(arg0, arg1); } + + /** + * @brief Emits the signal. + * If any one of the multiple callbacks returns true, the entire callback is consumed. + * + * @SINCE_2_3.35 + * @param[in] arg0 The first value to pass to callbacks + * @param[in] arg1 The second value to pass to callbacks + * @return The value returned by the last callback, or a default constructed value if no callbacks are connected + */ + Ret EmitOr(Arg0 arg0, Arg1 arg1) + { + return Impl().template EmitReturnOr(arg0, arg1); + } }; /**