pressed and pressedButtons don't work when multiple buttons are pressed
authorMartin Jones <martin.jones@nokia.com>
Tue, 10 Jul 2012 06:40:06 +0000 (16:40 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 11 Jul 2012 15:37:55 +0000 (17:37 +0200)
The pressed property would react to any mouse event, regardless of
whether it was in acceptedButtons, or there were other buttons still
pressed.  It will now remain true while any button in acceptedButtons
is pressed.

The pressedButtons property could contain buttons not in the
acceptedButtons mask.  It will now only contain buttons that are in the
acceptedButtons mask.

Task-number: QTBUG-26458
Change-Id: I6b25cc36a58c113de062d530761dc179d7ef4a5a
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
src/quick/items/qquickcanvas.cpp
src/quick/items/qquickmousearea.cpp
src/quick/items/qquickmousearea_p.h
src/quick/items/qquickmousearea_p_p.h
tests/auto/quick/qquickmousearea/data/simple.qml [new file with mode: 0644]
tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp

index 2de8fd5..e7134c1 100644 (file)
@@ -1187,7 +1187,7 @@ bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouse
             event->setAccepted(me->isAccepted());
             if (me->isAccepted())
                 return true;
-            if (mouseGrabberItem)
+            if (mouseGrabberItem && !event->buttons())
                 mouseGrabberItem->ungrabMouse();
         }
     }
