Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickmousearea.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
7#include "qquickwindow.h"
8#if QT_CONFIG(quick_draganddrop)
9#include "qquickdrag_p.h"
10#endif
11
12#include <private/qqmldata_p.h>
13#include <private/qsgadaptationlayer_p.h>
14
15#include <QtGui/private/qguiapplication_p.h>
16#include <QtGui/qevent.h>
17#include <QtGui/qstylehints.h>
18
19#include <float.h>
20
21QT_BEGIN_NAMESPACE
22
23DEFINE_BOOL_CONFIG_OPTION(qmlMaVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
24
25QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
26: enabled(true), hoverEnabled(false), scrollGestureEnabled(true), hovered(false), longPress(false),
27 moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
28 propagateComposedEvents(false), overThreshold(false),
29 pressAndHoldInterval(-1)
30#if QT_CONFIG(quick_draganddrop)
31 , drag(nullptr)
32#endif
33#if QT_CONFIG(cursor)
34 , cursor(nullptr)
35#endif
36{
37}
38
39QQuickMouseAreaPrivate::~QQuickMouseAreaPrivate()
40{
41#if QT_CONFIG(quick_draganddrop)
42 delete drag;
43#endif
44#if QT_CONFIG(cursor)
45 delete cursor;
46#endif
47}
48
49void QQuickMouseAreaPrivate::init()
50{
51 Q_Q(QQuickMouseArea);
52 q->setAcceptedMouseButtons(Qt::LeftButton);
53 q->setAcceptTouchEvents(false); // rely on mouse events synthesized from touch
54 q->setFiltersChildMouseEvents(true);
55 if (qmlMaVisualTouchDebugging()) {
56 q->setFlag(QQuickItem::ItemHasContents);
57 }
58}
59
60void QQuickMouseAreaPrivate::saveEvent(QMouseEvent *event)
61{
62 lastPos = event->position();
63 lastScenePos = event->scenePosition();
64 lastButton = event->button();
65 lastButtons = event->buttons();
66 lastModifiers = event->modifiers();
67 lastFlags = event->flags();
68}
69
70bool QQuickMouseAreaPrivate::isPressAndHoldConnected()
71{
72 Q_Q(QQuickMouseArea);
73 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, pressAndHold, (QQuickMouseEvent *));
74}
75
76bool QQuickMouseAreaPrivate::isDoubleClickConnected()
77{
78 Q_Q(QQuickMouseArea);
79 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, doubleClicked, (QQuickMouseEvent *));
80}
81
82bool QQuickMouseAreaPrivate::isClickConnected()
83{
84 Q_Q(QQuickMouseArea);
85 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, clicked, (QQuickMouseEvent *));
86}
87
88#if QT_CONFIG(wheelevent)
89bool QQuickMouseAreaPrivate::isWheelConnected()
90{
91 Q_Q(QQuickMouseArea);
92 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, wheel, (QQuickWheelEvent *));
93}
94#endif
95
96void QQuickMouseAreaPrivate::propagate(QQuickMouseEvent* event, PropagateType t)
97{
98 Q_Q(QQuickMouseArea);
99 if (!window || !propagateComposedEvents)
100 return;
101 QPointF scenePos = q->mapToScene(QPointF(event->x(), event->y()));
102 propagateHelper(event, window->contentItem(), scenePos, t);
103}
104
105bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *item,const QPointF &sp, PropagateType sig)
106{
107 //Based off of QQuickWindow::deliverInitialMousePressEvent
108 //But specific to MouseArea, so doesn't belong in window
109 Q_Q(const QQuickMouseArea);
110 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
111
112 if (itemPrivate->effectivelyClipsEventHandlingChildren()) {
113 QPointF p = item->mapFromScene(sp);
114 if (!item->contains(p))
115 return false;
116 }
117
118 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
119 for (int ii = children.size() - 1; ii >= 0; --ii) {
120 QQuickItem *child = children.at(ii);
121 if (!child->isVisible() || !child->isEnabled())
122 continue;
123 if (propagateHelper(ev, child, sp, sig))
124 return true;
125 }
126
127 QQuickMouseArea* ma = qobject_cast<QQuickMouseArea*>(item);
128 if (ma && ma != q && ma->isEnabled() && itemPrivate->acceptedMouseButtons() & ev->button()) {
129 switch (sig) {
130 case Click:
131 if (!ma->d_func()->isClickConnected())
132 return false;
133 break;
134 case DoubleClick:
135 if (!ma->d_func()->isDoubleClickConnected())
136 return false;
137 break;
138 case PressAndHold:
139 if (!ma->d_func()->isPressAndHoldConnected())
140 return false;
141 break;
142 }
143 QPointF p = item->mapFromScene(sp);
144 if (item->contains(p)) {
145 ev->setX(p.x());
146 ev->setY(p.y());
147 ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
148 switch (sig) {
149 case Click: emit ma->clicked(ev); break;
150 case DoubleClick: emit ma->doubleClicked(ev); break;
151 case PressAndHold: emit ma->pressAndHold(ev); break;
152 }
153 if (ev->isAccepted())
154 return true;
155 }
156 }
157 return false;
158
159}
160
161/*!
162 \qmltype MouseArea
163 \nativetype QQuickMouseArea
164 \inqmlmodule QtQuick
165 \ingroup qtquick-input
166 \brief Enables simple mouse handling.
167 \inherits Item
168
169 A MouseArea is an invisible item that is typically used in conjunction with
170 a visible item in order to provide mouse handling for that item.
171 By effectively acting as a proxy, the logic for mouse handling can be
172 contained within a MouseArea item.
173
174 The \l enabled property is used to enable and disable mouse handling for
175 the proxied item. When disabled, the mouse area becomes transparent to
176 mouse events.
177
178 MouseArea is an invisible Item, but it has a visible property.
179 When set to false, the mouse area becomes transparent to mouse events.
180
181 The \l pressed read-only property indicates whether or not the user is
182 holding down a mouse button over the mouse area. This property is often
183 used in bindings between properties in a user interface. The containsMouse
184 read-only property indicates the presence of the mouse cursor over the
185 mouse area but, by default, only when a mouse button is held down; see
186 the containsMouse documentation for details.
187
188 Information about the mouse position and button clicks are provided via
189 signals for which event handler properties are defined. The most commonly
190 used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
191 onPressed, onReleased and onPressAndHold. It's also possible to handle mouse
192 wheel events via the onWheel signal.
193
194 If a MouseArea overlaps with the area of other MouseArea items, you can choose
195 to propagate \c clicked, \c doubleClicked and \c pressAndHold events to these
196 other items by setting propagateComposedEvents to true and rejecting events
197 that should be propagated. See the propagateComposedEvents documentation for
198 details.
199
200 By default, MouseArea items only report mouse clicks and not changes to the
201 position of the mouse cursor. Setting the hoverEnabled property ensures that
202 handlers defined for onPositionChanged, onEntered and onExited are used and
203 that the containsMouse property is updated even when no mouse buttons are
204 pressed.
205
206 \section1 Example Usage
207
208 \div {class="float-right"}
209 \inlineimage qml-mousearea-snippet.png
210 {Red and green rectangles demonstrating click and hover states}
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(event->button(), true, event->source()));
645 if (event->isAccepted())
646 d->pressAndHoldTimer.start(pressAndHoldInterval(), 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(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(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(d->startScene);
682 curLocalPos = drag()->target()->parentItem()->mapFromScene(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(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 d->drag->xmin(),
704 dragPos.x(),
705 d->drag->xmax()));
706 }
707 if (dragY) {
708 dragPos.setY(startPos.y() + curLocalPos.y() - startLocalPos.y());
709 boundedDragPos.setY(qBound(
710 d->drag->ymin(),
711 dragPos.y(),
712 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(d->lastScenePos);
720 }
721
722 bool dragOverThresholdX = QQuickDeliveryAgentPrivate::dragOverThreshold(dragPos.x() - startPos.x(),
723 Qt::XAxis, event, d->drag->threshold());
724 bool dragOverThresholdY = QQuickDeliveryAgentPrivate::dragOverThreshold(dragPos.y() - startPos.y(),
725 Qt::YAxis, event, 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(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress, event->flags());
746#if QT_DEPRECATED_SINCE(6, 6)
747 me.setSource(event->source());
748#endif
749 emit mouseXChanged(&me);
750 me.setPosition(d->lastPos);
751 emit mouseYChanged(&me);
752 me.setPosition(d->lastPos);
753 emit positionChanged(&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(event->button(), false, 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 bool resetHovered = !hoverEnabled();
774 if (!resetHovered && event->pointerType() == QPointingDevice::PointerType::Finger) {
775 // mousePressEvent() above set containsMouse directly, bypassing the
776 // delivery agent's hoverItems bookkeeping. So if no frame-synchronous
777 // hover pass happened to run while the finger was down, there is nothing
778 // for clearFingerHover() to clear when it is lifted.
779 // Reset containsMouse now, unless it's from a hovering device.
780 auto *da = d->deliveryAgentPrivate();
781 resetHovered = !da || !da->isHoveredByHoveringDevice(this);
782 }
783 if (resetHovered)
784 setHovered(false);
785 QQuickWindow *w = window();
786 if (w && w->mouseGrabberItem() == this)
787 ungrabMouse();
788 if (!d->preventStealing)
789 setKeepMouseGrab(false);
790 }
791 }
792 d->doubleClick = false;
793}
794
795void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
796{
797 Q_D(QQuickMouseArea);
798 if (d->enabled) {
799 d->saveEvent(event);
800 QQuickMouseEvent &me = d->quickMouseEvent;
801 me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true,
802 false, event->flags());
803#if QT_DEPRECATED_SINCE(6, 6)
804 me.setSource(event->source());
805#endif
806 me.setAccepted(d->isDoubleClickConnected());
807 emit this->doubleClicked(&me);
808 if (!me.isAccepted())
809 d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
810 if (d->pressed)
811 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
812
813 // Do not call the base implementation: we don't want to call event->ignore().
814 return;
815 }
816 QQuickItem::mouseDoubleClickEvent(event);
817}
818
819void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
820{
821 Q_D(QQuickMouseArea);
822 if (!d->enabled && !d->pressed) {
823 // Note: The fact that MouseArea doesn't update 'containsMouse' when it's disabled, is a
824 // legacy behavior that is different from how hover events are supposed to work; Hover
825 // events are always delivered to both enabled and disabled items (when they explicitly
826 // subscribe for them), to open up for hover effects, like showing tooltips. Because of
827 // this difference, you cannot use a MouseArea to e.g trigger a tooltop on a parent that
828 // is disabled. But since MouseArea has always worked this way, it should (probably) stay
829 // that way to avoid regressions. HoverHandlers do not suffer from this limitation, and
830 // can therefore be used as a replacement to solve such cases.
831 QQuickItem::hoverEnterEvent(event);
832 } else {
833 d->lastPos = event->position();
834 d->lastModifiers = event->modifiers();
835 setHovered(true);
836 QQuickMouseEvent &me = d->quickMouseEvent;
837 me.reset(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
838 emit mouseXChanged(&me);
839 me.setPosition(d->lastPos);
840 emit mouseYChanged(&me);
841 me.setPosition(d->lastPos);
842 emit positionChanged(&me);
843 }
844
845 // A MouseArea should not block hover events
846 event->ignore();
847}
848
849void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
850{
851 Q_D(QQuickMouseArea);
852 if (!d->enabled && !d->pressed) {
853 QQuickItem::hoverMoveEvent(event);
854 } else if (d->lastPos != event->position()) {
855 d->lastPos = event->position();
856 d->lastModifiers = event->modifiers();
857 QQuickMouseEvent &me = d->quickMouseEvent;
858 me.reset(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
859 emit mouseXChanged(&me);
860 me.setPosition(d->lastPos);
861 emit mouseYChanged(&me);
862 me.setPosition(d->lastPos);
863 emit positionChanged(&me);
864 }
865
866 // A MouseArea should not block hover events
867 event->ignore();
868}
869
870void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
871{
872 Q_D(QQuickMouseArea);
873 if (!d->enabled && !d->pressed && !d->hovered)
874 QQuickItem::hoverLeaveEvent(event);
875 else
876 setHovered(false);
877
878 // A MouseArea should not block hover events
879 event->ignore();
880}
881
882#if QT_CONFIG(wheelevent)
883void QQuickMouseArea::wheelEvent(QWheelEvent *event)
884{
885 Q_D(QQuickMouseArea);
886 if (!d->enabled || (!isScrollGestureEnabled() && event->source() != Qt::MouseEventNotSynthesized)) {
887 QQuickItem::wheelEvent(event);
888 return;
889 }
890
891 QQuickWheelEvent &we = d->quickWheelEvent;
892 we.reset(event);
893 we.setAccepted(d->isWheelConnected());
894 emit wheel(&we);
895 if (!we.isAccepted())
896 QQuickItem::wheelEvent(event);
897}
898#endif
899
900void QQuickMouseArea::ungrabMouse()
901{
902 Q_D(QQuickMouseArea);
903 if (d->pressed) {
904 // if our mouse grab has been removed (probably by Flickable), fix our
905 // state
906 d->pressed = Qt::NoButton;
907 d->stealMouse = false;
908 d->doubleClick = false;
909 d->overThreshold = false;
910 setKeepMouseGrab(false);
911
912#if QT_CONFIG(quick_draganddrop)
913 if (d->drag)
914 d->drag->setActive(false);
915#endif
916
917 emit canceled();
918 emit pressedChanged();
919 emit containsPressChanged();
920 emit pressedButtonsChanged();
921
922 if (d->hovered && !isUnderMouse()) {
923 qCDebug(lcHoverTrace) << "losing hover: not under the mouse";
924 d->hovered = false;
925 emit hoveredChanged();
926 }
927 }
928}
929
930void QQuickMouseArea::mouseUngrabEvent()
931{
932 ungrabMouse();
933}
934
935void QQuickMouseArea::touchUngrabEvent()
936{
937 // allow a Pointer Handler to steal the grab from MouseArea
938 ungrabMouse();
939}
940
941bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
942{
943 Q_D(QQuickMouseArea);
944 QPointF localPos = mapFromScene(event->scenePosition());
945
946 QQuickWindow *c = window();
947 QQuickItem *grabber = c ? c->mouseGrabberItem() : nullptr;
948 bool stealThisEvent = d->stealMouse;
949 if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
950 QMouseEvent mouseEvent(event->type(), localPos, event->scenePosition(), event->globalPosition(),
951 event->button(), event->buttons(), event->modifiers());
952 mouseEvent.setAccepted(false);
953
954 switch (event->type()) {
955 case QEvent::MouseMove:
956 mouseMoveEvent(&mouseEvent);
957 break;
958 case QEvent::MouseButtonPress:
959 mousePressEvent(&mouseEvent);
960 break;
961 case QEvent::MouseButtonRelease:
962 mouseReleaseEvent(&mouseEvent);
963 stealThisEvent = d->stealMouse;
964 break;
965 default:
966 break;
967 }
968 grabber = c ? c->mouseGrabberItem() : nullptr;
969 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
970 grabMouse();
971
972 return stealThisEvent;
973 }
974 if (event->type() == QEvent::MouseButtonRelease) {
975 if (d->pressed) {
976 d->pressed &= ~event->button();
977 emit pressedButtonsChanged();
978 if (!d->pressed) {
979 // no other buttons are pressed
980 d->stealMouse = false;
981 d->overThreshold = false;
982 if (c && c->mouseGrabberItem() == this)
983 ungrabMouse();
984 emit canceled();
985 emit pressedChanged();
986 emit containsPressChanged();
987 if (d->hovered) {
988 qCDebug(lcHoverTrace) << "losing hover: button released";
989 d->hovered = false;
990 emit hoveredChanged();
991 }
992 }
993 }
994 }
995 return false;
996}
997
998bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
999{
1000 Q_D(QQuickMouseArea);
1001 if (!d->pressed &&
1002 (!d->enabled || !isVisible()
1003#if QT_CONFIG(quick_draganddrop)
1004 || !d->drag || !d->drag->filterChildren()
1005#endif
1006 )
1007 )
1008 return QQuickItem::childMouseEventFilter(i, e);
1009 switch (e->type()) {
1010 case QEvent::MouseButtonPress:
1011 case QEvent::MouseMove:
1012 case QEvent::MouseButtonRelease:
1013 return sendMouseEvent(static_cast<QMouseEvent *>(e));
1014 default:
1015 break;
1016 }
1017
1018 return QQuickItem::childMouseEventFilter(i, e);
1019}
1020
1021void QQuickMouseArea::timerEvent(QTimerEvent *event)
1022{
1023 Q_D(QQuickMouseArea);
1024 if (event->timerId() == d->pressAndHoldTimer.timerId()) {
1025 d->pressAndHoldTimer.stop();
1026#if QT_CONFIG(quick_draganddrop)
1027 bool dragged = d->drag && d->drag->active();
1028#else
1029 bool dragged = false;
1030#endif
1031 if (d->pressed && dragged == false && d->hovered == true) {
1032 d->longPress = true;
1033 QQuickMouseEvent &me = d->quickMouseEvent;
1034 me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress, d->lastFlags);
1035#if QT_DEPRECATED_SINCE(6, 6)
1036 me.setSource(Qt::MouseEventSynthesizedByQt);
1037#endif
1038 me.setAccepted(d->isPressAndHoldConnected());
1039 emit pressAndHold(&me);
1040 if (!me.isAccepted())
1041 d->propagate(&me, QQuickMouseAreaPrivate::PressAndHold);
1042 if (!me.isAccepted()) // no one handled the long press - allow click
1043 d->longPress = false;
1044 }
1045 }
1046}
1047
1048void QQuickMouseArea::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
1049{
1050 Q_D(QQuickMouseArea);
1051 QQuickItem::geometryChange(newGeometry, oldGeometry);
1052
1053 if (!d->lastScenePos.isValid())
1054 d->lastScenePos = mapToScene(d->lastPos);
1055 else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
1056 d->lastPos = mapFromScene(d->lastScenePos);
1057}
1058
1059void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
1060{
1061 Q_D(QQuickMouseArea);
1062 switch (change) {
1063 case ItemEnabledHasChanged:
1064 // If MouseArea becomes effectively disabled by disabling a parent
1065 // (for example, onPressed: parent.enabled = false), cancel the pressed state.
1066 if (d->pressed && !d->effectiveEnable)
1067 ungrabMouse();
1068 break;
1069 case ItemVisibleHasChanged:
1070 if (d->effectiveEnable && d->enabled && hoverEnabled()
1071 && d->hovered != (isVisible() && isUnderMouse())) {
1072 if (d->hovered) {
1073 // If hovered but no longer under the mouse then un-hover.
1074 setHovered(false);
1075 } else {
1076 // If under the mouse but not hovered then hover the QQuickMouseArea if it is
1077 // marked as a hovered item under the windows QQuickDeliveryAgentPrivate instance.
1078 // This is required as this QQuickMouseArea may be masked by another hoverable
1079 // QQuickMouseArea higher up in the scenes z-index ordering.
1080 QPointF globalPos{ QGuiApplicationPrivate::lastCursorPosition.toPoint() };
1081 QPointF scenePos{ d->window->mapFromGlobal(globalPos) };
1082
1083 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(d->window);
1084 QQuickDeliveryAgentPrivate *dap = wd->deliveryAgentPrivate();
1085
1086 // If the QQuickDeliveryAgentPrivate has not already found a hovered leaf
1087 // item then attempt to find one.
1088 if (!dap->hoveredLeafItemFound) {
1089 dap->deliverHoverEvent(scenePos, scenePos, Qt::NoModifier,
1090 QDateTime::currentSecsSinceEpoch());
1091 }
1092
1093 // Now if the QQuickDeliveryAgentPrivate has found a hovered leaf item check
1094 // that this QQuickMouseArea item was one of the hovered items.
1095 if (dap->hoveredLeafItemFound) {
1096 for (auto hoverItem : dap->hoverItems) {
1097 if (hoverItem.item == this) {
1098 // Found a match so update the hover state.
1099 d->lastScenePos = scenePos;
1100 d->lastPos = mapFromScene(d->lastScenePos);
1101 setHovered(true);
1102 break;
1103 }
1104 }
1105 }
1106 }
1107 }
1108 if (d->pressed && (!isVisible())) {
1109 // This happens when the mouse area hides itself
1110 // inside the press handler. In that case we should not keep the internal
1111 // state as pressed, since we never became the mouse grabber.
1112 ungrabMouse();
1113 }
1114 break;
1115 default:
1116 break;
1117 }
1118
1119 QQuickItem::itemChange(change, value);
1120}
1121
1122/*!
1123 \qmlproperty bool QtQuick::MouseArea::hoverEnabled
1124 This property holds whether hover events are handled.
1125
1126 By default, mouse events are only handled in response to a button event, or when a button is
1127 pressed. Hover enables handling of all mouse events even when no mouse button is
1128 pressed.
1129
1130 This property affects the containsMouse property and the onEntered, onExited and
1131 onPositionChanged signals.
1132*/
1133bool QQuickMouseArea::hoverEnabled() const
1134{
1135 return d_func()->hoverEnabled;
1136}
1137
1138void QQuickMouseArea::setHoverEnabled(bool h)
1139{
1140 Q_D(QQuickMouseArea);
1141 if (h == d->hoverEnabled)
1142 return;
1143
1144 d->hoverEnabled = h;
1145 setAcceptHoverEvents(h && d->enabled);
1146
1147 emit hoverEnabledChanged();
1148}
1149
1150
1151/*!
1152 \qmlproperty bool QtQuick::MouseArea::containsMouse
1153 This property holds whether the mouse is currently inside the mouse area.
1154
1155 \warning If hoverEnabled is \c false, \c containsMouse will be \c true
1156 when the mouse is pressed while the mouse cursor is inside the MouseArea.
1157 But if you set \c {mouse.accepted = false} in an \c onPressed handler,
1158 \c containsMouse will remain \c false because the press was rejected.
1159*/
1160bool QQuickMouseArea::hovered() const
1161{
1162 Q_D(const QQuickMouseArea);
1163 return d->hovered;
1164}
1165
1166/*!
1167 \qmlproperty bool QtQuick::MouseArea::pressed
1168 This property holds whether any of the \l acceptedButtons are currently pressed.
1169*/
1170bool QQuickMouseArea::isPressed() const
1171{
1172 Q_D(const QQuickMouseArea);
1173 return d->pressed;
1174}
1175
1176/*!
1177 \qmlproperty bool QtQuick::MouseArea::containsPress
1178 \since 5.4
1179 This is a convenience property equivalent to \c {pressed && containsMouse},
1180 i.e. it holds whether any of the \l acceptedButtons are currently pressed
1181 and the mouse is currently within the MouseArea.
1182
1183 This property is particularly useful for highlighting an item while the mouse
1184 is pressed within its bounds.
1185
1186 \sa pressed, containsMouse
1187*/
1188bool QQuickMouseArea::containsPress() const
1189{
1190 Q_D(const QQuickMouseArea);
1191 return d->pressed && d->hovered;
1192}
1193
1194void QQuickMouseArea::setHovered(bool h)
1195{
1196 Q_D(QQuickMouseArea);
1197 if (d->hovered != h) {
1198 qCDebug(lcHoverTrace) << this << d->hovered << "->" << h;
1199 d->hovered = h;
1200 emit hoveredChanged();
1201 d->hovered ? emit entered() : emit exited();
1202 if (d->pressed)
1203 emit containsPressChanged();
1204 }
1205}
1206
1207/*!
1208 \qmlproperty Qt::MouseButtons QtQuick::MouseArea::acceptedButtons
1209 This property holds the mouse buttons that the mouse area reacts to.
1210
1211 To specify that the MouseArea will react to multiple buttons,
1212 Qt::MouseButtons flag values are combined using the "|" (or) operator:
1213
1214 \code
1215 MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
1216 \endcode
1217
1218 To indicate that all possible mouse buttons are to be accepted,
1219 the special value 'Qt.AllButtons' may be used:
1220
1221 \code
1222 MouseArea { acceptedButtons: Qt.AllButtons }
1223 \endcode
1224
1225 The default value is \c Qt.LeftButton.
1226*/
1227Qt::MouseButtons QQuickMouseArea::acceptedButtons() const
1228{
1229 return acceptedMouseButtons();
1230}
1231
1232void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
1233{
1234 if (buttons != acceptedMouseButtons()) {
1235 setAcceptedMouseButtons(buttons);
1236 emit acceptedButtonsChanged();
1237 }
1238}
1239
1240bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventSource source)
1241{
1242 Q_D(QQuickMouseArea);
1243
1244 // Don't allow entering pressed state while invisible
1245 if (p && !d->effectiveVisible)
1246 return false;
1247
1248#if QT_CONFIG(quick_draganddrop)
1249 bool dragged = d->drag && d->drag->active();
1250#else
1251 bool dragged = false;
1252#endif
1253 bool wasPressed = d->pressed & button;
1254 bool isclick = wasPressed && p == false && dragged == false && d->hovered == true;
1255 Qt::MouseButtons oldPressed = d->pressed;
1256
1257 if (wasPressed != p) {
1258 QQuickMouseEvent &me = d->quickMouseEvent;
1259 me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress, d->lastFlags);
1260#if QT_DEPRECATED_SINCE(6, 6)
1261 me.setSource(source);
1262#endif
1263 if (p) {
1264 d->pressed |= button;
1265 if (!d->doubleClick)
1266 emit pressed(&me);
1267 me.setPosition(d->lastPos);
1268 emit mouseXChanged(&me);
1269 me.setPosition(d->lastPos);
1270 emit mouseYChanged(&me);
1271
1272 if (!me.isAccepted()) {
1273 d->pressed = Qt::NoButton;
1274 if (!hoverEnabled())
1275 setHovered(false);
1276 }
1277
1278 if (!oldPressed) {
1279 emit pressedChanged();
1280 emit containsPressChanged();
1281 }
1282 emit pressedButtonsChanged();
1283 } else {
1284 d->pressed &= ~button;
1285 emit released(&me);
1286 me.setPosition(d->lastPos);
1287 if (!d->pressed) {
1288 emit pressedChanged();
1289 emit containsPressChanged();
1290 }
1291 emit pressedButtonsChanged();
1292 if (isclick && !d->longPress && !d->doubleClick){
1293 me.setAccepted(d->isClickConnected());
1294 emit clicked(&me);
1295 if (!me.isAccepted())
1296 d->propagate(&me, QQuickMouseAreaPrivate::Click);
1297 }
1298 }
1299
1300 return me.isAccepted();
1301 }
1302 Q_UNUSED(source)
1303 return false;
1304}
1305
1306
1307/*!
1308 \qmlproperty Qt::CursorShape QtQuick::MouseArea::cursorShape
1309 This property holds the cursor shape for this mouse area.
1310 Note that on platforms that do not display a mouse cursor this may have
1311 no effect.
1312
1313 The available cursor shapes are:
1314 \list
1315 \li Qt.ArrowCursor
1316 \li Qt.UpArrowCursor
1317 \li Qt.CrossCursor
1318 \li Qt.WaitCursor
1319 \li Qt.IBeamCursor
1320 \li Qt.SizeVerCursor
1321 \li Qt.SizeHorCursor
1322 \li Qt.SizeBDiagCursor
1323 \li Qt.SizeFDiagCursor
1324 \li Qt.SizeAllCursor
1325 \li Qt.BlankCursor
1326 \li Qt.SplitVCursor
1327 \li Qt.SplitHCursor
1328 \li Qt.PointingHandCursor
1329 \li Qt.ForbiddenCursor
1330 \li Qt.WhatsThisCursor
1331 \li Qt.BusyCursor
1332 \li Qt.OpenHandCursor
1333 \li Qt.ClosedHandCursor
1334 \li Qt.DragCopyCursor
1335 \li Qt.DragMoveCursor
1336 \li Qt.DragLinkCursor
1337 \endlist
1338
1339 In order to only set a mouse cursor shape for a region without reacting
1340 to mouse events set the acceptedButtons to none:
1341
1342 \code
1343 MouseArea { cursorShape: Qt.IBeamCursor; acceptedButtons: Qt.NoButton }
1344 \endcode
1345
1346 The default value is \c Qt.ArrowCursor.
1347
1348 \note If the \c cursorShape property is set to \c undefined, the \c MouseArea will
1349 not change the existing shape when entering it.
1350
1351 \sa Qt::CursorShape
1352*/
1353
1354#if QT_CONFIG(cursor)
1355Qt::CursorShape QQuickMouseArea::cursorShape() const
1356{
1357 return cursor().shape();
1358}
1359
1360void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
1361{
1362 if (cursor().shape() == shape)
1363 return;
1364
1365 setCursor(shape);
1366
1367 emit cursorShapeChanged();
1368}
1369
1370#endif
1371
1372
1373/*!
1374 \qmlproperty int QtQuick::MouseArea::pressAndHoldInterval
1375 \since 5.9
1376
1377 This property overrides the elapsed time in milliseconds before
1378 \c pressAndHold is emitted.
1379
1380 If not explicitly set -- or after reset -- the value follows
1381 \c QStyleHints::mousePressAndHoldInterval.
1382
1383 Typically it's sufficient to set this property globally using the
1384 application style hint. This property should be used when varying intervals
1385 are needed for certain MouseAreas.
1386
1387 \sa pressAndHold
1388*/
1389int QQuickMouseArea::pressAndHoldInterval() const
1390{
1391 Q_D(const QQuickMouseArea);
1392 return d->pressAndHoldInterval > -1 ?
1393 d->pressAndHoldInterval : QGuiApplication::styleHints()->mousePressAndHoldInterval();
1394}
1395
1396void QQuickMouseArea::setPressAndHoldInterval(int interval)
1397{
1398 Q_D(QQuickMouseArea);
1399 if (interval != d->pressAndHoldInterval) {
1400 d->pressAndHoldInterval = interval;
1401 emit pressAndHoldIntervalChanged();
1402 }
1403}
1404
1405void QQuickMouseArea::resetPressAndHoldInterval()
1406{
1407 Q_D(QQuickMouseArea);
1408 if (d->pressAndHoldInterval > -1) {
1409 d->pressAndHoldInterval = -1;
1410 emit pressAndHoldIntervalChanged();
1411 }
1412}
1413
1414/*!
1415 \qmlpropertygroup QtQuick::MouseArea::drag
1416 \qmlproperty Item QtQuick::MouseArea::drag.target
1417 \qmlproperty bool QtQuick::MouseArea::drag.active
1418 \qmlproperty enumeration QtQuick::MouseArea::drag.axis
1419 \qmlproperty real QtQuick::MouseArea::drag.minimumX
1420 \qmlproperty real QtQuick::MouseArea::drag.maximumX
1421 \qmlproperty real QtQuick::MouseArea::drag.minimumY
1422 \qmlproperty real QtQuick::MouseArea::drag.maximumY
1423 \qmlproperty bool QtQuick::MouseArea::drag.filterChildren
1424 \qmlproperty real QtQuick::MouseArea::drag.threshold
1425 \qmlproperty bool QtQuick::MouseArea::drag.smoothed
1426
1427 \c drag provides a convenient way to make an item draggable.
1428
1429 \list
1430 \li \c drag.target specifies the id of the item to drag.
1431 \li \c drag.active specifies if the target item is currently being dragged.
1432 \li \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XAndYAxis)
1433 \li \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
1434 \endlist
1435
1436 The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
1437 of the rectangle is reduced when it is dragged to the right.
1438
1439 \snippet qml/mousearea/mousearea.qml drag
1440
1441 \note Items cannot be dragged if they are anchored for the requested
1442 \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1443 for \c rect in the above example, it cannot be dragged along the X-axis.
1444 This can be avoided by settng the anchor value to \c undefined in
1445 an \l {pressed}{onPressed} handler.
1446
1447 If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
1448 enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1449
1450 \snippet qml/mousearea/mouseareadragfilter.qml dragfilter
1451
1452 \c drag.threshold determines the threshold in pixels of when the drag operation should
1453 start. By default this is bound to a platform dependent value. This property was added in
1454 Qt Quick 2.2.
1455
1456 If \c drag.smoothed is \c true, the target will be moved only after the drag operation has
1457 started. If set to \c false, the target will be moved straight to the current mouse position.
1458 By default, this property is \c true. This property was added in Qt Quick 2.4
1459
1460 See the \l Drag attached property and \l DropArea if you want to make a drop.
1461*/
1462
1463#if QT_CONFIG(quick_draganddrop)
1464QQuickDrag *QQuickMouseArea::drag()
1465{
1466 Q_D(QQuickMouseArea);
1467 if (!d->drag)
1468 d->drag = new QQuickDrag;
1469 return d->drag;
1470}
1471#endif
1472
1473QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1474{
1475 Q_UNUSED(data);
1476 Q_D(QQuickMouseArea);
1477
1478 if (!qmlMaVisualTouchDebugging())
1479 return nullptr;
1480
1481 QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
1482 if (!rectangle) rectangle = d->sceneGraphContext()->createInternalRectangleNode();
1483
1484 rectangle->setRect(QRectF(0, 0, width(), height()));
1485 rectangle->setColor(QColor(255, 0, 0, 50));
1486 rectangle->update();
1487 return rectangle;
1488}
1489
1490QT_END_NAMESPACE
1491
1492#include "moc_qquickmousearea_p.cpp"