1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qquickpointerhandler_p.h"
41#include "qquickpointerhandler_p_p.h"
42#include <QtQuick/private/qquickitem_p.h>
43
44QT_BEGIN_NAMESPACE
45
46Q_LOGGING_CATEGORY(lcPointerHandlerDispatch, "qt.quick.handler.dispatch")
47Q_LOGGING_CATEGORY(lcPointerHandlerGrab, "qt.quick.handler.grab")
48Q_LOGGING_CATEGORY(lcPointerHandlerActive, "qt.quick.handler.active")
49
50/*!
51 \qmltype PointerHandler
52 \qmlabstract
53 \since 5.10
54 \instantiates QQuickPointerHandler
55 \inqmlmodule QtQuick
56 \brief Abstract handler for pointer events.
57
58 PointerHandler is the base class Input Handler (not registered as a QML type) for
59 events from any kind of pointing device (touch, mouse or graphics tablet).
60*/
61
62QQuickPointerHandler::QQuickPointerHandler(QQuickItem *parent)
63 : QObject(*(new QQuickPointerHandlerPrivate), parent)
64{
65}
66
67QQuickPointerHandler::QQuickPointerHandler(QQuickPointerHandlerPrivate &dd, QQuickItem *parent)
68 : QObject(dd, parent)
69{
70}
71
72QQuickPointerHandler::~QQuickPointerHandler()
73{
74 QQuickItem *parItem = parentItem();
75 if (parItem) {
76 QQuickItemPrivate *p = QQuickItemPrivate::get(item: parItem);
77 p->extra.value().pointerHandlers.removeOne(t: this);
78 }
79}
80
81/*!
82 \qmlproperty real PointerHandler::margin
83
84 The margin beyond the bounds of the \l {PointerHandler::parent}{parent}
85 item within which an event point can activate this handler. For example, on
86 a PinchHandler where the \l {PointerHandler::target}{target} is also the
87 \c parent, it's useful to set this to a distance at least half the width
88 of a typical user's finger, so that if the \c parent has been scaled down
89 to a very small size, the pinch gesture is still possible. Or, if a
90 TapHandler-based button is placed near the screen edge, it can be used
91 to comply with Fitts's Law: react to mouse clicks at the screen edge
92 even though the button is visually spaced away from the edge by a few pixels.
93
94 The default value is 0.
95
96 \image pointerHandlerMargin.png
97*/
98qreal QQuickPointerHandler::margin() const
99{
100 Q_D(const QQuickPointerHandler);
101 return d->m_margin;
102}
103
104void QQuickPointerHandler::setMargin(qreal pointDistanceThreshold)
105{
106 Q_D(QQuickPointerHandler);
107 if (d->m_margin == pointDistanceThreshold)
108 return;
109
110 d->m_margin = pointDistanceThreshold;
111 emit marginChanged();
112}
113
114/*!
115 \qmlproperty int PointerHandler::dragThreshold
116 \since 5.15
117
118 The distance in pixels that the user must drag an event point in order to
119 have it treated as a drag gesture.
120
121 The default value depends on the platform and screen resolution.
122 It can be reset back to the default value by setting it to undefined.
123 The behavior when a drag gesture begins varies in different handlers.
124*/
125int QQuickPointerHandler::dragThreshold() const
126{
127 Q_D(const QQuickPointerHandler);
128 if (d->dragThreshold < 0)
129 return qApp->styleHints()->startDragDistance();
130 return d->dragThreshold;
131}
132
133void QQuickPointerHandler::setDragThreshold(int t)
134{
135 Q_D(QQuickPointerHandler);
136 if (d->dragThreshold == t)
137 return;
138
139 if (t > std::numeric_limits<qint16>::max())
140 qWarning() << "drag threshold cannot exceed" << std::numeric_limits<qint16>::max();
141 d->dragThreshold = qint16(t);
142 emit dragThresholdChanged();
143}
144
145void QQuickPointerHandler::resetDragThreshold()
146{
147 Q_D(QQuickPointerHandler);
148 if (d->dragThreshold < 0)
149 return;
150
151 d->dragThreshold = -1;
152 emit dragThresholdChanged();
153}
154
155/*!
156 \since 5.15
157 \qmlproperty Qt::CursorShape PointerHandler::cursorShape
158 This property holds the cursor shape that will appear whenever the mouse is
159 hovering over the \l parentItem while \l active is \c true.
160
161 The available cursor shapes are:
162 \list
163 \li Qt.ArrowCursor
164 \li Qt.UpArrowCursor
165 \li Qt.CrossCursor
166 \li Qt.WaitCursor
167 \li Qt.IBeamCursor
168 \li Qt.SizeVerCursor
169 \li Qt.SizeHorCursor
170 \li Qt.SizeBDiagCursor
171 \li Qt.SizeFDiagCursor
172 \li Qt.SizeAllCursor
173 \li Qt.BlankCursor
174 \li Qt.SplitVCursor
175 \li Qt.SplitHCursor
176 \li Qt.PointingHandCursor
177 \li Qt.ForbiddenCursor
178 \li Qt.WhatsThisCursor
179 \li Qt.BusyCursor
180 \li Qt.OpenHandCursor
181 \li Qt.ClosedHandCursor
182 \li Qt.DragCopyCursor
183 \li Qt.DragMoveCursor
184 \li Qt.DragLinkCursor
185 \endlist
186
187 The default value is not set, which allows the \l {QQuickItem::cursor()}{cursor}
188 of \l parentItem to appear. This property can be reset to the same initial
189 condition by setting it to undefined.
190
191 \note When this property has not been set, or has been set to \c undefined,
192 if you read the value it will return \c Qt.ArrowCursor.
193
194 \sa Qt::CursorShape, QQuickItem::cursor(), HoverHandler::cursorShape
195*/
196#if QT_CONFIG(cursor)
197Qt::CursorShape QQuickPointerHandler::cursorShape() const
198{
199 Q_D(const QQuickPointerHandler);
200 return d->cursorShape;
201}
202
203void QQuickPointerHandler::setCursorShape(Qt::CursorShape shape)
204{
205 Q_D(QQuickPointerHandler);
206 if (d->cursorSet && shape == d->cursorShape)
207 return;
208 d->cursorShape = shape;
209 d->cursorSet = true;
210 if (auto *par = qmlobject_cast<QQuickItem *>(object: parent())) {
211 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item: par);
212 itemPriv->hasCursorHandler = true;
213 itemPriv->setHasCursorInChild(true);
214 }
215 emit cursorShapeChanged();
216}
217
218void QQuickPointerHandler::resetCursorShape()
219{
220 Q_D(QQuickPointerHandler);
221 if (!d->cursorSet)
222 return;
223 d->cursorShape = Qt::ArrowCursor;
224 d->cursorSet = false;
225 if (auto *parent = parentItem()) {
226 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item: parent);
227 itemPriv->hasCursorHandler = false;
228 itemPriv->setHasCursorInChild(itemPriv->hasCursor);
229 }
230 emit cursorShapeChanged();
231}
232
233bool QQuickPointerHandler::isCursorShapeExplicitlySet() const
234{
235 Q_D(const QQuickPointerHandler);
236 return d->cursorSet;
237}
238#endif
239
240/*!
241 Notification that the grab has changed in some way which is relevant to this handler.
242 The \a grabber (subject) will be the Input Handler whose state is changing,
243 or null if the state change regards an Item.
244 The \a transition (verb) tells what happened.
245 The \a point (object) is the point that was grabbed or ungrabbed.
246 EventPoint has the sole responsibility to call this function.
247 The Input Handler must react in whatever way is appropriate, and must
248 emit the relevant signals (for the benefit of QML code).
249 A subclass is allowed to override this virtual function, but must always
250 call its parent class's implementation in addition to (usually after)
251 whatever custom behavior it implements.
252*/
253void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point)
254{
255 qCDebug(lcPointerHandlerGrab) << point << transition << grabber;
256 Q_ASSERT(point);
257 if (grabber == this) {
258 bool wasCanceled = false;
259 switch (transition) {
260 case QQuickEventPoint::GrabPassive:
261 case QQuickEventPoint::GrabExclusive:
262 break;
263 case QQuickEventPoint::CancelGrabPassive:
264 case QQuickEventPoint::CancelGrabExclusive:
265 wasCanceled = true; // the grab was stolen by something else
266 Q_FALLTHROUGH();
267 case QQuickEventPoint::UngrabPassive:
268 case QQuickEventPoint::UngrabExclusive:
269 setActive(false);
270 point->setAccepted(false);
271 if (auto par = parentItem()) {
272 Q_D(const QQuickPointerHandler);
273 par->setKeepMouseGrab(d->hadKeepMouseGrab);
274 par->setKeepTouchGrab(d->hadKeepTouchGrab);
275 }
276 break;
277 case QQuickEventPoint::OverrideGrabPassive:
278 // Passive grab is still there, but we won't receive point updates right now.
279 // No need to notify about this.
280 return;
281 }
282 if (wasCanceled)
283 emit canceled(point);
284 emit grabChanged(transition, point);
285 }
286}
287
288/*!
289 Acquire or give up a passive grab of the given \a point, according to the \a grab state.
290
291 Unlike the exclusive grab, multiple Input Handlers can have passive grabs
292 simultaneously. This means that each of them will receive further events
293 when the \a point moves, and when it is finally released. Typically an
294 Input Handler should acquire a passive grab as soon as a point is pressed,
295 if the handler's constraints do not clearly rule out any interest in that
296 point. For example, DragHandler needs a passive grab in order to watch the
297 movement of a point to see whether it will be dragged past the drag
298 threshold. When a handler is actively manipulating its \l target (that is,
299 when \l active is true), it may be able to do its work with only a passive
300 grab, or it may acquire an exclusive grab if the gesture clearly must not
301 be interpreted in another way by another handler.
302*/
303void QQuickPointerHandler::setPassiveGrab(QQuickEventPoint *point, bool grab)
304{
305 qCDebug(lcPointerHandlerGrab) << point << grab;
306 if (grab) {
307 point->setGrabberPointerHandler(exclusiveGrabber: this, exclusive: false);
308 } else {
309 point->removePassiveGrabber(handler: this);
310 }
311}
312
313/*!
314 Check whether it's OK to take an exclusive grab of the \a point.
315
316 The default implementation will call approveGrabTransition() to check this
317 handler's \l grabPermissions. If grabbing can be done only by taking over
318 the exclusive grab from an Item, approveGrabTransition() checks the Item's
319 \l keepMouseGrab or \l keepTouchGrab flags appropriately. If grabbing can
320 be done only by taking over another handler's exclusive grab, canGrab()
321 also calls approveGrabTransition() on the handler which is about to lose
322 its grab. Either one can deny the takeover.
323*/
324bool QQuickPointerHandler::canGrab(QQuickEventPoint *point)
325{
326 QQuickPointerHandler *existingPhGrabber = point->grabberPointerHandler();
327 return approveGrabTransition(point, proposedGrabber: this) &&
328 (existingPhGrabber ? existingPhGrabber->approveGrabTransition(point, proposedGrabber: this) : true);
329}
330
331/*!
332 Check this handler's rules to see if \l proposedGrabber will be allowed to take
333 the exclusive grab. This function may be called twice: once on the instance which
334 will take the grab, and once on the instance which would thereby lose its grab,
335 in case of a takeover scenario.
336*/
337bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObject *proposedGrabber)
338{
339 Q_D(const QQuickPointerHandler);
340 bool allowed = false;
341 if (proposedGrabber == this) {
342 QObject* existingGrabber = point->exclusiveGrabber();
343 allowed = (existingGrabber == nullptr) || ((d->grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything);
344 if (existingGrabber) {
345 if (QQuickPointerHandler *existingPhGrabber = point->grabberPointerHandler()) {
346 if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfDifferentType) &&
347 existingPhGrabber->metaObject()->className() != metaObject()->className())
348 allowed = true;
349 if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfSameType) &&
350 existingPhGrabber->metaObject()->className() == metaObject()->className())
351 allowed = true;
352 } else if ((d->grabPermissions & CanTakeOverFromItems)) {
353 allowed = true;
354 QQuickItem * existingItemGrabber = point->grabberItem();
355 QQuickWindowPrivate *winPriv = QQuickWindowPrivate::get(c: parentItem()->window());
356 const bool isMouse = point->pointerEvent()->asPointerMouseEvent();
357 const bool isTouch = point->pointerEvent()->asPointerTouchEvent();
358 if (existingItemGrabber &&
359 ((existingItemGrabber->keepMouseGrab() &&
360 (isMouse || winPriv->isDeliveringTouchAsMouse())) ||
361 (existingItemGrabber->keepTouchGrab() && isTouch))) {
362 allowed = false;
363 // If the handler wants to steal the exclusive grab from an Item, the Item can usually veto
364 // by having its keepMouseGrab flag set. But an exception is if that Item is a parent that
365 // normally filters events (such as a Flickable): it needs to be possible for e.g. a
366 // DragHandler to operate on an Item inside a Flickable. Flickable is aggressive about
367 // grabbing on press (for fear of missing updates), but DragHandler uses a passive grab
368 // at first and then expects to be able to steal the grab later on. It cannot respect
369 // Flickable's wishes in that case, because then it would never have a chance.
370 if (existingItemGrabber->keepMouseGrab() &&
371 existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(child: parentItem())) {
372 if (winPriv->isDeliveringTouchAsMouse() && point->pointId() == winPriv->touchMouseId) {
373 qCDebug(lcPointerHandlerGrab) << this << "steals touchpoint" << point->pointId()
374 << "despite parent touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber;
375 allowed = true;
376 }
377 }
378 if (!allowed) {
379 qCDebug(lcPointerHandlerGrab) << this << "wants to grab point" << point->pointId()
380 << "but declines to steal from grabber" << existingItemGrabber
381 << "with keepMouseGrab=" << existingItemGrabber->keepMouseGrab()
382 << "keepTouchGrab=" << existingItemGrabber->keepTouchGrab();
383 }
384 }
385 }
386 }
387 } else {
388 // proposedGrabber is different: that means this instance will lose its grab
389 if (proposedGrabber) {
390 if ((d->grabPermissions & ApprovesTakeOverByAnything) == ApprovesTakeOverByAnything)
391 allowed = true;
392 if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfDifferentType) &&
393 proposedGrabber->metaObject()->className() != metaObject()->className())
394 allowed = true;
395 if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfSameType) &&
396 proposedGrabber->metaObject()->className() == metaObject()->className())
397 allowed = true;
398 if (!allowed && (d->grabPermissions & ApprovesTakeOverByItems) && proposedGrabber->inherits(classname: "QQuickItem"))
399 allowed = true;
400 } else {
401 if (!allowed && (d->grabPermissions & ApprovesCancellation))
402 allowed = true;
403 }
404 }
405 qCDebug(lcPointerHandlerGrab) << "point" << Qt::hex << point->pointId() << "permission" <<
406 QMetaEnum::fromType<GrabPermissions>().valueToKeys(value: grabPermissions()) <<
407 ':' << this << (allowed ? "approved to" : "denied to") << proposedGrabber;
408 return allowed;
409}
410
411/*!
412 \qmlproperty flags QtQuick::PointerHandler::grabPermissions
413
414 This property specifies the permissions when this handler's logic decides
415 to take over the exclusive grab, or when it is asked to approve grab
416 takeover or cancellation by another handler.
417
418 \value PointerHandler.TakeOverForbidden
419 This handler neither takes from nor gives grab permission to any type of Item or Handler.
420 \value PointerHandler.CanTakeOverFromHandlersOfSameType
421 This handler can take the exclusive grab from another handler of the same class.
422 \value PointerHandler.CanTakeOverFromHandlersOfDifferentType
423 This handler can take the exclusive grab from any kind of handler.
424 \value PointerHandler.CanTakeOverFromAnything
425 This handler can take the exclusive grab from any type of Item or Handler.
426 \value PointerHandler.ApprovesTakeOverByHandlersOfSameType
427 This handler gives permission for another handler of the same class to take the grab.
428 \value PointerHandler.ApprovesTakeOverByHandlersOfDifferentType
429 This handler gives permission for any kind of handler to take the grab.
430 \value PointerHandler.ApprovesTakeOverByItems
431 This handler gives permission for any kind of Item to take the grab.
432 \value PointerHandler.ApprovesCancellation
433 This handler will allow its grab to be set to null.
434 \value PointerHandler.ApprovesTakeOverByAnything
435 This handler gives permission for any any type of Item or Handler to take the grab.
436
437 The default is
438 \c {PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByAnything}
439 which allows most takeover scenarios but avoids e.g. two PinchHandlers fighting
440 over the same touchpoints.
441*/
442QQuickPointerHandler::GrabPermissions QQuickPointerHandler::grabPermissions() const
443{
444 Q_D(const QQuickPointerHandler);
445 return static_cast<QQuickPointerHandler::GrabPermissions>(d->grabPermissions);
446}
447
448void QQuickPointerHandler::setGrabPermissions(GrabPermissions grabPermission)
449{
450 Q_D(QQuickPointerHandler);
451 if (d->grabPermissions == grabPermission)
452 return;
453
454 d->grabPermissions = grabPermission;
455 emit grabPermissionChanged();
456}
457
458void QQuickPointerHandler::classBegin()
459{
460}
461
462void QQuickPointerHandler::componentComplete()
463{
464 Q_D(const QQuickPointerHandler);
465 if (d->cursorSet) {
466 if (auto *parent = parentItem()) {
467 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item: parent);
468 itemPriv->hasCursorHandler = true;
469 itemPriv->setHasCursorInChild(true);
470 }
471 }
472}
473
474QQuickPointerEvent *QQuickPointerHandler::currentEvent()
475{
476 Q_D(const QQuickPointerHandler);
477 return d->currentEvent;
478}
479
480/*!
481 Acquire or give up the exclusive grab of the given \a point, according to
482 the \a grab state, and subject to the rules: canGrab(), and the rule not to
483 relinquish another handler's grab. Returns true if permission is granted,
484 or if the exclusive grab has already been acquired or relinquished as
485 specified. Returns false if permission is denied either by this handler or
486 by the handler or item from which this handler would take over
487*/
488bool QQuickPointerHandler::setExclusiveGrab(QQuickEventPoint *point, bool grab)
489{
490 if ((grab && point->exclusiveGrabber() == this) || (!grab && point->exclusiveGrabber() != this))
491 return true;
492 // TODO m_hadKeepMouseGrab m_hadKeepTouchGrab
493 bool allowed = true;
494 if (grab) {
495 allowed = canGrab(point);
496 } else {
497 QQuickPointerHandler *existingPhGrabber = point->grabberPointerHandler();
498 // Ask before allowing one handler to cancel another's grab
499 if (existingPhGrabber && existingPhGrabber != this && !existingPhGrabber->approveGrabTransition(point, proposedGrabber: nullptr))
500 allowed = false;
501 }
502 qCDebug(lcPointerHandlerGrab) << point << (grab ? "grab" : "ungrab") << (allowed ? "allowed" : "forbidden") <<
503 point->exclusiveGrabber() << "->" << (grab ? this : nullptr);
504 if (allowed)
505 point->setGrabberPointerHandler(exclusiveGrabber: grab ? this : nullptr, exclusive: true);
506 return allowed;
507}
508
509/*!
510 Cancel any existing grab of the given \a point.
511*/
512void QQuickPointerHandler::cancelAllGrabs(QQuickEventPoint *point)
513{
514 qCDebug(lcPointerHandlerGrab) << point;
515 point->cancelAllGrabs(handler: this);
516}
517
518QPointF QQuickPointerHandler::eventPos(const QQuickEventPoint *point) const
519{
520 return (target() ? target()->mapFromScene(point: point->scenePosition()) : point->scenePosition());
521}
522
523bool QQuickPointerHandler::parentContains(const QQuickEventPoint *point) const
524{
525 if (!point)
526 return false;
527 if (QQuickItem *par = parentItem()) {
528 if (par->window()) {
529 QRect windowGeometry = par->window()->geometry();
530 if (!par->window()->isTopLevel())
531 windowGeometry = QRect(QWindowPrivate::get(window: par->window())->globalPosition(), par->window()->size());
532 QPoint screenPosition = par->window()->mapToGlobal(pos: point->scenePosition().toPoint());
533 if (!windowGeometry.contains(p: screenPosition))
534 return false;
535 }
536 QPointF p = par->mapFromScene(point: point->scenePosition());
537 qreal m = margin();
538 if (m > 0)
539 return p.x() >= -m && p.y() >= -m && p.x() <= par->width() + m && p.y() <= par->height() + m;
540 return par->contains(point: p);
541 }
542 return false;
543}
544
545/*!
546 \qmlproperty bool QtQuick::PointerHandler::enabled
547
548 If a PointerHandler is disabled, it will reject all events
549 and no signals will be emitted.
550*/
551bool QQuickPointerHandler::enabled() const
552{
553 Q_D(const QQuickPointerHandler);
554 return d->enabled;
555}
556
557void QQuickPointerHandler::setEnabled(bool enabled)
558{
559 Q_D(QQuickPointerHandler);
560 if (d->enabled == enabled)
561 return;
562
563 d->enabled = enabled;
564 emit enabledChanged();
565}
566
567bool QQuickPointerHandler::active() const
568{
569 Q_D(const QQuickPointerHandler);
570 return d->active;
571}
572
573/*!
574 \qmlproperty Item QtQuick::PointerHandler::target
575
576 The Item which this handler will manipulate.
577
578 By default, it is the same as the \l [QML] {parent}, the Item within which
579 the handler is declared. However, it can sometimes be useful to set the
580 target to a different Item, in order to handle events within one item
581 but manipulate another; or to \c null, to disable the default behavior
582 and do something else instead.
583*/
584void QQuickPointerHandler::setTarget(QQuickItem *target)
585{
586 Q_D(QQuickPointerHandler);
587 d->targetExplicitlySet = true;
588 if (d->target == target)
589 return;
590
591 QQuickItem *oldTarget = d->target;
592 d->target = target;
593 onTargetChanged(oldTarget);
594 emit targetChanged();
595}
596
597QQuickItem *QQuickPointerHandler::parentItem() const
598{
599 return static_cast<QQuickItem *>(QObject::parent());
600}
601
602QQuickItem *QQuickPointerHandler::target() const
603{
604 Q_D(const QQuickPointerHandler);
605 if (!d->targetExplicitlySet)
606 return parentItem();
607 return d->target;
608}
609
610void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event)
611{
612 bool wants = wantsPointerEvent(event);
613 qCDebug(lcPointerHandlerDispatch) << metaObject()->className() << objectName()
614 << "on" << parentItem()->metaObject()->className() << parentItem()->objectName()
615 << (wants ? "WANTS" : "DECLINES") << event;
616 if (wants) {
617 handlePointerEventImpl(event);
618 } else {
619 setActive(false);
620 int pCount = event->pointCount();
621 for (int i = 0; i < pCount; ++i) {
622 QQuickEventPoint *pt = event->point(i);
623 if (pt->grabberPointerHandler() == this && pt->state() != QQuickEventPoint::Stationary)
624 pt->cancelExclusiveGrab();
625 }
626 }
627 event->device()->eventDeliveryTargets().append(t: this);
628}
629
630bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event)
631{
632 Q_D(const QQuickPointerHandler);
633 Q_UNUSED(event)
634 return d->enabled;
635}
636
637bool QQuickPointerHandler::wantsEventPoint(QQuickEventPoint *point)
638{
639 bool ret = point->exclusiveGrabber() == this || point->passiveGrabbers().contains(t: this) || parentContains(point);
640 qCDebug(lcPointerHandlerDispatch) << Qt::hex << point->pointId() << "@" << point->scenePosition()
641 << metaObject()->className() << objectName() << ret;
642 return ret;
643}
644
645/*!
646 \readonly
647 \qmlproperty bool QtQuick::PointerHandler::active
648
649 This holds true whenever this Input Handler has taken sole responsibility
650 for handing one or more EventPoints, by successfully taking an exclusive
651 grab of those points. This means that it is keeping its properties
652 up-to-date according to the movements of those Event Points and actively
653 manipulating its \l target (if any).
654*/
655void QQuickPointerHandler::setActive(bool active)
656{
657 Q_D(QQuickPointerHandler);
658 if (d->active != active) {
659 qCDebug(lcPointerHandlerActive) << this << d->active << "->" << active;
660 d->active = active;
661 onActiveChanged();
662 emit activeChanged();
663 }
664}
665
666void QQuickPointerHandler::handlePointerEventImpl(QQuickPointerEvent *event)
667{
668 Q_D(QQuickPointerHandler);
669 d->currentEvent = event;
670}
671
672/*!
673 \readonly
674 \qmlproperty Item QtQuick::PointerHandler::parent
675
676 The \l Item which is the scope of the handler; the Item in which it was declared.
677 The handler will handle events on behalf of this Item, which means a
678 pointer event is relevant if at least one of its event points occurs within
679 the Item's interior. Initially \l [QML] {target} {target()} is the same, but it
680 can be reassigned.
681
682 \sa {target}, QObject::parent()
683*/
684
685/*!
686 \qmlsignal QtQuick::PointerHandler::grabChanged(GrabTransition transition, EventPoint point)
687
688 This signal is emitted when the grab has changed in some way which is
689 relevant to this handler.
690
691 The \a transition (verb) tells what happened.
692 The \a point (object) is the point that was grabbed or ungrabbed.
693*/
694
695/*!
696 \qmlsignal QtQuick::PointerHandler::canceled(EventPoint point)
697
698 If this handler has already grabbed the given \a point, this signal is
699 emitted when the grab is stolen by a different Pointer Handler or Item.
700*/
701
702QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate()
703 : grabPermissions(QQuickPointerHandler::CanTakeOverFromItems |
704 QQuickPointerHandler::CanTakeOverFromHandlersOfDifferentType |
705 QQuickPointerHandler::ApprovesTakeOverByAnything)
706 , cursorShape(Qt::ArrowCursor)
707 , enabled(true)
708 , active(false)
709 , targetExplicitlySet(false)
710 , hadKeepMouseGrab(false)
711 , hadKeepTouchGrab(false)
712 , cursorSet(false)
713{
714}
715
716template <typename TEventPoint>
717bool QQuickPointerHandlerPrivate::dragOverThreshold(qreal d, Qt::Axis axis, const TEventPoint *p) const
718{
719 Q_Q(const QQuickPointerHandler);
720 QStyleHints *styleHints = qApp->styleHints();
721 bool overThreshold = qAbs(t: d) > q->dragThreshold();
722 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
723 if (!overThreshold && dragVelocityLimitAvailable) {
724 qreal velocity = qreal(axis == Qt::XAxis ? p->velocity().x() : p->velocity().y());
725 overThreshold |= qAbs(t: velocity) > styleHints->startDragVelocity();
726 }
727 return overThreshold;
728}
729
730bool QQuickPointerHandlerPrivate::dragOverThreshold(QVector2D delta) const
731{
732 Q_Q(const QQuickPointerHandler);
733 const float threshold = q->dragThreshold();
734 return qAbs(t: delta.x()) > threshold || qAbs(t: delta.y()) > threshold;
735}
736
737bool QQuickPointerHandlerPrivate::dragOverThreshold(const QQuickEventPoint *point) const
738{
739 QPointF delta = point->scenePosition() - point->scenePressPosition();
740 return (dragOverThreshold(d: delta.x(), axis: Qt::XAxis, p: point) ||
741 dragOverThreshold(d: delta.y(), axis: Qt::YAxis, p: point));
742}
743
744QT_END_NAMESPACE
745

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/quick/handlers/qquickpointerhandler.cpp