Add a Hit-Test result events. 75/270975/20
authorjoogab.yun <joogab.yun@samsung.com>
Sat, 12 Feb 2022 06:25:35 +0000 (15:25 +0900)
committerjoogab.yun <joogab.yun@samsung.com>
Mon, 14 Mar 2022 03:23:50 +0000 (12:23 +0900)
In the case of TouchEvent or Gesture, there is no way to propagate the event to the view below that is not related.

So, before sending an touch event, send an hitTestResult event to the view in the hit-test process to ask whether it will be hit or not.
If it returns false, it means that it will not be hit, and the hit-test continues to the next view.

Change-Id: I5b8681f569f5c3b89acc3fb23c1eada3d49b1c7b

13 files changed:
automated-tests/src/dali/utc-Dali-Actor.cpp
automated-tests/src/dali/utc-Dali-HitTestAlgorithm.cpp
automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp
dali/devel-api/actors/actor-devel.cpp [changed mode: 0755->0644]
dali/devel-api/actors/actor-devel.h
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h
dali/internal/event/events/gesture-processor.cpp
dali/internal/event/events/gesture-processor.h
dali/internal/event/events/hit-test-algorithm-impl.cpp
dali/internal/event/events/hit-test-algorithm-impl.h
dali/internal/event/events/hover-event-processor.cpp
dali/internal/event/events/touch-event-processor.cpp

index 198fa00..0071883 100644 (file)
@@ -53,6 +53,7 @@ namespace
 bool gTouchCallBackCalled  = false;
 bool gTouchCallBackCalled2 = false;
 bool gTouchCallBackCalled3 = false;
+bool gHitTestTouchCallBackCalled = false;
 
 bool gHoverCallBackCalled = false;
 
@@ -112,6 +113,13 @@ static bool TestTouchCallback3(Actor, const TouchEvent&)
   END_TEST;
 }
 
+static bool TestHitTestTouchCallback(Actor, const TouchEvent&)
+{
+  gHitTestTouchCallBackCalled = true;
+  return false;
+  END_TEST;
+}
+
 static void ResetTouchCallbacks()
 {
   gTouchCallBackCalled  = false;
@@ -10279,3 +10287,108 @@ int UtcDaliActorRegisterProperty(void)
 
   END_TEST;
 }
