diff options
Diffstat (limited to 'src/widgets/graphicsview/qgraphicsscene.cpp')
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscene.cpp | 168 |
1 files changed, 69 insertions, 99 deletions
diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index 0eceaeacb2..634c0797b9 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only /*! \class QGraphicsScene @@ -222,7 +186,6 @@ #include <QtCore/qrect.h> #include <QtCore/qset.h> #include <QtCore/qstack.h> -#include <QtCore/qtimer.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/QMetaMethod> #include <QtWidgets/qapplication.h> @@ -244,6 +207,7 @@ #include <QtGui/qinputmethod.h> #include <private/qapplication_p.h> #include <private/qevent_p.h> +#include <QtGui/private/qeventpoint_p.h> #include <private/qobject_p.h> #if QT_CONFIG(graphicseffect) #include <private/qgraphicseffect_p.h> @@ -251,6 +215,8 @@ #include <private/qgesturemanager_p.h> #include <private/qpathclipper_p.h> +#include <QtCore/qpointer.h> + // #define GESTURE_DEBUG #ifndef GESTURE_DEBUG # define DEBUG if (0) qDebug @@ -365,7 +331,7 @@ void QGraphicsScenePrivate::_q_emitUpdated() // needs to happen in order to keep compatibility with the behavior from // Qt 4.4 and backward. if (isSignalConnected(changedSignalIndex)) { - for (auto view : qAsConst(views)) { + for (auto view : std::as_const(views)) { if (!view->d_func()->connectedToScene) { view->d_func()->connectedToScene = true; q->connect(q, SIGNAL(changed(QList<QRectF>)), @@ -377,10 +343,10 @@ void QGraphicsScenePrivate::_q_emitUpdated() updateAll = false; return; } - for (auto view : qAsConst(views)) + for (auto view : std::as_const(views)) view->d_func()->processPendingUpdates(); // It's important that we update all views before we dispatch, hence two for-loops. - for (auto view : qAsConst(views)) + for (auto view : std::as_const(views)) view->d_func()->dispatchPendingUpdateRequests(); return; } @@ -446,7 +412,7 @@ void QGraphicsScenePrivate::_q_polishItems() const QVariant booleanTrueVariant(true); QGraphicsItem *item = nullptr; QGraphicsItemPrivate *itemd = nullptr; - const int oldUnpolishedCount = unpolishedItems.count(); + const int oldUnpolishedCount = unpolishedItems.size(); for (int i = 0; i < oldUnpolishedCount; ++i) { item = unpolishedItems.at(i); @@ -464,7 +430,7 @@ void QGraphicsScenePrivate::_q_polishItems() } } - if (unpolishedItems.count() == oldUnpolishedCount) { + if (unpolishedItems.size() == oldUnpolishedCount) { // No new items were added to the vector. unpolishedItems.clear(); } else { @@ -483,7 +449,7 @@ void QGraphicsScenePrivate::_q_processDirtyItems() Q_ASSERT(calledEmitUpdated); // No need for further processing (except resetting the dirty states). // The growingItemsBoundingRect is updated in _q_emitUpdated. - for (auto topLevelItem : qAsConst(topLevelItems)) + for (auto topLevelItem : std::as_const(topLevelItems)) resetDirtyItem(topLevelItem, /*recursive=*/true); return; } @@ -492,7 +458,7 @@ void QGraphicsScenePrivate::_q_processDirtyItems() const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect; // Process items recursively. - for (auto topLevelItem : qAsConst(topLevelItems)) + for (auto topLevelItem : std::as_const(topLevelItems)) processDirtyItemsRecursive(topLevelItem); dirtyGrowingItemsBoundingRect = false; @@ -502,7 +468,7 @@ void QGraphicsScenePrivate::_q_processDirtyItems() if (wasPendingSceneUpdate) return; - for (auto view : qAsConst(views)) + for (auto view : std::as_const(views)) view->d_func()->processPendingUpdates(); if (calledEmitUpdated) { @@ -513,7 +479,7 @@ void QGraphicsScenePrivate::_q_processDirtyItems() } // Immediately dispatch all pending update requests on the views. - for (auto view : qAsConst(views)) + for (auto view : std::as_const(views)) view->d_func()->dispatchPendingUpdateRequests(); } @@ -556,7 +522,7 @@ void QGraphicsScenePrivate::unregisterScenePosItem(QGraphicsItem *item) */ void QGraphicsScenePrivate::_q_updateScenePosDescendants() { - for (QGraphicsItem *item : qAsConst(scenePosItems)) { + for (QGraphicsItem *item : std::as_const(scenePosItems)) { QGraphicsItem *p = item->d_ptr->parent; while (p) { p->d_ptr->scenePosDescendants = 1; @@ -609,7 +575,7 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) //attributes (e.g. sceneTransform). if (!item->d_ptr->inDestructor) { // Remove all children recursively - for (auto child : qAsConst(item->d_ptr->children)) + for (auto child : std::as_const(item->d_ptr->children)) q->removeItem(child); } @@ -1039,7 +1005,7 @@ void QGraphicsScenePrivate::ungrabMouse(QGraphicsItem *item, bool itemIsDying) void QGraphicsScenePrivate::clearMouseGrabber() { if (!mouseGrabberItems.isEmpty()) - mouseGrabberItems.first()->ungrabMouse(); + mouseGrabberItems.constFirst()->ungrabMouse(); lastMouseGrabberItem = nullptr; } @@ -1115,7 +1081,7 @@ void QGraphicsScenePrivate::clearKeyboardGrabber() void QGraphicsScenePrivate::enableMouseTrackingOnViews() { - for (QGraphicsView *view : qAsConst(views)) + for (QGraphicsView *view : std::as_const(views)) view->viewport()->setMouseTracking(true); } @@ -1378,7 +1344,7 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou // Set focus on the topmost enabled item that can take focus. bool setFocus = false; - for (QGraphicsItem *item : qAsConst(cachedItemsUnderMouse)) { + for (QGraphicsItem *item : std::as_const(cachedItemsUnderMouse)) { if (item->isBlockedByModalPanel() || (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling)) { // Make sure we don't clear focus. @@ -1401,7 +1367,7 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou // Check for scene modality. bool sceneModality = false; - for (auto modalPanel : qAsConst(modalPanels)) { + for (auto modalPanel : std::as_const(modalPanels)) { if (modalPanel->panelModality() == QGraphicsItem::SceneModal) { sceneModality = true; break; @@ -1420,7 +1386,7 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou // candidates one at a time, until the event is accepted. It's accepted by // default, so the receiver has to explicitly ignore it for it to pass // through. - for (QGraphicsItem *item : qAsConst(cachedItemsUnderMouse)) { + for (QGraphicsItem *item : std::as_const(cachedItemsUnderMouse)) { if (!(item->acceptedMouseButtons() & mouseEvent->button())) { // Skip items that don't accept the event's mouse button. continue; @@ -1696,7 +1662,7 @@ QGraphicsScene::~QGraphicsScene() // Remove this scene from all associated views. // Note: d->views is modified by QGraphicsView::setScene, so must make a copy const auto views = d->views; - for (auto view : qAsConst(views)) + for (auto view : std::as_const(views)) view->setScene(nullptr); } @@ -1815,8 +1781,8 @@ void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRect // in reverse order). QList<QGraphicsItem *> itemList = items(sourceRect, Qt::IntersectsItemBoundingRect); QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()]; - const int numItems = itemList.size(); - for (int i = 0; i < numItems; ++i) + const qsizetype numItems = itemList.size(); + for (qsizetype i = 0; i < numItems; ++i) itemArray[numItems - i - 1] = itemList.at(i); itemList.clear(); @@ -1833,7 +1799,7 @@ void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRect // Generate the style options QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems]; - for (int i = 0; i < numItems; ++i) + for (qsizetype i = 0; i < numItems; ++i) itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect()); // Render the scene. @@ -2167,7 +2133,7 @@ QList<QGraphicsItem *> QGraphicsScene::selectedItems() const // Optimization: Lazily removes items that are not selected. QGraphicsScene *that = const_cast<QGraphicsScene *>(this); QSet<QGraphicsItem *> actuallySelectedSet; - for (QGraphicsItem *item : qAsConst(that->d_func()->selectedItems)) { + for (QGraphicsItem *item : std::as_const(that->d_func()->selectedItems)) { if (item->isSelected()) actuallySelectedSet << item; } @@ -2257,7 +2223,7 @@ void QGraphicsScene::setSelectionArea(const QPainterPath &path, switch (selectionOperation) { case Qt::ReplaceSelection: // Deselect all items outside path. - for (QGraphicsItem *item : qAsConst(unselectItems)) { + for (QGraphicsItem *item : std::as_const(unselectItems)) { item->setSelected(false); changed = true; } @@ -2284,11 +2250,18 @@ void QGraphicsScene::clearSelection() // Disable emitting selectionChanged ++d->selectionChanging; - bool changed = !d->selectedItems.isEmpty(); + // iterate over a copy, as clearing selection might invalidate selectedItems + const auto selectedItems = d->selectedItems; + QSet<QGraphicsItem *> stillSelectedSet; - for (QGraphicsItem *item : qAsConst(d->selectedItems)) + for (QGraphicsItem *item : selectedItems) { item->setSelected(false); - d->selectedItems.clear(); + // items might override itemChange to prevent deselection + if (item->isSelected()) + stillSelectedSet << item; + } + const bool changed = stillSelectedSet != selectedItems; + d->selectedItems = stillSelectedSet; // Re-enable emitting selectionChanged() for individual items. --d->selectionChanging; @@ -2445,16 +2418,12 @@ void QGraphicsScene::addItem(QGraphicsItem *item) return; } - // QDeclarativeItems do not rely on initial itemChanged message, as the componentComplete - // function allows far more opportunity for delayed-construction optimization. - if (!item->d_ptr->isDeclarativeItem) { - if (d->unpolishedItems.isEmpty()) { - QMetaMethod method = metaObject()->method(d->polishItemsIndex); - method.invoke(this, Qt::QueuedConnection); - } - d->unpolishedItems.append(item); - item->d_ptr->pendingPolish = true; + if (d->unpolishedItems.isEmpty()) { + QMetaMethod method = metaObject()->method(d->polishItemsIndex); + method.invoke(this, Qt::QueuedConnection); } + d->unpolishedItems.append(item); + item->d_ptr->pendingPolish = true; // Detach this item from its parent if the parent's scene is different // from this scene. @@ -2544,7 +2513,7 @@ void QGraphicsScene::addItem(QGraphicsItem *item) // Add all children recursively item->d_ptr->ensureSortedChildren(); - for (auto child : qAsConst(item->d_ptr->children)) + for (auto child : std::as_const(item->d_ptr->children)) addItem(child); // Resolve font and palette. @@ -2916,7 +2885,7 @@ void QGraphicsScene::setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReas /*! Returns \c true if the scene has focus; otherwise returns \c false. If the scene - has focus, it will will forward key events from QKeyEvent to any item that + has focus, it will forward key events from QKeyEvent to any item that has focus. \sa setFocus(), setFocusItem() @@ -3047,7 +3016,7 @@ void QGraphicsScene::setBackgroundBrush(const QBrush &brush) { Q_D(QGraphicsScene); d->backgroundBrush = brush; - for (QGraphicsView *view : qAsConst(d->views)) { + for (QGraphicsView *view : std::as_const(d->views)) { view->resetCachedContent(); view->viewport()->update(); } @@ -3136,13 +3105,13 @@ void QGraphicsScene::update(const QRectF &rect) d->updatedRects.clear(); if (directUpdates) { // Update all views. - for (auto view : qAsConst(d->views)) + for (auto view : std::as_const(d->views)) view->d_func()->fullUpdatePending = true; } } else { if (directUpdates) { // Update all views. - for (auto view : qAsConst(d->views)) { + for (auto view : std::as_const(d->views)) { if (view->isTransformed()) view->d_func()->updateRectF(view->viewportTransform().mapRect(rect)); else @@ -3283,6 +3252,7 @@ bool QGraphicsScene::event(QEvent *event) // ### this should only be cleared if we received a new mouse move event, // which relies on us fixing the replay mechanism in QGraphicsView. d->cachedItemsUnderMouse.clear(); + break; default: break; } @@ -3803,7 +3773,7 @@ bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEv } QGraphicsItem *item = nullptr; - for (auto tmp : qAsConst(cachedItemsUnderMouse)) { + for (auto tmp : std::as_const(cachedItemsUnderMouse)) { if (itemAcceptsHoverEvents_helper(tmp)) { item = tmp; break; @@ -4426,7 +4396,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte QRegion pixmapExposed; QRectF exposedRect; if (!itemCache->allExposed) { - for (const auto &rect : qAsConst(itemCache->exposed)) { + for (const auto &rect : std::as_const(itemCache->exposed)) { exposedRect |= rect; pixmapExposed += itemToPixmap.mapRect(rect).toAlignedRect(); } @@ -4586,7 +4556,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Map the item's logical expose to pixmap coordinates. QRegion pixmapExposed = scrollExposure; if (!itemCache->allExposed) { - for (const auto &rect : qAsConst(itemCache->exposed)) + for (const auto &rect : std::as_const(itemCache->exposed)) pixmapExposed += itemToPixmap.mapRect(rect).toRect().adjusted(-1, -1, 1, 1); } @@ -4595,10 +4565,10 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte if (itemCache->allExposed) { br = item->boundingRect(); } else { - for (const auto &rect : qAsConst(itemCache->exposed)) + for (const auto &rect : std::as_const(itemCache->exposed)) br |= rect; QTransform pixmapToItem = itemToPixmap.inverted(); - for (const QRect &r : qAsConst(scrollExposure)) + for (const QRect &r : std::as_const(scrollExposure)) br |= pixmapToItem.mapRect(r); } styleOptionTmp = *option; @@ -5005,7 +4975,7 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b return; } - for (auto view : qAsConst(views)) { + for (auto view : std::as_const(views)) { QGraphicsViewPrivate *viewPrivate = view->d_func(); QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport); rect.translate(viewPrivate->dirtyScrollOffset); @@ -5161,7 +5131,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool QRectF dirtyRect; bool uninitializedDirtyRect = true; - for (auto view : qAsConst(views)) { + for (auto view : std::as_const(views)) { QGraphicsViewPrivate *viewPrivate = view->d_func(); QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport]; if (viewPrivate->fullUpdatePending @@ -5219,7 +5189,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool const bool bypassUpdateClip = !itemHasContents && wasDirtyParentViewBoundingRects; if (itemClipsChildrenToShape && !bypassUpdateClip) { // Make sure child updates are clipped to the item's bounding rect. - for (auto view : qAsConst(views)) + for (auto view : std::as_const(views)) view->d_func()->setUpdateClip(item); } if (!dirtyAncestorContainsChildren) { @@ -5229,7 +5199,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool const bool allChildrenDirty = item->d_ptr->allChildrenDirty; const bool parentIgnoresVisible = item->d_ptr->ignoreVisible; const bool parentIgnoresOpacity = item->d_ptr->ignoreOpacity; - for (auto child : qAsConst(item->d_ptr->children)) { + for (auto child : std::as_const(item->d_ptr->children)) { if (wasDirtyParentSceneTransform) child->d_ptr->dirtySceneTransform = 1; if (wasDirtyParentViewBoundingRects) @@ -5249,7 +5219,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool if (itemClipsChildrenToShape) { // Reset updateClip. - for (auto view : qAsConst(views)) + for (auto view : std::as_const(views)) view->d_func()->setUpdateClip(nullptr); } } else if (wasDirtyParentSceneTransform) { @@ -5330,7 +5300,7 @@ void QGraphicsScene::drawItems(QPainter *painter, d->rectAdjust = oldRectAdjust; // Reset discovery bits. - for (auto topLevelItem : qAsConst(topLevelItems)) + for (auto topLevelItem : std::as_const(topLevelItems)) topLevelItem->d_ptr->itemDiscovered = 0; painter->setWorldTransform(viewTransform); @@ -5840,8 +5810,8 @@ void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item, QTouch item->d_ptr->genericMapFromSceneTransform(static_cast<const QWidget *>(touchEvent->target())); for (int i = 0; i < touchEvent->pointCount(); ++i) { - auto &pt = QMutableEventPoint::from(touchEvent->point(i)); - QMutableEventPoint::from(pt).setPosition(mapFromScene.map(pt.scenePosition())); + auto &pt = touchEvent->point(i); + QMutableEventPoint::setPosition(pt, mapFromScene.map(pt.scenePosition())); } } @@ -5849,7 +5819,7 @@ int QGraphicsScenePrivate::findClosestTouchPointId(const QPointF &scenePos) { int closestTouchPointId = -1; qreal closestDistance = qreal(0.); - for (const QEventPoint &touchPoint : qAsConst(sceneCurrentTouchPoints)) { + for (const QEventPoint &touchPoint : std::as_const(sceneCurrentTouchPoints)) { qreal distance = QLineF(scenePos, touchPoint.scenePosition()).length(); if (closestTouchPointId == -1|| distance < closestDistance) { closestTouchPointId = touchPoint.id(); @@ -5999,7 +5969,7 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve // Set focus on the topmost enabled item that can take focus. bool setFocus = false; - for (QGraphicsItem *item : qAsConst(cachedItemsUnderMouse)) { + for (QGraphicsItem *item : std::as_const(cachedItemsUnderMouse)) { if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) { if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) { setFocus = true; @@ -6026,7 +5996,7 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve bool res = false; bool eventAccepted = touchEvent->isAccepted(); - for (QGraphicsItem *item : qAsConst(cachedItemsUnderMouse)) { + for (QGraphicsItem *item : std::as_const(cachedItemsUnderMouse)) { // first, try to deliver the touch event updateTouchPointsForItem(item, touchEvent); bool acceptTouchEvents = item->acceptTouchEvents(); @@ -6058,13 +6028,13 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve void QGraphicsScenePrivate::enableTouchEventsOnViews() { - for (QGraphicsView *view : qAsConst(views)) + for (QGraphicsView *view : std::as_const(views)) view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true); } void QGraphicsScenePrivate::updateInputMethodSensitivityInViews() { - for (auto view : qAsConst(views)) + for (auto view : std::as_const(views)) view->d_func()->updateInputMethodSensitivity(); } @@ -6430,7 +6400,7 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event) } } - for (QGesture *g : qAsConst(startedGestures)) { + for (QGesture *g : std::as_const(startedGestures)) { if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) { DEBUG() << "lets try to cancel some"; // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them @@ -6543,7 +6513,7 @@ void QGraphicsScenePrivate::grabGesture(QGraphicsItem *, Qt::GestureType gesture { (void)QGestureManager::instance(); // create a gesture manager if (!grabbedGestures[gesture]++) { - for (QGraphicsView *view : qAsConst(views)) + for (QGraphicsView *view : std::as_const(views)) view->viewport()->grabGesture(gesture); } } @@ -6555,7 +6525,7 @@ void QGraphicsScenePrivate::ungrabGesture(QGraphicsItem *item, Qt::GestureType g QGraphicsObject *obj = static_cast<QGraphicsObject *>(item); QGestureManager::instance()->cleanupCachedGestures(obj, gesture); if (!--grabbedGestures[gesture]) { - for (QGraphicsView *view : qAsConst(views)) + for (QGraphicsView *view : std::as_const(views)) view->viewport()->ungrabGesture(gesture); } } |