When an actor receiving a hover event is hidden or removed, it receives an interrupte... 05/301005/17
authorjoogab.yun <joogab.yun@samsung.com>
Tue, 7 Nov 2023 04:20:23 +0000 (13:20 +0900)
committerjoogab.yun <joogab.yun@samsung.com>
Wed, 8 Nov 2023 06:29:10 +0000 (15:29 +0900)
Change-Id: I6d20c67deafb15dfb86e1e815e84f1c4e91c086c

automated-tests/src/dali/utc-Dali-HoverProcessing.cpp
dali/internal/event/actors/actor-parent-impl.cpp
dali/internal/event/common/scene-impl.cpp
dali/internal/event/common/scene-impl.h
dali/internal/event/events/event-processor.cpp
dali/internal/event/events/event-processor.h
dali/internal/event/events/hover-event-processor.cpp
dali/internal/event/events/hover-event-processor.h

index 9dc8c89..720f7ab 100644 (file)
@@ -513,6 +513,8 @@ int UtcDaliHoverInterruptedParentConsumer(void)
 
   // Remove actor from Stage
   application.GetScene().Remove(actor);
+  data.Reset();
+  rootData.Reset();
 
   // Render and notify
   application.SendNotification();
@@ -743,6 +745,12 @@ int UtcDaliHoverActorBecomesInsensitiveParentConsumer(void)
   // Remove actor from Stage
   application.GetScene().Remove(actor);
 
+  // Because it was removed, it gets interrupted.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+  rootData.Reset();
+
   // Render and notify
   application.SendNotification();
   application.Render();
@@ -750,11 +758,13 @@ int UtcDaliHoverActorBecomesInsensitiveParentConsumer(void)
   // Make root actor insensitive
   rootActor.SetProperty(Actor::Property::SENSITIVE, false);
 
-  // Emit a motion signal, signalled with an interrupted (should get interrupted even if within root actor)
+  // Because it is insensitive, it does not receive the event.
   application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(200.0f, 200.0f)));
   DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
-  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
-  DALI_TEST_EQUALS(PointState::INTERRUPTED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(false, rootData.functorCalled, TEST_LOCATION);
+  data.Reset();
+  rootData.Reset();
+
   END_TEST;
 }
 
@@ -902,6 +912,12 @@ int UtcDaliHoverMultipleLayers(void)
 
   // Make rootActor invisible, render and notify
   rootActor.SetProperty(Actor::Property::VISIBLE, false);
+
+  // Because visible became false, we receive interrupted
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
   application.SendNotification();
   application.Render();
 
@@ -1209,6 +1225,11 @@ int UtcDaliHoverActorUnStaged(void)
   // Remove actor from stage
   application.GetScene().Remove(actor);
 
+  // Interrupted is received because the actor receiving the event removed.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
   // Render and notify
   application.SendNotification();
   application.Render();
@@ -1345,3 +1366,41 @@ int UtcDaliHoverEventIntegNewHoverEvent(void)
 
   END_TEST;
 }
+
+int UtcDaliHoverActorHide(void)
+{
+  TestApplication    application;
+  Integration::Scene stage = application.GetScene();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  actor.SetProperty(Actor::Property::VISIBLE, false);
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Interrupted is received because the actor receiving the event hides.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
index 7073f62..bf1b823 100644 (file)
@@ -531,6 +531,12 @@ void ActorParentImpl::EmitVisibilityChangedSignalRecursively(
   bool                               visible,
   DevelActor::VisibilityChange::Type type)
 {
+  if(!visible && mOwner.OnScene())
+  {
+    //The actor should receive an interrupted event when it is hidden.
+    mOwner.GetScene().SendInterruptedEvents(&mOwner);
+  }
+
   mOwner.EmitVisibilityChangedSignal(visible, type);
 
   if(mChildren)
index cfa06f1..9b34b5f 100644 (file)
@@ -270,6 +270,11 @@ void Scene::ProcessEvents()
   mEventProcessor.ProcessEvents();
 }
 
+void Scene::SendInterruptedEvents(Dali::Internal::Actor* actor)
+{
+  mEventProcessor.SendInterruptedEvents(actor);
+}
+
 void Scene::RebuildDepthTree()
 {
   // If the depth tree needs rebuilding, do it in this frame only.
index 13c4e5c..12f377a 100644 (file)
@@ -165,6 +165,12 @@ public:
   void ProcessEvents();
 
   /**
+   * This function is called by Core when sending a interrupted event to a specific actor.
+   * @param[in] actor The actor on which the event should occur.
+   */
+  void SendInterruptedEvents(Dali::Internal::Actor* actor);
+
+  /**
    * Rebuilds the depth tree at the end of the event frame if
    * it was requested this frame.
    */
index 44d9eef..442626e 100644 (file)
@@ -181,6 +181,12 @@ void EventProcessor::ProcessEvents()
   queueToProcess->Reset();
 }
 
+void EventProcessor::SendInterruptedEvents(Dali::Internal::Actor *actor)
+{
+    //TODO: Other event types should also be added if needed
+    mHoverEventProcessor.SendInterruptedHoverEvent(actor);
+}
+
 } // namespace Internal
 
 } // namespace Dali
index 442695b..6936898 100644 (file)
@@ -72,6 +72,12 @@ public:
    */
   void ProcessEvents();
 