+
+int UtcDaliActorDoesWantedHitTest(void)
+{
+  struct HitTestData
+  {
+  public:
+    HitTestData(const Vector3& scale, const Vector2& touchPoint, bool result)
+    : mScale(scale),
+      mTouchPoint(touchPoint),
+      mResult(result)
+    {
+    }
+
+    Vector3 mScale;
+    Vector2 mTouchPoint;
+    bool    mResult;
+  };
+
+  TestApplication application;
+  tet_infoline(" UtcDaliActorDoesWantedHitTest");
+
+  // Fill a vector with different hit tests.
+  struct HitTestData* hitTestData[] = {
+    //                    scale                     touch point           result
+    new HitTestData(Vector3(100.f, 100.f, 1.f), Vector2(289.f, 400.f), true),  // touch point close to the right edge (inside)
+    new HitTestData(Vector3(100.f, 100.f, 1.f), Vector2(291.f, 400.f), false), // touch point close to the right edge (outside)
+    new HitTestData(Vector3(110.f, 100.f, 1.f), Vector2(291.f, 400.f), true),  // same point as above with a wider scale. Should be inside.
+    new HitTestData(Vector3(100.f, 100.f, 1.f), Vector2(200.f, 451.f), false), // touch point close to the down edge (outside)
+    new HitTestData(Vector3(100.f, 110.f, 1.f), Vector2(200.f, 451.f), true),  // same point as above with a wider scale. Should be inside.
+    NULL,
+  };
+
+  // get the root layer
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  Actor lowerActor = Actor::New();
+  lowerActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  lowerActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  // actor and lowerActor have no relationship.
+  application.GetScene().Add(lowerActor);
+  application.GetScene().Add(actor);
+
+  ResetTouchCallbacks();
+  gHitTestTouchCallBackCalled = false;
+
+  unsigned int index = 0;
+  while(NULL != hitTestData[index])
+  {
+    actor.SetProperty(Actor::Property::SIZE, Vector2(1.f, 1.f));
+    actor.SetProperty(Actor::Property::SCALE, Vector3(hitTestData[index]->mScale.x, hitTestData[index]->mScale.y, hitTestData[index]->mScale.z));
+
+    lowerActor.SetProperty(Actor::Property::SIZE, Vector2(1.f, 1.f));
+    lowerActor.SetProperty(Actor::Property::SCALE, Vector3(hitTestData[index]->mScale.x, hitTestData[index]->mScale.y, hitTestData[index]->mScale.z));
+
+    // flush the queue and render once
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_CHECK(!gTouchCallBackCalled);
+    DALI_TEST_CHECK(!gTouchCallBackCalled2);
+    DALI_TEST_CHECK(!gHitTestTouchCallBackCalled);
+
+    // connect to its touch signal
+    actor.TouchedSignal().Connect(TestTouchCallback);
+    lowerActor.TouchedSignal().Connect(TestTouchCallback2);
+
+    // connect to its hit-test signal
+    Dali::DevelActor::HitTestResultSignal(actor).Connect(TestHitTestTouchCallback);
+
+    Dali::Integration::Point point;
+    point.SetState(PointState::DOWN);
+    point.SetScreenPosition(Vector2(hitTestData[index]->mTouchPoint.x, hitTestData[index]->mTouchPoint.y));
+    Dali::Integration::TouchEvent event;
+    event.AddPoint(point);
+
+    // flush the queue and render once
+    application.SendNotification();
+    application.Render();
+    application.ProcessEvent(event);
+
+    // check hit-test events
+    DALI_TEST_CHECK(gHitTestTouchCallBackCalled == hitTestData[index]->mResult);
+    // Passed all hit-tests of actor.
+    DALI_TEST_CHECK(gTouchCallBackCalled == false);
+    // The lowerActor was hit-tested.
+    DALI_TEST_CHECK(gTouchCallBackCalled2 == hitTestData[index]->mResult);
+
+    if(gTouchCallBackCalled2 != hitTestData[index]->mResult)
+      tet_printf("Test failed:\nScale %f %f %f\nTouchPoint %f, %f\nResult %d\n",
+                 hitTestData[index]->mScale.x,
+                 hitTestData[index]->mScale.y,
+                 hitTestData[index]->mScale.z,
+                 hitTestData[index]->mTouchPoint.x,
+                 hitTestData[index]->mTouchPoint.y,
+                 hitTestData[index]->mResult);
+
+    ResetTouchCallbacks();
+    gHitTestTouchCallBackCalled = false;
+    ++index;
+  }
+  END_TEST;
+}
index 2abc74e..1bac5af 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
  */
 
 #include <dali-test-suite-utils.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/events/hit-test-algorithm.h>
 #include <dali/integration-api/events/touch-event-integ.h>
 #include <dali/public-api/dali-core.h>
@@ -27,6 +28,14 @@ using namespace Dali;
 
 namespace
 {
+bool        gHitTestTouchCallBackCalled = false;
+static bool TestHitTestTouchCallback(Actor, const TouchEvent&)
+{
+  gHitTestTouchCallBackCalled = true;
+  return false;
+  END_TEST;
+}
+
 /**
  * The functor to be used in the hit-test algorithm to check whether the actor is hittable.
  */
@@ -372,3 +381,57 @@ int UtcDaliHitTestAlgorithmOverlay(void)
   DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION);
   END_TEST;
 }
