diff options
-rw-r--r-- | src/quick/handlers/qquickdraghandler.cpp | 2 | ||||
-rw-r--r-- | src/quick/handlers/qquickpointersinglehandler.cpp | 80 | ||||
-rw-r--r-- | src/quick/handlers/qquickpointersinglehandler_p.h | 39 | ||||
-rw-r--r-- | tests/manual/pointer/main.qml | 1 | ||||
-rw-r--r-- | tests/manual/pointer/qml.qrc | 7 | ||||
-rw-r--r-- | tests/manual/pointer/resources/arrowhead.png | bin | 0 -> 883 bytes | |||
-rw-r--r-- | tests/manual/pointer/resources/grabbing-location.svg | 1 | ||||
-rw-r--r-- | tests/manual/pointer/resources/mouse.png | bin | 0 -> 1919 bytes | |||
-rw-r--r-- | tests/manual/pointer/resources/mouse_left.png | bin | 0 -> 740 bytes | |||
-rw-r--r-- | tests/manual/pointer/resources/mouse_middle.png | bin | 0 -> 558 bytes | |||
-rw-r--r-- | tests/manual/pointer/resources/mouse_right.png | bin | 0 -> 906 bytes | |||
-rw-r--r-- | tests/manual/pointer/singlePointHandlerProperties.qml | 162 |
12 files changed, 267 insertions, 25 deletions
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp index 945d60119d..6caee6be13 100644 --- a/src/quick/handlers/qquickdraghandler.cpp +++ b/src/quick/handlers/qquickdraghandler.cpp @@ -69,7 +69,7 @@ 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()) + return ((point->state() != QQuickEventPoint::Pressed && pointId() == point->pointId()) || QQuickPointerSingleHandler::wantsEventPoint(point)); } diff --git a/src/quick/handlers/qquickpointersinglehandler.cpp b/src/quick/handlers/qquickpointersinglehandler.cpp index 3a67d66e8c..f39d8ac976 100644 --- a/src/quick/handlers/qquickpointersinglehandler.cpp +++ b/src/quick/handlers/qquickpointersinglehandler.cpp @@ -52,7 +52,9 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET) QQuickPointerSingleHandler::QQuickPointerSingleHandler(QObject *parent) : QQuickPointerDeviceHandler(parent) - , m_currentPointId(0) + , m_pointId(0) + , m_rotation(0) + , m_pressure(0) { } @@ -60,11 +62,11 @@ bool QQuickPointerSingleHandler::wantsPointerEvent(QQuickPointerEvent *event) { if (!QQuickPointerDeviceHandler::wantsPointerEvent(event)) return false; - if (m_currentPointId) { + if (m_pointId) { // 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 (auto point = event->pointById(m_pointId)) { if (wantsEventPoint(point)) { point->setAccepted(); return true; @@ -72,45 +74,62 @@ bool QQuickPointerSingleHandler::wantsPointerEvent(QQuickPointerEvent *event) point->cancelGrab(); } } else { - qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << m_currentPointId + qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << m_pointId << "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) { + for (int i = 0; i < c && !m_pointId; ++i) { QQuickEventPoint *p = event->point(i); if (!p->grabber() && wantsEventPoint(p)) { - m_currentPointId = p->pointId(); + m_pointId = p->pointId(); p->setAccepted(); } } } - return m_currentPointId; + return m_pointId; } void QQuickPointerSingleHandler::handlePointerEventImpl(QQuickPointerEvent *event) { QQuickPointerDeviceHandler::handlePointerEventImpl(event); - QQuickEventPoint *currentPoint = event->pointById(m_currentPointId); + QQuickEventPoint *currentPoint = event->pointById(m_pointId); Q_ASSERT(currentPoint); - if (!m_currentPointId || !currentPoint->isAccepted()) { - m_currentPointId = 0; - setPressedButtons(Qt::NoButton); + bool grab = false; + if (!m_pointId || !currentPoint->isAccepted() || currentPoint->state() == QQuickEventPoint::Released) { + reset(); + grab = false; } else { - setPressedButtons(event->buttons()); + if (event->asPointerTouchEvent()) { + QQuickEventTouchPoint *tp = static_cast<QQuickEventTouchPoint *>(currentPoint); + m_uniquePointId = tp->uniqueId(); + m_rotation = tp->rotation(); + m_pressure = tp->pressure(); + m_ellipseDiameters = tp->ellipseDiameters(); + } else if (event->asPointerTabletEvent()) { + // TODO + } else { + m_uniquePointId = event->device()->uniqueId(); + m_rotation = 0; + m_pressure = event->buttons() ? 1 : 0; + m_ellipseDiameters = QSizeF(); + } + m_pos = currentPoint->pos(); + m_velocity = currentPoint->velocity(); handleEventPoint(currentPoint); - if (currentPoint->state() == QQuickEventPoint::Released) { - m_currentPointId = 0; - setPressedButtons(Qt::NoButton); - setGrab(currentPoint, false); + if (currentPoint->state() == QQuickEventPoint::Pressed) { + m_pressPos = currentPoint->pos(); + emit pointIdChanged(); } + setPressedButtons(event->buttons()); + grab = true; } - bool grab = currentPoint->isAccepted() && currentPoint->state() != QQuickEventPoint::Released; + emit eventPointHandled(); + // TODO don't call setGrab(true) here, only setGrab(false), because concrete subclasses may + // wait for the drag threshold to be exceeded, for example setGrab(currentPoint, grab); - if (!grab) - m_currentPointId = 0; } bool QQuickPointerSingleHandler::wantsEventPoint(QQuickEventPoint *point) @@ -121,14 +140,16 @@ bool QQuickPointerSingleHandler::wantsEventPoint(QQuickEventPoint *point) void QQuickPointerSingleHandler::handleGrabCancel(QQuickEventPoint *point) { QQuickPointerHandler::handleGrabCancel(point); - m_currentPointId = 0; - setPressedButtons(Qt::NoButton); + reset(); } void QQuickPointerSingleHandler::onGrabChanged(QQuickEventPoint *point) { bool grabbing = (point->grabber() == this); setActive(grabbing); + if (grabbing) + m_sceneGrabPos = point->sceneGrabPos(); + emit singlePointGrabChanged(); } void QQuickPointerSingleHandler::setPressedButtons(Qt::MouseButtons buttons) @@ -139,4 +160,21 @@ void QQuickPointerSingleHandler::setPressedButtons(Qt::MouseButtons buttons) } } +void QQuickPointerSingleHandler::reset() +{ + bool pointIdChange = m_pointId != 0; + m_pointId = 0; + m_uniquePointId = QPointingDeviceUniqueId(); + m_pos = QPointF(); + m_pressPos = QPointF(); + m_sceneGrabPos = QPointF(); + m_velocity = QVector2D(); + m_rotation = 0; + m_pressure = 0; + m_ellipseDiameters = QSizeF(); + setPressedButtons(Qt::NoButton); + if (pointIdChange) + emit pointIdChanged(); +} + QT_END_NAMESPACE diff --git a/src/quick/handlers/qquickpointersinglehandler_p.h b/src/quick/handlers/qquickpointersinglehandler_p.h index e3c6bfaddf..8858b2c080 100644 --- a/src/quick/handlers/qquickpointersinglehandler_p.h +++ b/src/quick/handlers/qquickpointersinglehandler_p.h @@ -58,33 +58,66 @@ QT_BEGIN_NAMESPACE class Q_QUICK_PRIVATE_EXPORT QQuickPointerSingleHandler : public QQuickPointerDeviceHandler { Q_OBJECT + Q_PROPERTY(quint64 pointId READ pointId NOTIFY pointIdChanged) + Q_PROPERTY(QPointingDeviceUniqueId uniquePointId READ uniquePointId NOTIFY pointIdChanged) + Q_PROPERTY(QPointF pos READ pos NOTIFY eventPointHandled) + Q_PROPERTY(QPointF scenePos READ scenePos NOTIFY eventPointHandled) + Q_PROPERTY(QPointF pressPos READ pressPos NOTIFY pressedButtonsChanged) + Q_PROPERTY(QPointF scenePressPos READ scenePressPos NOTIFY pressedButtonsChanged) + Q_PROPERTY(QPointF sceneGrabPos READ sceneGrabPos NOTIFY singlePointGrabChanged) Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedButtonsChanged) + Q_PROPERTY(QVector2D velocity READ velocity NOTIFY eventPointHandled) + Q_PROPERTY(qreal rotation READ rotation NOTIFY eventPointHandled) + Q_PROPERTY(qreal pressure READ pressure NOTIFY eventPointHandled) + Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters NOTIFY eventPointHandled) public: QQuickPointerSingleHandler(QObject *parent = 0); virtual ~QQuickPointerSingleHandler() { } Qt::MouseButtons pressedButtons() const { return m_pressedButtons; } + QPointF pressPos() const { return m_pressPos; } + QPointF scenePressPos() const { return parentItem()->mapToScene(m_pressPos); } + QPointF sceneGrabPos() const { return m_sceneGrabPos; } + QPointF pos() const { return m_pos; } + QPointF scenePos() const { return parentItem()->mapToScene(m_pos); } + QVector2D velocity() const { return m_velocity; } + qreal rotation() const { return m_rotation; } + qreal pressure() const { return m_pressure; } + QSizeF ellipseDiameters() const { return m_ellipseDiameters; } + QPointingDeviceUniqueId uniquePointId() const { return m_uniquePointId; } signals: + void pointIdChanged(); void pressedButtonsChanged(); + void singlePointGrabChanged(); // QQuickPointerHandler::grabChanged signal can't be a property notifier here + void eventPointHandled(); 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); } + quint64 pointId() const { return m_pointId; } + QQuickEventPoint *currentPoint(QQuickPointerEvent *ev) { return ev->pointById(m_pointId); } void handleGrabCancel(QQuickEventPoint *point) override; void onGrabChanged(QQuickEventPoint *point) override; private: void setPressedButtons(Qt::MouseButtons buttons); + void reset(); private: - quint64 m_currentPointId; + quint64 m_pointId; + QPointingDeviceUniqueId m_uniquePointId; Qt::MouseButtons m_pressedButtons; + QPointF m_pos; + QPointF m_pressPos; + QPointF m_sceneGrabPos; + QVector2D m_velocity; + qreal m_rotation; + qreal m_pressure; + QSizeF m_ellipseDiameters; }; QT_END_NAMESPACE diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index 64b7148bd2..62202c39b1 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -50,6 +50,7 @@ Window { id: ll anchors.fill: parent Component.onCompleted: { + addExample("single point handler", "QQuickPointerSingleHandler: test properties copied from events", Qt.resolvedUrl("singlePointHandlerProperties.qml")) addExample("joystick", "DragHandler: move one item inside another with any pointing device", Qt.resolvedUrl("joystick.qml")) addExample("mixer", "mixing console", Qt.resolvedUrl("mixer.qml")) addExample("pinch", "PinchHandler: scale, rotate and drag", Qt.resolvedUrl("pinchHandler.qml")) diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 08488b020b..adf255ea1f 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -5,9 +5,16 @@ <file>map.qml</file> <file>mixer.qml</file> <file>pinchHandler.qml</file> + <file>singlePointHandlerProperties.qml</file> <file>content/Slider.qml</file> + <file>resources/arrowhead.png</file> + <file>resources/grabbing-location.svg</file> <file>resources/map.svgz</file> <file>resources/mixer-knob.png</file> + <file>resources/mouse.png</file> + <file>resources/mouse_left.png</file> + <file>resources/mouse_middle.png</file> + <file>resources/mouse_right.png</file> <file>resources/redball.png</file> <file>map2.qml</file> </qresource> diff --git a/tests/manual/pointer/resources/arrowhead.png b/tests/manual/pointer/resources/arrowhead.png Binary files differnew file mode 100644 index 0000000000..7719bc6d6a --- /dev/null +++ b/tests/manual/pointer/resources/arrowhead.png diff --git a/tests/manual/pointer/resources/grabbing-location.svg b/tests/manual/pointer/resources/grabbing-location.svg new file mode 100644 index 0000000000..c26881e9ba --- /dev/null +++ b/tests/manual/pointer/resources/grabbing-location.svg @@ -0,0 +1 @@ +<svg width="3408" height="3124"><path d="M1517 1562c0-126-93-229-208-229s-208 102-208 229c0 126 93 229 208 229s208-102 208-229zm123-172c-58-206-221-365-424-412l-270 531H380l203-223 219-241 346-380c42 14 82 32 121 54 232 128 402 375 449 671h-77zm-551-933c448 123 782 546 802 1055h1517C3386 673 2787 0 2050 0H696L0 1367h120l826-938 146 25c-1 1-2 2-3 4zm551 1277c-58 206-221 365-424 412l-270-531H380l203 223 219 241 346 380c42-14 82-32 121-54 232-128 402-375 449-671h-77zm-548 936l-146 25-826-938H0l696 1367h1354c737 0 1337-673 1358-1512H1891c-19 509-354 933-802 1055 1 1 2 2 3 4z" fill="#ee832b"/></svg> diff --git a/tests/manual/pointer/resources/mouse.png b/tests/manual/pointer/resources/mouse.png Binary files differnew file mode 100644 index 0000000000..268946df0a --- /dev/null +++ b/tests/manual/pointer/resources/mouse.png diff --git a/tests/manual/pointer/resources/mouse_left.png b/tests/manual/pointer/resources/mouse_left.png Binary files differnew file mode 100644 index 0000000000..9292301b47 --- /dev/null +++ b/tests/manual/pointer/resources/mouse_left.png diff --git a/tests/manual/pointer/resources/mouse_middle.png b/tests/manual/pointer/resources/mouse_middle.png Binary files differnew file mode 100644 index 0000000000..064e8b9c16 --- /dev/null +++ b/tests/manual/pointer/resources/mouse_middle.png diff --git a/tests/manual/pointer/resources/mouse_right.png b/tests/manual/pointer/resources/mouse_right.png Binary files differnew file mode 100644 index 0000000000..cab1a36ba6 --- /dev/null +++ b/tests/manual/pointer/resources/mouse_right.png diff --git a/tests/manual/pointer/singlePointHandlerProperties.qml b/tests/manual/pointer/singlePointHandlerProperties.qml new file mode 100644 index 0000000000..f5a938e401 --- /dev/null +++ b/tests/manual/pointer/singlePointHandlerProperties.qml @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.9 +import Qt.labs.handlers 1.0 + +Rectangle { + id: root + width: 480 + height: 480 + color: "black" + + Item { + id: crosshairs + x: dragHandler.pos.x - width / 2 + y: dragHandler.pos.y - height / 2 + width: parent.width / 2; height: parent.height / 2 + visible: dragHandler.active + rotation: dragHandler.rotation + + Rectangle { + color: "goldenrod" + anchors.centerIn: parent + width: 2; height: parent.height + antialiasing: true + } + Rectangle { + color: "goldenrod" + anchors.centerIn: parent + width: parent.width; height: 2 + antialiasing: true + } + Rectangle { + color: "goldenrod" + width: Math.max(2, 50 * dragHandler.pressure) + height: width + radius: width / 2 + anchors.centerIn: parent + antialiasing: true + Rectangle { + y: -40 + anchors.horizontalCenter: parent.horizontalCenter + color: "lightsteelblue" + implicitWidth: label.implicitWidth + implicitHeight: label.implicitHeight + Text { + id: label + text: 'id: ' + dragHandler.pointId.toString(16) + " uid: " + dragHandler.uniquePointId.numericId + + '\npos: (' + dragHandler.pos.x.toFixed(2) + ', ' + dragHandler.pos.y.toFixed(2) + ')' + } + } + } + Rectangle { + color: "transparent" + border.color: "white" + antialiasing: true + width: dragHandler.ellipseDiameters.width + height: dragHandler.ellipseDiameters.height + radius: Math.min(width / 2, height / 2) + anchors.centerIn: parent + } + } + Rectangle { + id: velocityVector + visible: width > 0 + width: dragHandler.velocity.length() * 100 + height: 2 + x: dragHandler.pos.x + y: dragHandler.pos.y + rotation: Math.atan2(dragHandler.velocity.y, dragHandler.velocity.x) * 180 / Math.PI + transformOrigin: Item.BottomLeft + antialiasing: true + + Image { + source: "resources/arrowhead.png" + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + width: 16 + height: 12 + antialiasing: true + } + } + + Component { + id: grabbingLocationIndicator + Image { + source: "resources/grabbing-location.svg" + sourceSize.width: 32 + sourceSize.height: 32 + } + } + + Component { + id: mouseButtonIndicator + Image { + property int buttons + source: "resources/mouse.png" + Image { + source: "resources/mouse_left.png" + visible: buttons & Qt.LeftButton + } + Image { + source: "resources/mouse_middle.png" + visible: buttons & Qt.MidButton + } + Image { + source: "resources/mouse_right.png" + visible: buttons & Qt.RightButton + } + } + } + + DragHandler { + id: dragHandler + target: null + onGrabChanged: if (active) { + console.log("grabbed " + point.pointId + " @ " + sceneGrabPos) + grabbingLocationIndicator.createObject(root, {"x": sceneGrabPos.x, "y": sceneGrabPos.y - 16}) + } + onPressedButtonsChanged: { + if (pressedButtons) + mouseButtonIndicator.createObject(root, {"x": pressPos.x - 44, "y": pressPos.y - 64, "buttons": pressedButtons}) + } + } +} |