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