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/qevent.h>
51 #include <QtGui/qguiapplication.h>
52 #include <QtGui/qstylehints.h>
58 DEFINE_BOOL_CONFIG_OPTION(qmlVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
60 static const int PressAndHoldDelay = 800;
62 QQuickDrag::QQuickDrag(QObject *parent)
63 : QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX),
64 _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false)
68 QQuickDrag::~QQuickDrag()
72 QQuickItem *QQuickDrag::target() const
77 void QQuickDrag::setTarget(QQuickItem *t)
85 void QQuickDrag::resetTarget()
93 QQuickDrag::Axis QQuickDrag::axis() const
98 void QQuickDrag::setAxis(QQuickDrag::Axis a)
106 qreal QQuickDrag::xmin() const
111 void QQuickDrag::setXmin(qreal m)
116 emit minimumXChanged();
119 qreal QQuickDrag::xmax() const
124 void QQuickDrag::setXmax(qreal m)
129 emit maximumXChanged();
132 qreal QQuickDrag::ymin() const
137 void QQuickDrag::setYmin(qreal m)
142 emit minimumYChanged();
145 qreal QQuickDrag::ymax() const
150 void QQuickDrag::setYmax(qreal m)
155 emit maximumYChanged();
158 bool QQuickDrag::active() const
163 void QQuickDrag::setActive(bool drag)
168 emit activeChanged();
171 bool QQuickDrag::filterChildren() const
173 return _filterChildren;
176 void QQuickDrag::setFilterChildren(bool filter)
178 if (_filterChildren == filter)
180 _filterChildren = filter;
181 emit filterChildrenChanged();
184 QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj)
186 return new QQuickDragAttached(obj);
189 QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
190 : absorb(true), hovered(false), pressed(false), longPress(false),
191 moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
192 propagateComposedEvents(false), drag(0)
196 QQuickMouseAreaPrivate::~QQuickMouseAreaPrivate()
201 void QQuickMouseAreaPrivate::init()
203 Q_Q(QQuickMouseArea);
204 q->setAcceptedMouseButtons(Qt::LeftButton);
205 q->setFiltersChildMouseEvents(true);
206 if (qmlVisualTouchDebugging()) {
207 q->setFlag(QQuickItem::ItemHasContents);
211 void QQuickMouseAreaPrivate::saveEvent(QMouseEvent *event)
213 lastPos = event->localPos();
214 lastScenePos = event->windowPos();
215 lastButton = event->button();
216 lastButtons = event->buttons();
217 lastModifiers = event->modifiers();
220 bool QQuickMouseAreaPrivate::isPressAndHoldConnected()
222 Q_Q(QQuickMouseArea);
223 IS_SIGNAL_CONNECTED(q, "pressAndHold(QQuickMouseEvent*)");
226 bool QQuickMouseAreaPrivate::isDoubleClickConnected()
228 Q_Q(QQuickMouseArea);
229 IS_SIGNAL_CONNECTED(q, "doubleClicked(QQuickMouseEvent*)");
232 bool QQuickMouseAreaPrivate::isClickConnected()
234 Q_Q(QQuickMouseArea);
235 IS_SIGNAL_CONNECTED(q, "clicked(QQuickMouseEvent*)");
238 bool QQuickMouseAreaPrivate::isWheelConnected()
240 Q_Q(QQuickMouseArea);
241 IS_SIGNAL_CONNECTED(q, "wheel(QQuickWheelEvent*)");
244 void QQuickMouseAreaPrivate::propagate(QQuickMouseEvent* event, PropagateType t)
246 Q_Q(QQuickMouseArea);
247 if (!propagateComposedEvents)
249 QPointF scenePos = q->mapToScene(QPointF(event->x(), event->y()));
250 propagateHelper(event, canvas->rootItem(), scenePos, t);
253 bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *item,const QPointF &sp, PropagateType sig)
255 //Based off of QQuickCanvas::deliverInitialMousePressEvent
256 //But specific to MouseArea, so doesn't belong in canvas
257 Q_Q(const QQuickMouseArea);
258 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
259 if (itemPrivate->opacity() == 0.0)
262 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
263 QPointF p = item->mapFromScene(sp);
264 if (!item->contains(p))
268 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
269 for (int ii = children.count() - 1; ii >= 0; --ii) {
270 QQuickItem *child = children.at(ii);
271 if (!child->isVisible() || !child->isEnabled())
273 if (propagateHelper(ev, child, sp, sig))
277 QQuickMouseArea* ma = qobject_cast<QQuickMouseArea*>(item);
278 if (ma && ma != q && itemPrivate->acceptedMouseButtons() & ev->button()) {
281 if (!ma->d_func()->isClickConnected())
285 if (!ma->d_func()->isDoubleClickConnected())
289 if (!ma->d_func()->isPressAndHoldConnected())
293 QPointF p = item->mapFromScene(sp);
294 if (item->contains(p)) {
297 ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
299 case Click: emit ma->clicked(ev); break;
300 case DoubleClick: emit ma->doubleClicked(ev); break;
301 case PressAndHold: emit ma->pressAndHold(ev); break;
303 if (ev->isAccepted())
312 \qmlclass MouseArea QQuickMouseArea
313 \inqmlmodule QtQuick 2
314 \ingroup qml-basic-interaction-elements
315 \brief The MouseArea item enables simple mouse handling.
318 A MouseArea is an invisible item that is typically used in conjunction with
319 a visible item in order to provide mouse handling for that item.
320 By effectively acting as a proxy, the logic for mouse handling can be
321 contained within a MouseArea item.
323 For basic key handling, see the \l{Keys}{Keys attached property}.
325 The \l enabled property is used to enable and disable mouse handling for
326 the proxied item. When disabled, the mouse area becomes transparent to
329 The \l pressed read-only property indicates whether or not the user is
330 holding down a mouse button over the mouse area. This property is often
331 used in bindings between properties in a user interface. The containsMouse
332 read-only property indicates the presence of the mouse cursor over the
333 mouse area but, by default, only when a mouse button is held down; see below
336 Information about the mouse position and button clicks are provided via
337 signals for which event handler properties are defined. The most commonly
338 used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
339 onPressed, onReleased and onPressAndHold. It's also possible to handle mouse
340 wheel events via the onWheel signal.
342 By default, MouseArea items only report mouse clicks and not changes to the
343 position of the mouse cursor. Setting the hoverEnabled property ensures that
344 handlers defined for onPositionChanged, onEntered and onExited are used and
345 that the containsMouse property is updated even when no mouse buttons are
348 \section1 Example Usage
350 \div {class="float-right"}
351 \inlineimage qml-mousearea-snippet.png
354 The following example uses a MouseArea in a \l Rectangle that changes
355 the \l Rectangle color to red when clicked:
357 \snippet doc/src/snippets/qml/mousearea/mousearea.qml import
359 \snippet doc/src/snippets/qml/mousearea/mousearea.qml intro
362 Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
363 additional information about the mouse event, such as the position, button,
364 and any key modifiers.
366 Here is an extension of the previous example that produces a different
367 color when the area is right clicked:
369 \snippet doc/src/snippets/qml/mousearea/mousearea.qml intro-extended
371 Behavioral Change in QtQuick 2.0
373 From QtQuick 2.0, the signals clicked, doubleClicked and pressAndHold have a different interaction
374 model with regards to the delivery of events to multiple overlapping MouseAreas. These signals can now propagate
375 to all MouseAreas in the area, in painting order, until accepted by one of them. A signal is accepted by
376 default if there is a signal handler for it, use mouse.accepted = false; to ignore. This propagation
377 can send the signal to MouseAreas other than the one which accepted the press event, although that MouseArea
378 will receive the signal first. This behavior can be enabled by setting propagateComposedEvents to true.
380 \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example}
384 \qmlsignal QtQuick2::MouseArea::onEntered()
386 This handler is called when the mouse enters the mouse area.
388 By default the onEntered handler is only called while a button is
389 pressed. Setting hoverEnabled to true enables handling of
390 onEntered when no mouse button is pressed.
396 \qmlsignal QtQuick2::MouseArea::onExited()
398 This handler is called when the mouse exits the mouse area.
400 By default the onExited handler is only called while a button is
401 pressed. Setting hoverEnabled to true enables handling of
402 onExited when no mouse button is pressed.
404 The example below shows a fairly typical relationship between
405 two MouseAreas, with \c mouseArea2 on top of \c mouseArea1. Moving the
406 mouse into \c mouseArea2 from \c mouseArea1 will cause \c onExited
407 to be called for \c mouseArea1.
410 width: 400; height: 400
418 width: 100; height: 100
419 anchors.centerIn: parent
425 If instead you give the two mouseAreas a parent-child relationship,
426 moving the mouse into \c mouseArea2 from \c mouseArea1 will \b not
427 cause \c onExited to be called for \c mouseArea1. Instead, they will
428 both be considered to be simultaneously hovered.
434 \qmlsignal QtQuick2::MouseArea::onPositionChanged(MouseEvent mouse)
436 This handler is called when the mouse position changes.
438 The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
439 position, and any buttons currently pressed.
441 The \e accepted property of the MouseEvent parameter is ignored in this handler.
443 By default the onPositionChanged handler is only called while a button is
444 pressed. Setting hoverEnabled to true enables handling of
445 onPositionChanged when no mouse button is pressed.
449 \qmlsignal QtQuick2::MouseArea::onClicked(MouseEvent mouse)
451 This handler is called when there is a click. A click is defined as a press followed by a release,
452 both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
453 releasing is also considered a click).
455 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
456 position of the release of the click, and whether the click was held.
458 The \e accepted property of the MouseEvent parameter is ignored in this handler.
462 \qmlsignal QtQuick2::MouseArea::onPressed(MouseEvent mouse)
464 This handler is called when there is a press.
465 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
466 position and which button was pressed.
468 The \e accepted property of the MouseEvent parameter determines whether this MouseArea
469 will handle the press and all future mouse events until release. The default is to accept
470 the event and not allow other MouseArea beneath this one to handle the event. If \e accepted
471 is set to false, no further events will be sent to this MouseArea until the button is next
476 \qmlsignal QtQuick2::MouseArea::onReleased(MouseEvent mouse)
478 This handler is called when there is a release.
479 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
480 position of the release of the click, and whether the click was held.
482 The \e accepted property of the MouseEvent parameter is ignored in this handler.
488 \qmlsignal QtQuick2::MouseArea::onPressAndHold(MouseEvent mouse)
490 This handler is called when there is a long press (currently 800ms).
491 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
492 position of the press, and which button is pressed.
494 The \e accepted property of the MouseEvent parameter is ignored in this handler.
498 \qmlsignal QtQuick2::MouseArea::onDoubleClicked(MouseEvent mouse)
500 This handler is called when there is a double-click (a press followed by a release followed by a press).
501 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
502 position of the release of the click, and whether the click was held.
504 If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
505 in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
506 click; otherwise they are suppressed. The accepted property defaults to true.
510 \qmlsignal QtQuick2::MouseArea::onCanceled()
512 This handler is called when mouse events have been canceled, either because an event was not accepted, or
513 because another element stole the mouse event handling.
515 This signal is for advanced use: it is useful when there is more than one MouseArea
516 that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
517 case, if you execute some logic on the pressed signal and then start dragging, the
518 \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
519 the logic when the MouseArea has lost the mouse handling to the \l Flickable,
520 \c onCanceled should be used in addition to onReleased.
524 \qmlsignal QtQuick2::MouseArea::onWheel(WheelEvent mouse)
526 This handler is called in response to both mouse wheel and trackpad scroll gestures.
528 The \l {WheelEvent}{wheel} parameter provides information about the event, including the x and y
529 position, any buttons currently pressed, and information about the wheel movement, including
530 angleDelta and pixelDelta.
533 QQuickMouseArea::QQuickMouseArea(QQuickItem *parent)
534 : QQuickItem(*(new QQuickMouseAreaPrivate), parent)
536 Q_D(QQuickMouseArea);
540 QQuickMouseArea::~QQuickMouseArea()
545 \qmlproperty real QtQuick2::MouseArea::mouseX
546 \qmlproperty real QtQuick2::MouseArea::mouseY
547 These properties hold the coordinates of the mouse cursor.
549 If the hoverEnabled property is false then these properties will only be valid
550 while a button is pressed, and will remain valid as long as the button is held
551 down even if the mouse is moved outside the area.
553 By default, this property is false.
555 If hoverEnabled is true then these properties will be valid when:
557 \li no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
558 \li a button is pressed and held, even if it has since moved out of the area.
561 The coordinates are relative to the MouseArea.
563 qreal QQuickMouseArea::mouseX() const
565 Q_D(const QQuickMouseArea);
566 return d->lastPos.x();
569 qreal QQuickMouseArea::mouseY() const
571 Q_D(const QQuickMouseArea);
572 return d->lastPos.y();
576 \qmlproperty bool QtQuick2::MouseArea::enabled
577 This property holds whether the item accepts mouse events.
579 By default, this property is true.
581 bool QQuickMouseArea::isEnabled() const
583 Q_D(const QQuickMouseArea);
587 void QQuickMouseArea::setEnabled(bool a)
589 Q_D(QQuickMouseArea);
590 if (a != d->absorb) {
592 emit enabledChanged();
597 \qmlproperty bool QtQuick2::MouseArea::preventStealing
598 This property holds whether the mouse events may be stolen from this
601 If a MouseArea is placed within an item that filters child mouse
602 events, such as Flickable, the mouse
603 events may be stolen from the MouseArea if a gesture is recognized
604 by the parent element, e.g. a flick gesture. If preventStealing is
605 set to true, no element will steal the mouse events.
607 Note that setting preventStealing to true once an element has started
608 stealing events will have no effect until the next press event.
610 By default this property is false.
612 bool QQuickMouseArea::preventStealing() const
614 Q_D(const QQuickMouseArea);
615 return d->preventStealing;
618 void QQuickMouseArea::setPreventStealing(bool prevent)
620 Q_D(QQuickMouseArea);
621 if (prevent != d->preventStealing) {
622 d->preventStealing = prevent;
623 setKeepMouseGrab(d->preventStealing && d->absorb);
624 emit preventStealingChanged();
630 \qmlproperty bool QtQuick2::MouseArea::propagateComposedEvents
631 This property holds whether composed mouse events will automatically propagate to
634 MouseArea contains several composed events, clicked, doubleClicked,
635 and pressAndHold. These can propagate via a separate mechanism to basic
636 mouse events, like pressed, which they are composed of.
638 If propagateComposedEvents is set to true, then composed events will be automatically
639 propagated to other MouseAreas in the same location in the scene. They are propagated
640 in painting order until an item accepts them. Unlike pressed handling, events will
641 not be automatically accepted if no handler is present.
643 This property greatly simplifies the usecase of when you want to have overlapping MouseAreas
644 handling the composed events together. For example: if you want one MouseArea to handle click
645 signals and the other to handle pressAndHold, or if you want one MouseArea to handle click most
646 of the time, but pass it through when certain conditions are met.
648 By default this property is false.
650 bool QQuickMouseArea::propagateComposedEvents() const
652 Q_D(const QQuickMouseArea);
653 return d->propagateComposedEvents;
656 void QQuickMouseArea::setPropagateComposedEvents(bool prevent)
658 Q_D(QQuickMouseArea);
659 if (prevent != d->propagateComposedEvents) {
660 d->propagateComposedEvents = prevent;
661 setKeepMouseGrab(d->propagateComposedEvents && d->absorb);
662 emit propagateComposedEventsChanged();
667 \qmlproperty MouseButtons QtQuick2::MouseArea::pressedButtons
668 This property holds the mouse buttons currently pressed.
670 It contains a bitwise combination of:
677 The code below displays "right" when the right mouse buttons is pressed:
679 \snippet doc/src/snippets/qml/mousearea/mousearea.qml mousebuttons
683 Qt::MouseButtons QQuickMouseArea::pressedButtons() const
685 Q_D(const QQuickMouseArea);
686 return d->lastButtons;
689 void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
691 Q_D(QQuickMouseArea);
693 d->stealMouse = d->preventStealing;
695 QQuickItem::mousePressEvent(event);
697 d->longPress = false;
700 d->dragX = drag()->axis() & QQuickDrag::XAxis;
701 d->dragY = drag()->axis() & QQuickDrag::YAxis;
704 d->drag->setActive(false);
706 d->startScene = event->windowPos();
707 d->pressAndHoldTimer.start(PressAndHoldDelay, this);
708 setKeepMouseGrab(d->stealMouse);
709 event->setAccepted(setPressed(true));
714 void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
716 Q_D(QQuickMouseArea);
717 if (!d->absorb && !d->pressed) {
718 QQuickItem::mouseMoveEvent(event);
724 // ### we should skip this if these signals aren't used
725 // ### can GV handle this for us?
726 const bool isInside = contains(d->lastPos);
727 if (d->hovered && !isInside)
729 else if (!d->hovered && isInside)
732 if (d->drag && d->drag->target()) {
734 d->targetStartPos = d->drag->target()->parentItem()
735 ? d->drag->target()->parentItem()->mapToScene(d->drag->target()->pos())
736 : d->drag->target()->pos();
739 QPointF startLocalPos;
741 if (drag()->target()->parentItem()) {
742 startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
743 curLocalPos = drag()->target()->parentItem()->mapFromScene(event->windowPos());
745 startLocalPos = d->startScene;
746 curLocalPos = event->windowPos();
749 const int dragThreshold = qApp->styleHints()->startDragDistance();
750 qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
751 qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
753 if (keepMouseGrab() && d->stealMouse && !d->drag->active())
754 d->drag->setActive(true);
756 QPointF startPos = d->drag->target()->parentItem()
757 ? d->drag->target()->parentItem()->mapFromScene(d->targetStartPos)
760 QPointF dragPos = d->drag->target()->pos();
762 if (d->dragX && d->drag->active()) {
763 qreal x = (curLocalPos.x() - startLocalPos.x()) + startPos.x();
764 if (x < drag()->xmin())
766 else if (x > drag()->xmax())
770 if (d->dragY && d->drag->active()) {
771 qreal y = (curLocalPos.y() - startLocalPos.y()) + startPos.y();
772 if (y < drag()->ymin())
774 else if (y > drag()->ymax())
778 d->drag->target()->setPos(dragPos);
780 if (!keepMouseGrab()) {
781 if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
782 || (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
783 || (d->dragX && d->dragY && (dx > dragThreshold || dy > dragThreshold))) {
784 setKeepMouseGrab(true);
785 d->stealMouse = true;
791 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
792 emit mouseXChanged(&me);
793 me.setPosition(d->lastPos);
794 emit mouseYChanged(&me);
795 me.setPosition(d->lastPos);
796 emit positionChanged(&me);
799 void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
801 Q_D(QQuickMouseArea);
802 d->stealMouse = false;
803 if (!d->absorb && !d->pressed) {
804 QQuickItem::mouseReleaseEvent(event);
809 d->drag->setActive(false);
810 // If we don't accept hover, we need to reset containsMouse.
811 if (!acceptHoverEvents())
813 QQuickCanvas *c = canvas();
814 if (c && c->mouseGrabberItem() == this)
816 setKeepMouseGrab(false);
819 d->doubleClick = false;
822 void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
824 Q_D(QQuickMouseArea);
827 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
828 me.setAccepted(d->isDoubleClickConnected());
829 emit this->doubleClicked(&me);
830 if (!me.isAccepted())
831 d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
832 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
834 QQuickItem::mouseDoubleClickEvent(event);
837 void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
839 Q_D(QQuickMouseArea);
840 if (!d->absorb && !d->pressed) {
841 QQuickItem::hoverEnterEvent(event);
843 d->lastPos = event->posF();
844 d->lastModifiers = event->modifiers();
846 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
847 emit mouseXChanged(&me);
848 me.setPosition(d->lastPos);
849 emit mouseYChanged(&me);
850 me.setPosition(d->lastPos);
854 void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
856 Q_D(QQuickMouseArea);
857 if (!d->absorb && !d->pressed) {
858 QQuickItem::hoverMoveEvent(event);
860 d->lastPos = event->posF();
861 d->lastModifiers = event->modifiers();
862 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
863 emit mouseXChanged(&me);
864 me.setPosition(d->lastPos);
865 emit mouseYChanged(&me);
866 me.setPosition(d->lastPos);
867 emit positionChanged(&me);
871 void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
873 Q_D(QQuickMouseArea);
874 if (!d->absorb && !d->pressed)
875 QQuickItem::hoverLeaveEvent(event);
880 void QQuickMouseArea::wheelEvent(QWheelEvent *event)
882 Q_D(QQuickMouseArea);
884 QQuickItem::wheelEvent(event);
888 QQuickWheelEvent we(event->posF().x(), event->posF().y(), event->angleDelta(),
889 event->pixelDelta(), event->buttons(), event->modifiers());
890 we.setAccepted(d->isWheelConnected());
892 if (!we.isAccepted())
893 QQuickItem::wheelEvent(event);
896 void QQuickMouseArea::ungrabMouse()
898 Q_D(QQuickMouseArea);
900 // if our mouse grab has been removed (probably by Flickable), fix our
903 d->stealMouse = false;
904 setKeepMouseGrab(false);
906 emit pressedChanged();
909 emit hoveredChanged();
914 void QQuickMouseArea::mouseUngrabEvent()
919 bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
921 Q_D(QQuickMouseArea);
922 QPointF localPos = mapFromScene(event->windowPos());
924 QQuickCanvas *c = canvas();
925 QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
926 bool stealThisEvent = d->stealMouse;
927 if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
928 QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
929 event->button(), event->buttons(), event->modifiers());
930 mouseEvent.setAccepted(false);
932 switch (event->type()) {
933 case QEvent::MouseMove:
934 mouseMoveEvent(&mouseEvent);
936 case QEvent::MouseButtonPress:
937 mousePressEvent(&mouseEvent);
939 case QEvent::MouseButtonRelease:
940 mouseReleaseEvent(&mouseEvent);
945 grabber = c->mouseGrabberItem();
946 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
949 return stealThisEvent;
951 if (event->type() == QEvent::MouseButtonRelease) {
954 d->stealMouse = false;
955 if (c && c->mouseGrabberItem() == this)
958 emit pressedChanged();
961 emit hoveredChanged();
968 bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
970 Q_D(QQuickMouseArea);
971 if (!d->pressed && (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren()))
972 return QQuickItem::childMouseEventFilter(i, e);
974 case QEvent::MouseButtonPress:
975 case QEvent::MouseMove:
976 case QEvent::MouseButtonRelease:
977 return sendMouseEvent(static_cast<QMouseEvent *>(e));
982 return QQuickItem::childMouseEventFilter(i, e);
985 void QQuickMouseArea::timerEvent(QTimerEvent *event)
987 Q_D(QQuickMouseArea);
988 if (event->timerId() == d->pressAndHoldTimer.timerId()) {
989 d->pressAndHoldTimer.stop();
990 bool dragged = d->drag && d->drag->active();
991 if (d->pressed && dragged == false && d->hovered == true) {
993 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
994 me.setAccepted(d->isPressAndHoldConnected());
995 emit pressAndHold(&me);
996 if (!me.isAccepted())
997 d->propagate(&me, QQuickMouseAreaPrivate::PressAndHold);
998 if (!me.isAccepted()) // no one handled the long press - allow click
999 d->longPress = false;
1004 void QQuickMouseArea::windowDeactivateEvent()
1007 QQuickItem::windowDeactivateEvent();
1010 void QQuickMouseArea::geometryChanged(const QRectF &newGeometry,
1011 const QRectF &oldGeometry)
1013 Q_D(QQuickMouseArea);
1014 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1016 if (d->lastScenePos.isNull)
1017 d->lastScenePos = mapToScene(d->lastPos);
1018 else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
1019 d->lastPos = mapFromScene(d->lastScenePos);
1022 void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
1024 Q_D(QQuickMouseArea);
1026 case ItemVisibleHasChanged:
1027 if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
1028 setHovered(!d->hovered);
1034 QQuickItem::itemChange(change, value);
1038 \qmlproperty bool QtQuick2::MouseArea::hoverEnabled
1039 This property holds whether hover events are handled.
1041 By default, mouse events are only handled in response to a button event, or when a button is
1042 pressed. Hover enables handling of all mouse events even when no mouse button is
1045 This property affects the containsMouse property and the onEntered, onExited and
1046 onPositionChanged signals.
1048 bool QQuickMouseArea::hoverEnabled() const
1050 return acceptHoverEvents();
1053 void QQuickMouseArea::setHoverEnabled(bool h)
1055 if (h == acceptHoverEvents())
1058 setAcceptHoverEvents(h);
1059 emit hoverEnabledChanged();
1064 \qmlproperty bool QtQuick2::MouseArea::containsMouse
1065 This property holds whether the mouse is currently inside the mouse area.
1067 \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
1068 In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
1070 bool QQuickMouseArea::hovered() const
1072 Q_D(const QQuickMouseArea);
1077 \qmlproperty bool QtQuick2::MouseArea::pressed
1078 This property holds whether the mouse area is currently pressed.
1080 bool QQuickMouseArea::pressed() const
1082 Q_D(const QQuickMouseArea);
1086 void QQuickMouseArea::setHovered(bool h)
1088 Q_D(QQuickMouseArea);
1089 if (d->hovered != h) {
1091 emit hoveredChanged();
1092 d->hovered ? emit entered() : emit exited();
1096 \qmlproperty QtQuick2::Qt::MouseButtons MouseArea::acceptedButtons
1097 This property holds the mouse buttons that the mouse area reacts to.
1099 The available buttons are:
1106 To accept more than one button the flags can be combined with the
1110 MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
1113 The default value is \c Qt.LeftButton.
1115 Qt::MouseButtons QQuickMouseArea::acceptedButtons() const
1117 return acceptedMouseButtons();
1120 void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
1122 if (buttons != acceptedMouseButtons()) {
1123 setAcceptedMouseButtons(buttons);
1124 emit acceptedButtonsChanged();
1128 bool QQuickMouseArea::setPressed(bool p)
1130 Q_D(QQuickMouseArea);
1131 bool dragged = d->drag && d->drag->active();
1132 bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
1134 if (d->pressed != p) {
1136 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
1138 if (!d->doubleClick)
1140 me.setPosition(d->lastPos);
1141 emit mouseXChanged(&me);
1142 me.setPosition(d->lastPos);
1143 emit mouseYChanged(&me);
1144 emit pressedChanged();
1147 me.setPosition(d->lastPos);
1148 emit pressedChanged();
1149 if (isclick && !d->longPress && !d->doubleClick){
1150 me.setAccepted(d->isClickConnected());
1152 if (!me.isAccepted())
1153 d->propagate(&me, QQuickMouseAreaPrivate::Click);
1157 return me.isAccepted();
1163 \qmlproperty Item QtQuick2::MouseArea::drag.target
1164 \qmlproperty bool QtQuick2::MouseArea::drag.active
1165 \qmlproperty enumeration QtQuick2::MouseArea::drag.axis
1166 \qmlproperty real QtQuick2::MouseArea::drag.minimumX
1167 \qmlproperty real QtQuick2::MouseArea::drag.maximumX
1168 \qmlproperty real QtQuick2::MouseArea::drag.minimumY
1169 \qmlproperty real QtQuick2::MouseArea::drag.maximumY
1170 \qmlproperty bool QtQuick2::MouseArea::drag.filterChildren
1172 \c drag provides a convenient way to make an item draggable.
1175 \li \c drag.target specifies the id of the item to drag.
1176 \li \c drag.active specifies if the target item is currently being dragged.
1177 \li \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
1178 \li \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
1181 The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
1182 of the rectangle is reduced when it is dragged to the right.
1184 \snippet doc/src/snippets/qml/mousearea/mousearea.qml drag
1186 \note Items cannot be dragged if they are anchored for the requested
1187 \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1188 for \c rect in the above example, it cannot be dragged along the X-axis.
1189 This can be avoided by settng the anchor value to \c undefined in
1190 an \l onPressed handler.
1192 If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
1193 enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1195 \snippet doc/src/snippets/qml/mousearea/mouseareadragfilter.qml dragfilter
1199 QQuickDrag *QQuickMouseArea::drag()
1201 Q_D(QQuickMouseArea);
1203 d->drag = new QQuickDrag;
1207 QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1210 Q_D(QQuickMouseArea);
1212 if (!qmlVisualTouchDebugging())
1215 QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
1216 if (!rectangle) rectangle = d->sceneGraphContext()->createRectangleNode();
1218 rectangle->setRect(QRectF(0, 0, width(), height()));
1219 rectangle->setColor(QColor(255, 0, 0, 50));
1220 rectangle->update();