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

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