| 1 | // Copyright (C) 2018 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 "qquickpointerhandler_p.h" |
| 5 | #include "qquickpointerhandler_p_p.h" |
| 6 | #include <QtQuick/private/qquickitem_p.h> |
| 7 | #include <QtQuick/private/qquickhandlerpoint_p.h> |
| 8 | #include <QtQuick/private/qquickdeliveryagent_p_p.h> |
| 9 | #include <QtGui/private/qinputdevice_p.h> |
| 10 | |
| 11 | #include <QtCore/qpointer.h> |
| 12 | |
| 13 | QT_BEGIN_NAMESPACE |
| 14 | |
| 15 | Q_LOGGING_CATEGORY(lcPointerHandlerDispatch, "qt.quick.handler.dispatch" ) |
| 16 | Q_STATIC_LOGGING_CATEGORY(lcPointerHandlerGrab, "qt.quick.handler.grab" ) |
| 17 | Q_STATIC_LOGGING_CATEGORY(lcPointerHandlerActive, "qt.quick.handler.active" ) |
| 18 | |
| 19 | /*! |
| 20 | \qmltype PointerHandler |
| 21 | \qmlabstract |
| 22 | \since 5.10 |
| 23 | \nativetype QQuickPointerHandler |
| 24 | \inqmlmodule QtQuick |
| 25 | \brief Abstract handler for pointer events. |
| 26 | |
| 27 | PointerHandler is the base class Input Handler (not registered as a QML type) for |
| 28 | events from any kind of pointing device (touch, mouse or graphics tablet). |
| 29 | */ |
| 30 | |
| 31 | /*! \internal |
| 32 | So far we only offer public QML API for Pointer Handlers, but we expect |
| 33 | in some future version of Qt to have public C++ API as well. This will open |
| 34 | up the possibility to instantiate handlers in custom items (which we should |
| 35 | begin doing in Qt Quick Controls in the near future), and to subclass to make |
| 36 | custom handlers (as TableView is already doing). |
| 37 | |
| 38 | To make a custom Pointer Handler, first try to choose the parent class |
| 39 | according to your needs. If the gesture that you want to recognize could |
| 40 | involve multiple touchpoints (even if it could start with only one point), |
| 41 | subclass QQuickMultiPointHandler. If you are sure that you never want to |
| 42 | handle more than one QEventPoint, subclass QQuickSinglePointHandler. |
| 43 | */ |
| 44 | QQuickPointerHandler::QQuickPointerHandler(QQuickItem *parent) |
| 45 | : QQuickPointerHandler(*(new QQuickPointerHandlerPrivate), parent) |
| 46 | { |
| 47 | } |
| 48 | |
| 49 | QQuickPointerHandler::QQuickPointerHandler(QQuickPointerHandlerPrivate &dd, QQuickItem *parent) |
| 50 | : QObject(dd, parent) |
| 51 | { |
| 52 | // When a handler is created in QML, the given parent is null, and we |
| 53 | // depend on QQuickItemPrivate::data_append() later when it's added to an |
| 54 | // item's DefaultProperty data property. But when a handler is created in |
| 55 | // C++ with a parent item, data_append() won't be called, and the caller |
| 56 | // shouldn't have to worry about it either. |
| 57 | if (parent) |
| 58 | QQuickItemPrivate::get(item: parent)->addPointerHandler(h: this); |
| 59 | } |
| 60 | |
| 61 | QQuickPointerHandler::~QQuickPointerHandler() |
| 62 | { |
| 63 | QQuickItem *parItem = parentItem(); |
| 64 | if (parItem) { |
| 65 | QQuickItemPrivate *p = QQuickItemPrivate::get(item: parItem); |
| 66 | p->extra.value().pointerHandlers.removeOne(t: this); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | /*! |
| 71 | \qmlproperty real PointerHandler::margin |
| 72 | |
| 73 | The margin beyond the bounds of the \l {PointerHandler::parent}{parent} |
| 74 | item within which an \l eventPoint can activate this handler. For example, on |
| 75 | a PinchHandler where the \l {PointerHandler::target}{target} is also the |
| 76 | \c parent, it's useful to set this to a distance at least half the width |
| 77 | of a typical user's finger, so that if the \c parent has been scaled down |
| 78 | to a very small size, the pinch gesture is still possible. Or, if a |
| 79 | TapHandler-based button is placed near the screen edge, it can be used |
| 80 | to comply with Fitts's Law: react to mouse clicks at the screen edge |
| 81 | even though the button is visually spaced away from the edge by a few pixels. |
| 82 | |
| 83 | The default value is 0. |
| 84 | |
| 85 | \image pointerHandlerMargin.png |
| 86 | */ |
| 87 | qreal QQuickPointerHandler::margin() const |
| 88 | { |
| 89 | Q_D(const QQuickPointerHandler); |
| 90 | return d->m_margin; |
| 91 | } |
| 92 | |
| 93 | void QQuickPointerHandler::setMargin(qreal pointDistanceThreshold) |
| 94 | { |
| 95 | Q_D(QQuickPointerHandler); |
| 96 | if (d->m_margin == pointDistanceThreshold) |
| 97 | return; |
| 98 | |
| 99 | d->m_margin = pointDistanceThreshold; |
| 100 | emit marginChanged(); |
| 101 | } |
| 102 | |
| 103 | /*! |
| 104 | \qmlproperty int PointerHandler::dragThreshold |
| 105 | \since 5.15 |
| 106 | |
| 107 | The distance in pixels that the user must drag an \l eventPoint in order to |
| 108 | have it treated as a drag gesture. |
| 109 | |
| 110 | The default value depends on the platform and screen resolution. |
| 111 | It can be reset back to the default value by setting it to undefined. |
| 112 | The behavior when a drag gesture begins varies in different handlers. |
| 113 | */ |
| 114 | int QQuickPointerHandler::dragThreshold() const |
| 115 | { |
| 116 | Q_D(const QQuickPointerHandler); |
| 117 | if (d->dragThreshold < 0) |
| 118 | return qApp->styleHints()->startDragDistance(); |
| 119 | return d->dragThreshold; |
| 120 | } |
| 121 | |
| 122 | void QQuickPointerHandler::setDragThreshold(int t) |
| 123 | { |
| 124 | Q_D(QQuickPointerHandler); |
| 125 | if (d->dragThreshold == t) |
| 126 | return; |
| 127 | |
| 128 | if (t > std::numeric_limits<qint16>::max()) |
| 129 | qWarning() << "drag threshold cannot exceed" << std::numeric_limits<qint16>::max(); |
| 130 | d->dragThreshold = qint16(t); |
| 131 | emit dragThresholdChanged(); |
| 132 | } |
| 133 | |
| 134 | void QQuickPointerHandler::resetDragThreshold() |
| 135 | { |
| 136 | Q_D(QQuickPointerHandler); |
| 137 | if (d->dragThreshold < 0) |
| 138 | return; |
| 139 | |
| 140 | d->dragThreshold = -1; |
| 141 | emit dragThresholdChanged(); |
| 142 | } |
| 143 | |
| 144 | /*! |
| 145 | \since 5.15 |
| 146 | \qmlproperty Qt::CursorShape PointerHandler::cursorShape |
| 147 | This property holds the cursor shape that will appear whenever the mouse is |
| 148 | hovering over the \l parent item while \l active is \c true. |
| 149 | |
| 150 | The available cursor shapes are: |
| 151 | \list |
| 152 | \li Qt.ArrowCursor |
| 153 | \li Qt.UpArrowCursor |
| 154 | \li Qt.CrossCursor |
| 155 | \li Qt.WaitCursor |
| 156 | \li Qt.IBeamCursor |
| 157 | \li Qt.SizeVerCursor |
| 158 | \li Qt.SizeHorCursor |
| 159 | \li Qt.SizeBDiagCursor |
| 160 | \li Qt.SizeFDiagCursor |
| 161 | \li Qt.SizeAllCursor |
| 162 | \li Qt.BlankCursor |
| 163 | \li Qt.SplitVCursor |
| 164 | \li Qt.SplitHCursor |
| 165 | \li Qt.PointingHandCursor |
| 166 | \li Qt.ForbiddenCursor |
| 167 | \li Qt.WhatsThisCursor |
| 168 | \li Qt.BusyCursor |
| 169 | \li Qt.OpenHandCursor |
| 170 | \li Qt.ClosedHandCursor |
| 171 | \li Qt.DragCopyCursor |
| 172 | \li Qt.DragMoveCursor |
| 173 | \li Qt.DragLinkCursor |
| 174 | \endlist |
| 175 | |
| 176 | The default value is not set, which allows the \l {QQuickItem::cursor()}{cursor} |
| 177 | of \l parent item to appear. This property can be reset to the same initial |
| 178 | condition by setting it to undefined. |
| 179 | |
| 180 | \note When this property has not been set, or has been set to \c undefined, |
| 181 | if you read the value it will return \c Qt.ArrowCursor. |
| 182 | |
| 183 | \sa Qt::CursorShape, QQuickItem::cursor(), HoverHandler::cursorShape |
| 184 | */ |
| 185 | #if QT_CONFIG(cursor) |
| 186 | Qt::CursorShape QQuickPointerHandler::cursorShape() const |
| 187 | { |
| 188 | Q_D(const QQuickPointerHandler); |
| 189 | return d->cursorShape; |
| 190 | } |
| 191 | |
| 192 | void QQuickPointerHandler::setCursorShape(Qt::CursorShape shape) |
| 193 | { |
| 194 | Q_D(QQuickPointerHandler); |
| 195 | if (d->cursorSet && shape == d->cursorShape) |
| 196 | return; |
| 197 | d->cursorShape = shape; |
| 198 | d->cursorSet = true; |
| 199 | d->cursorDirty = true; |
| 200 | if (auto *parent = parentItem()) { |
| 201 | QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item: parent); |
| 202 | itemPriv->hasCursorHandler = true; |
| 203 | itemPriv->setHasCursorInChild(true); |
| 204 | } |
| 205 | |
| 206 | emit cursorShapeChanged(); |
| 207 | } |
| 208 | |
| 209 | void QQuickPointerHandler::resetCursorShape() |
| 210 | { |
| 211 | Q_D(QQuickPointerHandler); |
| 212 | if (!d->cursorSet) |
| 213 | return; |
| 214 | d->cursorShape = Qt::ArrowCursor; |
| 215 | d->cursorSet = false; |
| 216 | if (auto *parent = parentItem()) { |
| 217 | QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item: parent); |
| 218 | itemPriv->hasCursorHandler = false; |
| 219 | itemPriv->setHasCursorInChild(itemPriv->hasCursor); |
| 220 | } |
| 221 | emit cursorShapeChanged(); |
| 222 | } |
| 223 | |
| 224 | bool QQuickPointerHandler::isCursorShapeExplicitlySet() const |
| 225 | { |
| 226 | Q_D(const QQuickPointerHandler); |
| 227 | return d->cursorSet; |
| 228 | } |
| 229 | #endif |
| 230 | |
| 231 | /*! |
| 232 | Notification that the grab has changed in some way which is relevant to this handler. |
| 233 | The \a grabber (subject) will be the Input Handler whose state is changing, |
| 234 | or null if the state change regards an Item. |
| 235 | The \a transition (verb) tells what happened. |
| 236 | The \a point (object) is the \l eventPoint that was grabbed or ungrabbed. |
| 237 | QQuickDeliveryAgent calls this function. |
| 238 | The Input Handler must react in whatever way is appropriate, and must |
| 239 | emit the relevant signals (for the benefit of QML code). |
| 240 | A subclass is allowed to override this virtual function, but must always |
| 241 | call its parent class's implementation in addition to (usually after) |
| 242 | whatever custom behavior it implements. |
| 243 | */ |
| 244 | void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, |
| 245 | QPointerEvent *event, QEventPoint &point) |
| 246 | { |
| 247 | Q_UNUSED(event); |
| 248 | qCDebug(lcPointerHandlerGrab) << point << transition << grabber; |
| 249 | if (grabber == this) { |
| 250 | bool wasCanceled = false; |
| 251 | switch (transition) { |
| 252 | case QPointingDevice::GrabPassive: |
| 253 | case QPointingDevice::GrabExclusive: |
| 254 | break; |
| 255 | case QPointingDevice::CancelGrabPassive: |
| 256 | case QPointingDevice::CancelGrabExclusive: |
| 257 | wasCanceled = true; // the grab was stolen by something else |
| 258 | Q_FALLTHROUGH(); |
| 259 | case QPointingDevice::UngrabPassive: |
| 260 | case QPointingDevice::UngrabExclusive: |
| 261 | setActive(false); |
| 262 | point.setAccepted(false); |
| 263 | if (auto par = parentItem()) { |
| 264 | Q_D(const QQuickPointerHandler); |
| 265 | par->setKeepMouseGrab(d->hadKeepMouseGrab); |
| 266 | par->setKeepTouchGrab(d->hadKeepTouchGrab); |
| 267 | } |
| 268 | break; |
| 269 | case QPointingDevice::OverrideGrabPassive: |
| 270 | // Passive grab is still there, but we won't receive point updates right now. |
| 271 | // No need to notify about this. |
| 272 | return; |
| 273 | } |
| 274 | if (wasCanceled) |
| 275 | emit canceled(point); |
| 276 | emit grabChanged(transition, point); |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | /*! |
| 281 | Acquire or give up a passive grab of the given \a point, according to the \a grab state. |
| 282 | |
| 283 | Unlike the exclusive grab, multiple Input Handlers can have passive grabs |
| 284 | simultaneously. This means that each of them will receive further events |
| 285 | when the \a point moves, and when it is finally released. Typically an |
| 286 | Input Handler should acquire a passive grab as soon as a point is pressed, |
| 287 | if the handler's constraints do not clearly rule out any interest in that |
| 288 | point. For example, DragHandler needs a passive grab in order to watch the |
| 289 | movement of a point to see whether it will be dragged past the drag |
| 290 | threshold. When a handler is actively manipulating its \l target (that is, |
| 291 | when \l active is true), it may be able to do its work with only a passive |
| 292 | grab, or it may acquire an exclusive grab if the gesture clearly must not |
| 293 | be interpreted in another way by another handler. |
| 294 | */ |
| 295 | void QQuickPointerHandler::setPassiveGrab(QPointerEvent *event, const QEventPoint &point, bool grab) |
| 296 | { |
| 297 | qCDebug(lcPointerHandlerGrab) << this << point << grab << "via" |
| 298 | << QQuickDeliveryAgentPrivate::currentOrItemDeliveryAgent(item: parentItem()); |
| 299 | if (grab) { |
| 300 | event->addPassiveGrabber(point, grabber: this); |
| 301 | } else { |
| 302 | event->removePassiveGrabber(point, grabber: this); |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | /*! |
| 307 | Check whether it's OK to take an exclusive grab of the \a point. |
| 308 | |
| 309 | The default implementation will call approveGrabTransition() to check this |
| 310 | handler's \l grabPermissions. If grabbing can be done only by taking over |
| 311 | the exclusive grab from an Item, approveGrabTransition() checks the Item's |
| 312 | \l keepMouseGrab or \l keepTouchGrab flags appropriately. If grabbing can |
| 313 | be done only by taking over another handler's exclusive grab, canGrab() |
| 314 | also calls approveGrabTransition() on the handler which is about to lose |
| 315 | its grab. Either one can deny the takeover. |
| 316 | */ |
| 317 | bool QQuickPointerHandler::canGrab(QPointerEvent *event, const QEventPoint &point) |
| 318 | { |
| 319 | QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(object: event->exclusiveGrabber(point)); |
| 320 | return approveGrabTransition(event, point, proposedGrabber: this) && |
| 321 | (existingPhGrabber ? existingPhGrabber->approveGrabTransition(event, point, proposedGrabber: this) : true); |
| 322 | } |
| 323 | |
| 324 | /*! |
| 325 | Check this handler's rules to see if \l proposedGrabber will be allowed to take |
| 326 | the exclusive grab. This function may be called twice: once on the instance which |
| 327 | will take the grab, and once on the instance which would thereby lose its grab, |
| 328 | in case of a takeover scenario. |
| 329 | */ |
| 330 | bool QQuickPointerHandler::approveGrabTransition(QPointerEvent *event, const QEventPoint &point, QObject *proposedGrabber) |
| 331 | { |
| 332 | Q_D(const QQuickPointerHandler); |
| 333 | bool allowed = false; |
| 334 | QObject* existingGrabber = event->exclusiveGrabber(point); |
| 335 | if (proposedGrabber == this) { |
| 336 | allowed = (existingGrabber == nullptr) || ((d->grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything); |
| 337 | if (existingGrabber) { |
| 338 | if (QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(object: event->exclusiveGrabber(point))) { |
| 339 | if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfDifferentType) && |
| 340 | existingPhGrabber->metaObject()->className() != metaObject()->className()) |
| 341 | allowed = true; |
| 342 | if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfSameType) && |
| 343 | existingPhGrabber->metaObject()->className() == metaObject()->className()) |
| 344 | allowed = true; |
| 345 | } else if ((d->grabPermissions & CanTakeOverFromItems)) { |
| 346 | allowed = true; |
| 347 | QQuickItem * existingItemGrabber = qobject_cast<QQuickItem *>(o: event->exclusiveGrabber(point)); |
| 348 | auto da = parentItem() ? QQuickItemPrivate::get(item: parentItem())->deliveryAgentPrivate() |
| 349 | : QQuickDeliveryAgentPrivate::currentEventDeliveryAgent ? static_cast<QQuickDeliveryAgentPrivate *>( |
| 350 | QQuickDeliveryAgentPrivate::get(o: QQuickDeliveryAgentPrivate::currentEventDeliveryAgent)) : nullptr; |
| 351 | const bool isTouchMouse = (da && da->isDeliveringTouchAsMouse()); |
| 352 | if (existingItemGrabber && |
| 353 | ((existingItemGrabber->keepMouseGrab() && |
| 354 | (QQuickDeliveryAgentPrivate::isMouseEvent(ev: event) || isTouchMouse)) || |
| 355 | (existingItemGrabber->keepTouchGrab() && QQuickDeliveryAgentPrivate::isTouchEvent(ev: event)))) { |
| 356 | allowed = false; |
| 357 | // If the handler wants to steal the exclusive grab from an Item, the Item can usually veto |
| 358 | // by having its keepMouseGrab flag set. But an exception is if that Item is a parent that |
| 359 | // normally filters events (such as a Flickable): it needs to be possible for e.g. a |
| 360 | // DragHandler to operate on an Item inside a Flickable. Flickable is aggressive about |
| 361 | // grabbing on press (for fear of missing updates), but DragHandler uses a passive grab |
| 362 | // at first and then expects to be able to steal the grab later on. It cannot respect |
| 363 | // Flickable's wishes in that case, because then it would never have a chance. |
| 364 | if (existingItemGrabber->keepMouseGrab() && |
| 365 | existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(child: parentItem())) { |
| 366 | Q_ASSERT(da); |
| 367 | if (isTouchMouse && point.id() == da->touchMouseId) { |
| 368 | qCDebug(lcPointerHandlerGrab) << this << "steals touchpoint" << point.id() |
| 369 | << "despite parent touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber; |
| 370 | allowed = true; |
| 371 | } |
| 372 | } |
| 373 | if (!allowed) { |
| 374 | qCDebug(lcPointerHandlerGrab) << this << "wants to grab point" << point.id() |
| 375 | << "but declines to steal from grabber" << existingItemGrabber |
| 376 | << "with keepMouseGrab=" << existingItemGrabber->keepMouseGrab() |
| 377 | << "keepTouchGrab=" << existingItemGrabber->keepTouchGrab(); |
| 378 | } |
| 379 | } |
| 380 | } |
| 381 | } |
| 382 | } else { |
| 383 | // proposedGrabber is different: that means this instance will lose its grab |
| 384 | if (proposedGrabber) { |
| 385 | if ((d->grabPermissions & ApprovesTakeOverByAnything) == ApprovesTakeOverByAnything) |
| 386 | allowed = true; |
| 387 | if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfDifferentType) && |
| 388 | proposedGrabber->metaObject()->className() != metaObject()->className()) |
| 389 | allowed = true; |
| 390 | if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfSameType) && |
| 391 | proposedGrabber->metaObject()->className() == metaObject()->className()) |
| 392 | allowed = true; |
| 393 | if (!allowed && (d->grabPermissions & ApprovesTakeOverByItems) && proposedGrabber->inherits(classname: "QQuickItem" )) |
| 394 | allowed = true; |
| 395 | } else { |
| 396 | if (d->grabPermissions & ApprovesCancellation) |
| 397 | allowed = true; |
| 398 | } |
| 399 | } |
| 400 | qCDebug(lcPointerHandlerGrab) << "point" << Qt::hex << point.id() << "permission" << |
| 401 | QMetaEnum::fromType<GrabPermissions>().valueToKeys(value: grabPermissions()) << |
| 402 | ':' << this << (allowed ? "approved from" : "denied from" ) << |
| 403 | existingGrabber << "to" << proposedGrabber; |
| 404 | return allowed; |
| 405 | } |
| 406 | |
| 407 | /*! |
| 408 | \qmlproperty flags QtQuick::PointerHandler::grabPermissions |
| 409 | |
| 410 | This property specifies the permissions when this handler's logic decides |
| 411 | to take over the exclusive grab, or when it is asked to approve grab |
| 412 | takeover or cancellation by another handler. |
| 413 | |
| 414 | \value PointerHandler.TakeOverForbidden |
| 415 | This handler neither takes from nor gives grab permission to any type of Item or Handler. |
| 416 | \value PointerHandler.CanTakeOverFromHandlersOfSameType |
| 417 | This handler can take the exclusive grab from another handler of the same class. |
| 418 | \value PointerHandler.CanTakeOverFromHandlersOfDifferentType |
| 419 | This handler can take the exclusive grab from any kind of handler. |
| 420 | \value PointerHandler.CanTakeOverFromItems |
| 421 | This handler can take the exclusive grab from any type of Item. |
| 422 | \value PointerHandler.CanTakeOverFromAnything |
| 423 | This handler can take the exclusive grab from any type of Item or Handler. |
| 424 | \value PointerHandler.ApprovesTakeOverByHandlersOfSameType |
| 425 | This handler gives permission for another handler of the same class to take the grab. |
| 426 | \value PointerHandler.ApprovesTakeOverByHandlersOfDifferentType |
| 427 | This handler gives permission for any kind of handler to take the grab. |
| 428 | \value PointerHandler.ApprovesTakeOverByItems |
| 429 | This handler gives permission for any kind of Item to take the grab. |
| 430 | \value PointerHandler.ApprovesCancellation |
| 431 | This handler will allow its grab to be set to null. |
| 432 | \value PointerHandler.ApprovesTakeOverByAnything |
| 433 | This handler gives permission for any type of Item or Handler to take the grab. |
| 434 | |
| 435 | The default is |
| 436 | \c {PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByAnything} |
| 437 | which allows most takeover scenarios but avoids e.g. two PinchHandlers fighting |
| 438 | over the same touchpoints. |
| 439 | */ |
| 440 | QQuickPointerHandler::GrabPermissions QQuickPointerHandler::grabPermissions() const |
| 441 | { |
| 442 | Q_D(const QQuickPointerHandler); |
| 443 | return static_cast<QQuickPointerHandler::GrabPermissions>(d->grabPermissions); |
| 444 | } |
| 445 | |
| 446 | void QQuickPointerHandler::setGrabPermissions(GrabPermissions grabPermission) |
| 447 | { |
| 448 | Q_D(QQuickPointerHandler); |
| 449 | if (d->grabPermissions == grabPermission) |
| 450 | return; |
| 451 | |
| 452 | d->grabPermissions = grabPermission; |
| 453 | emit grabPermissionChanged(); |
| 454 | } |
| 455 | |
| 456 | /*! |
| 457 | Overridden only because QQmlParserStatus requires it. |
| 458 | */ |
| 459 | void QQuickPointerHandler::classBegin() |
| 460 | { |
| 461 | } |
| 462 | |
| 463 | /*! |
| 464 | Overridden from QQmlParserStatus to ensure that parentItem() sets its |
| 465 | cursor if this handler's \l cursorShape property has been set, and that |
| 466 | this handler is added to the parent item. If it was declared as a named property |
| 467 | rather than declared directly inside an Item, data_append() will miss adding it. |
| 468 | */ |
| 469 | void QQuickPointerHandler::componentComplete() |
| 470 | { |
| 471 | Q_D(const QQuickPointerHandler); |
| 472 | if (auto *parent = parentItem()) { |
| 473 | QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item: parent); |
| 474 | itemPriv->addPointerHandler(h: this); |
| 475 | if (d->cursorSet) { |
| 476 | itemPriv->hasCursorHandler = true; |
| 477 | itemPriv->setHasCursorInChild(true); |
| 478 | } |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | /*! \internal |
| 483 | \deprecated You should handle the event during delivery by overriding |
| 484 | handlePointerEventImpl() or QQuickSinglePointHandler::handleEventPoint(). |
| 485 | Therefore currentEvent() should not be needed. It is here only because |
| 486 | onActiveChanged() does not take the event as an argument. |
| 487 | */ |
| 488 | QPointerEvent *QQuickPointerHandler::currentEvent() |
| 489 | { |
| 490 | Q_D(const QQuickPointerHandler); |
| 491 | return d->currentEvent; |
| 492 | } |
| 493 | |
| 494 | /*! |
| 495 | Acquire or give up the exclusive grab of the given \a point, according to |
| 496 | the \a grab state, and subject to the rules: canGrab(), and the rule not to |
| 497 | relinquish another handler's grab. Returns true if permission is granted, |
| 498 | or if the exclusive grab has already been acquired or relinquished as |
| 499 | specified. Returns false if permission is denied either by this handler or |
| 500 | by the handler or item from which this handler would take over |
| 501 | */ |
| 502 | bool QQuickPointerHandler::setExclusiveGrab(QPointerEvent *ev, const QEventPoint &point, bool grab) |
| 503 | { |
| 504 | // If the handler loses its grab because its window is deactivated, there's no QPointerEvent. |
| 505 | if (!ev) |
| 506 | return true; |
| 507 | if ((grab && ev->exclusiveGrabber(point) == this) || (!grab && ev->exclusiveGrabber(point) != this)) |
| 508 | return true; |
| 509 | // TODO m_hadKeepMouseGrab m_hadKeepTouchGrab |
| 510 | bool allowed = true; |
| 511 | if (grab) { |
| 512 | allowed = canGrab(event: ev, point); |
| 513 | } else { |
| 514 | QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(object: ev->exclusiveGrabber(point)); |
| 515 | // Ask before allowing one handler to cancel another's grab |
| 516 | if (existingPhGrabber && existingPhGrabber != this && !existingPhGrabber->approveGrabTransition(event: ev, point, proposedGrabber: nullptr)) |
| 517 | allowed = false; |
| 518 | } |
| 519 | qCDebug(lcPointerHandlerGrab) << point << (grab ? "grab" : "ungrab" ) << (allowed ? "allowed" : "forbidden" ) << |
| 520 | ev->exclusiveGrabber(point) << "->" << (grab ? this : nullptr); |
| 521 | if (allowed) |
| 522 | ev->setExclusiveGrabber(point, exclusiveGrabber: grab ? this : nullptr); |
| 523 | return allowed; |
| 524 | } |
| 525 | |
| 526 | /*! |
| 527 | Cancel any existing grab of the given \a point. |
| 528 | */ |
| 529 | void QQuickPointerHandler::cancelAllGrabs(QPointerEvent *event, QEventPoint &point) |
| 530 | { |
| 531 | qCDebug(lcPointerHandlerGrab) << point; |
| 532 | if (event->exclusiveGrabber(point) == this) { |
| 533 | event->setExclusiveGrabber(point, exclusiveGrabber: nullptr); |
| 534 | onGrabChanged(grabber: this, transition: QPointingDevice::CancelGrabExclusive, event, point); |
| 535 | } |
| 536 | if (event->removePassiveGrabber(point, grabber: this)) |
| 537 | onGrabChanged(grabber: this, transition: QPointingDevice::CancelGrabPassive, event, point); |
| 538 | } |
| 539 | |
| 540 | QPointF QQuickPointerHandler::eventPos(const QEventPoint &point) const |
| 541 | { |
| 542 | return (target() ? target()->mapFromScene(point: point.scenePosition()) : point.scenePosition()); |
| 543 | } |
| 544 | |
| 545 | /*! |
| 546 | Returns \c true if margin() > 0 and \a point is within the margin beyond |
| 547 | QQuickItem::boundingRect(), or else returns QQuickItem::contains() |
| 548 | QEventPoint::position() effectively (because parentContains(scenePosition) |
| 549 | calls QQuickItem::mapFromScene()). |
| 550 | */ |
| 551 | bool QQuickPointerHandler::parentContains(const QEventPoint &point) const |
| 552 | { |
| 553 | return parentContains(scenePosition: point.scenePosition()); |
| 554 | } |
| 555 | |
| 556 | /*! |
| 557 | Returns \c true if \a scenePosition is within the margin() beyond |
| 558 | QQuickItem::boundingRect() (if margin > 0), or parentItem() contains |
| 559 | \a scenePosition according to QQuickItem::contains(). (So if the \l margin |
| 560 | property is set, that overrides the bounds-check, and QQuickItem::contains() |
| 561 | is not called.) As a precheck, it's also required that the window contains |
| 562 | \a scenePosition mapped to global coordinates, if parentItem() is in a window. |
| 563 | */ |
| 564 | bool QQuickPointerHandler::parentContains(const QPointF &scenePosition) const |
| 565 | { |
| 566 | if (QQuickItem *par = parentItem()) { |
| 567 | if (par->window()) { |
| 568 | QRectF windowGeometry = par->window()->geometry(); |
| 569 | if (!par->window()->isTopLevel()) |
| 570 | windowGeometry = QRectF(QWindowPrivate::get(window: par->window())->globalPosition(), par->window()->size()); |
| 571 | QPointF screenPosition = par->window()->mapToGlobal(pos: scenePosition); |
| 572 | if (!windowGeometry.contains(p: screenPosition)) |
| 573 | return false; |
| 574 | } |
| 575 | QPointF p = par->mapFromScene(point: scenePosition); |
| 576 | qreal m = margin(); |
| 577 | if (m > 0) |
| 578 | return p.x() >= -m && p.y() >= -m && p.x() <= par->width() + m && p.y() <= par->height() + m; |
| 579 | return par->contains(point: p); |
| 580 | } else if (parent() && parent()->inherits(classname: "QQuick3DModel" )) { |
| 581 | // If the parent is from Qt Quick 3D, assume that |
| 582 | // bounds checking was already done, as part of picking. |
| 583 | return true; |
| 584 | } |
| 585 | return false; |
| 586 | } |
| 587 | |
| 588 | /*! |
| 589 | \qmlproperty bool QtQuick::PointerHandler::enabled |
| 590 | |
| 591 | If a PointerHandler is disabled, it will reject all events |
| 592 | and no signals will be emitted. |
| 593 | */ |
| 594 | bool QQuickPointerHandler::enabled() const |
| 595 | { |
| 596 | Q_D(const QQuickPointerHandler); |
| 597 | return d->enabled; |
| 598 | } |
| 599 | |
| 600 | void QQuickPointerHandler::setEnabled(bool enabled) |
| 601 | { |
| 602 | Q_D(QQuickPointerHandler); |
| 603 | if (d->enabled == enabled) |
| 604 | return; |
| 605 | |
| 606 | d->enabled = enabled; |
| 607 | d->onEnabledChanged(); |
| 608 | |
| 609 | emit enabledChanged(); |
| 610 | } |
| 611 | |
| 612 | /*! |
| 613 | \qmlproperty Item QtQuick::PointerHandler::target |
| 614 | |
| 615 | The Item which this handler will manipulate. |
| 616 | |
| 617 | By default, it is the same as the \l [QML] {parent}, the Item within which |
| 618 | the handler is declared. However, it can sometimes be useful to set the |
| 619 | target to a different Item, in order to handle events within one item |
| 620 | but manipulate another; or to \c null, to disable the default behavior |
| 621 | and do something else instead. |
| 622 | */ |
| 623 | QQuickItem *QQuickPointerHandler::target() const |
| 624 | { |
| 625 | Q_D(const QQuickPointerHandler); |
| 626 | if (!d->targetExplicitlySet) |
| 627 | return parentItem(); |
| 628 | return d->target; |
| 629 | } |
| 630 | |
| 631 | void QQuickPointerHandler::setTarget(QQuickItem *target) |
| 632 | { |
| 633 | Q_D(QQuickPointerHandler); |
| 634 | d->targetExplicitlySet = true; |
| 635 | if (d->target == target) |
| 636 | return; |
| 637 | |
| 638 | QQuickItem *oldTarget = d->target; |
| 639 | d->target = target; |
| 640 | onTargetChanged(oldTarget); |
| 641 | emit targetChanged(); |
| 642 | } |
| 643 | |
| 644 | /*! |
| 645 | \qmlproperty Item QtQuick::PointerHandler::parent |
| 646 | |
| 647 | The \l Item which is the scope of the handler; the Item in which it was |
| 648 | declared. The handler will handle events on behalf of this Item, which |
| 649 | means a pointer event is relevant if at least one of its |
| 650 | \l {eventPoint}{eventPoints} occurs within the Item's interior. Initially |
| 651 | \l [QML] {target} {target()} is the same, but it can be reassigned. |
| 652 | |
| 653 | \sa {target}, QObject::parent() |
| 654 | */ |
| 655 | /*! \internal |
| 656 | We still haven't shipped official support for declaring handlers in |
| 657 | QtQuick3D.Model objects. Many prerequisites are in place for that, so we |
| 658 | should try to keep it working; but there are issues with getting |
| 659 | DragHandler to drag its target intuitively in 3D space, for example. |
| 660 | TapHandler would work well enough. |
| 661 | |
| 662 | \note When a handler is declared in a \l [QtQuick3D] {Model}{QtQuick3D.Model} |
| 663 | object, the parent is not an Item, therefore this property is \c null. |
| 664 | */ |
| 665 | QQuickItem *QQuickPointerHandler::parentItem() const |
| 666 | { |
| 667 | return qmlobject_cast<QQuickItem *>(object: QObject::parent()); |
| 668 | } |
| 669 | |
| 670 | void QQuickPointerHandler::setParentItem(QQuickItem *p) |
| 671 | { |
| 672 | Q_D(QQuickPointerHandler); |
| 673 | if (QObject::parent() == p) |
| 674 | return; |
| 675 | |
| 676 | qCDebug(lcHandlerParent) << "reparenting handler" << this << ":" << parent() << "->" << p; |
| 677 | auto *oldParent = static_cast<QQuickItem *>(QObject::parent()); |
| 678 | if (oldParent) |
| 679 | QQuickItemPrivate::get(item: oldParent)->removePointerHandler(h: this); |
| 680 | setParent(p); |
| 681 | if (p) |
| 682 | QQuickItemPrivate::get(item: p)->addPointerHandler(h: this); |
| 683 | d->onParentChanged(oldParent, p); |
| 684 | emit parentChanged(); |
| 685 | } |
| 686 | |
| 687 | /*! \internal |
| 688 | Pointer Handlers do most of their work in implementations of virtual functions |
| 689 | that are called directly from QQuickItem, not by direct event handling. |
| 690 | But it's convenient to deliver TouchCancel events via QCoreApplication::sendEvent(). |
| 691 | Perhaps it will turn out that more events could be delivered this way. |
| 692 | */ |
| 693 | bool QQuickPointerHandler::event(QEvent *e) |
| 694 | { |
| 695 | switch (e->type()) { |
| 696 | case QEvent::TouchCancel: { |
| 697 | auto te = static_cast<QTouchEvent *>(e); |
| 698 | for (int i = 0; i < te->pointCount(); ++i) |
| 699 | onGrabChanged(grabber: this, transition: QPointingDevice::CancelGrabExclusive, event: te, point&: te->point(i)); |
| 700 | return true; |
| 701 | break; |
| 702 | } |
| 703 | default: |
| 704 | return QObject::event(event: e); |
| 705 | break; |
| 706 | } |
| 707 | } |
| 708 | |
| 709 | /*! \internal |
| 710 | The entry point to handle the \a event: it's called from |
| 711 | QQuickItemPrivate::handlePointerEvent(), begins with wantsPointerEvent(), |
| 712 | and calls handlePointerEventImpl() if that returns \c true. |
| 713 | */ |
| 714 | void QQuickPointerHandler::handlePointerEvent(QPointerEvent *event) |
| 715 | { |
| 716 | Q_D(QQuickPointerHandler); |
| 717 | bool wants = wantsPointerEvent(event); |
| 718 | qCDebug(lcPointerHandlerDispatch) << metaObject()->className() << objectName() |
| 719 | << "on" << parent()->metaObject()->className() << parent()->objectName() |
| 720 | << (wants ? "WANTS" : "DECLINES" ) << event; |
| 721 | d->currentEvent = event; |
| 722 | if (wants) { |
| 723 | handlePointerEventImpl(event); |
| 724 | d->lastEventTime = event->timestamp(); |
| 725 | } else { |
| 726 | #if QT_CONFIG(gestures) |
| 727 | if (event->type() != QEvent::NativeGesture) |
| 728 | #endif |
| 729 | setActive(false); |
| 730 | for (int i = 0; i < event->pointCount(); ++i) { |
| 731 | auto &pt = event->point(i); |
| 732 | if (event->exclusiveGrabber(point: pt) == this && pt.state() != QEventPoint::Stationary) |
| 733 | event->setExclusiveGrabber(point: pt, exclusiveGrabber: nullptr); |
| 734 | } |
| 735 | } |
| 736 | d->currentEvent = nullptr; |
| 737 | QQuickPointerHandlerPrivate::deviceDeliveryTargets(device: event->device()).append(t: this); |
| 738 | } |
| 739 | |
| 740 | /*! |
| 741 | It is the responsibility of this function to decide whether the \a event |
| 742 | could be relevant at all to this handler, as a preliminary check. |
| 743 | |
| 744 | Returns \c true if this handler would like handlePointerEventImpl() to be called. |
| 745 | If it returns \c false, the handler will be deactivated: \c setActive(false) |
| 746 | will be called, and any remaining exclusive grab will be relinquished, |
| 747 | as a fail-safe. |
| 748 | |
| 749 | If you override this function, you should call the immediate parent class |
| 750 | implementation (and return \c false if it returns \c false); that in turn |
| 751 | calls its parent class implementation, and so on. |
| 752 | QQuickSinglePointHandler::wantsPointerEvent() and |
| 753 | QQuickMultiPointHandler::wantsPointerEvent() call wantsEventPoint(), which |
| 754 | is also virtual. You usually can get the behavior you want by subclassing |
| 755 | the appropriate handler type, overriding |
| 756 | QQuickSinglePointHandler::handleEventPoint() or handlePointerEventImpl(), |
| 757 | and perhaps overriding wantsEventPoint() if needed. |
| 758 | |
| 759 | \sa wantsEventPoint(), QQuickPointerDeviceHandler::wantsPointerEvent(), |
| 760 | QQuickMultiPointHandler::wantsPointerEvent(), QQuickSinglePointHandler::wantsPointerEvent() |
| 761 | */ |
| 762 | bool QQuickPointerHandler::wantsPointerEvent(QPointerEvent *event) |
| 763 | { |
| 764 | Q_D(const QQuickPointerHandler); |
| 765 | Q_UNUSED(event); |
| 766 | return d->enabled; |
| 767 | } |
| 768 | |
| 769 | /*! |
| 770 | Returns \c true if the given \a point (as part of \a event) could be |
| 771 | relevant at all to this handler, as a preliminary check. |
| 772 | |
| 773 | If you override this function, you should call the immediate parent class |
| 774 | implementation (and return \c false if it returns \c false); that in turn |
| 775 | calls its parent class implementation, and so on. |
| 776 | |
| 777 | In particular, the bounds checking is done here: the base class |
| 778 | QQuickPointerHandler::wantsEventPoint() calls parentContains(point) |
| 779 | (which allows the flexibility promised by margin(), QQuickItem::contains() |
| 780 | and QQuickItem::containmentMask()). Pointer Handlers can receive |
| 781 | QEventPoints that are outside the parent item's bounds: this allows some |
| 782 | flexibility for dealing with multi-point gestures in which one or more |
| 783 | fingers have strayed outside the bounds, and yet the gesture is still |
| 784 | unambiguously intended for the target() item. |
| 785 | |
| 786 | You should not generally react to the \a event or \a point here, but it's |
| 787 | ok to set state to remember what needs to be done in your overridden |
| 788 | handlePointerEventImpl() or QQuickSinglePointHandler::handleEventPoint(). |
| 789 | */ |
| 790 | bool QQuickPointerHandler::wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) |
| 791 | { |
| 792 | Q_UNUSED(event); |
| 793 | bool ret = event->exclusiveGrabber(point) == this || |
| 794 | event->passiveGrabbers(point).contains(t: this) || parentContains(point); |
| 795 | qCDebug(lcPointerHandlerDispatch) << Qt::hex << point.id() << "@" << point.scenePosition() |
| 796 | << metaObject()->className() << objectName() << ret; |
| 797 | return ret; |
| 798 | } |
| 799 | |
| 800 | /*! |
| 801 | \readonly |
| 802 | \qmlproperty bool QtQuick::PointerHandler::active |
| 803 | |
| 804 | This holds \c true whenever this Input Handler has taken sole responsibility |
| 805 | for handing one or more \l {eventPoint}{eventPoints}, by successfully taking an |
| 806 | exclusive grab of those points. This means that it is keeping its properties |
| 807 | up-to-date according to the movements of those eventPoints and actively |
| 808 | manipulating its \l target (if any). |
| 809 | */ |
| 810 | bool QQuickPointerHandler::active() const |
| 811 | { |
| 812 | Q_D(const QQuickPointerHandler); |
| 813 | return d->active; |
| 814 | } |
| 815 | |
| 816 | void QQuickPointerHandler::setActive(bool active) |
| 817 | { |
| 818 | Q_D(QQuickPointerHandler); |
| 819 | if (d->active != active) { |
| 820 | qCDebug(lcPointerHandlerActive) << this << d->active << "->" << active; |
| 821 | d->active = active; |
| 822 | onActiveChanged(); |
| 823 | emit activeChanged(); |
| 824 | } |
| 825 | } |
| 826 | |
| 827 | /*! |
| 828 | This function can be overridden to implement whatever behavior a specific |
| 829 | subclass is intended to have: |
| 830 | \list |
| 831 | \li Handle all the event's QPointerEvent::points() for which |
| 832 | wantsEventPoint() already returned \c true. |
| 833 | \li Call setPassiveGrab() setExclusiveGrab() or cancelAllGrabs() as |
| 834 | necessary. |
| 835 | \li Call QEvent::accept() to stop propagation, or ignore() to allow it |
| 836 | to keep going. |
| 837 | \endlist |
| 838 | */ |
| 839 | void QQuickPointerHandler::handlePointerEventImpl(QPointerEvent *event) |
| 840 | { |
| 841 | Q_UNUSED(event); |
| 842 | } |
| 843 | |
| 844 | /*! |
| 845 | \qmlsignal QtQuick::PointerHandler::grabChanged(PointerDevice::GrabTransition transition, eventPoint point) |
| 846 | |
| 847 | This signal is emitted when the grab has changed in some way which is |
| 848 | relevant to this handler. |
| 849 | |
| 850 | The \a transition (verb) tells what happened. |
| 851 | The \a point (object) is the point that was grabbed or ungrabbed. |
| 852 | |
| 853 | Valid values for \a transition are: |
| 854 | |
| 855 | \value PointerDevice.GrabExclusive |
| 856 | This handler has taken primary responsibility for handling the \a point. |
| 857 | \value PointerDevice.UngrabExclusive |
| 858 | This handler has given up its previous exclusive grab. |
| 859 | \value PointerDevice.CancelGrabExclusive |
| 860 | This handler's exclusive grab has been taken over or cancelled. |
| 861 | \value PointerDevice.GrabPassive |
| 862 | This handler has acquired a passive grab, to monitor the \a point. |
| 863 | \value PointerDevice.UngrabPassive |
| 864 | This handler has given up its previous passive grab. |
| 865 | \value PointerDevice.CancelGrabPassive |
| 866 | This handler's previous passive grab has terminated abnormally. |
| 867 | */ |
| 868 | |
| 869 | /*! |
| 870 | \qmlsignal QtQuick::PointerHandler::canceled(eventPoint point) |
| 871 | |
| 872 | If this handler has already grabbed the given \a point, this signal is |
| 873 | emitted when the grab is stolen by a different Pointer Handler or Item. |
| 874 | */ |
| 875 | |
| 876 | QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate() |
| 877 | : grabPermissions(QQuickPointerHandler::CanTakeOverFromItems | |
| 878 | QQuickPointerHandler::CanTakeOverFromHandlersOfDifferentType | |
| 879 | QQuickPointerHandler::ApprovesTakeOverByAnything) |
| 880 | , cursorShape(Qt::ArrowCursor) |
| 881 | , enabled(true) |
| 882 | , active(false) |
| 883 | , targetExplicitlySet(false) |
| 884 | , hadKeepMouseGrab(false) |
| 885 | , hadKeepTouchGrab(false) |
| 886 | , cursorSet(false) |
| 887 | , cursorDirty(false) |
| 888 | { |
| 889 | } |
| 890 | |
| 891 | /*! \internal |
| 892 | Returns \c true if the movement delta \a d in pixels along the \a axis |
| 893 | exceeds QQuickPointerHandler::dragThreshold() \e or QEventPoint::velocity() |
| 894 | exceeds QStyleHints::startDragVelocity(). |
| 895 | |
| 896 | \sa QQuickDeliveryAgentPrivate::dragOverThreshold() |
| 897 | */ |
| 898 | template <typename TEventPoint> |
| 899 | bool QQuickPointerHandlerPrivate::dragOverThreshold(qreal d, Qt::Axis axis, const TEventPoint &p) const |
| 900 | { |
| 901 | Q_Q(const QQuickPointerHandler); |
| 902 | QStyleHints *styleHints = qApp->styleHints(); |
| 903 | bool overThreshold = qAbs(t: d) > q->dragThreshold(); |
| 904 | const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0); |
| 905 | if (!overThreshold && dragVelocityLimitAvailable) { |
| 906 | qreal velocity = qreal(axis == Qt::XAxis ? p.velocity().x() : p.velocity().y()); |
| 907 | overThreshold |= qAbs(t: velocity) > styleHints->startDragVelocity(); |
| 908 | } |
| 909 | return overThreshold; |
| 910 | } |
| 911 | |
| 912 | /*! |
| 913 | Returns \c true if the movement \a delta in pixels exceeds |
| 914 | QQuickPointerHandler::dragThreshold(). |
| 915 | |
| 916 | \sa QQuickDeliveryAgentPrivate::dragOverThreshold() |
| 917 | */ |
| 918 | bool QQuickPointerHandlerPrivate::dragOverThreshold(QVector2D delta) const |
| 919 | { |
| 920 | Q_Q(const QQuickPointerHandler); |
| 921 | const float threshold = q->dragThreshold(); |
| 922 | return qAbs(t: delta.x()) > threshold || qAbs(t: delta.y()) > threshold; |
| 923 | } |
| 924 | |
| 925 | /*! |
| 926 | Returns \c true if the movement delta of \a point in pixels |
| 927 | (calculated as QEventPoint::scenePosition() - QEventPoint::scenePressPosition()) |
| 928 | exceeds QQuickPointerHandler::dragThreshold(). |
| 929 | |
| 930 | \sa QQuickDeliveryAgentPrivate::dragOverThreshold() |
| 931 | */ |
| 932 | bool QQuickPointerHandlerPrivate::dragOverThreshold(const QEventPoint &point) const |
| 933 | { |
| 934 | QPointF delta = point.scenePosition() - point.scenePressPosition(); |
| 935 | return (dragOverThreshold(d: delta.x(), axis: Qt::XAxis, p: point) || |
| 936 | dragOverThreshold(d: delta.y(), axis: Qt::YAxis, p: point)); |
| 937 | } |
| 938 | |
| 939 | QVector<QObject *> &QQuickPointerHandlerPrivate::deviceDeliveryTargets(const QInputDevice *device) |
| 940 | { |
| 941 | return QQuickDeliveryAgentPrivate::deviceExtra(device)->deliveryTargets; |
| 942 | } |
| 943 | |
| 944 | QT_END_NAMESPACE |
| 945 | |
| 946 | #include "moc_qquickpointerhandler_p.cpp" |
| 947 | |