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 <QtGui/qevent.h>
49 #include <QtGui/qguiapplication.h>
50 #include <QtGui/qstylehints.h>
56 DEFINE_BOOL_CONFIG_OPTION(qmlVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
58 static const int PressAndHoldDelay = 800;
60 QQuickDrag::QQuickDrag(QObject *parent)
61 : QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX),
62 _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false)
66 QQuickDrag::~QQuickDrag()
70 QQuickItem *QQuickDrag::target() const
75 void QQuickDrag::setTarget(QQuickItem *t)
83 void QQuickDrag::resetTarget()
91 QQuickDrag::Axis QQuickDrag::axis() const
96 void QQuickDrag::setAxis(QQuickDrag::Axis a)
104 qreal QQuickDrag::xmin() const
109 void QQuickDrag::setXmin(qreal m)
114 emit minimumXChanged();
117 qreal QQuickDrag::xmax() const
122 void QQuickDrag::setXmax(qreal m)
127 emit maximumXChanged();
130 qreal QQuickDrag::ymin() const
135 void QQuickDrag::setYmin(qreal m)
140 emit minimumYChanged();
143 qreal QQuickDrag::ymax() const
148 void QQuickDrag::setYmax(qreal m)
153 emit maximumYChanged();
156 bool QQuickDrag::active() const
161 void QQuickDrag::setActive(bool drag)
166 emit activeChanged();
169 bool QQuickDrag::filterChildren() const
171 return _filterChildren;
174 void QQuickDrag::setFilterChildren(bool filter)
176 if (_filterChildren == filter)
178 _filterChildren = filter;
179 emit filterChildrenChanged();
182 QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj)
184 return new QQuickDragAttached(obj);
187 QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
188 : absorb(true), hovered(false), pressed(false), longPress(false),
189 moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
190 propagateComposedEvents(false), drag(0)
194 QQuickMouseAreaPrivate::~QQuickMouseAreaPrivate()
199 void QQuickMouseAreaPrivate::init()
201 Q_Q(QQuickMouseArea);
202 q->setAcceptedMouseButtons(Qt::LeftButton);
203 q->setFiltersChildMouseEvents(true);
204 if (qmlVisualTouchDebugging()) {
205 q->setFlag(QQuickItem::ItemHasContents);
209 void QQuickMouseAreaPrivate::saveEvent(QMouseEvent *event)
211 lastPos = event->localPos();
212 lastScenePos = event->windowPos();
213 lastButton = event->button();
214 lastButtons = event->buttons();
215 lastModifiers = event->modifiers();
218 bool QQuickMouseAreaPrivate::isPressAndHoldConnected()
220 Q_Q(QQuickMouseArea);
221 static int idx = QObjectPrivate::get(q)->signalIndex("pressAndHold(QQuickMouseEvent*)");
222 return QObjectPrivate::get(q)->isSignalConnected(idx);
225 bool QQuickMouseAreaPrivate::isDoubleClickConnected()
227 Q_Q(QQuickMouseArea);
228 static int idx = QObjectPrivate::get(q)->signalIndex("doubleClicked(QQuickMouseEvent*)");
229 return QObjectPrivate::get(q)->isSignalConnected(idx);
232 bool QQuickMouseAreaPrivate::isClickConnected()
234 Q_Q(QQuickMouseArea);
235 static int idx = QObjectPrivate::get(q)->signalIndex("clicked(QQuickMouseEvent*)");
236 return QObjectPrivate::get(q)->isSignalConnected(idx);
239 bool QQuickMouseAreaPrivate::isWheelConnected()
241 Q_Q(QQuickMouseArea);
242 static int idx = QObjectPrivate::get(q)->signalIndex("wheel(QQuickWheelEvent*)");
243 return QObjectPrivate::get(q)->isSignalConnected(idx);
246 void QQuickMouseAreaPrivate::propagate(QQuickMouseEvent* event, PropagateType t)
248 Q_Q(QQuickMouseArea);
249 if (!propagateComposedEvents)
251 QPointF scenePos = q->mapToScene(QPointF(event->x(), event->y()));
252 propagateHelper(event, canvas->rootItem(), scenePos, t);
255 bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *item,const QPointF &sp, PropagateType sig)
257 //Based off of QQuickCanvas::deliverInitialMousePressEvent
258 //But specific to MouseArea, so doesn't belong in canvas
259 Q_Q(const QQuickMouseArea);
260 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
261 if (itemPrivate->opacity() == 0.0)
264 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
265 QPointF p = item->mapFromScene(sp);
266 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
270 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
271 for (int ii = children.count() - 1; ii >= 0; --ii) {
272 QQuickItem *child = children.at(ii);
273 if (!child->isVisible() || !child->isEnabled())
275 if (propagateHelper(ev, child, sp, sig))
279 QQuickMouseArea* ma = qobject_cast<QQuickMouseArea*>(item);
280 if (ma && ma != q && itemPrivate->acceptedMouseButtons() & ev->button()) {
283 if (!ma->d_func()->isClickConnected())
287 if (!ma->d_func()->isDoubleClickConnected())
291 if (!ma->d_func()->isPressAndHoldConnected())
295 QPointF p = item->mapFromScene(sp);
296 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
299 ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
301 case Click: emit ma->clicked(ev); break;
302 case DoubleClick: emit ma->doubleClicked(ev); break;
303 case PressAndHold: emit ma->pressAndHold(ev); break;
305 if (ev->isAccepted())
314 \qmlclass MouseArea QQuickMouseArea
315 \inqmlmodule QtQuick 2
316 \ingroup qml-basic-interaction-elements
317 \brief The MouseArea item enables simple mouse handling.
320 A MouseArea is an invisible item that is typically used in conjunction with
321 a visible item in order to provide mouse handling for that item.
322 By effectively acting as a proxy, the logic for mouse handling can be
323 contained within a MouseArea item.
325 For basic key handling, see the \l{Keys}{Keys attached property}.
327 The \l enabled property is used to enable and disable mouse handling for
328 the proxied item. When disabled, the mouse area becomes transparent to
331 The \l pressed read-only property indicates whether or not the user is
332 holding down a mouse button over the mouse area. This property is often
333 used in bindings between properties in a user interface. The containsMouse
334 read-only property indicates the presence of the mouse cursor over the
335 mouse area but, by default, only when a mouse button is held down; see below
338 Information about the mouse position and button clicks are provided via
339 signals for which event handler properties are defined. The most commonly
340 used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
341 onPressed, onReleased and onPressAndHold. It's also possible to handle mouse
342 wheel events via the onWheel signal.
344 By default, MouseArea items only report mouse clicks and not changes to the
345 position of the mouse cursor. Setting the hoverEnabled property ensures that
346 handlers defined for onPositionChanged, onEntered and onExited are used and
347 that the containsMouse property is updated even when no mouse buttons are
350 \section1 Example Usage
352 \div {class="float-right"}
353 \inlineimage qml-mousearea-snippet.png
356 The following example uses a MouseArea in a \l Rectangle that changes
357 the \l Rectangle color to red when clicked:
359 \snippet doc/src/snippets/qml/mousearea/mousearea.qml import
361 \snippet doc/src/snippets/qml/mousearea/mousearea.qml intro
364 Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
365 additional information about the mouse event, such as the position, button,
366 and any key modifiers.
368 Here is an extension of the previous example that produces a different
369 color when the area is right clicked:
371 \snippet doc/src/snippets/qml/mousearea/mousearea.qml intro-extended
373 Behavioral Change in QtQuick 2.0
375 From QtQuick 2.0, the signals clicked, doubleClicked and pressAndHold have a different interaction
376 model with regards to the delivery of events to multiple overlapping MouseAreas. These signals can now propagate
377 to all MouseAreas in the area, in painting order, until accepted by one of them. A signal is accepted by
378 default if there is a signal handler for it, use mouse.accepted = false; to ignore. This propagation
379 can send the signal to MouseAreas other than the one which accepted the press event, although that MouseArea
380 will receive the signal first. This behavior can be enabled by setting propagateComposedEvents to true.
382 \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example}
386 \qmlsignal QtQuick2::MouseArea::onEntered()
388 This handler is called when the mouse enters the mouse area.
390 By default the onEntered handler is only called while a button is
391 pressed. Setting hoverEnabled to true enables handling of
392 onEntered when no mouse button is pressed.
398 \qmlsignal QtQuick2::MouseArea::onExited()
400 This handler is called when the mouse exits the mouse area.
402 By default the onExited handler is only called while a button is
403 pressed. Setting hoverEnabled to true enables handling of
404 onExited when no mouse button is pressed.
406 The example below shows a fairly typical relationship between
407 two MouseAreas, with \c mouseArea2 on top of \c mouseArea1. Moving the
408 mouse into \c mouseArea2 from \c mouseArea1 will cause \c onExited
409 to be called for \c mouseArea1.
412 width: 400; height: 400
420 width: 100; height: 100
421 anchors.centerIn: parent
427 If instead you give the two mouseAreas a parent-child relationship,
428 moving the mouse into \c mouseArea2 from \c mouseArea1 will \b not
429 cause \c onExited to be called for \c mouseArea1. Instead, they will
430 both be considered to be simultaneously hovered.
436 \qmlsignal QtQuick2::MouseArea::onPositionChanged(MouseEvent mouse)
438 This handler is called when the mouse position changes.
440 The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
441 position, and any buttons currently pressed.
443 The \e accepted property of the MouseEvent parameter is ignored in this handler.
445 By default the onPositionChanged handler is only called while a button is
446 pressed. Setting hoverEnabled to true enables handling of
447 onPositionChanged when no mouse button is pressed.
451 \qmlsignal QtQuick2::MouseArea::onClicked(MouseEvent mouse)
453 This handler is called when there is a click. A click is defined as a press followed by a release,
454 both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
455 releasing is also considered a click).
457 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
458 position of the release of the click, and whether the click was held.
460 The \e accepted property of the MouseEvent parameter is ignored in this handler.
464 \qmlsignal QtQuick2::MouseArea::onPressed(MouseEvent mouse)
466 This handler is called when there is a press.
467 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
468 position and which button was pressed.
470 The \e accepted property of the MouseEvent parameter determines whether this MouseArea
471 will handle the press and all future mouse events until release. The default is to accept
472 the event and not allow other MouseArea beneath this one to handle the event. If \e accepted
473 is set to false, no further events will be sent to this MouseArea until the button is next
478 \qmlsignal QtQuick2::MouseArea::onReleased(MouseEvent mouse)
480 This handler is called when there is a release.
481 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
482 position of the release of the click, and whether the click was held.
484 The \e accepted property of the MouseEvent parameter is ignored in this handler.
490 \qmlsignal QtQuick2::MouseArea::onPressAndHold(MouseEvent mouse)
492 This handler is called when there is a long press (currently 800ms).
493 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
494 position of the press, and which button is pressed.
496 The \e accepted property of the MouseEvent parameter is ignored in this handler.
500 \qmlsignal QtQuick2::MouseArea::onDoubleClicked(MouseEvent mouse)
502 This handler is called when there is a double-click (a press followed by a release followed by a press).
503 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
504 position of the release of the click, and whether the click was held.
506 If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
507 in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
508 click; otherwise they are suppressed. The accepted property defaults to true.
512 \qmlsignal QtQuick2::MouseArea::onCanceled()
514 This handler is called when mouse events have been canceled, either because an event was not accepted, or
515 because another element stole the mouse event handling.
517 This signal is for advanced use: it is useful when there is more than one MouseArea
518 that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
519 case, if you execute some logic on the pressed signal and then start dragging, the
520 \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
521 the logic when the MouseArea has lost the mouse handling to the \l Flickable,
522 \c onCanceled should be used in addition to onReleased.
526 \qmlsignal QtQuick2::MouseArea::onWheel(WheelEvent mouse)
528 This handler is called in response to both mouse wheel and trackpad scroll gestures.
530 The \l {WheelEvent}{wheel} parameter provides information about the event, including the x and y
531 position, any buttons currently pressed, and information about the wheel movement, including
532 angleDelta and pixelDelta.
535 QQuickMouseArea::QQuickMouseArea(QQuickItem *parent)
536 : QQuickItem(*(new QQuickMouseAreaPrivate), parent)
538 Q_D(QQuickMouseArea);
542 QQuickMouseArea::~QQuickMouseArea()
547 \qmlproperty real QtQuick2::MouseArea::mouseX
548 \qmlproperty real QtQuick2::MouseArea::mouseY
549 These properties hold the coordinates of the mouse cursor.
551 If the hoverEnabled property is false then these properties will only be valid
552 while a button is pressed, and will remain valid as long as the button is held
553 down even if the mouse is moved outside the area.
555 By default, this property is false.
557 If hoverEnabled is true then these properties will be valid when:
559 \i no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
560 \i a button is pressed and held, even if it has since moved out of the area.
563 The coordinates are relative to the MouseArea.
565 qreal QQuickMouseArea::mouseX() const
567 Q_D(const QQuickMouseArea);
568 return d->lastPos.x();
571 qreal QQuickMouseArea::mouseY() const
573 Q_D(const QQuickMouseArea);
574 return d->lastPos.y();
578 \qmlproperty bool QtQuick2::MouseArea::enabled
579 This property holds whether the item accepts mouse events.
581 By default, this property is true.
583 bool QQuickMouseArea::isEnabled() const
585 Q_D(const QQuickMouseArea);
589 void QQuickMouseArea::setEnabled(bool a)
591 Q_D(QQuickMouseArea);
592 if (a != d->absorb) {
594 emit enabledChanged();
599 \qmlproperty bool QtQuick2::MouseArea::preventStealing
600 This property holds whether the mouse events may be stolen from this
603 If a MouseArea is placed within an item that filters child mouse
604 events, such as Flickable, the mouse
605 events may be stolen from the MouseArea if a gesture is recognized
606 by the parent element, e.g. a flick gesture. If preventStealing is
607 set to true, no element will steal the mouse events.
609 Note that setting preventStealing to true once an element has started
610 stealing events will have no effect until the next press event.
612 By default this property is false.
614 bool QQuickMouseArea::preventStealing() const
616 Q_D(const QQuickMouseArea);
617 return d->preventStealing;
620 void QQuickMouseArea::setPreventStealing(bool prevent)
622 Q_D(QQuickMouseArea);
623 if (prevent != d->preventStealing) {
624 d->preventStealing = prevent;
625 setKeepMouseGrab(d->preventStealing && d->absorb);
626 emit preventStealingChanged();
632 \qmlproperty bool QtQuick2::MouseArea::propagateComposedEvents
633 This property holds whether composed mouse events will automatically propagate to
636 MouseArea contains several composed events, clicked, doubleClicked,
637 and pressAndHold. These can propagate via a separate mechanism to basic
638 mouse events, like pressed, which they are composed of.
640 If propagateComposedEvents is set to true, then composed events will be automatically
641 propagated to other MouseAreas in the same location in the scene. They are propagated
642 in painting order until an item accepts them. Unlike pressed handling, events will
643 not be automatically accepted if no handler is present.
645 This property greatly simplifies the usecase of when you want to have overlapping MouseAreas
646 handling the composed events together. For example: if you want one MouseArea to handle click
647 signals and the other to handle pressAndHold, or if you want one MouseArea to handle click most
648 of the time, but pass it through when certain conditions are met.
650 By default this property is false.
652 bool QQuickMouseArea::propagateComposedEvents() const
654 Q_D(const QQuickMouseArea);
655 return d->propagateComposedEvents;
658 void QQuickMouseArea::setPropagateComposedEvents(bool prevent)
660 Q_D(QQuickMouseArea);
661 if (prevent != d->propagateComposedEvents) {
662 d->propagateComposedEvents = prevent;
663 setKeepMouseGrab(d->propagateComposedEvents && d->absorb);
664 emit propagateComposedEventsChanged();
669 \qmlproperty MouseButtons QtQuick2::MouseArea::pressedButtons
670 This property holds the mouse buttons currently pressed.
672 It contains a bitwise combination of:
679 The code below displays "right" when the right mouse buttons is pressed:
681 \snippet doc/src/snippets/qml/mousearea/mousearea.qml mousebuttons
685 Qt::MouseButtons QQuickMouseArea::pressedButtons() const
687 Q_D(const QQuickMouseArea);
688 return d->lastButtons;
691 void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
693 Q_D(QQuickMouseArea);
695 d->stealMouse = d->preventStealing;
697 QQuickItem::mousePressEvent(event);
699 d->longPress = false;
702 d->dragX = drag()->axis() & QQuickDrag::XAxis;
703 d->dragY = drag()->axis() & QQuickDrag::YAxis;
706 d->drag->setActive(false);
708 d->startScene = event->windowPos();
709 d->pressAndHoldTimer.start(PressAndHoldDelay, this);
710 setKeepMouseGrab(d->stealMouse);
711 event->setAccepted(setPressed(true));
716 void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
718 Q_D(QQuickMouseArea);
719 if (!d->absorb && !d->pressed) {
720 QQuickItem::mouseMoveEvent(event);
726 // ### we should skip this if these signals aren't used
727 // ### can GV handle this for us?
728 bool contains = boundingRect().contains(d->lastPos);
729 if (d->hovered && !contains)
731 else if (!d->hovered && contains)
734 if (d->drag && d->drag->target()) {
736 d->targetStartPos = d->drag->target()->parentItem()
737 ? d->drag->target()->parentItem()->mapToScene(d->drag->target()->pos())
738 : d->drag->target()->pos();
741 QPointF startLocalPos;
743 if (drag()->target()->parentItem()) {
744 startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
745 curLocalPos = drag()->target()->parentItem()->mapFromScene(event->windowPos());
747 startLocalPos = d->startScene;
748 curLocalPos = event->windowPos();
751 const int dragThreshold = qApp->styleHints()->startDragDistance();
752 qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
753 qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
755 if (keepMouseGrab() && d->stealMouse && !d->drag->active())
756 d->drag->setActive(true);
758 QPointF startPos = d->drag->target()->parentItem()
759 ? d->drag->target()->parentItem()->mapFromScene(d->targetStartPos)
762 QPointF dragPos = d->drag->target()->pos();
764 if (d->dragX && d->drag->active()) {
765 qreal x = (curLocalPos.x() - startLocalPos.x()) + startPos.x();
766 if (x < drag()->xmin())
768 else if (x > drag()->xmax())
772 if (d->dragY && d->drag->active()) {
773 qreal y = (curLocalPos.y() - startLocalPos.y()) + startPos.y();
774 if (y < drag()->ymin())
776 else if (y > drag()->ymax())
780 d->drag->target()->setPos(dragPos);
782 if (!keepMouseGrab()) {
783 if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
784 || (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
785 || (d->dragX && d->dragY && (dx > dragThreshold || dy > dragThreshold))) {
786 setKeepMouseGrab(true);
787 d->stealMouse = true;
793 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
794 emit mouseXChanged(&me);
795 me.setPosition(d->lastPos);
796 emit mouseYChanged(&me);
797 me.setPosition(d->lastPos);
798 emit positionChanged(&me);
801 void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
803 Q_D(QQuickMouseArea);
804 d->stealMouse = false;
805 if (!d->absorb && !d->pressed) {
806 QQuickItem::mouseReleaseEvent(event);
811 d->drag->setActive(false);
812 // If we don't accept hover, we need to reset containsMouse.
813 if (!acceptHoverEvents())
815 QQuickCanvas *c = canvas();
816 if (c && c->mouseGrabberItem() == this)
818 setKeepMouseGrab(false);
821 d->doubleClick = false;
824 void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
826 Q_D(QQuickMouseArea);
829 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
830 me.setAccepted(d->isDoubleClickConnected());
831 emit this->doubleClicked(&me);
832 if (!me.isAccepted())
833 d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
834 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
836 QQuickItem::mouseDoubleClickEvent(event);
839 void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
841 Q_D(QQuickMouseArea);
842 if (!d->absorb && !d->pressed) {
843 QQuickItem::hoverEnterEvent(event);
845 d->lastPos = event->posF();
846 d->lastModifiers = event->modifiers();
848 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
849 emit mouseXChanged(&me);
850 me.setPosition(d->lastPos);
851 emit mouseYChanged(&me);
852 me.setPosition(d->lastPos);
856 void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
858 Q_D(QQuickMouseArea);
859 if (!d->absorb && !d->pressed) {
860 QQuickItem::hoverMoveEvent(event);
862 d->lastPos = event->posF();
863 d->lastModifiers = event->modifiers();
864 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
865 emit mouseXChanged(&me);
866 me.setPosition(d->lastPos);
867 emit mouseYChanged(&me);
868 me.setPosition(d->lastPos);
869 emit positionChanged(&me);
873 void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
875 Q_D(QQuickMouseArea);
876 if (!d->absorb && !d->pressed)
877 QQuickItem::hoverLeaveEvent(event);
882 void QQuickMouseArea::wheelEvent(QWheelEvent *event)
884 Q_D(QQuickMouseArea);
886 QQuickItem::wheelEvent(event);
890 QQuickWheelEvent we(event->posF().x(), event->posF().y(), event->angleDelta(),
891 event->pixelDelta(), event->buttons(), event->modifiers());
892 we.setAccepted(d->isWheelConnected());
894 if (!we.isAccepted())
895 QQuickItem::wheelEvent(event);
898 void QQuickMouseArea::ungrabMouse()
900 Q_D(QQuickMouseArea);
902 // if our mouse grab has been removed (probably by Flickable), fix our
905 d->stealMouse = false;
906 setKeepMouseGrab(false);
908 emit pressedChanged();
911 emit hoveredChanged();
916 void QQuickMouseArea::mouseUngrabEvent()
921 bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
923 Q_D(QQuickMouseArea);
924 QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
926 QQuickCanvas *c = canvas();
927 QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
928 bool stealThisEvent = d->stealMouse;
929 if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab())) {
930 QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
931 event->button(), event->buttons(), event->modifiers());
932 mouseEvent.setAccepted(false);
934 switch (event->type()) {
935 case QEvent::MouseMove:
936 mouseMoveEvent(&mouseEvent);
938 case QEvent::MouseButtonPress:
939 mousePressEvent(&mouseEvent);
941 case QEvent::MouseButtonRelease:
942 mouseReleaseEvent(&mouseEvent);
947 grabber = c->mouseGrabberItem();
948 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
951 return stealThisEvent;
953 if (event->type() == QEvent::MouseButtonRelease) {
956 d->stealMouse = false;
957 if (c && c->mouseGrabberItem() == this)
960 emit pressedChanged();
963 emit hoveredChanged();
970 bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
972 Q_D(QQuickMouseArea);
973 if (!d->pressed && (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren()))
974 return QQuickItem::childMouseEventFilter(i, e);
976 case QEvent::MouseButtonPress:
977 case QEvent::MouseMove:
978 case QEvent::MouseButtonRelease:
979 return sendMouseEvent(static_cast<QMouseEvent *>(e));
984 return QQuickItem::childMouseEventFilter(i, e);
987 void QQuickMouseArea::timerEvent(QTimerEvent *event)
989 Q_D(QQuickMouseArea);
990 if (event->timerId() == d->pressAndHoldTimer.timerId()) {
991 d->pressAndHoldTimer.stop();
992 bool dragged = d->drag && d->drag->active();
993 if (d->pressed && dragged == false && d->hovered == true) {
995 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
996 me.setAccepted(d->isPressAndHoldConnected());
997 emit pressAndHold(&me);
998 if (!me.isAccepted())
999 d->propagate(&me, QQuickMouseAreaPrivate::PressAndHold);
1000 if (!me.isAccepted()) // no one handled the long press - allow click
1001 d->longPress = false;
1006 void QQuickMouseArea::windowDeactivateEvent()
1009 QQuickItem::windowDeactivateEvent();
1012 void QQuickMouseArea::geometryChanged(const QRectF &newGeometry,
1013 const QRectF &oldGeometry)
1015 Q_D(QQuickMouseArea);
1016 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1018 if (d->lastScenePos.isNull)
1019 d->lastScenePos = mapToScene(d->lastPos);
1020 else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
1021 d->lastPos = mapFromScene(d->lastScenePos);
1024 void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
1026 Q_D(QQuickMouseArea);
1028 case ItemVisibleHasChanged:
1029 if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
1030 setHovered(!d->hovered);
1036 QQuickItem::itemChange(change, value);
1040 \qmlproperty bool QtQuick2::MouseArea::hoverEnabled
1041 This property holds whether hover events are handled.
1043 By default, mouse events are only handled in response to a button event, or when a button is
1044 pressed. Hover enables handling of all mouse events even when no mouse button is
1047 This property affects the containsMouse property and the onEntered, onExited and
1048 onPositionChanged signals.
1050 bool QQuickMouseArea::hoverEnabled() const
1052 return acceptHoverEvents();
1055 void QQuickMouseArea::setHoverEnabled(bool h)
1057 if (h == acceptHoverEvents())
1060 setAcceptHoverEvents(h);
1061 emit hoverEnabledChanged();
1066 \qmlproperty bool QtQuick2::MouseArea::containsMouse
1067 This property holds whether the mouse is currently inside the mouse area.
1069 \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
1070 In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
1072 bool QQuickMouseArea::hovered() const
1074 Q_D(const QQuickMouseArea);
1079 \qmlproperty bool QtQuick2::MouseArea::pressed
1080 This property holds whether the mouse area is currently pressed.
1082 bool QQuickMouseArea::pressed() const
1084 Q_D(const QQuickMouseArea);
1088 void QQuickMouseArea::setHovered(bool h)
1090 Q_D(QQuickMouseArea);
1091 if (d->hovered != h) {
1093 emit hoveredChanged();
1094 d->hovered ? emit entered() : emit exited();
1098 \qmlproperty QtQuick2::Qt::MouseButtons MouseArea::acceptedButtons
1099 This property holds the mouse buttons that the mouse area reacts to.
1101 The available buttons are:
1108 To accept more than one button the flags can be combined with the
1112 MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
1115 The default value is \c Qt.LeftButton.
1117 Qt::MouseButtons QQuickMouseArea::acceptedButtons() const
1119 return acceptedMouseButtons();
1122 void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
1124 if (buttons != acceptedMouseButtons()) {
1125 setAcceptedMouseButtons(buttons);
1126 emit acceptedButtonsChanged();
1130 bool QQuickMouseArea::setPressed(bool p)
1132 Q_D(QQuickMouseArea);
1133 bool dragged = d->drag && d->drag->active();
1134 bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
1136 if (d->pressed != p) {
1138 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
1140 if (!d->doubleClick)
1142 me.setPosition(d->lastPos);
1143 emit mouseXChanged(&me);
1144 me.setPosition(d->lastPos);
1145 emit mouseYChanged(&me);
1146 emit pressedChanged();
1149 me.setPosition(d->lastPos);
1150 emit pressedChanged();
1151 if (isclick && !d->longPress && !d->doubleClick){
1152 me.setAccepted(d->isClickConnected());
1154 if (!me.isAccepted())
1155 d->propagate(&me, QQuickMouseAreaPrivate::Click);
1159 return me.isAccepted();
1165 \qmlproperty Item QtQuick2::MouseArea::drag.target
1166 \qmlproperty bool QtQuick2::MouseArea::drag.active
1167 \qmlproperty enumeration QtQuick2::MouseArea::drag.axis
1168 \qmlproperty real QtQuick2::MouseArea::drag.minimumX
1169 \qmlproperty real QtQuick2::MouseArea::drag.maximumX
1170 \qmlproperty real QtQuick2::MouseArea::drag.minimumY
1171 \qmlproperty real QtQuick2::MouseArea::drag.maximumY
1172 \qmlproperty bool QtQuick2::MouseArea::drag.filterChildren
1174 \c drag provides a convenient way to make an item draggable.
1177 \i \c drag.target specifies the id of the item to drag.
1178 \i \c drag.active specifies if the target item is currently being dragged.
1179 \i \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
1180 \i \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
1183 The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
1184 of the rectangle is reduced when it is dragged to the right.
1186 \snippet doc/src/snippets/qml/mousearea/mousearea.qml drag
1188 \note Items cannot be dragged if they are anchored for the requested
1189 \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1190 for \c rect in the above example, it cannot be dragged along the X-axis.
1191 This can be avoided by settng the anchor value to \c undefined in
1192 an \l onPressed handler.
1194 If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
1195 enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1197 \snippet doc/src/snippets/qml/mousearea/mouseareadragfilter.qml dragfilter
1201 QQuickDrag *QQuickMouseArea::drag()
1203 Q_D(QQuickMouseArea);
1205 d->drag = new QQuickDrag;
1209 QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1212 Q_D(QQuickMouseArea);
1214 if (!qmlVisualTouchDebugging())
1217 QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
1218 if (!rectangle) rectangle = d->sceneGraphContext()->createRectangleNode();
1220 rectangle->setRect(QRectF(0, 0, width(), height()));
1221 rectangle->setColor(QColor(255, 0, 0, 50));
1222 rectangle->update();