From 9745006dadf5685f4ff82c6234938e19b9402801 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 30 Nov 2018 10:37:29 +0100 Subject: Reset last selected picker when releasing out of viewport Change-Id: Iec70e84024caf879358183fee34638def5038aef Task-number: QTBUG-72160 Reviewed-by: Mike Krus --- src/render/jobs/pickboundingvolumejob.cpp | 8 +- .../tst_pickboundingvolumejob.cpp | 88 ++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp index 2f1eb4cd8..2050b8772 100644 --- a/src/render/jobs/pickboundingvolumejob.cpp +++ b/src/render/jobs/pickboundingvolumejob.cpp @@ -232,8 +232,14 @@ bool PickBoundingVolumeJob::runHelper() for (const PickingUtils::ViewportCameraAreaDetails &vca : vcaDetails) { PickingUtils::HitList sphereHits; QRay3D ray = rayForViewportAndCamera(vca, event.first, event.second.pos()); - if (!ray.isValid()) + if (!ray.isValid()) { + // An invalid rays is when we've lost our surface or the mouse + // has moved out of the viewport In case of a button released + // outside of the viewport, we still want to notify the + // lastCurrent entity about this. + dispatchPickEvents(event.second, PickingUtils::HitList(), eventButton, eventButtons, eventModifiers, allHitsRequested); continue; + } PickingUtils::HierarchicalEntityPicker entityPicker(ray); if (entityPicker.collectHits(m_manager, m_node)) { diff --git a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp index b86df05a4..60b60eb6e 100644 --- a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp +++ b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp @@ -861,6 +861,94 @@ private Q_SLOTS: arbiter.events.clear(); } + void checkDispatchReleaseEventOnLastPickerWhenMovingOutOfViewport() + { + // GIVEN + QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml")); + QScopedPointer root(qobject_cast(sceneReader.root())); + QVERIFY(root); + + QList renderSettings = root->findChildren(); + QCOMPARE(renderSettings.size(), 1); + Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings(); + + settings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking); + settings->setPickResultMode(Qt3DRender::QPickingSettings::NearestPick); + settings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontAndBackFace); + + QScopedPointer test(new Qt3DRender::TestAspect(root.data())); + TestArbiter arbiter; + + // Runs Required jobs + runRequiredJobs(test.data()); + + // THEN + QList pickers = root->findChildren(); + QCOMPARE(pickers.size(), 2); + + Qt3DRender::QObjectPicker *picker1 = nullptr; + if (pickers.first()->objectName() == QLatin1String("Picker1")) + picker1 = pickers.first(); + else + picker1 = pickers.last(); + + Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(picker1->id()); + QVERIFY(backendPicker1); + Qt3DCore::QBackendNodePrivate::get(backendPicker1)->setArbiter(&arbiter); + + // WHEN -> Pressed on object + Qt3DRender::Render::PickBoundingVolumeJob pickBVJob; + initializePickBoundingVolumeJob(&pickBVJob, test.data()); + + QList> events; + events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), + Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)}); + pickBVJob.setMouseEvents(events); + bool earlyReturn = !pickBVJob.runHelper(); + + // THEN -> Pressed + QVERIFY(!earlyReturn); + QVERIFY(backendPicker1->isPressed()); + QCOMPARE(arbiter.events.count(), 1); + Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "pressed"); + Qt3DRender::QPickEventPtr pickEvent = change->value().value(); + QVERIFY(pickEvent); + QVERIFY(!Qt3DRender::QPickEventPrivate::get(pickEvent.data())->m_entity.isNull()); + QVERIFY(pickEvent.dynamicCast()); + + arbiter.events.clear(); + + // WHEN -> Releasing out of the viewport + events.clear(); + events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(10000.0f, 10000.0f), + Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)}); + pickBVJob.setMouseEvents(events); + earlyReturn = !pickBVJob.runHelper(); + + // THEN -> Should have received released event + QVERIFY(!earlyReturn); + QVERIFY(!backendPicker1->isPressed()); + QCOMPARE(arbiter.events.count(), 1); + change = arbiter.events.first().staticCast(); + QCOMPARE(change->propertyName(), "released"); + pickEvent = change->value().value(); + QVERIFY(pickEvent); + QVERIFY(Qt3DRender::QPickEventPrivate::get(pickEvent.data())->m_entity.isNull()); + + arbiter.events.clear(); + + // WHEN -> Releasing out of the viewport + events.clear(); + events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(10000.0f, 10000.0f), + Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)}); + pickBVJob.setMouseEvents(events); + earlyReturn = !pickBVJob.runHelper(); + + // THEN -> Should have received nothing + QCOMPARE(arbiter.events.count(), 0); + } + void checkDispatchHoverEvent_data() { generateAllPickingSettingsCombinations(); -- cgit v1.2.3