Skip to content

Commit 1ff4dc7

Browse files
authored
Merge pull request #59 from scratchcpp/target_click
Implement target click events
2 parents ed4ef5b + d751c7c commit 1ff4dc7

File tree

5 files changed

+53
-12
lines changed

5 files changed

+53
-12
lines changed

src/mouseeventhandler.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,19 @@ bool MouseEventHandler::eventFilter(QObject *obj, QEvent *event)
5555
forwardPointEvent(static_cast<QSinglePointEvent *>(event));
5656
return true;
5757

58-
case QEvent::MouseButtonRelease:
58+
case QEvent::MouseButtonRelease: {
5959
emit mouseReleased();
60+
QQuickItem *oldClickedItem = m_clickedItem;
6061

6162
if (m_clickedItem) {
6263
sendPointEventToItem(static_cast<QSinglePointEvent *>(event), m_clickedItem);
6364
m_clickedItem = nullptr;
64-
} else
65-
forwardPointEvent(static_cast<QSinglePointEvent *>(event));
65+
}
66+
67+
forwardPointEvent(static_cast<QSinglePointEvent *>(event), oldClickedItem);
6668

6769
return true;
70+
}
6871

6972
default:
7073
break;
@@ -73,7 +76,7 @@ bool MouseEventHandler::eventFilter(QObject *obj, QEvent *event)
7376
return QObject::eventFilter(obj, event);
7477
}
7578

76-
void MouseEventHandler::forwardPointEvent(QSinglePointEvent *event)
79+
void MouseEventHandler::forwardPointEvent(QSinglePointEvent *event, QQuickItem *oldClickedItem)
7780
{
7881
Q_ASSERT(m_spriteRepeater);
7982

@@ -97,22 +100,33 @@ void MouseEventHandler::forwardPointEvent(QSinglePointEvent *event)
97100
// Sort the list by layer order
98101
std::sort(sprites.begin(), sprites.end(), [](IRenderedTarget *t1, IRenderedTarget *t2) { return t1->scratchTarget()->layerOrder() > t2->scratchTarget()->layerOrder(); });
99102

100-
// Send the event to the hovered sprite
103+
// Find hovered sprite
104+
QQuickItem *hoveredItem = nullptr;
105+
101106
for (IRenderedTarget *sprite : sprites) {
102107
// contains() expects position in the item's coordinate system
103108
QPointF localPos = sprite->mapFromScene(event->scenePosition());
104109

105110
if (sprite->contains(localPos)) {
106-
sendPointEventToItem(event, sprite);
107-
return;
111+
hoveredItem = sprite;
112+
break;
108113
}
109114
}
110115

111116
// If there wasn't any hovered sprite, send the event to the stage
112-
Q_ASSERT(m_stage);
117+
if (!hoveredItem) {
118+
hoveredItem = m_stage;
119+
Q_ASSERT(m_stage);
120+
}
113121

114-
if (m_stage)
115-
sendPointEventToItem(event, m_stage);
122+
// Send the event to the item
123+
if (hoveredItem) {
124+
// Since both the hovered item and previously clicked item should receive mouse release event,
125+
// avoid duplicate events by checking whether the previously clicked item is the hovered item.
126+
if (!(event->type() == QEvent::MouseButtonRelease && hoveredItem == oldClickedItem)) {
127+
sendPointEventToItem(event, hoveredItem);
128+
}
129+
}
116130
}
117131

118132
void MouseEventHandler::sendPointEventToItem(QSinglePointEvent *event, QQuickItem *item)

src/mouseeventhandler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class MouseEventHandler : public QObject
3434
void mouseReleased();
3535

3636
private:
37-
void forwardPointEvent(QSinglePointEvent *event);
37+
void forwardPointEvent(QSinglePointEvent *event, QQuickItem *oldClickedItem = nullptr);
3838
void sendPointEventToItem(QSinglePointEvent *event, QQuickItem *item);
3939
void sendHoverEventToItem(QHoverEvent *originalEvent, QEvent::Type newType, QQuickItem *item);
4040

