A new gesture recognition method. 69/309669/84
authorjoogab.yun <joogab.yun@samsung.com>
Mon, 15 Apr 2024 07:02:41 +0000 (16:02 +0900)
committerjoogab.yun <joogab.yun@samsung.com>
Thu, 13 Jun 2024 00:22:39 +0000 (09:22 +0900)
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

53 files changed:
automated-tests/src/dali/utc-Dali-GeoHitTestAlgorithm.cpp
automated-tests/src/dali/utc-Dali-GeoTouchProcessing.cpp
automated-tests/src/dali/utc-Dali-GestureDetector.cpp
automated-tests/src/dali/utc-Dali-LongPressGestureDetector.cpp
automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp
automated-tests/src/dali/utc-Dali-PinchGestureDetector.cpp
automated-tests/src/dali/utc-Dali-RotationGestureDetector.cpp
automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/events/event-processor.cpp
dali/internal/event/events/event-processor.h
dali/internal/event/events/gesture-detector-impl.cpp
dali/internal/event/events/gesture-detector-impl.h
dali/internal/event/events/gesture-event-processor.cpp
dali/internal/event/events/gesture-event-processor.h
dali/internal/event/events/gesture-recognizer.h
dali/internal/event/events/hit-test-algorithm-impl.cpp
dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.cpp
dali/internal/event/events/long-press-gesture/long-press-gesture-detector-impl.h
dali/internal/event/events/long-press-gesture/long-press-gesture-processor.cpp
dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.cpp
dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.h
dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.cpp
dali/internal/event/events/pan-gesture/pan-gesture-detector-impl.h
dali/internal/event/events/pan-gesture/pan-gesture-processor.cpp
dali/internal/event/events/pan-gesture/pan-gesture-processor.h
dali/internal/event/events/pan-gesture/pan-gesture-recognizer.cpp
dali/internal/event/events/pan-gesture/pan-gesture-recognizer.h
dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.cpp
dali/internal/event/events/pinch-gesture/pinch-gesture-detector-impl.h
dali/internal/event/events/pinch-gesture/pinch-gesture-processor.cpp
dali/internal/event/events/pinch-gesture/pinch-gesture-processor.h
dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.cpp
dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.h
dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.cpp
dali/internal/event/events/rotation-gesture/rotation-gesture-detector-impl.h
dali/internal/event/events/rotation-gesture/rotation-gesture-processor.cpp
dali/internal/event/events/rotation-gesture/rotation-gesture-processor.h
dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.cpp
dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h
dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.cpp
dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h
dali/internal/event/events/tap-gesture/tap-gesture-processor.cpp
dali/internal/event/events/tap-gesture/tap-gesture-processor.h
dali/internal/event/events/tap-gesture/tap-gesture-recognizer.cpp
dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h
dali/internal/event/events/touch-event-impl.h
dali/internal/event/events/touch-event-processor.cpp
dali/internal/event/events/touch-event-processor.h
dali/public-api/events/gesture-detector.cpp
dali/public-api/events/gesture-detector.h
dali/public-api/signals/base-signal.h
dali/public-api/signals/dali-signal.h

index bc7d30b..e122a5b 100644 (file)
@@ -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);
index 4d02050..40f4afc 100644 (file)
@@ -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
index 5221435..e12bbdb 100644 (file)
 
 #include <dali-test-suite-utils.h>
 #include <dali/public-api/dali-core.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/touch-integ.h>
+#include <dali/integration-api/render-task-list-integ.h>
+#include <dali/internal/event/events/touch-event-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
+#include <dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h>
 #include <stdlib.h>
 
 #include <algorithm>
@@ -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<MouseButton::Type>(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;
+}
index 3ed67dd..31262cf 100644 (file)
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/events/long-press-gesture-detector-devel.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/touch-integ.h>
 #include <dali/integration-api/input-options.h>
 #include <dali/integration-api/render-task-list-integ.h>
+#include <dali/internal/event/events/touch-event-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
 #include <dali/public-api/dali-core.h>
 #include <stdlib.h>
 #include <test-touch-event-utils.h>
