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

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