aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp')
-rw-r--r--tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp437
1 files changed, 437 insertions, 0 deletions
diff --git a/tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp b/tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp
new file mode 100644
index 0000000000..68552bf88a
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QDebug>
+#include <QTouchEvent>
+
+#include "qsgitem.h"
+#include "qsgcanvas.h"
+#include "private/qsgrectangle_p.h"
+#include "../../../shared/util.h"
+
+struct TouchEventData {
+ QEvent::Type type;
+ QWidget *widget;
+ Qt::TouchPointStates states;
+ QList<QTouchEvent::TouchPoint> touchPoints;
+};
+
+static QTouchEvent::TouchPoint makeTouchPoint(QSGItem *item, const QPointF &p, const QPointF &lastPoint = QPointF())
+{
+ QPointF last = lastPoint.isNull() ? p : lastPoint;
+
+ QTouchEvent::TouchPoint tp;
+ tp.setPos(p);
+ tp.setLastPos(last);
+ tp.setScenePos(item->mapToScene(p));
+ tp.setLastScenePos(item->mapToScene(last));
+ tp.setScreenPos(item->canvas()->mapToGlobal(tp.scenePos().toPoint()));
+ tp.setLastScreenPos(item->canvas()->mapToGlobal(tp.lastScenePos().toPoint()));
+ return tp;
+}
+
+static TouchEventData makeTouchData(QEvent::Type type, QWidget *w, Qt::TouchPointStates states, const QList<QTouchEvent::TouchPoint> &touchPoints)
+{
+ TouchEventData d = { type, w, states, touchPoints };
+ return d;
+}
+
+static TouchEventData makeTouchData(QEvent::Type type, QWidget *w, Qt::TouchPointStates states, const QTouchEvent::TouchPoint &touchPoint)
+{
+ QList<QTouchEvent::TouchPoint> points;
+ points << touchPoint;
+ return makeTouchData(type, w, states, points);
+}
+
+#define COMPARE_TOUCH_POINTS(tp1, tp2) \
+{ \
+ QCOMPARE(tp1.pos(), tp2.pos()); \
+ QCOMPARE(tp1.lastPos(), tp2.lastPos()); \
+ QCOMPARE(tp1.scenePos(), tp2.scenePos()); \
+ QCOMPARE(tp1.lastScenePos(), tp2.lastScenePos()); \
+ QCOMPARE(tp1.screenPos(), tp2.screenPos()); \
+ QCOMPARE(tp1.lastScreenPos(), tp2.lastScreenPos()); \
+}
+
+#define COMPARE_TOUCH_DATA(d1, d2) \
+{ \
+ QCOMPARE((int)d1.type, (int)d2.type); \
+ QCOMPARE(d1.widget, d2.widget); \
+ QCOMPARE((int)d1.states, (int)d2.states); \
+ QCOMPARE(d1.touchPoints.count(), d2.touchPoints.count()); \
+ for (int i=0; i<d1.touchPoints.count(); i++) { \
+ COMPARE_TOUCH_POINTS(d1.touchPoints[i], d2.touchPoints[i]); \
+ } \
+}
+
+class TestTouchItem : public QSGRectangle
+{
+ Q_OBJECT
+public:
+ TestTouchItem(QSGItem *parent = 0)
+ : QSGRectangle(parent), acceptEvents(true)
+ {
+ border()->setWidth(1);
+ }
+
+ void reset() {
+ acceptEvents = true;
+ setEnabled(true);
+ setOpacity(1.0);
+
+ lastEvent = makeTouchData(QEvent::None, 0, 0, QList<QTouchEvent::TouchPoint>());
+ }
+
+ bool acceptEvents;
+ TouchEventData lastEvent;
+
+protected:
+ virtual void touchEvent(QTouchEvent *event) {
+ if (!acceptEvents) {
+ event->ignore();
+ return;
+ }
+ lastEvent = makeTouchData(event->type(), event->widget(), event->touchPointStates(), event->touchPoints());
+ event->accept();
+ }
+};
+
+
+class ConstantUpdateItem : public QSGItem
+{
+Q_OBJECT
+public:
+ ConstantUpdateItem(QSGItem *parent = 0) : QSGItem(parent), iterations(0) {setFlag(ItemHasContents);}
+
+ int iterations;
+protected:
+ QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *){
+ iterations++;
+ update();
+ return 0;
+ }
+};
+
+class tst_qsgcanvas : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsgcanvas();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void constantUpdates();
+
+ void touchEvent_basic();
+ void touchEvent_propagation();
+ void touchEvent_propagation_data();
+
+ void clearCanvas();
+};
+
+tst_qsgcanvas::tst_qsgcanvas()
+{
+}
+
+void tst_qsgcanvas::initTestCase()
+{
+}
+
+void tst_qsgcanvas::cleanupTestCase()
+{
+}
+
+//If the item calls update inside updatePaintNode, it should schedule another update
+void tst_qsgcanvas::constantUpdates()
+{
+ QSGCanvas canvas;
+ ConstantUpdateItem item(canvas.rootItem());
+ canvas.show();
+ QTRY_VERIFY(item.iterations > 60);
+}
+
+void tst_qsgcanvas::touchEvent_basic()
+{
+ QSGCanvas *canvas = new QSGCanvas;
+ canvas->resize(250, 250);
+ canvas->window()->move(100, 100);
+ canvas->show();
+
+ TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
+ bottomItem->setObjectName("Bottom Item");
+ bottomItem->setSize(QSizeF(150, 150));
+
+ TestTouchItem *middleItem = new TestTouchItem(bottomItem);
+ middleItem->setObjectName("Middle Item");
+ middleItem->setPos(QPointF(50, 50));
+ middleItem->setSize(QSizeF(150, 150));
+
+ TestTouchItem *topItem = new TestTouchItem(middleItem);
+ topItem->setObjectName("Top Item");
+ topItem->setPos(QPointF(50, 50));
+ topItem->setSize(QSizeF(150, 150));
+
+ QPointF pos(10, 10);
+
+ // press single point
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
+ topItem->reset();
+
+ // press multiple points
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint())
+ .press(1, bottomItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
+ topItem->reset();
+ bottomItem->reset();
+
+ // touch point on top item moves to bottom item, but top item should still receive the event
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).move(0, bottomItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
+ makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
+ topItem->reset();
+
+ // touch point on bottom item moves to top item, but bottom item should still receive the event
+ QTest::touchEvent(canvas).press(0, bottomItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).move(0, topItem->mapToScene(pos).toPoint());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
+ makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos)));
+ bottomItem->reset();
+
+ // a single stationary press on an item shouldn't cause an event
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).stationary(0)
+ .press(1, bottomItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); // received press only, not stationary
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
+ topItem->reset();
+ bottomItem->reset();
+
+ // move touch point from top item to bottom, and release
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).release(0, bottomItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
+ makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
+ topItem->reset();
+
+ // release while another point is pressed
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint())
+ .press(1, bottomItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).move(0, bottomItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).release(0, bottomItem->mapToScene(pos).toPoint())
+ .stationary(1);
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
+ makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos))));
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
+ topItem->reset();
+ bottomItem->reset();
+
+ delete topItem;
+ delete middleItem;
+ delete bottomItem;
+ delete canvas;
+}
+
+void tst_qsgcanvas::touchEvent_propagation()
+{
+ QFETCH(bool, acceptEvents);
+ QFETCH(bool, enableItem);
+ QFETCH(qreal, itemOpacity);
+
+ QSGCanvas *canvas = new QSGCanvas;
+ canvas->resize(250, 250);
+ canvas->window()->move(100, 100);
+ canvas->show();
+
+ TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
+ bottomItem->setObjectName("Bottom Item");
+ bottomItem->setSize(QSizeF(150, 150));
+
+ TestTouchItem *middleItem = new TestTouchItem(bottomItem);
+ middleItem->setObjectName("Middle Item");
+ middleItem->setPos(QPointF(50, 50));
+ middleItem->setSize(QSizeF(150, 150));
+
+ TestTouchItem *topItem = new TestTouchItem(middleItem);
+ topItem->setObjectName("Top Item");
+ topItem->setPos(QPointF(50, 50));
+ topItem->setSize(QSizeF(150, 150));
+
+ QPointF pos(10, 10);
+ QPoint pointInBottomItem = bottomItem->mapToScene(pos).toPoint(); // (10, 10)
+ QPoint pointInMiddleItem = middleItem->mapToScene(pos).toPoint(); // (60, 60) overlaps with bottomItem
+ QPoint pointInTopItem = topItem->mapToScene(pos).toPoint(); // (110, 110) overlaps with bottom & top items
+
+ // disable topItem
+ topItem->acceptEvents = acceptEvents;
+ topItem->setEnabled(enableItem);
+ topItem->setOpacity(itemOpacity);
+
+ // single touch to top item, should be received by middle item
+ QTest::touchEvent(canvas).press(0, pointInTopItem);
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(middleItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+ COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))));
+
+ // touch top and middle items, middle item should get both events
+ QTest::touchEvent(canvas).press(0, pointInTopItem)
+ .press(1, pointInMiddleItem);
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(middleItem->lastEvent.touchPoints.count(), 2);
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+ COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))
+ << makeTouchPoint(middleItem, pos) )));
+ middleItem->reset();
+
+ // disable middleItem as well
+ middleItem->acceptEvents = acceptEvents;
+ middleItem->setEnabled(enableItem);
+ middleItem->setOpacity(itemOpacity);
+
+ // touch top and middle items, bottom item should get all events
+ QTest::touchEvent(canvas).press(0, pointInTopItem)
+ .press(1, pointInMiddleItem);
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 2);
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))
+ << makeTouchPoint(bottomItem, bottomItem->mapFromItem(middleItem, pos)) )));
+ bottomItem->reset();
+
+ // disable bottom item as well
+ bottomItem->acceptEvents = acceptEvents;
+ bottomItem->setEnabled(enableItem);
+ bottomItem->setOpacity(itemOpacity);
+
+ // no events should be received
+ QTest::touchEvent(canvas).press(0, pointInTopItem)
+ .press(1, pointInMiddleItem)
+ .press(2, pointInBottomItem);
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+
+ topItem->reset();
+ middleItem->reset();
+ bottomItem->reset();
+
+ // disable middle item, touch on top item
+ middleItem->acceptEvents = acceptEvents;
+ middleItem->setEnabled(enableItem);
+ middleItem->setOpacity(itemOpacity);
+ QTest::touchEvent(canvas).press(0, pointInTopItem);
+ if (!enableItem || itemOpacity == 0) {
+ // middle item is disabled or has 0 opacity, bottom item receives the event
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))));
+ } else {
+ // middle item ignores event, sends it to the top item (top-most child)
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ makeTouchPoint(topItem, pos)));
+ }
+
+ delete topItem;
+ delete middleItem;
+ delete bottomItem;
+ delete canvas;
+}
+
+void tst_qsgcanvas::touchEvent_propagation_data()
+{
+ QTest::addColumn<bool>("acceptEvents");
+ QTest::addColumn<bool>("enableItem");
+ QTest::addColumn<qreal>("itemOpacity");
+
+ QTest::newRow("disable events") << false << true << 1.0;
+ QTest::newRow("disable item") << true << false << 1.0;
+ QTest::newRow("opacity of 0") << true << true << 0.0;
+}
+
+void tst_qsgcanvas::clearCanvas()
+{
+ QSGCanvas *canvas = new QSGCanvas;
+ QSGItem *item = new QSGItem;
+ item->setParentItem(canvas->rootItem());
+
+ QVERIFY(item->canvas() == canvas);
+
+ delete canvas;
+
+ QVERIFY(item->canvas() == 0);
+
+ delete item;
+}
+
+
+
+QTEST_MAIN(tst_qsgcanvas)
+
+#include "tst_qsgcanvas.moc"