@@ -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;
+}
index a1d4483..3d6a332 100644 (file)
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/events/pan-gesture-devel.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/touch-integ.h>
 #include <dali/integration-api/input-options.h>
 #include <dali/integration-api/profiling.h>
 #include <dali/integration-api/render-task-list-integ.h>
+#include <dali/internal/event/events/touch-event-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
 #include <dali/public-api/dali-core.h>
 #include <stdlib.h>
 #include <test-touch-event-utils.h>
@@ -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;
+}
index 2c45979..a6215f2 100644 (file)
 #include <dali-test-suite-utils.h>
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/touch-integ.h>
 #include <dali/integration-api/render-task-list-integ.h>
+#include <dali/internal/event/events/touch-event-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
 #include <dali/public-api/dali-core.h>
 #include <stdlib.h>
 #include <test-touch-event-utils.h>
@@ -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;
+}
index 8c1d929..f474ff7 100644 (file)
 #include <dali-test-suite-utils.h>
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/touch-integ.h>
 #include <dali/integration-api/render-task-list-integ.h>
+#include <dali/internal/event/events/touch-event-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
 #include <dali/public-api/dali-core.h>
 #include <stdlib.h>
 #include <test-touch-event-utils.h>
@@ -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;
+}
index 5c15b92..d09d3f6 100644 (file)
 #include <dali-test-suite-utils.h>
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/touch-integ.h>
 #include <dali/integration-api/render-task-list-integ.h>
+#include <dali/internal/event/events/touch-event-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
 #include <dali/public-api/dali-core.h>
 #include <stdlib.h>
 #include <test-touch-event-utils.h>
@@ -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;
+}
index 54ac552..b46eb90 100644 (file)
@@ -309,7 +309,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<typename Signal, typename Event>
+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;
 }
 
@@ -1001,11 +1015,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);
 }
 
index 442626e..abc3956 100644 (file)
@@ -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<Integration::TouchEvent&>(*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;
       }
 
index 6936898..d8f3b7c 100644 (file)
  *
  */
 
+// EXTERNAL INCLUDES
+#include <unordered_map>
+
 // INTERNAL INCLUDES
+#include <dali/integration-api/events/point.h>
 #include <dali/internal/common/message-buffer.h>
 #include <dali/internal/event/events/hover-event-processor.h>
 #include <dali/internal/event/events/key-event-processor.h>
@@ -38,6 +42,11 @@ class Scene;
 class GestureEventProcessor;
 class NotificationManager;
 
+using TouchPointsContainer          = std::list<Integration::Point>;
+using ActorTouchPointsContainer     = std::unordered_map<uint32_t, TouchPointsContainer>;
+
+using TouchEventProcessorsContainer = std::unordered_map<uint32_t, IntrusivePtr<TouchEventProcessor>>;
+using ActorIdDeviceIdContainer      = std::unordered_map<uint32_t, uint32_t>;
 /**
  * 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
index 1e98cb7..fc6f510 100644 (file)
@@ -27,6 +27,8 @@
 #include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/event/events/actor-gesture-data.h>
 #include <dali/internal/event/events/gesture-event-processor.h>
+#include <dali/internal/event/events/touch-event-impl.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
 
 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()) ||
index b7953ce..d58e581 100644 (file)
 
 // INTERNAL INCLUDES
 #include <dali/internal/event/actors/actor-impl.h>
+#include <dali/internal/event/events/actor-observer.h>
+#include <dali/internal/event/events/gesture-event.h>
+#include <dali/internal/event/events/gesture-recognizer.h>
+#include <dali/internal/event/render-tasks/render-task-impl.h>
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/events/gesture-detector.h>
@@ -41,6 +45,7 @@ class GestureEventProcessor;
 using GestureDetectorPtr            = IntrusivePtr<GestureDetector>;
 using GestureDetectorContainer      = std::vector<GestureDetector*>;
 using GestureDetectorActorContainer = std::vector<Actor*>;
+using GestureRecognizerPtr          = IntrusivePtr<GestureRecognizer>;
 
 /**
  * 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
index 1240148..350abc2 100644 (file)
@@ -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
index b54ea9d..2cf6346 100644 (file)
@@ -45,6 +45,8 @@ namespace Internal
 class Stage;
 class Scene;
 
+using GestureDetectorContainer = std::vector<GestureDetector*>;
+
 /**
  * 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;
index 0bc013d..fe4253d 100644 (file)
@@ -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.
    */
