/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
{
TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
Actor actor = Actor::New();
actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
{
TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
Actor actor = Actor::New();
actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
{
TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
Actor actor = Actor::New();
actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
{
TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
Actor actor = Actor::New();
actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
{
TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
// Connect to actor's hovered signal
SignalData data;
int UtcDaliGeoHoverMultipleRenderTasks(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
Integration::Scene stage(application.GetScene());
Vector2 stageSize(stage.GetSize());
int UtcDaliGeoHoverMultipleRenderTasksWithChildLayer(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
Integration::Scene stage(application.GetScene());
Vector2 stageSize(stage.GetSize());
int UtcDaliGeoHoverOffscreenRenderTasks(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
Integration::Scene stage(application.GetScene());
Vector2 stageSize(stage.GetSize());
int UtcDaliGeoHoverMultipleRenderableActors(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
Integration::Scene stage(application.GetScene());
Vector2 stageSize(stage.GetSize());
int UtcDaliGeoHoverLeaveActorReadded(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
Integration::Scene stage = application.GetScene();
int UtcDaliGeoHoverClippingActor(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
Integration::Scene stage = application.GetScene();
int UtcDaliGeoHoverActorHide(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
Integration::Scene stage = application.GetScene();
END_TEST;
}
+
+int UtcDaliGeoHoverEnsureDifferentConsumerReceivesInterrupted(void)
+{
+ // Interrupted event with a different consumer to previous event
+
+ TestApplication application;
+ Integration::Scene scene = application.GetScene();
+ scene.SetGeometryHittestEnabled(true);
+
+ Actor parent = Actor::New();
+ parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+ parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ scene.Add(parent);
+
+ Actor child = Actor::New();
+ child.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+ child.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ parent.Add(child);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Connect to parent's hover signal
+ SignalData dataParent;
+ HoverEventFunctor functorParent(dataParent);
+ parent.HoveredSignal().Connect(&application, functorParent);
+
+ // Connect to child's hovered signal but do not consume
+ SignalData dataChildNoConsume;
+ HoverEventFunctor functorChildNoConsume(dataChildNoConsume, false);
+ child.HoveredSignal().Connect(&application, functorChildNoConsume);
+
+ // Create a functor to consume the event of the child, but don't connect just yet
+ SignalData dataChildConsume;
+ HoverEventFunctor functorChildConsume(dataChildConsume);
+
+ auto resetData = [&]() { dataParent.Reset(); dataChildNoConsume.Reset(); dataChildConsume.Reset(); };
+
+ // Emit a started
+ application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+ DALI_TEST_EQUALS(true, dataParent.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataChildNoConsume.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(false, dataChildConsume.functorCalled, TEST_LOCATION);
+ resetData();
+
+ // Connect to child's hover event and consume so it's a different consumer on interrupted
+ child.HoveredSignal().Connect(&application, functorChildConsume);
+
+ // Emit interrupted, all three methods should be called
+ application.ProcessEvent(GenerateSingleHover(PointState::INTERRUPTED, Vector2(10.0f, 10.0f)));
+ DALI_TEST_EQUALS(true, dataParent.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataChildNoConsume.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataChildConsume.functorCalled, TEST_LOCATION);
+ resetData();
+
+ END_TEST;
+}
\ No newline at end of file
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
END_TEST;
}
+int UtcDaliGeoTouchEventNotConsumedInterrupted(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();
+
+ // Connect to actor's touched signal
+ SignalData data;
+ TouchEventFunctor functor(data, false);
+ 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 an interrupted signal, we should be signalled regardless of whether there is a hit or not even though we didn't consume
+ // as we still were the hit-actor in the last event.
+ application.ProcessEvent(GenerateSingleTouch(PointState::INTERRUPTED, Vector2(200.0f, 200.0f /* Outside actor */)));
+ DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION);
+ data.Reset();
+
+ // Emit another interrupted signal, our signal handler should not be called.
+ application.ProcessEvent(GenerateSingleTouch(PointState::INTERRUPTED, Vector2(200.0f, 200.0f)));
+ DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+ END_TEST;
+}
+
int UtcDaliGeoTouchEventParentConsumer(void)
{
TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
Actor actor = Actor::New();
actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
Actor actor = Actor::New();
actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
Actor actor = Actor::New();
actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
// Connect to actor's touched signal
SignalData data;
int UtcDaliGeoTouchEventMultipleRenderTasks(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
-
Integration::Scene scene(application.GetScene());
Vector2 sceneSize(scene.GetSize());
int UtcDaliGeoTouchEventMultipleRenderTasksWithChildLayer(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
int UtcDaliGeoTouchEventOffscreenRenderTasks(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
int UtcDaliGeoTouchEventMultipleRenderableActors(void)
{
- TestApplication application;
+ TestApplication application;
application.GetScene().SetGeometryHittestEnabled(true);
application.GetScene().SetGeometryHittestEnabled(true);
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
Actor parent = Actor::New();
parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
interceptData.Reset();
parentData.Reset();
-
END_TEST;
}
application.SendNotification();
application.Render();
- Actor rootActor(application.GetScene().GetRootLayer());
+ Actor rootActor(application.GetScene().GetRootLayer());
// Connect to root actor's intercept touched signal
SignalData sceneData;
DALI_TEST_EQUALS(true, sceneData.functorCalled, TEST_LOCATION);
sceneData.Reset();
-
END_TEST;
}
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
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
END_TEST;
}
+
+int UtcDaliHoverStartConsumerDifferentAtEnd(void)
+{
+ // Start a hover in one actor, continue it in another actor
+ // End hover in the second actor
+ // First actor should still get a hover finished call
+ TestApplication application;
+ Integration::Scene scene = 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);
+ scene.Add(actor);
+
+ Actor actor2 = Actor::New();
+ actor2.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+ actor2.SetProperty(Actor::Property::POSITION, Vector2(100.0f, 100.0f));
+ actor2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ scene.Add(actor2);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Connect to hover start actor's hovered signal
+ SignalData dataStartActor;
+ HoverEventFunctor functorStartActor(dataStartActor);
+ actor.HoveredSignal().Connect(&application, functorStartActor);
+
+ // Connect to second actor's hovered signal
+ SignalData dataSecondActor;
+ HoverEventFunctor functorSecondActor(dataSecondActor);
+ actor2.HoveredSignal().Connect(&application, functorSecondActor);
+
+ auto resetData = [&]() { dataStartActor.Reset(); dataSecondActor.Reset(); };
+
+ // Emit a started
+ application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+ DALI_TEST_EQUALS(true, dataStartActor.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(false, dataSecondActor.functorCalled, TEST_LOCATION);
+ resetData();
+
+ // Emit a hover somewhere else
+ application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(110.0f, 110.0f)));
+ DALI_TEST_EQUALS(false, dataStartActor.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataSecondActor.functorCalled, TEST_LOCATION);
+ resetData();
+
+ // Emit a hover end in the same point, the hover start actor should still be informed
+ application.ProcessEvent(GenerateSingleHover(PointState::FINISHED, Vector2(110.0f, 110.0f)));
+ DALI_TEST_EQUALS(true, dataStartActor.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataSecondActor.functorCalled, TEST_LOCATION);
+ resetData();
+
+ // Do it again with the geometry on
+ // Emit a started
+ application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+ DALI_TEST_EQUALS(true, dataStartActor.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(false, dataSecondActor.functorCalled, TEST_LOCATION);
+ resetData();
+
+ // Emit a hover somewhere else
+ application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(110.0f, 110.0f)));
+ DALI_TEST_EQUALS(false, dataStartActor.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataSecondActor.functorCalled, TEST_LOCATION);
+ resetData();
+
+ scene.SetGeometryHittestEnabled(true);
+
+ // Emit a hover end in the same point, the hover start actor should still be informed
+ application.ProcessEvent(GenerateSingleHover(PointState::FINISHED, Vector2(110.0f, 110.0f)));
+ DALI_TEST_EQUALS(true, dataStartActor.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataSecondActor.functorCalled, TEST_LOCATION);
+ resetData();
+
+ END_TEST;
+}
+
+int UtcDaliHoverEnsureDifferentConsumerReceivesInterrupted(void)
+{
+ // Interrupted event with a different consumer to previous event
+
+ TestApplication application;
+ Integration::Scene scene = application.GetScene();
+
+ Actor parent = Actor::New();
+ parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+ parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ scene.Add(parent);
+
+ Actor child = Actor::New();
+ child.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+ child.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ parent.Add(child);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Connect to parent's hover signal
+ SignalData dataParent;
+ HoverEventFunctor functorParent(dataParent);
+ parent.HoveredSignal().Connect(&application, functorParent);
+
+ // Connect to child's hovered signal but do not consume
+ SignalData dataChildNoConsume;
+ HoverEventFunctor functorChildNoConsume(dataChildNoConsume, false);
+ child.HoveredSignal().Connect(&application, functorChildNoConsume);
+
+ // Create a functor to consume the event of the child, but don't connect just yet
+ SignalData dataChildConsume;
+ HoverEventFunctor functorChildConsume(dataChildConsume);
+
+ auto resetData = [&]() { dataParent.Reset(); dataChildNoConsume.Reset(); dataChildConsume.Reset(); };
+
+ // Emit a started
+ application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+ DALI_TEST_EQUALS(true, dataParent.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataChildNoConsume.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(false, dataChildConsume.functorCalled, TEST_LOCATION);
+ resetData();
+
+ // Connect to child's hover event and consume so it's a different consumer on interrupted
+ child.HoveredSignal().Connect(&application, functorChildConsume);
+
+ // Emit interrupted, all three methods should be called
+ application.ProcessEvent(GenerateSingleHover(PointState::INTERRUPTED, Vector2(10.0f, 10.0f)));
+ DALI_TEST_EQUALS(true, dataParent.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataChildNoConsume.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataChildConsume.functorCalled, TEST_LOCATION);
+ resetData();
+
+ END_TEST;
+}
+
+int UtcDaliHoverEnsureDifferentConsumerReceivesLeave(void)
+{
+ // Motion event outside previous hit actor
+ // This event is consumed by a different actor
+ // The previous consumer's listener should still get called
+
+ TestApplication application;
+ Integration::Scene scene = application.GetScene();
+
+ Actor parent = Actor::New();
+ parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+ parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ scene.Add(parent);
+
+ Actor child = Actor::New();
+ child.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+ child.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ parent.Add(child);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Connect to parent's hover signal
+ SignalData dataParent;
+ HoverEventFunctor functorParent(dataParent);
+ parent.HoveredSignal().Connect(&application, functorParent);
+
+ // Connect to child's hovered signal but do not consume
+ SignalData dataChildNoConsume;
+ HoverEventFunctor functorChildNoConsume(dataChildNoConsume, false);
+ child.HoveredSignal().Connect(&application, functorChildNoConsume);
+
+ // Create a functor to consume the event of the child, but don't connect just yet
+ SignalData dataChildConsume;
+ HoverEventFunctor functorChildConsume(dataChildConsume);
+
+ auto resetData = [&]() { dataParent.Reset(); dataChildNoConsume.Reset(); dataChildConsume.Reset(); };
+
+ // Emit a started
+ application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+ DALI_TEST_EQUALS(true, dataParent.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataChildNoConsume.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(false, dataChildConsume.functorCalled, TEST_LOCATION);
+ resetData();
+
+ // Connect to child's hover event and consume so it's a different consumer on interrupted
+ child.HoveredSignal().Connect(&application, functorChildConsume);
+
+ // Also make last consumer insensitive
+ parent.SetProperty(Actor::Property::SENSITIVE, false);
+
+ // Emit interrupted, all three methods should be called
+ application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(110.0f, 110.0f)));
+ DALI_TEST_EQUALS(true, dataParent.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataChildNoConsume.functorCalled, TEST_LOCATION);
+ DALI_TEST_EQUALS(true, dataChildConsume.functorCalled, TEST_LOCATION);
+ resetData();
+
+ END_TEST;
+}
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali/internal/event/render-tasks/render-task-impl.h>
#include <dali/public-api/math/vector2.h>
-namespace Dali
-{
-namespace Internal
+namespace Dali::Internal
{
namespace
{
Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_HOVER_PROCESSOR");
#endif // defined(DEBUG_ENABLED)
+/**
+ * Structure for Variables used in the ProcessHoverEvent method.
+ */
+struct ProcessHoverEventVariables
+{
+ ProcessHoverEventVariables(bool geometry)
+ : isGeometry(geometry)
+ {
+ }
+
+ const bool isGeometry; ///< Whether it's a geometry or not.
+ Actor* lastPrimaryHitActor{nullptr}; ///< The last primary hit-actor.
+ Actor* lastConsumedActor{nullptr}; ///< The last consuming actor.
+ HoverEventPtr hoverEvent; ///< The current hover-event-impl.
+ Dali::HoverEvent hoverEventHandle; ///< The handle to the hover-event-impl.
+ RenderTaskPtr currentRenderTask; ///< The current render-task.
+ Dali::Actor consumedActor; ///< The actor that consumed the event.
+ Dali::Actor primaryHitActor; ///< The actor that has been hit by the primary point.
+ Integration::Point* primaryPoint{nullptr}; ///< The primary point of the hit.
+ PointState::Type primaryPointState{PointState::STARTED}; ///< The state of the primary point.
+};
+
const char* TOUCH_POINT_STATE[PointState::INTERRUPTED + 1] =
{
"STARTED",
bool ShouldEmitHoverEvent(const Actor& actorImpl, const Dali::HoverEvent& event)
{
PointState::Type state = event.GetState(0);
- return actorImpl.GetHoverRequired() && (state!= PointState::MOTION || actorImpl.IsDispatchHoverMotion());
+ return actorImpl.GetHoverRequired() && (state != PointState::MOTION || actorImpl.IsDispatchHoverMotion());
}
/**
Dali::Actor consumedActor;
std::list<Dali::Internal::Actor*>::reverse_iterator rIter = actorLists.rbegin();
- for (; rIter != actorLists.rend(); rIter++)
+ for(; rIter != actorLists.rend(); rIter++)
{
Actor* actorImpl(*rIter);
// Only emit the signal if the actor's hover signal has connections (or derived actor implementation requires hover).
actorImpl->SetHoverState(hoverEvent.GetState(0));
// If hover event is newly entering the actor, update it to the started state.
if(hoverEvent.GetState(0) == PointState::MOTION &&
- (currentState == PointState::FINISHED || currentState == PointState::INTERRUPTED || currentState == PointState::LEAVE))
+ (currentState == PointState::FINISHED || currentState == PointState::INTERRUPTED || currentState == PointState::LEAVE))
{
HoverEventPtr newHoverEvent = HoverEvent::Clone(GetImplementation(hoverEvent));
newHoverEvent->GetPoint(0).SetState(PointState::STARTED);
return consumedActor;
}
-
Dali::Actor AllocAndEmitHoverSignals(unsigned long time, Dali::Actor actor, const Integration::Point& point)
{
HoverEventPtr hoverEvent(new HoverEvent(time));
return EmitGeoHoverSignals(actorLists, hoverEventHandle);
}
-
/**
* Changes the state of the primary point to leave and emits the hover signals
*/
} // unnamed namespace
-HoverEventProcessor::HoverEventProcessor(Scene& scene)
-: mScene(scene),
- mLastPrimaryHitActor(MakeCallback(this, &HoverEventProcessor::OnObservedActorDisconnected))
-{
- DALI_LOG_TRACE_METHOD(gLogFilter);
-}
-
-HoverEventProcessor::~HoverEventProcessor()
-{
- DALI_LOG_TRACE_METHOD(gLogFilter);
-}
-
-void HoverEventProcessor::SendInterruptedHoverEvent(Dali::Internal::Actor* actor)
+struct HoverEventProcessor::Impl
{
- if(actor &&
- (mLastPrimaryHitActor.GetActor() == actor || mLastConsumedActor.GetActor() == actor))
- {
- Integration::Point point;
- point.SetState(PointState::INTERRUPTED);
- point.SetHitActor(Dali::Actor(actor));
- if(mScene.IsGeometryHittestEnabled())
- {
- std::list<Dali::Internal::Actor*> actorLists;
- actorLists.push_back(actor);
- GeoAllocAndEmitHoverSignals(actorLists, 0, point);
- }
- else
- {
- AllocAndEmitHoverSignals(GetMilliSeconds(), point.GetHitActor(), point);
- }
- Clear();
- }
-}
-
-void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event)
-{
- DALI_LOG_TRACE_METHOD(gLogFilter);
- DALI_ASSERT_ALWAYS(!event.points.empty() && "Empty HoverEvent sent from Integration\n");
-
- PointState::Type state = static_cast<PointState::Type>(event.points[0].GetState());
-
- PRINT_HIERARCHY(gLogFilter);
-
- DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_HOVER_EVENT");
-
- bool isGeometry = mScene.IsGeometryHittestEnabled();
-
- // Copy so we can add the results of a hit-test.
- HoverEventPtr hoverEvent(new HoverEvent(event.time));
-
- // 1) Check if it is an interrupted event - we should inform our last primary hit actor about this
- // and emit the stage signal as well.
-
- if(state == PointState::INTERRUPTED)
+ /**
+ * Emits an interrupted event while processing the latest hover event.
+ * @param[in/out] processor The hover-event-processor
+ * @param[in] isGeometry Whether it's a geometry or not
+ * @param[in] event The hover event that has occurred
+ */
+ static inline void EmitInterruptedEvent(HoverEventProcessor& processor, const bool isGeometry, const Integration::HoverEvent& event)
{
Dali::Actor consumingActor;
Integration::Point currentPoint(event.points[0]);
- Actor* lastPrimaryHitActor(mLastPrimaryHitActor.GetActor());
+ Actor* lastPrimaryHitActor(processor.mLastPrimaryHitActor.GetActor());
if(lastPrimaryHitActor)
{
Dali::Actor lastPrimaryHitActorHandle(lastPrimaryHitActor);
currentPoint.SetHitActor(lastPrimaryHitActorHandle);
if(isGeometry)
{
- consumingActor = GeoAllocAndEmitHoverSignals(mCandidateActorLists, event.time, currentPoint);
+ consumingActor = GeoAllocAndEmitHoverSignals(processor.mCandidateActorLists, event.time, currentPoint);
}
else
{
}
// If the last consumed actor was different to the primary hit actor then inform it as well (if it has not already been informed).
- Actor* lastConsumedActor(mLastConsumedActor.GetActor());
+ Actor* lastConsumedActor(processor.mLastConsumedActor.GetActor());
if(lastConsumedActor &&
- lastConsumedActor != lastPrimaryHitActor &&
- lastConsumedActor != consumingActor)
+ lastConsumedActor != lastPrimaryHitActor &&
+ lastConsumedActor != consumingActor)
{
Dali::Actor lastConsumedActorHandle(lastConsumedActor);
currentPoint.SetHitActor(lastConsumedActorHandle);
}
// Tell the hover-start consuming actor as well, if required
- Actor* hoverStartConsumedActor(mHoverStartConsumedActor.GetActor());
+ Actor* hoverStartConsumedActor(processor.mHoverStartConsumedActor.GetActor());
if(hoverStartConsumedActor &&
- hoverStartConsumedActor != lastPrimaryHitActor &&
- hoverStartConsumedActor != lastConsumedActor &&
- hoverStartConsumedActor != consumingActor)
+ hoverStartConsumedActor != lastPrimaryHitActor &&
+ hoverStartConsumedActor != lastConsumedActor &&
+ hoverStartConsumedActor != consumingActor)
{
Dali::Actor hoverStartConsumedActorHandle(hoverStartConsumedActor);
currentPoint.SetHitActor(hoverStartConsumedActorHandle);
}
}
- Clear();
- mHoverStartConsumedActor.SetActor(nullptr);
- return; // No need for hit testing
+ processor.Clear();
+ processor.mHoverStartConsumedActor.SetActor(nullptr);
}
- // 2) Hit Testing.
-
- Dali::HoverEvent hoverEventHandle(hoverEvent.Get());
-
- DALI_LOG_INFO(gLogFilter, Debug::Concise, "\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, "Point(s): %d\n", event.GetPointCount());
-
- RenderTaskPtr currentRenderTask;
- bool firstPointParsed = false;
-
- for(auto&& currentPoint : event.points)
+ /**
+ * Performs a hit-test and sets the variables in processor and localVars appropriately.
+ * @param[in/out] processor The hover-event-processor
+ * @param[in/out] localVars The struct of stack variables used by ProcessHoverEvent
+ * @param[in] event The hover event that has occurred
+ */
+ static inline void HitTest(HoverEventProcessor& processor, ProcessHoverEventVariables& localVars, const Integration::HoverEvent& event)
{
- HitTestAlgorithm::Results hitTestResults;
- hitTestResults.eventTime = event.time;
- ActorHoverableCheck actorHoverableCheck;
- HitTestAlgorithm::HitTest(mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, actorHoverableCheck, isGeometry);
-
- Integration::Point newPoint(currentPoint);
- newPoint.SetHitActor(hitTestResults.actor);
- newPoint.SetLocalPosition(hitTestResults.actorCoordinates);
-
- hoverEvent->AddPoint(newPoint);
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " State(%s), Screen(%.0f, %.0f), HitActor(%p, %s), Local(%.2f, %.2f)\n", TOUCH_POINT_STATE[currentPoint.GetState()], currentPoint.GetScreenPosition().x, currentPoint.GetScreenPosition().y, (hitTestResults.actor ? reinterpret_cast<void*>(&hitTestResults.actor.GetBaseObject()) : NULL), (hitTestResults.actor ? hitTestResults.actor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : ""), hitTestResults.actorCoordinates.x, hitTestResults.actorCoordinates.y);
-
- // Only set the currentRenderTask for the primary hit actor.
- if(!firstPointParsed)
+ bool firstPointParsed = false;
+ for(auto&& currentPoint : event.points)
{
- firstPointParsed = true;
- currentRenderTask = hitTestResults.renderTask;
- mCandidateActorLists = hitTestResults.actorLists;
+ HitTestAlgorithm::Results hitTestResults;
+ hitTestResults.eventTime = event.time;
+ ActorHoverableCheck actorHoverableCheck;
+ HitTestAlgorithm::HitTest(processor.mScene.GetSize(), processor.mScene.GetRenderTaskList(), processor.mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, actorHoverableCheck, localVars.isGeometry);
+
+ Integration::Point newPoint(currentPoint);
+ newPoint.SetHitActor(hitTestResults.actor);
+ newPoint.SetLocalPosition(hitTestResults.actorCoordinates);
+
+ localVars.hoverEvent->AddPoint(newPoint);
+
+ DALI_LOG_INFO(gLogFilter,
+ Debug::General,
+ " State(%s), Screen(%.0f, %.0f), HitActor(%p, %s), Local(%.2f, %.2f)\n",
+ TOUCH_POINT_STATE[currentPoint.GetState()],
+ currentPoint.GetScreenPosition().x,
+ currentPoint.GetScreenPosition().y,
+ (hitTestResults.actor ? reinterpret_cast<void*>(&hitTestResults.actor.GetBaseObject()) : NULL),
+ (hitTestResults.actor ? hitTestResults.actor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : ""),
+ hitTestResults.actorCoordinates.x,
+ hitTestResults.actorCoordinates.y);
+
+ // Only set the currentRenderTask for the primary hit actor.
+ if(!firstPointParsed)
+ {
+ firstPointParsed = true;
+ localVars.currentRenderTask = hitTestResults.renderTask;
+ processor.mCandidateActorLists = hitTestResults.actorLists;
+ }
}
}
- // 3) Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
-
- Integration::Point primaryPoint = hoverEvent->GetPoint(0);
- Dali::Actor primaryHitActor = primaryPoint.GetHitActor();
- PointState::Type primaryPointState = primaryPoint.GetState();
-
- // Emit the touch signal
- Dali::Actor consumedActor;
- if(currentRenderTask)
+ /**
+ * Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
+ * @param[in/out] processor The hover-event-processor
+ * @param[in/out] localVars The struct of stack variables used by ProcessHoverEvent
+ */
+ static inline void DeliverEventsToActorAndParents(HoverEventProcessor& processor, ProcessHoverEventVariables& localVars)
{
- Dali::Actor hitActor = hoverEvent->GetHitActor(0);
-
- if(isGeometry)
- {
- consumedActor = EmitGeoHoverSignals(mCandidateActorLists, hoverEventHandle);
- }
- else
+ // Emit the touch signal
+ if(localVars.currentRenderTask)
{
- // If the actor is hit first, the hover is started.
- if(hitActor &&
- mLastPrimaryHitActor.GetActor() != hitActor &&
- state == PointState::MOTION)
+ Dali::Actor hitActor = localVars.hoverEvent->GetHitActor(0);
+
+ if(localVars.isGeometry)
{
- Actor* hitActorImpl = &GetImplementation(hitActor);
- if(hitActorImpl->GetLeaveRequired())
+ localVars.consumedActor = EmitGeoHoverSignals(processor.mCandidateActorLists, localVars.hoverEventHandle);
+ }
+ else
+ {
+ // If the actor is hit first, the hover is started.
+ if(hitActor && processor.mLastPrimaryHitActor.GetActor() != hitActor && localVars.primaryPointState == PointState::MOTION)
{
- hoverEvent->GetPoint(0).SetState(PointState::STARTED);
+ Actor* hitActorImpl = &GetImplementation(hitActor);
+ if(hitActorImpl->GetLeaveRequired())
+ {
+ localVars.hoverEvent->GetPoint(0).SetState(PointState::STARTED);
+ }
}
+ localVars.consumedActor = EmitHoverSignals(hitActor, localVars.hoverEventHandle);
+ }
+
+ if(localVars.hoverEvent->GetPoint(0).GetState() != PointState::MOTION)
+ {
+ DALI_LOG_RELEASE_INFO("PrimaryHitActor:(%p), id(%d), name(%s), state(%s)\n",
+ localVars.primaryHitActor ? reinterpret_cast<void*>(&localVars.primaryHitActor.GetBaseObject()) : NULL,
+ localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
+ localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "",
+ TOUCH_POINT_STATE[localVars.hoverEvent->GetPoint(0).GetState()]);
+ DALI_LOG_RELEASE_INFO("ConsumedActor: (%p), id(%d), name(%s), state(%s)\n",
+ localVars.consumedActor ? reinterpret_cast<void*>(&localVars.consumedActor.GetBaseObject()) : NULL,
+ localVars.consumedActor ? localVars.consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
+ localVars.consumedActor ? localVars.consumedActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "",
+ TOUCH_POINT_STATE[localVars.hoverEvent->GetPoint(0).GetState()]);
}
- consumedActor = EmitHoverSignals(hitActor, hoverEventHandle);
}
- if(hoverEvent->GetPoint(0).GetState() != PointState::MOTION)
+ if((localVars.primaryPointState == PointState::STARTED) &&
+ (localVars.hoverEvent->GetPointCount() == 1) &&
+ (localVars.consumedActor && GetImplementation(localVars.consumedActor).OnScene()))
{
- DALI_LOG_RELEASE_INFO("PrimaryHitActor:(%p), id(%d), name(%s), state(%s)\n", primaryHitActor ? reinterpret_cast<void*>(&primaryHitActor.GetBaseObject()) : NULL, primaryHitActor ? primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, primaryHitActor ? primaryHitActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[hoverEvent->GetPoint(0).GetState()]);
- DALI_LOG_RELEASE_INFO("ConsumedActor: (%p), id(%d), name(%s), state(%s)\n", consumedActor ? reinterpret_cast<void*>(&consumedActor.GetBaseObject()) : NULL, consumedActor ? consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, consumedActor ? consumedActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[hoverEvent->GetPoint(0).GetState()]);
+ processor.mHoverStartConsumedActor.SetActor(&GetImplementation(localVars.consumedActor));
}
}
- if((primaryPointState == PointState::STARTED) &&
- (hoverEvent->GetPointCount() == 1) &&
- (consumedActor && GetImplementation(consumedActor).OnScene()))
+ /**
+ * Deliver Leave event to last hit or consuming actor if required.
+ * @param[in/out] processor The hover-event-processor
+ * @param[in/out] localVars The struct of stack variables used by ProcessHoverEvent
+ */
+ static inline void DeliverLeaveEvent(HoverEventProcessor& processor, ProcessHoverEventVariables& localVars)
{
- mHoverStartConsumedActor.SetActor(&GetImplementation(consumedActor));
- }
-
- // 4) Check if the last primary hit actor requires a leave event and if it was different to the current primary
- // hit actor. Also process the last consumed actor in the same manner.
-
- Actor* lastPrimaryHitActor(mLastPrimaryHitActor.GetActor());
- Actor* lastConsumedActor(mLastConsumedActor.GetActor());
- if((primaryPointState == PointState::STARTED) || (primaryPointState == PointState::MOTION) || (primaryPointState == PointState::FINISHED) || (primaryPointState == PointState::STATIONARY))
- {
- if(mLastRenderTask)
+ if((localVars.primaryPointState == PointState::STARTED) ||
+ (localVars.primaryPointState == PointState::MOTION) ||
+ (localVars.primaryPointState == PointState::FINISHED) ||
+ (localVars.primaryPointState == PointState::STATIONARY))
{
- Dali::Actor leaveEventConsumer;
- RenderTask& lastRenderTaskImpl = *mLastRenderTask.Get();
-
- if(lastPrimaryHitActor &&
- lastPrimaryHitActor != primaryHitActor &&
- lastPrimaryHitActor != consumedActor)
+ if(processor.mLastRenderTask)
{
- if(lastPrimaryHitActor->IsHittable() && IsActuallySensitive(lastPrimaryHitActor))
+ Dali::Actor leaveEventConsumer;
+ RenderTask& lastRenderTaskImpl = *processor.mLastRenderTask.Get();
+
+ if(localVars.lastPrimaryHitActor &&
+ localVars.lastPrimaryHitActor != localVars.primaryHitActor &&
+ localVars.lastPrimaryHitActor != localVars.consumedActor)
{
- if(isGeometry)
+ if(localVars.lastPrimaryHitActor->IsHittable() && IsActuallySensitive(localVars.lastPrimaryHitActor))
{
- // This is a situation where actors who received a hover event must leave.
- // Compare the lastActorList that received the hover event and the CandidateActorList that can receive the new hover event
- // If the hover event can no longer be received, Leave is sent.
- std::list<Dali::Internal::Actor*>::reverse_iterator rLastIter = mLastActorLists.rbegin();
- for(; rLastIter != mLastActorLists.rend(); rLastIter++)
+ if(localVars.isGeometry)
{
- bool find = false;
- std::list<Dali::Internal::Actor*>::reverse_iterator rCandidateIter = mCandidateActorLists.rbegin();
- for(; rCandidateIter != mCandidateActorLists.rend(); rCandidateIter++)
+ // This is a situation where actors who received a hover event must leave.
+ // Compare the lastActorList that received the hover event and the CandidateActorList that can receive the new hover event
+ // If the hover event can no longer be received, Leave is sent.
+ std::list<Dali::Internal::Actor*>::reverse_iterator rLastIter = processor.mLastActorLists.rbegin();
+ for(; rLastIter != processor.mLastActorLists.rend(); rLastIter++)
{
- if(*rCandidateIter == *rLastIter)
+ bool find = false;
+ std::list<Dali::Internal::Actor*>::reverse_iterator rCandidateIter = processor.mCandidateActorLists.rbegin();
+ for(; rCandidateIter != processor.mCandidateActorLists.rend(); rCandidateIter++)
+ {
+ if(*rCandidateIter == *rLastIter)
+ {
+ find = true;
+ break;
+ }
+ }
+ if(!find)
+ {
+ DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(*rLastIter), (*rLastIter)->GetId(), (*rLastIter)->GetName().data());
+ leaveEventConsumer = EmitHoverSignals(*rLastIter, lastRenderTaskImpl, localVars.hoverEvent, PointState::LEAVE, localVars.isGeometry);
+ }
+ // If the actor has been consumed, you do not need to proceed.
+ if(*rLastIter == localVars.lastConsumedActor)
{
- find = true;
break;
}
}
- if(!find)
- {
- DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(*rLastIter), (*rLastIter)->GetId(), (*rLastIter)->GetName().data());
- leaveEventConsumer = EmitHoverSignals(*rLastIter, lastRenderTaskImpl, hoverEvent, PointState::LEAVE, isGeometry);
- }
- // If the actor has been consumed, you do not need to proceed.
- if(*rLastIter == lastConsumedActor)
- {
- break;
- }
+ }
+ else if(localVars.lastPrimaryHitActor->GetLeaveRequired())
+ {
+ // In the case of isGeometry, it is not propagated but only sent to actors who are not hittable.
+ DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(localVars.lastPrimaryHitActor), localVars.lastPrimaryHitActor->GetId(), localVars.lastPrimaryHitActor->GetName().data());
+ leaveEventConsumer = EmitHoverSignals(processor.mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, localVars.hoverEvent, PointState::LEAVE, localVars.isGeometry);
}
}
- else if(lastPrimaryHitActor->GetLeaveRequired())
+ else if(localVars.primaryPointState != PointState::STARTED)
{
- // In the case of isGeometry, it is not propagated but only sent to actors who are not hittable.
- DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data());
- leaveEventConsumer = EmitHoverSignals(mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, hoverEvent, PointState::LEAVE, isGeometry);
+ // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one.
+ // An interrupted event is sent to allow some actors to go back to their original state (i.e. Button controls)
+ DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(localVars.lastPrimaryHitActor), localVars.lastPrimaryHitActor->GetId(), localVars.lastPrimaryHitActor->GetName().data());
+ leaveEventConsumer = EmitHoverSignals(processor.mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, localVars.hoverEvent, PointState::INTERRUPTED, localVars.isGeometry);
}
}
- else if(primaryPointState != PointState::STARTED)
- {
- // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one.
- // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
- DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data());
- leaveEventConsumer = EmitHoverSignals(mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, hoverEvent, PointState::INTERRUPTED, isGeometry);
- }
- }
- // Check if the motion event has been consumed by another actor's listener. In this case, the previously
- // consumed actor's listeners may need to be informed (through a leave event).
- // Further checks here to ensure we do not signal the same actor twice for the same event.
- if(lastConsumedActor &&
- lastConsumedActor != consumedActor &&
- lastConsumedActor != lastPrimaryHitActor &&
- lastConsumedActor != primaryHitActor &&
- lastConsumedActor != leaveEventConsumer)
- {
- if(lastConsumedActor->IsHittable() && IsActuallySensitive(lastConsumedActor))
+ // Check if the motion event has been consumed by another actor's listener. In this case, the previously
+ // consumed actor's listeners may need to be informed (through a leave event).
+ // Further checks here to ensure we do not signal the same actor twice for the same event.
+ if(localVars.lastConsumedActor &&
+ localVars.lastConsumedActor != localVars.consumedActor &&
+ localVars.lastConsumedActor != localVars.lastPrimaryHitActor &&
+ localVars.lastConsumedActor != localVars.primaryHitActor &&
+ localVars.lastConsumedActor != leaveEventConsumer)
{
- if(lastConsumedActor->GetLeaveRequired() && !isGeometry) // For geometry, we have already sent leave. There is no need to send leave repeatedly.
+ if(localVars.lastConsumedActor->IsHittable() && IsActuallySensitive(localVars.lastConsumedActor))
+ {
+ if(localVars.lastConsumedActor->GetLeaveRequired() && !localVars.isGeometry) // For geometry, we have already sent leave. There is no need to send leave repeatedly.
+ {
+ DALI_LOG_RELEASE_INFO("LeaveActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(localVars.lastConsumedActor), localVars.lastConsumedActor->GetId(), localVars.lastConsumedActor->GetName().data());
+ EmitHoverSignals(localVars.lastConsumedActor, lastRenderTaskImpl, localVars.hoverEvent, PointState::LEAVE, localVars.isGeometry);
+ }
+ }
+ else if(localVars.primaryPointState != PointState::STARTED)
{
- DALI_LOG_RELEASE_INFO("LeaveActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data());
- EmitHoverSignals(lastConsumedActor, lastRenderTaskImpl, hoverEvent, PointState::LEAVE, isGeometry);
+ // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one.
+ // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
+ DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(localVars.lastConsumedActor), localVars.lastConsumedActor->GetId(), localVars.lastConsumedActor->GetName().data());
+ EmitHoverSignals(processor.mLastConsumedActor.GetActor(), lastRenderTaskImpl, localVars.hoverEvent, PointState::INTERRUPTED, localVars.isGeometry);
}
}
- else if(primaryPointState != PointState::STARTED)
- {
- // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one.
- // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
- DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data());
- EmitHoverSignals(mLastConsumedActor.GetActor(), lastRenderTaskImpl, hoverEvent, PointState::INTERRUPTED, isGeometry);
- }
}
}
}
- // 5) If our primary point is a FINISHED event, then the primary point (in multi-touch) will change next
- // time so set our last primary actor to NULL. Do the same to the last consumed actor as well.
-
- if(primaryPointState == PointState::FINISHED)
+ /**
+ * Update the processor member appropriately by handling the final up event, and setting the last hit/consumed events etc.
+ * @param[in/out] processor The hover-event-processor
+ * @param[in/out] localVars The struct of stack variables used by ProcessHoverEvent
+ */
+ static inline void UpdateMembersWithCurrentHitInformation(HoverEventProcessor& processor, ProcessHoverEventVariables& localVars)
{
- Clear();
- }
- else
- {
- // The primaryHitActor may have been removed from the scene so ensure it is still on the scene before setting members.
- if(primaryHitActor && GetImplementation(primaryHitActor).OnScene())
+ // If our primary point is a FINISHED event, then the primary point (in multi-touch) will change next
+ // time so set our last primary actor to NULL. Do the same to the last consumed actor as well.
+
+ if(localVars.primaryPointState == PointState::FINISHED)
+ {
+ processor.Clear();
+ }
+ else
{
- 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())
+ // The primaryHitActor may have been removed from the scene so ensure it is still on the scene before setting members.
+ if(localVars.primaryHitActor && GetImplementation(localVars.primaryHitActor).OnScene())
{
- mLastConsumedActor.SetActor(&GetImplementation(consumedActor));
+ processor.mLastPrimaryHitActor.SetActor(&GetImplementation(localVars.primaryHitActor));
+ // Only observe the consumed actor if we have a primaryHitActor (check if it is still on the scene).
+ if(localVars.consumedActor && GetImplementation(localVars.consumedActor).OnScene())
+ {
+ processor.mLastConsumedActor.SetActor(&GetImplementation(localVars.consumedActor));
+ }
+ else
+ {
+ processor.mLastConsumedActor.SetActor(nullptr);
+ }
+
+ processor.mLastRenderTask = localVars.currentRenderTask;
+ processor.mLastActorLists = processor.mCandidateActorLists;
}
else
{
- mLastConsumedActor.SetActor(nullptr);
+ processor.Clear();
}
-
- mLastRenderTask = currentRenderTask;
- mLastActorLists = mCandidateActorLists;
- }
- else
- {
- Clear();
}
}
- // 6) Emit an interrupted event to the hover-started actor if it hasn't consumed the FINISHED.
-
- if(hoverEvent->GetPointCount() == 1) // Only want the first hover started
+ /**
+ * Deliver an interrupted event to the hover started actor as required.
+ * @param[in/out] processor The hover-event-processor
+ * @param[in/out] localVars The struct of stack variables used by ProcessHoverEvent
+ * @param[in] event The hover event that has occurred
+ */
+ static inline void DeliverInterruptedEventToHoverStartedActor(HoverEventProcessor& processor, ProcessHoverEventVariables& localVars, const Integration::HoverEvent& event)
{
- switch(primaryPointState)
+ if(localVars.hoverEvent->GetPointCount() == 1 && localVars.primaryPointState == PointState::FINISHED) // Only want the first hover started
{
- case PointState::FINISHED:
+ Actor* hoverStartConsumedActor(processor.mHoverStartConsumedActor.GetActor());
+ if(hoverStartConsumedActor &&
+ hoverStartConsumedActor != localVars.consumedActor &&
+ hoverStartConsumedActor != localVars.lastPrimaryHitActor &&
+ hoverStartConsumedActor != localVars.lastConsumedActor)
{
- Actor* hoverStartConsumedActor(mHoverStartConsumedActor.GetActor());
- if(hoverStartConsumedActor &&
- hoverStartConsumedActor != consumedActor &&
- hoverStartConsumedActor != lastPrimaryHitActor &&
- hoverStartConsumedActor != lastConsumedActor)
+ Dali::Actor hoverStartConsumedActorHandle(hoverStartConsumedActor);
+ Integration::Point primaryPoint = localVars.hoverEvent->GetPoint(0);
+ primaryPoint.SetHitActor(hoverStartConsumedActorHandle);
+ primaryPoint.SetState(PointState::INTERRUPTED);
+ if(localVars.isGeometry)
{
- Dali::Actor hoverStartConsumedActorHandle(hoverStartConsumedActor);
- Integration::Point primaryPoint = hoverEvent->GetPoint(0);
- primaryPoint.SetHitActor(hoverStartConsumedActorHandle);
- primaryPoint.SetState(PointState::INTERRUPTED);
- if(isGeometry)
- {
- std::list<Dali::Internal::Actor*> actorLists;
- actorLists.push_back(hoverStartConsumedActor);
- GeoAllocAndEmitHoverSignals(actorLists, event.time, primaryPoint);
- }
- else
- {
- AllocAndEmitHoverSignals(event.time, hoverStartConsumedActorHandle, primaryPoint);
- }
-
- // Restore hover-event to original state
- primaryPoint.SetHitActor(primaryHitActor);
- primaryPoint.SetState(primaryPointState);
+ std::list<Dali::Internal::Actor*> actorLists;
+ actorLists.push_back(hoverStartConsumedActor);
+ GeoAllocAndEmitHoverSignals(actorLists, event.time, primaryPoint);
+ }
+ else
+ {
+ AllocAndEmitHoverSignals(event.time, hoverStartConsumedActorHandle, primaryPoint);
}
- mHoverStartConsumedActor.SetActor(nullptr);
+ // Restore hover-event to original state
+ primaryPoint.SetHitActor(localVars.primaryHitActor);
+ primaryPoint.SetState(localVars.primaryPointState);
}
- // No break, Fallthrough
- case PointState::STARTED:
- case PointState::MOTION:
- case PointState::LEAVE:
- case PointState::STATIONARY:
- case PointState::INTERRUPTED:
- {
- // Ignore
- break;
- }
+ processor.mHoverStartConsumedActor.SetActor(nullptr);
+ }
+ }
+};
+
+HoverEventProcessor::HoverEventProcessor(Scene& scene)
+: mScene(scene),
+ mLastPrimaryHitActor(MakeCallback(this, &HoverEventProcessor::OnObservedActorDisconnected))
+{
+ DALI_LOG_TRACE_METHOD(gLogFilter);
+}
+
+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));
+ if(mScene.IsGeometryHittestEnabled())
+ {
+ std::list<Dali::Internal::Actor*> actorLists;
+ actorLists.push_back(actor);
+ GeoAllocAndEmitHoverSignals(actorLists, 0, point);
+ }
+ else
+ {
+ AllocAndEmitHoverSignals(GetMilliSeconds(), point.GetHitActor(), point);
}
+ Clear();
+ }
+}
+
+void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event)
+{
+ DALI_LOG_TRACE_METHOD(gLogFilter);
+ DALI_ASSERT_ALWAYS(!event.points.empty() && "Empty HoverEvent sent from Integration\n");
+
+ PRINT_HIERARCHY(gLogFilter);
+
+ DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_HOVER_EVENT");
+
+ ProcessHoverEventVariables localVars(mScene.IsGeometryHittestEnabled());
+
+ // Copy so we can add the results of a hit-test.
+ localVars.hoverEvent = new HoverEvent(event.time);
+
+ // 1) Check if it is an interrupted event - we should inform our last primary hit actor about this
+ // and emit the stage signal as well.
+ if(event.points[0].GetState() == PointState::INTERRUPTED)
+ {
+ Impl::EmitInterruptedEvent(*this, localVars.isGeometry, event);
+ return; // No need for hit testing
}
+
+ // 2) Hit Testing.
+ DALI_LOG_INFO(gLogFilter, Debug::Concise, "\n");
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Point(s): %d\n", event.GetPointCount());
+ localVars.hoverEventHandle = Dali::HoverEvent(localVars.hoverEvent.Get());
+ Impl::HitTest(*this, localVars, event);
+
+ // 3) Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
+ localVars.primaryPoint = &localVars.hoverEvent->GetPoint(0);
+ localVars.primaryHitActor = localVars.primaryPoint->GetHitActor();
+ localVars.primaryPointState = localVars.primaryPoint->GetState();
+ Impl::DeliverEventsToActorAndParents(*this, localVars);
+
+ // 4) Check if the last primary hit actor requires a leave event and if it was different to the current primary
+ // hit actor. Also process the last consumed actor in the same manner.
+ localVars.lastPrimaryHitActor = mLastPrimaryHitActor.GetActor();
+ localVars.lastConsumedActor = mLastConsumedActor.GetActor();
+ Impl::DeliverLeaveEvent(*this, localVars);
+
+ // 5) Update the processor member appropriately.
+ Impl::UpdateMembersWithCurrentHitInformation(*this, localVars);
+
+ // 6) Emit an interrupted event to the hover-started actor if it hasn't consumed the FINISHED.
+ Impl::DeliverInterruptedEventToHoverStartedActor(*this, localVars, event);
}
void HoverEventProcessor::Clear()
SendInterruptedHoverEvent(actor);
}
-} // namespace Internal
-
-} // namespace Dali
+} // namespace Dali::Internal