aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/handlers/handlers.pri19
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp168
-rw-r--r--src/quick/handlers/qquickdraghandler_p.h133
-rw-r--r--src/quick/handlers/qquickhandlersmodule.cpp96
-rw-r--r--src/quick/handlers/qquickhandlersmodule_p.h68
-rw-r--r--src/quick/handlers/qquickmultipointerhandler.cpp219
-rw-r--r--src/quick/handlers/qquickmultipointerhandler_p.h112
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp291
-rw-r--r--src/quick/handlers/qquickpinchhandler_p.h171
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler.cpp109
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler_p.h97
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp184
-rw-r--r--src/quick/handlers/qquickpointerhandler_p.h120
-rw-r--r--src/quick/handlers/qquickpointersinglehandler.cpp131
-rw-r--r--src/quick/handlers/qquickpointersinglehandler_p.h93
-rw-r--r--src/quick/items/qquickevents.cpp149
-rw-r--r--src/quick/items/qquickevents_p_p.h76
-rw-r--r--src/quick/items/qquickflickable.cpp3
-rw-r--r--src/quick/items/qquickitem.cpp17
-rw-r--r--src/quick/items/qquickitem_p.h4
-rw-r--r--src/quick/items/qquickwindow.cpp78
-rw-r--r--src/quick/items/qquickwindow_p.h2
-rw-r--r--src/quick/quick.pro1
23 files changed, 2260 insertions, 81 deletions
diff --git a/src/quick/handlers/handlers.pri b/src/quick/handlers/handlers.pri
new file mode 100644
index 0000000000..f32f330d4e
--- /dev/null
+++ b/src/quick/handlers/handlers.pri
@@ -0,0 +1,19 @@
+HEADERS += \
+ $$PWD/qquickdraghandler_p.h \
+ $$PWD/qquickpointerhandler_p.h \
+ $$PWD/qquickpointerdevicehandler_p.h \
+ $$PWD/qquickmultipointerhandler_p.h \
+ $$PWD/qquickpinchhandler_p.h \
+ $$PWD/qquickpointersinglehandler_p.h \
+ $$PWD/qquickhandlersmodule_p.h \
+ $$PWD/qquickpointerdevicehandler_p.h \
+ $$PWD/qquickhandlersmodule_p.h \
+
+SOURCES += \
+ $$PWD/qquickdraghandler.cpp \
+ $$PWD/qquickpointerhandler.cpp \
+ $$PWD/qquickpointerdevicehandler.cpp \
+ $$PWD/qquickmultipointerhandler.cpp \
+ $$PWD/qquickpinchhandler.cpp \
+ $$PWD/qquickpointersinglehandler.cpp \
+ $$PWD/qquickhandlersmodule.cpp \
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp
new file mode 100644
index 0000000000..dadf8bba04
--- /dev/null
+++ b/src/quick/handlers/qquickdraghandler.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdraghandler_p.h"
+#include <private/qquickwindow_p.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype DragHandler
+ \instantiates QQuickDragHandler
+ \inqmlmodule QtQuick
+ \ingroup qtquick-handlers
+ \brief Handler for dragging
+
+ DragHandler is a handler that is used to interactively move an Item.
+
+ At this time, drag-and-drop is not yet supported.
+
+ \sa Drag, MouseArea
+*/
+
+QQuickDragHandler::QQuickDragHandler(QObject *parent)
+ : QQuickPointerSingleHandler(parent)
+ , m_dragging(false)
+{
+}
+
+QQuickDragHandler::~QQuickDragHandler()
+{
+}
+
+bool QQuickDragHandler::wantsEventPoint(QQuickEventPoint *point)
+{
+ // If we've already been interested in a point, stay interested, even if it has strayed outside bounds.
+ return ((point->state() != QQuickEventPoint::Pressed && currentPointId() == point->pointId())
+ || QQuickPointerSingleHandler::wantsEventPoint(point));
+}
+
+void QQuickDragHandler::handleEventPoint(QQuickEventPoint *point)
+{
+ // If there's no target or the target has no parent, we shouldn't be dragging
+ if (!target() || !target()->parentItem())
+ return;
+ point->setAccepted();
+ switch (point->state()) {
+ case QQuickEventPoint::Pressed:
+ m_startPos = target()->mapToScene(QPointF());
+ break;
+ case QQuickEventPoint::Updated: {
+ QPointF delta = point->scenePos() - point->scenePressPos();
+ if (!m_xAxis.enabled())
+ delta.setX(0);
+ if (!m_yAxis.enabled())
+ delta.setY(0);
+ if (m_dragging) {
+ QPointF pos = target()->parentItem()->mapFromScene(m_startPos) + delta;
+ enforceAxisConstraints(&pos);
+ target()->setPosition(pos);
+ } else if ((m_xAxis.enabled() && QQuickWindowPrivate::dragOverThreshold(delta.x(), Qt::XAxis, point)) ||
+ (m_yAxis.enabled() && QQuickWindowPrivate::dragOverThreshold(delta.y(), Qt::YAxis, point))) {
+ m_dragging = true;
+ setGrab(point, true);
+ emit draggingChanged();
+ }
+ } break;
+ case QQuickEventPoint::Released:
+ if (m_dragging) {
+ m_dragging = false;
+ emit draggingChanged();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void QQuickDragHandler::enforceConstraints()
+{
+ if (!target() || !target()->parentItem())
+ return;
+ QPointF pos = target()->position();
+ QPointF copy(pos);
+ enforceAxisConstraints(&pos);
+ if (pos != copy)
+ target()->setPosition(pos);
+}
+
+void QQuickDragHandler::enforceAxisConstraints(QPointF *localPos)
+{
+ if (m_xAxis.enabled())
+ localPos->setX(qBound(m_xAxis.minimum(), localPos->x(), m_xAxis.maximum()));
+ if (m_yAxis.enabled())
+ localPos->setY(qBound(m_yAxis.minimum(), localPos->y(), m_yAxis.maximum()));
+}
+
+QQuickDragAxis::QQuickDragAxis()
+ : m_minimum(-DBL_MAX)
+ , m_maximum(DBL_MAX)
+ , m_enabled(true)
+{
+}
+
+void QQuickDragAxis::setMinimum(qreal minimum)
+{
+ if (m_minimum == minimum)
+ return;
+
+ m_minimum = minimum;
+ emit minimumChanged();
+}
+
+void QQuickDragAxis::setMaximum(qreal maximum)
+{
+ if (m_maximum == maximum)
+ return;
+
+ m_maximum = maximum;
+ emit maximumChanged();
+}
+
+void QQuickDragAxis::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ m_enabled = enabled;
+ emit enabledChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h
new file mode 100644
index 0000000000..e7cb675025
--- /dev/null
+++ b/src/quick/handlers/qquickdraghandler_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDRAGHANDLER_H
+#define QQUICKDRAGHANDLER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickpointersinglehandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickDragAxis : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged)
+ Q_PROPERTY(qreal maximum READ maximum WRITE setMaximum NOTIFY maximumChanged)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+
+public:
+ QQuickDragAxis();
+
+ qreal minimum() const { return m_minimum; }
+ void setMinimum(qreal minimum);
+
+ qreal maximum() const { return m_maximum; }
+ void setMaximum(qreal maximum);
+
+ bool enabled() const { return m_enabled; }
+ void setEnabled(bool enabled);
+
+signals:
+ void minimumChanged();
+ void maximumChanged();
+ void enabledChanged();
+
+private:
+ qreal m_minimum;
+ qreal m_maximum;
+ bool m_enabled;
+};
+
+class Q_AUTOTEST_EXPORT QQuickDragHandler : public QQuickPointerSingleHandler
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickDragAxis * xAxis READ xAxis CONSTANT)
+ Q_PROPERTY(QQuickDragAxis * yAxis READ yAxis CONSTANT)
+ Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
+
+public:
+ QQuickDragHandler(QObject *parent = 0);
+ ~QQuickDragHandler();
+
+ void handleEventPoint(QQuickEventPoint *point) override;
+
+ QQuickDragAxis *xAxis() { return &m_xAxis; }
+ QQuickDragAxis *yAxis() { return &m_yAxis; }
+
+ bool dragging() const { return m_dragging; }
+
+ Q_INVOKABLE void enforceConstraints();
+
+Q_SIGNALS:
+// void gestureStarted(QQuickGestureEvent *gesture);
+ void draggingChanged();
+
+protected:
+ bool wantsEventPoint(QQuickEventPoint *point) override;
+
+private:
+ void ungrab();
+ void enforceAxisConstraints(QPointF *localPos);
+
+private:
+ bool m_dragging;
+ QPointF m_startPos;
+ QQuickDragAxis m_xAxis;
+ QQuickDragAxis m_yAxis;
+
+ friend class QQuickDragAxis;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickDragHandler)
+QML_DECLARE_TYPE(QQuickDragAxis)
+
+#endif // QQUICKDRAGHANDLER_H
diff --git a/src/quick/handlers/qquickhandlersmodule.cpp b/src/quick/handlers/qquickhandlersmodule.cpp
new file mode 100644
index 0000000000..97d6f1d499
--- /dev/null
+++ b/src/quick/handlers/qquickhandlersmodule.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickhandlersmodule_p.h"
+#include "qquickpointerhandler_p.h"
+#include "qquickdraghandler_p.h"
+#include "qquickpinchhandler_p.h"
+
+static void initResources()
+{
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(qmake_Qt_labs_handlers);
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+static QQmlPrivate::AutoParentResult handler_autoParent(QObject *obj, QObject *parent)
+{
+ if (QQuickItem *parentItem = qmlobject_cast<QQuickItem *>(parent)) {
+ QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(obj);
+ if (handler && !handler->target()) {
+ handler->setTarget(parentItem);
+ return QQmlPrivate::Parented;
+ }
+ }
+ return QQmlPrivate::IncompatibleObject;
+}
+
+static void qt_quickhandlers_defineModule(const char *uri, int major, int minor)
+{
+ QQmlPrivate::RegisterAutoParent autoparent = { 0, &handler_autoParent };
+ QQmlPrivate::qmlregister(QQmlPrivate::AutoParentRegistration, &autoparent);
+ qmlRegisterUncreatableType<QQuickPointerEvent>(uri, major, minor, "PointerEvent",
+ QQuickPointerHandler::tr("PointerEvent is only available as a parameter of several signals in PointerHandler"));
+ qmlRegisterUncreatableType<QQuickPointerDevice>(uri, major, minor, "PointerDevice",
+ QQuickPointerHandler::tr("PointerDevice is only available as a property of PointerEvent"));
+ qRegisterMetaType<QPointerUniqueId>("QPointerUniqueId");
+ qmlRegisterUncreatableType<QPointerUniqueId>(uri, major, minor, "PointerUniqueId",
+ QQuickPointerHandler::tr("PointerUniqueId is only available as a property of PointerEvent"));
+
+ qmlRegisterType<QQuickPointerHandler>(uri,major,minor,"PointerHandler");
+ qmlRegisterType<QQuickDragHandler>(uri,major,minor,"DragHandler");
+ qmlRegisterUncreatableType<QQuickDragAxis>(uri, major, minor, "DragAxis",
+ QQuickDragHandler::tr("DragAxis is only available as a grouped property of DragHandler"));
+ qmlRegisterType<QQuickPinchHandler>(uri,major,minor,"PinchHandler");
+}
+
+void QQuickHandlersModule::defineModule()
+{
+ initResources();
+
+ const char uri[] = "Qt.labs.handlers";
+ int majorVersion = 1;
+ int minorVersion = 0;
+
+ qt_quickhandlers_defineModule(uri, majorVersion, minorVersion);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickhandlersmodule_p.h b/src/quick/handlers/qquickhandlersmodule_p.h
new file mode 100644
index 0000000000..7eb8d39b98
--- /dev/null
+++ b/src/quick/handlers/qquickhandlersmodule_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKHANDLERSMODULE_P_H
+#define QQUICKHANDLERSMODULE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qqml.h>
+#include <private/qtquickglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QQuickHandlersModule
+{
+public:
+ static void defineModule();
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKHANDLERSMODULE_P_H
+
diff --git a/src/quick/handlers/qquickmultipointerhandler.cpp b/src/quick/handlers/qquickmultipointerhandler.cpp
new file mode 100644
index 0000000000..746d33a12c
--- /dev/null
+++ b/src/quick/handlers/qquickmultipointerhandler.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmultipointerhandler_p.h"
+#include <private/qquickitem_p.h>
+#include <QLineF>
+#include <QMouseEvent>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ An intermediate class (not registered as a QML type)
+ for the type of handler which requires and acts upon a specific number
+ of multiple touchpoints.
+*/
+QQuickMultiPointerHandler::QQuickMultiPointerHandler(QObject *parent, int requiredPointCount)
+ : QQuickPointerDeviceHandler(parent)
+ , m_requiredPointCount(requiredPointCount)
+ , m_pointDistanceThreshold(0)
+{
+}
+
+QQuickMultiPointerHandler::~QQuickMultiPointerHandler()
+{
+}
+
+bool QQuickMultiPointerHandler::wantsPointerEvent(QQuickPointerEvent *event)
+{
+ if (!QQuickPointerDeviceHandler::wantsPointerEvent(event))
+ return false;
+ if (event->pointCount() < m_requiredPointCount)
+ return false;
+ if (sameAsCurrentPoints(event))
+ return true;
+
+ const QVector<QQuickEventPoint *> candidatePoints = pointsInsideOrNearTarget(event);
+ const bool ret = (candidatePoints.size() == m_requiredPointCount);
+ if (ret)
+ m_currentPoints = candidatePoints;
+ return ret;
+}
+
+QVector<QQuickEventPoint *> QQuickMultiPointerHandler::pointsInsideOrNearTarget(QQuickPointerEvent *event)
+{
+ QVector<QQuickEventPoint *> ret;
+ int c = event->pointCount();
+ QRectF targetBounds = target()->mapRectToScene(target()->boundingRect())
+ .marginsAdded(QMarginsF(m_pointDistanceThreshold, m_pointDistanceThreshold, m_pointDistanceThreshold, m_pointDistanceThreshold));
+ for (int i = 0; i < c; ++i) {
+ QQuickEventPoint *p = event->point(i);
+ if (targetBounds.contains(p->scenePos()))
+ ret << p;
+ }
+ return ret;
+}
+
+void QQuickMultiPointerHandler::setRequiredPointCount(int c)
+{
+ if (m_requiredPointCount == c)
+ return;
+
+ m_requiredPointCount = c;
+ emit requiredPointCountChanged();
+}
+
+void QQuickMultiPointerHandler::setPointDistanceThreshold(qreal pointDistanceThreshold)
+{
+ if (m_pointDistanceThreshold == pointDistanceThreshold)
+ return;
+
+ m_pointDistanceThreshold = pointDistanceThreshold;
+ emit pointDistanceThresholdChanged();
+}
+
+bool QQuickMultiPointerHandler::sameAsCurrentPoints(QQuickPointerEvent *event)
+{
+ bool ret = true;
+ int c = event->pointCount();
+ if (c != m_currentPoints.size())
+ return false;
+ // TODO optimize: either ensure the points are sorted,
+ // or use std::equal with a predicate
+ for (int i = 0; ret && i < c; ++i) {
+ bool found = false;
+ quint64 pointId = event->point(i)->pointId();
+ for (QQuickEventPoint *o : qAsConst(m_currentPoints))
+ if (o && pointId == o->pointId())
+ found = true;
+ if (!found)
+ ret = false;
+ }
+ return ret;
+}
+
+// TODO make templates for these functions somehow?
+QPointF QQuickMultiPointerHandler::touchPointCentroid()
+{
+ QPointF ret;
+ if (Q_UNLIKELY(m_currentPoints.size() == 0))
+ return ret;
+ for (QQuickEventPoint *point : qAsConst(m_currentPoints))
+ ret += point->scenePos();
+ return ret / m_currentPoints.size();
+}
+
+qreal QQuickMultiPointerHandler::averageTouchPointDistance(const QPointF &ref)
+{
+ qreal ret = 0;
+ if (Q_UNLIKELY(m_currentPoints.size() == 0))
+ return ret;
+ for (QQuickEventPoint *point : qAsConst(m_currentPoints))
+ ret += QVector2D(point->scenePos() - ref).length();
+ return ret / m_currentPoints.size();
+}
+
+qreal QQuickMultiPointerHandler::averageStartingDistance(const QPointF &ref)
+{
+ // TODO cache it in setActive()?
+ qreal ret = 0;
+ if (Q_UNLIKELY(m_currentPoints.size() == 0))
+ return ret;
+ for (QQuickEventPoint *point : qAsConst(m_currentPoints))
+ ret += QVector2D(point->sceneGrabPos() - ref).length();
+ return ret / m_currentPoints.size();
+}
+
+QVector<QQuickMultiPointerHandler::PointData> QQuickMultiPointerHandler::angles(const QPointF &ref) const
+{
+ QVector<PointData> angles;
+ angles.reserve(m_currentPoints.count());
+ for (QQuickEventPoint *point : qAsConst(m_currentPoints)) {
+ qreal angle = QLineF(ref, point->scenePos()).angle();
+ angles.append(PointData(point->pointId(), angle));
+ }
+ return angles;
+}
+
+qreal QQuickMultiPointerHandler::averageAngleDelta(const QVector<PointData> &old, const QVector<PointData> &newAngles)
+{
+ qreal avgAngleDelta = 0;
+ int numSamples = 0;
+
+ auto oldBegin = old.constBegin();
+
+ for (PointData newData : newAngles) {
+ quint64 id = newData.id;
+ auto it = std::find_if(oldBegin, old.constEnd(), [id] (PointData pd) { return pd.id == id; });
+ qreal angleD = 0;
+ if (it != old.constEnd()) {
+ PointData oldData = *it;
+ // We might rotate from 359 degrees to 1 degree. However, this
+ // should be interpreted as a rotation of +2 degrees instead of
+ // -358 degrees. Therefore, we call remainder() to translate the angle
+ // to be in the range [-180, 180] (-350 to +10 etc)
+ angleD = remainder(newData.angle - oldData.angle, qreal(360));
+ // optimization: narrow down the O(n^2) search to optimally O(n)
+ // if both vectors have the same points and they are in the same order
+ if (it == oldBegin)
+ ++oldBegin;
+ numSamples++;
+ }
+ avgAngleDelta += angleD;
+ }
+ if (numSamples > 1)
+ avgAngleDelta /= numSamples;
+
+ return avgAngleDelta;
+}
+
+void QQuickMultiPointerHandler::acceptPoints(const QVector<QQuickEventPoint *> &points)
+{
+ for (QQuickEventPoint* point : points)
+ point->setAccepted();
+}
+
+void QQuickMultiPointerHandler::grabPoints(QVector<QQuickEventPoint *> points)
+{
+ for (QQuickEventPoint* point : points)
+ point->setGrabberPointerHandler(this);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickmultipointerhandler_p.h b/src/quick/handlers/qquickmultipointerhandler_p.h
new file mode 100644
index 0000000000..2a23a14f8a
--- /dev/null
+++ b/src/quick/handlers/qquickmultipointerhandler_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOINTERMULTIHANDLER_H
+#define QQUICKPOINTERMULTIHANDLER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickitem.h"
+#include "qevent.h"
+#include "qquickpointerdevicehandler_p.h"
+#include "../items/qquickmultipointtoucharea_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickMultiPointerHandler : public QQuickPointerDeviceHandler
+{
+ Q_OBJECT
+ Q_PROPERTY(int requiredPointCount READ requiredPointCount WRITE setRequiredPointCount NOTIFY requiredPointCountChanged)
+ Q_PROPERTY(qreal pointDistanceThreshold READ pointDistanceThreshold WRITE setPointDistanceThreshold NOTIFY pointDistanceThresholdChanged)
+
+public:
+ QQuickMultiPointerHandler(QObject *parent = 0, int requiredPointCount = 2);
+ ~QQuickMultiPointerHandler();
+
+ int requiredPointCount() const { return m_requiredPointCount; }
+ void setRequiredPointCount(int c);
+
+ qreal pointDistanceThreshold() const { return m_pointDistanceThreshold; }
+ void setPointDistanceThreshold(qreal pointDistanceThreshold);
+
+signals:
+ void requiredPointCountChanged();
+ void pointDistanceThresholdChanged();
+
+protected:
+ struct PointData {
+ PointData() : id(0), angle(0) {}
+ PointData(quint64 id, qreal angle) : id(id), angle(angle) {}
+ quint64 id;
+ qreal angle;
+ };
+
+ bool wantsPointerEvent(QQuickPointerEvent *event) override;
+ bool sameAsCurrentPoints(QQuickPointerEvent *event);
+ QVector<QQuickEventPoint *> pointsInsideOrNearTarget(QQuickPointerEvent *event);
+ QPointF touchPointCentroid();
+ qreal averageTouchPointDistance(const QPointF &ref);
+ qreal averageStartingDistance(const QPointF &ref);
+ qreal averageTouchPointAngle(const QPointF &ref);
+ qreal averageStartingAngle(const QPointF &ref);
+ QVector<PointData> angles(const QPointF &ref) const;
+ static qreal averageAngleDelta(const QVector<PointData> &old, const QVector<PointData> &newAngles);
+ void acceptPoints(const QVector<QQuickEventPoint *> &points);
+ void grabPoints(QVector<QQuickEventPoint *> points);
+
+protected:
+ QVector<QQuickEventPoint *> m_currentPoints;
+ int m_requiredPointCount;
+ qreal m_pointDistanceThreshold;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMultiPointerHandler)
+
+#endif // QQUICKPOINTERMULTIHANDLER_H
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
new file mode 100644
index 0000000000..8ee8e2c6b6
--- /dev/null
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -0,0 +1,291 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpinchhandler_p.h"
+#include <QtQuick/qquickwindow.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qquickitem_p.h>
+#include <private/qguiapplication_p.h>
+#include <private/qquickwindow_p.h>
+#include <QEvent>
+#include <QMouseEvent>
+#include <QDebug>
+#include <qpa/qplatformnativeinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch")
+
+/*!
+ \qmltype PinchHandler
+ \instantiates QQuickPinchHandler
+ \inqmlmodule QtQuick
+ \ingroup qtquick-handlers
+ \brief Handler for pinch gestures
+
+ PinchHandler is a handler that is used to interactively rotate and zoom an Item.
+*/
+
+QQuickPinchHandler::QQuickPinchHandler(QObject *parent)
+ : QQuickMultiPointerHandler(parent, 2)
+ , m_scale(1)
+ , m_rotation(0)
+ , m_translation(0,0)
+ , m_minimumScale(-qInf())
+ , m_maximumScale(qInf())
+ , m_minimumRotation(-qInf())
+ , m_maximumRotation(qInf())
+ , m_minimumX(-qInf())
+ , m_maximumX(qInf())
+ , m_minimumY(-qInf())
+ , m_maximumY(qInf())
+ , m_pinchOrigin(PinchCenter)
+ , m_startScale(1)
+ , m_startRotation(0)
+{
+ connect(this, &QQuickPinchHandler::targetChanged, this, &QQuickPinchHandler::onTargetChanged);
+}
+
+QQuickPinchHandler::~QQuickPinchHandler()
+{
+}
+
+void QQuickPinchHandler::setMinimumScale(qreal minimumScale)
+{
+ if (m_minimumScale == minimumScale)
+ return;
+
+ m_minimumScale = minimumScale;
+ emit minimumScaleChanged();
+}
+
+void QQuickPinchHandler::setMaximumScale(qreal maximumScale)
+{
+ if (m_maximumScale == maximumScale)
+ return;
+
+ m_maximumScale = maximumScale;
+ emit maximumScaleChanged();
+}
+
+void QQuickPinchHandler::setMinimumRotation(qreal minimumRotation)
+{
+ if (m_minimumRotation == minimumRotation)
+ return;
+
+ m_minimumRotation = minimumRotation;
+ emit minimumRotationChanged();
+}
+
+void QQuickPinchHandler::setMaximumRotation(qreal maximumRotation)
+{
+ if (m_maximumRotation == maximumRotation)
+ return;
+
+ m_maximumRotation = maximumRotation;
+ emit maximumRotationChanged();
+}
+
+void QQuickPinchHandler::setPinchOrigin(QQuickPinchHandler::PinchOrigin pinchOrigin)
+{
+ if (m_pinchOrigin == pinchOrigin)
+ return;
+
+ m_pinchOrigin = pinchOrigin;
+ emit pinchOriginChanged();
+}
+
+/*!
+ \qmlproperty QQuickPinchHandler::minimumX
+
+ The minimum acceptable x coordinate of the centroid
+ */
+void QQuickPinchHandler::setMinimumX(qreal minX)
+{
+ if (m_minimumX == minX)
+ return;
+ m_minimumX = minX;
+ emit minimumXChanged();
+}
+
+/*!
+ \qmlproperty QQuickPinchHandler::maximumX
+
+ The maximum acceptable x coordinate of the centroid
+ */
+void QQuickPinchHandler::setMaximumX(qreal maxX)
+{
+ if (m_maximumX == maxX)
+ return;
+ m_maximumX = maxX;
+ emit maximumXChanged();
+}
+
+/*!
+ \qmlproperty QQuickPinchHandler::minimumY
+
+ The minimum acceptable y coordinate of the centroid
+ */
+void QQuickPinchHandler::setMinimumY(qreal minY)
+{
+ if (m_minimumY == minY)
+ return;
+ m_minimumY = minY;
+ emit minimumYChanged();
+}
+
+/*!
+ \qmlproperty QQuickPinchHandler::maximumY
+
+ The maximum acceptable y coordinate of the centroid
+ */
+void QQuickPinchHandler::setMaximumY(qreal maxY)
+{
+ if (m_maximumY == maxY)
+ return;
+ m_maximumY = maxY;
+ emit maximumYChanged();
+}
+
+/*!
+ \qmlproperty QQuickPinchHandler::minimumTouchPoints
+
+ The pinch begins when this number of fingers are pressed.
+ Until then, PinchHandler tracks the positions of any pressed fingers,
+ but if it's an insufficient number, it does not scale or rotate
+ its \l target, and the \l active property will remain false.
+*/
+
+/*!
+ \qmlproperty QQuickPinchHandler::active
+*/
+
+void QQuickPinchHandler::onActiveChanged()
+{
+ if (active()) {
+ m_startScale = m_scale; // TODO incompatible with independent x/y scaling
+ m_startRotation = m_rotation;
+ m_startCentroid = touchPointCentroid();
+ m_startAngles = angles(m_startCentroid);
+ m_startDistance = averageTouchPointDistance(m_startCentroid);
+ m_activeRotation = 0;
+ m_startMatrix = m_transform.matrix();
+ qCInfo(lcPinchHandler) << "activated with starting scale" << m_startScale << "rotation" << m_startRotation;
+ grabPoints(m_currentPoints);
+ } else {
+ qCInfo(lcPinchHandler) << "deactivated with scale" << m_scale << "rotation" << m_rotation;
+ }
+}
+
+void QQuickPinchHandler::onTargetChanged()
+{
+ if (target()) {
+ // TODO if m_target was previously set differently,
+ // does prepending to the new target remove it from the old one?
+ // If not, should we fix that there, or here?
+ m_transform.prependToItem(target());
+ }
+}
+
+void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
+{
+ Q_UNUSED(event)
+
+ if (Q_UNLIKELY(lcPinchHandler().isDebugEnabled())) {
+ for (QQuickEventPoint *point : qAsConst(m_currentPoints))
+ qCDebug(lcPinchHandler) << point->state() << point->sceneGrabPos() << "->" << point->scenePos();
+ }
+
+ // TODO check m_pinchOrigin: right now it acts like it's set to PinchCenter
+ m_centroid = touchPointCentroid();
+ QRectF bounds(m_minimumX, m_minimumY, m_maximumX, m_maximumY);
+ // avoid mapping the minima and maxima, as they might have unmappable values
+ // such as -inf/+inf. Because of this we perform the bounding to min/max in local coords.
+ QPointF centroidLocalPos;
+ if (target() && target()->parentItem()) {
+ centroidLocalPos = target()->parentItem()->mapFromScene(m_centroid);
+ centroidLocalPos = QPointF(qBound(bounds.left(), centroidLocalPos.x(), bounds.right()),
+ qBound(bounds.top(), centroidLocalPos.y(), bounds.bottom()));
+ }
+ // 1. scale
+ qreal dist = averageTouchPointDistance(m_centroid);
+ qreal activeScale = dist / m_startDistance;
+ activeScale = qBound(m_minimumScale/m_startScale, activeScale, m_maximumScale/m_startScale);
+ m_scale = m_startScale * activeScale;
+
+ // 2. rotate
+ QVector<PointData> newAngles = angles(m_centroid);
+ const qreal angleDelta = averageAngleDelta(m_startAngles, newAngles);
+ m_activeRotation += angleDelta;
+ const qreal totalRotation = m_startRotation + m_activeRotation;
+ m_rotation = qBound(m_minimumRotation, totalRotation, m_maximumRotation);
+ m_activeRotation += (m_rotation - totalRotation); //adjust for the potential bounding above
+ m_startAngles = std::move(newAngles);
+
+ if (target() && target()->parentItem()) {
+ // 3. Drag/translate
+ QPointF activeTranslation(centroidLocalPos - target()->parentItem()->mapFromScene(m_startCentroid));
+
+ // apply rotation + scaling around the centroid - then apply translation.
+ QMatrix4x4 mat;
+ QVector3D xlatOrigin(centroidLocalPos - target()->position());
+ mat.translate(xlatOrigin);
+ mat.rotate(m_activeRotation, 0, 0, -1);
+ mat.scale(activeScale);
+ mat.translate(-xlatOrigin);
+ mat.translate(QVector3D(activeTranslation));
+
+ // TODO some translation inadvertently happens; try to hold the chosen pinch origin in place
+
+ qCDebug(lcPinchHandler) << "centroid" << m_startCentroid << "->" << m_centroid
+ << ", distance" << m_startDistance << "->" << dist
+ << ", startScale" << m_startScale << "->" << m_scale
+ << ", activeRotation" << m_activeRotation
+ << ", rotation" << m_rotation;
+
+ mat = mat * m_startMatrix;
+ m_transform.setMatrix(mat);
+ m_translation = QPointF(mat.constData()[12], mat.constData()[13]);
+ }
+
+ acceptPoints(m_currentPoints);
+ emit updated();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpinchhandler_p.h b/src/quick/handlers/qquickpinchhandler_p.h
new file mode 100644
index 0000000000..83d6447b15
--- /dev/null
+++ b/src/quick/handlers/qquickpinchhandler_p.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPINCHHANDLER_H
+#define QQUICKPINCHHANDLER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickitem.h"
+#include "qevent.h"
+#include "qquickmultipointerhandler_p.h"
+#include <private/qquicktranslate_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickPinchHandler : public QQuickMultiPointerHandler
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged)
+ Q_PROPERTY(qreal maximumScale READ maximumScale WRITE setMaximumScale NOTIFY maximumScaleChanged)
+ Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged)
+ Q_PROPERTY(qreal maximumRotation READ maximumRotation WRITE setMaximumRotation NOTIFY maximumRotationChanged)
+ Q_PROPERTY(PinchOrigin pinchOrigin READ pinchOrigin WRITE setPinchOrigin NOTIFY pinchOriginChanged)
+ Q_PROPERTY(QPointF centroid READ centroid NOTIFY updated)
+ Q_PROPERTY(qreal scale READ scale NOTIFY updated)
+ Q_PROPERTY(qreal rotation READ rotation NOTIFY updated)
+ Q_PROPERTY(QPointF translation READ translation NOTIFY updated)
+ Q_PROPERTY(qreal minimumX READ minimumX WRITE setMinimumX NOTIFY minimumXChanged)
+ Q_PROPERTY(qreal maximumX READ maximumX WRITE setMaximumX NOTIFY maximumXChanged)
+ Q_PROPERTY(qreal minimumY READ minimumY WRITE setMinimumY NOTIFY minimumYChanged)
+ Q_PROPERTY(qreal maximumY READ maximumY WRITE setMaximumY NOTIFY maximumYChanged)
+
+public:
+ enum PinchOrigin {
+ FirstPoint, PinchCenter, TargetCenter
+ };
+ Q_ENUM(PinchOrigin)
+
+ QQuickPinchHandler(QObject *parent = 0);
+ ~QQuickPinchHandler();
+
+ qreal minimumScale() const { return m_minimumScale; }
+ void setMinimumScale(qreal minimumScale);
+
+ qreal maximumScale() const { return m_maximumScale; }
+ void setMaximumScale(qreal maximumScale);
+
+ qreal minimumRotation() const { return m_minimumRotation; }
+ void setMinimumRotation(qreal minimumRotation);
+
+ qreal maximumRotation() const { return m_maximumRotation; }
+ void setMaximumRotation(qreal maximumRotation);
+
+ PinchOrigin pinchOrigin() const { return m_pinchOrigin; }
+ void setPinchOrigin(PinchOrigin pinchOrigin);
+
+ QPointF translation() const { return m_translation; }
+ qreal scale() const { return m_scale; }
+ qreal rotation() const { return m_rotation; }
+ QPointF centroid() const { return m_centroid; }
+
+ qreal minimumX() const { return m_minimumX; }
+ void setMinimumX(qreal minX);
+ qreal maximumX() const { return m_maximumX; }
+ void setMaximumX(qreal maxX);
+ qreal minimumY() const { return m_minimumY; }
+ void setMinimumY(qreal minY);
+ qreal maximumY() const { return m_maximumY; }
+ void setMaximumY(qreal maxY);
+
+signals:
+ void requiredPointCountChanged();
+ void minimumScaleChanged();
+ void maximumScaleChanged();
+ void minimumRotationChanged();
+ void maximumRotationChanged();
+ void minimumXChanged();
+ void maximumXChanged();
+ void minimumYChanged();
+ void maximumYChanged();
+ void pinchOriginChanged();
+ void updated();
+
+protected:
+ void onActiveChanged() override;
+ void onTargetChanged();
+ void handlePointerEventImpl(QQuickPointerEvent *event) override;
+
+private:
+ // properties
+ qreal m_scale;
+ qreal m_rotation;
+ QPointF m_translation;
+ QPointF m_centroid;
+
+ qreal m_minimumScale;
+ qreal m_maximumScale;
+
+ qreal m_minimumRotation;
+ qreal m_maximumRotation;
+
+ qreal m_minimumX;
+ qreal m_maximumX;
+ qreal m_minimumY;
+ qreal m_maximumY;
+
+ PinchOrigin m_pinchOrigin;
+
+ // internal
+ qreal m_startScale;
+ qreal m_startRotation;
+ qreal m_activeRotation;
+ QPointF m_startCentroid;
+ qreal m_startDistance;
+
+ QVector<PointData> m_startAngles;
+ QMatrix4x4 m_startMatrix;
+ QQuickMatrix4x4 m_transform;
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPinchHandler)
+
+#endif // QQUICKPINCHHANDLER_H
diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp
new file mode 100644
index 0000000000..03704ac09e
--- /dev/null
+++ b/src/quick/handlers/qquickpointerdevicehandler.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpointerdevicehandler_p.h"
+#include <private/qquickitem_p.h>
+#include <QMouseEvent>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ An intermediate class (not registered as a QML type)
+ for handlers which allow filtering based on device type,
+ pointer type, or device-specific buttons (such as mouse or stylus buttons).
+ */
+QQuickPointerDeviceHandler::QQuickPointerDeviceHandler(QObject *parent)
+ : QQuickPointerHandler(parent)
+ , m_acceptedDevices(QQuickPointerDevice::AllDevices)
+ , m_acceptedPointerTypes(QQuickPointerDevice::AllPointerTypes)
+ , m_acceptedButtons(Qt::AllButtons)
+{
+}
+
+QQuickPointerDeviceHandler::~QQuickPointerDeviceHandler()
+{
+}
+
+void QQuickPointerDeviceHandler::setAcceptedDevices(QQuickPointerDevice::DeviceTypes acceptedDevices)
+{
+ if (m_acceptedDevices == acceptedDevices)
+ return;
+
+ m_acceptedDevices = acceptedDevices;
+ emit acceptedDevicesChanged();
+}
+
+void QQuickPointerDeviceHandler::setAcceptedPointerTypes(QQuickPointerDevice::PointerTypes acceptedPointerTypes)
+{
+ if (m_acceptedPointerTypes == acceptedPointerTypes)
+ return;
+
+ m_acceptedPointerTypes = acceptedPointerTypes;
+ emit acceptedPointerTypesChanged();
+}
+
+void QQuickPointerDeviceHandler::setAcceptedButtons(Qt::MouseButtons buttons)
+{
+ if (m_acceptedButtons == buttons)
+ return;
+
+ m_acceptedButtons = buttons;
+ emit acceptedButtonsChanged();
+}
+
+bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event)
+{
+ if (!QQuickPointerHandler::wantsPointerEvent(event))
+ return false;
+ qCDebug(lcPointerHandlerDispatch) << objectName()
+ << "checking device type" << m_acceptedDevices
+ << "pointer type" << m_acceptedPointerTypes
+ << "buttons" << m_acceptedButtons;
+ if ((event->device()->type() & m_acceptedDevices) == 0)
+ return false;
+ if ((event->device()->pointerType() & m_acceptedPointerTypes) == 0)
+ return false;
+ if (event->device()->pointerType() != QQuickPointerDevice::Finger &&
+ (event->buttons() & m_acceptedButtons) == 0 && (event->button() & m_acceptedButtons) == 0)
+ return false;
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointerdevicehandler_p.h b/src/quick/handlers/qquickpointerdevicehandler_p.h
new file mode 100644
index 0000000000..bb12d3ccdb
--- /dev/null
+++ b/src/quick/handlers/qquickpointerdevicehandler_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOINTERDEVICEHANDLER_H
+#define QQUICKPOINTERDEVICEHANDLER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickpointerhandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickPointerDeviceHandler : public QQuickPointerHandler
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickPointerDevice::DeviceTypes acceptedDevices READ acceptedDevices WRITE setAcceptedDevices NOTIFY acceptedDevicesChanged)
+ Q_PROPERTY(QQuickPointerDevice::PointerTypes acceptedPointerTypes READ acceptedPointerTypes WRITE setAcceptedPointerTypes NOTIFY acceptedPointerTypesChanged)
+ Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
+
+public:
+ QQuickPointerDeviceHandler(QObject *parent = 0);
+ ~QQuickPointerDeviceHandler();
+
+ QQuickPointerDevice::DeviceTypes acceptedDevices() const { return m_acceptedDevices; }
+ QQuickPointerDevice::PointerTypes acceptedPointerTypes() const { return m_acceptedPointerTypes; }
+ Qt::MouseButtons acceptedButtons() const { return m_acceptedButtons; }
+
+public slots:
+ void setAcceptedDevices(QQuickPointerDevice::DeviceTypes acceptedDevices);
+ void setAcceptedPointerTypes(QQuickPointerDevice::PointerTypes acceptedPointerTypes);
+ void setAcceptedButtons(Qt::MouseButtons buttons);
+
+Q_SIGNALS:
+ void acceptedDevicesChanged();
+ void acceptedPointerTypesChanged();
+ void acceptedButtonsChanged();
+
+protected:
+ bool wantsPointerEvent(QQuickPointerEvent *event) override;
+ void setPressed(bool pressed);
+
+protected:
+ QQuickPointerDevice::DeviceTypes m_acceptedDevices;
+ QQuickPointerDevice::PointerTypes m_acceptedPointerTypes;
+ Qt::MouseButtons m_acceptedButtons;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPointerDeviceHandler)
+
+#endif // QQUICKPOINTERDEVICEHANDLER_H
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
new file mode 100644
index 0000000000..6225d2a24a
--- /dev/null
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpointerhandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcPointerHandlerDispatch, "qt.quick.handler.dispatch")
+
+/*!
+ \qmltype PointerHandler
+ \instantiates QQuickPointerHandler
+ \inqmlmodule QtQuick
+ \ingroup qtquick-handlers
+ \brief Handler for pointer events
+
+ PointerHandler is a handler for pointer events regardless of source.
+ They may represent events from a touch, mouse or tablet device.
+*/
+
+QQuickPointerHandler::QQuickPointerHandler(QObject *parent)
+ : QObject(parent)
+ , m_currentEvent(nullptr)
+ , m_target(nullptr)
+ , m_enabled(true)
+ , m_active(false)
+{
+}
+
+void QQuickPointerHandler::setGrab(QQuickEventPoint *point, bool grab)
+{
+ if (grab) {
+ QQuickPointerHandler *oldGrabber = point->grabberPointerHandler();
+ if (oldGrabber && oldGrabber != this)
+ oldGrabber->handleGrabCancel(point);
+ point->setGrabberPointerHandler(this);
+ onGrabChanged(point);
+ emit grabChanged(point);
+ } else if (point->grabberPointerHandler() == this) {
+ point->setGrabberPointerHandler(nullptr);
+ onGrabChanged(point);
+ emit grabChanged(point);
+ }
+}
+
+QPointF QQuickPointerHandler::eventPos(const QQuickEventPoint *point) const
+{
+ return (m_target ? m_target->mapFromScene(point->scenePos()) : point->scenePos());
+}
+
+bool QQuickPointerHandler::targetContains(const QQuickEventPoint *point) const
+{
+ if (!m_target || !point)
+ return false;
+ return m_target->contains(m_target->mapFromScene(point->scenePos()));
+}
+
+/*!
+ \qmlproperty QQuickPointerHandler::enabled
+
+ If a PointerHandler is disabled, it will reject all events
+ and no signals will be emitted.
+
+ TODO is it too extreme not even to emit pressed/updated/released?
+ or should we disable only the higher-level interpretation, in subclasses?
+*/
+void QQuickPointerHandler::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ m_enabled = enabled;
+ emit enabledChanged();
+}
+
+void QQuickPointerHandler::setTarget(QQuickItem *target)
+{
+ if (m_target == target)
+ return;
+
+ if (m_target) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(m_target);
+ p->extra.value().pointerHandlers.removeOne(this);
+ }
+
+ m_target = target;
+ if (m_target) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(m_target);
+ p->extra.value().pointerHandlers.append(this);
+ // Accept all buttons, and leave filtering to pointerEvent() and/or user JS,
+ // because there can be multiple handlers...
+ m_target->setAcceptedMouseButtons(Qt::AllButtons);
+ }
+ emit targetChanged();
+}
+
+void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event)
+{
+ const bool wants = wantsPointerEvent(event);
+ setActive(wants);
+ if (wants)
+ handlePointerEventImpl(event);
+ else
+ setActive(false);
+}
+
+void QQuickPointerHandler::handleGrabCancel(QQuickEventPoint *point)
+{
+ qCDebug(lcPointerHandlerDispatch) << point;
+ Q_ASSERT(point);
+ setActive(false);
+ point->setAccepted(false);
+ emit canceled(point);
+}
+
+bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event)
+{
+ Q_UNUSED(event)
+ return m_enabled;
+}
+
+void QQuickPointerHandler::setActive(bool active)
+{
+ if (m_active != active) {
+ m_active = active;
+ onActiveChanged();
+ emit activeChanged();
+ }
+}
+
+void QQuickPointerHandler::handlePointerEventImpl(QQuickPointerEvent *event)
+{
+ m_currentEvent = event;
+}
+
+/*!
+ \qmlproperty QQuickPointerHandler::parent
+
+ The \l Item which is the scope of the handler; the Item in which it was declared.
+ The handler will handle events on behalf of this Item, which means a
+ pointer event is relevant if at least one of its event points occurs within
+ the Item's interior. Initially \l target() is the same, but target()
+ can be reassigned.
+
+ \sa QQuickPointerHandler::target(), QObject::parent()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointerhandler_p.h b/src/quick/handlers/qquickpointerhandler_p.h
new file mode 100644
index 0000000000..9595897d72
--- /dev/null
+++ b/src/quick/handlers/qquickpointerhandler_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOINTERHANDLER_H
+#define QQUICKPOINTERHANDLER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qevent.h"
+
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcPointerHandlerDispatch)
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerHandler : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool active READ active NOTIFY activeChanged)
+ Q_PROPERTY(QQuickItem * target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QQuickItem * parent READ parentItem CONSTANT)
+
+public:
+ QQuickPointerHandler(QObject *parent = 0);
+ virtual ~QQuickPointerHandler() { }
+
+public:
+ bool enabled() const { return m_enabled; }
+ void setEnabled(bool enabled);
+
+ bool active() const { return m_active; }
+
+ QQuickItem *target() const { return m_target; }
+ void setTarget(QQuickItem *target);
+
+ QQuickItem * parentItem() const { return static_cast<QQuickItem *>(QObject::parent()); }
+
+ void handlePointerEvent(QQuickPointerEvent *event);
+
+Q_SIGNALS:
+ void enabledChanged();
+ void activeChanged();
+ void targetChanged();
+ void grabChanged(QQuickEventPoint *point);
+ void canceled(QQuickEventPoint *point);
+
+protected:
+ QQuickPointerEvent *currentEvent() { return m_currentEvent; }
+ virtual bool wantsPointerEvent(QQuickPointerEvent *event);
+ virtual void handlePointerEventImpl(QQuickPointerEvent *event);
+ void setActive(bool active);
+ virtual void onActiveChanged() { }
+ virtual void onGrabChanged(QQuickEventPoint *) { }
+ void setGrab(QQuickEventPoint *point, bool grab);
+ virtual void handleGrabCancel(QQuickEventPoint *point);
+ QPointF eventPos(const QQuickEventPoint *point) const;
+ bool targetContains(const QQuickEventPoint *point) const;
+
+private:
+ QQuickPointerEvent *m_currentEvent;
+ QQuickItem *m_target;
+ bool m_enabled : 1;
+ bool m_active : 1;
+
+ friend class QQuickEventPoint;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPointerHandler)
+
+#endif // QQUICKPOINTERHANDLER_H
diff --git a/src/quick/handlers/qquickpointersinglehandler.cpp b/src/quick/handlers/qquickpointersinglehandler.cpp
new file mode 100644
index 0000000000..d97348ea22
--- /dev/null
+++ b/src/quick/handlers/qquickpointersinglehandler.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpointersinglehandler_p.h"
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET)
+
+/*!
+ An intermediate class (not registered as a QML type)
+ for the most common handlers: those which expect only a single point.
+ wantsPointerEvent() will choose the first point which is inside the
+ \l target item, and return true as long as the event contains that point.
+ Override handleEventPoint() to implement a single-point handler.
+*/
+
+QQuickPointerSingleHandler::QQuickPointerSingleHandler(QObject *parent)
+ : QQuickPointerDeviceHandler(parent)
+ , m_currentPointId(0)
+{
+}
+
+bool QQuickPointerSingleHandler::wantsPointerEvent(QQuickPointerEvent *event)
+{
+ if (!QQuickPointerDeviceHandler::wantsPointerEvent(event))
+ return false;
+ if (m_currentPointId) {
+ // We already know which one we want, so check whether it's there.
+ // It's expected to be an update or a release.
+ // If we no longer want it, cancel the grab.
+ if (auto point = event->pointById(m_currentPointId)) {
+ if (wantsEventPoint(point)) {
+ point->setAccepted();
+ return true;
+ } else if (point->grabber() == this) {
+ point->cancelGrab();
+ }
+ } else {
+ qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << m_currentPointId
+ << "is missing from current event, but was neither canceled nor released";
+ return false;
+ }
+ } else {
+ // We have not yet chosen a point; choose the first one for which wantsEventPoint() returns true.
+ int c = event->pointCount();
+ for (int i = 0; i < c && !m_currentPointId; ++i) {
+ QQuickEventPoint *p = event->point(i);
+ if (!p->grabber() && wantsEventPoint(p)) {
+ m_currentPointId = p->pointId();
+ p->setAccepted();
+ }
+ }
+ }
+ return m_currentPointId;
+}
+
+void QQuickPointerSingleHandler::handlePointerEventImpl(QQuickPointerEvent *event)
+{
+ QQuickPointerDeviceHandler::handlePointerEventImpl(event);
+ QQuickEventPoint *currentPoint = event->pointById(m_currentPointId);
+ Q_ASSERT(currentPoint);
+ if (!m_currentPointId || !currentPoint->isAccepted()) {
+ m_currentPointId = 0;
+ setPressedButtons(Qt::NoButton);
+ } else {
+ setPressedButtons(event->buttons());
+ handleEventPoint(currentPoint);
+ }
+ bool grab = currentPoint->isAccepted() && currentPoint->state() != QQuickEventPoint::Released;
+ setGrab(currentPoint, grab);
+ if (!grab)
+ m_currentPointId = 0;
+}
+
+bool QQuickPointerSingleHandler::wantsEventPoint(QQuickEventPoint *point)
+{
+ return targetContains(point);
+}
+
+void QQuickPointerSingleHandler::handleGrabCancel(QQuickEventPoint *point)
+{
+ QQuickPointerHandler::handleGrabCancel(point);
+ m_currentPointId = 0;
+ setPressedButtons(Qt::NoButton);
+}
+
+void QQuickPointerSingleHandler::setPressedButtons(Qt::MouseButtons buttons)
+{
+ if (buttons != m_pressedButtons) {
+ m_pressedButtons = buttons;
+ emit pressedButtonsChanged();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointersinglehandler_p.h b/src/quick/handlers/qquickpointersinglehandler_p.h
new file mode 100644
index 0000000000..69a3263271
--- /dev/null
+++ b/src/quick/handlers/qquickpointersinglehandler_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOINTERSINGLEHANDLER_H
+#define QQUICKPOINTERSINGLEHANDLER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickpointerdevicehandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerSingleHandler : public QQuickPointerDeviceHandler
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedButtonsChanged)
+
+public:
+ QQuickPointerSingleHandler(QObject *parent = 0);
+ virtual ~QQuickPointerSingleHandler() { }
+
+ Qt::MouseButtons pressedButtons() const { return m_pressedButtons; }
+
+signals:
+ void pressedButtonsChanged();
+
+protected:
+ bool wantsPointerEvent(QQuickPointerEvent *event) override;
+ virtual bool wantsEventPoint(QQuickEventPoint *point);
+ void handlePointerEventImpl(QQuickPointerEvent *event) override;
+ virtual void handleEventPoint(QQuickEventPoint *point) = 0;
+ quint64 currentPointId() const { return m_currentPointId; }
+ QQuickEventPoint *currentPoint(QQuickPointerEvent *ev) { return ev->pointById(m_currentPointId); }
+ void handleGrabCancel(QQuickEventPoint *point) override;
+
+private:
+ void setPressedButtons(Qt::MouseButtons buttons);
+
+private:
+ quint64 m_currentPointId;
+ Qt::MouseButtons m_pressedButtons;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPointerSingleHandler)
+
+#endif // QQUICKPOINTERSINGLEHANDLER_H
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 42588fd058..f8038ed11f 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -40,6 +40,7 @@
#include "qquickevents_p_p.h"
#include <QtGui/private/qguiapplication_p.h>
#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquickwindow_p.h>
#include <private/qdebug_p.h>
@@ -447,7 +448,15 @@ Item {
typedef QHash<QTouchDevice *, QQuickPointerDevice *> PointerDeviceForTouchDeviceHash;
Q_GLOBAL_STATIC(PointerDeviceForTouchDeviceHash, g_touchDevices)
-Q_GLOBAL_STATIC_WITH_ARGS(QQuickPointerDevice, g_genericMouseDevice,
+struct ConstructableQQuickPointerDevice : public QQuickPointerDevice
+{
+ ConstructableQQuickPointerDevice(DeviceType devType, PointerType pType, Capabilities caps,
+ int maxPoints, int buttonCount, const QString &name,
+ qint64 uniqueId = 0)
+ : QQuickPointerDevice(devType, pType, caps, maxPoints, buttonCount, name, uniqueId) {}
+
+};
+Q_GLOBAL_STATIC_WITH_ARGS(ConstructableQQuickPointerDevice, g_genericMouseDevice,
(QQuickPointerDevice::Mouse,
QQuickPointerDevice::GenericPointer,
QQuickPointerDevice::Position | QQuickPointerDevice::Scroll | QQuickPointerDevice::Hover,
@@ -504,35 +513,108 @@ QQuickPointerDevice *QQuickPointerDevice::tabletDevice(qint64 id)
return nullptr;
}
-void QQuickEventPoint::reset(Qt::TouchPointState state, QPointF scenePos, quint64 pointId, ulong timestamp)
+void QQuickEventPoint::reset(Qt::TouchPointState state, const QPointF &scenePos, quint64 pointId, ulong timestamp, const QVector2D &velocity)
{
m_scenePos = scenePos;
- m_pointId = pointId;
+ if (m_pointId != pointId) {
+ if (m_grabber) {
+ qWarning() << m_grabber << "failed to ungrab previous point" << m_pointId;
+ cancelGrab();
+ }
+ m_pointId = pointId;
+ }
m_valid = true;
m_accept = false;
m_state = static_cast<QQuickEventPoint::State>(state);
m_timestamp = timestamp;
- if (state == Qt::TouchPointPressed)
+ if (state == Qt::TouchPointPressed) {
m_pressTimestamp = timestamp;
- // TODO calculate velocity
+ m_scenePressPos = scenePos;
+ }
+ // TODO if Q_LIKELY(velocity.isNull) calculate velocity
+ m_velocity = velocity;
}
-QQuickItem *QQuickEventPoint::grabber() const
+void QQuickEventPoint::localize(QQuickItem *target)
+{
+ if (target)
+ m_pos = target->mapFromScene(scenePos());
+ else
+ m_pos = QPointF();
+}
+
+void QQuickEventPoint::invalidate()
+{
+ m_valid = false;
+ m_pointId = 0;
+}
+
+QObject *QQuickEventPoint::grabber() const
{
return m_grabber.data();
}
-void QQuickEventPoint::setGrabber(QQuickItem *grabber)
+void QQuickEventPoint::setGrabber(QObject *grabber)
+{
+ if (QQuickPointerHandler *phGrabber = qmlobject_cast<QQuickPointerHandler *>(grabber))
+ setGrabberPointerHandler(phGrabber);
+ else
+ setGrabberItem(static_cast<QQuickItem *>(grabber));
+}
+
+QQuickItem *QQuickEventPoint::grabberItem() const
+{
+ return (m_grabberIsHandler ? nullptr : static_cast<QQuickItem *>(m_grabber.data()));
+}
+
+void QQuickEventPoint::setGrabberItem(QQuickItem *grabber)
{
- if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled()) && m_grabber.data() != grabber) {
- auto device = static_cast<const QQuickPointerEvent *>(parent())->device();
- static const QMetaEnum stateMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("State"));
- QString deviceName = (device ? device->name() : QLatin1String("null device"));
- deviceName.resize(16, ' '); // shorten, and align in case of sequential output
- qCDebug(lcPointerGrab) << deviceName << "point" << hex << m_pointId << stateMetaEnum.valueToKey(state())
- << ": grab" << m_grabber << "->" << grabber;
+ if (grabber != m_grabber.data()) {
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ auto device = static_cast<const QQuickPointerEvent *>(parent())->device();
+ static const QMetaEnum stateMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("State"));
+ QString deviceName = (device ? device->name() : QLatin1String("null device"));
+ deviceName.resize(16, ' '); // shorten, and align in case of sequential output
+ qCDebug(lcPointerGrab) << deviceName << "point" << hex << m_pointId << stateMetaEnum.valueToKey(state())
+ << ": grab" << m_grabber << "->" << grabber;
+ }
+ m_grabber = QPointer<QObject>(grabber);
+ m_grabberIsHandler = false;
+ m_sceneGrabPos = m_scenePos;
+ }
+}
+
+QQuickPointerHandler *QQuickEventPoint::grabberPointerHandler() const
+{
+ return (m_grabberIsHandler ? static_cast<QQuickPointerHandler *>(m_grabber.data()) : nullptr);
+}
+
+void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber)
+{
+ if (grabber != m_grabber.data()) {
+ if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
+ auto device = static_cast<const QQuickPointerEvent *>(parent())->device();
+ static const QMetaEnum stateMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("State"));
+ QString deviceName = (device ? device->name() : QLatin1String("null device"));
+ deviceName.resize(16, ' '); // shorten, and align in case of sequential output
+ qCDebug(lcPointerGrab) << deviceName << "point" << hex << m_pointId << stateMetaEnum.valueToKey(state())
+ << ": grab" << m_grabber << "->" << grabber;
+ }
+ m_grabber = QPointer<QObject>(grabber);
+ m_grabberIsHandler = true;
+ m_sceneGrabPos = m_scenePos;
}
- m_grabber = QPointer<QQuickItem>(grabber);
+}
+
+void QQuickEventPoint::cancelGrab()
+{
+ if (m_grabber.isNull()) {
+ qWarning("cancelGrab: no grabber");
+ return;
+ }
+ if (auto handler = grabberPointerHandler())
+ handler->handleGrabCancel(this);
+ m_grabber.clear();
}
void QQuickEventPoint::setAccepted(bool accepted)
@@ -549,7 +631,7 @@ QQuickEventTouchPoint::QQuickEventTouchPoint(QQuickPointerTouchEvent *parent)
void QQuickEventTouchPoint::reset(const QTouchEvent::TouchPoint &tp, ulong timestamp)
{
- QQuickEventPoint::reset(tp.state(), tp.scenePos(), tp.id(), timestamp);
+ QQuickEventPoint::reset(tp.state(), tp.scenePos(), tp.id(), timestamp, tp.velocity());
m_rotation = tp.rotation();
m_pressure = tp.pressure();
// m_uniqueId = tp.uniqueId();
@@ -597,10 +679,15 @@ QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
default:
break;
}
- m_mousePoint->reset(state, ev->windowPos(), 0, ev->timestamp()); // mouse is 0
+ m_mousePoint->reset(state, ev->windowPos(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
return this;
}
+void QQuickPointerMouseEvent::localize(QQuickItem *target)
+{
+ m_mousePoint->localize(target);
+}
+
QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
{
auto ev = static_cast<QTouchEvent*>(event);
@@ -620,11 +707,11 @@ QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
m_touchPoints.insert(i, new QQuickEventTouchPoint(this));
// Make sure the grabbers are right from one event to the next
- QVector<QQuickItem*> grabbers;
+ QVector<QObject*> grabbers;
// Copy all grabbers, because the order of points might have changed in the event.
// The ID is all that we can rely on (release might remove the first point etc).
for (int i = 0; i < newPointCount; ++i) {
- QQuickItem *grabber = nullptr;
+ QObject *grabber = nullptr;
if (auto point = pointById(tps.at(i).id()))
grabber = point->grabber();
grabbers.append(grabber);
@@ -636,7 +723,7 @@ QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
if (point->state() == QQuickEventPoint::Pressed) {
if (grabbers.at(i))
qWarning() << "TouchPointPressed without previous release event" << point;
- point->setGrabber(nullptr);
+ point->setGrabberItem(nullptr);
} else {
point->setGrabber(grabbers.at(i));
}
@@ -645,6 +732,12 @@ QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
return this;
}
+void QQuickPointerTouchEvent::localize(QQuickItem *target)
+{
+ for (auto point : qAsConst(m_touchPoints))
+ point->localize(target);
+}
+
QQuickEventPoint *QQuickPointerMouseEvent::point(int i) const {
if (i == 0)
return m_mousePoint;
@@ -659,7 +752,7 @@ QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const {
QQuickEventPoint::QQuickEventPoint(QQuickPointerEvent *parent)
: QObject(parent), m_pointId(0), m_grabber(nullptr), m_timestamp(0), m_pressTimestamp(0),
- m_state(QQuickEventPoint::Released), m_valid(false), m_accept(false)
+ m_state(QQuickEventPoint::Released), m_valid(false), m_accept(false), m_grabberIsHandler(false)
{
Q_UNUSED(m_reserved);
}
@@ -680,16 +773,16 @@ QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) cons
return event;
}
-QVector<QQuickItem *> QQuickPointerMouseEvent::grabbers() const
+QVector<QObject *> QQuickPointerMouseEvent::grabbers() const
{
- QVector<QQuickItem *> result;
- if (QQuickItem *grabber = m_mousePoint->grabber())
+ QVector<QObject *> result;
+ if (QObject *grabber = m_mousePoint->grabber())
result << grabber;
return result;
}
void QQuickPointerMouseEvent::clearGrabbers() const {
- m_mousePoint->setGrabber(nullptr);
+ m_mousePoint->setGrabberItem(nullptr);
}
bool QQuickPointerMouseEvent::isPressEvent() const
@@ -707,12 +800,12 @@ bool QQuickPointerTouchEvent::allPointsAccepted() const {
return true;
}
-QVector<QQuickItem *> QQuickPointerTouchEvent::grabbers() const
+QVector<QObject *> QQuickPointerTouchEvent::grabbers() const
{
- QVector<QQuickItem *> result;
+ QVector<QObject *> result;
for (int i = 0; i < m_pointCount; ++i) {
auto point = m_touchPoints.at(i);
- if (QQuickItem *grabber = point->grabber()) {
+ if (QObject *grabber = point->grabber()) {
if (!result.contains(grabber))
result << grabber;
}
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 6179791413..e8bc307b1a 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -68,6 +68,7 @@ class QQuickPointerEvent;
class QQuickPointerMouseEvent;
class QQuickPointerTabletEvent;
class QQuickPointerTouchEvent;
+class QQuickPointerHandler;
class QQuickKeyEvent : public QObject
{
@@ -249,12 +250,17 @@ private:
class Q_QUICK_PRIVATE_EXPORT QQuickEventPoint : public QObject
{
Q_OBJECT
+ Q_PROPERTY(QQuickPointerEvent *event READ pointerEvent)
+ Q_PROPERTY(QPointF pos READ pos)
Q_PROPERTY(QPointF scenePos READ scenePos)
+ Q_PROPERTY(QPointF scenePressPos READ scenePressPos)
+ Q_PROPERTY(QPointF sceneGrabPos READ sceneGrabPos)
+ Q_PROPERTY(QVector2D velocity READ velocity)
Q_PROPERTY(State state READ state)
Q_PROPERTY(quint64 pointId READ pointId)
Q_PROPERTY(qreal timeHeld READ timeHeld)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
- Q_PROPERTY(QQuickItem *grabber READ grabber WRITE setGrabber)
+ Q_PROPERTY(QObject *grabber READ grabber WRITE setGrabber)
public:
enum State {
@@ -268,31 +274,49 @@ public:
QQuickEventPoint(QQuickPointerEvent *parent);
- void reset(Qt::TouchPointState state, QPointF scenePos, quint64 pointId, ulong timestamp);
+ void reset(Qt::TouchPointState state, const QPointF &scenePos, quint64 pointId, ulong timestamp, const QVector2D &velocity = QVector2D());
+ void localize(QQuickItem *target);
- void invalidate() { m_valid = false; }
+ void invalidate();
QQuickPointerEvent *pointerEvent() const;
+ QPointF pos() const { return m_pos; }
QPointF scenePos() const { return m_scenePos; }
+ QPointF scenePressPos() const { return m_scenePressPos; }
+ QPointF sceneGrabPos() const { return m_sceneGrabPos; }
+ QVector2D velocity() const { return m_velocity; }
State state() const { return m_state; }
quint64 pointId() const { return m_pointId; }
bool isValid() const { return m_valid; }
qreal timeHeld() const { return (m_timestamp - m_pressTimestamp) / 1000.0; }
bool isAccepted() const { return m_accept; }
void setAccepted(bool accepted = true);
- QQuickItem *grabber() const;
- void setGrabber(QQuickItem *grabber);
+ QObject *grabber() const;
+ void setGrabber(QObject *grabber);
+
+ QQuickItem *grabberItem() const;
+ void setGrabberItem(QQuickItem *grabber);
+
+ QQuickPointerHandler *grabberPointerHandler() const;
+ void setGrabberPointerHandler(QQuickPointerHandler *grabber);
+
+ Q_INVOKABLE void cancelGrab();
private:
+ QPointF m_pos;
QPointF m_scenePos;
+ QPointF m_scenePressPos;
+ QPointF m_sceneGrabPos;
+ QVector2D m_velocity;
quint64 m_pointId;
- QPointer<QQuickItem> m_grabber;
+ QPointer<QObject> m_grabber;
ulong m_timestamp;
ulong m_pressTimestamp;
State m_state;
bool m_valid : 1;
bool m_accept : 1;
- int m_reserved : 30;
+ bool m_grabberIsHandler : 1;
+ int m_reserved : 29;
Q_DISABLE_COPY(QQuickEventPoint)
};
@@ -349,6 +373,7 @@ public: // property accessors
public: // helpers for C++ only (during event delivery)
virtual QQuickPointerEvent *reset(QEvent *ev) = 0;
+ virtual void localize(QQuickItem *target) = 0;
virtual bool isPressEvent() const = 0;
virtual QQuickPointerMouseEvent *asPointerMouseEvent() { return nullptr; }
@@ -366,7 +391,7 @@ public: // helpers for C++ only (during event delivery)
virtual int pointCount() const = 0;
virtual QQuickEventPoint *point(int i) const = 0;
virtual QQuickEventPoint *pointById(quint64 pointId) const = 0;
- virtual QVector<QQuickItem *> grabbers() const = 0;
+ virtual QVector<QObject *> grabbers() const = 0;
virtual void clearGrabbers() const = 0;
ulong timestamp() const { return m_event->timestamp(); }
@@ -388,6 +413,7 @@ public:
: QQuickPointerEvent(parent), m_mousePoint(new QQuickEventPoint(this)) { }
QQuickPointerEvent *reset(QEvent *) override;
+ void localize(QQuickItem *target) override;
bool isPressEvent() const override;
QQuickPointerMouseEvent *asPointerMouseEvent() override { return this; }
const QQuickPointerMouseEvent *asPointerMouseEvent() const override { return this; }
@@ -395,7 +421,7 @@ public:
QQuickEventPoint *point(int i) const override;
QQuickEventPoint *pointById(quint64 pointId) const override;
bool allPointsAccepted() const override;
- QVector<QQuickItem *> grabbers() const override;
+ QVector<QObject *> grabbers() const override;
void clearGrabbers() const override;
QMouseEvent *asMouseEvent(const QPointF& localPos) const;
@@ -417,6 +443,7 @@ public:
{ }
QQuickPointerEvent *reset(QEvent *) override;
+ void localize(QQuickItem *target) override;
bool isPressEvent() const override;
QQuickPointerTouchEvent *asPointerTouchEvent() override { return this; }
const QQuickPointerTouchEvent *asPointerTouchEvent() const override { return this; }
@@ -425,7 +452,7 @@ public:
QQuickEventPoint *pointById(quint64 pointId) const override;
const QTouchEvent::TouchPoint *touchPointById(int pointId) const;
bool allPointsAccepted() const override;
- QVector<QQuickItem *> grabbers() const override;
+ QVector<QObject *> grabbers() const override;
void clearGrabbers() const override;
QMouseEvent *syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const;
@@ -496,20 +523,7 @@ public:
Q_ENUM(CapabilityFlag)
Q_FLAG(Capabilities)
- QQuickPointerDevice(DeviceType devType, PointerType pType, Capabilities caps, int maxPoints, int buttonCount, const QString &name, qint64 uniqueId = 0)
- : m_deviceType(devType), m_pointerType(pType), m_capabilities(caps)
- , m_maximumTouchPoints(maxPoints), m_buttonCount(buttonCount), m_name(name), m_uniqueId(uniqueId), m_event(nullptr)
- {
- if (m_deviceType == Mouse) {
- m_event = new QQuickPointerMouseEvent;
- } else if (m_deviceType == TouchScreen || m_deviceType == TouchPad) {
- m_event = new QQuickPointerTouchEvent;
- } else {
- Q_ASSERT(false);
- }
- }
- ~QQuickPointerDevice() { delete m_event; }
DeviceType type() const { return m_deviceType; }
PointerType pointerType() const { return m_pointerType; }
Capabilities capabilities() const { return m_capabilities; }
@@ -526,6 +540,21 @@ public:
static QQuickPointerDevice *tabletDevice(qint64);
private:
+ QQuickPointerDevice(DeviceType devType, PointerType pType, Capabilities caps, int maxPoints, int buttonCount, const QString &name, qint64 uniqueId = 0)
+ : m_deviceType(devType), m_pointerType(pType), m_capabilities(caps)
+ , m_maximumTouchPoints(maxPoints), m_buttonCount(buttonCount), m_name(name), m_uniqueId(uniqueId), m_event(nullptr)
+ {
+ if (m_deviceType == Mouse) {
+ m_event = new QQuickPointerMouseEvent;
+ } else if (m_deviceType == TouchScreen || m_deviceType == TouchPad) {
+ m_event = new QQuickPointerTouchEvent;
+ } else {
+ Q_ASSERT(false);
+ }
+ }
+ ~QQuickPointerDevice() { delete m_event; }
+
+private:
DeviceType m_deviceType;
PointerType m_pointerType;
Capabilities m_capabilities;
@@ -537,6 +566,7 @@ private:
QQuickPointerEvent *m_event;
Q_DISABLE_COPY(QQuickPointerDevice)
+ friend struct ConstructableQQuickPointerDevice;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickPointerDevice::DeviceTypes)
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 00a1306627..5561f8d976 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -44,6 +44,7 @@
#include "qquickwindow_p.h"
#include "qquickevents_p_p.h"
+#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquicktransition_p.h>
#include <private/qqmlglobal_p.h>
@@ -1784,6 +1785,8 @@ void QQuickFlickablePrivate::data_append(QQmlListProperty<QObject> *prop, QObjec
i->setParentItem(static_cast<QQuickFlickablePrivate*>(prop->data)->contentItem);
} else {
o->setParent(prop->object); // XXX todo - do we want this?
+ if (QQuickPointerHandler *pointerHandler = qmlobject_cast<QQuickPointerHandler *>(o))
+ pointerHandler->setTarget(static_cast<QQuickItem *>(prop->object));
}
}
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 504446a8be..97a4e51def 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -67,6 +67,7 @@
#include <QtQuick/private/qquickstate_p.h>
#include <private/qquickitem_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
+#include <QtQuick/private/qquickpointerhandler_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4object_p.h>
@@ -86,6 +87,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE_TARGET)
Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
+Q_DECLARE_LOGGING_CATEGORY(lcPointerHandlerDispatch)
void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
{
@@ -3219,7 +3221,9 @@ void QQuickItemPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
} else {
if (o->inherits("QGraphicsItem"))
qWarning("Cannot add a QtQuick 1.0 item (%s) into a QtQuick 2.0 scene!", o->metaObject()->className());
- else {
+ else if (QQuickPointerHandler *pointerHandler = qmlobject_cast<QQuickPointerHandler *>(o)) {
+ pointerHandler->setTarget(that);
+ } else {
QQuickWindow *thisWindow = qmlobject_cast<QQuickWindow *>(o);
QQuickItem *item = that;
QQuickWindow *itemWindow = that->window();
@@ -5082,6 +5086,17 @@ void QQuickItemPrivate::deliverShortcutOverrideEvent(QKeyEvent *event)
}
}
+void QQuickItemPrivate::handlePointerEvent(QQuickPointerEvent *event)
+{
+ Q_Q(QQuickItem);
+ if (extra.isAllocated()) {
+ for (QQuickPointerHandler *handler : extra->pointerHandlers) {
+ qCDebug(lcPointerHandlerDispatch) << " delivering" << event << "to" << handler << "on" << q;
+ handler->handlePointerEvent(event);
+ }
+ }
+}
+
/*!
Called when \a change occurs for this item.
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index c0c9bd46bd..e7ead7fa87 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -87,6 +87,7 @@ class QQuickItemKeyFilter;
class QQuickLayoutMirroringAttached;
class QQuickEnterKeyAttached;
class QQuickScreenAttached;
+class QQuickPointerHandler;
class QQuickContents : public QQuickItemChangeListener
{
@@ -344,6 +345,7 @@ public:
QQuickLayoutMirroringAttached* layoutDirectionAttached;
QQuickEnterKeyAttached *enterKeyAttached;
QQuickItemKeyFilter *keyHandler;
+ QVector<QQuickPointerHandler *> pointerHandlers;
#if QT_CONFIG(quick_shadereffect)
mutable QQuickItemLayer *layer;
#endif
@@ -561,6 +563,8 @@ public:
#endif
void deliverShortcutOverrideEvent(QKeyEvent *);
+ virtual void handlePointerEvent(QQuickPointerEvent *);
+
bool isTransparentForPositioner() const;
void setTransparentForPositioner(bool trans);
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 07d87989b5..96c2937038 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -46,6 +46,7 @@
#include "qquickevents_p_p.h"
#include <private/qquickdrag_p.h>
+#include <private/qquickpointerhandler_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgtexture_p.h>
@@ -659,7 +660,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
if (!q->mouseGrabberItem())
item->grabMouse();
auto pointerEventPoint = pointerEvent->pointById(p.id());
- pointerEventPoint->setGrabber(item);
+ pointerEventPoint->setGrabberItem(item);
if (checkIfDoubleClicked(event->timestamp())) {
QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item, false));
@@ -747,11 +748,11 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << touchMouseId << "->" << q->mouseGrabberItem();
auto point = touchMouseDevice->pointerEvent()->pointById(touchMouseId);
if (point)
- point->setGrabber(grabber);
+ point->setGrabberItem(grabber);
} else {
QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent();
Q_ASSERT(event->pointCount() == 1);
- event->point(0)->setGrabber(grabber);
+ event->point(0)->setGrabberItem(grabber);
}
if (oldGrabber) {
@@ -762,9 +763,9 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
}
}
-void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVector<int> &ids)
+void QQuickWindowPrivate::grabTouchPoints(QObject *grabber, const QVector<int> &ids)
{
- QSet<QQuickItem*> ungrab;
+ QSet<QObject*> ungrab;
for (int i = 0; i < ids.count(); ++i) {
// FIXME: deprecate this function, we need a device
int id = ids.at(i);
@@ -774,7 +775,7 @@ void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVector<int
}
if (id == touchMouseId) {
auto point = touchMouseDevice->pointerEvent()->pointById(id);
- auto touchMouseGrabber = point->grabber();
+ auto touchMouseGrabber = point->grabberItem();
if (touchMouseGrabber) {
point->setGrabber(nullptr);
touchMouseGrabber->mouseUngrabEvent();
@@ -790,7 +791,7 @@ void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVector<int
auto point = device->pointerEvent()->pointById(id);
if (!point)
continue;
- QQuickItem *oldGrabber = point->grabber();
+ QObject *oldGrabber = point->grabber();
if (oldGrabber == grabber)
continue;
@@ -799,8 +800,10 @@ void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVector<int
ungrab.insert(oldGrabber);
}
}
- for (QQuickItem *oldGrabber : qAsConst(ungrab))
- oldGrabber->touchUngrabEvent();
+ for (QObject *oldGrabber : qAsConst(ungrab))
+ if (QQuickItem *item = qmlobject_cast<QQuickItem *>(oldGrabber))
+ item->touchUngrabEvent();
+ // TODO else if the old grabber was a PointerHandler, notify it somehow?
}
void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool touch)
@@ -812,7 +815,7 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to
auto pointerEvent = device->pointerEvent();
for (int i = 0; i < pointerEvent->pointCount(); ++i) {
if (pointerEvent->point(i)->grabber() == grabber) {
- pointerEvent->point(i)->setGrabber(nullptr);
+ pointerEvent->point(i)->setGrabberItem(nullptr);
// FIXME send ungrab event only once
grabber->touchUngrabEvent();
}
@@ -1485,12 +1488,12 @@ QQuickItem *QQuickWindow::mouseGrabberItem() const
QQuickPointerEvent *event = d->touchMouseDevice->pointerEvent();
auto point = event->pointById(d->touchMouseId);
Q_ASSERT(point);
- return point->grabber();
+ return point->grabberItem();
}
QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent();
Q_ASSERT(event->pointCount());
- return event->point(0)->grabber();
+ return event->point(0)->grabberItem();
}
@@ -1642,7 +1645,13 @@ void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEven
Q_Q(QQuickWindow);
auto point = pointerEvent->point(0);
lastMousePosition = point->scenePos();
- QQuickItem *grabber = point->grabber();
+
+ if (point->grabberPointerHandler()) {
+ point->grabberPointerHandler()->handlePointerEvent(pointerEvent);
+ return;
+ }
+
+ QQuickItem *grabber = point->grabberItem();
if (grabber) {
// if the update consists of changing button state, then don't accept it
// unless the button is one in which the item is interested
@@ -1873,10 +1882,14 @@ bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event)
// A TouchCancel event will typically not contain any points.
// Deliver it to all items that have active touches.
QQuickPointerEvent *pointerEvent = QQuickPointerDevice::touchDevice(event->device())->pointerEvent();
- QVector<QQuickItem *> grabbers = pointerEvent->grabbers();
-
- for (QQuickItem *grabber: qAsConst(grabbers)) {
- q->sendEvent(grabber, event);
+ QVector<QObject *> grabbers = pointerEvent->grabbers();
+
+ for (QObject *grabber: qAsConst(grabbers)) {
+ if (QQuickItem *grabberItem = qmlobject_cast<QQuickItem *>(grabber))
+ q->sendEvent(grabberItem, event);
+ else //if (QQuickPointerHandler *grabberHandler = qmlobject_cast<QQuickPointerHandler *>(grabber))
+// grabberHandler->handlePointerEvent()
+ qWarning("unexpected: can't deliver touch cancel to a PointerHandler (yet?)");
}
touchMouseId = -1;
touchMouseDevice = nullptr;
@@ -2014,8 +2027,6 @@ void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
{
- Q_Q(QQuickWindow);
-
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
event->accept();
return;
@@ -2048,7 +2059,7 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
updateCursor(event->windowPos());
#endif
- if (!q->mouseGrabberItem()) {
+ if (!QQuickPointerDevice::genericMouseDevice()->pointerEvent()->point(0)->grabber()) {
QPointF last = lastMousePosition.isNull() ? event->windowPos() : lastMousePosition;
lastMousePosition = event->windowPos();
@@ -2216,7 +2227,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event)
if (point->state() == QQuickEventPoint::Released) {
int id = point->pointId();
qCDebug(DBG_TOUCH_TARGET) << "TP" << id << "released";
- point->setGrabber(nullptr);
+ point->setGrabberItem(nullptr);
if (id == touchMouseId) {
touchMouseId = -1;
touchMouseDevice = nullptr;
@@ -2236,8 +2247,14 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event)
bool QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event, QSet<QQuickItem *> *hasFiltered)
{
const auto grabbers = event->grabbers();
- for (auto grabber : grabbers)
- deliverMatchingPointsToItem(grabber, event, hasFiltered);
+ for (auto grabber : grabbers) {
+ // The grabber is guaranteed to be either an item or a handler, but
+ // we need the item in order to call deliverMatchingPointsToItem().
+ QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber);
+ if (!receiver)
+ receiver = static_cast<QQuickPointerHandler *>(grabber)->target();
+ deliverMatchingPointsToItem(receiver, event, hasFiltered);
+ }
return false;
}
@@ -2268,6 +2285,13 @@ bool QQuickWindowPrivate::deliverPressEvent(QQuickPointerEvent *event, QSet<QQui
bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent, QSet<QQuickItem *> *hasFiltered)
{
Q_Q(QQuickWindow);
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ pointerEvent->localize(item);
+
+ // Let the Item's handlers (if any) have the event first.
+ itemPrivate->handlePointerEvent(pointerEvent);
+ if (pointerEvent->allPointsAccepted())
+ return true;
// TODO: unite this mouse point delivery with the synthetic mouse event below
if (auto event = pointerEvent->asPointerMouseEvent()) {
@@ -2275,7 +2299,6 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
auto point = event->point(0);
if (point->isAccepted())
return false;
-
// The only reason to already have a mouse grabber here is
// synthetic events - flickable sends one when setPressDelay is used.
auto oldMouseGrabber = q->mouseGrabberItem();
@@ -2327,7 +2350,6 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
eventAccepted = touchEvent->isAccepted();
// If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it.
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (!eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
// send mouse event
if (deliverTouchAsMouse(item, event))
@@ -2341,7 +2363,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
auto pointerEventPoint = event->pointById(point.id());
pointerEventPoint->setAccepted();
if (point.state() == Qt::TouchPointPressed)
- pointerEventPoint->setGrabber(item);
+ pointerEventPoint->setGrabberItem(item);
}
} else {
// But if the event was not accepted then we know this item
@@ -2350,7 +2372,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
if (point.state() == Qt::TouchPointPressed) {
if (event->pointById(point.id())->grabber() == item) {
qCDebug(DBG_TOUCH_TARGET) << "TP" << point.id() << "disassociated";
- event->pointById(point.id())->setGrabber(nullptr);
+ event->pointById(point.id())->setGrabberItem(nullptr);
}
}
}
@@ -2589,7 +2611,7 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target;
touchMouseId = tp.id();
touchMouseDevice = event->device();
- touchMouseDevice->pointerEvent()->pointById(tp.id())->setGrabber(target);
+ touchMouseDevice->pointerEvent()->pointById(tp.id())->setGrabberItem(target);
target->grabMouse();
}
filtered = true;
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index be915903c6..30e3b71d0a 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -143,7 +143,7 @@ public:
bool deliverTouchAsMouse(QQuickItem *item, QQuickPointerEvent *pointerEvent);
void translateTouchEvent(QTouchEvent *touchEvent);
void setMouseGrabber(QQuickItem *grabber);
- void grabTouchPoints(QQuickItem *grabber, const QVector<int> &ids);
+ void grabTouchPoints(QObject *grabber, const QVector<int> &ids);
void removeGrabber(QQuickItem *grabber, bool mouse = true, bool touch = true);
static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
void deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent);
diff --git a/src/quick/quick.pro b/src/quick/quick.pro
index 8f4f9a8290..2f49a53aa1 100644
--- a/src/quick/quick.pro
+++ b/src/quick/quick.pro
@@ -28,6 +28,7 @@ ANDROID_BUNDLED_FILES += \
include(util/util.pri)
include(scenegraph/scenegraph.pri)
include(items/items.pri)
+include(handlers/handlers.pri)
qtConfig(quick-designer): \
include(designer/designer.pri)
qtConfig(accessibility) {