1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickmousearea_p.h"
43 #include "qquickmousearea_p_p.h"
44 #include "qquickwindow.h"
45 #include "qquickevents_p_p.h"
46 #include "qquickdrag_p.h"
48 #include <private/qqmldata_p.h>
50 #include <QtGui/private/qguiapplication_p.h>
52 #include <QtGui/qevent.h>
53 #include <QtGui/qguiapplication.h>
54 #include <QtGui/qstylehints.h>
60 DEFINE_BOOL_CONFIG_OPTION(qmlVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
62 static const int PressAndHoldDelay = 800;
64 #ifndef QT_NO_DRAGANDDROP
66 QQuickDrag::QQuickDrag(QObject *parent)
67 : QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX),
68 _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false)
72 QQuickDrag::~QQuickDrag()
76 QQuickItem *QQuickDrag::target() const
81 void QQuickDrag::setTarget(QQuickItem *t)
89 void QQuickDrag::resetTarget()
97 QQuickDrag::Axis QQuickDrag::axis() const
102 void QQuickDrag::setAxis(QQuickDrag::Axis a)
110 qreal QQuickDrag::xmin() const
115 void QQuickDrag::setXmin(qreal m)
120 emit minimumXChanged();
123 qreal QQuickDrag::xmax() const
128 void QQuickDrag::setXmax(qreal m)
133 emit maximumXChanged();
136 qreal QQuickDrag::ymin() const
141 void QQuickDrag::setYmin(qreal m)
146 emit minimumYChanged();
149 qreal QQuickDrag::ymax() const
154 void QQuickDrag::setYmax(qreal m)
159 emit maximumYChanged();
162 bool QQuickDrag::active() const
167 void QQuickDrag::setActive(bool drag)
172 emit activeChanged();
175 bool QQuickDrag::filterChildren() const
177 return _filterChildren;
180 void QQuickDrag::setFilterChildren(bool filter)
182 if (_filterChildren == filter)
184 _filterChildren = filter;
185 emit filterChildrenChanged();
188 QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj)
190 return new QQuickDragAttached(obj);
193 #endif // QT_NO_DRAGANDDROP
195 QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
196 : enabled(true), hovered(false), longPress(false),
197 moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
198 propagateComposedEvents(false), pressed(0)
199 #ifndef QT_NO_DRAGANDDROP
208 QQuickMouseAreaPrivate::~QQuickMouseAreaPrivate()
210 #ifndef QT_NO_DRAGANDDROP
218 void QQuickMouseAreaPrivate::init()
220 Q_Q(QQuickMouseArea);
221 q->setAcceptedMouseButtons(Qt::LeftButton);
222 q->setFiltersChildMouseEvents(true);
223 if (qmlVisualTouchDebugging()) {
224 q->setFlag(QQuickItem::ItemHasContents);
228 void QQuickMouseAreaPrivate::saveEvent(QMouseEvent *event)
230 lastPos = event->localPos();
231 lastScenePos = event->windowPos();
232 lastButton = event->button();
233 lastButtons = event->buttons();
234 lastModifiers = event->modifiers();
237 bool QQuickMouseAreaPrivate::isPressAndHoldConnected()
239 Q_Q(QQuickMouseArea);
240 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, pressAndHold, (QQuickMouseEvent *));
243 bool QQuickMouseAreaPrivate::isDoubleClickConnected()
245 Q_Q(QQuickMouseArea);
246 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, doubleClicked, (QQuickMouseEvent *));
249 bool QQuickMouseAreaPrivate::isClickConnected()
251 Q_Q(QQuickMouseArea);
252 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, clicked, (QQuickMouseEvent *));
255 bool QQuickMouseAreaPrivate::isWheelConnected()
257 Q_Q(QQuickMouseArea);
258 IS_SIGNAL_CONNECTED(q, QQuickMouseArea, wheel, (QQuickWheelEvent *));
261 void QQuickMouseAreaPrivate::propagate(QQuickMouseEvent* event, PropagateType t)
263 Q_Q(QQuickMouseArea);
264 if (!propagateComposedEvents)
266 QPointF scenePos = q->mapToScene(QPointF(event->x(), event->y()));
267 propagateHelper(event, window->rootItem(), scenePos, t);
270 bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *item,const QPointF &sp, PropagateType sig)
272 //Based off of QQuickWindow::deliverInitialMousePressEvent
273 //But specific to MouseArea, so doesn't belong in window
274 Q_Q(const QQuickMouseArea);
275 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
277 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
278 QPointF p = item->mapFromScene(sp);
279 if (!item->contains(p))
283 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
284 for (int ii = children.count() - 1; ii >= 0; --ii) {
285 QQuickItem *child = children.at(ii);
286 if (!child->isVisible() || !child->isEnabled())
288 if (propagateHelper(ev, child, sp, sig))
292 QQuickMouseArea* ma = qobject_cast<QQuickMouseArea*>(item);
293 if (ma && ma != q && itemPrivate->acceptedMouseButtons() & ev->button()) {
296 if (!ma->d_func()->isClickConnected())
300 if (!ma->d_func()->isDoubleClickConnected())
304 if (!ma->d_func()->isPressAndHoldConnected())
308 QPointF p = item->mapFromScene(sp);
309 if (item->contains(p)) {
312 ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
314 case Click: emit ma->clicked(ev); break;
315 case DoubleClick: emit ma->doubleClicked(ev); break;
316 case PressAndHold: emit ma->pressAndHold(ev); break;
318 if (ev->isAccepted())
328 \instantiates QQuickMouseArea
329 \inqmlmodule QtQuick 2
330 \ingroup qtquick-input
331 \brief Enables simple mouse handling
334 A MouseArea is an invisible item that is typically used in conjunction with
335 a visible item in order to provide mouse handling for that item.
336 By effectively acting as a proxy, the logic for mouse handling can be
337 contained within a MouseArea item.
339 For basic key handling, see the \l{Keys}{Keys attached property}.
341 The \l enabled property is used to enable and disable mouse handling for
342 the proxied item. When disabled, the mouse area becomes transparent to
345 The \l pressed read-only property indicates whether or not the user is
346 holding down a mouse button over the mouse area. This property is often
347 used in bindings between properties in a user interface. The containsMouse
348 read-only property indicates the presence of the mouse cursor over the
349 mouse area but, by default, only when a mouse button is held down; see below
352 Information about the mouse position and button clicks are provided via
353 signals for which event handler properties are defined. The most commonly
354 used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
355 onPressed, onReleased and onPressAndHold. It's also possible to handle mouse
356 wheel events via the onWheel signal.
358 By default, MouseArea items only report mouse clicks and not changes to the
359 position of the mouse cursor. Setting the hoverEnabled property ensures that
360 handlers defined for onPositionChanged, onEntered and onExited are used and
361 that the containsMouse property is updated even when no mouse buttons are
364 \section1 Example Usage
366 \div {class="float-right"}
367 \inlineimage qml-mousearea-snippet.png
370 The following example uses a MouseArea in a \l Rectangle that changes
371 the \l Rectangle color to red when clicked:
373 \snippet qml/mousearea/mousearea.qml import
375 \snippet qml/mousearea/mousearea.qml intro
378 Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
379 additional information about the mouse event, such as the position, button,
380 and any key modifiers.
382 Here is an extension of the previous example that produces a different
383 color when the area is right clicked:
385 \snippet qml/mousearea/mousearea.qml intro-extended
387 Behavioral Change in QtQuick 2.0
389 From QtQuick 2.0, the signals clicked, doubleClicked and pressAndHold have a different interaction
390 model with regards to the delivery of events to multiple overlapping MouseAreas. These signals can now propagate
391 to all MouseAreas in the area, in painting order, until accepted by one of them. A signal is accepted by
392 default if there is a signal handler for it, use mouse.accepted = false; to ignore. This propagation
393 can send the signal to MouseAreas other than the one which accepted the press event, although that MouseArea
394 will receive the signal first. This behavior can be enabled by setting propagateComposedEvents to true.
396 \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example}
400 \qmlsignal QtQuick2::MouseArea::onEntered()
402 This handler is called when the mouse enters the mouse area.
404 By default the onEntered handler is only called while a button is
405 pressed. Setting hoverEnabled to true enables handling of
406 onEntered when no mouse button is pressed.
412 \qmlsignal QtQuick2::MouseArea::onExited()
414 This handler is called when the mouse exits the mouse area.
416 By default the onExited handler is only called while a button is
417 pressed. Setting hoverEnabled to true enables handling of
418 onExited when no mouse button is pressed.
420 The example below shows a fairly typical relationship between
421 two MouseAreas, with \c mouseArea2 on top of \c mouseArea1. Moving the
422 mouse into \c mouseArea2 from \c mouseArea1 will cause \c onExited
423 to be called for \c mouseArea1.
426 width: 400; height: 400
434 width: 100; height: 100
435 anchors.centerIn: parent
441 If instead you give the two mouseAreas a parent-child relationship,
442 moving the mouse into \c mouseArea2 from \c mouseArea1 will \b not
443 cause \c onExited to be called for \c mouseArea1. Instead, they will
444 both be considered to be simultaneously hovered.
450 \qmlsignal QtQuick2::MouseArea::onPositionChanged(MouseEvent mouse)
452 This handler is called when the mouse position changes.
454 The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
455 position, and any buttons currently pressed.
457 The \e accepted property of the MouseEvent parameter is ignored in this handler.
459 By default the onPositionChanged handler is only called while a button is
460 pressed. Setting hoverEnabled to true enables handling of
461 onPositionChanged when no mouse button is pressed.
465 \qmlsignal QtQuick2::MouseArea::onClicked(MouseEvent mouse)
467 This handler is called when there is a click. A click is defined as a press followed by a release,
468 both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
469 releasing is also considered a click).
471 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
472 position of the release of the click, and whether the click was held.
474 The \e accepted property of the MouseEvent parameter is ignored in this handler.
478 \qmlsignal QtQuick2::MouseArea::onPressed(MouseEvent mouse)
480 This handler is called when there is a press.
481 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
482 position and which button was pressed.
484 The \e accepted property of the MouseEvent parameter determines whether this MouseArea
485 will handle the press and all future mouse events until release. The default is to accept
486 the event and not allow other MouseArea beneath this one to handle the event. If \e accepted
487 is set to false, no further events will be sent to this MouseArea until the button is next
492 \qmlsignal QtQuick2::MouseArea::onReleased(MouseEvent mouse)
494 This handler is called when there is a release.
495 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
496 position of the release of the click, and whether the click was held.
498 The \e accepted property of the MouseEvent parameter is ignored in this handler.
504 \qmlsignal QtQuick2::MouseArea::onPressAndHold(MouseEvent mouse)
506 This handler is called when there is a long press (currently 800ms).
507 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
508 position of the press, and which button is pressed.
510 The \e accepted property of the MouseEvent parameter is ignored in this handler.
514 \qmlsignal QtQuick2::MouseArea::onDoubleClicked(MouseEvent mouse)
516 This handler is called when there is a double-click (a press followed by a release followed by a press).
517 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
518 position of the release of the click, and whether the click was held.
520 If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
521 in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
522 click; otherwise they are suppressed. The accepted property defaults to true.
526 \qmlsignal QtQuick2::MouseArea::onCanceled()
528 This handler is called when mouse events have been canceled, either because an event was not accepted, or
529 because another item stole the mouse event handling.
531 This signal is for advanced use: it is useful when there is more than one MouseArea
532 that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
533 case, if you execute some logic on the pressed signal and then start dragging, the
534 \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
535 the logic when the MouseArea has lost the mouse handling to the \l Flickable,
536 \c onCanceled should be used in addition to onReleased.
540 \qmlsignal QtQuick2::MouseArea::onWheel(WheelEvent wheel)
542 This handler is called in response to both mouse wheel and trackpad scroll gestures.
544 The \l {WheelEvent}{wheel} parameter provides information about the event, including the x and y
545 position, any buttons currently pressed, and information about the wheel movement, including
546 angleDelta and pixelDelta.
549 QQuickMouseArea::QQuickMouseArea(QQuickItem *parent)
550 : QQuickItem(*(new QQuickMouseAreaPrivate), parent)
552 Q_D(QQuickMouseArea);
556 QQuickMouseArea::~QQuickMouseArea()
561 \qmlproperty real QtQuick2::MouseArea::mouseX
562 \qmlproperty real QtQuick2::MouseArea::mouseY
563 These properties hold the coordinates of the mouse cursor.
565 If the hoverEnabled property is false then these properties will only be valid
566 while a button is pressed, and will remain valid as long as the button is held
567 down even if the mouse is moved outside the area.
569 By default, this property is false.
571 If hoverEnabled is true then these properties will be valid when:
573 \li no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
574 \li a button is pressed and held, even if it has since moved out of the area.
577 The coordinates are relative to the MouseArea.
579 qreal QQuickMouseArea::mouseX() const
581 Q_D(const QQuickMouseArea);
582 return d->lastPos.x();
585 qreal QQuickMouseArea::mouseY() const
587 Q_D(const QQuickMouseArea);
588 return d->lastPos.y();
592 \qmlproperty bool QtQuick2::MouseArea::enabled
593 This property holds whether the item accepts mouse events.
595 By default, this property is true.
597 bool QQuickMouseArea::isEnabled() const
599 Q_D(const QQuickMouseArea);
603 void QQuickMouseArea::setEnabled(bool a)
605 Q_D(QQuickMouseArea);
606 if (a != d->enabled) {
608 emit enabledChanged();
613 \qmlproperty bool QtQuick2::MouseArea::preventStealing
614 This property holds whether the mouse events may be stolen from this
617 If a MouseArea is placed within an item that filters child mouse
618 events, such as Flickable, the mouse
619 events may be stolen from the MouseArea if a gesture is recognized
620 by the parent item, e.g. a flick gesture. If preventStealing is
621 set to true, no item will steal the mouse events.
623 Note that setting preventStealing to true once an item has started
624 stealing events will have no effect until the next press event.
626 By default this property is false.
628 bool QQuickMouseArea::preventStealing() const
630 Q_D(const QQuickMouseArea);
631 return d->preventStealing;
634 void QQuickMouseArea::setPreventStealing(bool prevent)
636 Q_D(QQuickMouseArea);
637 if (prevent != d->preventStealing) {
638 d->preventStealing = prevent;
639 setKeepMouseGrab(d->preventStealing && d->enabled);
640 emit preventStealingChanged();
646 \qmlproperty bool QtQuick2::MouseArea::propagateComposedEvents
647 This property holds whether composed mouse events will automatically propagate to
650 MouseArea contains several composed events, clicked, doubleClicked,
651 and pressAndHold. These can propagate via a separate mechanism to basic
652 mouse events, like pressed, which they are composed of.
654 If propagateComposedEvents is set to true, then composed events will be automatically
655 propagated to other MouseAreas in the same location in the scene. They are propagated
656 in painting order until an item accepts them. Unlike pressed handling, events will
657 not be automatically accepted if no handler is present.
659 This property greatly simplifies the usecase of when you want to have overlapping MouseAreas
660 handling the composed events together. For example: if you want one MouseArea to handle click
661 signals and the other to handle pressAndHold, or if you want one MouseArea to handle click most
662 of the time, but pass it through when certain conditions are met.
664 By default this property is false.
666 bool QQuickMouseArea::propagateComposedEvents() const
668 Q_D(const QQuickMouseArea);
669 return d->propagateComposedEvents;
672 void QQuickMouseArea::setPropagateComposedEvents(bool prevent)
674 Q_D(QQuickMouseArea);
675 if (prevent != d->propagateComposedEvents) {
676 d->propagateComposedEvents = prevent;
677 setKeepMouseGrab(d->propagateComposedEvents && d->enabled);
678 emit propagateComposedEventsChanged();
683 \qmlproperty MouseButtons QtQuick2::MouseArea::pressedButtons
684 This property holds the mouse buttons currently pressed.
686 It contains a bitwise combination of:
693 The code below displays "right" when the right mouse buttons is pressed:
695 \snippet qml/mousearea/mousearea.qml mousebuttons
697 \note this property only handles buttons specified in \l acceptedButtons.
701 Qt::MouseButtons QQuickMouseArea::pressedButtons() const
703 Q_D(const QQuickMouseArea);
707 void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
709 Q_D(QQuickMouseArea);
711 d->stealMouse = d->preventStealing;
712 if (!d->enabled || !(event->button() & acceptedMouseButtons())) {
713 QQuickItem::mousePressEvent(event);
715 d->longPress = false;
717 #ifndef QT_NO_DRAGANDDROP
719 d->drag->setActive(false);
722 d->startScene = event->windowPos();
723 d->pressAndHoldTimer.start(PressAndHoldDelay, this);
724 setKeepMouseGrab(d->stealMouse);
725 event->setAccepted(setPressed(event->button(), true));
729 void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
731 Q_D(QQuickMouseArea);
732 if (!d->enabled && !d->pressed) {
733 QQuickItem::mouseMoveEvent(event);
739 // ### we should skip this if these signals aren't used
740 // ### can GV handle this for us?
741 const bool isInside = contains(d->lastPos);
742 if (d->hovered && !isInside)
744 else if (!d->hovered && isInside)
747 #ifndef QT_NO_DRAGANDDROP
748 if (d->drag && d->drag->target()) {
750 d->targetStartPos = d->drag->target()->parentItem()
751 ? d->drag->target()->parentItem()->mapToScene(d->drag->target()->pos())
752 : d->drag->target()->pos();
755 QPointF startLocalPos;
757 if (drag()->target()->parentItem()) {
758 startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
759 curLocalPos = drag()->target()->parentItem()->mapFromScene(event->windowPos());
761 startLocalPos = d->startScene;
762 curLocalPos = event->windowPos();
765 qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
766 qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
768 if (keepMouseGrab() && d->stealMouse && !d->drag->active())
769 d->drag->setActive(true);
771 QPointF startPos = d->drag->target()->parentItem()
772 ? d->drag->target()->parentItem()->mapFromScene(d->targetStartPos)
775 QPointF dragPos = d->drag->target()->pos();
777 bool dragX = drag()->axis() & QQuickDrag::XAxis;
778 bool dragY = drag()->axis() & QQuickDrag::YAxis;
780 if (dragX && d->drag->active()) {
781 qreal x = (curLocalPos.x() - startLocalPos.x()) + startPos.x();
782 if (x < drag()->xmin())
784 else if (x > drag()->xmax())
788 if (dragY && d->drag->active()) {
789 qreal y = (curLocalPos.y() - startLocalPos.y()) + startPos.y();
790 if (y < drag()->ymin())
792 else if (y > drag()->ymax())
796 d->drag->target()->setPos(dragPos);
798 if (!keepMouseGrab()) {
799 bool xDragged = QQuickWindowPrivate::dragOverThreshold(dx, Qt::XAxis, event);
800 bool yDragged = QQuickWindowPrivate::dragOverThreshold(dy, Qt::YAxis, event);
801 if ((!dragY && !yDragged && dragX && xDragged)
802 || (!dragX && !xDragged && dragY && yDragged)
803 || (dragX && dragY && (xDragged || yDragged))) {
804 setKeepMouseGrab(true);
805 d->stealMouse = true;
813 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
814 emit mouseXChanged(&me);
815 me.setPosition(d->lastPos);
816 emit mouseYChanged(&me);
817 me.setPosition(d->lastPos);
818 emit positionChanged(&me);
821 void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
823 Q_D(QQuickMouseArea);
824 d->stealMouse = false;
825 if (!d->enabled && !d->pressed) {
826 QQuickItem::mouseReleaseEvent(event);
829 setPressed(event->button(), false);
831 // no other buttons are pressed
832 #ifndef QT_NO_DRAGANDDROP
834 d->drag->setActive(false);
836 // If we don't accept hover, we need to reset containsMouse.
837 if (!acceptHoverEvents())
839 QQuickWindow *w = window();
840 if (w && w->mouseGrabberItem() == this)
842 setKeepMouseGrab(false);
845 d->doubleClick = false;
848 void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
850 Q_D(QQuickMouseArea);
853 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
854 me.setAccepted(d->isDoubleClickConnected());
855 emit this->doubleClicked(&me);
856 if (!me.isAccepted())
857 d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
858 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
860 QQuickItem::mouseDoubleClickEvent(event);
863 void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
865 Q_D(QQuickMouseArea);
866 if (!d->enabled && !d->pressed) {
867 QQuickItem::hoverEnterEvent(event);
869 d->lastPos = event->posF();
870 d->lastModifiers = event->modifiers();
872 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
873 emit mouseXChanged(&me);
874 me.setPosition(d->lastPos);
875 emit mouseYChanged(&me);
876 me.setPosition(d->lastPos);
880 void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
882 Q_D(QQuickMouseArea);
883 if (!d->enabled && !d->pressed) {
884 QQuickItem::hoverMoveEvent(event);
886 d->lastPos = event->posF();
887 d->lastModifiers = event->modifiers();
888 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
889 emit mouseXChanged(&me);
890 me.setPosition(d->lastPos);
891 emit mouseYChanged(&me);
892 me.setPosition(d->lastPos);
893 emit positionChanged(&me);
897 void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
899 Q_D(QQuickMouseArea);
900 if (!d->enabled && !d->pressed)
901 QQuickItem::hoverLeaveEvent(event);
906 void QQuickMouseArea::wheelEvent(QWheelEvent *event)
908 Q_D(QQuickMouseArea);
910 QQuickItem::wheelEvent(event);
914 QQuickWheelEvent we(event->posF().x(), event->posF().y(), event->angleDelta(),
915 event->pixelDelta(), event->buttons(), event->modifiers());
916 we.setAccepted(d->isWheelConnected());
918 if (!we.isAccepted())
919 QQuickItem::wheelEvent(event);
922 void QQuickMouseArea::ungrabMouse()
924 Q_D(QQuickMouseArea);
926 // if our mouse grab has been removed (probably by Flickable), fix our
929 d->stealMouse = false;
930 setKeepMouseGrab(false);
932 emit pressedChanged();
933 emit pressedButtonsChanged();
936 emit hoveredChanged();
941 void QQuickMouseArea::mouseUngrabEvent()
946 bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
948 Q_D(QQuickMouseArea);
949 QPointF localPos = mapFromScene(event->windowPos());
951 QQuickWindow *c = window();
952 QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
953 bool stealThisEvent = d->stealMouse;
954 if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
955 QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
956 event->button(), event->buttons(), event->modifiers());
957 mouseEvent.setAccepted(false);
959 switch (event->type()) {
960 case QEvent::MouseMove:
961 mouseMoveEvent(&mouseEvent);
963 case QEvent::MouseButtonPress:
964 mousePressEvent(&mouseEvent);
966 case QEvent::MouseButtonRelease:
967 mouseReleaseEvent(&mouseEvent);
972 grabber = c->mouseGrabberItem();
973 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
976 return stealThisEvent;
978 if (event->type() == QEvent::MouseButtonRelease) {
980 d->pressed &= ~event->button();
981 emit pressedButtonsChanged();
983 // no other buttons are pressed
984 d->stealMouse = false;
985 if (c && c->mouseGrabberItem() == this)
988 emit pressedChanged();
991 emit hoveredChanged();
999 bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
1001 Q_D(QQuickMouseArea);
1003 (!d->enabled || !isVisible()
1004 #ifndef QT_NO_DRAGANDDROP
1005 || !d->drag || !d->drag->filterChildren()
1009 return QQuickItem::childMouseEventFilter(i, e);
1010 switch (e->type()) {
1011 case QEvent::MouseButtonPress:
1012 case QEvent::MouseMove:
1013 case QEvent::MouseButtonRelease:
1014 return sendMouseEvent(static_cast<QMouseEvent *>(e));
1019 return QQuickItem::childMouseEventFilter(i, e);
1022 void QQuickMouseArea::timerEvent(QTimerEvent *event)
1024 Q_D(QQuickMouseArea);
1025 if (event->timerId() == d->pressAndHoldTimer.timerId()) {
1026 d->pressAndHoldTimer.stop();
1027 #ifndef QT_NO_DRAGANDDROP
1028 bool dragged = d->drag && d->drag->active();
1030 bool dragged = false;
1032 if (d->pressed && dragged == false && d->hovered == true) {
1033 d->longPress = true;
1034 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
1035 me.setAccepted(d->isPressAndHoldConnected());
1036 emit pressAndHold(&me);
1037 if (!me.isAccepted())
1038 d->propagate(&me, QQuickMouseAreaPrivate::PressAndHold);
1039 if (!me.isAccepted()) // no one handled the long press - allow click
1040 d->longPress = false;
1045 void QQuickMouseArea::windowDeactivateEvent()
1048 QQuickItem::windowDeactivateEvent();
1051 void QQuickMouseArea::geometryChanged(const QRectF &newGeometry,
1052 const QRectF &oldGeometry)
1054 Q_D(QQuickMouseArea);
1055 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1057 if (d->lastScenePos.isNull)
1058 d->lastScenePos = mapToScene(d->lastPos);
1059 else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
1060 d->lastPos = mapFromScene(d->lastScenePos);
1063 void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
1065 Q_D(QQuickMouseArea);
1067 case ItemVisibleHasChanged:
1068 if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse())) {
1070 QPointF cursorPos = QGuiApplicationPrivate::lastCursorPosition;
1071 d->lastScenePos = d->window->mapFromGlobal(cursorPos.toPoint());
1072 d->lastPos = mapFromScene(d->lastScenePos);
1074 setHovered(!d->hovered);
1081 QQuickItem::itemChange(change, value);
1085 \qmlproperty bool QtQuick2::MouseArea::hoverEnabled
1086 This property holds whether hover events are handled.
1088 By default, mouse events are only handled in response to a button event, or when a button is
1089 pressed. Hover enables handling of all mouse events even when no mouse button is
1092 This property affects the containsMouse property and the onEntered, onExited and
1093 onPositionChanged signals.
1095 bool QQuickMouseArea::hoverEnabled() const
1097 return acceptHoverEvents();
1100 void QQuickMouseArea::setHoverEnabled(bool h)
1102 if (h == acceptHoverEvents())
1105 setAcceptHoverEvents(h);
1106 emit hoverEnabledChanged();
1111 \qmlproperty bool QtQuick2::MouseArea::containsMouse
1112 This property holds whether the mouse is currently inside the mouse area.
1114 \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
1115 In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
1117 bool QQuickMouseArea::hovered() const
1119 Q_D(const QQuickMouseArea);
1124 \qmlproperty bool QtQuick2::MouseArea::pressed
1125 This property holds whether any of the \l acceptedButtons are currently pressed.
1127 bool QQuickMouseArea::pressed() const
1129 Q_D(const QQuickMouseArea);
1133 void QQuickMouseArea::setHovered(bool h)
1135 Q_D(QQuickMouseArea);
1136 if (d->hovered != h) {
1138 emit hoveredChanged();
1139 d->hovered ? emit entered() : emit exited();
1144 \qmlproperty QtQuick2::Qt::MouseButtons MouseArea::acceptedButtons
1145 This property holds the mouse buttons that the mouse area reacts to.
1147 The available buttons are:
1154 To accept more than one button the flags can be combined with the
1158 MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
1161 The default value is \c Qt.LeftButton.
1163 Qt::MouseButtons QQuickMouseArea::acceptedButtons() const
1165 return acceptedMouseButtons();
1168 void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
1170 if (buttons != acceptedMouseButtons()) {
1171 setAcceptedMouseButtons(buttons);
1172 emit acceptedButtonsChanged();
1176 bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p)
1178 Q_D(QQuickMouseArea);
1180 #ifndef QT_NO_DRAGANDDROP
1181 bool dragged = d->drag && d->drag->active();
1183 bool dragged = false;
1185 bool wasPressed = d->pressed & button;
1186 bool isclick = wasPressed && p == false && dragged == false && d->hovered == true;
1187 Qt::MouseButtons oldPressed = d->pressed;
1189 if (wasPressed != p) {
1190 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
1192 d->pressed |= button;
1193 if (!d->doubleClick)
1195 me.setPosition(d->lastPos);
1196 emit mouseXChanged(&me);
1197 me.setPosition(d->lastPos);
1198 emit mouseYChanged(&me);
1200 emit pressedChanged();
1201 emit pressedButtonsChanged();
1203 d->pressed &= ~button;
1205 me.setPosition(d->lastPos);
1207 emit pressedChanged();
1208 emit pressedButtonsChanged();
1209 if (isclick && !d->longPress && !d->doubleClick){
1210 me.setAccepted(d->isClickConnected());
1212 if (!me.isAccepted())
1213 d->propagate(&me, QQuickMouseAreaPrivate::Click);
1217 return me.isAccepted();
1224 \qmlproperty QtQuick2::Qt::CursorShape MouseArea::cursorShape
1225 This property holds the cursor shape for this mouse area.
1226 Note that on platforms that do not display a mouse cursor this may have
1229 The available cursor shapes are:
1232 \li Qt.UpArrowCursor
1236 \li Qt.SizeVerCursor
1237 \li Qt.SizeHorCursor
1238 \li Qt.SizeBDiagCursor
1239 \li Qt.SizeFDiagCursor
1240 \li Qt.SizeAllCursor
1244 \li Qt.PointingHandCursor
1245 \li Qt.ForbiddenCursor
1246 \li Qt.WhatsThisCursor
1248 \li Qt.OpenHandCursor
1249 \li Qt.ClosedHandCursor
1250 \li Qt.DragCopyCursor
1251 \li Qt.DragMoveCursor
1252 \li Qt.DragLinkCursor
1255 In order to only set a mouse cursor shape for a region without reacting
1256 to mouse events set the acceptedButtons to none:
1259 MouseArea { cursorShape: Qt.IBeamCursor; acceptedButtons: Qt.NoButton }
1262 The default value is \c Qt.ArrowCursor.
1266 #ifndef QT_NO_CURSOR
1267 Qt::CursorShape QQuickMouseArea::cursorShape() const
1269 return cursor().shape();
1272 void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
1274 if (cursor().shape() == shape)
1279 emit cursorShapeChanged();
1285 \qmlproperty Item QtQuick2::MouseArea::drag.target
1286 \qmlproperty bool QtQuick2::MouseArea::drag.active
1287 \qmlproperty enumeration QtQuick2::MouseArea::drag.axis
1288 \qmlproperty real QtQuick2::MouseArea::drag.minimumX
1289 \qmlproperty real QtQuick2::MouseArea::drag.maximumX
1290 \qmlproperty real QtQuick2::MouseArea::drag.minimumY
1291 \qmlproperty real QtQuick2::MouseArea::drag.maximumY
1292 \qmlproperty bool QtQuick2::MouseArea::drag.filterChildren
1294 \c drag provides a convenient way to make an item draggable.
1297 \li \c drag.target specifies the id of the item to drag.
1298 \li \c drag.active specifies if the target item is currently being dragged.
1299 \li \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
1300 \li \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
1303 The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
1304 of the rectangle is reduced when it is dragged to the right.
1306 \snippet qml/mousearea/mousearea.qml drag
1308 \note Items cannot be dragged if they are anchored for the requested
1309 \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1310 for \c rect in the above example, it cannot be dragged along the X-axis.
1311 This can be avoided by settng the anchor value to \c undefined in
1312 an \l onPressed handler.
1314 If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
1315 enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1317 \snippet qml/mousearea/mouseareadragfilter.qml dragfilter
1321 #ifndef QT_NO_DRAGANDDROP
1322 QQuickDrag *QQuickMouseArea::drag()
1324 Q_D(QQuickMouseArea);
1326 d->drag = new QQuickDrag;
1331 QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1334 Q_D(QQuickMouseArea);
1336 if (!qmlVisualTouchDebugging())
1339 QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
1340 if (!rectangle) rectangle = d->sceneGraphContext()->createRectangleNode();
1342 rectangle->setRect(QRectF(0, 0, width(), height()));
1343 rectangle->setColor(QColor(255, 0, 0, 50));
1344 rectangle->update();