1// Copyright (C) 2016 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 "qquickmousearea_p.h"
5#include "qquickmousearea_p_p.h"
6#include "qquickwindow.h"
7#if QT_CONFIG(quick_draganddrop)
8#include "qquickdrag_p.h"
9#endif
10
11#include <private/qqmldata_p.h>
12#include <private/qsgadaptationlayer_p.h>
13
14#include <QtGui/private/qguiapplication_p.h>
15#include <QtGui/qevent.h>
16#include <QtGui/qstylehints.h>
17
18#include <float.h>
19
20QT_BEGIN_NAMESPACE
21
22DEFINE_BOOL_CONFIG_OPTION(qmlMaVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
23
24Q_DECLARE_LOGGING_CATEGORY(lcHoverTrace)
25
26QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
27: enabled(true), hoverEnabled(false), scrollGestureEnabled(true), hovered(false), longPress(false),
28 moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
29 propagateComposedEvents(false), overThreshold(false),
30 pressAndHoldInterval(-1)
31#if QT_CONFIG(quick_draganddrop)
32 , drag(nullptr)
33#endif
34#if QT_CONFIG(cursor)
35 , cursor(nullptr)
36#endif
37{
38}
39
40QQuickMouseAreaPrivate::~QQuickMouseAreaPrivate()
41{
42#if QT_CONFIG(quick_draganddrop)
43 delete drag;
44#endif
45#if QT_CONFIG(cursor)
46 delete cursor;
47#endif
48}
49
50void QQuickMouseAreaPrivate::init()
51{
52 Q_Q(QQuickMouseArea);
53 q->setAcceptedMouseButtons(Qt::LeftButton);
54 q->setAcceptTouchEvents(false); // rely on mouse events synthesized from touch
55 q->setFiltersChildMouseEvents(true);
56 if (qmlMaVisualTouchDebugging()) {
57 q->setFlag(flag: QQuickItem::ItemHasContents);
58 }
59}
60
61void QQuickMouseAreaPrivate::saveEvent(QMouseEvent *event)
62{
63 lastPos = event->position();
64 lastScenePos = event->scenePosition();
65 lastButton = event->button();
66 lastButtons = event->buttons();
67 lastModifiers = event->modifiers();
68 lastFlags = event->flags();
69}
70
71bool QQuickMouseAreaPrivate::isPressAndHoldConnected()
72{
73 Q_Q(QQuickMouseArea);
74 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, pressAndHold, (QQuickMouseEvent *));
75}
76
77bool QQuickMouseAreaPrivate::isDoubleClickConnected()
78{
79 Q_Q(QQuickMouseArea);
80 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, doubleClicked, (QQuickMouseEvent *));
81}
82
83bool QQuickMouseAreaPrivate::isClickConnected()
84{
85 Q_Q(QQuickMouseArea);
86 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, clicked, (QQuickMouseEvent *));
87}
88
89#if QT_CONFIG(wheelevent)
90bool QQuickMouseAreaPrivate::isWheelConnected()
91{
92 Q_Q(QQuickMouseArea);
93 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, wheel, (QQuickWheelEvent *));
94}
95#endif
96
97void QQuickMouseAreaPrivate::propagate(QQuickMouseEvent* event, PropagateType t)
98{
99 Q_Q(QQuickMouseArea);
100 if (!window || !propagateComposedEvents)
101 return;
102 QPointF scenePos = q->mapToScene(point: QPointF(event->x(), event->y()));
103 propagateHelper(event, window->contentItem(), scenePos, t);
104}
105
106bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *item,const QPointF &sp, PropagateType sig)
107{
108 //Based off of QQuickWindow::deliverInitialMousePressEvent
109 //But specific to MouseArea, so doesn't belong in window
110 Q_Q(const QQuickMouseArea);
111 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
112
113 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
114 QPointF p = item->mapFromScene(point: sp);
115 if (!item->contains(point: p))
116 return false;
117 }
118
119 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
120 for (int ii = children.size() - 1; ii >= 0; --ii) {
121 QQuickItem *child = children.at(i: ii);
122 if (!child->isVisible() || !child->isEnabled())
123 continue;
124 if (propagateHelper(ev, item: child, sp, sig))
125 return true;
126 }
127
128 QQuickMouseArea* ma = qobject_cast<QQuickMouseArea*>(object: item);
129 if (ma && ma != q && ma->isEnabled() && itemPrivate->acceptedMouseButtons() & ev->button()) {
130 switch (sig) {
131 case Click:
132 if (!ma->d_func()->isClickConnected())
133 return false;
134 break;
135 case DoubleClick:
136 if (!ma->d_func()->isDoubleClickConnected())
137 return false;
138 break;
139 case PressAndHold:
140 if (!ma->d_func()->isPressAndHoldConnected())
141 return false;
142 break;
143 }
144 QPointF p = item->mapFromScene(point: sp);
145 if (item->contains(point: p)) {
146 ev->setX(p.x());
147 ev->setY(p.y());
148 ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
149 switch (sig) {
150 case Click: emit ma->clicked(mouse: ev); break;
151 case DoubleClick: emit ma->doubleClicked(mouse: ev); break;
152 case PressAndHold: emit ma->pressAndHold(mouse: ev); break;
153 }
154 if (ev->isAccepted())
155 return true;
156 }
157 }
158 return false;
159
160}
161
162/*!
163 \qmltype MouseArea
164 \nativetype QQuickMouseArea
165 \inqmlmodule QtQuick
166 \ingroup qtquick-input
167 \brief Enables simple mouse handling.
168 \inherits Item
169
170 A MouseArea is an invisible item that is typically used in conjunction with
171 a visible item in order to provide mouse handling for that item.
172 By effectively acting as a proxy, the logic for mouse handling can be
173 contained within a MouseArea item.
174
175 The \l enabled property is used to enable and disable mouse handling for
176 the proxied item. When disabled, the mouse area becomes transparent to
177 mouse events.
178
179 MouseArea is an invisible Item, but it has a visible property.
180 When set to false, the mouse area becomes transparent to mouse events.
181
182 The \l pressed read-only property indicates whether or not the user is
183 holding down a mouse button over the mouse area. This property is often
184 used in bindings between properties in a user interface. The containsMouse
185 read-only property indicates the presence of the mouse cursor over the
186 mouse area but, by default, only when a mouse button is held down; see
187 the containsMouse documentation for details.
188
189 Information about the mouse position and button clicks are provided via
190 signals for which event handler properties are defined. The most commonly
191 used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
192 onPressed, onReleased and onPressAndHold. It's also possible to handle mouse
193 wheel events via the onWheel signal.
194
195 If a MouseArea overlaps with the area of other MouseArea items, you can choose
196 to propagate \c clicked, \c doubleClicked and \c pressAndHold events to these
197 other items by setting propagateComposedEvents to true and rejecting events
198 that should be propagated. See the propagateComposedEvents documentation for
199 details.
200
201 By default, MouseArea items only report mouse clicks and not changes to the
202 position of the mouse cursor. Setting the hoverEnabled property ensures that
203 handlers defined for onPositionChanged, onEntered and onExited are used and
204 that the containsMouse property is updated even when no mouse buttons are
205 pressed.
206
207 \section1 Example Usage
208
209 \div {class="float-right"}
210 \inlineimage qml-mousearea-snippet.png
211 \enddiv
212
213 The following example uses a MouseArea in a \l Rectangle that changes
214 the \l Rectangle color to red when clicked:
215
216 \snippet qml/mousearea/mousearea.qml import
217 \codeline
218 \snippet qml/mousearea/mousearea.qml intro
219
220 \clearfloat
221 Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
222 additional information about the mouse event, such as the position, button,
223 and any key modifiers.
224
225 Here is an extension of the previous example that produces a different
226 color when the area is right clicked:
227
228 \snippet qml/mousearea/mousearea.qml intro-extended
229
230 \sa MouseEvent, {mousearea}{MouseArea example},
231 {Important Concepts In Qt Quick - User Input}
232*/
233
234/*!
235 \qmlsignal QtQuick::MouseArea::entered()
236
237 This signal is emitted when the mouse enters the mouse area.
238
239 By default this signal is only emitted if a button is currently
240 pressed. Set \l hoverEnabled to true to emit this signal
241 even when no mouse button is pressed.
242
243 \sa hoverEnabled
244*/
245
246/*!
247 \qmlsignal QtQuick::MouseArea::exited()
248
249 This signal is emitted when the mouse exits the mouse area.
250
251 By default this signal is only emitted if a button is currently
252 pressed. Set \l hoverEnabled to true to emit this signal
253 even when no mouse button is pressed.
254
255 The example below shows a fairly typical relationship between
256 two MouseAreas, with \c mouseArea2 on top of \c mouseArea1. Moving the
257 mouse into \c mouseArea2 from \c mouseArea1 will cause \c mouseArea1
258 to emit the \c exited signal.
259 \qml
260 Rectangle {
261 width: 400; height: 400
262 MouseArea {
263 id: mouseArea1
264 anchors.fill: parent
265 hoverEnabled: true
266 }
267 MouseArea {
268 id: mouseArea2
269 width: 100; height: 100
270 anchors.centerIn: parent
271 hoverEnabled: true
272 }
273 }
274 \endqml
275
276 If instead you give the two MouseAreas a parent-child relationship,
277 moving the mouse into \c mouseArea2 from \c mouseArea1 will \b not
278 cause \c mouseArea1 to emit \c exited. Instead, they will
279 both be considered to be simultaneously hovered.
280
281 \sa hoverEnabled
282*/
283
284/*!
285 \qmlsignal QtQuick::MouseArea::positionChanged(MouseEvent mouse)
286
287 This signal is emitted when the mouse position changes.
288
289 The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
290 position, and any buttons currently pressed.
291
292 By default this signal is only emitted if a button is currently
293 pressed. Set \l hoverEnabled to true to emit this signal
294 even when no mouse button is pressed.
295
296 When handling this signal, changing the \l {MouseEvent::}{accepted} property of the \a mouse
297 parameter has no effect.
298*/
299
300/*!
301 \qmlsignal QtQuick::MouseArea::clicked(MouseEvent mouse)
302
303 This signal is emitted when there is a click. A click is defined as a press followed by a release,
304 both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
305 releasing is also considered a click).
306
307 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
308 position of the release of the click, and whether the click was held.
309
310 When handling this signal, changing the \l {MouseEvent::}{accepted} property of the \a mouse
311 parameter has no effect, unless the \l propagateComposedEvents property is \c true.
312*/
313
314/*!
315 \qmlsignal QtQuick::MouseArea::pressed(MouseEvent mouse)
316
317 This signal is emitted when there is a press.
318 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
319 position and which button was pressed.
320
321 When handling this signal, use the \l {MouseEvent::}{accepted} property of the \a mouse
322 parameter to control whether this MouseArea handles the press and all future mouse events until
323 release. The default is to accept the event and not allow other MouseAreas beneath this one to
324 handle the event. If \e accepted is set to false, no further events will be sent to this MouseArea
325 until the button is next pressed.
326*/
327
328/*!
329 \qmlsignal QtQuick::MouseArea::released(MouseEvent mouse)
330
331 This signal is emitted when there is a release.
332 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
333 position of the release of the click, and whether the click was held.
334
335 When handling this signal, changing the \l {MouseEvent::}{accepted} property of the \a mouse
336 parameter has no effect.
337
338 \sa canceled
339*/
340
341/*!
342 \qmlsignal QtQuick::MouseArea::pressAndHold(MouseEvent mouse)
343
344 This signal is emitted when there is a long press (currently 800ms).
345 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
346 position of the press, and which button is pressed.
347
348 When handling this signal, changing the \l {MouseEvent::}{accepted} property of the \a mouse
349 parameter has no effect, unless the \l propagateComposedEvents property is \c true.
350*/
351
352/*!
353 \qmlsignal QtQuick::MouseArea::doubleClicked(MouseEvent mouse)
354
355 This signal is emitted when there is a double-click (a press followed by a release followed by a press).
356 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
357 position of the release of the click, and whether the click was held.
358
359 When handling this signal, if the \l {MouseEvent::}{accepted} property of the \a mouse
360 parameter is set to false, the pressed/released/clicked signals will be emitted for the second
361 click; otherwise they are suppressed. The \c accepted property defaults to true.
362*/
363
364/*!
365 \qmlsignal QtQuick::MouseArea::canceled()
366
367 This signal is emitted when mouse events have been canceled, because another item stole the mouse event handling.
368
369 This signal is for advanced use: it is useful when there is more than one MouseArea
370 that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
371 case, if you execute some logic in the \c onPressed signal handler and then start dragging, the
372 \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
373 the logic when the MouseArea has lost the mouse handling to the \l Flickable,
374 \c canceled should be handled in addition to \l released.
375*/
376
377/*!
378 \qmlsignal QtQuick::MouseArea::wheel(WheelEvent wheel)
379
380 This signal is emitted in response to both mouse wheel and trackpad scroll gestures.
381
382 The \a wheel parameter provides information about the event, including the x and y
383 position, any buttons currently pressed, and information about the wheel movement, including
384 angleDelta and pixelDelta.
385*/
386
387QQuickMouseArea::QQuickMouseArea(QQuickItem *parent)
388 : QQuickItem(*(new QQuickMouseAreaPrivate), parent)
389{
390 Q_D(QQuickMouseArea);
391 d->init();
392#if QT_CONFIG(cursor)
393 // Explcitly call setCursor on QQuickItem since
394 // it internally keeps a boolean hasCursor that doesn't
395 // get set to true unless you call setCursor
396 setCursor(Qt::ArrowCursor);
397#endif
398}
399
400QQuickMouseArea::~QQuickMouseArea()
401{
402}
403
404/*!
405 \qmlproperty real QtQuick::MouseArea::mouseX
406 \qmlproperty real QtQuick::MouseArea::mouseY
407 These properties hold the coordinates of the mouse cursor.
408
409 If the hoverEnabled property is false then these properties will only be valid
410 while a button is pressed, and will remain valid as long as the button is held
411 down even if the mouse is moved outside the area.
412
413 By default, this property is false.
414
415 If hoverEnabled is true then these properties will be valid when:
416 \list
417 \li no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
418 \li a button is pressed and held, even if it has since moved out of the area.
419 \endlist
420
421 The coordinates are relative to the MouseArea.
422*/
423qreal QQuickMouseArea::mouseX() const
424{
425 Q_D(const QQuickMouseArea);
426 return d->lastPos.x();
427}
428
429qreal QQuickMouseArea::mouseY() const
430{
431 Q_D(const QQuickMouseArea);
432 return d->lastPos.y();
433}
434
435/*!
436 \qmlproperty bool QtQuick::MouseArea::enabled
437 This property holds whether the item accepts mouse events.
438
439 \note Due to historical reasons, this property is not equivalent to
440 Item.enabled. It only affects mouse events, and its effect does not
441 propagate to child items.
442
443 By default, this property is true.
444*/
445bool QQuickMouseArea::isEnabled() const
446{
447 Q_D(const QQuickMouseArea);
448 return d->enabled;
449}
450
451void QQuickMouseArea::setEnabled(bool a)
452{
453 Q_D(QQuickMouseArea);
454 if (a != d->enabled) {
455 d->enabled = a;
456 setAcceptHoverEvents(a && d->hoverEnabled);
457 emit enabledChanged();
458 }
459}
460
461/*!
462 \qmlproperty bool QtQuick::MouseArea::scrollGestureEnabled
463 \since 5.5
464
465 This property controls whether this MouseArea responds to scroll gestures
466 from non-mouse devices, such as the 2-finger flick gesture on a trackpad.
467 If set to false, the \l wheel signal be emitted only when the wheel event
468 comes from an actual mouse with a wheel, while scroll gesture events will
469 pass through to any other Item that will handle them. For example, the user
470 might perform a flick gesture while the cursor is over an item containing a
471 MouseArea, intending to interact with a Flickable which is underneath.
472 Setting this property to false will allow the PinchArea to handle the mouse
473 wheel or the pinch gesture, while the Flickable handles the flick gesture.
474
475 By default, this property is true.
476*/
477bool QQuickMouseArea::isScrollGestureEnabled() const
478{
479 Q_D(const QQuickMouseArea);
480 return d->scrollGestureEnabled;
481}
482
483void QQuickMouseArea::setScrollGestureEnabled(bool e)
484{
485 Q_D(QQuickMouseArea);
486 if (e != d->scrollGestureEnabled) {
487 d->scrollGestureEnabled = e;
488 emit scrollGestureEnabledChanged();
489 }
490}
491
492/*!
493 \qmlproperty bool QtQuick::MouseArea::preventStealing
494 This property holds whether the mouse events may be stolen from this
495 MouseArea.
496
497 If a MouseArea is placed within an item that filters child mouse
498 events, such as Flickable, the mouse
499 events may be stolen from the MouseArea if a gesture is recognized
500 by the parent item, e.g. a flick gesture. If preventStealing is
501 set to true, no item will steal the mouse events.
502
503 Note that setting preventStealing to true once an item has started
504 stealing events will have no effect until the next press event.
505
506 By default this property is false.
507*/
508bool QQuickMouseArea::preventStealing() const
509{
510 Q_D(const QQuickMouseArea);
511 return d->preventStealing;
512}
513
514void QQuickMouseArea::setPreventStealing(bool prevent)
515{
516 Q_D(QQuickMouseArea);
517 if (prevent != d->preventStealing) {
518 d->preventStealing = prevent;
519 setKeepMouseGrab(d->preventStealing && d->enabled);
520 emit preventStealingChanged();
521 }
522}
523
524
525/*!
526 \qmlproperty bool QtQuick::MouseArea::propagateComposedEvents
527 This property holds whether composed mouse events will automatically propagate to
528 other MouseAreas that overlap with this MouseArea but are lower in the visual stacking order.
529 By default, this property is false.
530
531 MouseArea contains several composed events: \c clicked, \c doubleClicked and \c pressAndHold.
532 These are composed of basic mouse events, like \c pressed, and can be propagated differently
533 in comparison to basic events.
534
535 If propagateComposedEvents is set to true, then composed events will be automatically
536 propagated to other MouseAreas in the same location in the scene. Each event is propagated
537 to the next \l enabled MouseArea beneath it in the stacking order, propagating down this visual
538 hierarchy until a MouseArea accepts the event. Unlike \c pressed events, composed events will
539 not be automatically accepted if no handler is present.
540
541 For example, below is a yellow \l Rectangle that contains a blue \l Rectangle. The blue
542 rectangle is the top-most item in the hierarchy of the visual stacking order; it will
543 visually rendered above the yellow rectangle. Since the blue rectangle sets
544 propagateComposedEvents to true, and also sets \l MouseEvent::accepted to false for all
545 received \c clicked events, any \c clicked events it receives are propagated to the
546 MouseArea of the yellow rectangle beneath it.
547
548 \qml
549 import QtQuick 2.0
550
551 Rectangle {
552 color: "yellow"
553 width: 100; height: 100
554
555 MouseArea {
556 anchors.fill: parent
557 onClicked: console.log("clicked yellow")
558 }
559
560 Rectangle {
561 color: "blue"
562 width: 50; height: 50
563
564 MouseArea {
565 anchors.fill: parent
566 propagateComposedEvents: true
567 onClicked: (mouse)=> {
568 console.log("clicked blue")
569 mouse.accepted = false
570 }
571 }
572 }
573 }
574 \endqml
575
576 Clicking on the blue rectangle will cause the \c onClicked handler of its child MouseArea to
577 be invoked; the event will then be propagated to the MouseArea of the yellow rectangle, causing
578 its own \c onClicked handler to be invoked.
579
580 This property greatly simplifies the usecase of when you want to have overlapping MouseAreas
581 handling the composed events together. For example: if you want one MouseArea to handle \c clicked
582 signals and the other to handle \c pressAndHold, or if you want one MouseArea to handle \c clicked most
583 of the time, but pass it through when certain conditions are met.
584*/
585bool QQuickMouseArea::propagateComposedEvents() const
586{
587 Q_D(const QQuickMouseArea);
588 return d->propagateComposedEvents;
589}
590
591void QQuickMouseArea::setPropagateComposedEvents(bool prevent)
592{
593 Q_D(QQuickMouseArea);
594 if (prevent != d->propagateComposedEvents) {
595 d->propagateComposedEvents = prevent;
596 setKeepMouseGrab(d->propagateComposedEvents && d->enabled);
597 emit propagateComposedEventsChanged();
598 }
599}
600
601/*!
602 \qmlproperty MouseButtons QtQuick::MouseArea::pressedButtons
603 This property holds the mouse buttons currently pressed.
604
605 It contains a bitwise combination of:
606 \list
607 \li Qt.LeftButton
608 \li Qt.RightButton
609 \li Qt.MiddleButton
610 \endlist
611
612 The code below displays "right" when the right mouse buttons is pressed:
613
614 \snippet qml/mousearea/mousearea.qml mousebuttons
615
616 \note this property only handles buttons specified in \l acceptedButtons.
617
618 \sa acceptedButtons
619*/
620Qt::MouseButtons QQuickMouseArea::pressedButtons() const
621{
622 Q_D(const QQuickMouseArea);
623 return d->pressed;
624}
625
626void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
627{
628 Q_D(QQuickMouseArea);
629 d->moved = false;
630 d->stealMouse = d->preventStealing;
631 d->overThreshold = false;
632 if (!d->enabled || !(event->button() & acceptedMouseButtons())) {
633 QQuickItem::mousePressEvent(event);
634 } else {
635 d->longPress = false;
636 d->saveEvent(event);
637#if QT_CONFIG(quick_draganddrop)
638 if (d->drag)
639 d->drag->setActive(false);
640#endif
641 setHovered(true);
642 d->startScene = event->scenePosition();
643 setKeepMouseGrab(d->stealMouse);
644 event->setAccepted(setPressed(button: event->button(), p: true, source: event->source()));
645 if (event->isAccepted())
646 d->pressAndHoldTimer.start(msec: pressAndHoldInterval(), obj: this);
647 }
648}
649
650void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
651{
652 Q_D(QQuickMouseArea);
653 if (!d->enabled && !d->pressed) {
654 QQuickItem::mouseMoveEvent(event);
655 return;
656 }
657
658 // ### we should skip this if these signals aren't used
659 // ### can GV handle this for us?
660 setHovered(contains(point: event->position()));
661
662 if ((event->buttons() & acceptedMouseButtons()) == 0) {
663 QQuickItem::mouseMoveEvent(event);
664 return;
665 }
666
667 d->saveEvent(event);
668
669
670#if QT_CONFIG(quick_draganddrop)
671 if (d->drag && d->drag->target()) {
672 if (!d->moved) {
673 d->targetStartPos = d->drag->target()->parentItem()
674 ? d->drag->target()->parentItem()->mapToScene(point: d->drag->target()->position())
675 : d->drag->target()->position();
676 }
677
678 QPointF startLocalPos;
679 QPointF curLocalPos;
680 if (drag()->target()->parentItem()) {
681 startLocalPos = drag()->target()->parentItem()->mapFromScene(point: d->startScene);
682 curLocalPos = drag()->target()->parentItem()->mapFromScene(point: event->scenePosition());
683 } else {
684 startLocalPos = d->startScene;
685 curLocalPos = event->scenePosition();
686 }
687
688 if (keepMouseGrab() && d->stealMouse && d->overThreshold && !d->drag->active())
689 d->drag->setActive(true);
690
691 QPointF startPos = d->drag->target()->parentItem()
692 ? d->drag->target()->parentItem()->mapFromScene(point: d->targetStartPos)
693 : d->targetStartPos;
694
695 bool dragX = drag()->axis() & QQuickDrag::XAxis;
696 bool dragY = drag()->axis() & QQuickDrag::YAxis;
697
698 QPointF dragPos = d->drag->target()->position();
699 QPointF boundedDragPos = dragPos;
700 if (dragX) {
701 dragPos.setX(startPos.x() + curLocalPos.x() - startLocalPos.x());
702 boundedDragPos.setX(qBound(
703 min: d->drag->xmin(),
704 val: dragPos.x(),
705 max: d->drag->xmax()));
706 }
707 if (dragY) {
708 dragPos.setY(startPos.y() + curLocalPos.y() - startLocalPos.y());
709 boundedDragPos.setY(qBound(
710 min: d->drag->ymin(),
711 val: dragPos.y(),
712 max: d->drag->ymax()));
713 }
714
715 QPointF targetPos = d->drag->target()->position();
716
717 if (d->drag->active()) {
718 d->drag->target()->setPosition(boundedDragPos);
719 d->lastPos = mapFromScene(point: d->lastScenePos);
720 }
721
722 bool dragOverThresholdX = QQuickDeliveryAgentPrivate::dragOverThreshold(d: dragPos.x() - startPos.x(),
723 axis: Qt::XAxis, event, startDragThreshold: d->drag->threshold());
724 bool dragOverThresholdY = QQuickDeliveryAgentPrivate::dragOverThreshold(d: dragPos.y() - startPos.y(),
725 axis: Qt::YAxis, event, startDragThreshold: d->drag->threshold());
726
727 if (!d->overThreshold && (((targetPos.x() != boundedDragPos.x()) && dragOverThresholdX) ||
728 ((targetPos.y() != boundedDragPos.y()) && dragOverThresholdY)))
729 {
730 d->overThreshold = true;
731 if (d->drag->smoothed())
732 d->startScene = event->scenePosition();
733 }
734
735 if (!keepMouseGrab() && d->overThreshold) {
736 setKeepMouseGrab(true);
737 d->stealMouse = true;
738 }
739
740 d->moved = true;
741 }
742#endif
743
744 QQuickMouseEvent &me = d->quickMouseEvent;
745 me.reset(x: d->lastPos.x(), y: d->lastPos.y(), button: d->lastButton, buttons: d->lastButtons, modifiers: d->lastModifiers, isClick: false, wasHeld: d->longPress, flags: event->flags());
746#if QT_DEPRECATED_SINCE(6, 6)
747 me.setSource(event->source());
748#endif
749 emit mouseXChanged(mouse: &me);
750 me.setPosition(d->lastPos);
751 emit mouseYChanged(mouse: &me);
752 me.setPosition(d->lastPos);
753 emit positionChanged(mouse: &me);
754}
755
756void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
757{
758 Q_D(QQuickMouseArea);
759 d->stealMouse = false;
760 d->overThreshold = false;
761 if (!d->enabled && !d->pressed) {
762 QQuickItem::mouseReleaseEvent(event);
763 } else {
764 d->saveEvent(event);
765 setPressed(button: event->button(), p: false, source: event->source());
766 if (!d->pressed) {
767 // no other buttons are pressed
768#if QT_CONFIG(quick_draganddrop)
769 if (d->drag)
770 d->drag->setActive(false);
771#endif
772 // If we don't accept hover, we need to reset containsMouse.
773 if (!hoverEnabled())
774 setHovered(false);
775 QQuickWindow *w = window();
776 if (w && w->mouseGrabberItem() == this)
777 ungrabMouse();
778 if (!d->preventStealing)
779 setKeepMouseGrab(false);
780 }
781 }
782 d->doubleClick = false;
783}
784
785void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
786{
787 Q_D(QQuickMouseArea);
788 if (d->enabled) {
789 d->saveEvent(event);
790 QQuickMouseEvent &me = d->quickMouseEvent;
791 me.reset(x: d->lastPos.x(), y: d->lastPos.y(), button: d->lastButton, buttons: d->lastButtons, modifiers: d->lastModifiers, isClick: true,
792 wasHeld: false, flags: event->flags());
793#if QT_DEPRECATED_SINCE(6, 6)
794 me.setSource(event->source());
795#endif
796 me.setAccepted(d->isDoubleClickConnected());
797 emit this->doubleClicked(mouse: &me);
798 if (!me.isAccepted())
799 d->propagate(event: &me, t: QQuickMouseAreaPrivate::DoubleClick);
800 if (d->pressed)
801 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
802
803 // Do not call the base implementation: we don't want to call event->ignore().
804 return;
805 }
806 QQuickItem::mouseDoubleClickEvent(event);
807}
808
809void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
810{
811 Q_D(QQuickMouseArea);
812 if (!d->enabled && !d->pressed) {
813 // Note: The fact that MouseArea doesn't update 'containsMouse' when it's disabled, is a
814 // legacy behavior that is different from how hover events are supposed to work; Hover
815 // events are always delivered to both enabled and disabled items (when they explicitly
816 // subscribe for them), to open up for hover effects, like showing tooltips. Because of
817 // this difference, you cannot use a MouseArea to e.g trigger a tooltop on a parent that
818 // is disabled. But since MouseArea has always worked this way, it should (probably) stay
819 // that way to avoid regressions. HoverHandlers do not suffer from this limitation, and
820 // can therefore be used as a replacement to solve such cases.
821 QQuickItem::hoverEnterEvent(event);
822 } else {
823 d->lastPos = event->position();
824 d->lastModifiers = event->modifiers();
825 setHovered(true);
826 QQuickMouseEvent &me = d->quickMouseEvent;
827 me.reset(x: d->lastPos.x(), y: d->lastPos.y(), button: Qt::NoButton, buttons: Qt::NoButton, modifiers: d->lastModifiers, isClick: false, wasHeld: false);
828 emit mouseXChanged(mouse: &me);
829 me.setPosition(d->lastPos);
830 emit mouseYChanged(mouse: &me);
831 me.setPosition(d->lastPos);
832 emit positionChanged(mouse: &me);
833 }
834
835 // A MouseArea should not block hover events
836 event->ignore();
837}
838
839void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
840{
841 Q_D(QQuickMouseArea);
842 if (!d->enabled && !d->pressed) {
843 QQuickItem::hoverMoveEvent(event);
844 } else if (d->lastPos != event->position()) {
845 d->lastPos = event->position();
846 d->lastModifiers = event->modifiers();
847 QQuickMouseEvent &me = d->quickMouseEvent;
848 me.reset(x: d->lastPos.x(), y: d->lastPos.y(), button: Qt::NoButton, buttons: Qt::NoButton, modifiers: d->lastModifiers, isClick: false, wasHeld: false);
849 emit mouseXChanged(mouse: &me);
850 me.setPosition(d->lastPos);
851 emit mouseYChanged(mouse: &me);
852 me.setPosition(d->lastPos);
853 emit positionChanged(mouse: &me);
854 }
855
856 // A MouseArea should not block hover events
857 event->ignore();
858}
859
860void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
861{
862 Q_D(QQuickMouseArea);
863 if (!d->enabled && !d->pressed && !d->hovered)
864 QQuickItem::hoverLeaveEvent(event);
865 else
866 setHovered(false);
867
868 // A MouseArea should not block hover events
869 event->ignore();
870}
871
872#if QT_CONFIG(wheelevent)
873void QQuickMouseArea::wheelEvent(QWheelEvent *event)
874{
875 Q_D(QQuickMouseArea);
876 if (!d->enabled || (!isScrollGestureEnabled() && event->source() != Qt::MouseEventNotSynthesized)) {
877 QQuickItem::wheelEvent(event);
878 return;
879 }
880
881 QQuickWheelEvent &we = d->quickWheelEvent;
882 we.reset(event);
883 we.setAccepted(d->isWheelConnected());
884 emit wheel(wheel: &we);
885 if (!we.isAccepted())
886 QQuickItem::wheelEvent(event);
887}
888#endif
889
890void QQuickMouseArea::ungrabMouse()
891{
892 Q_D(QQuickMouseArea);
893 if (d->pressed) {
894 // if our mouse grab has been removed (probably by Flickable), fix our
895 // state
896 d->pressed = Qt::NoButton;
897 d->stealMouse = false;
898 d->doubleClick = false;
899 d->overThreshold = false;
900 setKeepMouseGrab(false);
901
902#if QT_CONFIG(quick_draganddrop)
903 if (d->drag)
904 d->drag->setActive(false);
905#endif
906
907 emit canceled();
908 emit pressedChanged();
909 emit containsPressChanged();
910 emit pressedButtonsChanged();
911
912 if (d->hovered && !isUnderMouse()) {
913 qCDebug(lcHoverTrace) << "losing hover: not under the mouse";
914 d->hovered = false;
915 emit hoveredChanged();
916 }
917 }
918}
919
920void QQuickMouseArea::mouseUngrabEvent()
921{
922 ungrabMouse();
923}
924
925void QQuickMouseArea::touchUngrabEvent()
926{
927 // allow a Pointer Handler to steal the grab from MouseArea
928 ungrabMouse();
929}
930
931bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
932{
933 Q_D(QQuickMouseArea);
934 QPointF localPos = mapFromScene(point: event->scenePosition());
935
936 QQuickWindow *c = window();
937 QQuickItem *grabber = c ? c->mouseGrabberItem() : nullptr;
938 bool stealThisEvent = d->stealMouse;
939 if ((stealThisEvent || contains(point: localPos)) && (!grabber || !grabber->keepMouseGrab())) {
940 QMouseEvent mouseEvent(event->type(), localPos, event->scenePosition(), event->globalPosition(),
941 event->button(), event->buttons(), event->modifiers());
942 mouseEvent.setAccepted(false);
943
944 switch (event->type()) {
945 case QEvent::MouseMove:
946 mouseMoveEvent(event: &mouseEvent);
947 break;
948 case QEvent::MouseButtonPress:
949 mousePressEvent(event: &mouseEvent);
950 break;
951 case QEvent::MouseButtonRelease:
952 mouseReleaseEvent(event: &mouseEvent);
953 stealThisEvent = d->stealMouse;
954 break;
955 default:
956 break;
957 }
958 grabber = c ? c->mouseGrabberItem() : nullptr;
959 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
960 grabMouse();
961
962 return stealThisEvent;
963 }
964 if (event->type() == QEvent::MouseButtonRelease) {
965 if (d->pressed) {
966 d->pressed &= ~event->button();
967 emit pressedButtonsChanged();
968 if (!d->pressed) {
969 // no other buttons are pressed
970 d->stealMouse = false;
971 d->overThreshold = false;
972 if (c && c->mouseGrabberItem() == this)
973 ungrabMouse();
974 emit canceled();
975 emit pressedChanged();
976 emit containsPressChanged();
977 if (d->hovered) {
978 qCDebug(lcHoverTrace) << "losing hover: button released";
979 d->hovered = false;
980 emit hoveredChanged();
981 }
982 }
983 }
984 }
985 return false;
986}
987
988bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
989{
990 Q_D(QQuickMouseArea);
991 if (!d->pressed &&
992 (!d->enabled || !isVisible()
993#if QT_CONFIG(quick_draganddrop)
994 || !d->drag || !d->drag->filterChildren()
995#endif
996 )
997 )
998 return QQuickItem::childMouseEventFilter(i, e);
999 switch (e->type()) {
1000 case QEvent::MouseButtonPress:
1001 case QEvent::MouseMove:
1002 case QEvent::MouseButtonRelease:
1003 return sendMouseEvent(event: static_cast<QMouseEvent *>(e));
1004 default:
1005 break;
1006 }
1007
1008 return QQuickItem::childMouseEventFilter(i, e);
1009}
1010
1011void QQuickMouseArea::timerEvent(QTimerEvent *event)
1012{
1013 Q_D(QQuickMouseArea);
1014 if (event->timerId() == d->pressAndHoldTimer.timerId()) {
1015 d->pressAndHoldTimer.stop();
1016#if QT_CONFIG(quick_draganddrop)
1017 bool dragged = d->drag && d->drag->active();
1018#else
1019 bool dragged = false;
1020#endif
1021 if (d->pressed && dragged == false && d->hovered == true) {
1022 d->longPress = true;
1023 QQuickMouseEvent &me = d->quickMouseEvent;
1024 me.reset(x: d->lastPos.x(), y: d->lastPos.y(), button: d->lastButton, buttons: d->lastButtons, modifiers: d->lastModifiers, isClick: false, wasHeld: d->longPress, flags: d->lastFlags);
1025#if QT_DEPRECATED_SINCE(6, 6)
1026 me.setSource(Qt::MouseEventSynthesizedByQt);
1027#endif
1028 me.setAccepted(d->isPressAndHoldConnected());
1029 emit pressAndHold(mouse: &me);
1030 if (!me.isAccepted())
1031 d->propagate(event: &me, t: QQuickMouseAreaPrivate::PressAndHold);
1032 if (!me.isAccepted()) // no one handled the long press - allow click
1033 d->longPress = false;
1034 }
1035 }
1036}
1037
1038void QQuickMouseArea::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
1039{
1040 Q_D(QQuickMouseArea);
1041 QQuickItem::geometryChange(newGeometry, oldGeometry);
1042
1043 if (!d->lastScenePos.isValid())
1044 d->lastScenePos = mapToScene(point: d->lastPos);
1045 else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
1046 d->lastPos = mapFromScene(point: d->lastScenePos);
1047}
1048
1049void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
1050{
1051 Q_D(QQuickMouseArea);
1052 switch (change) {
1053 case ItemEnabledHasChanged:
1054 // If MouseArea becomes effectively disabled by disabling a parent
1055 // (for example, onPressed: parent.enabled = false), cancel the pressed state.
1056 if (d->pressed && !d->effectiveEnable)
1057 ungrabMouse();
1058 break;
1059 case ItemVisibleHasChanged:
1060 if (d->effectiveEnable && d->enabled && hoverEnabled()
1061 && d->hovered != (isVisible() && isUnderMouse())) {
1062 if (d->hovered) {
1063 // If hovered but no longer under the mouse then un-hover.
1064 setHovered(false);
1065 } else {
1066 // If under the mouse but not hovered then hover the QQuickMouseArea if it is
1067 // marked as a hovered item under the windows QQuickDeliveryAgentPrivate instance.
1068 // This is required as this QQuickMouseArea may be masked by another hoverable
1069 // QQuickMouseArea higher up in the scenes z-index ordering.
1070 QPointF globalPos{ QGuiApplicationPrivate::lastCursorPosition.toPoint() };
1071 QPointF scenePos{ d->window->mapFromGlobal(pos: globalPos) };
1072
1073 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(c: d->window);
1074 QQuickDeliveryAgentPrivate *dap = wd->deliveryAgentPrivate();
1075
1076 // If the QQuickDeliveryAgentPrivate has not already found a hovered leaf
1077 // item then attempt to find one.
1078 if (!dap->hoveredLeafItemFound) {
1079 dap->deliverHoverEvent(scenePos, lastScenePos: scenePos, modifiers: Qt::NoModifier,
1080 timestamp: QDateTime::currentSecsSinceEpoch());
1081 }
1082
1083 // Now if the QQuickDeliveryAgentPrivate has found a hovered leaf item check
1084 // that this QQuickMouseArea item was one of the hovered items.
1085 if (dap->hoveredLeafItemFound) {
1086 for (auto hoverItem : dap->hoverItems) {
1087 if (hoverItem.first == this) {
1088 // Found a match so update the hover state.
1089 d->lastScenePos = scenePos;
1090 d->lastPos = mapFromScene(point: d->lastScenePos);
1091 setHovered(true);
1092 break;
1093 }
1094 }
1095 }
1096 }
1097 }
1098 if (d->pressed && (!isVisible())) {
1099 // This happens when the mouse area hides itself
1100 // inside the press handler. In that case we should not keep the internal
1101 // state as pressed, since we never became the mouse grabber.
1102 ungrabMouse();
1103 }
1104 break;
1105 default:
1106 break;
1107 }
1108
1109 QQuickItem::itemChange(change, value);
1110}
1111
1112/*!
1113 \qmlproperty bool QtQuick::MouseArea::hoverEnabled
1114 This property holds whether hover events are handled.
1115
1116 By default, mouse events are only handled in response to a button event, or when a button is
1117 pressed. Hover enables handling of all mouse events even when no mouse button is
1118 pressed.
1119
1120 This property affects the containsMouse property and the onEntered, onExited and
1121 onPositionChanged signals.
1122*/
1123bool QQuickMouseArea::hoverEnabled() const
1124{
1125 return d_func()->hoverEnabled;
1126}
1127
1128void QQuickMouseArea::setHoverEnabled(bool h)
1129{
1130 Q_D(QQuickMouseArea);
1131 if (h == d->hoverEnabled)
1132 return;
1133
1134 d->hoverEnabled = h;
1135 setAcceptHoverEvents(h && d->enabled);
1136
1137 emit hoverEnabledChanged();
1138}
1139
1140
1141/*!
1142 \qmlproperty bool QtQuick::MouseArea::containsMouse
1143 This property holds whether the mouse is currently inside the mouse area.
1144
1145 \warning If hoverEnabled is \c false, \c containsMouse will be \c true
1146 when the mouse is pressed while the mouse cursor is inside the MouseArea.
1147 But if you set \c {mouse.accepted = false} in an \c onPressed handler,
1148 \c containsMouse will remain \c false because the press was rejected.
1149*/
1150bool QQuickMouseArea::hovered() const
1151{
1152 Q_D(const QQuickMouseArea);
1153 return d->hovered;
1154}
1155
1156/*!
1157 \qmlproperty bool QtQuick::MouseArea::pressed
1158 This property holds whether any of the \l acceptedButtons are currently pressed.
1159*/
1160bool QQuickMouseArea::isPressed() const
1161{
1162 Q_D(const QQuickMouseArea);
1163 return d->pressed;
1164}
1165
1166/*!
1167 \qmlproperty bool QtQuick::MouseArea::containsPress
1168 \since 5.4
1169 This is a convenience property equivalent to \c {pressed && containsMouse},
1170 i.e. it holds whether any of the \l acceptedButtons are currently pressed
1171 and the mouse is currently within the MouseArea.
1172
1173 This property is particularly useful for highlighting an item while the mouse
1174 is pressed within its bounds.
1175
1176 \sa pressed, containsMouse
1177*/
1178bool QQuickMouseArea::containsPress() const
1179{
1180 Q_D(const QQuickMouseArea);
1181 return d->pressed && d->hovered;
1182}
1183
1184void QQuickMouseArea::setHovered(bool h)
1185{
1186 Q_D(QQuickMouseArea);
1187 if (d->hovered != h) {
1188 qCDebug(lcHoverTrace) << this << d->hovered << "->" << h;
1189 d->hovered = h;
1190 emit hoveredChanged();
1191 d->hovered ? emit entered() : emit exited();
1192 if (d->pressed)
1193 emit containsPressChanged();
1194 }
1195}
1196
1197/*!
1198 \qmlproperty Qt::MouseButtons QtQuick::MouseArea::acceptedButtons
1199 This property holds the mouse buttons that the mouse area reacts to.
1200
1201 To specify that the MouseArea will react to multiple buttons,
1202 Qt::MouseButtons flag values are combined using the "|" (or) operator:
1203
1204 \code
1205 MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
1206 \endcode
1207
1208 To indicate that all possible mouse buttons are to be accepted,
1209 the special value 'Qt.AllButtons' may be used:
1210
1211 \code
1212 MouseArea { acceptedButtons: Qt.AllButtons }
1213 \endcode
1214
1215 The default value is \c Qt.LeftButton.
1216*/
1217Qt::MouseButtons QQuickMouseArea::acceptedButtons() const
1218{
1219 return acceptedMouseButtons();
1220}
1221
1222void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
1223{
1224 if (buttons != acceptedMouseButtons()) {
1225 setAcceptedMouseButtons(buttons);
1226 emit acceptedButtonsChanged();
1227 }
1228}
1229
1230bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventSource source)
1231{
1232 Q_D(QQuickMouseArea);
1233
1234 // Don't allow entering pressed state while invisible
1235 if (p && !d->effectiveVisible)
1236 return false;
1237
1238#if QT_CONFIG(quick_draganddrop)
1239 bool dragged = d->drag && d->drag->active();
1240#else
1241 bool dragged = false;
1242#endif
1243 bool wasPressed = d->pressed & button;
1244 bool isclick = wasPressed && p == false && dragged == false && d->hovered == true;
1245 Qt::MouseButtons oldPressed = d->pressed;
1246
1247 if (wasPressed != p) {
1248 QQuickMouseEvent &me = d->quickMouseEvent;
1249 me.reset(x: d->lastPos.x(), y: d->lastPos.y(), button: d->lastButton, buttons: d->lastButtons, modifiers: d->lastModifiers, isClick: isclick, wasHeld: d->longPress, flags: d->lastFlags);
1250#if QT_DEPRECATED_SINCE(6, 6)
1251 me.setSource(source);
1252#endif
1253 if (p) {
1254 d->pressed |= button;
1255 if (!d->doubleClick)
1256 emit pressed(mouse: &me);
1257 me.setPosition(d->lastPos);
1258 emit mouseXChanged(mouse: &me);
1259 me.setPosition(d->lastPos);
1260 emit mouseYChanged(mouse: &me);
1261
1262 if (!me.isAccepted()) {
1263 d->pressed = Qt::NoButton;
1264 if (!hoverEnabled())
1265 setHovered(false);
1266 }
1267
1268 if (!oldPressed) {
1269 emit pressedChanged();
1270 emit containsPressChanged();
1271 }
1272 emit pressedButtonsChanged();
1273 } else {
1274 d->pressed &= ~button;
1275 emit released(mouse: &me);
1276 me.setPosition(d->lastPos);
1277 if (!d->pressed) {
1278 emit pressedChanged();
1279 emit containsPressChanged();
1280 }
1281 emit pressedButtonsChanged();
1282 if (isclick && !d->longPress && !d->doubleClick){
1283 me.setAccepted(d->isClickConnected());
1284 emit clicked(mouse: &me);
1285 if (!me.isAccepted())
1286 d->propagate(event: &me, t: QQuickMouseAreaPrivate::Click);
1287 }
1288 }
1289
1290 return me.isAccepted();
1291 }
1292 Q_UNUSED(source)
1293 return false;
1294}
1295
1296
1297/*!
1298 \qmlproperty Qt::CursorShape QtQuick::MouseArea::cursorShape
1299 This property holds the cursor shape for this mouse area.
1300 Note that on platforms that do not display a mouse cursor this may have
1301 no effect.
1302
1303 The available cursor shapes are:
1304 \list
1305 \li Qt.ArrowCursor
1306 \li Qt.UpArrowCursor
1307 \li Qt.CrossCursor
1308 \li Qt.WaitCursor
1309 \li Qt.IBeamCursor
1310 \li Qt.SizeVerCursor
1311 \li Qt.SizeHorCursor
1312 \li Qt.SizeBDiagCursor
1313 \li Qt.SizeFDiagCursor
1314 \li Qt.SizeAllCursor
1315 \li Qt.BlankCursor
1316 \li Qt.SplitVCursor
1317 \li Qt.SplitHCursor
1318 \li Qt.PointingHandCursor
1319 \li Qt.ForbiddenCursor
1320 \li Qt.WhatsThisCursor
1321 \li Qt.BusyCursor
1322 \li Qt.OpenHandCursor
1323 \li Qt.ClosedHandCursor
1324 \li Qt.DragCopyCursor
1325 \li Qt.DragMoveCursor
1326 \li Qt.DragLinkCursor
1327 \endlist
1328
1329 In order to only set a mouse cursor shape for a region without reacting
1330 to mouse events set the acceptedButtons to none:
1331
1332 \code
1333 MouseArea { cursorShape: Qt.IBeamCursor; acceptedButtons: Qt.NoButton }
1334 \endcode
1335
1336 The default value is \c Qt.ArrowCursor.
1337
1338 \note If the \c cursorShape property is set to \c undefined, the \c MouseArea will
1339 not change the existing shape when entering it.
1340
1341 \sa Qt::CursorShape
1342*/
1343
1344#if QT_CONFIG(cursor)
1345Qt::CursorShape QQuickMouseArea::cursorShape() const
1346{
1347 return cursor().shape();
1348}
1349
1350void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
1351{
1352 if (cursor().shape() == shape)
1353 return;
1354
1355 setCursor(shape);
1356
1357 emit cursorShapeChanged();
1358}
1359
1360#endif
1361
1362
1363/*!
1364 \qmlproperty int QtQuick::MouseArea::pressAndHoldInterval
1365 \since 5.9
1366
1367 This property overrides the elapsed time in milliseconds before
1368 \c pressAndHold is emitted.
1369
1370 If not explicitly set -- or after reset -- the value follows
1371 \c QStyleHints::mousePressAndHoldInterval.
1372
1373 Typically it's sufficient to set this property globally using the
1374 application style hint. This property should be used when varying intervals
1375 are needed for certain MouseAreas.
1376
1377 \sa pressAndHold
1378*/
1379int QQuickMouseArea::pressAndHoldInterval() const
1380{
1381 Q_D(const QQuickMouseArea);
1382 return d->pressAndHoldInterval > -1 ?
1383 d->pressAndHoldInterval : QGuiApplication::styleHints()->mousePressAndHoldInterval();
1384}
1385
1386void QQuickMouseArea::setPressAndHoldInterval(int interval)
1387{
1388 Q_D(QQuickMouseArea);
1389 if (interval != d->pressAndHoldInterval) {
1390 d->pressAndHoldInterval = interval;
1391 emit pressAndHoldIntervalChanged();
1392 }
1393}
1394
1395void QQuickMouseArea::resetPressAndHoldInterval()
1396{
1397 Q_D(QQuickMouseArea);
1398 if (d->pressAndHoldInterval > -1) {
1399 d->pressAndHoldInterval = -1;
1400 emit pressAndHoldIntervalChanged();
1401 }
1402}
1403
1404/*!
1405 \qmlpropertygroup QtQuick::MouseArea::drag
1406 \qmlproperty Item QtQuick::MouseArea::drag.target
1407 \qmlproperty bool QtQuick::MouseArea::drag.active
1408 \qmlproperty enumeration QtQuick::MouseArea::drag.axis
1409 \qmlproperty real QtQuick::MouseArea::drag.minimumX
1410 \qmlproperty real QtQuick::MouseArea::drag.maximumX
1411 \qmlproperty real QtQuick::MouseArea::drag.minimumY
1412 \qmlproperty real QtQuick::MouseArea::drag.maximumY
1413 \qmlproperty bool QtQuick::MouseArea::drag.filterChildren
1414 \qmlproperty real QtQuick::MouseArea::drag.threshold
1415 \qmlproperty bool QtQuick::MouseArea::drag.smoothed
1416
1417 \c drag provides a convenient way to make an item draggable.
1418
1419 \list
1420 \li \c drag.target specifies the id of the item to drag.
1421 \li \c drag.active specifies if the target item is currently being dragged.
1422 \li \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XAndYAxis)
1423 \li \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
1424 \endlist
1425
1426 The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
1427 of the rectangle is reduced when it is dragged to the right.
1428
1429 \snippet qml/mousearea/mousearea.qml drag
1430
1431 \note Items cannot be dragged if they are anchored for the requested
1432 \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1433 for \c rect in the above example, it cannot be dragged along the X-axis.
1434 This can be avoided by settng the anchor value to \c undefined in
1435 an \l {pressed}{onPressed} handler.
1436
1437 If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
1438 enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1439
1440 \snippet qml/mousearea/mouseareadragfilter.qml dragfilter
1441
1442 \c drag.threshold determines the threshold in pixels of when the drag operation should
1443 start. By default this is bound to a platform dependent value. This property was added in
1444 Qt Quick 2.2.
1445
1446 If \c drag.smoothed is \c true, the target will be moved only after the drag operation has
1447 started. If set to \c false, the target will be moved straight to the current mouse position.
1448 By default, this property is \c true. This property was added in Qt Quick 2.4
1449
1450 See the \l Drag attached property and \l DropArea if you want to make a drop.
1451*/
1452
1453#if QT_CONFIG(quick_draganddrop)
1454QQuickDrag *QQuickMouseArea::drag()
1455{
1456 Q_D(QQuickMouseArea);
1457 if (!d->drag)
1458 d->drag = new QQuickDrag;
1459 return d->drag;
1460}
1461#endif
1462
1463QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1464{
1465 Q_UNUSED(data);
1466 Q_D(QQuickMouseArea);
1467
1468 if (!qmlMaVisualTouchDebugging())
1469 return nullptr;
1470
1471 QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
1472 if (!rectangle) rectangle = d->sceneGraphContext()->createInternalRectangleNode();
1473
1474 rectangle->setRect(QRectF(0, 0, width(), height()));
1475 rectangle->setColor(QColor(255, 0, 0, 50));
1476 rectangle->update();
1477 return rectangle;
1478}
1479
1480QT_END_NAMESPACE
1481
1482#include "moc_qquickmousearea_p.cpp"
1483

source code of qtdeclarative/src/quick/items/qquickmousearea.cpp