src/renderedtarget.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,16 +265,26 @@ void RenderedTarget::mousePressEvent(QMouseEvent *event)
265265
{
266266
if (event->button() == Qt::LeftButton)
267267
m_clicked = true;
268+
269+
if (m_engine && (!m_spriteModel || !m_spriteModel->sprite()->draggable())) {
270+
// Notify libscratchcpp about the click
271+
m_engine->clickTarget(scratchTarget());
272+
}
268273
}
269274

270275
void RenderedTarget::mouseReleaseEvent(QMouseEvent *event)
271276
{
272277
m_clicked = false;
273278
Q_ASSERT(m_mouseArea);
279+
Q_ASSERT(m_engine);
274280

275281
// Stop dragging
276282
if (m_mouseArea->draggedSprite() == this)
277283
m_mouseArea->setDraggedSprite(nullptr);
284+
else if (m_engine && m_spriteModel && m_spriteModel->sprite()->draggable()) {
285+
// Notify libscratchcpp about the click
286+
m_engine->clickTarget(scratchTarget());
287+
}
278288
}
279289

280290
void RenderedTarget::mouseMoveEvent(QMouseEvent *event)

test/mouseeventhandler/mouseeventhandler_test.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ TEST(MouseEventHandlerTest, MousePressReleaseEvent)
304304
releasedSpy.clear();
305305

306306
// Send release (should be sent to sprite 1)
307+
EXPECT_CALL(renderedTarget3, contains(localPos)).WillOnce(Return(false));
308+
EXPECT_CALL(renderedTarget1, contains(localPos)).WillOnce(Return(true));
307309
EXPECT_CALL(renderedTarget1, mouseReleaseEvent(_)).WillOnce(WithArgs<0>(Invoke(checkReleaseEvent)));
308310
ASSERT_TRUE(handler.eventFilter(nullptr, &releaseEvent));
309311
ASSERT_EQ(pressedSpy.count(), 0);
@@ -321,8 +323,10 @@ TEST(MouseEventHandlerTest, MousePressReleaseEvent)
321323
pressedSpy.clear();
322324
releasedSpy.clear();
323325

324-
// Send release (should be sent to sprite 1)
326+
// Send release while sprite 3 is hovered (should be sent to both sprites)
327+
EXPECT_CALL(renderedTarget3, contains(localPos)).WillOnce(Return(true));
325328
EXPECT_CALL(renderedTarget1, mouseReleaseEvent(_)).WillOnce(WithArgs<0>(Invoke(checkReleaseEvent)));
329+
EXPECT_CALL(renderedTarget3, mouseReleaseEvent(_)).WillOnce(WithArgs<0>(Invoke(checkReleaseEvent)));
326330
ASSERT_TRUE(handler.eventFilter(nullptr, &releaseEvent));
327331
ASSERT_EQ(pressedSpy.count(), 0);
328332
ASSERT_EQ(releasedSpy.count(), 1);
@@ -351,6 +355,9 @@ TEST(MouseEventHandlerTest, MousePressReleaseEvent)
351355
releasedSpy.clear();
352356

353357
// Send release (should be sent to stage)
358+
EXPECT_CALL(renderedTarget3, contains(localPos)).WillOnce(Return(false));
359+
EXPECT_CALL(renderedTarget1, contains(localPos)).WillOnce(Return(false));
360+
EXPECT_CALL(renderedTarget2, contains(localPos)).WillOnce(Return(false));
354361
EXPECT_CALL(stage, mouseReleaseEvent(_)).WillOnce(WithArgs<0>(Invoke(checkReleaseEvent)));
355362
ASSERT_TRUE(handler.eventFilter(nullptr, &releaseEvent));
356363
ASSERT_EQ(pressedSpy.count(), 0);