+  /**
+   * This function is called when sending a interrupted event to a specific actor.
+   * @param[in] actor The actor on which the event should occur.
+   */
+  void SendInterruptedEvents(Dali::Internal::Actor *actor);
+
 private:
   Scene&                 mScene;                 ///< The Scene events are processed for.
   TouchEventProcessor    mTouchEventProcessor;   ///< Processes touch events.
index b9a7f02..0b4ae9e 100644 (file)
@@ -22,6 +22,9 @@
 #include <sstream>
 #endif
 
+// EXTERNAL INCLUDES
+#include <chrono>
+
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
 #include <dali/integration-api/events/hover-event-integ.h>
@@ -169,10 +172,21 @@ struct ActorHoverableCheck : public HitTestAlgorithm::HitTestInterface
   }
 };
 
+uint32_t GetMilliSeconds()
+{
+  // Get the time of a monotonic clock since its epoch.
+  auto epoch = std::chrono::steady_clock::now().time_since_epoch();
+
+  auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
+
+  return static_cast<uint32_t>(duration.count());
+}
+
 } // unnamed namespace
 
 HoverEventProcessor::HoverEventProcessor(Scene& scene)
-: mScene(scene)
+: mScene(scene),
+  mLastPrimaryHitActor(MakeCallback(this, &HoverEventProcessor::OnObservedActorDisconnected))
 {
   DALI_LOG_TRACE_METHOD(gLogFilter);
 }
@@ -182,6 +196,19 @@ HoverEventProcessor::~HoverEventProcessor()
   DALI_LOG_TRACE_METHOD(gLogFilter);
 }
 
+void HoverEventProcessor::SendInterruptedHoverEvent(Dali::Internal::Actor* actor)
+{
+  if(actor &&
+     (mLastPrimaryHitActor.GetActor() == actor || mLastConsumedActor.GetActor() == actor))
+  {
+    Integration::Point point;
+    point.SetState(PointState::INTERRUPTED);
+    point.SetHitActor(Dali::Actor(actor));
+    AllocAndEmitHoverSignals(GetMilliSeconds(), point.GetHitActor(), point);
+    Clear();
+  }
+}
+
 void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event)
 {
   DALI_LOG_TRACE_METHOD(gLogFilter);
@@ -235,11 +262,8 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
       AllocAndEmitHoverSignals(event.time, hoverStartConsumedActorHandle, currentPoint);
     }
 
-    mLastPrimaryHitActor.SetActor(nullptr);
-    mLastConsumedActor.SetActor(nullptr);
+    Clear();
     mHoverStartConsumedActor.SetActor(nullptr);
-    mLastRenderTask.Reset();
-
     return; // No need for hit testing
   }
 
@@ -379,9 +403,7 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
 
   if(primaryPointState == PointState::FINISHED)
   {
-    mLastPrimaryHitActor.SetActor(nullptr);
-    mLastConsumedActor.SetActor(nullptr);
-    mLastRenderTask.Reset();
+    Clear();
   }
   else
   {
@@ -389,7 +411,6 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
     if(primaryHitActor && GetImplementation(primaryHitActor).OnScene())
     {
       mLastPrimaryHitActor.SetActor(&GetImplementation(primaryHitActor));
-
       // Only observe the consumed actor if we have a primaryHitActor (check if it is still on the scene).
       if(consumedActor && GetImplementation(consumedActor).OnScene())
       {
@@ -404,9 +425,7 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
     }
     else
     {
-      mLastPrimaryHitActor.SetActor(nullptr);
-      mLastConsumedActor.SetActor(nullptr);
-      mLastRenderTask.Reset();
+      Clear();
     }
   }
 
@@ -452,6 +471,18 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
   }
 }
 
+void HoverEventProcessor::Clear()
+{
+  mLastPrimaryHitActor.SetActor(nullptr);
+  mLastConsumedActor.SetActor(nullptr);
+  mLastRenderTask.Reset();
+}
+
+void HoverEventProcessor::OnObservedActorDisconnected(Dali::Internal::Actor* actor)
+{
+  SendInterruptedHoverEvent(actor);
+}
+
 } // namespace Internal
 
 } // namespace Dali
index 5b4116f..94c75ad 100644 (file)
@@ -66,6 +66,12 @@ public:
    */
   void ProcessHoverEvent(const Integration::HoverEvent& event);
 
+  /**
+   * This function is called when sending a interrupted hover event to a specific actor.
+   * @param[in] actor The actor on which the hover event should occur.
+   */
+  void SendInterruptedHoverEvent(Dali::Internal::Actor* actor);
+
 private:
   // Undefined
   HoverEventProcessor(const HoverEventProcessor&);
@@ -73,6 +79,17 @@ private:
   // Undefined
   HoverEventProcessor& operator=(const HoverEventProcessor& rhs);
 
+  /**
+   * Clears the value.
+   */
+  void Clear();
+
+  /**
+   * Called by some actor-observers when the observed actor is disconnected.
+   * @param[in]  actor  The actor that has been disconnected.
+   */
+  void OnObservedActorDisconnected(Dali::Internal::Actor* actor);
+
   Scene&        mScene;                   ///< Reference to the scene
   ActorObserver mLastPrimaryHitActor;     ///< Stores the last primary point hit actor
   ActorObserver mLastConsumedActor;       ///< Stores the last consumed actor