From 5fe77951b92d45ee2b7a404fb19a495e1e07ff15 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 31 Dec 2023 13:36:41 +0100 Subject: [PATCH 1/2] Send mouse release events to hovered and previously clicked items --- src/mouseeventhandler.cpp | 34 +++++++++++++------ src/mouseeventhandler.h | 2 +- .../mouseeventhandler_test.cpp | 9 ++++- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/mouseeventhandler.cpp b/src/mouseeventhandler.cpp index 283a29a..1ff8821 100644 --- a/src/mouseeventhandler.cpp +++ b/src/mouseeventhandler.cpp @@ -55,16 +55,19 @@ bool MouseEventHandler::eventFilter(QObject *obj, QEvent *event) forwardPointEvent(static_cast(event)); return true; - case QEvent::MouseButtonRelease: + case QEvent::MouseButtonRelease: { emit mouseReleased(); + QQuickItem *oldClickedItem = m_clickedItem; if (m_clickedItem) { sendPointEventToItem(static_cast(event), m_clickedItem); m_clickedItem = nullptr; - } else - forwardPointEvent(static_cast(event)); + } + + forwardPointEvent(static_cast(event), oldClickedItem); return true; + } default: break; @@ -73,7 +76,7 @@ bool MouseEventHandler::eventFilter(QObject *obj, QEvent *event) return QObject::eventFilter(obj, event); } -void MouseEventHandler::forwardPointEvent(QSinglePointEvent *event) +void MouseEventHandler::forwardPointEvent(QSinglePointEvent *event, QQuickItem *oldClickedItem) { Q_ASSERT(m_spriteRepeater); @@ -97,22 +100,33 @@ void MouseEventHandler::forwardPointEvent(QSinglePointEvent *event) // Sort the list by layer order std::sort(sprites.begin(), sprites.end(), [](IRenderedTarget *t1, IRenderedTarget *t2) { return t1->scratchTarget()->layerOrder() > t2->scratchTarget()->layerOrder(); }); - // Send the event to the hovered sprite + // Find hovered sprite + QQuickItem *hoveredItem = nullptr; + for (IRenderedTarget *sprite : sprites) { // contains() expects position in the item's coordinate system QPointF localPos = sprite->mapFromScene(event->scenePosition()); if (sprite->contains(localPos)) { - sendPointEventToItem(event, sprite); - return; + hoveredItem = sprite; + break; } } // If there wasn't any hovered sprite, send the event to the stage - Q_ASSERT(m_stage); + if (!hoveredItem) { + hoveredItem = m_stage; + Q_ASSERT(m_stage); + } - if (m_stage) - sendPointEventToItem(event, m_stage); + // Send the event to the item + if (hoveredItem) { + // Since both the hovered item and previously clicked item should receive mouse release event, + // avoid duplicate events by checking whether the previously clicked item is the hovered item. + if (!(event->type() == QEvent::MouseButtonRelease && hoveredItem == oldClickedItem)) { + sendPointEventToItem(event, hoveredItem); + } + } } void MouseEventHandler::sendPointEventToItem(QSinglePointEvent *event, QQuickItem *item) diff --git a/src/mouseeventhandler.h b/src/mouseeventhandler.h index ac60ed1..dd2255b 100644 --- a/src/mouseeventhandler.h +++ b/src/mouseeventhandler.h @@ -34,7 +34,7 @@ class MouseEventHandler : public QObject void mouseReleased(); private: - void forwardPointEvent(QSinglePointEvent *event); + void forwardPointEvent(QSinglePointEvent *event, QQuickItem *oldClickedItem = nullptr); void sendPointEventToItem(QSinglePointEvent *event, QQuickItem *item); void sendHoverEventToItem(QHoverEvent *originalEvent, QEvent::Type newType, QQuickItem *item); diff --git a/test/mouseeventhandler/mouseeventhandler_test.cpp b/test/mouseeventhandler/mouseeventhandler_test.cpp index 8c39434..73df96a 100644 --- a/test/mouseeventhandler/mouseeventhandler_test.cpp +++ b/test/mouseeventhandler/mouseeventhandler_test.cpp @@ -304,6 +304,8 @@ TEST(MouseEventHandlerTest, MousePressReleaseEvent) releasedSpy.clear(); // Send release (should be sent to sprite 1) + EXPECT_CALL(renderedTarget3, contains(localPos)).WillOnce(Return(false)); + EXPECT_CALL(renderedTarget1, contains(localPos)).WillOnce(Return(true)); EXPECT_CALL(renderedTarget1, mouseReleaseEvent(_)).WillOnce(WithArgs<0>(Invoke(checkReleaseEvent))); ASSERT_TRUE(handler.eventFilter(nullptr, &releaseEvent)); ASSERT_EQ(pressedSpy.count(), 0); @@ -321,8 +323,10 @@ TEST(MouseEventHandlerTest, MousePressReleaseEvent) pressedSpy.clear(); releasedSpy.clear(); - // Send release (should be sent to sprite 1) + // Send release while sprite 3 is hovered (should be sent to both sprites) + EXPECT_CALL(renderedTarget3, contains(localPos)).WillOnce(Return(true)); EXPECT_CALL(renderedTarget1, mouseReleaseEvent(_)).WillOnce(WithArgs<0>(Invoke(checkReleaseEvent))); + EXPECT_CALL(renderedTarget3, mouseReleaseEvent(_)).WillOnce(WithArgs<0>(Invoke(checkReleaseEvent))); ASSERT_TRUE(handler.eventFilter(nullptr, &releaseEvent)); ASSERT_EQ(pressedSpy.count(), 0); ASSERT_EQ(releasedSpy.count(), 1); @@ -351,6 +355,9 @@ TEST(MouseEventHandlerTest, MousePressReleaseEvent) releasedSpy.clear(); // Send release (should be sent to stage) + EXPECT_CALL(renderedTarget3, contains(localPos)).WillOnce(Return(false)); + EXPECT_CALL(renderedTarget1, contains(localPos)).WillOnce(Return(false)); + EXPECT_CALL(renderedTarget2, contains(localPos)).WillOnce(Return(false)); EXPECT_CALL(stage, mouseReleaseEvent(_)).WillOnce(WithArgs<0>(Invoke(checkReleaseEvent))); ASSERT_TRUE(handler.eventFilter(nullptr, &releaseEvent)); ASSERT_EQ(pressedSpy.count(), 0); From d751c7c3409d9739924c10168f6b3938d661edfd Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sun, 31 Dec 2023 13:37:17 +0100 Subject: [PATCH 2/2] Notify libscratchcpp about target clicks --- src/renderedtarget.cpp | 10 ++++++++++ test/renderedtarget/renderedtarget_test.cpp | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/renderedtarget.cpp b/src/renderedtarget.cpp index f6be5d5..b963e5b 100644 --- a/src/renderedtarget.cpp +++ b/src/renderedtarget.cpp @@ -265,16 +265,26 @@ void RenderedTarget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) m_clicked = true; + + if (m_engine && (!m_spriteModel || !m_spriteModel->sprite()->draggable())) { + // Notify libscratchcpp about the click + m_engine->clickTarget(scratchTarget()); + } } void RenderedTarget::mouseReleaseEvent(QMouseEvent *event) { m_clicked = false; Q_ASSERT(m_mouseArea); + Q_ASSERT(m_engine); // Stop dragging if (m_mouseArea->draggedSprite() == this) m_mouseArea->setDraggedSprite(nullptr); + else if (m_engine && m_spriteModel && m_spriteModel->sprite()->draggable()) { + // Notify libscratchcpp about the click + m_engine->clickTarget(scratchTarget()); + } } void RenderedTarget::mouseMoveEvent(QMouseEvent *event) diff --git a/test/renderedtarget/renderedtarget_test.cpp b/test/renderedtarget/renderedtarget_test.cpp index 828da88..22b9fb7 100644 --- a/test/renderedtarget/renderedtarget_test.cpp +++ b/test/renderedtarget/renderedtarget_test.cpp @@ -576,11 +576,13 @@ TEST_F(RenderedTargetTest, SpriteDragging) QMouseEvent moveEventRightButton(QEvent::MouseMove, QPointF(), QPointF(), Qt::RightButton, Qt::RightButton, Qt::NoModifier); QMouseEvent pressEventRightButton(QEvent::MouseButtonPress, QPointF(), QPointF(), Qt::RightButton, Qt::RightButton, Qt::NoModifier); QMouseEvent releaseEventRightButton(QEvent::MouseButtonRelease, QPointF(), QPointF(), Qt::RightButton, Qt::RightButton, Qt::NoModifier); + EXPECT_CALL(engine, clickTarget(&sprite)); QCoreApplication::sendEvent(&target, &pressEventRightButton); QCoreApplication::sendEvent(&target, &moveEventRightButton); ASSERT_EQ(sprite.x(), 64.08); ASSERT_EQ(sprite.y(), -6.86); ASSERT_EQ(mouseArea.draggedSprite(), nullptr); + EXPECT_CALL(engine, clickTarget).Times(0); QCoreApplication::sendEvent(&target, &releaseEventRightButton); ASSERT_EQ(mouseArea.draggedSprite(), nullptr); @@ -591,11 +593,13 @@ TEST_F(RenderedTargetTest, SpriteDragging) // Try right mouse button with "draggable" set to true (should not work) sprite.setDraggable(true); + EXPECT_CALL(engine, clickTarget).Times(0); QCoreApplication::sendEvent(&target, &pressEventRightButton); QCoreApplication::sendEvent(&target, &moveEventRightButton); ASSERT_EQ(sprite.x(), 64.08); ASSERT_EQ(sprite.y(), -6.86); ASSERT_EQ(mouseArea.draggedSprite(), nullptr); + EXPECT_CALL(engine, clickTarget(&sprite)); QCoreApplication::sendEvent(&target, &releaseEventRightButton); ASSERT_EQ(mouseArea.draggedSprite(), nullptr); @@ -609,6 +613,7 @@ TEST_F(RenderedTargetTest, SpriteDragging) QMouseEvent moveEvent(QEvent::MouseMove, QPointF(), QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(), QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(), QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + EXPECT_CALL(engine, clickTarget(&sprite)); QCoreApplication::sendEvent(&target, &pressEvent); QCoreApplication::sendEvent(&target, &moveEvent); ASSERT_EQ(sprite.x(), 64.08); @@ -619,10 +624,12 @@ TEST_F(RenderedTargetTest, SpriteDragging) ASSERT_EQ(sprite.x(), 64.08); ASSERT_EQ(sprite.y(), -6.86); ASSERT_EQ(mouseArea.draggedSprite(), nullptr); + EXPECT_CALL(engine, clickTarget).Times(0); QCoreApplication::sendEvent(&target, &releaseEvent); // Try left mouse button with "draggable" set to true sprite.setDraggable(true); + EXPECT_CALL(engine, clickTarget).Times(0); QCoreApplication::sendEvent(&target, &pressEvent); EXPECT_CALL(engine, mouseX()).WillOnce(Return(67.95)); EXPECT_CALL(engine, mouseY()).WillOnce(Return(2.1)); @@ -663,12 +670,15 @@ TEST_F(RenderedTargetTest, SpriteDragging) // Try to drag the second sprite while the first is being dragged sprite.setDraggable(true); + EXPECT_CALL(engine, clickTarget).Times(0); QCoreApplication::sendEvent(&anotherTarget, &pressEvent); QCoreApplication::sendEvent(&anotherTarget, &moveEvent); ASSERT_EQ(mouseArea.draggedSprite(), &target); + EXPECT_CALL(engine, clickTarget(&sprite)); QCoreApplication::sendEvent(&anotherTarget, &releaseEvent); // Stop dragging + EXPECT_CALL(engine, clickTarget).Times(0); QCoreApplication::sendEvent(&target, &releaseEvent); ASSERT_EQ(std::round(sprite.x() * 100) / 100, 68.26); ASSERT_EQ(std::round(sprite.y() * 100) / 100, -1.95);