index 578f5fe..9f566d3 100644 (file)
@@ -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<float>::max();
     childHit.depth           = std::numeric_limits<int32_t>::min();
     ActorContainer& children = actor.GetChildrenInternal();
index 52c315e..b31307d 100644 (file)
 #include <cstring> // for strcmp
 
 // INTERNAL INCLUDES
-
+#include <dali/internal/event/common/scene-impl.h>
+#include <dali/internal/event/events/gesture-requests.h>
 #include <dali/internal/event/events/gesture-event-processor.h>
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-impl.h>
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-recognizer.h>
 #include <dali/public-api/object/type-registry.h>
 
 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<const LongPressGestureEvent*>(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<const LongPressGestureRequest&>(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
index 449b5d7..871b248 100644 (file)
@@ -21,6 +21,7 @@
 // INTERNAL INCLUDES
 #include <dali/internal/event/events/gesture-detector-impl.h>
 #include <dali/public-api/events/long-press-gesture-detector.h>
+#include <dali/internal/event/events/long-press-gesture/long-press-gesture-event.h>
 
 namespace Dali
 {
@@ -34,7 +35,7 @@ using LongPressGestureDetectorContainer = DerivedGestureDetectorContainer<LongPr
 /**
  * @copydoc Dali::LongPressGestureDetector
  */
-class LongPressGestureDetector : public GestureDetector
+class LongPressGestureDetector : public GestureDetector, public RecognizerObserver<LongPressGestureEvent>
 {
 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
index 6b680ae..32535ec 100644 (file)
@@ -344,11 +344,12 @@ void LongPressGestureProcessor::OnGesturedActorStageDisconnection()
 bool LongPressGestureProcessor::CheckGestureDetector(GestureDetector* detector, Actor* actor)
 {
   DALI_ASSERT_DEBUG(mCurrentLongPressEvent);
-
-  LongPressGestureDetector* longPressDetector(static_cast<LongPressGestureDetector*>(detector));
-
-  return (longPressDetector->GetMinimumTouchesRequired() <= mCurrentLongPressEvent->numberOfTouches) &&
-         (longPressDetector->GetMaximumTouchesRequired() >= mCurrentLongPressEvent->numberOfTouches);
+  bool ret = false;
+  if(detector)
+  {
+    ret = detector->CheckGestureDetector(mCurrentLongPressEvent, actor, mCurrentRenderTask);
+  }
+  return ret;
 }
 
 void LongPressGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates)
index eac654b..79c7188 100644 (file)
@@ -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<const LongPressGestureRequest&>(request);
index 9d60f38..ec6f3ad 100644 (file)
@@ -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;
index 93afaa5..4707ef3 100644 (file)
@@ -27,6 +27,8 @@
 #include <dali/internal/event/common/property-helper.h>
 #include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/event/events/gesture-event-processor.h>
+#include <dali/internal/event/events/gesture-requests.h>
+#include <dali/internal/event/events/pan-gesture/pan-gesture-recognizer.h>
 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
 #include <dali/public-api/events/pan-gesture.h>
 #include <dali/public-api/math/degree.h>
@@ -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<uint32_t>::max())
+  mMaximumMotionEventAge(std::numeric_limits<uint32_t>::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<const PanGestureRequest&>(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<const PanGestureEvent*>(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<float>(panEvent.timeDelta);
+    velocity.y = pan->GetDisplacement().y / static_cast<float>(panEvent.timeDelta);
+    pan->SetVelocity(velocity);
+
+    Vector2 screenVelocity;
+    screenVelocity.x = pan->GetScreenDisplacement().x / static_cast<float>(panEvent.timeDelta);
+    screenVelocity.y = pan->GetScreenDisplacement().y / static_cast<float>(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
index a03f681..e84e24d 100644 (file)
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/internal/event/events/gesture-detector-impl.h>
+#include <dali/internal/event/events/pan-gesture/pan-gesture-event.h>
 #include <dali/public-api/events/gesture.h>
 #include <dali/public-api/events/pan-gesture-detector.h>
 #include <dali/public-api/events/pan-gesture.h>
@@ -44,7 +45,7 @@ class PanGesture;
 /**
  * @copydoc Dali::PanGestureDetector
  */
-class PanGestureDetector : public GestureDetector
+class PanGestureDetector : public GestureDetector, public RecognizerObserver<PanGestureEvent>
 {
 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
index 4df4ee7..d9667f7 100644 (file)
@@ -131,6 +131,8 @@ PanGestureProcessor::PanGestureProcessor(SceneGraph::UpdateManager& updateManage
   mMinTouchesRequired(1),
   mMaxTouchesRequired(1),
   mMaxMotionEventAge(std::numeric_limits<uint32_t>::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<PanGestureRecognizer*>(mGestureRecognizer.Get());
     if(panRecognizer)
     {
@@ -465,6 +468,7 @@ void PanGestureProcessor::SetMinimumPanEvents(int32_t value)
 {
   if(mGestureRecognizer)
   {
+    mMinimumPanEvents = value;
     PanGestureRecognizer* panRecognizer = dynamic_cast<PanGestureRecognizer*>(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<PanGestureDetector*>(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<PanGestureDetector*>(detector));
+    ret = panDetector->CheckGestureDetector(mCurrentPanEvent, actor, mCurrentRenderTask, mPossiblePanPosition);
   }
-  return retVal;
+  return ret;
 }
 
 void PanGestureProcessor::EmitGestureSignal(Actor* actor, const GestureDetectorContainer& gestureDetectors, Vector2 actorCoordinates)
index c9f60c3..bcb870f 100644 (file)
@@ -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
 };
index d5b40d0..1494096 100644 (file)
@@ -65,7 +65,8 @@ PanGestureRecognizer::PanGestureRecognizer(Observer& observer, Vector2 screenSiz
   mMinimumDistanceSquared(static_cast<unsigned int>(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<float>(mMinimumDistanceSquared)))
             {
               // If the touch point(s) have moved enough distance to be considered a pan, then tell Core that the pan gesture has started and change our state accordingly.
-              mState = STARTED;
-              SendPan(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<const PanGestureRequest&>(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)
index c1b1f30..812409e 100644 (file)
@@ -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
index 9aa9652..c112d50 100644 (file)
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
 #include <dali/internal/event/events/gesture-event-processor.h>
+#include <dali/internal/event/events/gesture-requests.h>
+#include <dali/internal/event/common/scene-impl.h>
 #include <dali/public-api/events/pinch-gesture.h>
 #include <dali/public-api/object/type-registry.h>
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-impl.h>
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.h>
 
 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
index bc52950..f7987c2 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/internal/event/events/gesture-detector-impl.h>
 #include <dali/public-api/events/pinch-gesture-detector.h>
 #include <dali/public-api/events/pinch-gesture.h>
+#include <dali/internal/event/events/pinch-gesture/pinch-gesture-event.h>
 
 namespace Dali
 {
@@ -35,7 +36,7 @@ using PinchGestureDetectorContainer = DerivedGestureDetectorContainer<PinchGestu
 /**
  * @copydoc Dali::PinchGestureDetector
  */
-class PinchGestureDetector : public GestureDetector
+class PinchGestureDetector : public GestureDetector, public RecognizerObserver<PinchGestureEvent>
 {
 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;
 };
index 73e8dcd..9d7792e 100644 (file)
@@ -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)
index 9d7acf0..b5ea1a4 100644 (file)
@@ -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&);
index 9ab75a2..4409b9c 100644 (file)
@@ -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.
index 6343481..1f046da 100644 (file)
@@ -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;
index 07d6776..d29fa85 100644 (file)
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
 #include <dali/internal/event/events/gesture-event-processor.h>
+#include <dali/internal/event/common/scene-impl.h>
 #include <dali/public-api/events/rotation-gesture.h>
 #include <dali/public-api/object/type-registry.h>
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-impl.h>
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.h>
 
 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
index 2e0eb9e..4235866 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/internal/event/events/gesture-detector-impl.h>
 #include <dali/public-api/events/rotation-gesture-detector.h>
 #include <dali/public-api/events/rotation-gesture.h>
+#include <dali/internal/event/events/rotation-gesture/rotation-gesture-event.h>
 
 namespace Dali
 {
@@ -35,7 +36,7 @@ using RotationGestureDetectorContainer = DerivedGestureDetectorContainer<Rotatio
 /**
  * @copydoc Dali::RotationGestureDetector
  */
-class RotationGestureDetector : public GestureDetector
+class RotationGestureDetector : public GestureDetector, public RecognizerObserver<RotationGestureEvent>
 {
 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;
 };
index a83b1b2..5809119 100644 (file)
@@ -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)
index f1459bc..7be07d8 100644 (file)
@@ -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
 
index dc10844..2e57e40 100644 (file)
@@ -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;
index 886d2fc..a3aa2f8 100644 (file)
@@ -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
index 902f4d3..3a34a57 100644 (file)
@@ -26,7 +26,9 @@
 #include <dali/integration-api/platform-abstraction.h>
 #include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/event/events/gesture-event-processor.h>
+#include <dali/internal/event/events/gesture-requests.h>
 #include <dali/internal/event/events/tap-gesture/tap-gesture-impl.h>
+#include <dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h>
 #include <dali/public-api/events/tap-gesture.h>
 #include <dali/public-api/object/type-registry.h>
 
@@ -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<const TapGestureEvent*>(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<const TapGestureRequest&>(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
index 0f4b8b6..97d8a6f 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/internal/event/events/gesture-detector-impl.h>
 #include <dali/public-api/events/tap-gesture-detector.h>
 #include <dali/public-api/events/tap-gesture.h>
+#include <dali/internal/event/events/tap-gesture/tap-gesture-event.h>
 
 namespace Dali
 {
@@ -35,7 +36,7 @@ using TapGestureDetectorContainer = DerivedGestureDetectorContainer<TapGestureDe
 /**
  * @copydoc Dali::TapGestureDetector
  */
-class TapGestureDetector : public GestureDetector
+class TapGestureDetector : public GestureDetector, public RecognizerObserver<TapGestureEvent>
 {
 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
index e15e4c7..30a2dbd 100644 (file)
@@ -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<TapGestureDetector*>(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
index 5296942..e5eb3b9 100644 (file)
@@ -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&);
index c624a8e..1938268 100644 (file)
@@ -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
index b36406c..bc7311c 100644 (file)
@@ -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;
index 6c1abf3..7e2c472 100644 (file)
@@ -183,6 +183,11 @@ public:
     return mRenderTask;
   }
 
+  Dali::RenderTask& GetRenderTaskPtr()
+  {
+    return mRenderTask;
+  }
+
   // Setters
 
   /**
index 0c35355..0ead0f9 100644 (file)
@@ -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<Dali::Internal::Actor*>::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<Dali::Internal::Actor*>::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<Dali::Internal::Actor*>::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);
+                }
               }
             }
           }
index c128c42..0230993 100644 (file)
@@ -48,7 +48,7 @@ struct ActorObserver;
  *
  * - Hit Testing & Touch Event Delivery are described in Dali::Actor.
  */
-class TouchEventProcessor
+class TouchEventProcessor : public RefObject
 {
 public:
   /**
index a9cc55a..280697a 100644 (file)
@@ -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
index e94959d..72dc3ac 100644 (file)
@@ -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
index 5420952..98a0a86 100644 (file)
@@ -197,6 +197,46 @@ public:
     return returnVal;
   }
 
+  template<typename Ret, typename... Args>
+  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<Ret, Args...>(*callback, args...);
+      }
+    }
+
+    if(!signalDeleted)
+    {
+      // Cleanup NULL values from Connection container
+      CleanupConnections();
+      mSignalDeleted = nullptr;
+    }
+
+    return returnVal;
+  }
+
   /**
    * @brief Emits a signal with  parameter pack.
    *
index 6401134..febabe2 100644 (file)
@@ -893,6 +893,20 @@ public:
   {
     return Impl().template EmitReturn<Ret, Arg0, Arg1>(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<Ret, Arg0, Arg1>(arg0, arg1);
+  }
 };
 
 /**