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);
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;
}
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);
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);
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();
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);
// 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);
// 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);
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
#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>
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;
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;
+}
#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>
}
};
+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
///////////////////////////////////////////////////////////////////////////////
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;
+}
#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>
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
{
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
///////////////////////////////////////////////////////////////////////////////
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;
+}
#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>
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
///////////////////////////////////////////////////////////////////////////////
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;
+}
#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>
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
///////////////////////////////////////////////////////////////////////////////
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;
+}
#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>
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;
+}
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;
}
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);
}
mWheelEventProcessor(scene),
mEventQueue0(INITIAL_BUFFER_SIZE),
mEventQueue1(INITIAL_BUFFER_SIZE),
- mCurrentEventQueue(&mEventQueue0)
+ mCurrentEventQueue(&mEventQueue0),
+ mTouchEventProcessors(),
+ mActorTouchPoints(),
+ mActorIdDeviceId()
{
}
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;
}
*
*/
+// 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>
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.
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
#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
{
: Object(sceneObject),
mType(type),
mGestureEventProcessor(ThreadLocalStorage::Get().GetGestureEventProcessor()),
+ mFeededActor(),
+ mRenderTask(nullptr),
+ mGestureRecognizer(),
mIsDetected(false)
{
}
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
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()) ||
// 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>
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.
/**
* @copydoc Dali::GestureDetector
*/
-class GestureDetector : public Object, public Object::Observer
+class GestureDetector : public Object, public Object::Observer, public ConnectionTracker
{
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.
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.
*/
*/
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.
*/
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
mTapGestureProcessor(),
mRotationGestureProcessor(),
mRenderController(renderController),
+ mGestureDetectors(),
envOptionMinimumPanDistance(-1),
envOptionMinimumPanEvents(-1)
{
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())
return mTapGestureProcessor;
}
+const PinchGestureProcessor& GestureEventProcessor::GetPinchGestureProcessor()
+{
+ return mPinchGestureProcessor;
+}
+
+const RotationGestureProcessor& GestureEventProcessor::GetRotationGestureProcessor()
+{
+ return mRotationGestureProcessor;
+}
+
} // namespace Internal
} // namespace Dali
class Stage;
class Scene;
+using GestureDetectorContainer = std::vector<GestureDetector*>;
+
/**
* Gesture Event Processing:
*
*/
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
*/
const TapGestureProcessor& GetTapGestureProcessor();
+ /**
+ * @return the pinch gesture processor
+ */
+ const PinchGestureProcessor& GetPinchGestureProcessor();
+
+ /**
+ * @return the rotation gesture processor
+ */
+ const RotationGestureProcessor& GetRotationGestureProcessor();
+
private:
// Undefined
GestureEventProcessor(const GestureEventProcessor&);
TapGestureProcessor mTapGestureProcessor;
RotationGestureProcessor mRotationGestureProcessor;
Integration::RenderController& mRenderController;
+ GestureDetectorContainer mGestureDetectors;
int32_t envOptionMinimumPanDistance;
int32_t envOptionMinimumPanEvents;
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.
*/
/**
* 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,
HitActor& hit,
bool isGeometry)
{
- if(clippingActor || hitCheck.IsActorHittable(&actor))
+ bool isClippingOrHittable = clippingActor || hitCheck.IsActorHittable(&actor);
+ if(isClippingOrHittable || isGeometry)
{
Vector3 size(actor.GetCurrentSize());
// 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.
}
// 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;
}
}
}
+ return true;
}
/**
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.
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();
#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
namespace
{
-const unsigned int DEFAULT_TOUCHES_REQUIRED = 1;
+const uint32_t DEFAULT_TOUCHES_REQUIRED = 1;
} // unnamed namespace
LongPressGestureDetectorPtr LongPressGestureDetector::New()
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)
// 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
// 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
{
/**
* @copydoc Dali::LongPressGestureDetector
*/
-class LongPressGestureDetector : public GestureDetector
+class LongPressGestureDetector : public GestureDetector, public RecognizerObserver<LongPressGestureEvent>
{
public: // Creation
/**
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&)
*/
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
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)
}
}
+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);
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;
#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>
{
namespace
{
+const unsigned long MAXIMUM_TIME_WITH_VALID_LAST_VELOCITY(50u);
// Properties
// Name Type writable animatable constraint-input enum for index-checking
: 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())
{
}
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)
// 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
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
// 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>
/**
* @copydoc Dali::PanGestureDetector
*/
-class PanGestureDetector : public GestureDetector
+class PanGestureDetector : public GestureDetector, public RecognizerObserver<PanGestureEvent>
{
public: // Typedefs
using AngleThresholdPair = Dali::PanGestureDetector::AngleThresholdPair;
*/
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
*/
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
/**
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
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.
{
{
if(mGestureRecognizer)
{
+ mMinimumDistance = value;
PanGestureRecognizer* panRecognizer = dynamic_cast<PanGestureRecognizer*>(mGestureRecognizer.Get());
if(panRecognizer)
{
{
if(mGestureRecognizer)
{
+ mMinimumPanEvents = value;
PanGestureRecognizer* panRecognizer = dynamic_cast<PanGestureRecognizer*>(mGestureRecognizer.Get());
if(panRecognizer)
{
}
}
+int32_t PanGestureProcessor::GetMinimumDistance() const
+{
+ return mMinimumDistance;
+}
+
+int32_t PanGestureProcessor::GetMinimumPanEvents() const
+{
+ return mMinimumPanEvents;
+}
+
const SceneGraph::PanGesture& PanGestureProcessor::GetSceneObject() const
{
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)
*/
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&);
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
};
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)
{
}
mState = CLEAR; // We should change our state to CLEAR.
mTouchEvents.clear();
+ mPrimaryDeviceId = -1;
}
else
{
{
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);
case POSSIBLE:
{
- unsigned int pointCount(event.GetPointCount());
+ uint32_t pointCount(event.GetPointCount());
if((pointCount >= mMinimumTouchesRequired) && (pointCount <= mMaximumTouchesRequired))
{
if(primaryPointState == PointState::MOTION)
(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)
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:
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;
}
}
// If this was the primary point being released, then we change our state back to CLEAR...
mState = CLEAR;
mTouchEvents.clear();
+ mPrimaryDeviceId = -1;
}
else
{
// Change our state back to clear when the primary touch point is released.
mState = CLEAR;
mTouchEvents.clear();
+ mPrimaryDeviceId = -1;
}
break;
}
}
}
+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);
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();
{
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
mThresholdAdjustmentPerFrame = Vector2::ZERO;
}
}
+ else if (state == GestureState::CONTINUING && mPrimaryDeviceId != currentEvent.points[0].GetDeviceId())
+ {
+ return false;
+ }
gesture.previousPosition = previousPosition;
gesture.timeDelta = currentEvent.time - previousTime;
mObserver.Process(*mScene, gesture);
}
+ return true;
}
void PanGestureRecognizer::SetMinimumDistance(int32_t minimumDistance)
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;
* 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
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
// 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
{
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)
// 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
#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
{
/**
* @copydoc Dali::PinchGestureDetector
*/
-class PinchGestureDetector : public GestureDetector
+class PinchGestureDetector : public GestureDetector, public RecognizerObserver<PinchGestureEvent>
{
public: // Creation
/**
*/
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;
};
}
}
+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");
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)
*/
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&);
}
}
+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.
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;
// 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
{
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
#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
{
/**
* @copydoc Dali::RotationGestureDetector
*/
-class RotationGestureDetector : public GestureDetector
+class RotationGestureDetector : public GestureDetector, public RecognizerObserver<RotationGestureEvent>
{
public: // Creation
/**
{ /* 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;
};
}
}
+uint32_t RotationGestureProcessor::GetMinimumTouchEvents() const
+{
+ return mMinimumTouchEvents;
+}
+
+uint32_t RotationGestureProcessor::GetMinimumTouchEventsAfterStart() const
+{
+ return mMinimumTouchEventsAfterStart;
+}
+
void RotationGestureProcessor::OnGesturedActorStageDisconnection()
{
mCurrentRotationEmitters.clear();
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)
*/
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
}
}
+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;
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
#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>
mWaitTime(DEFAULT_TAP_WAIT_TIME),
mTappedActor(),
mTap(),
- mReceiveAllTapEvents(false)
+ mCurrentTapActor(),
+ mReceiveAllTapEvents(false),
+ mPossibleProcessed(false)
{
}
else
{
mTappedActor = tappedActor;
+ mWaitTime = mGestureEventProcessor.GetTapGestureProcessor().GetMaximumAllowedTime();
mTimerId = platformAbstraction.StartTimer(mWaitTime, MakeCallback(this, &TapGestureDetector::TimerCallback));
}
}
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)
// 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
#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
{
/**
* @copydoc Dali::TapGestureDetector
*/
-class TapGestureDetector : public GestureDetector
+class TapGestureDetector : public GestureDetector, public RecognizerObserver<TapGestureEvent>
{
public: // Creation
/**
*/
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;
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
{
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))
// 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;
}
}
}
+uint32_t TapGestureProcessor::GetRecognizerTime() const
+{
+ return mRecognizerTime;
+}
+
void TapGestureProcessor::SetMaximumMotionAllowedDistance(float distance)
{
if(distance < 0.0f)
}
}
+float TapGestureProcessor::GetMaximumMotionAllowedDistance() const
+{
+ return mMaximumMotionAllowedDistance;
+}
+
void TapGestureProcessor::UpdateDetection()
{
DALI_ASSERT_DEBUG(!mTapGestureDetectors.empty());
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
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.
*/
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&);
}
}
+void TapGestureRecognizer::CancelEvent()
+{
+ mState = CLEAR;
+}
+
void TapGestureRecognizer::SetupForTouchDown(const Integration::TouchEvent& event, const Integration::Point& point)
{
mTouchPosition = point.GetScreenPosition();
{
event.sourceType = mSourceType;
event.sourceData = mSourceData;
+
if(mScene)
{
// Create another handle so the recognizer cannot be destroyed during process function
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;
return mRenderTask;
}
+ Dali::RenderTask& GetRenderTaskPtr()
+ {
+ return mRenderTask;
+ }
+
// Setters
/**
for(; rIter != processor.mCandidateActorLists.rend(); rIter++)
{
Actor* actorImpl(*rIter);
+ if(actorImpl == interceptedActor)
+ {
+ break;
+ }
EmitTouchSignals(actorImpl, *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry);
}
}
// 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);
+ }
}
}
}
*
* - Hit Testing & Touch Event Delivery are described in Dali::Actor.
*/
-class TouchEventProcessor
+class TouchEventProcessor : public RefObject
{
public:
/**
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
* @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
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.
*
{
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);
+ }
};
/**