#include #include /** * Custom recognizer that triggers on touch begin and updates * */ class TestRecognizer : public QGestureRecognizer { public: TestRecognizer() {}; QGesture *create(QObject *target); QGestureRecognizer::Result recognize(QGesture *state, QObject *, QEvent *event); }; static Qt::GestureType customId = Qt::CustomGesture; QGesture *TestRecognizer::create(QObject *target) { if (target && target->isWidgetType()) { static_cast(target)->setAttribute(Qt::WA_AcceptTouchEvents); } return new QGesture; } QGestureRecognizer::Result TestRecognizer::recognize(QGesture *q, QObject *, QEvent *event) { const QTouchEvent *ev = static_cast(event); QGestureRecognizer::Result result; switch (event->type()) { case QEvent::TouchBegin: case QEvent::TouchUpdate: { q->setHotSpot(ev->touchPoints().first().screenPos()); result = QGestureRecognizer::TriggerGesture; break; } case QEvent::TouchEnd: { q->setHotSpot(ev->touchPoints().first().screenPos()); if (q->state() != Qt::NoGesture) { result = QGestureRecognizer::FinishGesture; } else { result = QGestureRecognizer::CancelGesture; } break; } default: result = QGestureRecognizer::Ignore; break; } qDebug() << "TEST TestRecognizer::recognize" << event->type() << result; return result; } /** * A test graphics object, will accept gesture if * Thing.acceptNextEvent == true, ignore if false */ class Thing : public QGraphicsObject { Q_OBJECT public: explicit Thing(QGraphicsItem *parent = 0) : QGraphicsObject(parent), acceptNextEvent(true), lastGestureState(Qt::NoGesture), count(0) {} virtual QRectF boundingRect() const { return QRectF(0,0,3,3); } virtual void paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) { p->setPen(Qt::NoPen); p->setBrush(QBrush(Qt::red)); p->drawRect(0,0,3,3); } virtual bool event(QEvent *event) { QGestureEvent *gestureEvent = static_cast(event); if(event->type() == QEvent::GestureOverride) { qDebug() << "TEST" << this << "received override" << gestureEvent; } else if(event->type() == QEvent::Gesture) { lastGestureState = gestureEvent->gesture(customId)->state(); ++count; qDebug() << "TEST" << this << "received gesture" << gestureEvent->gesture(customId) << lastGestureState; if(acceptNextEvent) { gestureEvent->accept(); gestureEvent->accept(customId); } else { gestureEvent->ignore(); gestureEvent->ignore(customId); } return true; } else if(event->type() == QEvent::TouchBegin) { qDebug() << "TEST" << this << "touchbegin"; event->accept(); return true; } return QGraphicsObject::event(event); } bool acceptNextEvent; Qt::GestureState lastGestureState; int count; }; class GestureTest : public QObject { Q_OBJECT public: GestureTest() {} private slots: void initTestCase(); void testReceivePartialGestures(); public: QMainWindow *w; QGraphicsView *v; QGraphicsScene *s; QList things; }; void GestureTest::testReceivePartialGestures() { bool VerifyCounts(false); Thing *top = things.first(); Thing *second = things.at(1); Thing *bottom = things.last(); QVERIFY( top->zValue() > second->zValue()); QVERIFY(second->zValue() > bottom->zValue()); QPoint pos = v->mapFromScene(top->boundingRect().center() + top->pos()); QVERIFY(!VerifyCounts || (top->count == 0 && second->count == 0 && bottom->count == 0)); QCOMPARE(top->lastGestureState, Qt::NoGesture); QCOMPARE(second->lastGestureState, Qt::NoGesture); QCOMPARE(bottom->lastGestureState, Qt::NoGesture); // things accept events by default QTest::touchEvent(v->viewport()).press(0, pos); // gesture started qDebug() << top->count; QVERIFY(!VerifyCounts || (top->count == 1 && second->count == 0 && bottom->count == 0)); QCOMPARE(top->lastGestureState, Qt::GestureStarted); QCOMPARE(second->lastGestureState, Qt::NoGesture); QCOMPARE(bottom->lastGestureState, Qt::NoGesture); top->acceptNextEvent = false; QVERIFY(second->acceptNextEvent == true); QTest::touchEvent(v->viewport()).move(0, pos); // second should receive the partial gesture QVERIFY(!VerifyCounts || (top->count == 2 && second->count == 1 && bottom->count == 0)); QCOMPARE(top->lastGestureState, Qt::GestureUpdated); QCOMPARE(second->lastGestureState, Qt::GestureUpdated); // the one on the bottom should not receive the gesture QCOMPARE(bottom->lastGestureState, Qt::NoGesture); } void GestureTest::initTestCase() { w = new QMainWindow; v = new QGraphicsView; s = new QGraphicsScene; s->setSceneRect(0,0,100,100); QGestureRecognizer::unregisterRecognizer(Qt::PanGesture); QGestureRecognizer::unregisterRecognizer(Qt::TapGesture); customId = QGestureRecognizer::registerRecognizer(new TestRecognizer); for(int i=4; i>0; --i) { Thing *thing = new Thing; thing->setZValue(i); thing->setAcceptTouchEvents(true); thing->grabGesture(customId, Qt::ReceivePartialGestures); s->addItem(thing); things.append(thing); } v->setScene(s); v->viewport()->grabGesture(customId); v->viewport()->setAttribute(Qt::WA_AcceptTouchEvents); w->setCentralWidget(v); w->setWindowFlags(Qt::X11BypassWindowManagerHint); w->show(); QTest::qWaitForWindowShown(w); } QTEST_MAIN(GestureTest) #include "main.moc"