diff options
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 10 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 24 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene_p.h | 3 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview.cpp | 27 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicswidget.cpp | 5 | ||||
-rw-r--r-- | tests/auto/qgraphicsview/tst_qgraphicsview.cpp | 101 |
6 files changed, 167 insertions, 3 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 5c29e9c..b8ff5b4 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1421,7 +1421,9 @@ void QGraphicsItem::setCursor(const QCursor &cursor) d_ptr->setExtra(QGraphicsItemPrivate::ExtraCursor, qVariantValue<QCursor>(cursorVariant)); d_ptr->hasCursor = 1; if (d_ptr->scene) { + d_ptr->scene->d_func()->allItemsUseDefaultCursor = false; foreach (QGraphicsView *view, d_ptr->scene->views()) { + view->viewport()->setMouseTracking(true); // Note: Some of this logic is duplicated in QGraphicsView's mouse events. if (view->underMouse()) { foreach (QGraphicsItem *itemUnderCursor, view->items(view->mapFromGlobal(QCursor::pos()))) { @@ -2053,7 +2055,13 @@ bool QGraphicsItem::acceptsHoverEvents() const */ void QGraphicsItem::setAcceptHoverEvents(bool enabled) { + if (d_ptr->acceptsHover == quint32(enabled)) + return; d_ptr->acceptsHover = quint32(enabled); + if (d_ptr->acceptsHover && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreHoverEvents) { + d_ptr->scene->d_func()->allItemsIgnoreHoverEvents = false; + d_ptr->scene->d_func()->enableMouseTrackingOnViews(); + } } /*! @@ -2063,7 +2071,7 @@ void QGraphicsItem::setAcceptHoverEvents(bool enabled) */ void QGraphicsItem::setAcceptsHoverEvents(bool enabled) { - d_ptr->acceptsHover = quint32(enabled); + setAcceptHoverEvents(enabled); } /*! diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 0439847..e885238 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -351,6 +351,8 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() dragDropItem(0), enterWidget(0), lastDropAction(Qt::IgnoreAction), + allItemsIgnoreHoverEvents(true), + allItemsUseDefaultCursor(true), painterStateProtection(true), sortCacheEnabled(false), updatingSortCache(false), @@ -1047,6 +1049,12 @@ void QGraphicsScenePrivate::clearKeyboardGrabber() ungrabKeyboard(keyboardGrabberItems.first()); } +void QGraphicsScenePrivate::enableMouseTrackingOnViews() +{ + foreach (QGraphicsView *view, views) + view->viewport()->setMouseTracking(true); +} + /*! Returns all items for the screen position in \a event. */ @@ -2763,6 +2771,8 @@ void QGraphicsScene::clear() d->lastItemCount = 0; d->bspTree.clear(); d->largestUntransformableItem = QRectF(); + d->allItemsIgnoreHoverEvents = true; + d->allItemsUseDefaultCursor = true; } /*! @@ -2927,6 +2937,17 @@ void QGraphicsScene::addItem(QGraphicsItem *item) ++d->selectionChanging; int oldSelectedItemSize = d->selectedItems.size(); + // Enable mouse tracking if the item accepts hover events or has a cursor set. + if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) { + d->allItemsIgnoreHoverEvents = false; + d->enableMouseTrackingOnViews(); + } + if (d->allItemsUseDefaultCursor && item->hasCursor()) { + d->allItemsUseDefaultCursor = false; + if (d->allItemsIgnoreHoverEvents) // already enabled otherwise + d->enableMouseTrackingOnViews(); + } + // Update selection lists if (item->isSelected()) d->selectedItems << item; @@ -4219,6 +4240,9 @@ bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *i */ bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent) { + if (allItemsIgnoreHoverEvents) + return false; + // Find the first item that accepts hover events, reusing earlier // calculated data is possible. if (cachedItemsUnderMouse.isEmpty()) { diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 8af8b28..9ace725 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -168,6 +168,9 @@ public: Qt::DropAction lastDropAction; QList<QGraphicsItem *> cachedItemsUnderMouse; QList<QGraphicsItem *> hoverItems; + bool allItemsIgnoreHoverEvents; + bool allItemsUseDefaultCursor; + void enableMouseTrackingOnViews(); QMap<Qt::MouseButton, QPointF> mouseGrabberButtonDownPos; QMap<Qt::MouseButton, QPointF> mouseGrabberButtonDownScenePos; QMap<Qt::MouseButton, QPoint> mouseGrabberButtonDownScreenPos; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index b41dc66..797c895 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -587,6 +587,10 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event) return; if (!scene) return; + if (scene->d_func()->allItemsIgnoreHoverEvents && scene->d_func()->allItemsUseDefaultCursor + && !event->buttons()) { // forward event to the scene if something is pressed. + return; // No need to process this event further. + } QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove); mouseEvent.setWidget(q->viewport()); @@ -614,6 +618,16 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event) } #ifndef QT_NO_CURSOR + // If all the items ignore hover events, we don't look-up any items + // in QGraphicsScenePrivate::dispatchHoverEvent, hence the + // cachedItemsUnderMouse list will be empty. We therefore do the look-up + // for cursor items here if not all items use the default cursor. + if (scene->d_func()->allItemsIgnoreHoverEvents && !scene->d_func()->allItemsUseDefaultCursor + && scene->d_func()->cachedItemsUnderMouse.isEmpty()) { + scene->d_func()->cachedItemsUnderMouse = scene->d_func()->itemsAtPosition(mouseEvent.screenPos(), + mouseEvent.scenePos(), + mouseEvent.widget()); + } // Find the topmost item under the mouse with a cursor. foreach (QGraphicsItem *item, scene->d_func()->cachedItemsUnderMouse) { if (item->hasCursor()) { @@ -1688,6 +1702,12 @@ void QGraphicsView::setScene(QGraphicsScene *scene) d->recalculateContentSize(); d->lastCenterPoint = sceneRect().center(); d->keepLastCenterPoint = true; + // We are only interested in mouse tracking if items accept + // hover events or use non-default cursors. + if (!d->scene->d_func()->allItemsIgnoreHoverEvents + || !d->scene->d_func()->allItemsUseDefaultCursor) { + d->viewport->setMouseTracking(true); + } } else { d->recalculateContentSize(); } @@ -2799,7 +2819,12 @@ void QGraphicsView::setupViewport(QWidget *widget) widget->setAutoFillBackground(true); } - widget->setMouseTracking(true); + // We are only interested in mouse tracking if items + // accept hover events or use non-default cursors. + if (d->scene && (!d->scene->d_func()->allItemsIgnoreHoverEvents + || !d->scene->d_func()->allItemsUseDefaultCursor)) { + widget->setMouseTracking(true); + } widget->setAcceptDrops(acceptDrops()); } diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 7f02fb9..2e7d82a 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -1635,6 +1635,11 @@ void QGraphicsWidget::setWindowFlags(Qt::WindowFlags wFlags) else d->scene->d_func()->addPopup(this); } + + if (d->scene && d->scene->d_func()->allItemsIgnoreHoverEvents && d->hasDecoration()) { + d->scene->d_func()->allItemsIgnoreHoverEvents = false; + d->scene->d_func()->enableMouseTrackingOnViews(); + } } /*! diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index 412c6c5..6b3a9d4 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -191,6 +191,7 @@ private slots: void scrollAfterResize_data(); void scrollAfterResize(); void centerOnDirtyItem(); + void mouseTracking(); // task specific tests below me void task172231_untransformableItems(); @@ -2515,7 +2516,8 @@ void tst_QGraphicsView::replayMouseMove() // One mouse event should be translated into one scene event. for (int i = 0; i < 3; ++i) { - sendMouseMove(view.viewport(), view.viewport()->rect().center()); + sendMouseMove(view.viewport(), view.viewport()->rect().center(), + Qt::LeftButton, Qt::MouseButtons(Qt::LeftButton)); QCOMPARE(viewSpy.count(), i + 1); QCOMPARE(sceneSpy.count(), i + 1); } @@ -2705,6 +2707,7 @@ void tst_QGraphicsView::task186827_deleteReplayedItem() MouseMoveCounter view; view.setScene(&scene); view.show(); + view.viewport()->setMouseTracking(true); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif @@ -3048,6 +3051,102 @@ void tst_QGraphicsView::centerOnDirtyItem() QCOMPARE(before, after); } +void tst_QGraphicsView::mouseTracking() +{ + // Mouse tracking should only be automatically enabled if items either accept hover events + // or have a cursor set. We never disable mouse tracking if it is already enabled. + + { // Make sure mouse tracking is disabled by default. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view(&scene); + QVERIFY(!view.viewport()->hasMouseTracking()); + } + + { // Make sure we don't disable mouse tracking in setupViewport/setScene. + QGraphicsView view; + QWidget *viewport = new QWidget; + viewport->setMouseTracking(true); + view.setViewport(viewport); + QVERIFY(viewport->hasMouseTracking()); + + QGraphicsScene scene(-10000, -10000, 20000, 20000); + view.setScene(&scene); + QVERIFY(viewport->hasMouseTracking()); + } + + // Make sure we enable mouse tracking when having items that accept hover events. + { + // Adding an item to the scene after the scene is set on the view. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view(&scene); + + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setAcceptHoverEvents(true); + scene.addItem(item); + QVERIFY(view.viewport()->hasMouseTracking()); + } + { + // Adding an item to the scene before the scene is set on the view. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setAcceptHoverEvents(true); + scene.addItem(item); + + QGraphicsView view(&scene); + QVERIFY(view.viewport()->hasMouseTracking()); + } + { + // QGraphicsWidget implicitly accepts hover if it has window decoration. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view(&scene); + + QGraphicsWidget *widget = new QGraphicsWidget; + scene.addItem(widget); + QVERIFY(!view.viewport()->hasMouseTracking()); + // Enable window decoraton. + widget->setWindowFlags(Qt::Window | Qt::WindowTitleHint); + QVERIFY(view.viewport()->hasMouseTracking()); + } + + // Make sure we enable mouse tracking when having items with a cursor set. + { + // Adding an item to the scene after the scene is set on the view. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view(&scene); + + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setCursor(Qt::CrossCursor); + scene.addItem(item); + QVERIFY(view.viewport()->hasMouseTracking()); + } + { + // Adding an item to the scene before the scene is set on the view. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setCursor(Qt::CrossCursor); + scene.addItem(item); + + QGraphicsView view(&scene); + QVERIFY(view.viewport()->hasMouseTracking()); + } + + // Make sure we propagate mouse tracking to all views. + { + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view1(&scene); + QGraphicsView view2(&scene); + QGraphicsView view3(&scene); + + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setCursor(Qt::CrossCursor); + scene.addItem(item); + + QVERIFY(view1.viewport()->hasMouseTracking()); + QVERIFY(view2.viewport()->hasMouseTracking()); + QVERIFY(view3.viewport()->hasMouseTracking()); + } +} + QTEST_MAIN(tst_QGraphicsView) #include "tst_qgraphicsview.moc" #endif |