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 "qquickcanvas.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, canvas->rootItem(), scenePos, t);
270 bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *item,const QPointF &sp, PropagateType sig)
272 //Based off of QQuickCanvas::deliverInitialMousePressEvent
273 //But specific to MouseArea, so doesn't belong in canvas
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())
327 \qmlclass MouseArea QQuickMouseArea
328 \inqmlmodule QtQuick 2
329 \ingroup qtquick-input
330 \brief Enables simple mouse handling
333 A MouseArea is an invisible item that is typically used in conjunction with
334 a visible item in order to provide mouse handling for that item.
335 By effectively acting as a proxy, the logic for mouse handling can be
336 contained within a MouseArea item.
338 For basic key handling, see the \l{Keys}{Keys attached property}.
340 The \l enabled property is used to enable and disable mouse handling for
341 the proxied item. When disabled, the mouse area becomes transparent to
344 The \l pressed read-only property indicates whether or not the user is
345 holding down a mouse button over the mouse area. This property is often
346 used in bindings between properties in a user interface. The containsMouse
347 read-only property indicates the presence of the mouse cursor over the
348 mouse area but, by default, only when a mouse button is held down; see below
351 Information about the mouse position and button clicks are provided via
352 signals for which event handler properties are defined. The most commonly
353 used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
354 onPressed, onReleased and onPressAndHold. It's also possible to handle mouse
355 wheel events via the onWheel signal.
357 By default, MouseArea items only report mouse clicks and not changes to the
358 position of the mouse cursor. Setting the hoverEnabled property ensures that
359 handlers defined for onPositionChanged, onEntered and onExited are used and
360 that the containsMouse property is updated even when no mouse buttons are
363 \section1 Example Usage
365 \div {class="float-right"}
366 \inlineimage qml-mousearea-snippet.png
369 The following example uses a MouseArea in a \l Rectangle that changes
370 the \l Rectangle color to red when clicked:
372 \snippet qml/mousearea/mousearea.qml import
374 \snippet qml/mousearea/mousearea.qml intro
377 Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
378 additional information about the mouse event, such as the position, button,
379 and any key modifiers.
381 Here is an extension of the previous example that produces a different
382 color when the area is right clicked:
384 \snippet qml/mousearea/mousearea.qml intro-extended
386 Behavioral Change in QtQuick 2.0
388 From QtQuick 2.0, the signals clicked, doubleClicked and pressAndHold have a different interaction
389 model with regards to the delivery of events to multiple overlapping MouseAreas. These signals can now propagate
390 to all MouseAreas in the area, in painting order, until accepted by one of them. A signal is accepted by
391 default if there is a signal handler for it, use mouse.accepted = false; to ignore. This propagation
392 can send the signal to MouseAreas other than the one which accepted the press event, although that MouseArea
393 will receive the signal first. This behavior can be enabled by setting propagateComposedEvents to true.
395 \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example}
399 \qmlsignal QtQuick2::MouseArea::onEntered()
401 This handler is called when the mouse enters the mouse area.
403 By default the onEntered handler is only called while a button is
404 pressed. Setting hoverEnabled to true enables handling of
405 onEntered when no mouse button is pressed.
411 \qmlsignal QtQuick2::MouseArea::onExited()
413 This handler is called when the mouse exits the mouse area.
415 By default the onExited handler is only called while a button is
416 pressed. Setting hoverEnabled to true enables handling of
417 onExited when no mouse button is pressed.
419 The example below shows a fairly typical relationship between
420 two MouseAreas, with \c mouseArea2 on top of \c mouseArea1. Moving the
421 mouse into \c mouseArea2 from \c mouseArea1 will cause \c onExited
422 to be called for \c mouseArea1.
425 width: 400; height: 400
433 width: 100; height: 100
434 anchors.centerIn: parent
440 If instead you give the two mouseAreas a parent-child relationship,
441 moving the mouse into \c mouseArea2 from \c mouseArea1 will \b not
442 cause \c onExited to be called for \c mouseArea1. Instead, they will
443 both be considered to be simultaneously hovered.
449 \qmlsignal QtQuick2::MouseArea::onPositionChanged(MouseEvent mouse)
451 This handler is called when the mouse position changes.
453 The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
454 position, and any buttons currently pressed.
456 The \e accepted property of the MouseEvent parameter is ignored in this handler.
458 By default the onPositionChanged handler is only called while a button is
459 pressed. Setting hoverEnabled to true enables handling of
460 onPositionChanged when no mouse button is pressed.
464 \qmlsignal QtQuick2::MouseArea::onClicked(MouseEvent mouse)
466 This handler is called when there is a click. A click is defined as a press followed by a release,
467 both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
468 releasing is also considered a click).
470 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
471 position of the release of the click, and whether the click was held.
473 The \e accepted property of the MouseEvent parameter is ignored in this handler.
477 \qmlsignal QtQuick2::MouseArea::onPressed(MouseEvent mouse)
479 This handler is called when there is a press.
480 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
481 position and which button was pressed.
483 The \e accepted property of the MouseEvent parameter determines whether this MouseArea
484 will handle the press and all future mouse events until release. The default is to accept
485 the event and not allow other MouseArea beneath this one to handle the event. If \e accepted
486 is set to false, no further events will be sent to this MouseArea until the button is next
491 \qmlsignal QtQuick2::MouseArea::onReleased(MouseEvent mouse)
493 This handler is called when there is a release.
494 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
495 position of the release of the click, and whether the click was held.
497 The \e accepted property of the MouseEvent parameter is ignored in this handler.
503 \qmlsignal QtQuick2::MouseArea::onPressAndHold(MouseEvent mouse)
505 This handler is called when there is a long press (currently 800ms).
506 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
507 position of the press, and which button is pressed.
509 The \e accepted property of the MouseEvent parameter is ignored in this handler.
513 \qmlsignal QtQuick2::MouseArea::onDoubleClicked(MouseEvent mouse)
515 This handler is called when there is a double-click (a press followed by a release followed by a press).
516 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
517 position of the release of the click, and whether the click was held.
519 If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
520 in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
521 click; otherwise they are suppressed. The accepted property defaults to true.
525 \qmlsignal QtQuick2::MouseArea::onCanceled()
527 This handler is called when mouse events have been canceled, either because an event was not accepted, or
528 because another item stole the mouse event handling.
530 This signal is for advanced use: it is useful when there is more than one MouseArea
531 that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
532 case, if you execute some logic on the pressed signal and then start dragging, the
533 \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
534 the logic when the MouseArea has lost the mouse handling to the \l Flickable,
535 \c onCanceled should be used in addition to onReleased.
539 \qmlsignal QtQuick2::MouseArea::onWheel(WheelEvent wheel)
541 This handler is called in response to both mouse wheel and trackpad scroll gestures.
543 The \l {WheelEvent}{wheel} parameter provides information about the event, including the x and y
544 position, any buttons currently pressed, and information about the wheel movement, including
545 angleDelta and pixelDelta.
548 QQuickMouseArea::QQuickMouseArea(QQuickItem *parent)
549 : QQuickItem(*(new QQuickMouseAreaPrivate), parent)
551 Q_D(QQuickMouseArea);
555 QQuickMouseArea::~QQuickMouseArea()
560 \qmlproperty real QtQuick2::MouseArea::mouseX
561 \qmlproperty real QtQuick2::MouseArea::mouseY
562 These properties hold the coordinates of the mouse cursor.
564 If the hoverEnabled property is false then these properties will only be valid
565 while a button is pressed, and will remain valid as long as the button is held
566 down even if the mouse is moved outside the area.
568 By default, this property is false.
570 If hoverEnabled is true then these properties will be valid when:
572 \li no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
573 \li a button is pressed and held, even if it has since moved out of the area.
576 The coordinates are relative to the MouseArea.
578 qreal QQuickMouseArea::mouseX() const
580 Q_D(const QQuickMouseArea);
581 return d->lastPos.x();
584 qreal QQuickMouseArea::mouseY() const
586 Q_D(const QQuickMouseArea);
587 return d->lastPos.y();
591 \qmlproperty bool QtQuick2::MouseArea::enabled
592 This property holds whether the item accepts mouse events.
594 By default, this property is true.
596 bool QQuickMouseArea::isEnabled() const
598 Q_D(const QQuickMouseArea);
602 void QQuickMouseArea::setEnabled(bool a)
604 Q_D(QQuickMouseArea);
605 if (a != d->enabled) {
607 emit enabledChanged();
612 \qmlproperty bool QtQuick2::MouseArea::preventStealing
613 This property holds whether the mouse events may be stolen from this
616 If a MouseArea is placed within an item that filters child mouse
617 events, such as Flickable, the mouse
618 events may be stolen from the MouseArea if a gesture is recognized
619 by the parent item, e.g. a flick gesture. If preventStealing is
620 set to true, no item will steal the mouse events.
622 Note that setting preventStealing to true once an item has started
623 stealing events will have no effect until the next press event.
625 By default this property is false.
627 bool QQuickMouseArea::preventStealing() const
629 Q_D(const QQuickMouseArea);
630 return d->preventStealing;
633 void QQuickMouseArea::setPreventStealing(bool prevent)
635 Q_D(QQuickMouseArea);
636 if (prevent != d->preventStealing) {
637 d->preventStealing = prevent;
638 setKeepMouseGrab(d->preventStealing && d->enabled);
639 emit preventStealingChanged();
645 \qmlproperty bool QtQuick2::MouseArea::propagateComposedEvents
646 This property holds whether composed mouse events will automatically propagate to
649 MouseArea contains several composed events, clicked, doubleClicked,
650 and pressAndHold. These can propagate via a separate mechanism to basic
651 mouse events, like pressed, which they are composed of.
653 If propagateComposedEvents is set to true, then composed events will be automatically
654 propagated to other MouseAreas in the same location in the scene. They are propagated
655 in painting order until an item accepts them. Unlike pressed handling, events will
656 not be automatically accepted if no handler is present.
658 This property greatly simplifies the usecase of when you want to have overlapping MouseAreas
659 handling the composed events together. For example: if you want one MouseArea to handle click
660 signals and the other to handle pressAndHold, or if you want one MouseArea to handle click most
661 of the time, but pass it through when certain conditions are met.
663 By default this property is false.
665 bool QQuickMouseArea::propagateComposedEvents() const
667 Q_D(const QQuickMouseArea);
668 return d->propagateComposedEvents;
671 void QQuickMouseArea::setPropagateComposedEvents(bool prevent)
673 Q_D(QQuickMouseArea);
674 if (prevent != d->propagateComposedEvents) {
675 d->propagateComposedEvents = prevent;
676 setKeepMouseGrab(d->propagateComposedEvents && d->enabled);
677 emit propagateComposedEventsChanged();
682 \qmlproperty MouseButtons QtQuick2::MouseArea::pressedButtons
683 This property holds the mouse buttons currently pressed.
685 It contains a bitwise combination of:
692 The code below displays "right" when the right mouse buttons is pressed:
694 \snippet qml/mousearea/mousearea.qml mousebuttons
696 \note this property only handles buttons specified in \l acceptedButtons.
700 Qt::MouseButtons QQuickMouseArea::pressedButtons() const
702 Q_D(const QQuickMouseArea);
706 void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
708 Q_D(QQuickMouseArea);
710 d->stealMouse = d->preventStealing;
711 if (!d->enabled || !(event->button() & acceptedMouseButtons())) {
712 QQuickItem::mousePressEvent(event);
714 d->longPress = false;
716 #ifndef QT_NO_DRAGANDDROP
718 d->drag->setActive(false);
721 d->startScene = event->windowPos();
722 d->pressAndHoldTimer.start(PressAndHoldDelay, this);
723 setKeepMouseGrab(d->stealMouse);
724 event->setAccepted(setPressed(event->button(), true));
728 void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
730 Q_D(QQuickMouseArea);
731 if (!d->enabled && !d->pressed) {
732 QQuickItem::mouseMoveEvent(event);
738 // ### we should skip this if these signals aren't used
739 // ### can GV handle this for us?
740 const bool isInside = contains(d->lastPos);
741 if (d->hovered && !isInside)
743 else if (!d->hovered && isInside)
746 #ifndef QT_NO_DRAGANDDROP
747 if (d->drag && d->drag->target()) {
749 d->targetStartPos = d->drag->target()->parentItem()
750 ? d->drag->target()->parentItem()->mapToScene(d->drag->target()->pos())
751 : d->drag->target()->pos();
754 QPointF startLocalPos;
756 if (drag()->target()->parentItem()) {
757 startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
758 curLocalPos = drag()->target()->parentItem()->mapFromScene(event->windowPos());
760 startLocalPos = d->startScene;
761 curLocalPos = event->windowPos();
764 qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
765 qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
767 if (keepMouseGrab() && d->stealMouse && !d->drag->active())
768 d->drag->setActive(true);
770 QPointF startPos = d->drag->target()->parentItem()
771 ? d->drag->target()->parentItem()->mapFromScene(d->targetStartPos)
774 QPointF dragPos = d->drag->target()->pos();
776 bool dragX = drag()->axis() & QQuickDrag::XAxis;
777 bool dragY = drag()->axis() & QQuickDrag::YAxis;
779 if (dragX && d->drag->active()) {
780 qreal x = (curLocalPos.x() - startLocalPos.x()) + startPos.x();
781 if (x < drag()->xmin())
783 else if (x > drag()->xmax())
787 if (dragY && d->drag->active()) {
788 qreal y = (curLocalPos.y() - startLocalPos.y()) + startPos.y();
789 if (y < drag()->ymin())
791 else if (y > drag()->ymax())
795 d->drag->target()->setPos(dragPos);
797 if (!keepMouseGrab()) {
798 bool xDragged = QQuickCanvasPrivate::dragOverThreshold(dx, Qt::XAxis, event);
799 bool yDragged = QQuickCanvasPrivate::dragOverThreshold(dy, Qt::YAxis, event);
800 if ((!dragY && !yDragged && dragX && xDragged)
801 || (!dragX && !xDragged && dragY && yDragged)
802 || (dragX && dragY && (xDragged || yDragged))) {
803 setKeepMouseGrab(true);
804 d->stealMouse = true;
812 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
813 emit mouseXChanged(&me);
814 me.setPosition(d->lastPos);
815 emit mouseYChanged(&me);
816 me.setPosition(d->lastPos);
817 emit positionChanged(&me);
820 void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
822 Q_D(QQuickMouseArea);
823 d->stealMouse = false;
824 if (!d->enabled && !d->pressed) {
825 QQuickItem::mouseReleaseEvent(event);
828 setPressed(event->button(), false);
830 // no other buttons are pressed
831 #ifndef QT_NO_DRAGANDDROP
833 d->drag->setActive(false);
835 // If we don't accept hover, we need to reset containsMouse.
836 if (!acceptHoverEvents())
838 QQuickCanvas *c = canvas();
839 if (c && c->mouseGrabberItem() == this)
841 setKeepMouseGrab(false);
844 d->doubleClick = false;
847 void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
849 Q_D(QQuickMouseArea);
852 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
853 me.setAccepted(d->isDoubleClickConnected());
854 emit this->doubleClicked(&me);
855 if (!me.isAccepted())
856 d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
857 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
859 QQuickItem::mouseDoubleClickEvent(event);
862 void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
864 Q_D(QQuickMouseArea);
865 if (!d->enabled && !d->pressed) {
866 QQuickItem::hoverEnterEvent(event);
868 d->lastPos = event->posF();
869 d->lastModifiers = event->modifiers();
871 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
872 emit mouseXChanged(&me);
873 me.setPosition(d->lastPos);
874 emit mouseYChanged(&me);
875 me.setPosition(d->lastPos);
879 void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
881 Q_D(QQuickMouseArea);
882 if (!d->enabled && !d->pressed) {
883 QQuickItem::hoverMoveEvent(event);
885 d->lastPos = event->posF();
886 d->lastModifiers = event->modifiers();
887 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
888 emit mouseXChanged(&me);
889 me.setPosition(d->lastPos);
890 emit mouseYChanged(&me);
891 me.setPosition(d->lastPos);
892 emit positionChanged(&me);
896 void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
898 Q_D(QQuickMouseArea);
899 if (!d->enabled && !d->pressed)
900 QQuickItem::hoverLeaveEvent(event);
905 void QQuickMouseArea::wheelEvent(QWheelEvent *event)
907 Q_D(QQuickMouseArea);
909 QQuickItem::wheelEvent(event);
913 QQuickWheelEvent we(event->posF().x(), event->posF().y(), event->angleDelta(),
914 event->pixelDelta(), event->buttons(), event->modifiers());
915 we.setAccepted(d->isWheelConnected());
917 if (!we.isAccepted())
918 QQuickItem::wheelEvent(event);
921 void QQuickMouseArea::ungrabMouse()
923 Q_D(QQuickMouseArea);
925 // if our mouse grab has been removed (probably by Flickable), fix our
928 d->stealMouse = false;
929 setKeepMouseGrab(false);
931 emit pressedChanged();
932 emit pressedButtonsChanged();
935 emit hoveredChanged();
940 void QQuickMouseArea::mouseUngrabEvent()
945 bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
947 Q_D(QQuickMouseArea);
948 QPointF localPos = mapFromScene(event->windowPos());
950 QQuickCanvas *c = canvas();
951 QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
952 bool stealThisEvent = d->stealMouse;
953 if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
954 QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
955 event->button(), event->buttons(), event->modifiers());
956 mouseEvent.setAccepted(false);
958 switch (event->type()) {
959 case QEvent::MouseMove:
960 mouseMoveEvent(&mouseEvent);
962 case QEvent::MouseButtonPress:
963 mousePressEvent(&mouseEvent);
965 case QEvent::MouseButtonRelease:
966 mouseReleaseEvent(&mouseEvent);
971 grabber = c->mouseGrabberItem();
972 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
975 return stealThisEvent;
977 if (event->type() == QEvent::MouseButtonRelease) {
979 d->pressed &= ~event->button();
980 emit pressedButtonsChanged();
982 // no other buttons are pressed
983 d->stealMouse = false;
984 if (c && c->mouseGrabberItem() == this)
987 emit pressedChanged();
990 emit hoveredChanged();
998 bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
1000 Q_D(QQuickMouseArea);
1002 (!d->enabled || !isVisible()
1003 #ifndef QT_NO_DRAGANDDROP
1004 || !d->drag || !d->drag->filterChildren()
1008 return QQuickItem::childMouseEventFilter(i, e);
1009 switch (e->type()) {
1010 case QEvent::MouseButtonPress:
1011 case QEvent::MouseMove:
1012 case QEvent::MouseButtonRelease:
1013 return sendMouseEvent(static_cast<QMouseEvent *>(e));
1018 return QQuickItem::childMouseEventFilter(i, e);
1021 void QQuickMouseArea::timerEvent(QTimerEvent *event)
1023 Q_D(QQuickMouseArea);
1024 if (event->timerId() == d->pressAndHoldTimer.timerId()) {
1025 d->pressAndHoldTimer.stop();
1026 #ifndef QT_NO_DRAGANDDROP
1027 bool dragged = d->drag && d->drag->active();
1029 bool dragged = false;
1031 if (d->pressed && dragged == false && d->hovered == true) {
1032 d->longPress = true;
1033 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
1034 me.setAccepted(d->isPressAndHoldConnected());
1035 emit pressAndHold(&me);
1036 if (!me.isAccepted())
1037 d->propagate(&me, QQuickMouseAreaPrivate::PressAndHold);
1038 if (!me.isAccepted()) // no one handled the long press - allow click
1039 d->longPress = false;
1044 void QQuickMouseArea::windowDeactivateEvent()
1047 QQuickItem::windowDeactivateEvent();
1050 void QQuickMouseArea::geometryChanged(const QRectF &newGeometry,
1051 const QRectF &oldGeometry)
1053 Q_D(QQuickMouseArea);
1054 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1056 if (d->lastScenePos.isNull)
1057 d->lastScenePos = mapToScene(d->lastPos);
1058 else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
1059 d->lastPos = mapFromScene(d->lastScenePos);
1062 void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
1064 Q_D(QQuickMouseArea);
1066 case ItemVisibleHasChanged:
1067 if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse())) {
1069 QPointF cursorPos = QGuiApplicationPrivate::lastCursorPosition;
1070 d->lastScenePos = d->canvas->mapFromGlobal(cursorPos.toPoint());
1071 d->lastPos = mapFromScene(d->lastScenePos);
1073 setHovered(!d->hovered);
1080 QQuickItem::itemChange(change, value);
1084 \qmlproperty bool QtQuick2::MouseArea::hoverEnabled
1085 This property holds whether hover events are handled.
1087 By default, mouse events are only handled in response to a button event, or when a button is
1088 pressed. Hover enables handling of all mouse events even when no mouse button is
1091 This property affects the containsMouse property and the onEntered, onExited and
1092 onPositionChanged signals.
1094 bool QQuickMouseArea::hoverEnabled() const
1096 return acceptHoverEvents();
1099 void QQuickMouseArea::setHoverEnabled(bool h)
1101 if (h == acceptHoverEvents())
1104 setAcceptHoverEvents(h);
1105 emit hoverEnabledChanged();
1110 \qmlproperty bool QtQuick2::MouseArea::containsMouse
1111 This property holds whether the mouse is currently inside the mouse area.
1113 \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
1114 In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
1116 bool QQuickMouseArea::hovered() const
1118 Q_D(const QQuickMouseArea);
1123 \qmlproperty bool QtQuick2::MouseArea::pressed
1124 This property holds whether any of the \l acceptedButtons are currently pressed.
1126 bool QQuickMouseArea::pressed() const
1128 Q_D(const QQuickMouseArea);
1132 void QQuickMouseArea::setHovered(bool h)
1134 Q_D(QQuickMouseArea);
1135 if (d->hovered != h) {
1137 emit hoveredChanged();
1138 d->hovered ? emit entered() : emit exited();
1139 #ifndef QT_NO_CURSOR
1142 canvas()->setCursor(QCursor(*d->cursor));
1144 canvas()->unsetCursor();
1152 \qmlproperty QtQuick2::Qt::MouseButtons MouseArea::acceptedButtons
1153 This property holds the mouse buttons that the mouse area reacts to.
1155 The available buttons are:
1162 To accept more than one button the flags can be combined with the
1166 MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
1169 The default value is \c Qt.LeftButton.
1171 Qt::MouseButtons QQuickMouseArea::acceptedButtons() const
1173 return acceptedMouseButtons();
1176 void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
1178 if (buttons != acceptedMouseButtons()) {
1179 setAcceptedMouseButtons(buttons);
1180 emit acceptedButtonsChanged();
1184 bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p)
1186 Q_D(QQuickMouseArea);
1188 #ifndef QT_NO_DRAGANDDROP
1189 bool dragged = d->drag && d->drag->active();
1191 bool dragged = false;
1193 bool wasPressed = d->pressed & button;
1194 bool isclick = wasPressed && p == false && dragged == false && d->hovered == true;
1195 Qt::MouseButtons oldPressed = d->pressed;
1197 if (wasPressed != p) {
1198 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
1200 d->pressed |= button;
1201 if (!d->doubleClick)
1203 me.setPosition(d->lastPos);
1204 emit mouseXChanged(&me);
1205 me.setPosition(d->lastPos);
1206 emit mouseYChanged(&me);
1208 emit pressedChanged();
1209 emit pressedButtonsChanged();
1211 d->pressed &= ~button;
1213 me.setPosition(d->lastPos);
1215 emit pressedChanged();
1216 emit pressedButtonsChanged();
1217 if (isclick && !d->longPress && !d->doubleClick){
1218 me.setAccepted(d->isClickConnected());
1220 if (!me.isAccepted())
1221 d->propagate(&me, QQuickMouseAreaPrivate::Click);
1225 return me.isAccepted();
1232 \qmlproperty QtQuick2::Qt::CursorShape MouseArea::cursorShape
1233 This property holds the cursor shape for this mouse area.
1234 Note that on platforms that do not display a mouse cursor this may have
1237 The available cursor shapes are:
1240 \li Qt.UpArrowCursor
1244 \li Qt.SizeVerCursor
1245 \li Qt.SizeHorCursor
1246 \li Qt.SizeBDiagCursor
1247 \li Qt.SizeFDiagCursor
1248 \li Qt.SizeAllCursor
1252 \li Qt.PointingHandCursor
1253 \li Qt.ForbiddenCursor
1254 \li Qt.WhatsThisCursor
1256 \li Qt.OpenHandCursor
1257 \li Qt.ClosedHandCursor
1258 \li Qt.DragCopyCursor
1259 \li Qt.DragMoveCursor
1260 \li Qt.DragLinkCursor
1263 In order to only set a mouse cursor shape for a region without reacting
1264 to mouse events set the acceptedButtons to none:
1267 MouseArea { cursorShape: Qt.IBeamCursor; acceptedButtons: Qt.NoButton }
1270 The default value is \c Qt.ArrowCursor.
1274 #ifndef QT_NO_CURSOR
1275 Qt::CursorShape QQuickMouseArea::cursorShape() const
1277 Q_D(const QQuickMouseArea);
1279 return d->cursor->shape();
1280 return Qt::ArrowCursor;
1283 void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
1285 Q_D(QQuickMouseArea);
1286 setHoverEnabled(true);
1288 d->cursor = new QCursor(shape);
1293 \qmlproperty Item QtQuick2::MouseArea::drag.target
1294 \qmlproperty bool QtQuick2::MouseArea::drag.active
1295 \qmlproperty enumeration QtQuick2::MouseArea::drag.axis
1296 \qmlproperty real QtQuick2::MouseArea::drag.minimumX
1297 \qmlproperty real QtQuick2::MouseArea::drag.maximumX
1298 \qmlproperty real QtQuick2::MouseArea::drag.minimumY
1299 \qmlproperty real QtQuick2::MouseArea::drag.maximumY
1300 \qmlproperty bool QtQuick2::MouseArea::drag.filterChildren
1302 \c drag provides a convenient way to make an item draggable.
1305 \li \c drag.target specifies the id of the item to drag.
1306 \li \c drag.active specifies if the target item is currently being dragged.
1307 \li \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
1308 \li \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
1311 The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
1312 of the rectangle is reduced when it is dragged to the right.
1314 \snippet qml/mousearea/mousearea.qml drag
1316 \note Items cannot be dragged if they are anchored for the requested
1317 \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1318 for \c rect in the above example, it cannot be dragged along the X-axis.
1319 This can be avoided by settng the anchor value to \c undefined in
1320 an \l onPressed handler.
1322 If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
1323 enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1325 \snippet qml/mousearea/mouseareadragfilter.qml dragfilter
1329 #ifndef QT_NO_DRAGANDDROP
1330 QQuickDrag *QQuickMouseArea::drag()
1332 Q_D(QQuickMouseArea);
1334 d->drag = new QQuickDrag;
1339 QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1342 Q_D(QQuickMouseArea);
1344 if (!qmlVisualTouchDebugging())
1347 QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
1348 if (!rectangle) rectangle = d->sceneGraphContext()->createRectangleNode();
1350 rectangle->setRect(QRectF(0, 0, width(), height()));
1351 rectangle->setColor(QColor(255, 0, 0, 50));
1352 rectangle->update();