test/renderedtarget/renderedtarget_test.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,11 +576,13 @@ TEST_F(RenderedTargetTest, SpriteDragging)
576576
QMouseEvent moveEventRightButton(QEvent::MouseMove, QPointF(), QPointF(), Qt::RightButton, Qt::RightButton, Qt::NoModifier);
577577
QMouseEvent pressEventRightButton(QEvent::MouseButtonPress, QPointF(), QPointF(), Qt::RightButton, Qt::RightButton, Qt::NoModifier);
578578
QMouseEvent releaseEventRightButton(QEvent::MouseButtonRelease, QPointF(), QPointF(), Qt::RightButton, Qt::RightButton, Qt::NoModifier);
579+
EXPECT_CALL(engine, clickTarget(&sprite));
579580
QCoreApplication::sendEvent(&target, &pressEventRightButton);
580581
QCoreApplication::sendEvent(&target, &moveEventRightButton);
581582
ASSERT_EQ(sprite.x(), 64.08);
582583
ASSERT_EQ(sprite.y(), -6.86);
583584
ASSERT_EQ(mouseArea.draggedSprite(), nullptr);
585+
EXPECT_CALL(engine, clickTarget).Times(0);
584586
QCoreApplication::sendEvent(&target, &releaseEventRightButton);
585587
ASSERT_EQ(mouseArea.draggedSprite(), nullptr);
586588

@@ -591,11 +593,13 @@ TEST_F(RenderedTargetTest, SpriteDragging)
591593

592594
// Try right mouse button with "draggable" set to true (should not work)
593595
sprite.setDraggable(true);
596+
EXPECT_CALL(engine, clickTarget).Times(0);
594597
QCoreApplication::sendEvent(&target, &pressEventRightButton);
595598
QCoreApplication::sendEvent(&target, &moveEventRightButton);
596599
ASSERT_EQ(sprite.x(), 64.08);
597600
ASSERT_EQ(sprite.y(), -6.86);
598601
ASSERT_EQ(mouseArea.draggedSprite(), nullptr);
602+
EXPECT_CALL(engine, clickTarget(&sprite));
599603
QCoreApplication::sendEvent(&target, &releaseEventRightButton);
600604
ASSERT_EQ(mouseArea.draggedSprite(), nullptr);
601605

@@ -609,6 +613,7 @@ TEST_F(RenderedTargetTest, SpriteDragging)
609613
QMouseEvent moveEvent(QEvent::MouseMove, QPointF(), QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
610614
QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(), QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
611615
QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(), QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
616+
EXPECT_CALL(engine, clickTarget(&sprite));
612617
QCoreApplication::sendEvent(&target, &pressEvent);
613618
QCoreApplication::sendEvent(&target, &moveEvent);
614619
ASSERT_EQ(sprite.x(), 64.08);
@@ -619,10 +624,12 @@ TEST_F(RenderedTargetTest, SpriteDragging)
619624
ASSERT_EQ(sprite.x(), 64.08);
620625
ASSERT_EQ(sprite.y(), -6.86);
621626
ASSERT_EQ(mouseArea.draggedSprite(), nullptr);
627+
EXPECT_CALL(engine, clickTarget).Times(0);
622628
QCoreApplication::sendEvent(&target, &releaseEvent);
623629

624630
// Try left mouse button with "draggable" set to true
625631
sprite.setDraggable(true);
632+
EXPECT_CALL(engine, clickTarget).Times(0);
626633
QCoreApplication::sendEvent(&target, &pressEvent);
627634
EXPECT_CALL(engine, mouseX()).WillOnce(Return(67.95));
628635
EXPECT_CALL(engine, mouseY()).WillOnce(Return(2.1));
@@ -663,12 +670,15 @@ TEST_F(RenderedTargetTest, SpriteDragging)
663670

664671
// Try to drag the second sprite while the first is being dragged
665672
sprite.setDraggable(true);
673+
EXPECT_CALL(engine, clickTarget).Times(0);
666674
QCoreApplication::sendEvent(&anotherTarget, &pressEvent);
667675
QCoreApplication::sendEvent(&anotherTarget, &moveEvent);
668676
ASSERT_EQ(mouseArea.draggedSprite(), &target);
677+
EXPECT_CALL(engine, clickTarget(&sprite));
669678
QCoreApplication::sendEvent(&anotherTarget, &releaseEvent);
670679

671680
// Stop dragging
681+
EXPECT_CALL(engine, clickTarget).Times(0);
672682
QCoreApplication::sendEvent(&target, &releaseEvent);
673683
ASSERT_EQ(std::round(sprite.x() * 100) / 100, 68.26);
674684
ASSERT_EQ(std::round(sprite.y() * 100) / 100, -1.95);

0 commit comments

Comments
 (0)