File indexing completed on 2024-06-02 05:42:14
0001 // SPDX-FileCopyrightText: 2016 The Qt Company Ltd. 0002 // SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org> 0003 // SPDX-License-Identifier: GPL-2.0-or-later 0004 0005 #include "delegatetoucharea.h" 0006 0007 #include <QCursor> 0008 #include <QGuiApplication> 0009 #include <QStyleHints> 0010 0011 // Some code taken from MouseArea 0012 0013 DelegateTouchArea::DelegateTouchArea(QQuickItem *parent) 0014 : QQuickItem{parent} 0015 , m_pressAndHoldTimer{new QTimer{this}} 0016 { 0017 m_pressAndHoldTimer->setInterval(600); 0018 m_pressAndHoldTimer->setSingleShot(true); 0019 connect(m_pressAndHoldTimer, &QTimer::timeout, this, &DelegateTouchArea::startPressAndHold); 0020 0021 // Explcitly call setCursor on QQuickItem since 0022 // it internally keeps a boolean hasCursor that doesn't 0023 // get set to true unless you call setCursor 0024 setCursor(Qt::ArrowCursor); 0025 0026 setAcceptHoverEvents(true); 0027 setAcceptTouchEvents(true); 0028 setFlags(QQuickItem::ItemIsFocusScope); 0029 setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton); 0030 } 0031 0032 bool DelegateTouchArea::pressed() 0033 { 0034 return m_pressed; 0035 } 0036 0037 void DelegateTouchArea::setPressed(bool pressed) 0038 { 0039 if (pressed != m_pressed) { 0040 m_pressed = pressed; 0041 Q_EMIT pressedChanged(pressed); 0042 } 0043 } 0044 0045 bool DelegateTouchArea::hovered() 0046 { 0047 return m_hovered; 0048 } 0049 0050 void DelegateTouchArea::setHovered(bool hovered) 0051 { 0052 if (hovered != m_hovered) { 0053 m_hovered = hovered; 0054 Q_EMIT hoveredChanged(hovered); 0055 } 0056 } 0057 0058 Qt::CursorShape DelegateTouchArea::cursorShape() 0059 { 0060 return cursor().shape(); 0061 } 0062 0063 void DelegateTouchArea::setCursorShape(Qt::CursorShape cursorShape) 0064 { 0065 if (cursor().shape() == cursorShape) { 0066 return; 0067 } 0068 0069 setCursor(cursorShape); 0070 Q_EMIT cursorShapeChanged(); 0071 } 0072 0073 void DelegateTouchArea::unsetCursor() 0074 { 0075 setCursorShape(Qt::ArrowCursor); 0076 } 0077 0078 QPointF DelegateTouchArea::pressPosition() 0079 { 0080 return m_mouseDownPosition; 0081 } 0082 0083 void DelegateTouchArea::mousePressEvent(QMouseEvent *event) 0084 { 0085 if (event->button() & Qt::RightButton) { 0086 Q_EMIT rightMousePress(); 0087 } else if (event->button() & Qt::LeftButton) { 0088 handlePressEvent(event, event->points().first().position()); 0089 event->accept(); 0090 } else { 0091 QQuickItem::mousePressEvent(event); 0092 } 0093 } 0094 0095 void DelegateTouchArea::mouseMoveEvent(QMouseEvent *event) 0096 { 0097 handleMoveEvent(event, event->points().first().position()); 0098 event->accept(); 0099 } 0100 0101 void DelegateTouchArea::mouseReleaseEvent(QMouseEvent *event) 0102 { 0103 if (event->button() & Qt::LeftButton) { 0104 handleReleaseEvent(event, true); 0105 event->accept(); 0106 } else { 0107 QQuickItem::mouseReleaseEvent(event); 0108 } 0109 } 0110 0111 void DelegateTouchArea::mouseUngrabEvent() 0112 { 0113 if (m_pressed) { 0114 handleReleaseEvent(nullptr, false); 0115 } 0116 QQuickItem::mouseUngrabEvent(); 0117 } 0118 0119 void DelegateTouchArea::touchEvent(QTouchEvent *event) 0120 { 0121 bool unhandled = true; 0122 const auto &firstPoint = event->points().first(); 0123 0124 switch (firstPoint.state()) { 0125 case QEventPoint::State::Pressed: 0126 handlePressEvent(event, firstPoint.position()); 0127 event->accept(); 0128 unhandled = false; 0129 break; 0130 case QEventPoint::State::Updated: 0131 handleMoveEvent(event, firstPoint.position()); 0132 event->accept(); 0133 unhandled = false; 0134 break; 0135 case QEventPoint::State::Released: 0136 handleReleaseEvent(event, true); 0137 event->accept(); 0138 unhandled = false; 0139 break; 0140 case QEventPoint::State::Stationary: 0141 case QEventPoint::State::Unknown: 0142 break; 0143 } 0144 0145 if (unhandled) { 0146 QQuickItem::touchEvent(event); 0147 } 0148 } 0149 0150 void DelegateTouchArea::touchUngrabEvent() 0151 { 0152 if (m_pressed) { 0153 handleReleaseEvent(nullptr, false); 0154 } 0155 QQuickItem::touchUngrabEvent(); 0156 } 0157 0158 void DelegateTouchArea::hoverEnterEvent(QHoverEvent *event) 0159 { 0160 setHovered(true); 0161 0162 // don't block hover events 0163 event->ignore(); 0164 } 0165 0166 void DelegateTouchArea::hoverLeaveEvent(QHoverEvent *event) 0167 { 0168 setHovered(false); 0169 0170 // don't block hover events 0171 event->ignore(); 0172 } 0173 0174 void DelegateTouchArea::handlePressEvent(QPointerEvent *event, QPointF point) 0175 { 0176 // ignore multiple press events 0177 if (m_pressed) { 0178 return; 0179 } 0180 0181 setPressed(true); 0182 forceActiveFocus(Qt::MouseFocusReason); 0183 0184 m_mouseDownPosition = point; 0185 Q_EMIT pressPositionChanged(); 0186 0187 m_pressAndHoldTimer->start(); 0188 } 0189 0190 void DelegateTouchArea::handleReleaseEvent(QPointerEvent *event, bool click) 0191 { 0192 // NOTE: event can be nullptr! 0193 0194 bool wasPressed = m_pressed; 0195 setPressed(false); 0196 0197 if (!m_pressAndHeld && click && wasPressed) { 0198 Q_EMIT clicked(); 0199 } 0200 0201 if (m_pressAndHeld) { 0202 Q_EMIT pressAndHoldReleased(); 0203 } 0204 0205 m_pressAndHoldTimer->stop(); 0206 m_pressAndHeld = false; 0207 } 0208 0209 void DelegateTouchArea::handleMoveEvent(QPointerEvent *event, QPointF point) 0210 { 0211 if (QPointF(point - m_mouseDownPosition).manhattanLength() >= QGuiApplication::styleHints()->startDragDistance()) { 0212 m_pressAndHoldTimer->stop(); 0213 setPressed(false); 0214 } 0215 } 0216 0217 void DelegateTouchArea::startPressAndHold() 0218 { 0219 m_pressAndHeld = true; 0220 Q_EMIT pressAndHold(); 0221 }