From ed3ed0b9db97a8fab0c03add23228b6b0a96f171 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 12 Feb 2018 16:26:38 +0100 Subject: Fix touch point positions of non-transformable QGraphicsItems TouchEvent::TouchPoint::pos was not updated in QGraphicsScenePrivate::updateTouchPointsForItem(). To prevent the transformation being calculated repeatedly for each touch point member, extract a function genericMapFromSceneTransform() from genericMapFromScene() returning the transformation and use that whereever multiple points are transformed. Add a test, extracting helper functionality from tst_QGraphicsItem::touchEventPropagation(). In addition, fold tst_QGraphicsScene::checkTouchPointsEllipseDiameters() from c48f4bde0044bd5b23af231f3639d0779ecbdb03 into this test, so that it is testing all transformations. Task-number: QTBUG-66192 Change-Id: If71886d2c14c4e216f7781ea2f22f1adc444e6cf Reviewed-by: Andy Shaw Reviewed-by: Richard Moe Gustavsen --- .../qgraphicsitem/tst_qgraphicsitem.cpp | 225 +++++++++++++++++---- .../qgraphicsscene/tst_qgraphicsscene.cpp | 76 ------- 2 files changed, 190 insertions(+), 111 deletions(-) (limited to 'tests') diff --git a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp index 26831002ce..4f4a11a79c 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -54,10 +55,13 @@ #include #include #include +#include #include #include Q_DECLARE_METATYPE(QPainterPath) +Q_DECLARE_METATYPE(QSizeF) +Q_DECLARE_METATYPE(QTransform) #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) #include @@ -435,6 +439,8 @@ private slots: void focusHandling(); void touchEventPropagation_data(); void touchEventPropagation(); + void touchEventTransformation_data(); + void touchEventTransformation(); void deviceCoordinateCache_simpleRotations(); void resolvePaletteForItemChildren(); @@ -465,6 +471,7 @@ private slots: private: QList paintedItems; + QTouchDevice *m_touchDevice = nullptr; }; void tst_QGraphicsItem::construction() @@ -10945,6 +10952,95 @@ void tst_QGraphicsItem::focusHandling() QCOMPARE(scene.focusItem(), focusableUnder); } +class TouchEventTestee : public QGraphicsRectItem +{ +public: + TouchEventTestee(const QSizeF &size = QSizeF(100, 100)) : + QGraphicsRectItem(QRectF(QPointF(), size)) + { + setAcceptTouchEvents(true); + setFlag(QGraphicsItem::ItemIsFocusable, false); + } + + QList touchBeginPoints() const { return m_touchBeginPoints; } + int touchBeginEventCount() const { return m_touchBeginPoints.size(); } + + QList touchUpdatePoints() const { return m_touchUpdatePoints; } + int touchUpdateEventCount() const { return m_touchUpdatePoints.size(); } + +protected: + bool sceneEvent(QEvent *ev) override + { + switch (ev->type()) { + case QEvent::TouchBegin: + m_touchBeginPoints.append(static_cast(ev)->touchPoints().constFirst()); + ev->accept(); + return true; + case QEvent::TouchUpdate: + m_touchUpdatePoints.append(static_cast(ev)->touchPoints().constFirst()); + ev->accept(); + return true; + default: + break; + } + + return QGraphicsRectItem::sceneEvent(ev); + } + +private: + QList m_touchBeginPoints; + QList m_touchUpdatePoints; +}; + +static QList + createTouchPoints(const QGraphicsView &view, + const QPointF &scenePos, + const QSizeF &ellipseDiameters, + Qt::TouchPointState state = Qt::TouchPointPressed) +{ + QTouchEvent::TouchPoint tp(0); + tp.setState(state); + tp.setScenePos(scenePos); + tp.setStartScenePos(scenePos); + tp.setLastScenePos(scenePos); + const QPointF screenPos = view.viewport()->mapToGlobal(view.mapFromScene(scenePos)); + tp.setScreenPos(screenPos); + tp.setStartScreenPos(screenPos); + tp.setLastScreenPos(screenPos); + tp.setEllipseDiameters(ellipseDiameters); + const QSizeF screenSize = QApplication::desktop()->screenGeometry(&view).size(); + tp.setNormalizedPos(QPointF(screenPos.x() / screenSize.width(), screenPos.y() / screenSize.height())); + return QList() << tp; +} + +static bool comparePointF(const QPointF &p1, const QPointF &p2) +{ + return qFuzzyCompare(p1.x(), p2.x()) && qFuzzyCompare(p1.y(), p2.y()); +} + +static bool compareSizeF(const QSizeF &s1, const QSizeF &s2) +{ + return qFuzzyCompare(s1.width(), s2.width()) && qFuzzyCompare(s1.height(), s2.height()); +} + +static QByteArray msgPointFComparisonFailed(const QPointF &p1, const QPointF &p2) +{ + return QByteArray::number(p1.x()) + ", " + QByteArray::number(p1.y()) + + " != " + QByteArray::number(p2.x()) + ", " + QByteArray::number(p2.y()); +} + +static QByteArray msgSizeFComparisonFailed(const QSizeF &s1, const QSizeF &s2) +{ + return QByteArray::number(s1.width()) + 'x' + QByteArray::number(s1.height()) + + " != " + QByteArray::number(s2.width()) + 'x' + QByteArray::number(s2.height()); +} + +#define COMPARE_POINTF(ACTUAL, EXPECTED) \ + QVERIFY2(comparePointF(ACTUAL, EXPECTED), msgPointFComparisonFailed(ACTUAL, EXPECTED).constData()) + +#define COMPARE_SIZEF(ACTUAL, EXPECTED) \ + QVERIFY2(compareSizeF(ACTUAL, EXPECTED), msgSizeFComparisonFailed(ACTUAL, EXPECTED).constData()) + void tst_QGraphicsItem::touchEventPropagation_data() { QTest::addColumn("flag"); @@ -10963,29 +11059,7 @@ void tst_QGraphicsItem::touchEventPropagation() QFETCH(QGraphicsItem::GraphicsItemFlag, flag); QFETCH(int, expectedCount); - class Testee : public QGraphicsRectItem - { - public: - int touchBeginEventCount; - - Testee() - : QGraphicsRectItem(0, 0, 100, 100) - , touchBeginEventCount(0) - { - setAcceptTouchEvents(true); - setFlag(QGraphicsItem::ItemIsFocusable, false); - } - - bool sceneEvent(QEvent *ev) - { - if (ev->type() == QEvent::TouchBegin) - ++touchBeginEventCount; - - return QGraphicsRectItem::sceneEvent(ev); - } - }; - - Testee *touchEventReceiver = new Testee; + TouchEventTestee *touchEventReceiver = new TouchEventTestee; QGraphicsItem *topMost = new QGraphicsRectItem(touchEventReceiver->boundingRect()); QGraphicsScene scene; @@ -10998,26 +11072,107 @@ void tst_QGraphicsItem::touchEventPropagation() topMost->setFlag(flag, true); QGraphicsView view(&scene); + view.setWindowTitle(QLatin1String(QTest::currentTestFunction()) + QLatin1String("::") + + QLatin1String(QTest::currentDataTag())); view.setSceneRect(touchEventReceiver->boundingRect()); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - QCOMPARE(touchEventReceiver->touchBeginEventCount, 0); + QCOMPARE(touchEventReceiver->touchBeginEventCount(), 0); - QTouchEvent::TouchPoint tp(0); - tp.setState(Qt::TouchPointPressed); - tp.setScenePos(view.sceneRect().center()); - tp.setLastScenePos(view.sceneRect().center()); + const QPointF scenePos = view.sceneRect().center(); + sendMousePress(&scene, scenePos); + if (m_touchDevice == nullptr) + m_touchDevice = QTest::createTouchDevice(); + QTouchEvent touchBegin(QEvent::TouchBegin, m_touchDevice, Qt::NoModifier, Qt::TouchPointPressed, + createTouchPoints(view, scenePos, QSizeF(10, 10))); + touchBegin.setTarget(view.viewport()); - QList touchPoints; - touchPoints << tp; + qApp->sendEvent(&scene, &touchBegin); + QCOMPARE(touchEventReceiver->touchBeginEventCount(), expectedCount); +} - sendMousePress(&scene, tp.scenePos()); - QTouchDevice *device = QTest::createTouchDevice(); - QTouchEvent touchBegin(QEvent::TouchBegin, device, Qt::NoModifier, Qt::TouchPointPressed, touchPoints); +void tst_QGraphicsItem::touchEventTransformation_data() +{ + QTest::addColumn("flag"); + QTest::addColumn("viewTransform"); + QTest::addColumn("touchScenePos"); + QTest::addColumn("ellipseDiameters"); + QTest::addColumn("expectedItemPos"); + + QTest::newRow("notransform") + << QGraphicsItem::ItemIsSelectable << QTransform() + << QPointF(150, 150) << QSizeF(7, 8) << QPointF(50, 50); + QTest::newRow("scaled") + << QGraphicsItem::ItemIsSelectable << QTransform::fromScale(0.5, 0.5) + << QPointF(150, 150) << QSizeF(7, 8) << QPointF(50, 50); + // QTBUG-66192: When the item ignores the downscaling transformation, + // it will receive the touch point at 25,25 instead of 50,50. + QTest::newRow("scaled/ItemIgnoresTransformations") + << QGraphicsItem::ItemIgnoresTransformations << QTransform::fromScale(0.5, 0.5) + << QPointF(150, 150) << QSizeF(7, 8) << QPointF(25, 25); +} + +void tst_QGraphicsItem::touchEventTransformation() +{ + QFETCH(QGraphicsItem::GraphicsItemFlag, flag); + QFETCH(QTransform, viewTransform); + QFETCH(QPointF, touchScenePos); + QFETCH(QSizeF, ellipseDiameters); + QFETCH(QPointF, expectedItemPos); + + TouchEventTestee *touchEventReceiver = new TouchEventTestee; + + QGraphicsScene scene; + scene.addItem(touchEventReceiver); + const QPointF itemPos(100, 100); + + touchEventReceiver->setPos(itemPos); + + touchEventReceiver->setFlag(flag, true); + + QGraphicsView view(&scene); + view.setWindowTitle(QLatin1String(QTest::currentTestFunction()) + QLatin1String("::") + + QLatin1String(QTest::currentDataTag())); + view.setSceneRect(QRectF(QPointF(0, 0), QSizeF(300, 300))); + view.setTransform(viewTransform); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QCOMPARE(touchEventReceiver->touchBeginEventCount(), 0); + + if (m_touchDevice == nullptr) + m_touchDevice = QTest::createTouchDevice(); + QTouchEvent touchBegin(QEvent::TouchBegin, m_touchDevice, Qt::NoModifier, Qt::TouchPointPressed, + createTouchPoints(view, touchScenePos, ellipseDiameters)); + touchBegin.setTarget(view.viewport()); + + QCoreApplication::sendEvent(&scene, &touchBegin); + QCOMPARE(touchEventReceiver->touchBeginEventCount(), 1); + + const QTouchEvent::TouchPoint touchBeginPoint = touchEventReceiver->touchBeginPoints().constFirst(); + + COMPARE_POINTF(touchBeginPoint.scenePos(), touchScenePos); + COMPARE_POINTF(touchBeginPoint.startScenePos(), touchScenePos); + COMPARE_POINTF(touchBeginPoint.lastScenePos(), touchScenePos); + COMPARE_POINTF(touchBeginPoint.pos(), expectedItemPos); + COMPARE_SIZEF(touchBeginPoint.ellipseDiameters(), ellipseDiameters); // Must remain untransformed + + QTouchEvent touchUpdate(QEvent::TouchUpdate, m_touchDevice, Qt::NoModifier, Qt::TouchPointMoved, + createTouchPoints(view, touchScenePos, ellipseDiameters, Qt::TouchPointMoved)); + touchUpdate.setTarget(view.viewport()); + + QCoreApplication::sendEvent(&scene, &touchUpdate); + QCOMPARE(touchEventReceiver->touchUpdateEventCount(), 1); + + const QTouchEvent::TouchPoint touchUpdatePoint = touchEventReceiver->touchUpdatePoints().constFirst(); + + COMPARE_POINTF(touchUpdatePoint.scenePos(), touchScenePos); + COMPARE_POINTF(touchBeginPoint.startScenePos(), touchScenePos); + COMPARE_POINTF(touchUpdatePoint.lastScenePos(), touchScenePos); + COMPARE_POINTF(touchUpdatePoint.pos(), expectedItemPos); + COMPARE_SIZEF(touchUpdatePoint.ellipseDiameters(), ellipseDiameters); // Must remain untransformed - qApp->sendEvent(&scene, &touchBegin); - QCOMPARE(touchEventReceiver->touchBeginEventCount, expectedCount); } void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations() diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp index fe8571abf1..3b340d06ab 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp @@ -254,7 +254,6 @@ private slots: void zeroScale(); void focusItemChangedSignal(); void minimumRenderSize(); - void checkTouchPointsEllipseDiameters(); // task specific tests below me void task139710_bspTreeCrash(); @@ -4765,81 +4764,6 @@ void tst_QGraphicsScene::minimumRenderSize() QVERIFY(smallChild->repaints > smallerGrandChild->repaints); } -class TouchItem : public QGraphicsRectItem -{ -public: - TouchItem() : QGraphicsRectItem(QRectF(-10, -10, 20, 20)), - seenTouch(false) - { - setAcceptTouchEvents(true); - setFlag(QGraphicsItem::ItemIgnoresTransformations); - } - bool seenTouch; - QList touchPoints; -protected: - bool sceneEvent(QEvent *event) override - { - switch (event->type()) { - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - seenTouch = true; - touchPoints = static_cast(event)->touchPoints(); - event->accept(); - return true; - default: - break; - } - return QGraphicsRectItem::sceneEvent(event); - } -}; - -void tst_QGraphicsScene::checkTouchPointsEllipseDiameters() -{ - QGraphicsScene scene; - QGraphicsView view(&scene); - scene.setSceneRect(1, 1, 198, 198); - view.scale(1.5, 1.5); - view.setFocus(); - TouchItem *rect = new TouchItem; - scene.addItem(rect); - view.show(); - QApplication::setActiveWindow(&view); - QVERIFY(QTest::qWaitForWindowActive(&view)); - - const QSizeF ellipseDiameters(10.0, 10.0); - QTouchEvent::TouchPoint touchPoint(0); - touchPoint.setState(Qt::TouchPointPressed); - touchPoint.setPos(view.mapFromScene(rect->mapToScene(rect->boundingRect().center()))); - touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); - touchPoint.setEllipseDiameters(ellipseDiameters); - - QList touchPoints = { touchPoint }; - - QTouchDevice *testDevice = QTest::createTouchDevice(QTouchDevice::TouchPad); - QTouchEvent touchEvent(QEvent::TouchBegin, - testDevice, - Qt::NoModifier, - Qt::TouchPointPressed, - touchPoints); - QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(rect->seenTouch); - QVERIFY(rect->touchPoints.size() == 1); - QCOMPARE(ellipseDiameters, rect->touchPoints.first().ellipseDiameters()); - - rect->seenTouch = false; - rect->touchPoints.clear(); - QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, - testDevice, - Qt::NoModifier, - Qt::TouchPointMoved, - touchPoints); - QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(rect->seenTouch); - QVERIFY(rect->touchPoints.size() == 1); - QCOMPARE(ellipseDiameters, rect->touchPoints.first().ellipseDiameters()); -} - void tst_QGraphicsScene::taskQTBUG_15977_renderWithDeviceCoordinateCache() { QGraphicsScene scene; -- cgit v1.2.3