From 27ce15ae5c7f47f6a2c456db74c41b5be6d4144f Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Tue, 20 Apr 2010 19:42:24 +0200 Subject: use touch events if possible --- testapp/qscrollareakineticscroller.cpp | 2 +- touchy/qscrollareakineticscroller.cpp | 117 ++++++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 31 deletions(-) diff --git a/testapp/qscrollareakineticscroller.cpp b/testapp/qscrollareakineticscroller.cpp index a1ed70d..0b37a16 100644 --- a/testapp/qscrollareakineticscroller.cpp +++ b/testapp/qscrollareakineticscroller.cpp @@ -94,7 +94,7 @@ public: : q_ptr(0) , area(0) , ignoreEvents(false) - {} + { } void init() { diff --git a/touchy/qscrollareakineticscroller.cpp b/touchy/qscrollareakineticscroller.cpp index 6702325..ad7a137 100644 --- a/touchy/qscrollareakineticscroller.cpp +++ b/touchy/qscrollareakineticscroller.cpp @@ -80,6 +80,7 @@ public: QAbstractScrollArea *area; QItemSelection oldSelection; // the selection before the first mouse down bool ignoreEvents; + bool isTouchEnabled; QPoint lastOvershoot; // don't change the type to QPointF or we might never shoot completely back. QPointer childWidget; // the widget where the mouse was pressed QPointF fractionalPosition; @@ -94,6 +95,7 @@ public: : q_ptr(0) , area(0) , ignoreEvents(false) + , isTouchEnabled(false) {} void init() @@ -164,6 +166,7 @@ void QScrollAreaKineticScroller::setWidget(QAbstractScrollArea *widget) view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); } + d->isTouchEnabled = d->area->viewport()->testAttribute(Qt::WA_AcceptTouchEvents); } } @@ -177,35 +180,87 @@ bool QScrollAreaKineticScroller::eventFilter(QObject *o, QEvent *e) bool isMouseDown = false; if (d->area && (o == d->area->viewport()) && - !d->ignoreEvents && d->area->isEnabled() && isEnabled()) { + !d->ignoreEvents && d->area->isEnabled() && isEnabled()) { switch (e->type()) { - case QEvent::TouchBegin: { - QTouchEvent *te = static_cast(e); - if (te->touchPoints().count() == 1) - res = handleInput(InputPress, te->touchPoints().at(0).pos() - d->lastOvershoot, timestamp); + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + if (d->isTouchEnabled) { + Input type = (e->type() == QEvent::TouchBegin) ? InputPress : + ((e->type() == QEvent::TouchEnd) ? InputRelease : InputMove); + QTouchEvent *te = static_cast(e); + int idx = (te->deviceType() == QTouchEvent::TouchScreen) ? 0 : 1; + + if (te->touchPoints().count() == (idx + 1)) + res = handleInput(type, te->touchPoints().at(idx).pos() - d->lastOvershoot, timestamp); + } break; - } - case QEvent::TouchUpdate: { - QTouchEvent *te = static_cast(e); - if (te->touchPoints().count() == 1) - res = handleInput(InputMove, te->touchPoints().at(0).pos() - d->lastOvershoot, timestamp); + + case QEvent::Wheel: +#ifdef Q_WS_MAC + // the two-finger gesture is mapped to wheel events by default + res = d->isTouchEnabled; +#endif break; - } - case QEvent::TouchEnd: { - QTouchEvent *te = static_cast(e); - if (te->touchPoints().count() == 1) - res = handleInput(InputRelease, te->touchPoints().at(0).pos() - d->lastOvershoot, timestamp); + + case QEvent::MouseButtonPress: + if (!d->isTouchEnabled) { + // re-install the event filter so that we get the mouse release before all other filters. + // this is an evil hack, but hard to work around without prioritized event filters. + d->area->viewport()->removeEventFilter(this); + d->area->viewport()->installEventFilter(this); + } + // fall through + + case QEvent::MouseButtonDblClick: + isMouseDown = true; + // fall through + + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + if (!d->isTouchEnabled) { + Input type = (e->type() == QEvent::MouseButtonRelease) ? InputRelease : + ((e->type() == QEvent::MouseMove) ? InputMove : InputPress); + QMouseEvent *me = static_cast(e); + isMouseEvent = true; + res = handleInput(type, me->posF() - d->lastOvershoot, timestamp); + } + break; + + case QEvent::ChildAdded: + case QEvent::ChildRemoved: { + QChildEvent *ce = static_cast(e); + if (ce->child()->isWidgetType()) { + static_cast(ce->child())->setAttribute(Qt::WA_TransparentForMouseEvents, ce->added()); + if ((e->type() == QEvent::ChildRemoved) && (ce->child() == d->childWidget)) + d->childWidget = 0; + } break; } default: break; } } - + if (res) e->accept(); res |= QObject::eventFilter(o, e); + // all child widgets get the WA_TransparentForMouseEvents attribute, so + // we have to find the "real" widget to forward this event to... + if (!res && isMouseEvent) { + QMouseEvent *me = static_cast(e); + + if (isMouseDown) + d->childWidget = d->mouseTransparentChildAtGlobalPos(d->area->viewport(), me->globalPos()); + + if (d->childWidget) { + QMouseEvent cme(me->type(), me->pos(), + me->globalPos(), me->button(), me->buttons(), me->modifiers()); + d->sendEvent(d->childWidget, &cme); + res = cme.isAccepted(); + } + } return res; } @@ -250,21 +305,23 @@ void QScrollAreaKineticScroller::cancelPress(const QPointF &pressPos) QPoint pos = pressPos.toPoint(); - /* - if (QWidget *childWidget = d->mouseTransparentChildAtGlobalPos(d->area->viewport(), d->view->mapToGlobal(pos))) { - */ if (d->childWidget) { - // simulate a mouse-move and mouse-release far, far away - QPoint faraway(-1000, -1000); - QMouseEvent cmem(QEvent::MouseMove, faraway, d->childWidget->mapToGlobal(faraway), - Qt::LeftButton, QApplication::mouseButtons() | Qt::LeftButton, - QApplication::keyboardModifiers()); - d->sendEvent(d->childWidget, &cmem); - - QMouseEvent cmer(QEvent::MouseButtonRelease, faraway, d->childWidget->mapToGlobal(faraway), - Qt::LeftButton, QApplication::mouseButtons() & ~Qt::LeftButton, - QApplication::keyboardModifiers()); - d->sendEvent(d->childWidget, &cmer); + if (d->isTouchEnabled) { + //TODO + // TouchUpdate + TouchEnd? + } else { + // simulate a mouse-move and mouse-release far, far away + QPoint faraway(-1000, -1000); + QMouseEvent cmem(QEvent::MouseMove, faraway, d->childWidget->mapToGlobal(faraway), + Qt::LeftButton, QApplication::mouseButtons() | Qt::LeftButton, + QApplication::keyboardModifiers()); + d->sendEvent(d->childWidget, &cmem); + + QMouseEvent cmer(QEvent::MouseButtonRelease, faraway, d->childWidget->mapToGlobal(faraway), + Qt::LeftButton, QApplication::mouseButtons() & ~Qt::LeftButton, + QApplication::keyboardModifiers()); + d->sendEvent(d->childWidget, &cmer); + } } if (QAbstractItemView *view = qobject_cast(d->area)) -- cgit v1.2.3