+
+int UtcDaliHitTestAlgorithmDoesWantedHitTest(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm with does wanted to HitTest");
+
+  Stage             stage             = Stage::GetCurrent();
+  RenderTaskList    renderTaskList    = stage.GetRenderTaskList();
+  RenderTask        defaultRenderTask = renderTaskList.GetTask(0u);
+  Dali::CameraActor cameraActor       = defaultRenderTask.GetCameraActor();
+
+  Vector2 stageSize(stage.GetSize());
+  cameraActor.SetOrthographicProjection(stageSize);
+  cameraActor.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 1600.0f));
+
+  Vector2 actorSize(stageSize * 0.5f);
+  // Create two actors with half the size of the stage and set them to be overlapping
+  Actor blue = Actor::New();
+  blue.SetProperty(Actor::Property::NAME, "Blue");
+  blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  blue.SetProperty(Actor::Property::PARENT_ORIGIN, AnchorPoint::CENTER);
+  blue.SetProperty(Actor::Property::SIZE, actorSize);
+
+  Actor green = Actor::New();
+  green.SetProperty(Actor::Property::NAME, "Green");
+  green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  green.SetProperty(Actor::Property::PARENT_ORIGIN, AnchorPoint::CENTER);
+  green.SetProperty(Actor::Property::SIZE, actorSize);
+
+  // Add the actors to the view
+  stage.Add(blue);
+  stage.Add(green);
+
+  // connect to its hit-test signal
+  Dali::DevelActor::HitTestResultSignal(green).Connect(TestHitTestTouchCallback);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(0);
+  application.Render(10);
+
+  gHitTestTouchCallBackCalled = false;
+
+  HitTestAlgorithm::Results results;
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+
+  // check hit-test events
+  // The green actor received an event that the green actor was hit.
+  DALI_TEST_CHECK(gHitTestTouchCallBackCalled == true);
+  // The green actor passed the hit-test. So blue was the final hit.
+  DALI_TEST_CHECK(results.actor == blue);
+
+  END_TEST;
+}
index 714c146..24921c3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -40,6 +40,13 @@ void utc_dali_tap_gesture_detector_cleanup(void)
 ///////////////////////////////////////////////////////////////////////////////
 namespace
 {
+bool        gHitTestTouchCallBackCalled = false;
+static bool TestHitTestTouchCallback(Actor, const TouchEvent&)
+{
+  gHitTestTouchCallBackCalled = true;
+  return false;
+  END_TEST;
+}
 // Stores data that is populated in the callback and will be read by the TET cases
 struct SignalData
 {
@@ -1144,4 +1151,60 @@ int UtcDaliTapGestureReceiveAllTapEvents(void)
   data.Reset();
 
   END_TEST;
+}
+
+int UtcDaliTapGestureDoesWantedHitTest(void)
+{
+  TestApplication application;
+
+  Actor blue = Actor::New();
+  blue.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+
+  Actor green = Actor::New();
+  green.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+
+  application.GetScene().Add(blue);
+  application.GetScene().Add(green);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  SignalData             blueData;
+  GestureReceivedFunctor blueFunctor(blueData);
+
+  TapGestureDetector blueDetector = TapGestureDetector::New();
+  blueDetector.Attach(blue);
+  blueDetector.DetectedSignal().Connect(&application, blueFunctor);
+
+  SignalData             greenData;
+  GestureReceivedFunctor greenFunctor(greenData);
+
+  TapGestureDetector greenDetector = TapGestureDetector::New();
+  greenDetector.Attach(green);
+  greenDetector.DetectedSignal().Connect(&application, greenFunctor);
+
+  // connect to its hit-test signal
+  gHitTestTouchCallBackCalled = false;
+  Dali::DevelActor::HitTestResultSignal(green).Connect(TestHitTestTouchCallback);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(20.0f, 20.0f), 0, 100));
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(20.0f, 20.0f), 0, 120));
+  application.SendNotification();
+
+  // check hit-test events
+  // The green actor received an event that the green actor was hit.
+  DALI_TEST_EQUALS(true, gHitTestTouchCallBackCalled, TEST_LOCATION);
+
+  // The green actor passed the hit-test. So blue was the final hit.
+  DALI_TEST_EQUALS(false, greenData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, blueData.functorCalled, TEST_LOCATION);
+
+  blueData.Reset();
+  greenData.Reset();
+
+  END_TEST;
 }
\ No newline at end of file
old mode 100755 (executable)
new mode 100644 (file)
index ab0fe4d..37fa3fb
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -63,6 +63,11 @@ void SwitchParent(Actor actor, Actor newParent)
   return GetImplementation(actor).SwitchParent(GetImplementation(newParent));
 }
 
+Actor::TouchEventSignalType& HitTestResultSignal(Actor actor)
+{
+  return GetImplementation(actor).HitTestResultSignal();
+}
+
 } // namespace DevelActor
 
 } // namespace Dali
index aca2b6e..5cda265 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_ACTOR_DEVEL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -348,6 +348,39 @@ DALI_CORE_API void SetNeedGesturePropagation(Actor actor, bool propagation);
  */
 DALI_CORE_API void SwitchParent(Actor actor, Actor newParent);
 
