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 QtDeclarative 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>
55 static const int PressAndHoldDelay = 800;
57 QQuickDrag::QQuickDrag(QObject *parent)
58 : QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX),
59 _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false)
63 QQuickDrag::~QQuickDrag()
67 QQuickItem *QQuickDrag::target() const
72 void QQuickDrag::setTarget(QQuickItem *t)
80 void QQuickDrag::resetTarget()
88 QQuickDrag::Axis QQuickDrag::axis() const
93 void QQuickDrag::setAxis(QQuickDrag::Axis a)
101 qreal QQuickDrag::xmin() const
106 void QQuickDrag::setXmin(qreal m)
111 emit minimumXChanged();
114 qreal QQuickDrag::xmax() const
119 void QQuickDrag::setXmax(qreal m)
124 emit maximumXChanged();
127 qreal QQuickDrag::ymin() const
132 void QQuickDrag::setYmin(qreal m)
137 emit minimumYChanged();
140 qreal QQuickDrag::ymax() const
145 void QQuickDrag::setYmax(qreal m)
150 emit maximumYChanged();
153 bool QQuickDrag::active() const
158 void QQuickDrag::setActive(bool drag)
163 emit activeChanged();
166 bool QQuickDrag::filterChildren() const
168 return _filterChildren;
171 void QQuickDrag::setFilterChildren(bool filter)
173 if (_filterChildren == filter)
175 _filterChildren = filter;
176 emit filterChildrenChanged();
179 QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj)
181 return new QQuickDragAttached(obj);
184 QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
185 : absorb(true), hovered(false), pressed(false), longPress(false),
186 moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
187 propagateComposedEvents(false), drag(0)
191 QQuickMouseAreaPrivate::~QQuickMouseAreaPrivate()
196 void QQuickMouseAreaPrivate::init()
198 Q_Q(QQuickMouseArea);
199 q->setAcceptedMouseButtons(Qt::LeftButton);
200 q->setFiltersChildMouseEvents(true);
203 void QQuickMouseAreaPrivate::saveEvent(QMouseEvent *event)
205 lastPos = event->localPos();
206 lastScenePos = event->windowPos();
207 lastButton = event->button();
208 lastButtons = event->buttons();
209 lastModifiers = event->modifiers();
212 bool QQuickMouseAreaPrivate::isPressAndHoldConnected()
214 Q_Q(QQuickMouseArea);
215 static int idx = QObjectPrivate::get(q)->signalIndex("pressAndHold(QQuickMouseEvent*)");
216 return QObjectPrivate::get(q)->isSignalConnected(idx);
219 bool QQuickMouseAreaPrivate::isDoubleClickConnected()
221 Q_Q(QQuickMouseArea);
222 static int idx = QObjectPrivate::get(q)->signalIndex("doubleClicked(QQuickMouseEvent*)");
223 return QObjectPrivate::get(q)->isSignalConnected(idx);
226 bool QQuickMouseAreaPrivate::isClickConnected()
228 Q_Q(QQuickMouseArea);
229 static int idx = QObjectPrivate::get(q)->signalIndex("clicked(QQuickMouseEvent*)");
230 return QObjectPrivate::get(q)->isSignalConnected(idx);
233 void QQuickMouseAreaPrivate::propagate(QQuickMouseEvent* event, PropagateType t)
235 Q_Q(QQuickMouseArea);
236 if (!propagateComposedEvents)
238 QPointF scenePos = q->mapToScene(QPointF(event->x(), event->y()));
239 propagateHelper(event, canvas->rootItem(), scenePos, t);
242 bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *item,const QPointF &sp, PropagateType sig)
244 //Based off of QQuickCanvas::deliverInitialMousePressEvent
245 //But specific to MouseArea, so doesn't belong in canvas
246 Q_Q(const QQuickMouseArea);
247 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
248 if (itemPrivate->opacity == 0.0)
251 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
252 QPointF p = item->mapFromScene(sp);
253 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
257 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
258 for (int ii = children.count() - 1; ii >= 0; --ii) {
259 QQuickItem *child = children.at(ii);
260 if (!child->isVisible() || !child->isEnabled())
262 if (propagateHelper(ev, child, sp, sig))
266 QQuickMouseArea* ma = qobject_cast<QQuickMouseArea*>(item);
267 if (ma && ma != q && itemPrivate->acceptedMouseButtons & ev->button()) {
270 if (!ma->d_func()->isClickConnected())
274 if (!ma->d_func()->isDoubleClickConnected())
278 if (!ma->d_func()->isPressAndHoldConnected())
282 QPointF p = item->mapFromScene(sp);
283 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
286 ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
288 case Click: emit ma->clicked(ev); break;
289 case DoubleClick: emit ma->doubleClicked(ev); break;
290 case PressAndHold: emit ma->pressAndHold(ev); break;
292 if (ev->isAccepted())
301 \qmlclass MouseArea QQuickMouseArea
302 \inqmlmodule QtQuick 2
303 \ingroup qml-basic-interaction-elements
304 \brief The MouseArea item enables simple mouse handling.
307 A MouseArea is an invisible item that is typically used in conjunction with
308 a visible item in order to provide mouse handling for that item.
309 By effectively acting as a proxy, the logic for mouse handling can be
310 contained within a MouseArea item.
312 For basic key handling, see the \l{Keys}{Keys attached property}.
314 The \l enabled property is used to enable and disable mouse handling for
315 the proxied item. When disabled, the mouse area becomes transparent to
318 The \l pressed read-only property indicates whether or not the user is
319 holding down a mouse button over the mouse area. This property is often
320 used in bindings between properties in a user interface. The containsMouse
321 read-only property indicates the presence of the mouse cursor over the
322 mouse area but, by default, only when a mouse button is held down; see below
325 Information about the mouse position and button clicks are provided via
326 signals for which event handler properties are defined. The most commonly
327 used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
328 onPressed, onReleased and onPressAndHold.
330 By default, MouseArea items only report mouse clicks and not changes to the
331 position of the mouse cursor. Setting the hoverEnabled property ensures that
332 handlers defined for onPositionChanged, onEntered and onExited are used and
333 that the containsMouse property is updated even when no mouse buttons are
336 \section1 Example Usage
338 \div {class="float-right"}
339 \inlineimage qml-mousearea-snippet.png
342 The following example uses a MouseArea in a \l Rectangle that changes
343 the \l Rectangle color to red when clicked:
345 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml import
347 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro
350 Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
351 additional information about the mouse event, such as the position, button,
352 and any key modifiers.
354 Here is an extension of the previous example that produces a different
355 color when the area is right clicked:
357 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro-extended
359 Behavioral Change in QtQuick 2.0
361 From QtQuick 2.0, the signals clicked, doubleClicked and pressAndHold have a different interaction
362 model with regards to the delivery of events to multiple overlapping MouseAreas. These signals can now propagate
363 to all MouseAreas in the area, in painting order, until accepted by one of them. A signal is accepted by
364 default if there is a signal handler for it, use mouse.accepted = false; to ignore. This propagation
365 can send the signal to MouseAreas other than the one which accepted the press event, although that MouseArea
366 will receive the signal first. This behavior can be enabled by setting propagateComposedEvents to true.
368 \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example}
372 \qmlsignal QtQuick2::MouseArea::onEntered()
374 This handler is called when the mouse enters the mouse area.
376 By default the onEntered handler is only called while a button is
377 pressed. Setting hoverEnabled to true enables handling of
378 onEntered when no mouse button is pressed.
384 \qmlsignal QtQuick2::MouseArea::onExited()
386 This handler is called when the mouse exits the mouse area.
388 By default the onExited handler is only called while a button is
389 pressed. Setting hoverEnabled to true enables handling of
390 onExited when no mouse button is pressed.
392 The example below shows a fairly typical relationship between
393 two MouseAreas, with \c mouseArea2 on top of \c mouseArea1. Moving the
394 mouse into \c mouseArea2 from \c mouseArea1 will cause \c onExited
395 to be called for \c mouseArea1.
398 width: 400; height: 400
406 width: 100; height: 100
407 anchors.centerIn: parent
413 If instead you give the two mouseAreas a parent-child relationship,
414 moving the mouse into \c mouseArea2 from \c mouseArea1 will \b not
415 cause \c onExited to be called for \c mouseArea1. Instead, they will
416 both be considered to be simultaneously hovered.
422 \qmlsignal QtQuick2::MouseArea::onPositionChanged(MouseEvent mouse)
424 This handler is called when the mouse position changes.
426 The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
427 position, and any buttons currently pressed.
429 The \e accepted property of the MouseEvent parameter is ignored in this handler.
431 By default the onPositionChanged handler is only called while a button is
432 pressed. Setting hoverEnabled to true enables handling of
433 onPositionChanged when no mouse button is pressed.
437 \qmlsignal QtQuick2::MouseArea::onClicked(MouseEvent mouse)
439 This handler is called when there is a click. A click is defined as a press followed by a release,
440 both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
441 releasing is also considered a click).
443 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
444 position of the release of the click, and whether the click was held.
446 The \e accepted property of the MouseEvent parameter is ignored in this handler.
450 \qmlsignal QtQuick2::MouseArea::onPressed(MouseEvent mouse)
452 This handler is called when there is a press.
453 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
454 position and which button was pressed.
456 The \e accepted property of the MouseEvent parameter determines whether this MouseArea
457 will handle the press and all future mouse events until release. The default is to accept
458 the event and not allow other MouseArea beneath this one to handle the event. If \e accepted
459 is set to false, no further events will be sent to this MouseArea until the button is next
464 \qmlsignal QtQuick2::MouseArea::onReleased(MouseEvent mouse)
466 This handler is called when there is a release.
467 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
468 position of the release of the click, and whether the click was held.
470 The \e accepted property of the MouseEvent parameter is ignored in this handler.
476 \qmlsignal QtQuick2::MouseArea::onPressAndHold(MouseEvent mouse)
478 This handler is called when there is a long press (currently 800ms).
479 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
480 position of the press, and which button is pressed.
482 The \e accepted property of the MouseEvent parameter is ignored in this handler.
486 \qmlsignal QtQuick2::MouseArea::onDoubleClicked(MouseEvent mouse)
488 This handler is called when there is a double-click (a press followed by a release followed by a press).
489 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
490 position of the release of the click, and whether the click was held.
492 If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
493 in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
494 click; otherwise they are suppressed. The accepted property defaults to true.
498 \qmlsignal QtQuick2::MouseArea::onCanceled()
500 This handler is called when mouse events have been canceled, either because an event was not accepted, or
501 because another element stole the mouse event handling.
503 This signal is for advanced use: it is useful when there is more than one MouseArea
504 that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
505 case, if you execute some logic on the pressed signal and then start dragging, the
506 \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
507 the logic when the MouseArea has lost the mouse handling to the \l Flickable,
508 \c onCanceled should be used in addition to onReleased.
510 QQuickMouseArea::QQuickMouseArea(QQuickItem *parent)
511 : QQuickItem(*(new QQuickMouseAreaPrivate), parent)
513 Q_D(QQuickMouseArea);
517 QQuickMouseArea::~QQuickMouseArea()
522 \qmlproperty real QtQuick2::MouseArea::mouseX
523 \qmlproperty real QtQuick2::MouseArea::mouseY
524 These properties hold the coordinates of the mouse cursor.
526 If the hoverEnabled property is false then these properties will only be valid
527 while a button is pressed, and will remain valid as long as the button is held
528 down even if the mouse is moved outside the area.
530 By default, this property is false.
532 If hoverEnabled is true then these properties will be valid when:
534 \i no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
535 \i a button is pressed and held, even if it has since moved out of the area.
538 The coordinates are relative to the MouseArea.
540 qreal QQuickMouseArea::mouseX() const
542 Q_D(const QQuickMouseArea);
543 return d->lastPos.x();
546 qreal QQuickMouseArea::mouseY() const
548 Q_D(const QQuickMouseArea);
549 return d->lastPos.y();
553 \qmlproperty bool QtQuick2::MouseArea::enabled
554 This property holds whether the item accepts mouse events.
556 By default, this property is true.
558 bool QQuickMouseArea::isEnabled() const
560 Q_D(const QQuickMouseArea);
564 void QQuickMouseArea::setEnabled(bool a)
566 Q_D(QQuickMouseArea);
567 if (a != d->absorb) {
569 emit enabledChanged();
574 \qmlproperty bool QtQuick2::MouseArea::preventStealing
575 This property holds whether the mouse events may be stolen from this
578 If a MouseArea is placed within an item that filters child mouse
579 events, such as Flickable, the mouse
580 events may be stolen from the MouseArea if a gesture is recognized
581 by the parent element, e.g. a flick gesture. If preventStealing is
582 set to true, no element will steal the mouse events.
584 Note that setting preventStealing to true once an element has started
585 stealing events will have no effect until the next press event.
587 By default this property is false.
589 bool QQuickMouseArea::preventStealing() const
591 Q_D(const QQuickMouseArea);
592 return d->preventStealing;
595 void QQuickMouseArea::setPreventStealing(bool prevent)
597 Q_D(QQuickMouseArea);
598 if (prevent != d->preventStealing) {
599 d->preventStealing = prevent;
600 setKeepMouseGrab(d->preventStealing && d->absorb);
601 emit preventStealingChanged();
607 \qmlproperty bool QtQuick2::MouseArea::propagateComposedEvents
608 This property holds whether composed mouse events will automatically propagate to
611 MouseArea contains several composed events, clicked, doubleClicked,
612 and pressAndHold. These can propagate via a separate mechanism to basic
613 mouse events, like pressed, which they are composed of.
615 If propagateComposedEvents is set to true, then composed events will be automatically
616 propagated to other MouseAreas in the same location in the scene. They are propagated
617 in painting order until an item accepts them. Unlike pressed handling, events will
618 not be automatically accepted if no handler is present.
620 This property greatly simplifies the usecase of when you want to have overlapping MouseAreas
621 handling the composed events together. For example: if you want one MouseArea to handle click
622 signals and the other to handle pressAndHold, or if you want one MouseArea to handle click most
623 of the time, but pass it through when certain conditions are met.
625 By default this property is false.
627 bool QQuickMouseArea::propagateComposedEvents() const
629 Q_D(const QQuickMouseArea);
630 return d->propagateComposedEvents;
633 void QQuickMouseArea::setPropagateComposedEvents(bool prevent)
635 Q_D(QQuickMouseArea);
636 if (prevent != d->propagateComposedEvents) {
637 d->propagateComposedEvents = prevent;
638 setKeepMouseGrab(d->propagateComposedEvents && d->absorb);
639 emit propagateComposedEventsChanged();
644 \qmlproperty MouseButtons QtQuick2::MouseArea::pressedButtons
645 This property holds the mouse buttons currently pressed.
647 It contains a bitwise combination of:
654 The code below displays "right" when the right mouse buttons is pressed:
656 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml mousebuttons
660 Qt::MouseButtons QQuickMouseArea::pressedButtons() const
662 Q_D(const QQuickMouseArea);
663 return d->lastButtons;
666 void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
668 Q_D(QQuickMouseArea);
670 d->stealMouse = d->preventStealing;
672 QQuickItem::mousePressEvent(event);
674 d->longPress = false;
677 d->dragX = drag()->axis() & QQuickDrag::XAxis;
678 d->dragY = drag()->axis() & QQuickDrag::YAxis;
681 d->drag->setActive(false);
683 d->startScene = event->windowPos();
684 d->pressAndHoldTimer.start(PressAndHoldDelay, this);
685 setKeepMouseGrab(d->stealMouse);
686 event->setAccepted(setPressed(true));
691 void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
693 Q_D(QQuickMouseArea);
695 QQuickItem::mouseMoveEvent(event);
701 // ### we should skip this if these signals aren't used
702 // ### can GV handle this for us?
703 bool contains = boundingRect().contains(d->lastPos);
704 if (d->hovered && !contains)
706 else if (!d->hovered && contains)
709 if (d->drag && d->drag->target()) {
711 d->targetStartPos = d->drag->target()->parentItem()
712 ? d->drag->target()->parentItem()->mapToScene(d->drag->target()->pos())
713 : d->drag->target()->pos();
716 QPointF startLocalPos;
718 if (drag()->target()->parentItem()) {
719 startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
720 curLocalPos = drag()->target()->parentItem()->mapFromScene(event->windowPos());
722 startLocalPos = d->startScene;
723 curLocalPos = event->windowPos();
726 const int dragThreshold = qApp->styleHints()->startDragDistance();
727 qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
728 qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
730 if (keepMouseGrab() && d->stealMouse && !d->drag->active())
731 d->drag->setActive(true);
733 QPointF startPos = d->drag->target()->parentItem()
734 ? d->drag->target()->parentItem()->mapFromScene(d->targetStartPos)
737 QPointF dragPos = d->drag->target()->pos();
739 if (d->dragX && d->drag->active()) {
740 qreal x = (curLocalPos.x() - startLocalPos.x()) + startPos.x();
741 if (x < drag()->xmin())
743 else if (x > drag()->xmax())
747 if (d->dragY && d->drag->active()) {
748 qreal y = (curLocalPos.y() - startLocalPos.y()) + startPos.y();
749 if (y < drag()->ymin())
751 else if (y > drag()->ymax())
755 d->drag->target()->setPos(dragPos);
757 if (!keepMouseGrab()) {
758 if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
759 || (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
760 || (d->dragX && d->dragY && (dx > dragThreshold || dy > dragThreshold))) {
761 setKeepMouseGrab(true);
762 d->stealMouse = true;
768 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
769 emit mouseXChanged(&me);
770 me.setPosition(d->lastPos);
771 emit mouseYChanged(&me);
772 me.setPosition(d->lastPos);
773 emit positionChanged(&me);
776 void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
778 Q_D(QQuickMouseArea);
779 d->stealMouse = false;
781 QQuickItem::mouseReleaseEvent(event);
786 d->drag->setActive(false);
787 // If we don't accept hover, we need to reset containsMouse.
788 if (!acceptHoverEvents())
790 QQuickCanvas *c = canvas();
791 if (c && c->mouseGrabberItem() == this)
793 setKeepMouseGrab(false);
796 d->doubleClick = false;
799 void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
801 Q_D(QQuickMouseArea);
804 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
805 me.setAccepted(d->isDoubleClickConnected());
806 emit this->doubleClicked(&me);
807 if (!me.isAccepted())
808 d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
809 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
811 QQuickItem::mouseDoubleClickEvent(event);
814 void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
816 Q_D(QQuickMouseArea);
818 QQuickItem::hoverEnterEvent(event);
820 d->lastPos = event->posF();
821 d->lastModifiers = event->modifiers();
823 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
824 emit mouseXChanged(&me);
825 me.setPosition(d->lastPos);
826 emit mouseYChanged(&me);
827 me.setPosition(d->lastPos);
831 void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
833 Q_D(QQuickMouseArea);
835 QQuickItem::hoverMoveEvent(event);
837 d->lastPos = event->posF();
838 d->lastModifiers = event->modifiers();
839 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
840 emit mouseXChanged(&me);
841 me.setPosition(d->lastPos);
842 emit mouseYChanged(&me);
843 me.setPosition(d->lastPos);
844 emit positionChanged(&me);
848 void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
850 Q_D(QQuickMouseArea);
852 QQuickItem::hoverLeaveEvent(event);
857 void QQuickMouseArea::ungrabMouse()
859 Q_D(QQuickMouseArea);
861 // if our mouse grab has been removed (probably by Flickable), fix our
864 d->stealMouse = false;
865 setKeepMouseGrab(false);
867 emit pressedChanged();
870 emit hoveredChanged();
875 void QQuickMouseArea::mouseUngrabEvent()
880 bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
882 Q_D(QQuickMouseArea);
883 QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
885 QQuickCanvas *c = canvas();
886 QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
887 bool stealThisEvent = d->stealMouse;
888 if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab())) {
889 QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
890 event->button(), event->buttons(), event->modifiers());
891 mouseEvent.setAccepted(false);
893 switch (event->type()) {
894 case QEvent::MouseMove:
895 mouseMoveEvent(&mouseEvent);
897 case QEvent::MouseButtonPress:
898 mousePressEvent(&mouseEvent);
900 case QEvent::MouseButtonRelease:
901 mouseReleaseEvent(&mouseEvent);
906 grabber = c->mouseGrabberItem();
907 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
910 return stealThisEvent;
912 if (event->type() == QEvent::MouseButtonRelease) {
915 d->stealMouse = false;
916 if (c && c->mouseGrabberItem() == this)
919 emit pressedChanged();
922 emit hoveredChanged();
929 bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
931 Q_D(QQuickMouseArea);
932 if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
933 return QQuickItem::childMouseEventFilter(i, e);
935 case QEvent::MouseButtonPress:
936 case QEvent::MouseMove:
937 case QEvent::MouseButtonRelease:
938 return sendMouseEvent(static_cast<QMouseEvent *>(e));
943 return QQuickItem::childMouseEventFilter(i, e);
946 void QQuickMouseArea::timerEvent(QTimerEvent *event)
948 Q_D(QQuickMouseArea);
949 if (event->timerId() == d->pressAndHoldTimer.timerId()) {
950 d->pressAndHoldTimer.stop();
951 bool dragged = d->drag && d->drag->active();
952 if (d->pressed && dragged == false && d->hovered == true) {
954 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
955 me.setAccepted(d->isPressAndHoldConnected());
956 emit pressAndHold(&me);
957 if (!me.isAccepted())
958 d->propagate(&me, QQuickMouseAreaPrivate::PressAndHold);
959 if (!me.isAccepted()) // no one handled the long press - allow click
960 d->longPress = false;
965 void QQuickMouseArea::windowDeactivateEvent()
968 QQuickItem::windowDeactivateEvent();
971 void QQuickMouseArea::geometryChanged(const QRectF &newGeometry,
972 const QRectF &oldGeometry)
974 Q_D(QQuickMouseArea);
975 QQuickItem::geometryChanged(newGeometry, oldGeometry);
977 if (d->lastScenePos.isNull)
978 d->lastScenePos = mapToScene(d->lastPos);
979 else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
980 d->lastPos = mapFromScene(d->lastScenePos);
983 void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
985 Q_D(QQuickMouseArea);
987 case ItemVisibleHasChanged:
988 if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
989 setHovered(!d->hovered);
995 QQuickItem::itemChange(change, value);
999 \qmlproperty bool QtQuick2::MouseArea::hoverEnabled
1000 This property holds whether hover events are handled.
1002 By default, mouse events are only handled in response to a button event, or when a button is
1003 pressed. Hover enables handling of all mouse events even when no mouse button is
1006 This property affects the containsMouse property and the onEntered, onExited and
1007 onPositionChanged signals.
1009 bool QQuickMouseArea::hoverEnabled() const
1011 return acceptHoverEvents();
1014 void QQuickMouseArea::setHoverEnabled(bool h)
1016 if (h == acceptHoverEvents())
1019 setAcceptHoverEvents(h);
1020 emit hoverEnabledChanged();
1025 \qmlproperty bool QtQuick2::MouseArea::containsMouse
1026 This property holds whether the mouse is currently inside the mouse area.
1028 \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
1029 In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
1031 bool QQuickMouseArea::hovered() const
1033 Q_D(const QQuickMouseArea);
1038 \qmlproperty bool QtQuick2::MouseArea::pressed
1039 This property holds whether the mouse area is currently pressed.
1041 bool QQuickMouseArea::pressed() const
1043 Q_D(const QQuickMouseArea);
1047 void QQuickMouseArea::setHovered(bool h)
1049 Q_D(QQuickMouseArea);
1050 if (d->hovered != h) {
1052 emit hoveredChanged();
1053 d->hovered ? emit entered() : emit exited();
1057 \qmlproperty QtQuick2::Qt::MouseButtons MouseArea::acceptedButtons
1058 This property holds the mouse buttons that the mouse area reacts to.
1060 The available buttons are:
1067 To accept more than one button the flags can be combined with the
1071 MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
1074 The default value is \c Qt.LeftButton.
1076 Qt::MouseButtons QQuickMouseArea::acceptedButtons() const
1078 return acceptedMouseButtons();
1081 void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
1083 if (buttons != acceptedMouseButtons()) {
1084 setAcceptedMouseButtons(buttons);
1085 emit acceptedButtonsChanged();
1089 bool QQuickMouseArea::setPressed(bool p)
1091 Q_D(QQuickMouseArea);
1092 bool dragged = d->drag && d->drag->active();
1093 bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
1095 if (d->pressed != p) {
1097 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
1099 if (!d->doubleClick)
1101 me.setPosition(d->lastPos);
1102 emit mouseXChanged(&me);
1103 me.setPosition(d->lastPos);
1104 emit mouseYChanged(&me);
1105 emit pressedChanged();
1108 me.setPosition(d->lastPos);
1109 emit pressedChanged();
1110 if (isclick && !d->longPress && !d->doubleClick){
1111 me.setAccepted(d->isClickConnected());
1113 if (!me.isAccepted())
1114 d->propagate(&me, QQuickMouseAreaPrivate::Click);
1118 return me.isAccepted();
1124 \qmlproperty Item QtQuick2::MouseArea::drag.target
1125 \qmlproperty bool QtQuick2::MouseArea::drag.active
1126 \qmlproperty enumeration QtQuick2::MouseArea::drag.axis
1127 \qmlproperty real QtQuick2::MouseArea::drag.minimumX
1128 \qmlproperty real QtQuick2::MouseArea::drag.maximumX
1129 \qmlproperty real QtQuick2::MouseArea::drag.minimumY
1130 \qmlproperty real QtQuick2::MouseArea::drag.maximumY
1131 \qmlproperty bool QtQuick2::MouseArea::drag.filterChildren
1133 \c drag provides a convenient way to make an item draggable.
1136 \i \c drag.target specifies the id of the item to drag.
1137 \i \c drag.active specifies if the target item is currently being dragged.
1138 \i \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
1139 \i \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
1142 The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
1143 of the rectangle is reduced when it is dragged to the right.
1145 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml drag
1147 \note Items cannot be dragged if they are anchored for the requested
1148 \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1149 for \c rect in the above example, it cannot be dragged along the X-axis.
1150 This can be avoided by settng the anchor value to \c undefined in
1151 an \l onPressed handler.
1153 If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
1154 enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1156 \snippet doc/src/snippets/declarative/mousearea/mouseareadragfilter.qml dragfilter
1160 QQuickDrag *QQuickMouseArea::drag()
1162 Q_D(QQuickMouseArea);
1164 d->drag = new QQuickDrag;