// Remove actor from Stage
application.GetScene().Remove(actor);
+ data.Reset();
+ rootData.Reset();
// Render and notify
application.SendNotification();
// 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();
// 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;
}
// 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();
// 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();
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;
+}
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)
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.
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.
*/
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
*/
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.
#include <sstream>
#endif
+// EXTERNAL INCLUDES
+#include <chrono>
+
// INTERNAL INCLUDES
#include <dali/integration-api/debug.h>
#include <dali/integration-api/events/hover-event-integ.h>
}
};
+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);
}
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);
AllocAndEmitHoverSignals(event.time, hoverStartConsumedActorHandle, currentPoint);
}
- mLastPrimaryHitActor.SetActor(nullptr);
- mLastConsumedActor.SetActor(nullptr);
+ Clear();
mHoverStartConsumedActor.SetActor(nullptr);
- mLastRenderTask.Reset();
-
return; // No need for hit testing
}
if(primaryPointState == PointState::FINISHED)
{
- mLastPrimaryHitActor.SetActor(nullptr);
- mLastConsumedActor.SetActor(nullptr);
- mLastRenderTask.Reset();
+ Clear();
}
else
{
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())
{
}
else
{
- mLastPrimaryHitActor.SetActor(nullptr);
- mLastConsumedActor.SetActor(nullptr);
- mLastRenderTask.Reset();
+ Clear();
}
}
}
}
+void HoverEventProcessor::Clear()
+{
+ mLastPrimaryHitActor.SetActor(nullptr);
+ mLastConsumedActor.SetActor(nullptr);
+ mLastRenderTask.Reset();
+}
+
+void HoverEventProcessor::OnObservedActorDisconnected(Dali::Internal::Actor* actor)
+{
+ SendInterruptedHoverEvent(actor);
+}
+
} // namespace Internal
} // namespace Dali
*/
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&);
// 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