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>
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 void QQuickMouseAreaPrivate::propagate(QQuickMouseEvent* event, PropagateType t)
241 Q_Q(QQuickMouseArea);
242 if (!propagateComposedEvents)
244 QPointF scenePos = q->mapToScene(QPointF(event->x(), event->y()));
245 propagateHelper(event, canvas->rootItem(), scenePos, t);
248 bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *item,const QPointF &sp, PropagateType sig)
250 //Based off of QQuickCanvas::deliverInitialMousePressEvent
251 //But specific to MouseArea, so doesn't belong in canvas
252 Q_Q(const QQuickMouseArea);
253 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
254 if (itemPrivate->opacity() == 0.0)
257 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
258 QPointF p = item->mapFromScene(sp);
259 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
263 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
264 for (int ii = children.count() - 1; ii >= 0; --ii) {
265 QQuickItem *child = children.at(ii);
266 if (!child->isVisible() || !child->isEnabled())
268 if (propagateHelper(ev, child, sp, sig))
272 QQuickMouseArea* ma = qobject_cast<QQuickMouseArea*>(item);
273 if (ma && ma != q && itemPrivate->acceptedMouseButtons() & ev->button()) {
276 if (!ma->d_func()->isClickConnected())
280 if (!ma->d_func()->isDoubleClickConnected())
284 if (!ma->d_func()->isPressAndHoldConnected())
288 QPointF p = item->mapFromScene(sp);
289 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
292 ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
294 case Click: emit ma->clicked(ev); break;
295 case DoubleClick: emit ma->doubleClicked(ev); break;
296 case PressAndHold: emit ma->pressAndHold(ev); break;
298 if (ev->isAccepted())
307 \qmlclass MouseArea QQuickMouseArea
308 \inqmlmodule QtQuick 2
309 \ingroup qml-basic-interaction-elements
310 \brief The MouseArea item enables simple mouse handling.
313 A MouseArea is an invisible item that is typically used in conjunction with
314 a visible item in order to provide mouse handling for that item.
315 By effectively acting as a proxy, the logic for mouse handling can be
316 contained within a MouseArea item.
318 For basic key handling, see the \l{Keys}{Keys attached property}.
320 The \l enabled property is used to enable and disable mouse handling for
321 the proxied item. When disabled, the mouse area becomes transparent to
324 The \l pressed read-only property indicates whether or not the user is
325 holding down a mouse button over the mouse area. This property is often
326 used in bindings between properties in a user interface. The containsMouse
327 read-only property indicates the presence of the mouse cursor over the
328 mouse area but, by default, only when a mouse button is held down; see below
331 Information about the mouse position and button clicks are provided via
332 signals for which event handler properties are defined. The most commonly
333 used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
334 onPressed, onReleased and onPressAndHold.
336 By default, MouseArea items only report mouse clicks and not changes to the
337 position of the mouse cursor. Setting the hoverEnabled property ensures that
338 handlers defined for onPositionChanged, onEntered and onExited are used and
339 that the containsMouse property is updated even when no mouse buttons are
342 \section1 Example Usage
344 \div {class="float-right"}
345 \inlineimage qml-mousearea-snippet.png
348 The following example uses a MouseArea in a \l Rectangle that changes
349 the \l Rectangle color to red when clicked:
351 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml import
353 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro
356 Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
357 additional information about the mouse event, such as the position, button,
358 and any key modifiers.
360 Here is an extension of the previous example that produces a different
361 color when the area is right clicked:
363 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro-extended
365 Behavioral Change in QtQuick 2.0
367 From QtQuick 2.0, the signals clicked, doubleClicked and pressAndHold have a different interaction
368 model with regards to the delivery of events to multiple overlapping MouseAreas. These signals can now propagate
369 to all MouseAreas in the area, in painting order, until accepted by one of them. A signal is accepted by
370 default if there is a signal handler for it, use mouse.accepted = false; to ignore. This propagation
371 can send the signal to MouseAreas other than the one which accepted the press event, although that MouseArea
372 will receive the signal first. This behavior can be enabled by setting propagateComposedEvents to true.
374 \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example}
378 \qmlsignal QtQuick2::MouseArea::onEntered()
380 This handler is called when the mouse enters the mouse area.
382 By default the onEntered handler is only called while a button is
383 pressed. Setting hoverEnabled to true enables handling of
384 onEntered when no mouse button is pressed.
390 \qmlsignal QtQuick2::MouseArea::onExited()
392 This handler is called when the mouse exits the mouse area.
394 By default the onExited handler is only called while a button is
395 pressed. Setting hoverEnabled to true enables handling of
396 onExited when no mouse button is pressed.
398 The example below shows a fairly typical relationship between
399 two MouseAreas, with \c mouseArea2 on top of \c mouseArea1. Moving the
400 mouse into \c mouseArea2 from \c mouseArea1 will cause \c onExited
401 to be called for \c mouseArea1.
404 width: 400; height: 400
412 width: 100; height: 100
413 anchors.centerIn: parent
419 If instead you give the two mouseAreas a parent-child relationship,
420 moving the mouse into \c mouseArea2 from \c mouseArea1 will \b not
421 cause \c onExited to be called for \c mouseArea1. Instead, they will
422 both be considered to be simultaneously hovered.
428 \qmlsignal QtQuick2::MouseArea::onPositionChanged(MouseEvent mouse)
430 This handler is called when the mouse position changes.
432 The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
433 position, and any buttons currently pressed.
435 The \e accepted property of the MouseEvent parameter is ignored in this handler.
437 By default the onPositionChanged handler is only called while a button is
438 pressed. Setting hoverEnabled to true enables handling of
439 onPositionChanged when no mouse button is pressed.
443 \qmlsignal QtQuick2::MouseArea::onClicked(MouseEvent mouse)
445 This handler is called when there is a click. A click is defined as a press followed by a release,
446 both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
447 releasing is also considered a click).
449 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
450 position of the release of the click, and whether the click was held.
452 The \e accepted property of the MouseEvent parameter is ignored in this handler.
456 \qmlsignal QtQuick2::MouseArea::onPressed(MouseEvent mouse)
458 This handler is called when there is a press.
459 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
460 position and which button was pressed.
462 The \e accepted property of the MouseEvent parameter determines whether this MouseArea
463 will handle the press and all future mouse events until release. The default is to accept
464 the event and not allow other MouseArea beneath this one to handle the event. If \e accepted
465 is set to false, no further events will be sent to this MouseArea until the button is next
470 \qmlsignal QtQuick2::MouseArea::onReleased(MouseEvent mouse)
472 This handler is called when there is a release.
473 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
474 position of the release of the click, and whether the click was held.
476 The \e accepted property of the MouseEvent parameter is ignored in this handler.
482 \qmlsignal QtQuick2::MouseArea::onPressAndHold(MouseEvent mouse)
484 This handler is called when there is a long press (currently 800ms).
485 The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
486 position of the press, and which button is pressed.
488 The \e accepted property of the MouseEvent parameter is ignored in this handler.
492 \qmlsignal QtQuick2::MouseArea::onDoubleClicked(MouseEvent mouse)
494 This handler is called when there is a double-click (a press followed by a release followed by a press).
495 The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
496 position of the release of the click, and whether the click was held.
498 If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
499 in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
500 click; otherwise they are suppressed. The accepted property defaults to true.
504 \qmlsignal QtQuick2::MouseArea::onCanceled()
506 This handler is called when mouse events have been canceled, either because an event was not accepted, or
507 because another element stole the mouse event handling.
509 This signal is for advanced use: it is useful when there is more than one MouseArea
510 that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
511 case, if you execute some logic on the pressed signal and then start dragging, the
512 \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
513 the logic when the MouseArea has lost the mouse handling to the \l Flickable,
514 \c onCanceled should be used in addition to onReleased.
516 QQuickMouseArea::QQuickMouseArea(QQuickItem *parent)
517 : QQuickItem(*(new QQuickMouseAreaPrivate), parent)
519 Q_D(QQuickMouseArea);
523 QQuickMouseArea::~QQuickMouseArea()
528 \qmlproperty real QtQuick2::MouseArea::mouseX
529 \qmlproperty real QtQuick2::MouseArea::mouseY
530 These properties hold the coordinates of the mouse cursor.
532 If the hoverEnabled property is false then these properties will only be valid
533 while a button is pressed, and will remain valid as long as the button is held
534 down even if the mouse is moved outside the area.
536 By default, this property is false.
538 If hoverEnabled is true then these properties will be valid when:
540 \i no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
541 \i a button is pressed and held, even if it has since moved out of the area.
544 The coordinates are relative to the MouseArea.
546 qreal QQuickMouseArea::mouseX() const
548 Q_D(const QQuickMouseArea);
549 return d->lastPos.x();
552 qreal QQuickMouseArea::mouseY() const
554 Q_D(const QQuickMouseArea);
555 return d->lastPos.y();
559 \qmlproperty bool QtQuick2::MouseArea::enabled
560 This property holds whether the item accepts mouse events.
562 By default, this property is true.
564 bool QQuickMouseArea::isEnabled() const
566 Q_D(const QQuickMouseArea);
570 void QQuickMouseArea::setEnabled(bool a)
572 Q_D(QQuickMouseArea);
573 if (a != d->absorb) {
575 emit enabledChanged();
580 \qmlproperty bool QtQuick2::MouseArea::preventStealing
581 This property holds whether the mouse events may be stolen from this
584 If a MouseArea is placed within an item that filters child mouse
585 events, such as Flickable, the mouse
586 events may be stolen from the MouseArea if a gesture is recognized
587 by the parent element, e.g. a flick gesture. If preventStealing is
588 set to true, no element will steal the mouse events.
590 Note that setting preventStealing to true once an element has started
591 stealing events will have no effect until the next press event.
593 By default this property is false.
595 bool QQuickMouseArea::preventStealing() const
597 Q_D(const QQuickMouseArea);
598 return d->preventStealing;
601 void QQuickMouseArea::setPreventStealing(bool prevent)
603 Q_D(QQuickMouseArea);
604 if (prevent != d->preventStealing) {
605 d->preventStealing = prevent;
606 setKeepMouseGrab(d->preventStealing && d->absorb);
607 emit preventStealingChanged();
613 \qmlproperty bool QtQuick2::MouseArea::propagateComposedEvents
614 This property holds whether composed mouse events will automatically propagate to
617 MouseArea contains several composed events, clicked, doubleClicked,
618 and pressAndHold. These can propagate via a separate mechanism to basic
619 mouse events, like pressed, which they are composed of.
621 If propagateComposedEvents is set to true, then composed events will be automatically
622 propagated to other MouseAreas in the same location in the scene. They are propagated
623 in painting order until an item accepts them. Unlike pressed handling, events will
624 not be automatically accepted if no handler is present.
626 This property greatly simplifies the usecase of when you want to have overlapping MouseAreas
627 handling the composed events together. For example: if you want one MouseArea to handle click
628 signals and the other to handle pressAndHold, or if you want one MouseArea to handle click most
629 of the time, but pass it through when certain conditions are met.
631 By default this property is false.
633 bool QQuickMouseArea::propagateComposedEvents() const
635 Q_D(const QQuickMouseArea);
636 return d->propagateComposedEvents;
639 void QQuickMouseArea::setPropagateComposedEvents(bool prevent)
641 Q_D(QQuickMouseArea);
642 if (prevent != d->propagateComposedEvents) {
643 d->propagateComposedEvents = prevent;
644 setKeepMouseGrab(d->propagateComposedEvents && d->absorb);
645 emit propagateComposedEventsChanged();
650 \qmlproperty MouseButtons QtQuick2::MouseArea::pressedButtons
651 This property holds the mouse buttons currently pressed.
653 It contains a bitwise combination of:
660 The code below displays "right" when the right mouse buttons is pressed:
662 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml mousebuttons
666 Qt::MouseButtons QQuickMouseArea::pressedButtons() const
668 Q_D(const QQuickMouseArea);
669 return d->lastButtons;
672 void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
674 Q_D(QQuickMouseArea);
676 d->stealMouse = d->preventStealing;
678 QQuickItem::mousePressEvent(event);
680 d->longPress = false;
683 d->dragX = drag()->axis() & QQuickDrag::XAxis;
684 d->dragY = drag()->axis() & QQuickDrag::YAxis;
687 d->drag->setActive(false);
689 d->startScene = event->windowPos();
690 d->pressAndHoldTimer.start(PressAndHoldDelay, this);
691 setKeepMouseGrab(d->stealMouse);
692 event->setAccepted(setPressed(true));
697 void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
699 Q_D(QQuickMouseArea);
701 QQuickItem::mouseMoveEvent(event);
707 // ### we should skip this if these signals aren't used
708 // ### can GV handle this for us?
709 bool contains = boundingRect().contains(d->lastPos);
710 if (d->hovered && !contains)
712 else if (!d->hovered && contains)
715 if (d->drag && d->drag->target()) {
717 d->targetStartPos = d->drag->target()->parentItem()
718 ? d->drag->target()->parentItem()->mapToScene(d->drag->target()->pos())
719 : d->drag->target()->pos();
722 QPointF startLocalPos;
724 if (drag()->target()->parentItem()) {
725 startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
726 curLocalPos = drag()->target()->parentItem()->mapFromScene(event->windowPos());
728 startLocalPos = d->startScene;
729 curLocalPos = event->windowPos();
732 const int dragThreshold = qApp->styleHints()->startDragDistance();
733 qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
734 qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
736 if (keepMouseGrab() && d->stealMouse && !d->drag->active())
737 d->drag->setActive(true);
739 QPointF startPos = d->drag->target()->parentItem()
740 ? d->drag->target()->parentItem()->mapFromScene(d->targetStartPos)
743 QPointF dragPos = d->drag->target()->pos();
745 if (d->dragX && d->drag->active()) {
746 qreal x = (curLocalPos.x() - startLocalPos.x()) + startPos.x();
747 if (x < drag()->xmin())
749 else if (x > drag()->xmax())
753 if (d->dragY && d->drag->active()) {
754 qreal y = (curLocalPos.y() - startLocalPos.y()) + startPos.y();
755 if (y < drag()->ymin())
757 else if (y > drag()->ymax())
761 d->drag->target()->setPos(dragPos);
763 if (!keepMouseGrab()) {
764 if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
765 || (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
766 || (d->dragX && d->dragY && (dx > dragThreshold || dy > dragThreshold))) {
767 setKeepMouseGrab(true);
768 d->stealMouse = true;
774 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
775 emit mouseXChanged(&me);
776 me.setPosition(d->lastPos);
777 emit mouseYChanged(&me);
778 me.setPosition(d->lastPos);
779 emit positionChanged(&me);
782 void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
784 Q_D(QQuickMouseArea);
785 d->stealMouse = false;
787 QQuickItem::mouseReleaseEvent(event);
792 d->drag->setActive(false);
793 // If we don't accept hover, we need to reset containsMouse.
794 if (!acceptHoverEvents())
796 QQuickCanvas *c = canvas();
797 if (c && c->mouseGrabberItem() == this)
799 setKeepMouseGrab(false);
802 d->doubleClick = false;
805 void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
807 Q_D(QQuickMouseArea);
810 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
811 me.setAccepted(d->isDoubleClickConnected());
812 emit this->doubleClicked(&me);
813 if (!me.isAccepted())
814 d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
815 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
817 QQuickItem::mouseDoubleClickEvent(event);
820 void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
822 Q_D(QQuickMouseArea);
824 QQuickItem::hoverEnterEvent(event);
826 d->lastPos = event->posF();
827 d->lastModifiers = event->modifiers();
829 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
830 emit mouseXChanged(&me);
831 me.setPosition(d->lastPos);
832 emit mouseYChanged(&me);
833 me.setPosition(d->lastPos);
837 void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
839 Q_D(QQuickMouseArea);
841 QQuickItem::hoverMoveEvent(event);
843 d->lastPos = event->posF();
844 d->lastModifiers = event->modifiers();
845 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
846 emit mouseXChanged(&me);
847 me.setPosition(d->lastPos);
848 emit mouseYChanged(&me);
849 me.setPosition(d->lastPos);
850 emit positionChanged(&me);
854 void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
856 Q_D(QQuickMouseArea);
858 QQuickItem::hoverLeaveEvent(event);
863 void QQuickMouseArea::ungrabMouse()
865 Q_D(QQuickMouseArea);
867 // if our mouse grab has been removed (probably by Flickable), fix our
870 d->stealMouse = false;
871 setKeepMouseGrab(false);
873 emit pressedChanged();
876 emit hoveredChanged();
881 void QQuickMouseArea::mouseUngrabEvent()
886 bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
888 Q_D(QQuickMouseArea);
889 QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
891 QQuickCanvas *c = canvas();
892 QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
893 bool stealThisEvent = d->stealMouse;
894 if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab())) {
895 QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
896 event->button(), event->buttons(), event->modifiers());
897 mouseEvent.setAccepted(false);
899 switch (event->type()) {
900 case QEvent::MouseMove:
901 mouseMoveEvent(&mouseEvent);
903 case QEvent::MouseButtonPress:
904 mousePressEvent(&mouseEvent);
906 case QEvent::MouseButtonRelease:
907 mouseReleaseEvent(&mouseEvent);
912 grabber = c->mouseGrabberItem();
913 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
916 return stealThisEvent;
918 if (event->type() == QEvent::MouseButtonRelease) {
921 d->stealMouse = false;
922 if (c && c->mouseGrabberItem() == this)
925 emit pressedChanged();
928 emit hoveredChanged();
935 bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
937 Q_D(QQuickMouseArea);
938 if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
939 return QQuickItem::childMouseEventFilter(i, e);
941 case QEvent::MouseButtonPress:
942 case QEvent::MouseMove:
943 case QEvent::MouseButtonRelease:
944 return sendMouseEvent(static_cast<QMouseEvent *>(e));
949 return QQuickItem::childMouseEventFilter(i, e);
952 void QQuickMouseArea::timerEvent(QTimerEvent *event)
954 Q_D(QQuickMouseArea);
955 if (event->timerId() == d->pressAndHoldTimer.timerId()) {
956 d->pressAndHoldTimer.stop();
957 bool dragged = d->drag && d->drag->active();
958 if (d->pressed && dragged == false && d->hovered == true) {
960 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
961 me.setAccepted(d->isPressAndHoldConnected());
962 emit pressAndHold(&me);
963 if (!me.isAccepted())
964 d->propagate(&me, QQuickMouseAreaPrivate::PressAndHold);
965 if (!me.isAccepted()) // no one handled the long press - allow click
966 d->longPress = false;
971 void QQuickMouseArea::windowDeactivateEvent()
974 QQuickItem::windowDeactivateEvent();
977 void QQuickMouseArea::geometryChanged(const QRectF &newGeometry,
978 const QRectF &oldGeometry)
980 Q_D(QQuickMouseArea);
981 QQuickItem::geometryChanged(newGeometry, oldGeometry);
983 if (d->lastScenePos.isNull)
984 d->lastScenePos = mapToScene(d->lastPos);
985 else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
986 d->lastPos = mapFromScene(d->lastScenePos);
989 void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
991 Q_D(QQuickMouseArea);
993 case ItemVisibleHasChanged:
994 if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
995 setHovered(!d->hovered);
1001 QQuickItem::itemChange(change, value);
1005 \qmlproperty bool QtQuick2::MouseArea::hoverEnabled
1006 This property holds whether hover events are handled.
1008 By default, mouse events are only handled in response to a button event, or when a button is
1009 pressed. Hover enables handling of all mouse events even when no mouse button is
1012 This property affects the containsMouse property and the onEntered, onExited and
1013 onPositionChanged signals.
1015 bool QQuickMouseArea::hoverEnabled() const
1017 return acceptHoverEvents();
1020 void QQuickMouseArea::setHoverEnabled(bool h)
1022 if (h == acceptHoverEvents())
1025 setAcceptHoverEvents(h);
1026 emit hoverEnabledChanged();
1031 \qmlproperty bool QtQuick2::MouseArea::containsMouse
1032 This property holds whether the mouse is currently inside the mouse area.
1034 \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
1035 In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
1037 bool QQuickMouseArea::hovered() const
1039 Q_D(const QQuickMouseArea);
1044 \qmlproperty bool QtQuick2::MouseArea::pressed
1045 This property holds whether the mouse area is currently pressed.
1047 bool QQuickMouseArea::pressed() const
1049 Q_D(const QQuickMouseArea);
1053 void QQuickMouseArea::setHovered(bool h)
1055 Q_D(QQuickMouseArea);
1056 if (d->hovered != h) {
1058 emit hoveredChanged();
1059 d->hovered ? emit entered() : emit exited();
1063 \qmlproperty QtQuick2::Qt::MouseButtons MouseArea::acceptedButtons
1064 This property holds the mouse buttons that the mouse area reacts to.
1066 The available buttons are:
1073 To accept more than one button the flags can be combined with the
1077 MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
1080 The default value is \c Qt.LeftButton.
1082 Qt::MouseButtons QQuickMouseArea::acceptedButtons() const
1084 return acceptedMouseButtons();
1087 void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
1089 if (buttons != acceptedMouseButtons()) {
1090 setAcceptedMouseButtons(buttons);
1091 emit acceptedButtonsChanged();
1095 bool QQuickMouseArea::setPressed(bool p)
1097 Q_D(QQuickMouseArea);
1098 bool dragged = d->drag && d->drag->active();
1099 bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
1101 if (d->pressed != p) {
1103 QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
1105 if (!d->doubleClick)
1107 me.setPosition(d->lastPos);
1108 emit mouseXChanged(&me);
1109 me.setPosition(d->lastPos);
1110 emit mouseYChanged(&me);
1111 emit pressedChanged();
1114 me.setPosition(d->lastPos);
1115 emit pressedChanged();
1116 if (isclick && !d->longPress && !d->doubleClick){
1117 me.setAccepted(d->isClickConnected());
1119 if (!me.isAccepted())
1120 d->propagate(&me, QQuickMouseAreaPrivate::Click);
1124 return me.isAccepted();
1130 \qmlproperty Item QtQuick2::MouseArea::drag.target
1131 \qmlproperty bool QtQuick2::MouseArea::drag.active
1132 \qmlproperty enumeration QtQuick2::MouseArea::drag.axis
1133 \qmlproperty real QtQuick2::MouseArea::drag.minimumX
1134 \qmlproperty real QtQuick2::MouseArea::drag.maximumX
1135 \qmlproperty real QtQuick2::MouseArea::drag.minimumY
1136 \qmlproperty real QtQuick2::MouseArea::drag.maximumY
1137 \qmlproperty bool QtQuick2::MouseArea::drag.filterChildren
1139 \c drag provides a convenient way to make an item draggable.
1142 \i \c drag.target specifies the id of the item to drag.
1143 \i \c drag.active specifies if the target item is currently being dragged.
1144 \i \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
1145 \i \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
1148 The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
1149 of the rectangle is reduced when it is dragged to the right.
1151 \snippet doc/src/snippets/declarative/mousearea/mousearea.qml drag
1153 \note Items cannot be dragged if they are anchored for the requested
1154 \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1155 for \c rect in the above example, it cannot be dragged along the X-axis.
1156 This can be avoided by settng the anchor value to \c undefined in
1157 an \l onPressed handler.
1159 If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
1160 enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1162 \snippet doc/src/snippets/declarative/mousearea/mouseareadragfilter.qml dragfilter
1166 QQuickDrag *QQuickMouseArea::drag()
1168 Q_D(QQuickMouseArea);
1170 d->drag = new QQuickDrag;
1174 QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1177 Q_D(QQuickMouseArea);
1179 if (!qmlVisualTouchDebugging())
1182 QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
1183 if (!rectangle) rectangle = d->sceneGraphContext()->createRectangleNode();
1185 rectangle->setRect(QRectF(0, 0, width(), height()));
1186 rectangle->setColor(QColor(255, 0, 0, 50));
1187 rectangle->update();