+/**
+ * @brief This signal is emitted when an actor is hit through hit-test.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void MyCallbackName( Actor actor );
+ * @endcode
+ * actor The actor to intercept
+ *
+ * @note This callback is called when the actor is hit.
+ * If true is returned, TouchEvent is called from the this actor.
+ * If false is returned, the hit test starts again from the next lower actor.
+ *
+ * @note example
+ *   Actor topActor = Actor::New();
+ *   Actor bottomActor = Actor::New();
+ *   topActor.TouchedSignal().Connect(&application, topActorFunctor);
+ *   bottomActor.TouchedSignal().Connect(&application, bottomActorFunctor);
+ * The two actors have no relationship.
+ * So when the topActor is touched, the event cannot be propagated to the bottomActor.
+ *
+ * If you connect HitTestResultSignal to topActor.
+ *   Dali::DevelActor::HitTestResultSignal(topActor).Connect(&application, hitTestResultFunctor);
+ *
+ * If the hitTestResult Functor returns false, it passes the hit-test and starts the hit-test again from the next lower actor.
+ * So the bottomActor can be hit and receive touch events.
+ * If hitTestResult returns true, it means that it has been hit. So it receives a TouchEvent from itself.
+ *
+ * @return The signal to connect to
+ * @pre The Actor has been initialized
+ */
+DALI_CORE_API Actor::TouchEventSignalType& HitTestResultSignal(Actor actor);
+
 } // namespace DevelActor
 
 } // namespace Dali
index 174f5e3..73756a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
 #include <dali/devel-api/common/capabilities.h>
 
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/touch-integ.h>
 
 #include <dali/internal/event/actors/actor-coords.h>
 #include <dali/internal/event/actors/actor-parent.h>
@@ -1014,6 +1015,22 @@ void Actor::EmitLayoutDirectionChangedSignal(LayoutDirection::Type type)
   EmitSignal(*this, mLayoutDirectionChangedSignal, type);
 }
 
+bool Actor::EmitHitTestResultSignal(Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp)
+{
+  bool hit = true;
+
+  if(IsHitTestResultRequired())
+  {
+    Dali::Actor        handle(this);
+    Integration::Point newPoint(point);
+    newPoint.SetHitActor(handle);
+    newPoint.SetLocalPosition(hitPointLocal);
+    Dali::TouchEvent touchEvent = Dali::Integration::NewTouchEvent(timeStamp, newPoint);
+    hit                         = mHitTestResultSignal.Emit(handle, touchEvent);
+  }
+  return hit;
+}
+
 DevelActor::ChildChangedSignalType& Actor::ChildAddedSignal()
 {
   return mParentImpl.ChildAddedSignal();
@@ -1048,6 +1065,7 @@ Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node)
   mOnRelayoutSignal(),
   mVisibilityChangedSignal(),
   mLayoutDirectionChangedSignal(),
+  mHitTestResultSignal(),
   mTargetOrientation(Quaternion::IDENTITY),
   mTargetColor(Color::WHITE),
   mTargetPosition(Vector3::ZERO),
index 8ab4be7..bade273 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ACTOR_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,6 +33,8 @@
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
 
+#include <dali/integration-api/events/touch-event-integ.h>
+
 #include <dali/internal/common/const-string.h>
 #include <dali/internal/common/internal-constants.h>
 #include <dali/internal/common/memory-pool-object-allocator.h>
@@ -1205,6 +1207,15 @@ public:
   }
 
   /**
+   * Query whether the application or derived actor type requires hit-test result events.
+   * @return True if hit-test result events are required.
+   */
+  bool IsHitTestResultRequired() const
+  {
+    return !mHitTestResultSignal.Empty();
+  }
+
+  /**
    * Query whether the application or derived actor type requires intercept touch events.
    * @return True if intercept touch events are required.
    */
