| 1 | // Copyright (C) 2017 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
| 3 | |
| 4 | #include "qquickpresshandler_p_p.h" |
| 5 | |
| 6 | #include <QtCore/private/qobject_p.h> |
| 7 | #include <QtGui/qguiapplication.h> |
| 8 | #include <QtGui/qstylehints.h> |
| 9 | #include <QtQuick/qquickitem.h> |
| 10 | #include <QtQuick/private/qquickevents_p_p.h> |
| 11 | #include <QtQuickTemplates2/private/qquicktextarea_p.h> |
| 12 | #include <QtQuickTemplates2/private/qquicktextfield_p.h> |
| 13 | |
| 14 | QT_BEGIN_NAMESPACE |
| 15 | |
| 16 | void QQuickPressHandler::mousePressEvent(QMouseEvent *event) |
| 17 | { |
| 18 | longPress = false; |
| 19 | pressPos = event->position(); |
| 20 | if (Qt::LeftButton == (event->buttons() & Qt::LeftButton)) { |
| 21 | timer.start(msec: QGuiApplication::styleHints()->mousePressAndHoldInterval(), obj: control); |
| 22 | delayedMousePressEvent = std::make_unique<QMouseEvent>(args: event->type(), args: event->position().toPoint(), args: event->globalPosition().toPoint(), |
| 23 | args: event->button(), args: event->buttons(), args: event->modifiers(), args: event->pointingDevice()); |
| 24 | } else { |
| 25 | timer.stop(); |
| 26 | } |
| 27 | |
| 28 | if (isSignalConnected(item: control, signalName: "pressed(QQuickMouseEvent*)" , signalIndex&: pressedSignalIndex)) { |
| 29 | QQuickMouseEvent mev; |
| 30 | mev.reset(x: pressPos.x(), y: pressPos.y(), button: event->button(), buttons: event->buttons(), |
| 31 | modifiers: event->modifiers(), isClick: false/*isClick*/, wasHeld: false/*wasHeld*/); |
| 32 | mev.setAccepted(true); |
| 33 | QQuickMouseEvent *mevPtr = &mev; |
| 34 | void *args[] = { nullptr, &mevPtr }; |
| 35 | QMetaObject::metacall(control, QMetaObject::InvokeMetaMethod, pressedSignalIndex, args); |
| 36 | event->setAccepted(mev.isAccepted()); |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | void QQuickPressHandler::mouseMoveEvent(QMouseEvent *event) |
| 41 | { |
| 42 | if (qAbs(t: event->position().x() - pressPos.x()) > QGuiApplication::styleHints()->startDragDistance()) |
| 43 | timer.stop(); |
| 44 | } |
| 45 | |
| 46 | void QQuickPressHandler::mouseReleaseEvent(QMouseEvent *event) |
| 47 | { |
| 48 | if (!longPress) |
| 49 | timer.stop(); |
| 50 | |
| 51 | if (isSignalConnected(item: control, signalName: "released(QQuickMouseEvent*)" , signalIndex&: releasedSignalIndex)) { |
| 52 | QQuickMouseEvent mev; |
| 53 | mev.reset(x: pressPos.x(), y: pressPos.y(), button: event->button(), buttons: event->buttons(), |
| 54 | modifiers: event->modifiers(), isClick: false/*isClick*/, wasHeld: false/*wasHeld*/); |
| 55 | mev.setAccepted(true); |
| 56 | QQuickMouseEvent *mevPtr = &mev; |
| 57 | void *args[] = { nullptr, &mevPtr }; |
| 58 | QMetaObject::metacall(control, QMetaObject::InvokeMetaMethod, releasedSignalIndex, args); |
| 59 | event->setAccepted(mev.isAccepted()); |
| 60 | } |
| 61 | |
| 62 | } |
| 63 | |
| 64 | void QQuickPressHandler::timerEvent(QTimerEvent *) |
| 65 | { |
| 66 | timer.stop(); |
| 67 | clearDelayedMouseEvent(); |
| 68 | |
| 69 | longPress = isSignalConnected(item: control, signalName: "pressAndHold(QQuickMouseEvent*)" , signalIndex&: pressAndHoldSignalIndex); |
| 70 | if (longPress) { |
| 71 | QQuickMouseEvent mev; |
| 72 | QT_WARNING_PUSH |
| 73 | QT_WARNING_DISABLE_DEPRECATED |
| 74 | mev.reset(x: pressPos.x(), y: pressPos.y(), button: Qt::LeftButton, buttons: Qt::LeftButton, |
| 75 | modifiers: QGuiApplication::keyboardModifiers(), isClick: false/*isClick*/, wasHeld: true/*wasHeld*/); |
| 76 | QT_WARNING_POP |
| 77 | mev.setAccepted(true); |
| 78 | // Use fast signal invocation since we already got its index |
| 79 | QQuickMouseEvent *mevPtr = &mev; |
| 80 | void *args[] = { nullptr, &mevPtr }; |
| 81 | QMetaObject::metacall(control, QMetaObject::InvokeMetaMethod, pressAndHoldSignalIndex, args); |
| 82 | if (!mev.isAccepted()) |
| 83 | longPress = false; |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | void QQuickPressHandler::clearDelayedMouseEvent() |
| 88 | { |
| 89 | delayedMousePressEvent.reset(); |
| 90 | } |
| 91 | |
| 92 | bool QQuickPressHandler::isActive() |
| 93 | { |
| 94 | return !(timer.isActive() || longPress); |
| 95 | } |
| 96 | |
| 97 | bool QQuickPressHandler::isSignalConnected(QQuickItem *item, const char *signalName, int &signalIndex) |
| 98 | { |
| 99 | if (signalIndex == -1) |
| 100 | signalIndex = item->metaObject()->indexOfSignal(signal: signalName); |
| 101 | Q_ASSERT(signalIndex != -1); |
| 102 | const auto signalMetaMethod = item->metaObject()->method(index: signalIndex); |
| 103 | if (QQuickTextArea *textArea = qobject_cast<QQuickTextArea*>(object: item)) { |
| 104 | return textArea->isSignalConnected(signal: signalMetaMethod); |
| 105 | } else if (QQuickTextField *textField = qobject_cast<QQuickTextField*>(object: item)) { |
| 106 | return textField->isSignalConnected(signal: signalMetaMethod); |
| 107 | } |
| 108 | qFatal(msg: "Unhandled control type for signal name: %s" , signalName); |
| 109 | return false; |
| 110 | } |
| 111 | |
| 112 | QT_END_NAMESPACE |
| 113 | |