@@ -1229,7 +1229,7 @@ void QQuickCanvas::mousePressEvent(QMouseEvent *event)
 {
     Q_D(QQuickCanvas);
 #ifdef MOUSE_DEBUG
-    qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
+    qWarning() << "QQuickCanvas::mousePressEvent()" << event->localPos() << event->button() << event->buttons();
 #endif
 
     d->deliverMouseEvent(event);
@@ -1240,7 +1240,7 @@ void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
 {
     Q_D(QQuickCanvas);
 #ifdef MOUSE_DEBUG
-    qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
+    qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons();
 #endif
 
     if (!d->mouseGrabberItem) {
@@ -1249,7 +1249,7 @@ void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
     }
 
     d->deliverMouseEvent(event);
-    if (d->mouseGrabberItem)
+    if (d->mouseGrabberItem && !event->buttons())
         d->mouseGrabberItem->ungrabMouse();
 }
 
@@ -1258,7 +1258,7 @@ void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
 {
     Q_D(QQuickCanvas);
 #ifdef MOUSE_DEBUG
-    qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
+    qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->localPos() << event->button() << event->buttons();
 #endif
 
     if (!d->mouseGrabberItem && (event->buttons() & event->button()) == event->buttons()) {
@@ -1293,7 +1293,7 @@ void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
 {
     Q_D(QQuickCanvas);
 #ifdef MOUSE_DEBUG
-    qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
+    qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->localPos() << event->button() << event->buttons();
 #endif
 
     if (!d->mouseGrabberItem) {
@@ -1423,7 +1423,7 @@ void QQuickCanvas::wheelEvent(QWheelEvent *event)
 {
     Q_D(QQuickCanvas);
 #ifdef MOUSE_DEBUG
-    qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->pixelDelta() << event->angleDelta();
+    qWarning() << "QQuickCanvas::wheelEvent()" << event->pixelDelta() << event->angleDelta();
 #endif
 
     //if the actual wheel event was accepted, accept the compatability wheel event and return early
index a2522a4..a26c7c9 100644 (file)
@@ -193,9 +193,9 @@ QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj)
 #endif // QT_NO_DRAGANDDROP
 
 QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
-: enabled(true), hovered(false), pressed(false), longPress(false),
+: enabled(true), hovered(false), longPress(false),
   moved(false), dragX(true), dragY(true), stealMouse(false), doubleClick(false), preventStealing(false),
-  propagateComposedEvents(false)
+  propagateComposedEvents(false), pressed(0)
 #ifndef QT_NO_DRAGANDDROP
   , drag(0)
 #endif
@@ -693,12 +693,14 @@ void QQuickMouseArea::setPropagateComposedEvents(bool prevent)
 
     \snippet qml/mousearea/mousearea.qml mousebuttons
 
+    \note this property only handles buttons specified in \l acceptedButtons.
+
     \sa acceptedButtons
 */
 Qt::MouseButtons QQuickMouseArea::pressedButtons() const
 {
     Q_D(const QQuickMouseArea);
-    return d->lastButtons;
+    return d->pressed;
 }
 
 void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
@@ -706,9 +708,9 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
     Q_D(QQuickMouseArea);
     d->moved = false;
     d->stealMouse = d->preventStealing;
-    if (!d->enabled)
+    if (!d->enabled || !(event->button() & acceptedMouseButtons())) {
         QQuickItem::mousePressEvent(event);
-    else {
+    else {
         d->longPress = false;
         d->saveEvent(event);
 #ifndef QT_NO_DRAGANDDROP
@@ -719,7 +721,7 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
         d->startScene = event->windowPos();
         d->pressAndHoldTimer.start(PressAndHoldDelay, this);
         setKeepMouseGrab(d->stealMouse);
-        event->setAccepted(setPressed(true));
+        event->setAccepted(setPressed(event->button(), true));
 
 #ifndef QT_NO_DRAGANDDROP
         if (d->drag) {
@@ -827,19 +829,21 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
         QQuickItem::mouseReleaseEvent(event);
     } else {
         d->saveEvent(event);
-        setPressed(false);
+        setPressed(event->button(), false);
+        if (!d->pressed) {
+            // no other buttons are pressed
 #ifndef QT_NO_DRAGANDDROP
-        if (d->drag)
-            d->drag->setActive(false);
+            if (d->drag)
+                d->drag->setActive(false);
 #endif
-        // If we don't accept hover, we need to reset containsMouse.
-        if (!acceptHoverEvents())
-            setHovered(false);
-        QQuickCanvas *c = canvas();
-        if (c && c->mouseGrabberItem() == this)
-            ungrabMouse();
-        setKeepMouseGrab(false);
-
+            // If we don't accept hover, we need to reset containsMouse.
+            if (!acceptHoverEvents())
+                setHovered(false);
+            QQuickCanvas *c = canvas();
+            if (c && c->mouseGrabberItem() == this)
+                ungrabMouse();
+            setKeepMouseGrab(false);
+        }
     }
     d->doubleClick = false;
 }
@@ -924,11 +928,12 @@ void QQuickMouseArea::ungrabMouse()
     if (d->pressed) {
         // if our mouse grab has been removed (probably by Flickable), fix our
         // state
-        d->pressed = false;
+        d->pressed = 0;
         d->stealMouse = false;
         setKeepMouseGrab(false);
         emit canceled();
         emit pressedChanged();
+        emit pressedButtonsChanged();
         if (d->hovered) {
             d->hovered = false;
             emit hoveredChanged();
@@ -975,15 +980,19 @@ bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
     }
     if (event->type() == QEvent::MouseButtonRelease) {
         if (d->pressed) {
-            d->pressed = false;
-            d->stealMouse = false;
-            if (c && c->mouseGrabberItem() == this)
-                ungrabMouse();
-            emit canceled();
-            emit pressedChanged();
-            if (d->hovered) {
-                d->hovered = false;
-                emit hoveredChanged();
+            d->pressed &= ~event->button();
+            emit pressedButtonsChanged();
+            if (!d->pressed) {
+                // no other buttons are pressed
+                d->stealMouse = false;
+                if (c && c->mouseGrabberItem() == this)
+                    ungrabMouse();
+                emit canceled();
+                emit pressedChanged();
+                if (d->hovered) {
+                    d->hovered = false;
+                    emit hoveredChanged();
+                }
             }
         }
     }
@@ -1116,7 +1125,7 @@ bool QQuickMouseArea::hovered() const
 
 /*!
     \qmlproperty bool QtQuick2::MouseArea::pressed
-    This property holds whether the mouse area is currently pressed.
+    This property holds whether any of the \l acceptedButtons are currently pressed.
 */
 bool QQuickMouseArea::pressed() const
 {
@@ -1176,31 +1185,39 @@ void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
     }
 }
 
-bool QQuickMouseArea::setPressed(bool p)
+bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p)
 {
     Q_D(QQuickMouseArea);
+
 #ifndef QT_NO_DRAGANDDROP
     bool dragged = d->drag && d->drag->active();
 #else
     bool dragged = false;
 #endif
-    bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
+    bool wasPressed = d->pressed & button;
+    bool isclick = wasPressed && p == false && dragged == false && d->hovered == true;
+    Qt::MouseButtons oldPressed = d->pressed;
 
-    if (d->pressed != p) {
-        d->pressed = p;
+    if (wasPressed != p) {
         QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
-        if (d->pressed) {
+        if (p) {
+            d->pressed |= button;
             if (!d->doubleClick)
                 emit pressed(&me);
             me.setPosition(d->lastPos);
             emit mouseXChanged(&me);
             me.setPosition(d->lastPos);
             emit mouseYChanged(&me);
-            emit pressedChanged();
+            if (!oldPressed)
+                emit pressedChanged();
+            emit pressedButtonsChanged();
         } else {
+            d->pressed &= ~button;
             emit released(&me);
             me.setPosition(d->lastPos);
-            emit pressedChanged();
+            if (!d->pressed)
+                emit pressedChanged();
+            emit pressedButtonsChanged();
             if (isclick && !d->longPress && !d->doubleClick){
                 me.setAccepted(d->isClickConnected());
                 emit clicked(&me);
index 14b74f4..8a8de3b 100644 (file)
@@ -135,7 +135,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
     Q_PROPERTY(bool containsMouse READ hovered NOTIFY hoveredChanged)
     Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
     Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
-    Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedChanged)
+    Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedButtonsChanged)
     Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
     Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged)
 #ifndef QT_NO_DRAGANDDROP
@@ -187,6 +187,7 @@ Q_SIGNALS:
     void hoveredChanged();
     void pressedChanged();
     void enabledChanged();
+    void pressedButtonsChanged();
     void acceptedButtonsChanged();
     void hoverEnabledChanged();
 #ifndef QT_NO_CURSOR
@@ -210,7 +211,7 @@ Q_SIGNALS:
 
 protected:
     void setHovered(bool);
-    bool setPressed(bool);
+    bool setPressed(Qt::MouseButton button, bool);
     bool sendMouseEvent(QMouseEvent *event);
 
     virtual void mousePressEvent(QMouseEvent *event);
index 39a0616..aa28da8 100644 (file)
@@ -87,7 +87,6 @@ public:
 
     bool enabled : 1;
     bool hovered : 1;
-    bool pressed : 1;
     bool longPress : 1;
     bool moved : 1;
     bool dragX : 1;
@@ -96,6 +95,7 @@ public:
     bool doubleClick : 1;
     bool preventStealing : 1;
     bool propagateComposedEvents : 1;
+    Qt::MouseButtons pressed;
 #ifndef QT_NO_DRAGANDDROP
     QQuickDrag *drag;
 #endif
diff --git a/tests/auto/quick/qquickmousearea/data/simple.qml b/tests/auto/quick/qquickmousearea/data/simple.qml
new file mode 100644 (file)
index 0000000..56d561e
--- /dev/null
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Rectangle {
+    id: whiteRect
+    width: 200
+    height: 200
+    color: "white"
+    MouseArea {
+        objectName: "mousearea"
+        anchors.fill: parent
+    }
+}
index 686c057..7d42eb2 100644 (file)
@@ -82,6 +82,8 @@ private slots:
     void onWheel();
     void transformedMouseArea_data();
     void transformedMouseArea();
+    void pressedMultipleButtons_data();
+    void pressedMultipleButtons();
 
 private:
     void acceptedButton_data();
@@ -1175,6 +1177,132 @@ void tst_QQuickMouseArea::transformedMouseArea()
     delete canvas;
 }
 
+void tst_QQuickMouseArea::pressedMultipleButtons_data()
+{
+    QTest::addColumn<Qt::MouseButtons>("accepted");
+    QTest::addColumn<QList<Qt::MouseButtons> >("buttons");
+    QTest::addColumn<QList<bool> >("pressed");
+    QTest::addColumn<QList<Qt::MouseButtons> >("pressedButtons");
+    QTest::addColumn<int>("changeCount");
+
+    QList<Qt::MouseButtons> buttons;
+    QList<bool> pressed;
+    QList<Qt::MouseButtons> pressedButtons;
+    buttons << Qt::LeftButton
+            << (Qt::LeftButton | Qt::RightButton)
+            << Qt::LeftButton
+            << 0;
+    pressed << true
+            << true
+            << true
+            << false;
+    pressedButtons << Qt::LeftButton
+            << Qt::LeftButton
+            << Qt::LeftButton
+            << 0;
+    QTest::newRow("Accept Left - Press left, Press Right, Release Right")
+            << Qt::MouseButtons(Qt::LeftButton) << buttons << pressed << pressedButtons << 2;
+
+    buttons.clear();
+    pressed.clear();
+    pressedButtons.clear();
+    buttons << Qt::LeftButton
+            << (Qt::LeftButton | Qt::RightButton)
+            << Qt::RightButton
+            << 0;
+    pressed << true
+            << true
+            << false
+            << false;
+    pressedButtons << Qt::LeftButton
+            << Qt::LeftButton
+            << 0
+            << 0;
+    QTest::newRow("Accept Left - Press left, Press Right, Release Left")
+            << Qt::MouseButtons(Qt::LeftButton) << buttons << pressed << pressedButtons << 2;
+
+    buttons.clear();
+    pressed.clear();
+    pressedButtons.clear();
+    buttons << Qt::LeftButton
+            << (Qt::LeftButton | Qt::RightButton)
+            << Qt::LeftButton
+            << 0;
+    pressed << true
+            << true
+            << true
+            << false;
+    pressedButtons << Qt::LeftButton
+            << (Qt::LeftButton | Qt::RightButton)
+            << Qt::LeftButton
+            << 0;
+    QTest::newRow("Accept Left|Right - Press left, Press Right, Release Right")
+        << (Qt::LeftButton | Qt::RightButton) << buttons << pressed << pressedButtons << 4;
+
+    buttons.clear();
+    pressed.clear();
+    pressedButtons.clear();
+    buttons << Qt::RightButton
+            << (Qt::LeftButton | Qt::RightButton)
+            << Qt::LeftButton
+            << 0;
+    pressed << true
+            << true
+            << false
+            << false;
+    pressedButtons << Qt::RightButton
+            << Qt::RightButton
+            << 0
+            << 0;
+    QTest::newRow("Accept Right - Press Right, Press Left, Release Right")
+            << Qt::MouseButtons(Qt::RightButton) << buttons << pressed << pressedButtons << 2;
+}
+
+void tst_QQuickMouseArea::pressedMultipleButtons()
+{
+    QFETCH(Qt::MouseButtons, accepted);
+    QFETCH(QList<Qt::MouseButtons>, buttons);
+    QFETCH(QList<bool>, pressed);
+    QFETCH(QList<Qt::MouseButtons>, pressedButtons);
+    QFETCH(int, changeCount);
+
+    QQuickView *canvas = createView();
+    canvas->setSource(testFileUrl("simple.qml"));
+    canvas->show();
+    canvas->requestActivateWindow();
+    QVERIFY(canvas->rootObject() != 0);
+
+    QQuickMouseArea *mouseArea = canvas->rootObject()->findChild<QQuickMouseArea *>("mousearea");
+    QVERIFY(mouseArea != 0);
+
+    QSignalSpy pressedSpy(mouseArea, SIGNAL(pressedChanged()));
+    QSignalSpy pressedButtonsSpy(mouseArea, SIGNAL(pressedButtonsChanged()));
+    mouseArea->setAcceptedMouseButtons(accepted);
+
+    QPoint point(10,10);
+
+    int prevButtons = 0;
+    for (int i = 0; i < buttons.count(); ++i) {
+        int btns = buttons.at(i);
+
+        // The windowsysteminterface takes care of sending releases
+        QTest::mousePress(canvas, (Qt::MouseButton)btns, 0, point);
+
+        QCOMPARE(mouseArea->pressed(), pressed.at(i));
+        QCOMPARE(mouseArea->pressedButtons(), pressedButtons.at(i));
+
+        prevButtons = buttons.at(i);
+    }
+
+    QTest::mousePress(canvas, Qt::NoButton, 0, point);
+    QCOMPARE(mouseArea->pressed(), false);
+
+    QCOMPARE(pressedSpy.count(), 2);
+    QCOMPARE(pressedButtonsSpy.count(), changeCount);
+
+    delete canvas;
+}
+
 QTEST_MAIN(tst_QQuickMouseArea)
 
 #include "tst_qquickmousearea.moc"