summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview/qgraphicsscene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/graphicsview/qgraphicsscene.cpp')
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp212
1 files changed, 115 insertions, 97 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 7eb49e9e76..d004ed23b4 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -334,7 +334,6 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
updateAll(false),
calledEmitUpdated(false),
selectionChanging(0),
- dirtyItemResetPending(false),
regenerateIndex(true),
purgePending(false),
indexTimerId(0),
@@ -678,31 +677,81 @@ void QGraphicsScenePrivate::_q_polishItems()
unpolishedItems.clear();
}
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::_q_resetDirtyItems()
+void QGraphicsScenePrivate::_q_processDirtyItems()
{
+ Q_Q(QGraphicsScene);
+ if (dirtyItems.isEmpty())
+ return;
+
+ if (updateAll) {
+ for (int i = 0; i < dirtyItems.size(); ++i)
+ resetDirtyItem(dirtyItems.at(i));
+ dirtyItems.clear();
+ return;
+ }
+
+ const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask);
for (int i = 0; i < dirtyItems.size(); ++i) {
QGraphicsItem *item = dirtyItems.at(i);
- item->d_ptr->dirty = 0;
- item->d_ptr->dirtyChildren = 0;
+ if (useCompatUpdate && !item->d_ptr->itemIsUntransformable()
+ && qFuzzyIsNull(item->boundingRegionGranularity())) {
+ // This block of code is kept for compatibility. Since 4.5, by default
+ // QGraphicsView does not connect the signal and we use the below
+ // method of delivering updates.
+ q->update(item->sceneBoundingRect());
+ resetDirtyItem(item);
+ continue;
+ }
+
+ QRectF dirtyRect;
+ bool uninitializedDirtyRect = true;
+
+ for (int j = 0; j < views.size(); ++j) {
+ QGraphicsView *view = views.at(j);
+ QGraphicsViewPrivate *viewPrivate = view->d_func();
+ if (viewPrivate->fullUpdatePending)
+ continue;
+ switch (viewPrivate->viewportUpdateMode) {
+ case QGraphicsView::NoViewportUpdate:
+ continue;
+ case QGraphicsView::FullViewportUpdate:
+ view->viewport()->update();
+ viewPrivate->fullUpdatePending = 1;
+ continue;
+ default:
+ break;
+ }
+
+ if (uninitializedDirtyRect) {
+ dirtyRect = adjustedItemBoundingRect(item);
+ if (!item->d_ptr->dirty) {
+ _q_adjustRect(&item->d_ptr->needsRepaint);
+ dirtyRect &= item->d_ptr->needsRepaint;
+ }
+
+ if (item->d_ptr->dirtyChildren && !item->d_ptr->children.isEmpty()
+ && !item->d_ptr->childrenClippedToShape()) {
+ QRectF childrenBounds = item->childrenBoundingRect();
+ _q_adjustRect(&childrenBounds);
+ dirtyRect |= childrenBounds;
+ }
+ uninitializedDirtyRect = false;
+ }
+
+ if (item->d_ptr->paintedViewBoundingRectsNeedRepaint)
+ viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport));
+
+ if (!item->d_ptr->hasBoundingRegionGranularity)
+ viewPrivate->updateRect(viewPrivate->mapToViewRect(item, dirtyRect));
+ else
+ viewPrivate->updateRegion(viewPrivate->mapToViewRegion(item, dirtyRect));
+ }
+ resetDirtyItem(item);
}
- dirtyItems.clear();
- dirtyItemResetPending = false;
-}
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::resetDirtyItemsLater()
-{
- Q_Q(QGraphicsScene);
- if (dirtyItemResetPending)
- return;
- // dirtyItems.reserve(indexedItems.size() + unindexedItems.size());
- dirtyItemResetPending = true;
- QMetaObject::invokeMethod(q, "_q_resetDirtyItems", Qt::QueuedConnection);
+ dirtyItems.clear();
+ for (int i = 0; i < views.size(); ++i)
+ views.at(i)->d_func()->processPendingUpdates();
}
/*!
@@ -761,10 +810,9 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item)
// Update selected & hovered item bookkeeping
selectedItems.remove(item);
hoverItems.removeAll(item);
- pendingUpdateItems.removeAll(item);
cachedItemsUnderMouse.removeAll(item);
unpolishedItems.removeAll(item);
- dirtyItems.removeAll(item);
+ removeFromDirtyItems(item);
//We remove all references of item from the sceneEventFilter arrays
QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin();
@@ -3319,7 +3367,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *item)
d->pendingUpdateItems.removeAll(item);
d->cachedItemsUnderMouse.removeAll(item);
d->unpolishedItems.removeAll(item);
- d->dirtyItems.removeAll(item);
+ d->removeFromDirtyItems(item);
//We remove all references of item from the sceneEventFilter arrays
QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = d->sceneEventFilters.begin();
@@ -3330,11 +3378,6 @@ void QGraphicsScene::removeItem(QGraphicsItem *item)
++iterator;
}
-
- //Ensure dirty flag have the correct default value so the next time it will be added it will receive updates
- item->d_func()->dirty = 0;
- item->d_func()->dirtyChildren = 0;
-
// Remove all children recursively
foreach (QGraphicsItem *child, item->children())
removeItem(child);
@@ -5050,7 +5093,9 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
}
QRectF brect = item->boundingRect();
_q_adjustRect(&brect);
- viewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1) & exposedRegion.boundingRect();
+ const QRect paintedViewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1);
+ item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect);
+ viewBoundingRect = paintedViewBoundingRect & exposedRegion.boundingRect();
} else {
transform = parentTransform;
}
@@ -5117,6 +5162,44 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
painter->restore();
}
+void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
+ bool maybeDirtyClipPath, bool force, bool ignoreOpacity)
+{
+ Q_ASSERT(item);
+ if (updateAll)
+ return;
+
+ if (item->d_ptr->discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath,
+ /*ignoreVisibleBit=*/force,
+ /*ignoreDirtyBit=*/false, ignoreOpacity)) {
+ return;
+ }
+
+ const bool fullItemUpdate = rect.isNull();
+ if (!fullItemUpdate && rect.isEmpty())
+ return;
+
+ if (dirtyItems.isEmpty())
+ QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
+
+ if (item->d_ptr->inDirtyList) {
+ if (fullItemUpdate)
+ item->d_ptr->dirty = 1;
+ else if (!item->d_ptr->dirty)
+ item->d_ptr->needsRepaint |= rect;
+ } else {
+ dirtyItems.append(item);
+ item->d_ptr->inDirtyList = 1;
+ if (fullItemUpdate)
+ item->d_ptr->dirty = 1;
+ else if (!item->d_ptr->dirty)
+ item->d_ptr->needsRepaint = rect;
+ }
+
+ if (invalidateChildren)
+ item->d_ptr->dirtyChildren = 1;
+}
+
/*!
Paints the given \a items using the provided \a painter, after the
background has been drawn, and before the foreground has been
@@ -5238,6 +5321,8 @@ void QGraphicsScene::drawItems(QPainter *painter,
// Draw the item
d->drawItemHelper(item, painter, &options[i], widget, d->painterStateProtection);
+ const QRect paintedViewBoundingRect = painter->worldTransform().mapRect(options[i].rect).adjusted(-1, -1, 1, 1);
+ item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect);
if (saveState)
painter->restore();
@@ -5364,73 +5449,6 @@ bool QGraphicsScene::focusNextPrevChild(bool next)
*/
/*!
- \internal
-
- This private function is called by QGraphicsItem, which is a friend of
- QGraphicsScene. It is used by QGraphicsScene to record the rectangles that
- need updating. It also launches a single-shot timer to ensure that
- updated() will be emitted later.
-
- The \a item parameter is the item that changed, and \a rect is the
- area of the item that changed given in item coordinates.
-*/
-void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect)
-{
- Q_D(QGraphicsScene);
- // Deliver the actual update.
- if (!d->updateAll) {
- if (d->views.isEmpty() || ((d->connectedSignals & d->changedSignalMask) && !item->d_ptr->itemIsUntransformable()
- && qFuzzyIsNull(item->boundingRegionGranularity()))) {
- // This block of code is kept for compatibility. Since 4.5, by default
- // QGraphicsView does not connect the signal and we use the below
- // method of delivering updates.
- update(item->sceneBoundingRect());
- } else {
- // ### Remove _q_adjustedRects().
- QRectF boundingRect(adjustedItemBoundingRect(item));
- if (!rect.isNull()) {
- QRectF adjustedRect(rect);
- _q_adjustRect(&adjustedRect);
- boundingRect &= adjustedRect;
- }
-
- // Update each view directly.
- for (int i = 0; i < d->views.size(); ++i)
- d->views.at(i)->d_func()->itemUpdated(item, boundingRect);
- }
- }
- if (item->d_ptr->dirty) {
- d->dirtyItems << item;
- d->resetDirtyItemsLater();
- }
-
- if (!item->isVisible())
- return; // Hiding an item won't effect the largestUntransformableItem/sceneRect.
-
- // Update d->largestUntransformableItem by mapping this item's bounding
- // rect back to the topmost untransformable item's untransformed
- // coordinate system (which sort of equals the 1:1 coordinate system of an
- // untransformed view).
- if (item->d_ptr->itemIsUntransformable()) {
- QGraphicsItem *parent = item;
- while (parent && (parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations))
- parent = parent->parentItem();
- d->largestUntransformableItem |= item->mapToItem(parent, item->boundingRect()).boundingRect();
- }
-
- // Only track the automatically growing scene rect if the scene has no
- // defined scene rect.
- if (!d->hasSceneRect) {
- QRectF oldGrowingItemsBoundingRect = d->growingItemsBoundingRect;
- QRectF adjustedItemSceneBoundingRect(item->sceneBoundingRect());
- _q_adjustRect(&adjustedItemSceneBoundingRect);
- d->growingItemsBoundingRect |= adjustedItemSceneBoundingRect;
- if (d->growingItemsBoundingRect != oldGrowingItemsBoundingRect)
- emit sceneRectChanged(d->growingItemsBoundingRect);
- }
-}
-
-/*!
\since 4.4
Returns the scene's style, or the same as QApplication::style() if the