diff options
Diffstat (limited to 'src/quick/handlers/qquickwheelhandler.cpp')
-rw-r--r-- | src/quick/handlers/qquickwheelhandler.cpp | 183 |
1 files changed, 102 insertions, 81 deletions
diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp index 90e4fef97e..7e29af1422 100644 --- a/src/quick/handlers/qquickwheelhandler.cpp +++ b/src/quick/handlers/qquickwheelhandler.cpp @@ -1,54 +1,20 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qquickwheelhandler_p.h" #include "qquickwheelhandler_p_p.h" +#include <QtQuick/private/qquickitem_p.h> #include <QLoggingCategory> #include <QtMath> QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(lcWheelHandler, "qt.quick.handler.wheel") +Q_STATIC_LOGGING_CATEGORY(lcWheelHandler, "qt.quick.handler.wheel") /*! \qmltype WheelHandler \instantiates QQuickWheelHandler + \inherits SinglePointHandler \inqmlmodule QtQuick \ingroup qtquick-input-handlers \brief Handler for the mouse wheel. @@ -71,33 +37,26 @@ Q_LOGGING_CATEGORY(lcWheelHandler, "qt.quick.handler.wheel") \snippet pointerHandlers/handlerFlick.qml 0 - Alternatively if \l targetProperty is not set or \l target is null, + Alternatively, if \l property is not set or \l target is null, WheelHandler will not automatically manipulate anything; but the \l rotation property can be used in a binding to manipulate another property, or you can implement \c onWheel and handle the wheel event directly. - WheelHandler handles only a rotating mouse wheel by default. - Optionally it can handle smooth-scrolling events from touchpad gestures, - by setting \l acceptedDevices to \c{PointerDevice.Mouse | PointerDevice.TouchPad}. + WheelHandler handles only a rotating mouse wheel by default; this + can be changed by setting acceptedDevices. - \note Some non-mouse hardware (such as a touch-sensitive Wacom tablet, or - a Linux laptop touchpad) generates real wheel events from gestures. - WheelHandler will respond to those events as wheel events regardless of the - setting of the \l acceptedDevices property. - - \sa MouseArea - \sa Flickable + \sa MouseArea, Flickable, {Qt Quick Examples - Pointer Handlers} */ QQuickWheelHandler::QQuickWheelHandler(QQuickItem *parent) : QQuickSinglePointHandler(*(new QQuickWheelHandlerPrivate), parent) { - setAcceptedDevices(QQuickPointerDevice::Mouse); + setAcceptedDevices(QInputDevice::DeviceType::Mouse); } /*! - \qmlproperty enum QtQuick::WheelHandler::orientation + \qmlproperty enumeration QtQuick::WheelHandler::orientation Which wheel to react to. The default is \c Qt.Vertical. @@ -125,13 +84,13 @@ void QQuickWheelHandler::setOrientation(Qt::Orientation orientation) \qmlproperty bool QtQuick::WheelHandler::invertible Whether or not to reverse the direction of property change if - \l QQuickPointerScrollEvent::inverted is true. The default is \c true. + \l QWheelEvent::inverted is \c true. The default is \c true. If the operating system has a "natural scrolling" setting that causes scrolling to be in the same direction as the finger movement, then if this property is set to \c true, and WheelHandler is directly setting a property on \l target, the direction of movement will correspond to the system setting. - If this property is set to \l false, it will invert the \l rotation so that + If this property is set to \c false, it will invert the \l rotation so that the direction of motion is always the same as the direction of finger movement. */ bool QQuickWheelHandler::isInvertible() const @@ -161,10 +120,12 @@ void QQuickWheelHandler::setInvertible(bool invertible) \l {Qt::ScrollPhase}{scroll phase} information, such as events from some touchpads, the \l active property will become \c false as soon as an event with phase \l Qt::ScrollEnd is received; in that case the timeout is not - necessary. But a conventional mouse with a wheel does not provide the - \l {QQuickPointerScrollEvent::phase}{scroll phase}: the mouse cannot detect - when the user has decided to stop scrolling, so the \l active property - transitions to \c false after this much time has elapsed. + necessary. But a conventional mouse with a wheel does not provide a scroll + phase: the mouse cannot detect when the user has decided to stop + scrolling, so the \l active property transitions to \c false after this + much time has elapsed. + + \sa QWheelEvent::phase() */ qreal QQuickWheelHandler::activeTimeout() const { @@ -358,60 +319,90 @@ void QQuickWheelHandler::setTargetTransformAroundCursor(bool ttac) emit targetTransformAroundCursorChanged(); } -bool QQuickWheelHandler::wantsPointerEvent(QQuickPointerEvent *event) +/*! + \qmlproperty bool QtQuick::WheelHandler::blocking + \since 6.3 + + Whether this handler prevents other items or handlers behind it from + handling the same wheel event. This property is \c true by default. +*/ +bool QQuickWheelHandler::isBlocking() const +{ + Q_D(const QQuickWheelHandler); + return d->blocking; +} + +void QQuickWheelHandler::setBlocking(bool blocking) +{ + Q_D(QQuickWheelHandler); + if (d->blocking == blocking) + return; + + d->blocking = blocking; + emit blockingChanged(); +} + +bool QQuickWheelHandler::wantsPointerEvent(QPointerEvent *event) { if (!event) return false; - QQuickPointerScrollEvent *scroll = event->asPointerScrollEvent(); - if (!scroll) + if (event->type() != QEvent::Wheel) return false; - if (!acceptedDevices().testFlag(QQuickPointerDevice::DeviceType::TouchPad) - && scroll->synthSource() != Qt::MouseEventNotSynthesized) + QWheelEvent *we = static_cast<QWheelEvent *>(event); + if (!acceptedDevices().testFlag(QPointingDevice::DeviceType::TouchPad) + && we->source() != Qt::MouseEventNotSynthesized) return false; if (!active()) { switch (orientation()) { case Qt::Horizontal: - if (qFuzzyIsNull(scroll->angleDelta().x()) && qFuzzyIsNull(scroll->pixelDelta().x())) + if (!(we->angleDelta().x()) && !(we->pixelDelta().x())) return false; break; case Qt::Vertical: - if (qFuzzyIsNull(scroll->angleDelta().y()) && qFuzzyIsNull(scroll->pixelDelta().y())) + if (!(we->angleDelta().y()) && !(we->pixelDelta().y())) return false; break; } } - QQuickEventPoint *point = event->point(0); - if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(point) && parentContains(point)) { - setPointId(point->pointId()); + auto &point = event->point(0); + if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(event, point) && parentContains(point)) { + setPointId(point.id()); return true; } return false; } -void QQuickWheelHandler::handleEventPoint(QQuickEventPoint *point) +void QQuickWheelHandler::handleEventPoint(QPointerEvent *ev, QEventPoint &point) { Q_D(QQuickWheelHandler); - QQuickPointerScrollEvent *event = point->pointerEvent()->asPointerScrollEvent(); + QQuickSinglePointHandler::handleEventPoint(ev, point); + + if (ev->type() != QEvent::Wheel) + return; + const QWheelEvent *event = static_cast<const QWheelEvent *>(ev); setActive(true); // ScrollEnd will not happen unless it was already active (see setActive(false) below) - point->setAccepted(); + if (d->blocking) + point.setAccepted(); qreal inversion = !d->invertible && event->isInverted() ? -1 : 1; qreal angleDelta = inversion * qreal(orientation() == Qt::Horizontal ? event->angleDelta().x() : event->angleDelta().y()) / 8; d->rotation += angleDelta; emit rotationChanged(); - emit wheel(event); + + d->wheelEvent.reset(event); + emit wheel(&d->wheelEvent); if (!d->propertyName.isEmpty() && target()) { QQuickItem *t = target(); // writing target()'s property is done via QMetaProperty::write() so that any registered interceptors can react. if (d->propertyName == QLatin1String("scale")) { qreal multiplier = qPow(d->targetScaleMultiplier, angleDelta * d->rotationScale / 15); // wheel "clicks" - const QPointF centroidParentPos = t->parentItem()->mapFromScene(point->scenePosition()); + const QPointF centroidParentPos = t->parentItem()->mapFromScene(point.scenePosition()); const QPointF positionWas = t->position(); const qreal scaleWas = t->scale(); const qreal activePropertyValue = scaleWas * multiplier; qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "pixel delta" << event->pixelDelta() - << "@" << point->position() << "in parent" << centroidParentPos - << "in scene" << point->scenePosition() + << "@" << point.position() << "in parent" << centroidParentPos + << "in scene" << point.scenePosition() << "multiplier" << multiplier << "scale" << scaleWas << "->" << activePropertyValue; d->targetMetaProperty().write(t, activePropertyValue); @@ -427,10 +418,10 @@ void QQuickWheelHandler::handleEventPoint(QQuickEventPoint *point) const QPointF positionWas = t->position(); const qreal rotationWas = t->rotation(); const qreal activePropertyValue = rotationWas + angleDelta * d->rotationScale; - const QPointF centroidParentPos = t->parentItem()->mapFromScene(point->scenePosition()); + const QPointF centroidParentPos = t->parentItem()->mapFromScene(point.scenePosition()); qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "pixel delta" << event->pixelDelta() - << "@" << point->position() << "in parent" << centroidParentPos - << "in scene" << point->scenePosition() << "rotation" << t->rotation() + << "@" << point.position() << "in parent" << centroidParentPos + << "in scene" << point.scenePosition() << "rotation" << t->rotation() << "->" << activePropertyValue; d->targetMetaProperty().write(t, activePropertyValue); if (d->targetTransformAroundCursor) { @@ -442,8 +433,9 @@ void QQuickWheelHandler::handleEventPoint(QQuickEventPoint *point) t->setPosition(adjPos); } } else { - qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "scaled" << angleDelta << "total" << d->rotation << "pixel delta" << event->pixelDelta() - << "@" << point->position() << "in scene" << point->scenePosition() << "rotation" << t->rotation(); + qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "scaled" << angleDelta + << "total" << d->rotation << "pixel delta" << event->pixelDelta() + << "@" << point.position() << "in scene" << point.scenePosition() << "rotation" << t->rotation(); qreal delta = 0; if (event->hasPixelDelta()) { delta = inversion * d->rotationScale * qreal(orientation() == Qt::Horizontal ? event->pixelDelta().x() : event->pixelDelta().y()); @@ -477,7 +469,7 @@ void QQuickWheelHandler::handleEventPoint(QQuickEventPoint *point) void QQuickWheelHandler::onTargetChanged(QQuickItem *oldTarget) { - Q_UNUSED(oldTarget) + Q_UNUSED(oldTarget); Q_D(QQuickWheelHandler); d->metaPropertyDirty = true; } @@ -498,6 +490,14 @@ void QQuickWheelHandler::timerEvent(QTimerEvent *event) } } +/*! + \qmlsignal QtQuick::WheelHandler::wheel(WheelEvent event) + + This signal is emitted every time this handler receives an \a event + of type \l QWheelEvent: that is, every time the wheel is moved or the + scrolling gesture is updated. +*/ + QQuickWheelHandlerPrivate::QQuickWheelHandlerPrivate() : QQuickSinglePointHandlerPrivate() { @@ -517,4 +517,25 @@ QMetaProperty &QQuickWheelHandlerPrivate::targetMetaProperty() const return metaProperty; } +/*! + \qmlproperty flags WheelHandler::acceptedDevices + + The types of pointing devices that can activate this handler. + + By default, this property is set to + \l{QInputDevice::DeviceType}{PointerDevice.Mouse}, so as to react only to + events from an actual mouse wheel. + + WheelHandler can be made to respond to both mouse wheel and touchpad + scrolling by setting acceptedDevices to + \c{PointerDevice.Mouse | PointerDevice.TouchPad}. + + \note Some non-mouse hardware (such as a touch-sensitive Wacom tablet, or a + Linux laptop touchpad) generates real wheel events from gestures. + WheelHandler will respond to those events as wheel events even if + \c acceptedDevices remains set to its default value. +*/ + QT_END_NAMESPACE + +#include "moc_qquickwheelhandler_p.cpp" |