@@ -1340,6 +1351,23 @@ public:
   void EmitLayoutDirectionChangedSignal(LayoutDirection::Type type);
 
   /**
+   * Used by the EventProcessor to emit hit-test result touch event signals.
+   * @param[in] point The point of event touched.
+   * @param[in] hitPointLocal The hit point in the Actor's local reference system.
+   * @param[in] timeStamp The time the event occurred.
+   * @return True if the event was consumed.
+   */
+  bool EmitHitTestResultSignal(Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp);
+
+  /**
+   * @copydoc DevelActor::HitTestResultSignal()
+   */
+  Dali::Actor::TouchEventSignalType& HitTestResultSignal()
+  {
+    return mHitTestResultSignal;
+  }
+
+  /**
    * @copydoc DevelActor::InterceptTouchedSignal()
    */
   Dali::Actor::TouchEventSignalType& InterceptTouchedSignal()
@@ -1830,6 +1858,7 @@ protected:
   Dali::Actor::OnRelayoutSignalType             mOnRelayoutSignal;
   DevelActor::VisibilityChangedSignalType       mVisibilityChangedSignal;
   Dali::Actor::LayoutDirectionChangedSignalType mLayoutDirectionChangedSignal;
+  Dali::Actor::TouchEventSignalType             mHitTestResultSignal;
 
   Quaternion mTargetOrientation; ///< Event-side storage for orientation
   Vector4    mTargetColor;       ///< Event-side storage for color
index 551acc1..1cf4b26 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -61,6 +61,11 @@ struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
     return layer->IsTouchConsumed();
   }
 
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  {
+    return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+  }
+
   GestureType::Value mType;
 };
 
@@ -71,6 +76,8 @@ GestureProcessor::GestureProcessor(GestureType::Value type)
   mNeedsUpdate(false),
   mType(type),
   mCurrentGesturedActor(nullptr),
+  mPoint(),
+  mEventTime(0u),
   mGesturedActorDisconnected(false)
 {
 }
@@ -84,6 +91,11 @@ void GestureProcessor::ProcessTouch(Scene& scene, const Integration::TouchEvent&
 {
   if(mGestureRecognizer)
   {
+    if(!event.points.empty())
+    {
+      mPoint     = event.points[0];
+      mEventTime = event.time;
+    }
     mGestureRecognizer->SendEvent(scene, event);
   }
 }
@@ -192,6 +204,8 @@ void GestureProcessor::ProcessAndEmit(HitTestAlgorithm::Results& hitTestResults)
 bool GestureProcessor::HitTest(Scene& scene, Vector2 screenCoordinates, HitTestAlgorithm::Results& hitTestResults)
 {
   GestureHitTestCheck hitCheck(mType);
+  hitTestResults.point     = mPoint;
+  hitTestResults.eventTime = mEventTime;
   HitTestAlgorithm::HitTest(scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), screenCoordinates, hitTestResults, hitCheck);
   return hitTestResults.renderTask && hitTestResults.actor;
 }
index 85261e5..e2015f3 100644 (file)
@@ -186,6 +186,8 @@ protected:                                 //Data
 private:                                             // Data
   GestureType::Value mType;                          ///< Type of GestureProcessor
   Actor*             mCurrentGesturedActor;          ///< The current actor that has been gestured.
+  Integration::Point mPoint;                         ///< The point of event touched.
+  uint32_t           mEventTime;                     ///< The time the event occurred.
   bool               mGesturedActorDisconnected : 1; ///< Indicates whether the gestured actor has been disconnected from the scene
 };
 
index ec5cc7c..81bf36a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -89,6 +89,11 @@ struct HitTestFunctionWrapper : public HitTestInterface
     return false;
   }
 
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  {
+    return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+  }
+
   Dali::HitTestAlgorithm::HitTestFunction mFunc;
 };
 
@@ -114,6 +119,11 @@ struct ActorTouchableCheck : public HitTestInterface
   {
     return layer->IsTouchConsumed();
   }
