diff options
-rw-r--r-- | src/declarative/items/qsgcanvas.cpp | 62 | ||||
-rw-r--r-- | src/declarative/items/qsgcanvas_p.h | 4 | ||||
-rw-r--r-- | src/declarative/items/qsgitem.cpp | 19 | ||||
-rw-r--r-- | src/declarative/items/qsgmousearea.cpp | 2 | ||||
-rw-r--r-- | tests/auto/declarative/qsgmousearea/data/hoverPropagation.qml | 54 | ||||
-rw-r--r-- | tests/auto/declarative/qsgmousearea/tst_qsgmousearea.cpp | 26 |
6 files changed, 140 insertions, 27 deletions
diff --git a/src/declarative/items/qsgcanvas.cpp b/src/declarative/items/qsgcanvas.cpp index ecb4e2b524..2efdd50c73 100644 --- a/src/declarative/items/qsgcanvas.cpp +++ b/src/declarative/items/qsgcanvas.cpp @@ -422,7 +422,6 @@ QSGCanvasPrivate::QSGCanvasPrivate() : rootItem(0) , activeFocusItem(0) , mouseGrabberItem(0) - , hoverItem(0) , dirtyItemList(0) , context(0) , contextFailed(false) @@ -955,17 +954,19 @@ QSGItem *QSGCanvas::mouseGrabberItem() const } -void QSGCanvasPrivate::clearHover() +bool QSGCanvasPrivate::clearHover() { Q_Q(QSGCanvas); - if (!hoverItem) - return; + if (hoverItems.isEmpty()) + return false; QPointF pos = q->mapFromGlobal(QCursor::pos()); - QSGItem *item = hoverItem; - hoverItem = 0; - sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QApplication::keyboardModifiers(), true); + bool accepted = false; + foreach (QSGItem* item, hoverItems) + accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QApplication::keyboardModifiers(), true) || accepted; + hoverItems.clear(); + return accepted; } @@ -1205,11 +1206,7 @@ void QSGCanvas::mouseMoveEvent(QMouseEvent *event) bool delivered = d->deliverHoverEvent(d->rootItem, event->pos(), last, event->modifiers(), accepted); if (!delivered) { //take care of any exits - if (d->hoverItem) { - QSGItem *item = d->hoverItem; - d->hoverItem = 0; - accepted = d->sendHoverEvent(QEvent::HoverLeave, item, event->pos(), last, event->modifiers(), accepted); - } + accepted = d->clearHover(); } event->setAccepted(accepted); return; @@ -1247,20 +1244,43 @@ bool QSGCanvasPrivate::deliverHoverEvent(QSGItem *item, const QPointF &scenePos, if (itemPrivate->hoverEnabled) { QPointF p = item->mapFromScene(scenePos); if (QRectF(0, 0, item->width(), item->height()).contains(p)) { - if (hoverItem == item) { + if (!hoverItems.isEmpty() && hoverItems[0] == item) { //move accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted); } else { - //exit from previous - if (hoverItem) { - QSGItem *item = hoverItem; - hoverItem = 0; - accepted = sendHoverEvent(QEvent::HoverLeave, item, scenePos, lastScenePos, modifiers, accepted); + QList<QSGItem*> parents; + QSGItem* parent = item; + parents << item; + while ((parent = parent->parentItem())) + parents << parent; + + //exit from previous (excepting ancestors) + while (!hoverItems.isEmpty() && !parents.contains(hoverItems[0])){ + sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted); + hoverItems.removeFirst(); } - //enter new item - hoverItem = item; - accepted = sendHoverEvent(QEvent::HoverEnter, item, scenePos, lastScenePos, modifiers, accepted); + if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item + accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted); + } else { + //enter any ancestors that also wish to be hovered and aren't + int startIdx = -1; + if (!hoverItems.isEmpty()) + startIdx = parents.indexOf(hoverItems[0]); + if (startIdx == -1) + startIdx = parents.count() - 1; + + for (int i = startIdx; i >= 0; i--) { + if (QSGItemPrivate::get(parents[i])->hoverEnabled) { + hoverItems.prepend(parents[i]); + sendHoverEvent(QEvent::HoverEnter, parents[i], scenePos, lastScenePos, modifiers, accepted); + } + } + + //enter new item + hoverItems.prepend(item); + accepted = sendHoverEvent(QEvent::HoverEnter, item, scenePos, lastScenePos, modifiers, accepted); + } } return true; } diff --git a/src/declarative/items/qsgcanvas_p.h b/src/declarative/items/qsgcanvas_p.h index 20fc332e1b..d26b311e59 100644 --- a/src/declarative/items/qsgcanvas_p.h +++ b/src/declarative/items/qsgcanvas_p.h @@ -117,11 +117,11 @@ public: bool deliverHoverEvent(QSGItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted); bool sendHoverEvent(QEvent::Type, QSGItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool accepted); - void clearHover(); + bool clearHover(); void deliverDragEvent(QSGDragEvent *); bool deliverDragEvent(QSGItem *item, QSGDragEvent *); - QDeclarativeGuard<QSGItem> hoverItem; + QList<QSGItem*> hoverItems; enum FocusOption { DontChangeFocusProperty = 0x01, }; diff --git a/src/declarative/items/qsgitem.cpp b/src/declarative/items/qsgitem.cpp index 043c568a82..ef77bfda02 100644 --- a/src/declarative/items/qsgitem.cpp +++ b/src/declarative/items/qsgitem.cpp @@ -1161,6 +1161,8 @@ void QSGItemPrivate::initCanvas(InitializationState *state, QSGCanvas *c) c->itemsToPolish.remove(q); if (c->mouseGrabberItem == q) c->mouseGrabberItem = 0; + if ( hoverEnabled ) + c->hoverItems.removeAll(q); } canvas = c; @@ -3021,8 +3023,21 @@ void QSGItem::setAcceptHoverEvents(bool enabled) Q_D(QSGItem); d->hoverEnabled = enabled; - if (d->canvas && d->hoverEnabled && !d->canvas->hasMouseTracking()) - d->canvas->setMouseTracking(true); + if (d->canvas){ + QSGCanvasPrivate *c = QSGCanvasPrivate::get(d->canvas); + if (d->hoverEnabled){ + if (!d->canvas->hasMouseTracking()) + d->canvas->setMouseTracking(true); + if (isUnderMouse()) + c->hoverItems.prepend(this); + c->sendHoverEvent(QEvent::HoverEnter, this, c->lastMousePosition, c->lastMousePosition, + QApplication::keyboardModifiers(), true); + } else { + c->hoverItems.removeAll(this); + c->sendHoverEvent(QEvent::HoverLeave, this, c->lastMousePosition, c->lastMousePosition, + QApplication::keyboardModifiers(), true); + } + } } void QSGItem::grabMouse() diff --git a/src/declarative/items/qsgmousearea.cpp b/src/declarative/items/qsgmousearea.cpp index ac577a4810..88a617fd71 100644 --- a/src/declarative/items/qsgmousearea.cpp +++ b/src/declarative/items/qsgmousearea.cpp @@ -834,8 +834,6 @@ void QSGMouseArea::setHoverEnabled(bool h) setAcceptHoverEvents(h); emit hoverEnabledChanged(); - if (d->hovered != isUnderMouse()) - setHovered(!d->hovered); } bool QSGMouseArea::hovered() const diff --git a/tests/auto/declarative/qsgmousearea/data/hoverPropagation.qml b/tests/auto/declarative/qsgmousearea/data/hoverPropagation.qml new file mode 100644 index 0000000000..c47c794132 --- /dev/null +++ b/tests/auto/declarative/qsgmousearea/data/hoverPropagation.qml @@ -0,0 +1,54 @@ +import QtQuick 2.0 + +Item{ + width: 400 + height: 200 + property bool point1: ma2.containsMouse && !ma1.containsMouse + property bool point2: ma3.containsMouse && ma4.containsMouse + Rectangle{ + width: 200 + height: 200 + color: ma1.containsMouse ? "red" : "white" + MouseArea{ + id: ma1 + hoverEnabled: true + anchors.fill: parent + } + Rectangle{ + width: 100 + height: 100 + color: ma2.containsMouse ? "blue" : "white" + MouseArea{ + id: ma2 + hoverEnabled: true + anchors.fill: parent + } + } + } + + Item{ + x:200 + Rectangle{ + width: 200 + height: 200 + color: ma3.containsMouse ? "yellow" : "white" + Rectangle{ + width: 100 + height: 100 + color: ma4.containsMouse ? "green" : "white" + } + } + MouseArea{ + id: ma3 + hoverEnabled: true + width: 200 + height: 200 + MouseArea{ + id: ma4 + width: 100 + height: 100 + hoverEnabled: true + } + } + } +} diff --git a/tests/auto/declarative/qsgmousearea/tst_qsgmousearea.cpp b/tests/auto/declarative/qsgmousearea/tst_qsgmousearea.cpp index 8e711e6ceb..e9788cd147 100644 --- a/tests/auto/declarative/qsgmousearea/tst_qsgmousearea.cpp +++ b/tests/auto/declarative/qsgmousearea/tst_qsgmousearea.cpp @@ -75,6 +75,7 @@ private slots: void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); void hoverPosition(); + void hoverPropagation(); private: QSGView *createView(); @@ -741,6 +742,31 @@ void tst_QSGMouseArea::hoverPosition() delete canvas; } +void tst_QSGMouseArea::hoverPropagation() +{ + //QTBUG-18175, to behave like GV did. + QSGView *canvas = createView(); + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/hoverPropagation.qml")); + + QSGItem *root = canvas->rootObject(); + QVERIFY(root != 0); + + QCOMPARE(root->property("point1").toBool(), false); + QCOMPARE(root->property("point2").toBool(), false); + + QMouseEvent moveEvent(QEvent::MouseMove, QPoint(32, 32), Qt::NoButton, Qt::NoButton, 0); + QApplication::sendEvent(canvas, &moveEvent); + QCOMPARE(root->property("point1").toBool(), true); + QCOMPARE(root->property("point2").toBool(), false); + + QMouseEvent moveEvent2(QEvent::MouseMove, QPoint(232, 32), Qt::NoButton, Qt::NoButton, 0); + QApplication::sendEvent(canvas, &moveEvent2); + QCOMPARE(root->property("point1").toBool(), false); + QCOMPARE(root->property("point2").toBool(), true); + + delete canvas; +} + QTEST_MAIN(tst_QSGMouseArea) #include "tst_qsgmousearea.moc" |