GeometryTouchEvent :InterceptTouchEvents are propagated in a parent-child relationship. 68/322368/4
authorjoogab.yun <joogab.yun@samsung.com>
Tue, 8 Apr 2025 04:54:41 +0000 (13:54 +0900)
committerjoogab.yun <joogab.yun@samsung.com>
Wed, 9 Apr 2025 01:32:16 +0000 (10:32 +0900)
Change-Id: Iffe7d8d5aca362ce9fee7e0fed4eac28d87c15cf

automated-tests/src/dali/utc-Dali-GeoTouchProcessing.cpp
dali/internal/event/events/touch-event-processor.cpp

index 40f4afcb0e493fa8914f68b10491db12e4b1d604..7d61e2aa6a7e4510793fdeb0d43c1b54e0274bb4 100644 (file)
@@ -2368,6 +2368,123 @@ int UtcDaliGeoTouchEventIntercept04(void)
   END_TEST;
 }
 
+int UtcDaliGeoTouchEventIntercept05(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Actor parentA = Actor::New();
+  parentA.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  parentA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(parentA);
+
+  Actor actorA = Actor::New();
+  actorA.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  parentA.Add(actorA);
+
+  Actor parentB = Actor::New();
+  parentB.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  parentB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(parentB);
+
+  Actor actorB = Actor::New();
+  actorB.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  parentB.Add(actorB);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        dataA;
+  TouchEventFunctor functorA(dataA); // consume
+  actorA.TouchedSignal().Connect(&application, functorA);
+
+  // Connect to parent's touched signal
+  SignalData        parentDataA;
+  TouchEventFunctor parentFunctorA(parentDataA); // consume
+  parentA.TouchedSignal().Connect(&application, parentFunctorA);
+
+  // Connect to actor's touched signal
+  SignalData        dataB;
+  TouchEventFunctor functorB(dataB); // consume
+  actorB.TouchedSignal().Connect(&application, functorB);
+
+  // Connect to parent's touched signal
+  SignalData        parentDataB;
+  TouchEventFunctor parentFunctorB(parentDataB); // consume
+  parentB.TouchedSignal().Connect(&application, parentFunctorB);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, dataB.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, dataB.receivedTouch.points[0].state, TEST_LOCATION);
+
+  dataA.Reset();
+  parentDataA.Reset();
+  dataB.Reset();
+  parentDataB.Reset();
+
+  // Connect to parent's intercept touched signal
+  SignalData        interceptDataA;
+  TouchEventFunctor interceptFunctorA(interceptDataA, true /* Do intercept */);
+  Dali::DevelActor::InterceptTouchedSignal(parentA).Connect(&application, interceptFunctorA);
+
+  SignalData        interceptDataB;
+  TouchEventFunctor interceptFunctorB(interceptDataB, true /* Do intercept */);
+  Dali::DevelActor::InterceptTouchedSignal(parentB).Connect(&application, interceptFunctorB);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+
+  // The actor gets interrupted. Because touch is intercepted by parent.
+  // Intercepts are propagated in a parent-child relationship based on the hit actor.
+  DALI_TEST_EQUALS(true, dataB.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, dataB.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, interceptDataB.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, interceptDataB.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actorB == interceptDataB.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(parentB == interceptDataB.touchedActor);
+
+  // parentA and parentB are siblings. So parentA does not receive interceptTouchEvent.
+  DALI_TEST_EQUALS(false, interceptDataA.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, dataA.functorCalled, TEST_LOCATION);
+
+  dataA.Reset();
+  parentDataA.Reset();
+  dataB.Reset();
+  parentDataB.Reset();
+  interceptDataA.Reset();
+  interceptDataB.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a move signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(20.0f, 20.0f)));
+
+  // Since InterceptTouchEvent is not called because it has already been intercepted by the parent, only the parent will receive the touchEvent.
+  DALI_TEST_EQUALS(false, dataB.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, interceptDataB.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, parentDataB.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, parentDataB.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(parentB == parentDataB.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(parentB == parentDataB.touchedActor);
+
+  dataA.Reset();
+  parentDataA.Reset();
+  dataB.Reset();
+  parentDataB.Reset();
+  interceptDataA.Reset();
+  interceptDataB.Reset();
+
+  END_TEST;
+}
+
 int UtcDaliGeoTouchAreaOffset(void)
 {
   TestApplication application;
index 8dbd9134041ed444a38a1a3cb290ebd530d9d989..8e0463c7b46e079321e80d3f03ed5d6a737bdf25 100644 (file)
@@ -125,27 +125,40 @@ Dali::Actor EmitInterceptTouchSignals(Dali::Actor actor, const Dali::TouchEvent&
 }
 
 // geometry
-// child -> below
-Dali::Actor EmitGeoInterceptTouchSignals(std::list<Dali::Internal::Actor*>& actorLists, std::list<Dali::Internal::Actor*>& interceptActorList, const Dali::TouchEvent& touchEvent, ActorObserver& lastConsumedActor)
+// child -> parent
+Dali::Actor EmitGeoInterceptTouchSignals(Dali::Actor actor,
+                                        const Dali::TouchEvent& touchEvent,
+                                        ActorObserver& lastConsumedActor)
 {
-  interceptActorList.clear();
   Dali::Actor interceptedActor;
-  for(auto&& actor : actorLists)
+
+  if(actor)
   {
-    interceptActorList.push_back(actor);
-    if(ShouldEmitInterceptTouchEvent(*actor, touchEvent))
+    Dali::Actor parent = actor.GetParent();
+    if(parent)
     {
-      DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_INTERCEPT_TOUCH_EVENT_SIGNAL");
-      if(actor->EmitInterceptTouchEventSignal(touchEvent))
-      {
-        interceptedActor = Dali::Actor(actor);
-        break;
-      }
+      // Recursively deliver events to the actor and its parents for intercept touch event.
+      interceptedActor = EmitGeoInterceptTouchSignals(parent, touchEvent, lastConsumedActor);
     }
-    // If there is a consumed actor, the intercept is sent only up to the moment before the consumed actor.
-    if(lastConsumedActor.GetActor() == actor)
+
+    if(!interceptedActor)
     {
-      break;
+      bool   intercepted = false;
+      Actor& actorImpl(GetImplementation(actor));
+      if(ShouldEmitInterceptTouchEvent(actorImpl, touchEvent))
+      {
+        DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_INTERCEPT_TOUCH_EVENT_SIGNAL");
+        intercepted = actorImpl.EmitInterceptTouchEventSignal(touchEvent);
+        if(intercepted)
+        {
+          interceptedActor = Dali::Actor(&actorImpl);
+        }
+      }
+      // If there is a consumed actor, the intercept is sent only up to the moment before the consumed actor.
+      if(lastConsumedActor.GetActor() == actor)
+      {
+        return interceptedActor;
+      }
     }
   }
   return interceptedActor;
@@ -462,11 +475,22 @@ struct TouchEventProcessor::Impl
         {
           Dali::Actor interceptedActor;
           // Let's find out if there is an intercept actor.
-          interceptedActor = EmitGeoInterceptTouchSignals(processor.mCandidateActorLists, processor.mInterceptedActorLists, localVars.touchEventHandle, processor.mLastConsumedActor);
+          interceptedActor = EmitGeoInterceptTouchSignals(localVars.primaryHitActor, localVars.touchEventHandle, processor.mLastConsumedActor);
           if(interceptedActor)
           {
             processor.mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor));
 
+            processor.mInterceptedActorLists.clear();
+            // Create a list of intercepted actors from the candidate list.
+            for(auto& actorImpl : processor.mCandidateActorLists)
+            {
+              processor.mInterceptedActorLists.push_back(actorImpl);
+              if(actorImpl == interceptedActor)
+              {
+                break;
+              }
+            }
+
             // If there is an interception, send an interrupted event to the last consumed actor or to the actor that hit previously.
             if(processor.mLastConsumedActor.GetActor() &&
                processor.mLastConsumedActor.GetActor() != interceptedActor &&