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 \instantiates 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 }
833
834 // A MouseArea should not block hover events
835 event->ignore();
836}
837
838void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
839{
840 Q_D(QQuickMouseArea);
841 if (!d->enabled && !d->pressed) {
842 QQuickItem::hoverMoveEvent(event);
843 } else if (d->lastPos != event->position()) {
844 d->lastPos = event->position();
845 d->lastModifiers = event->modifiers();
846 QQuickMouseEvent &me = d->quickMouseEvent;
847 me.reset(x: d->lastPos.x(), y: d->lastPos.y(), button: Qt::NoButton, buttons: Qt::NoButton, modifiers: d->lastModifiers, isClick: false, wasHeld: false);
848 emit mouseXChanged(mouse: &me);
849 me.setPosition(d->lastPos);
850 emit mouseYChanged(mouse: &me);
851 me.setPosition(d->lastPos);
852 emit positionChanged(mouse: &me);
853 }
854
855 // A MouseArea should not block hover events
856 event->ignore();
857}
858
859void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
860{
861 Q_D(QQuickMouseArea);
862 if (!d->enabled && !d->pressed && !d->hovered)
863 QQuickItem::hoverLeaveEvent(event);
864 else
865 setHovered(false);
866
867 // A MouseArea should not block hover events
868 event->ignore();
869}
870
871#if QT_CONFIG(wheelevent)
872void QQuickMouseArea::wheelEvent(QWheelEvent *event)
873{
874 Q_D(QQuickMouseArea);
875 if (!d->enabled || (!isScrollGestureEnabled() && event->source() != Qt::MouseEventNotSynthesized)) {
876 QQuickItem::wheelEvent(event);
877 return;
878 }
879
880 QQuickWheelEvent &we = d->quickWheelEvent;
881 we.reset(event);
882 we.setAccepted(d->isWheelConnected());
883 emit wheel(wheel: &we);
884 if (!we.isAccepted())
885 QQuickItem::wheelEvent(event);
886}
887#endif
888
889void QQuickMouseArea::ungrabMouse()
890{
891 Q_D(QQuickMouseArea);
892 if (d->pressed) {
893 // if our mouse grab has been removed (probably by Flickable), fix our
894 // state
895 d->pressed = Qt::NoButton;
896 d->stealMouse = false;
897 d->doubleClick = false;
898 d->overThreshold = false;
899 setKeepMouseGrab(false);
900
901#if QT_CONFIG(quick_draganddrop)
902 if (d->drag)
903 d->drag->setActive(false);
904#endif
905
906 emit canceled();
907 emit pressedChanged();
908 emit containsPressChanged();
909 emit pressedButtonsChanged();
910
911 if (d->hovered && !isUnderMouse()) {
912 qCDebug(lcHoverTrace) << "losing hover: not under the mouse";
913 d->hovered = false;
914 emit hoveredChanged();
915 }
916 }
917}
918
919void QQuickMouseArea::mouseUngrabEvent()
920{
921 ungrabMouse();
922}
923
924void QQuickMouseArea::touchUngrabEvent()
925{
926 // allow a Pointer Handler to steal the grab from MouseArea
927 ungrabMouse();
928}
929
930bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
931{
932 Q_D(QQuickMouseArea);
933 QPointF localPos = mapFromScene(point: event->scenePosition());
934
935 QQuickWindow *c = window();
936 QQuickItem *grabber = c ? c->mouseGrabberItem() : nullptr;
937 bool stealThisEvent = d->stealMouse;
938 if ((stealThisEvent || contains(point: localPos)) && (!grabber || !grabber->keepMouseGrab())) {
939 QMouseEvent mouseEvent(event->type(), localPos, event->scenePosition(), event->globalPosition(),
940 event->button(), event->buttons(), event->modifiers());
941 mouseEvent.setAccepted(false);
942
943 switch (event->type()) {
944 case QEvent::MouseMove:
945 mouseMoveEvent(event: &mouseEvent);
946 break;
947 case QEvent::MouseButtonPress:
948 mousePressEvent(event: &mouseEvent);
949 break;
950 case QEvent::MouseButtonRelease:
951 mouseReleaseEvent(event: &mouseEvent);
952 stealThisEvent = d->stealMouse;
953 break;
954 default:
955 break;
956 }
957 grabber = c ? c->mouseGrabberItem() : nullptr;
958 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
959 grabMouse();
960
961 return stealThisEvent;
962 }
963 if (event->type() == QEvent::MouseButtonRelease) {
964 if (d->pressed) {
965 d->pressed &= ~event->button();
966 emit pressedButtonsChanged();
967 if (!d->pressed) {
968 // no other buttons are pressed
969 d->stealMouse = false;
970 d->overThreshold = false;
971 if (c && c->mouseGrabberItem() == this)
972 ungrabMouse();
973 emit canceled();
974 emit pressedChanged();
975 emit containsPressChanged();
976 if (d->hovered) {
977 qCDebug(lcHoverTrace) << "losing hover: button released";
978 d->hovered = false;
979 emit hoveredChanged();
980 }
981 }
982 }
983 }
984 return false;
985}
986
987bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
988{
989 Q_D(QQuickMouseArea);
990 if (!d->pressed &&
991 (!d->enabled || !isVisible()
992#if QT_CONFIG(quick_draganddrop)
993 || !d->drag || !d->drag->filterChildren()
994#endif
995 )
996 )
997 return QQuickItem::childMouseEventFilter(i, e);
998 switch (e->type()) {
999 case QEvent::MouseButtonPress:
1000 case QEvent::MouseMove:
1001 case QEvent::MouseButtonRelease:
1002 return sendMouseEvent(event: static_cast<QMouseEvent *>(e));
1003 default:
1004 break;
1005 }
1006
1007 return QQuickItem::childMouseEventFilter(i, e);
1008}
1009
1010void QQuickMouseArea::timerEvent(QTimerEvent *event)
1011{
1012 Q_D(QQuickMouseArea);
1013 if (event->timerId() == d->pressAndHoldTimer.timerId()) {
1014 d->pressAndHoldTimer.stop();
1015#if QT_CONFIG(quick_draganddrop)
1016 bool dragged = d->drag && d->drag->active();
1017#else
1018 bool dragged = false;
1019#endif
1020 if (d->pressed && dragged == false && d->hovered == true) {
1021 d->longPress = true;
1022 QQuickMouseEvent &me = d->quickMouseEvent;
1023 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);
1024#if QT_DEPRECATED_SINCE(6, 6)
1025 me.setSource(Qt::MouseEventSynthesizedByQt);
1026#endif
1027 me.setAccepted(d->isPressAndHoldConnected());
1028 emit pressAndHold(mouse: &me);
1029 if (!me.isAccepted())
1030 d->propagate(event: &me, t: QQuickMouseAreaPrivate::PressAndHold);
1031 if (!me.isAccepted()) // no one handled the long press - allow click
1032 d->longPress = false;
1033 }
1034 }
1035}
1036
1037void QQuickMouseArea::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
1038{
1039 Q_D(QQuickMouseArea);
1040 QQuickItem::geometryChange(newGeometry, oldGeometry);
1041
1042 if (d->lastScenePos.isNull)
1043 d->lastScenePos = mapToScene(point: d->lastPos);
1044 else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
1045 d->lastPos = mapFromScene(point: d->lastScenePos);
1046}
1047
1048void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
1049{
1050 Q_D(QQuickMouseArea);
1051 switch (change) {
1052 case ItemEnabledHasChanged:
1053 // If MouseArea becomes effectively disabled by disabling a parent
1054 // (for example, onPressed: parent.enabled = false), cancel the pressed state.
1055 if (d->pressed && !d->effectiveEnable)
1056 ungrabMouse();
1057 break;
1058 case ItemVisibleHasChanged:
1059 if (d->effectiveEnable && d->enabled && hoverEnabled()
1060 && d->hovered != (isVisible() && isUnderMouse())) {
1061 if (d->hovered) {
1062 // If hovered but no longer under the mouse then un-hover.
1063 setHovered(false);
1064 } else {
1065 // If under the mouse but not hovered then hover the QQuickMouseArea if it is
1066 // marked as a hovered item under the windows QQuickDeliveryAgentPrivate instance.
1067 // This is required as this QQuickMouseArea may be masked by another hoverable
1068 // QQuickMouseArea higher up in the scenes z-index ordering.
1069 QPointF globalPos{ QGuiApplicationPrivate::lastCursorPosition.toPoint() };
1070 QPointF scenePos{ d->window->mapFromGlobal(pos: globalPos) };
1071
1072 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(c: d->window);
1073 QQuickDeliveryAgentPrivate *dap = wd->deliveryAgentPrivate();
1074
1075 // If the QQuickDeliveryAgentPrivate has not already found a hovered leaf
1076 // item then attempt to find one.
1077 if (!dap->hoveredLeafItemFound) {
1078 dap->deliverHoverEvent(scenePos, lastScenePos: scenePos, modifiers: Qt::NoModifier,
1079 timestamp: QDateTime::currentSecsSinceEpoch());
1080 }
1081
1082 // Now if the QQuickDeliveryAgentPrivate has found a hovered leaf item check
1083 // that this QQuickMouseArea item was one of the hovered items.
1084 if (dap->hoveredLeafItemFound) {
1085 for (auto hoverItem : dap->hoverItems) {
1086 if (hoverItem.first == this) {
1087 // Found a match so update the hover state.
1088 d->lastScenePos = scenePos;
1089 d->lastPos = mapFromScene(point: d->lastScenePos);
1090 setHovered(true);
1091 break;
1092 }
1093 }
1094 }
1095 }
1096 }
1097 if (d->pressed && (!isVisible())) {
1098 // This happens when the mouse area hides itself
1099 // inside the press handler. In that case we should not keep the internal
1100 // state as pressed, since we never became the mouse grabber.
1101 ungrabMouse();
1102 }
1103 break;
1104 default:
1105 break;
1106 }
1107
1108 QQuickItem::itemChange(change, value);
1109}
1110
1111/*!
1112 \qmlproperty bool QtQuick::MouseArea::hoverEnabled
1113 This property holds whether hover events are handled.
1114
1115 By default, mouse events are only handled in response to a button event, or when a button is
1116 pressed. Hover enables handling of all mouse events even when no mouse button is
1117 pressed.
1118
1119 This property affects the containsMouse property and the onEntered, onExited and
1120 onPositionChanged signals.
1121*/
1122bool QQuickMouseArea::hoverEnabled() const
1123{
1124 return d_func()->hoverEnabled;
1125}
1126
1127void QQuickMouseArea::setHoverEnabled(bool h)
1128{
1129 Q_D(QQuickMouseArea);
1130 if (h == d->hoverEnabled)
1131 return;
1132
1133 d->hoverEnabled = h;
1134 setAcceptHoverEvents(h && d->enabled);
1135
1136 emit hoverEnabledChanged();
1137}
1138
1139
1140/*!
1141 \qmlproperty bool QtQuick::MouseArea::containsMouse
1142 This property holds whether the mouse is currently inside the mouse area.
1143
1144 \warning If hoverEnabled is \c false, \c containsMouse will be \c true
1145 when the mouse is pressed while the mouse cursor is inside the MouseArea.
1146 But if you set \c {mouse.accepted = false} in an \c onPressed handler,
1147 \c containsMouse will remain \c false because the press was rejected.
1148*/
1149bool QQuickMouseArea::hovered() const
1150{
1151 Q_D(const QQuickMouseArea);
1152 return d->hovered;
1153}
1154
1155/*!
1156 \qmlproperty bool QtQuick::MouseArea::pressed
1157 This property holds whether any of the \l acceptedButtons are currently pressed.
1158*/
1159bool QQuickMouseArea::isPressed() const
1160{
1161 Q_D(const QQuickMouseArea);
1162 return d->pressed;
1163}
1164
1165/*!
1166 \qmlproperty bool QtQuick::MouseArea::containsPress
1167 \since 5.4
1168 This is a convenience property equivalent to \c {pressed && containsMouse},
1169 i.e. it holds whether any of the \l acceptedButtons are currently pressed
1170 and the mouse is currently within the MouseArea.
1171
1172 This property is particularly useful for highlighting an item while the mouse
1173 is pressed within its bounds.
1174
1175 \sa pressed, containsMouse
1176*/
1177bool QQuickMouseArea::containsPress() const
1178{
1179 Q_D(const QQuickMouseArea);
1180 return d->pressed && d->hovered;
1181}
1182
1183void QQuickMouseArea::setHovered(bool h)
1184{
1185 Q_D(QQuickMouseArea);
1186 if (d->hovered != h) {
1187 qCDebug(lcHoverTrace) << this << d->hovered << "->" << h;
1188 d->hovered = h;
1189 emit hoveredChanged();
1190 d->hovered ? emit entered() : emit exited();
1191 if (d->pressed)
1192 emit containsPressChanged();
1193 }
1194}
1195
1196/*!
1197 \qmlproperty Qt::MouseButtons QtQuick::MouseArea::acceptedButtons
1198 This property holds the mouse buttons that the mouse area reacts to.
1199
1200 To specify that the MouseArea will react to multiple buttons,
1201 Qt::MouseButtons flag values are combined using the "|" (or) operator:
1202
1203 \code
1204 MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
1205 \endcode
1206
1207 To indicate that all possible mouse buttons are to be accepted,
1208 the special value 'Qt.AllButtons' may be used:
1209
1210 \code
1211 MouseArea { acceptedButtons: Qt.AllButtons }
1212 \endcode
1213
1214 The default value is \c Qt.LeftButton.
1215*/
1216Qt::MouseButtons QQuickMouseArea::acceptedButtons() const
1217{
1218 return acceptedMouseButtons();
1219}
1220
1221void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
1222{
1223 if (buttons != acceptedMouseButtons()) {
1224 setAcceptedMouseButtons(buttons);
1225 emit acceptedButtonsChanged();
1226 }
1227}
1228
1229bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventSource source)
1230{
1231 Q_D(QQuickMouseArea);
1232
1233#if QT_CONFIG(quick_draganddrop)
1234 bool dragged = d->drag && d->drag->active();
1235#else
1236 bool dragged = false;
1237#endif
1238 bool wasPressed = d->pressed & button;
1239 bool isclick = wasPressed && p == false && dragged == false && d->hovered == true;
1240 Qt::MouseButtons oldPressed = d->pressed;
1241
1242 if (wasPressed != p) {
1243 QQuickMouseEvent &me = d->quickMouseEvent;
1244 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);
1245#if QT_DEPRECATED_SINCE(6, 6)
1246 me.setSource(source);
1247#endif
1248 if (p) {
1249 d->pressed |= button;
1250 if (!d->doubleClick)
1251 emit pressed(mouse: &me);
1252 me.setPosition(d->lastPos);
1253 emit mouseXChanged(mouse: &me);
1254 me.setPosition(d->lastPos);
1255 emit mouseYChanged(mouse: &me);
1256
1257 if (!me.isAccepted()) {
1258 d->pressed = Qt::NoButton;
1259 if (!hoverEnabled())
1260 setHovered(false);
1261 }
1262
1263 if (!oldPressed) {
1264 emit pressedChanged();
1265 emit containsPressChanged();
1266 }
1267 emit pressedButtonsChanged();
1268 } else {
1269 d->pressed &= ~button;
1270 emit released(mouse: &me);
1271 me.setPosition(d->lastPos);
1272 if (!d->pressed) {
1273 emit pressedChanged();
1274 emit containsPressChanged();
1275 }
1276 emit pressedButtonsChanged();
1277 if (isclick && !d->longPress && !d->doubleClick){
1278 me.setAccepted(d->isClickConnected());
1279 emit clicked(mouse: &me);
1280 if (!me.isAccepted())
1281 d->propagate(event: &me, t: QQuickMouseAreaPrivate::Click);
1282 }
1283 }
1284
1285 return me.isAccepted();
1286 }
1287 return false;
1288}
1289
1290
1291/*!
1292 \qmlproperty Qt::CursorShape QtQuick::MouseArea::cursorShape
1293 This property holds the cursor shape for this mouse area.
1294 Note that on platforms that do not display a mouse cursor this may have
1295 no effect.
1296
1297 The available cursor shapes are:
1298 \list
1299 \li Qt.ArrowCursor
1300 \li Qt.UpArrowCursor
1301 \li Qt.CrossCursor
1302 \li Qt.WaitCursor
1303 \li Qt.IBeamCursor
1304 \li Qt.SizeVerCursor
1305 \li Qt.SizeHorCursor
1306 \li Qt.SizeBDiagCursor
1307 \li Qt.SizeFDiagCursor
1308 \li Qt.SizeAllCursor
1309 \li Qt.BlankCursor
1310 \li Qt.SplitVCursor
1311 \li Qt.SplitHCursor
1312 \li Qt.PointingHandCursor
1313 \li Qt.ForbiddenCursor
1314 \li Qt.WhatsThisCursor
1315 \li Qt.BusyCursor
1316 \li Qt.OpenHandCursor
1317 \li Qt.ClosedHandCursor
1318 \li Qt.DragCopyCursor
1319 \li Qt.DragMoveCursor
1320 \li Qt.DragLinkCursor
1321 \endlist
1322
1323 In order to only set a mouse cursor shape for a region without reacting
1324 to mouse events set the acceptedButtons to none:
1325
1326 \code
1327 MouseArea { cursorShape: Qt.IBeamCursor; acceptedButtons: Qt.NoButton }
1328 \endcode
1329
1330 The default value is \c Qt.ArrowCursor.
1331 \sa Qt::CursorShape
1332*/
1333
1334#if QT_CONFIG(cursor)
1335Qt::CursorShape QQuickMouseArea::cursorShape() const
1336{
1337 return cursor().shape();
1338}
1339
1340void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
1341{
1342 if (cursor().shape() == shape)
1343 return;
1344
1345 setCursor(shape);
1346
1347 emit cursorShapeChanged();
1348}
1349
1350#endif
1351
1352
1353/*!
1354 \qmlproperty int QtQuick::MouseArea::pressAndHoldInterval
1355 \since 5.9
1356
1357 This property overrides the elapsed time in milliseconds before
1358 \c pressAndHold is emitted.
1359
1360 If not explicitly set -- or after reset -- the value follows
1361 \c QStyleHints::mousePressAndHoldInterval.
1362
1363 Typically it's sufficient to set this property globally using the
1364 application style hint. This property should be used when varying intervals
1365 are needed for certain MouseAreas.
1366
1367 \sa pressAndHold
1368*/
1369int QQuickMouseArea::pressAndHoldInterval() const
1370{
1371 Q_D(const QQuickMouseArea);
1372 return d->pressAndHoldInterval > -1 ?
1373 d->pressAndHoldInterval : QGuiApplication::styleHints()->mousePressAndHoldInterval();
1374}
1375
1376void QQuickMouseArea::setPressAndHoldInterval(int interval)
1377{
1378 Q_D(QQuickMouseArea);
1379 if (interval != d->pressAndHoldInterval) {
1380 d->pressAndHoldInterval = interval;
1381 emit pressAndHoldIntervalChanged();
1382 }
1383}
1384
1385void QQuickMouseArea::resetPressAndHoldInterval()
1386{
1387 Q_D(QQuickMouseArea);
1388 if (d->pressAndHoldInterval > -1) {
1389 d->pressAndHoldInterval = -1;
1390 emit pressAndHoldIntervalChanged();
1391 }
1392}
1393
1394/*!
1395 \qmlpropertygroup QtQuick::MouseArea::drag
1396 \qmlproperty Item QtQuick::MouseArea::drag.target
1397 \qmlproperty bool QtQuick::MouseArea::drag.active
1398 \qmlproperty enumeration QtQuick::MouseArea::drag.axis
1399 \qmlproperty real QtQuick::MouseArea::drag.minimumX
1400 \qmlproperty real QtQuick::MouseArea::drag.maximumX
1401 \qmlproperty real QtQuick::MouseArea::drag.minimumY
1402 \qmlproperty real QtQuick::MouseArea::drag.maximumY
1403 \qmlproperty bool QtQuick::MouseArea::drag.filterChildren
1404 \qmlproperty real QtQuick::MouseArea::drag.threshold
1405 \qmlproperty bool QtQuick::MouseArea::drag.smoothed
1406
1407 \c drag provides a convenient way to make an item draggable.
1408
1409 \list
1410 \li \c drag.target specifies the id of the item to drag.
1411 \li \c drag.active specifies if the target item is currently being dragged.
1412 \li \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XAndYAxis)
1413 \li \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
1414 \endlist
1415
1416 The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
1417 of the rectangle is reduced when it is dragged to the right.
1418
1419 \snippet qml/mousearea/mousearea.qml drag
1420
1421 \note Items cannot be dragged if they are anchored for the requested
1422 \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1423 for \c rect in the above example, it cannot be dragged along the X-axis.
1424 This can be avoided by settng the anchor value to \c undefined in
1425 an \l {pressed}{onPressed} handler.
1426
1427 If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
1428 enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1429
1430 \snippet qml/mousearea/mouseareadragfilter.qml dragfilter
1431
1432 \c drag.threshold determines the threshold in pixels of when the drag operation should
1433 start. By default this is bound to a platform dependent value. This property was added in
1434 Qt Quick 2.2.
1435
1436 If \c drag.smoothed is \c true, the target will be moved only after the drag operation has
1437 started. If set to \c false, the target will be moved straight to the current mouse position.
1438 By default, this property is \c true. This property was added in Qt Quick 2.4
1439
1440 See the \l Drag attached property and \l DropArea if you want to make a drop.
1441*/
1442
1443#if QT_CONFIG(quick_draganddrop)
1444QQuickDrag *QQuickMouseArea::drag()
1445{
1446 Q_D(QQuickMouseArea);
1447 if (!d->drag)
1448 d->drag = new QQuickDrag;
1449 return d->drag;
1450}
1451#endif
1452
1453QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1454{
1455 Q_UNUSED(data);
1456 Q_D(QQuickMouseArea);
1457
1458 if (!qmlMaVisualTouchDebugging())
1459 return nullptr;
1460
1461 QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
1462 if (!rectangle) rectangle = d->sceneGraphContext()->createInternalRectangleNode();
1463
1464 rectangle->setRect(QRectF(0, 0, width(), height()));
1465 rectangle->setColor(QColor(255, 0, 0, 50));
1466 rectangle->update();
1467 return rectangle;
1468}
1469
1470QT_END_NAMESPACE
1471
1472#include "moc_qquickmousearea_p.cpp"
1473

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