diff options
Diffstat (limited to 'src/gui/graphicsview/qgraphicsscene.cpp')
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 394 |
1 files changed, 280 insertions, 114 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 1f78a18..13f70e5 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -292,15 +292,21 @@ static inline bool QRectF_intersects(const QRectF &s, const QRectF &r) // QRectF::intersects() returns false always if either the source or target // rectangle's width or height are 0. This works around that problem. -static QRectF _q_adjustedRect(const QRectF &rect) +static inline void _q_adjustRect(QRectF *rect) { - static const qreal p = (qreal)0.00001; - QRectF r = rect; - if (!r.width()) - r.adjust(-p, 0, p, 0); - if (!r.height()) - r.adjust(0, -p, 0, p); - return r; + Q_ASSERT(rect); + if (!rect->width()) + rect->adjust(-0.00001, 0, 0.00001, 0); + if (!rect->height()) + rect->adjust(0, -0.00001, 0, 0.00001); +} + +static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item) +{ + Q_ASSERT(item); + QRectF boundingRect(item->boundingRect()); + _q_adjustRect(&boundingRect); + return boundingRect; } static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent) @@ -632,10 +638,11 @@ void QGraphicsScenePrivate::_q_updateLater() */ void QGraphicsScenePrivate::_q_polishItems() { + const QVariant booleanTrueVariant(true); foreach (QGraphicsItem *item, unpolishedItems) { if (!item->d_ptr->explicitlyHidden) { - item->itemChange(QGraphicsItem::ItemVisibleChange, true); - item->itemChange(QGraphicsItem::ItemVisibleHasChanged, true); + item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); + item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant); } if (item->isWidget()) { QEvent event(QEvent::Polish); @@ -690,13 +697,6 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) { Q_Q(QGraphicsScene); - if (QGraphicsItem *parent = item->d_func()->parent) { - QVariant variant; - qVariantSetValue<QGraphicsItem *>(variant, item); - parent->itemChange(QGraphicsItem::ItemChildRemovedChange, variant); - parent->d_func()->children.removeAll(item); - } - // Clear focus on the item to remove any reference in the focusWidget // chain. item->clearFocus(); @@ -740,6 +740,15 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) unpolishedItems.removeAll(item); dirtyItems.removeAll(item); + //We remove all references of item from the sceneEventFilter arrays + QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin(); + while (iterator != sceneEventFilters.end()) { + if (iterator.value() == item || iterator.key() == item) + iterator = sceneEventFilters.erase(iterator); + else + ++iterator; + } + // Remove from scene transform cache int transformIndex = item->d_func()->sceneTransformIndex; if (transformIndex != -1) { @@ -1358,6 +1367,48 @@ QGraphicsWidget *QGraphicsScenePrivate::windowForItem(const QGraphicsItem *item) return 0; } + +QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPointF &pos) const +{ + QList<QGraphicsItem *> items; + + // The index returns a rough estimate of what items are inside the rect. + // Refine it by iterating through all returned items. + QRectF adjustedRect = QRectF(pos, QSize(1,1)); + foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) { + // Find the item's scene transform in a clever way. + QTransform x = item->sceneTransform(); + bool keep = false; + + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + const QRectF br(adjustedItemBoundingRect(item)); + // Rect intersects/contains item's shape + if (QRectF_intersects(adjustedRect, x.mapRect(br))) { + bool ok; + QTransform xinv = x.inverted(&ok); + if (ok) { + if (item->contains(xinv.map(pos))) { + items << item; + keep = true; + } + } + } + + if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) { + // Recurse into children that clip children. + bool ok; + QTransform xinv = x.inverted(&ok); + if (ok) + childItems_helper(&items, item, xinv.map(pos)); + } + } + + sortItems(&items, Qt::AscendingOrder, sortCacheEnabled); + return items; +} + QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QRectF &rect, Qt::ItemSelectionMode mode, Qt::SortOrder order) const @@ -1368,7 +1419,8 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QRectF &rect, // The index returns a rough estimate of what items are inside the rect. // Refine it by iterating through all returned items. - QRectF adjustedRect = _q_adjustedRect(rect); + QRectF adjustedRect(rect); + _q_adjustRect(&adjustedRect); foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) { // Find the item's scene transform in a clever way. QTransform x = item->sceneTransform(); @@ -1377,7 +1429,7 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QRectF &rect, // ### _q_adjustedRect is only needed because QRectF::intersects, // QRectF::contains and QTransform::map() and friends don't work with // flat rectangles. - QRectF br = _q_adjustedRect(item->boundingRect()); + const QRectF br(adjustedItemBoundingRect(item)); if (mode >= Qt::ContainsItemBoundingRect) { // Rect intersects/contains item's bounding rect QRectF mbr = x.mapRect(br); @@ -1392,7 +1444,7 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QRectF &rect, bool ok; QTransform xinv = x.inverted(&ok); if (ok) { - if (path == QPainterPath()) + if (path.isEmpty()) path.addRect(rect); if (itemCollidesWithPath(item, xinv.map(path), mode)) { items << item; @@ -1429,7 +1481,8 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPolygonF &poly { QList<QGraphicsItem *> items; - QRectF polyRect = _q_adjustedRect(polygon.boundingRect()); + QRectF polyRect(polygon.boundingRect()); + _q_adjustRect(&polyRect); QPainterPath path; // The index returns a rough estimate of what items are inside the rect. @@ -1442,7 +1495,7 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPolygonF &poly // ### _q_adjustedRect is only needed because QRectF::intersects, // QRectF::contains and QTransform::map() and friends don't work with // flat rectangles. - QRectF br = _q_adjustedRect(item->boundingRect()); + const QRectF br(adjustedItemBoundingRect(item)); if (mode >= Qt::ContainsItemBoundingRect) { // Polygon contains/intersects item's bounding rect if (path == QPainterPath()) @@ -1487,21 +1540,47 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPainterPath &p Qt::SortOrder order) const { QList<QGraphicsItem *> items; + QRectF pathRect(path.controlPointRect()); + _q_adjustRect(&pathRect); + // The index returns a rough estimate of what items are inside the rect. // Refine it by iterating through all returned items. - foreach (QGraphicsItem *item, estimateItemsInRect(_q_adjustedRect(path.controlPointRect()))) { + foreach (QGraphicsItem *item, estimateItemsInRect(pathRect)) { // Find the item's scene transform in a clever way. QTransform x = item->sceneTransform(); - bool ok; - QTransform xinv = x.inverted(&ok); - if (ok) { - QPainterPath mappedPath = xinv.map(path); - if (itemCollidesWithPath(item, mappedPath, mode)) { + bool keep = false; + + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + const QRectF br(adjustedItemBoundingRect(item)); + if (mode >= Qt::ContainsItemBoundingRect) { + // Path contains/intersects item's bounding rect + if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br))) + || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) { items << item; - if (item->flags() & QGraphicsItem::ItemClipsChildrenToShape) - childItems_helper(&items, item, mappedPath, mode); + keep = true; + } + } else { + // Path contains/intersects item's shape + if (QRectF_intersects(pathRect, x.mapRect(br))) { + bool ok; + QTransform xinv = x.inverted(&ok); + if (ok) { + if (itemCollidesWithPath(item, xinv.map(path), mode)) { + items << item; + keep = true; + } + } } } + + if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) { + bool ok; + QTransform xinv = x.inverted(&ok); + if (ok) + childItems_helper(&items, item, xinv.map(path), mode); + } } if (order != Qt::SortOrder(-1)) @@ -1511,13 +1590,13 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPainterPath &p void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items, const QGraphicsItem *parent, - const QRectF &rect, - Qt::ItemSelectionMode mode) const + const QPointF &pos) const { - QPainterPath path; bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape); - QRectF r = !parentClip ? _q_adjustedRect(rect) : _q_adjustedRect(rect).intersected(_q_adjustedRect(parent->boundingRect())); - if (r.isEmpty()) + if (parentClip && parent->d_ptr->isClippedAway()) + return; + // ### is this needed? + if (parentClip && !parent->boundingRect().contains(pos)) return; QList<QGraphicsItem *> &children = parent->d_ptr->children; @@ -1527,31 +1606,73 @@ void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items, continue; // Skip invisible items and all their children. - if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity(), qreal(0.0))) + if (item->d_ptr->isInvisible()) continue; - // ### _q_adjustedRect is only needed because QRectF::intersects, - // QRectF::contains and QTransform::map() and friends don't work with - // flat rectangles. - QRectF br = _q_adjustedRect(item->boundingRect()); - QRectF mbr = item->mapRectToParent(br); bool keep = false; - if (mode >= Qt::ContainsItemBoundingRect) { - // Rect intersects/contains item's bounding rect - if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr)) - || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(br))) { + if (!item->d_ptr->isClippedAway()) { + if (item->contains(item->mapFromParent(pos))) { items->append(item); keep = true; } - } else { - // Rect intersects/contains item's shape - if (QRectF_intersects(rect, mbr)) { - if (path == QPainterPath()) - path.addRect(rect); - if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + } + + if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) + // Recurse into children. + childItems_helper(items, item, item->mapFromParent(pos)); + } +} + + +void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items, + const QGraphicsItem *parent, + const QRectF &rect, + Qt::ItemSelectionMode mode) const +{ + bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape); + if (parentClip && parent->d_ptr->isClippedAway()) + return; + QRectF adjustedRect(rect); + _q_adjustRect(&adjustedRect); + QRectF r = !parentClip ? adjustedRect : adjustedRect.intersected(adjustedItemBoundingRect(parent)); + if (r.isEmpty()) + return; + + QPainterPath path; + QList<QGraphicsItem *> &children = parent->d_ptr->children; + for (int i = 0; i < children.size(); ++i) { + QGraphicsItem *item = children.at(i); + if (item->d_ptr->hasTransform && !item->transform().isInvertible()) + continue; + + // Skip invisible items and all their children. + if (item->d_ptr->isInvisible()) + continue; + + bool keep = false; + if (!item->d_ptr->isClippedAway()) { + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + const QRectF br(adjustedItemBoundingRect(item)); + QRectF mbr = item->mapRectToParent(br); + if (mode >= Qt::ContainsItemBoundingRect) { + // Rect intersects/contains item's bounding rect + if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr)) + || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(br))) { items->append(item); keep = true; } + } else { + // Rect intersects/contains item's shape + if (QRectF_intersects(rect, mbr)) { + if (path == QPainterPath()) + path.addRect(rect); + if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + items->append(item); + keep = true; + } + } } } @@ -1568,18 +1689,22 @@ void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items, } } + void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items, const QGraphicsItem *parent, const QPolygonF &polygon, Qt::ItemSelectionMode mode) const { - QPainterPath path; bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape); - QRectF polyRect = _q_adjustedRect(polygon.boundingRect()); - QRectF r = !parentClip ? polyRect : polyRect.intersected(_q_adjustedRect(parent->boundingRect())); + if (parentClip && parent->d_ptr->isClippedAway()) + return; + QRectF polyRect(polygon.boundingRect()); + _q_adjustRect(&polyRect); + QRectF r = !parentClip ? polyRect : polyRect.intersected(adjustedItemBoundingRect(parent)); if (r.isEmpty()) return; + QPainterPath path; QList<QGraphicsItem *> &children = parent->d_ptr->children; for (int i = 0; i < children.size(); ++i) { QGraphicsItem *item = children.at(i); @@ -1587,32 +1712,34 @@ void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items, continue; // Skip invisible items. - if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity() + 1, qreal(1.0))) + if (item->d_ptr->isInvisible()) continue; - // ### _q_adjustedRect is only needed because QRectF::intersects, - // QRectF::contains and QTransform::map() and friends don't work with - // flat rectangles. - QRectF br = _q_adjustedRect(item->boundingRect()); bool keep = false; - if (mode >= Qt::ContainsItemBoundingRect) { - // Polygon contains/intersects item's bounding rect - if (path == QPainterPath()) - path.addPolygon(polygon); - if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br))) - || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) { - items->append(item); - keep = true; - } - } else { - // Polygon contains/intersects item's shape - if (QRectF_intersects(polyRect, item->mapRectToParent(br))) { + if (!item->d_ptr->isClippedAway()) { + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + const QRectF br(adjustedItemBoundingRect(item)); + if (mode >= Qt::ContainsItemBoundingRect) { + // Polygon contains/intersects item's bounding rect if (path == QPainterPath()) path.addPolygon(polygon); - if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br))) + || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) { items->append(item); keep = true; } + } else { + // Polygon contains/intersects item's shape + if (QRectF_intersects(polyRect, item->mapRectToParent(br))) { + if (path == QPainterPath()) + path.addPolygon(polygon); + if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + items->append(item); + keep = true; + } + } } } @@ -1629,30 +1756,52 @@ void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items, Qt::ItemSelectionMode mode) const { bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape); - QPainterPath intersectedPath = !parentClip ? path : path.intersected(parent->shape()); - if (intersectedPath.isEmpty()) + if (parentClip && parent->d_ptr->isClippedAway()) + return; + QRectF pathRect(path.boundingRect()); + _q_adjustRect(&pathRect); + QRectF r = !parentClip ? pathRect : pathRect.intersected(adjustedItemBoundingRect(parent)); + if (r.isEmpty()) return; QList<QGraphicsItem *> &children = parent->d_ptr->children; for (int i = 0; i < children.size(); ++i) { QGraphicsItem *item = children.at(i); + if (item->d_ptr->hasTransform && !item->transform().isInvertible()) + continue; // Skip invisible items. - if (!item->d_ptr->visible || qFuzzyCompare(item->effectiveOpacity(), qreal(0.0))) + if (item->d_ptr->isInvisible()) continue; - QTransform x = item->sceneTransform(); - - bool ok; - QTransform xinv = x.inverted(&ok); - if (ok) { - QPainterPath mappedPath = xinv.map(path); - if (itemCollidesWithPath(item, mappedPath, mode)) { - items->append(item); - if (!item->d_ptr->children.isEmpty()) - childItems_helper(items, item, mappedPath, mode); + bool keep = false; + if (!item->d_ptr->isClippedAway()) { + // ### _q_adjustedRect is only needed because QRectF::intersects, + // QRectF::contains and QTransform::map() and friends don't work with + // flat rectangles. + const QRectF br(adjustedItemBoundingRect(item)); + if (mode >= Qt::ContainsItemBoundingRect) { + // Polygon contains/intersects item's bounding rect + if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br))) + || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) { + items->append(item); + keep = true; + } + } else { + // Path contains/intersects item's shape + if (QRectF_intersects(pathRect, item->mapRectToParent(br))) { + if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) { + items->append(item); + keep = true; + } + } } } + + if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) { + // Recurse into children that clip children. + childItems_helper(items, item, item->mapFromParent(path), mode); + } } } @@ -2326,17 +2475,8 @@ QList<QGraphicsItem *> QGraphicsScene::items() const */ QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const { - QList<QGraphicsItem *> itemsAtPoint; - - // Find all items within a 1x1 rect area starting at pos. This can be - // inefficient for scenes that use small coordinates (like unity - // coordinates), or for detailed graphs. ### The index should support - // fetching items at a pos to avoid this limitation. - foreach (QGraphicsItem *item, items(QRectF(pos, QSizeF(1, 1)), Qt::IntersectsItemBoundingRect)) { - if (item->contains(item->mapFromScene(pos))) - itemsAtPoint << item; - } - return itemsAtPoint; + Q_D(const QGraphicsScene); + return d->items_helper(pos); } @@ -2723,8 +2863,9 @@ void QGraphicsScene::addItem(QGraphicsItem *item) // Notify the item that its scene is changing, and allow the item to // react. - QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(item->itemChange(QGraphicsItem::ItemSceneChange, - qVariantFromValue<QGraphicsScene *>(this))); + const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, + qVariantFromValue<QGraphicsScene *>(this))); + QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(newSceneVariant); if (targetScene != this) { if (targetScene && item->scene() != targetScene) targetScene->addItem(item); @@ -2818,7 +2959,7 @@ void QGraphicsScene::addItem(QGraphicsItem *item) emit selectionChanged(); // Deliver post-change notification - item->itemChange(QGraphicsItem::ItemSceneHasChanged, qVariantFromValue<QGraphicsScene *>(this)); + item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); } /*! @@ -3082,8 +3223,9 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) // Notify the item that it's scene is changing to 0, allowing the item to // react. - QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(item->itemChange(QGraphicsItem::ItemSceneChange, - qVariantFromValue<QGraphicsScene *>(0))); + const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange, + qVariantFromValue<QGraphicsScene *>(0))); + QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(newSceneVariant); if (targetScene != 0 && targetScene != this) { targetScene->addItem(item); return; @@ -3154,6 +3296,16 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) d->unpolishedItems.removeAll(item); d->dirtyItems.removeAll(item); + //We remove all references of item from the sceneEventFilter arrays + QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = d->sceneEventFilters.begin(); + while (iterator != d->sceneEventFilters.end()) { + if (iterator.value() == item || iterator.key() == item) + iterator = d->sceneEventFilters.erase(iterator); + else + ++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; @@ -3181,7 +3333,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) emit selectionChanged(); // Deliver post-change notification - item->itemChange(QGraphicsItem::ItemSceneHasChanged, qVariantFromValue<QGraphicsScene *>(0)); + item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); } /*! @@ -3455,7 +3607,7 @@ QVariant QGraphicsScene::inputMethodQuery(Qt::InputMethodQuery query) const void QGraphicsScene::update(const QRectF &rect) { Q_D(QGraphicsScene); - if (d->updateAll) + if (d->updateAll || (rect.isEmpty() && !rect.isNull())) return; // Check if anyone's connected; if not, we can send updates directly to @@ -4564,7 +4716,9 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Item's (local) bounding rect QRectF brect = item->boundingRect(); - if (_q_adjustedRect(brect).isEmpty()) + QRectF adjustedBrect(brect); + _q_adjustRect(&adjustedBrect); + if (adjustedBrect.isEmpty()) return; // Fetch the off-screen transparent buffer and exposed area info. @@ -4595,16 +4749,17 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte if (cacheMode == QGraphicsItem::ItemCoordinateCache) { QSize pixmapSize; bool fixedCacheSize = false; + QRectF brectAligned = brect.toAlignedRect(); if ((fixedCacheSize = itemCache->fixedSize.isValid())) { pixmapSize = itemCache->fixedSize; } else { - pixmapSize = brect.toAlignedRect().size(); + pixmapSize = brectAligned.size().toSize(); } // Create or recreate the pixmap. int adjust = itemCache->fixedSize.isValid() ? 0 : 2; QSize adjustSize(adjust*2, adjust*2); - QRectF br = brect.adjusted(-adjust, -adjust, adjust, adjust); + QRectF br = brectAligned.adjusted(-adjust, -adjust, adjust, adjust); if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) { pix = QPixmap(pixmapSize + adjustSize); itemCache->exposed.clear(); @@ -4614,9 +4769,11 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte // Redraw any newly exposed areas. if (itemCache->allExposed || !itemCache->exposed.isEmpty()) { // Fit the item's bounding rect into the pixmap's coordinates. - const QPointF scale(pixmapSize.width() / brect.width(), pixmapSize.height() / brect.height()); QTransform itemToPixmap; - itemToPixmap.scale(scale.x(), scale.y()); + if (fixedCacheSize) { + const QPointF scale(pixmapSize.width() / brect.width(), pixmapSize.height() / brect.height()); + itemToPixmap.scale(scale.x(), scale.y()); + } itemToPixmap.translate(-br.x(), -br.y()); // Generate the item's exposedRect and map its list of expose @@ -4769,8 +4926,9 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) { // Construct an item-to-pixmap transform. QPointF p = deviceRect.topLeft(); - QTransform itemToPixmap = QTransform::fromTranslate(-p.x(), -p.y()); - itemToPixmap = painter->worldTransform() * itemToPixmap; + QTransform itemToPixmap = painter->worldTransform(); + if (!p.isNull()) + itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y()); // Map the item's logical expose to pixmap coordinates. QRegion pixmapExposed = scrollExposure; @@ -5104,9 +5262,12 @@ void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect) update(item->sceneBoundingRect()); } else { // ### Remove _q_adjustedRects(). - QRectF boundingRect = _q_adjustedRect(item->boundingRect()); - if (!rect.isNull()) - boundingRect &= _q_adjustedRect(rect); + 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) @@ -5118,6 +5279,9 @@ void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect) 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 @@ -5133,7 +5297,9 @@ void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect) // defined scene rect. if (!d->hasSceneRect) { QRectF oldGrowingItemsBoundingRect = d->growingItemsBoundingRect; - d->growingItemsBoundingRect |= _q_adjustedRect(item->sceneBoundingRect()); + QRectF adjustedItemSceneBoundingRect(item->sceneBoundingRect()); + _q_adjustRect(&adjustedItemSceneBoundingRect); + d->growingItemsBoundingRect |= adjustedItemSceneBoundingRect; if (d->growingItemsBoundingRect != oldGrowingItemsBoundingRect) emit sceneRectChanged(d->growingItemsBoundingRect); } |