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: int(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 | |