+
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  {
+    return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+  }
 };
 
 /**
@@ -158,7 +168,9 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                             bool                                       layerIs3d,
                             uint32_t                                   clippingDepth,
                             uint32_t                                   clippingBitPlaneMask,
-                            const RayTest&                             rayTest)
+                            const RayTest&                             rayTest,
+                            const Integration::Point&                  point,
+                            const uint32_t                             eventTime)
 {
   HitActor hit;
 
@@ -245,7 +257,8 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
               }
             }
 
-            if(haveHitActor)
+            // If the hit actor does not want to hit, the hit-test continues.
+            if(haveHitActor && hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime))
             {
               hit.actor       = &actor;
               hit.hitPosition = hitPointLocal;
@@ -302,12 +315,14 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                                                layerIs3d,
                                                newClippingDepth,
                                                clippingBitPlaneMask,
-                                               rayTest));
+                                               rayTest,
+                                               point,
+                                               eventTime));
 
         // Make sure the set hit actor is actually hittable. This is usually required when we have some
         // clipping as we need to hit-test all actors as we descend the tree regardless of whether they
         // are hittable or not.
-        if(currentHit.actor && !hitCheck.IsActorHittable(currentHit.actor))
+        if(currentHit.actor && (!hitCheck.IsActorHittable(currentHit.actor)))
         {
           continue;
         }
@@ -488,7 +503,9 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
                                        0u,
                                        0u,
-                                       rayTest);
+                                       rayTest,
+                                       results.point,
+                                       results.eventTime);
             }
             else if(IsWithinSourceActors(*sourceActor, *layer))
             {
@@ -505,7 +522,9 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
                                        0u,
                                        0u,
-                                       rayTest);
+                                       rayTest,
+                                       results.point,
+                                       results.eventTime);
             }
 
             // If this layer is set to consume the hit, then do not check any layers behind it
@@ -569,7 +588,6 @@ bool HitTestRenderTaskList(const Vector2&    sceneSize,
       // Skip to next task
       continue;
     }
-
     if(HitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest))
     {
       // Return true when an actor is hit (or layer in our render-task consumes the hit)
index e70ddaa..fa22507 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_HIT_TEST_ALGORITHM_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/events/hit-test-algorithm.h>
+#include <dali/integration-api/events/touch-event-integ.h>
 #include <dali/internal/event/render-tasks/render-task-impl.h>
 #include <dali/public-api/actors/actor.h>
 
@@ -37,11 +38,13 @@ namespace HitTestAlgorithm
 {
 struct Results
 {
-  RenderTaskPtr renderTask;       ///< The render-task displaying the actor.
-  Dali::Actor   actor;            ///< The hit actor.
-  Vector2       actorCoordinates; ///< The actor coordinates.
-  Vector4       rayOrigin;        ///< The point of origin of the ray.
-  Vector4       rayDirection;     ///< The direction vector of the ray.
+  RenderTaskPtr      renderTask;       ///< The render-task displaying the actor.
+  Dali::Actor        actor;            ///< The hit actor.
+  Vector2            actorCoordinates; ///< The actor coordinates.
+  Vector4            rayOrigin;        ///< The point of origin of the ray.
+  Vector4            rayDirection;     ///< The direction vector of the ray.
+  Integration::Point point;            ///< The point of event touched.
+  uint32_t           eventTime;        ///< The time the event occurred.
 };
 
 /**
@@ -81,6 +84,21 @@ struct HitTestInterface
    */
   virtual bool DoesLayerConsumeHit(Layer* layer) = 0;
 
+  /**
+   * Called by the hit-test algorithm to determine whether the actor will be hit or not.
+   *
+   * @note If true is returned, then this actor will be hit.
+   *       If false is returend, then this actor passes the hit-test and the next actor performs the hit-test.
+   *
+   * @param[in] actor The hit actor.
+   * @param[in] point The point of event touched.
+   * @param[in] hitPointLocal The hit point in the Actor's local reference system.
+   * @param[in] timeStamp The time the event occurred.
+   *
+   * @return true if the actor should be the hit, false otherwise.
+   */
+  virtual bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) = 0;
+
 protected:
   /**
    * Virtual destructor, no deletion through this interface
index 99ddc97..114255e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -153,6 +153,12 @@ struct ActorHoverableCheck : public HitTestAlgorithm::HitTestInterface
   {
     return layer->IsHoverConsumed();
   }
+
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  {
+    // Hover event is always hit.
+    return true;
+  }
 };
 
 } // unnamed namespace
index 2e173b5..e8673ed 100644 (file)
@@ -308,6 +308,8 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
   for(auto&& currentPoint : event.points)
   {
     HitTestAlgorithm::Results hitTestResults;
+    hitTestResults.point = currentPoint;
+    hitTestResults.eventTime = event.time;
     if(!firstPointParsed)
     {
       firstPointParsed = true;