summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Jones <martin.jones@nokia.com>2010-07-22 03:57:46 (GMT)
committerMartin Jones <martin.jones@nokia.com>2010-07-22 03:57:46 (GMT)
commit5dd0dfcd7a079065f99c6149c15b58e69f302729 (patch)
treebf9bf2f202cdf5fdd5d4b52931036c8bc458569c
parent91215b48022b3b3980960f1b5f301ac84f14d49d (diff)
downloadQt-5dd0dfcd7a079065f99c6149c15b58e69f302729.zip
Qt-5dd0dfcd7a079065f99c6149c15b58e69f302729.tar.gz
Qt-5dd0dfcd7a079065f99c6149c15b58e69f302729.tar.bz2
Allow MouseArea dragging to filter mouse events from descendants
This allows dragging a MouseArea that contains a clickable MouseArea, for example. Task-number: QTBUG-12323 Reviewed-by: Michael Brasser
-rw-r--r--doc/src/snippets/declarative/mouseareadragfilter.qml72
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable.cpp2
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea.cpp96
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea_p.h10
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea_p_p.h4
-rw-r--r--tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp11
6 files changed, 189 insertions, 6 deletions
diff --git a/doc/src/snippets/declarative/mouseareadragfilter.qml b/doc/src/snippets/declarative/mouseareadragfilter.qml
new file mode 100644
index 0000000..52ed10c
--- /dev/null
+++ b/doc/src/snippets/declarative/mouseareadragfilter.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [dragfilter]
+import Qt 4.7
+
+Rectangle {
+ width: 480
+ height: 320
+ Rectangle {
+ x: 30; y: 30
+ width: 300; height: 240
+ color: "lightsteelblue"
+
+ MouseArea {
+ anchors.fill: parent
+ drag.target: parent;
+ drag.axis: "XAxis"
+ drag.minimumX: 30
+ drag.maximumX: 150
+ drag.filterChildren: true
+
+ Rectangle {
+ color: "yellow"
+ x: 50; y : 50
+ width: 100; height: 100
+ MouseArea {
+ anchors.fill: parent
+ onClicked: console.log("Clicked")
+ }
+ }
+ }
+ }
+}
+//! [dragfilter]
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
index 9af5f56..b286e11 100644
--- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
@@ -1214,6 +1214,7 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
d->handleMousePressEvent(&mouseEvent);
d->captureDelayedPress(event);
+ stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
break;
case QEvent::GraphicsSceneMouseRelease:
if (d->delayedPressEvent) {
@@ -1234,7 +1235,6 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
default:
break;
}
- stealThisEvent = d->stealMouse; // Update stealThisEvent and grabber in case changed by function calls above
grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) {
d->clearDelayedPress();
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp
index 8ee6093..40c621a 100644
--- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp
+++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp
@@ -53,7 +53,7 @@ static const int PressAndHoldDelay = 800;
QDeclarativeDrag::QDeclarativeDrag(QObject *parent)
: QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX), _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX),
-_active(false)
+_active(false), _filterChildren(false)
{
}
@@ -160,12 +160,24 @@ void QDeclarativeDrag::setActive(bool drag)
emit activeChanged();
}
+bool QDeclarativeDrag::filterChildren() const
+{
+ return _filterChildren;
+}
+
+void QDeclarativeDrag::setFilterChildren(bool filter)
+{
+ if (_filterChildren == filter)
+ return;
+ _filterChildren = filter;
+ emit filterChildrenChanged();
+}
+
QDeclarativeMouseAreaPrivate::~QDeclarativeMouseAreaPrivate()
{
delete drag;
}
-
/*!
\qmlclass MouseArea QDeclarativeMouseArea
\since 4.7
@@ -398,6 +410,7 @@ void QDeclarativeMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeMouseArea);
d->moved = false;
+ d->stealMouse = false;
if (!d->absorb)
QDeclarativeItem::mousePressEvent(event);
else {
@@ -456,8 +469,10 @@ void QDeclarativeMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
const int dragThreshold = QApplication::startDragDistance();
qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
- if ((d->dragX && !(dx < dragThreshold)) || (d->dragY && !(dy < dragThreshold)))
+ if ((d->dragX && !(dx < dragThreshold)) || (d->dragY && !(dy < dragThreshold))) {
d->drag->setActive(true);
+ d->stealMouse = true;
+ }
if (!keepMouseGrab()) {
if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
|| (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
@@ -495,6 +510,7 @@ void QDeclarativeMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void QDeclarativeMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeMouseArea);
+ d->stealMouse = false;
if (!d->absorb) {
QDeclarativeItem::mouseReleaseEvent(event);
} else {
@@ -505,6 +521,8 @@ void QDeclarativeMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
// If we don't accept hover, we need to reset containsMouse.
if (!acceptHoverEvents())
setHovered(false);
+ if (scene()->mouseGrabberItem() == this)
+ ungrabMouse();
setKeepMouseGrab(false);
}
}
@@ -579,6 +597,71 @@ bool QDeclarativeMouseArea::sceneEvent(QEvent *event)
return rv;
}
+bool QDeclarativeMouseArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
+
+ QGraphicsScene *s = scene();
+ QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ return stealThisEvent;
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ d->stealMouse = false;
+ ungrabMouse();
+ }
+ return false;
+}
+
+bool QDeclarativeMouseArea::sceneEventFilter(QGraphicsItem *i, QEvent *e)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
+ return QDeclarativeItem::sceneEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QDeclarativeItem::sceneEventFilter(i, e);
+}
+
void QDeclarativeMouseArea::timerEvent(QTimerEvent *event)
{
Q_D(QDeclarativeMouseArea);
@@ -759,6 +842,7 @@ QDeclarativeDrag *QDeclarativeMouseArea::drag()
\qmlproperty real MouseArea::drag.maximumX
\qmlproperty real MouseArea::drag.minimumY
\qmlproperty real MouseArea::drag.maximumY
+ \qmlproperty bool MouseArea::drag.filterChildren
\c drag provides a convenient way to make an item draggable.
@@ -779,6 +863,12 @@ QDeclarativeDrag *QDeclarativeMouseArea::drag()
for \c rect in the above example, it cannot be dragged along the X-axis.
This can be avoided by settng the anchor value to \c undefined in
an \l onPressed handler.
+
+ If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
+ enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
+
+ \snippet doc/src/snippets/declarative/mouseareadragfilter.qml dragfilter
+
*/
QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p.h
index 4fe3fcb..0da7515 100644
--- a/src/declarative/graphicsitems/qdeclarativemousearea_p.h
+++ b/src/declarative/graphicsitems/qdeclarativemousearea_p.h
@@ -62,6 +62,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeDrag : public QObject
Q_PROPERTY(qreal minimumY READ ymin WRITE setYmin NOTIFY minimumYChanged)
Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged)
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
+ Q_PROPERTY(bool filterChildren READ filterChildren WRITE setFilterChildren NOTIFY filterChildrenChanged)
//### consider drag and drop
public:
@@ -88,6 +89,9 @@ public:
bool active() const;
void setActive(bool);
+ bool filterChildren() const;
+ void setFilterChildren(bool);
+
Q_SIGNALS:
void targetChanged();
void axisChanged();
@@ -96,6 +100,7 @@ Q_SIGNALS:
void minimumYChanged();
void maximumYChanged();
void activeChanged();
+ void filterChildrenChanged();
private:
QGraphicsObject *_target;
@@ -104,7 +109,8 @@ private:
qreal _xmax;
qreal _ymin;
qreal _ymax;
- bool _active;
+ bool _active : 1;
+ bool _filterChildren: 1;
Q_DISABLE_COPY(QDeclarativeDrag)
};
@@ -177,6 +183,8 @@ protected:
void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
bool sceneEvent(QEvent *);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+ bool sceneEventFilter(QGraphicsItem *i, QEvent *e);
void timerEvent(QTimerEvent *event);
virtual void geometryChanged(const QRectF &newGeometry,
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h
index 3d7bd1e..cf9dc18 100644
--- a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h
@@ -68,7 +68,7 @@ class QDeclarativeMouseAreaPrivate : public QDeclarativeItemPrivate
public:
QDeclarativeMouseAreaPrivate()
: absorb(true), hovered(false), pressed(false), longPress(false),
- moved(false), drag(0)
+ moved(false), stealMouse(false), drag(0)
{
}
@@ -78,6 +78,7 @@ public:
{
Q_Q(QDeclarativeMouseArea);
q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFiltersChildEvents(true);
}
void saveEvent(QGraphicsSceneMouseEvent *event) {
@@ -101,6 +102,7 @@ public:
bool moved : 1;
bool dragX : 1;
bool dragY : 1;
+ bool stealMouse : 1;
QDeclarativeDrag *drag;
QPointF startScene;
qreal startX;
diff --git a/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp b/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp
index 5a10372..c9bb467 100644
--- a/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp
+++ b/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp
@@ -137,6 +137,17 @@ void tst_QDeclarativeMouseArea::dragProperties()
QCOMPARE(yminSpy.count(),1);
QCOMPARE(ymaxSpy.count(),1);
+ // filterChildren
+ QSignalSpy filterChildrenSpy(drag, SIGNAL(filterChildrenChanged()));
+
+ drag->setFilterChildren(true);
+
+ QVERIFY(drag->filterChildren());
+ QCOMPARE(filterChildrenSpy.count(), 1);
+
+ drag->setFilterChildren(true);
+ QCOMPARE(filterChildrenSpy.count(), 1);
+
delete canvas;
}