aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@digia.com>2014-11-13 17:54:26 +0100
committerShawn Rutledge <shawn.rutledge@digia.com>2015-01-25 21:59:35 +0100
commitd896d76b0f2ff0387cd09a04107ea5df087268e1 (patch)
treebe6d7385188baa3a83c8e59b400baf4d7cae5984
parent817cd03a5f437c9e8862646cca5ea016b1223bc7 (diff)
PinchArea: handle native gestures when available
PinchArea is the first Item where we handle a QNativeGestureEvent, so QQuickWindowPrivate::deliverGestureEvent is added to deliver these events in the same way as the other deliverXEvent methods. For now there is not a separate virtual event handler in QQuickItem, because QNativeGestureEvent is not universally available, so it's necessary to handle this event type in QQuickPinchArea::event(). updatePinchTarget() contains code factored out from updatePinch() to do the necessary tranformations on the Item which was set as pinch.target in QML. So far the QNativeGestureEvents are generated only on OSX, so the behavior of the PinchArea on other platforms is unmodified. On OSX the intention is that we do not need to enable multiple-touch events in order to use any of the common 2-finger gestures, and the "feel" will be similar to that of gestures in native applications. [ChangeLog][QtQuick][PinchArea] Pinch gestures are recognized by the operating system on OSX Change-Id: I693526ea120a9144beb7666afeab6256caa73e51 Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com>
-rw-r--r--src/quick/items/qquickitem.cpp3
-rw-r--r--src/quick/items/qquickpincharea.cpp176
-rw-r--r--src/quick/items/qquickpincharea_p.h7
-rw-r--r--src/quick/items/qquickwindow.cpp35
-rw-r--r--src/quick/items/qquickwindow_p.h1
5 files changed, 167 insertions, 55 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 38736e44b2..2d81714ee1 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -7316,6 +7316,9 @@ bool QQuickItem::event(QEvent *ev)
dropEvent(static_cast<QDropEvent*>(ev));
break;
#endif // QT_NO_DRAGANDDROP
+ case QEvent::NativeGesture:
+ ev->ignore();
+ break;
default:
return QObject::event(ev);
}
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 7e934316d8..c2ea91ed1e 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -37,7 +37,10 @@
#include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
+#include <qpa/qplatformintegration.h>
#include <qpa/qplatformnativeinterface.h>
+#include <private/qguiapplication_p.h>
+#include <QVariant>
#include <float.h>
#include <math.h>
@@ -178,7 +181,10 @@ QQuickPinchAreaPrivate::~QQuickPinchAreaPrivate()
\li using the onPinchStarted, onPinchUpdated and onPinchFinished handlers
\endlist
- \sa PinchEvent
+ Since Qt 5.5, PinchArea can react to native pinch gesture events from the
+ operating system if available; otherwise it reacts only to touch events.
+
+ \sa PinchEvent, QNativeGestureEvent, QTouchEvent
*/
/*!
@@ -526,34 +532,40 @@ void QQuickPinchArea::updatePinch()
d->lastPoint1 = touchPoint1.scenePos();
d->lastPoint2 = touchPoint2.scenePos();
emit pinchUpdated(&pe);
- if (d->pinch && d->pinch->target()) {
- qreal s = d->pinchStartScale * scale;
- s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
- pinch()->target()->setScale(s);
- QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos;
- if (pinch()->axis() & QQuickPinch::XAxis) {
- qreal x = pos.x();
- if (x < pinch()->xmin())
- x = pinch()->xmin();
- else if (x > pinch()->xmax())
- x = pinch()->xmax();
- pinch()->target()->setX(x);
- }
- if (pinch()->axis() & QQuickPinch::YAxis) {
- qreal y = pos.y();
- if (y < pinch()->ymin())
- y = pinch()->ymin();
- else if (y > pinch()->ymax())
- y = pinch()->ymax();
- pinch()->target()->setY(y);
- }
- if (d->pinchStartRotation >= pinch()->minimumRotation()
- && d->pinchStartRotation <= pinch()->maximumRotation()) {
- qreal r = d->pinchRotation + d->pinchStartRotation;
- r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
- pinch()->target()->setRotation(r);
- }
- }
+ updatePinchTarget();
+ }
+ }
+}
+
+void QQuickPinchArea::updatePinchTarget()
+{
+ Q_D(QQuickPinchArea);
+ if (d->pinch && d->pinch->target()) {
+ qreal s = d->pinchStartScale * d->pinchLastScale;
+ s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
+ pinch()->target()->setScale(s);
+ QPointF pos = d->sceneLastCenter - d->sceneStartCenter + d->pinchStartPos;
+ if (pinch()->axis() & QQuickPinch::XAxis) {
+ qreal x = pos.x();
+ if (x < pinch()->xmin())
+ x = pinch()->xmin();
+ else if (x > pinch()->xmax())
+ x = pinch()->xmax();
+ pinch()->target()->setX(x);
+ }
+ if (pinch()->axis() & QQuickPinch::YAxis) {
+ qreal y = pos.y();
+ if (y < pinch()->ymin())
+ y = pinch()->ymin();
+ else if (y > pinch()->ymax())
+ y = pinch()->ymax();
+ pinch()->target()->setY(y);
+ }
+ if (d->pinchStartRotation >= pinch()->minimumRotation()
+ && d->pinchStartRotation <= pinch()->maximumRotation()) {
+ qreal r = d->pinchRotation + d->pinchStartRotation;
+ r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
+ pinch()->target()->setRotation(r);
}
}
}
@@ -597,31 +609,95 @@ void QQuickPinchArea::itemChange(ItemChange change, const ItemChangeData &value)
QQuickItem::itemChange(change, value);
}
-#ifdef Q_OS_OSX
-void QQuickPinchArea::hoverEnterEvent(QHoverEvent *event)
+bool QQuickPinchArea::event(QEvent *event)
{
- Q_UNUSED(event);
- setTouchEventsEnabled(true);
-}
+ Q_D(QQuickPinchArea);
+ if (!d->enabled || !isVisible())
+ return QQuickItem::event(event);
-void QQuickPinchArea::hoverLeaveEvent(QHoverEvent *event)
-{
- Q_UNUSED(event);
- setTouchEventsEnabled(false);
-}
+ switch (event->type()) {
+#ifndef QT_NO_GESTURES
+ case QEvent::NativeGesture: {
+ QNativeGestureEvent *gesture = static_cast<QNativeGestureEvent *>(event);
+ switch (gesture->gestureType()) {
+ case Qt::BeginNativeGesture:
+ clearPinch(); // probably not necessary; JIC
+ d->pinchStartCenter = gesture->localPos();
+ d->pinchStartAngle = 0.0;
+ d->pinchStartRotation = 0.0;
+ d->pinchRotation = 0.0;
+ d->pinchStartScale = 1.0;
+ d->pinchLastAngle = 0.0;
+ d->pinchLastScale = 1.0;
+ d->sceneStartPoint1 = gesture->windowPos();
+ d->sceneStartPoint2 = gesture->windowPos(); // TODO we never really know
+ d->lastPoint1 = gesture->windowPos();
+ d->lastPoint2 = gesture->windowPos(); // TODO we never really know
+ if (d->pinch && d->pinch->target()) {
+ d->pinchStartPos = d->pinch->target()->position();
+ d->pinchStartScale = d->pinch->target()->scale();
+ d->pinchStartRotation = d->pinch->target()->rotation();
+ d->pinch->setActive(true);
+ }
+ break;
+ case Qt::EndNativeGesture:
+ clearPinch();
+ break;
+ case Qt::ZoomNativeGesture: {
+ qreal scale = d->pinchLastScale * (1.0 + gesture->value());
+ QQuickPinchEvent pe(d->pinchStartCenter, scale, d->pinchLastAngle, 0.0);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(d->pinchStartCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(mapFromScene(d->lastPoint1));
+ pe.setPoint2(mapFromScene(d->lastPoint2));
+ pe.setPointCount(2);
+ d->pinchLastScale = scale;
+ if (d->inPinch)
+ emit pinchUpdated(&pe);
+ else
+ emit pinchStarted(&pe);
+ d->inPinch = true;
+ updatePinchTarget();
+ } break;
+ case Qt::RotateNativeGesture: {
+ qreal angle = d->pinchLastAngle + gesture->value();
+ QQuickPinchEvent pe(d->pinchStartCenter, d->pinchLastScale, angle, 0.0);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(d->pinchStartCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(mapFromScene(d->lastPoint1));
+ pe.setPoint2(mapFromScene(d->lastPoint2));
+ pe.setPointCount(2);
+ d->pinchLastAngle = angle;
+ if (d->inPinch)
+ emit pinchUpdated(&pe);
+ else
+ emit pinchStarted(&pe);
+ d->inPinch = true;
+ d->pinchRotation = angle;
+ updatePinchTarget();
+ } break;
+#endif // QT_NO_GESTURES
+ default:
+ return QQuickItem::event(event);
+ }
+ } break;
+ case QEvent::Wheel:
+ event->ignore();
+ return false;
+ default:
+ return QQuickItem::event(event);
+ }
-void QQuickPinchArea::setTouchEventsEnabled(bool enable)
-{
- // Resolve function for enabling touch events from the (cocoa) platform plugin.
- typedef void (*RegisterTouchWindowFunction)(QWindow *, bool);
- RegisterTouchWindowFunction registerTouchWindow = reinterpret_cast<RegisterTouchWindowFunction>(
- QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow"));
- if (!registerTouchWindow)
- return; // Not necessarily an error, Qt might be using a different platform plugin.
-
- registerTouchWindow(window(), enable);
+ return true;
}
-#endif // Q_OS_OSX
QQuickPinch *QQuickPinchArea::pinch()
{
diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h
index 28db59fb55..21282237b7 100644
--- a/src/quick/items/qquickpincharea_p.h
+++ b/src/quick/items/qquickpincharea_p.h
@@ -274,15 +274,12 @@ protected:
void geometryChanged(const QRectF &newGeometry,
const QRectF &oldGeometry) Q_DECL_OVERRIDE;
void itemChange(ItemChange change, const ItemChangeData& value) Q_DECL_OVERRIDE;
-#ifdef Q_OS_OSX
- void hoverEnterEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
- void hoverLeaveEvent(QHoverEvent *event) Q_DECL_OVERRIDE;
- void setTouchEventsEnabled(bool enable);
-#endif
+ bool event(QEvent *) Q_DECL_OVERRIDE;
private:
void clearPinch();
void updatePinch();
+ void updatePinchTarget();
void handlePress();
void handleRelease();
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index f58bd489fe..a387046d46 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1394,6 +1394,9 @@ bool QQuickWindow::event(QEvent *e)
d->windowManager->handleUpdateRequest(this);
break;
}
+ case QEvent::NativeGesture:
+ d->deliverGestureEvent(d->contentItem, static_cast<QNativeGestureEvent*>(e));
+ break;
default:
break;
}
@@ -1751,6 +1754,38 @@ bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event
return false;
}
+bool QQuickWindowPrivate::deliverGestureEvent(QQuickItem *item, QNativeGestureEvent *event)
+{
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+
+ if ((itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) && !item->contains(event->localPos()))
+ return false;
+
+ QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QQuickItem *child = children.at(ii);
+ if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
+ continue;
+ if (deliverGestureEvent(child, event))
+ return true;
+ }
+
+ QPointF p = item->mapFromScene(event->localPos());
+
+ if (item->contains(p)) {
+ QNativeGestureEvent copy(event->gestureType(), p, event->windowPos(), event->screenPos(),
+ event->value(), 0L, 0L); // TODO can't copy things I can't access
+ event->accept();
+ item->event(&copy);
+ if (copy.isAccepted()) {
+ event->accept();
+ return true;
+ }
+ }
+
+ return false;
+}
+
/*! \reimp */
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 4f6149117a..2bfc928e0d 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -141,6 +141,7 @@ public:
#ifndef QT_NO_WHEELEVENT
bool deliverWheelEvent(QQuickItem *, QWheelEvent *);
#endif
+ bool deliverGestureEvent(QQuickItem *, QNativeGestureEvent *);
bool deliverTouchPoints(QQuickItem *, QTouchEvent *, const QList<QTouchEvent::TouchPoint> &, QSet<int> *,
QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *, QSet<QQuickItem*> *filtered);
void deliverTouchEvent(QTouchEvent *);