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
14QT_BEGIN_NAMESPACE
15
16void 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
40void QQuickPressHandler::mouseMoveEvent(QMouseEvent *event)
41{
42 if (qAbs(t: int(event->position().x() - pressPos.x())) > QGuiApplication::styleHints()->startDragDistance())
43 timer.stop();
44}
45
46void 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
64void 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;
72QT_WARNING_PUSH
73QT_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*/);
76QT_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
87void QQuickPressHandler::clearDelayedMouseEvent()
88{
89 delayedMousePressEvent.reset();
90}
91
92bool QQuickPressHandler::isActive()
93{
94 return !(timer.isActive() || longPress);
95}
96
97bool 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
112QT_END_NAMESPACE
113

source code of qtdeclarative/src/quicktemplates/qquickpresshandler.cpp