diff options
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r-- | src/gui/graphicsview/graphicsview.pri | 1 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 284 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.h | 6 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 83 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 74 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.h | 2 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene_p.h | 25 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp | 4 |
8 files changed, 439 insertions, 40 deletions
diff --git a/src/gui/graphicsview/graphicsview.pri b/src/gui/graphicsview/graphicsview.pri index 9d232e4..15b86b5 100644 --- a/src/gui/graphicsview/graphicsview.pri +++ b/src/gui/graphicsview/graphicsview.pri @@ -23,6 +23,7 @@ HEADERS += graphicsview/qgraphicsgridlayout.h \ graphicsview/qgraphicswidget.h \ graphicsview/qgraphicswidget_p.h \ graphicsview/qgridlayoutengine_p.h + SOURCES += graphicsview/qgraphicsgridlayout.cpp \ graphicsview/qgraphicsitem.cpp \ graphicsview/qgraphicsitemanimation.cpp \ diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 708ba09..2b3d453 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -581,6 +581,7 @@ #include <QtGui/qpixmapcache.h> #include <QtGui/qstyleoption.h> #include <QtGui/qevent.h> +#include <QtGui/qgraphicseffect.h> #include <private/qgraphicsitem_p.h> #include <private/qgraphicswidget_p.h> @@ -1042,11 +1043,6 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent) */ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect) { - if (!dirtyChildrenBoundingRect) { - *rect |= x->mapRect(childrenBoundingRect); - return; - } - for (int i = 0; i < children.size(); ++i) { QGraphicsItem *child = children.at(i); QGraphicsItemPrivate *childd = child->d_ptr; @@ -1054,19 +1050,20 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec if (hasPos || childd->transformData) { // COMBINE QTransform matrix = childd->transformToParent(); - matrix *= *x; + if (x) + matrix *= *x; *rect |= matrix.mapRect(child->boundingRect()); if (!childd->children.isEmpty()) childd->childrenBoundingRectHelper(&matrix, rect); } else { - *rect |= x->mapRect(child->boundingRect()); + if (x) + *rect |= x->mapRect(child->boundingRect()); + else + *rect |= child->boundingRect(); if (!childd->children.isEmpty()) childd->childrenBoundingRectHelper(x, rect); } } - - childrenBoundingRect = *rect; - dirtyChildrenBoundingRect = 0; } void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, @@ -1210,6 +1207,7 @@ QGraphicsItem::~QGraphicsItem() d_ptr->setParentItemHelper(0); } + delete d_ptr->graphicsEffect; if (d_ptr->transformData) { for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) { QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i); @@ -2018,8 +2016,8 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo enabled = newEnabledVariant.toBool(); // Schedule redraw. - if (update && scene) - scene->d_func()->markDirty(q_ptr); + if (update) + q_ptr->update(); foreach (QGraphicsItem *child, children) { if (!newEnabled || !child->d_ptr->explicitlyDisabled) @@ -2123,8 +2121,8 @@ void QGraphicsItem::setSelected(bool selected) return; d_ptr->selected = newSelected; + update(); if (d_ptr->scene) { - d_ptr->scene->d_func()->markDirty(this); QGraphicsScenePrivate *sceneD = d_ptr->scene->d_func(); if (selected) { sceneD->selectedItems << this; @@ -2231,6 +2229,118 @@ void QGraphicsItem::setOpacity(qreal opacity) } /*! + Returns a pointer to this item's effect if it has one; otherwise 0. + + \since 4.6 +*/ +QGraphicsEffect *QGraphicsItem::graphicsEffect() const +{ + return d_ptr->graphicsEffect; +} + +/*! + Sets \a effect as the item's effect. If there already is an effect installed + on this item, QGraphicsItem will delete the existing effect before installing + the new \a effect. + + If \a effect is the installed on a different item, setGraphicsEffect() will remove + the effect from the item and install it on this item. + + \note This function will apply the effect on itself and all its children. + + \since 4.6 +*/ +void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) +{ + if (d_ptr->graphicsEffect == effect) + return; + + if (d_ptr->graphicsEffect && effect) { + delete d_ptr->graphicsEffect; + d_ptr->graphicsEffect = 0; + } + + if (!effect) { + // Unset current effect. + QGraphicsEffectPrivate *oldEffectPrivate = d_ptr->graphicsEffect->d_func(); + d_ptr->graphicsEffect = 0; + if (oldEffectPrivate) { + oldEffectPrivate->setGraphicsEffectSource(0); // deletes the current source. + if (d_ptr->scene) // Update the views directly. + d_ptr->scene->d_func()->markDirty(this, QRectF(), false, false, false, false, true); + } + } else { + // Set new effect. + QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this); + QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced); + d_ptr->graphicsEffect = effect; + effect->d_func()->setGraphicsEffectSource(source); + } + + prepareGeometryChange(); +} + +/*! + \internal + \since 4.6 + Returns the effective bounding rect of the item. + If the item has no effect, this is the same as the item's bounding rect. + If the item has an effect, the effective rect can be larger than the item's + bouding rect, depending on the effect. + + \sa boundingRect() +*/ +QRectF QGraphicsItemPrivate::effectiveBoundingRect() const +{ + QGraphicsEffect *effect = graphicsEffect; + QRectF brect = effect && effect->isEnabled() ? effect->boundingRect() : q_ptr->boundingRect(); + if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) + return brect; + + const QGraphicsItem *effectParent = parent; + while (effectParent) { + effect = effectParent->d_ptr->graphicsEffect; + if (effect && effect->isEnabled()) + brect = effect->boundingRectFor(brect); + if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) + return brect; + effectParent = effectParent->d_ptr->parent; + } + + return brect; +} + +/*! + \internal + \since 4.6 + Returns the effective bounding rect of this item in scene coordinates, + by combining sceneTransform() with boundingRect(), taking into account + the effect that the item might have. + + If the item has no effect, this is the same as sceneBoundingRect(). + + \sa effectiveBoundingRect(), sceneBoundingRect() +*/ +QRectF QGraphicsItemPrivate::sceneEffectiveBoundingRect() const +{ + // Find translate-only offset + // COMBINE + QPointF offset; + const QGraphicsItem *parentItem = q_ptr; + const QGraphicsItemPrivate *itemd; + do { + itemd = parentItem->d_ptr; + if (itemd->transformData) + break; + offset += itemd->pos; + } while ((parentItem = itemd->parent)); + + QRectF br = effectiveBoundingRect(); + br.translate(offset); + return !parentItem ? br : parentItem->sceneTransform().mapRect(br); +} + +/*! Returns true if this item can accept drag and drop events; otherwise, returns false. By default, items do not accept drag and drop events; items are transparent to drag and drop. @@ -3757,10 +3867,10 @@ QRectF QGraphicsItem::childrenBoundingRect() const if (!d_ptr->dirtyChildrenBoundingRect) return d_ptr->childrenBoundingRect; - QRectF childRect; - QTransform x; - d_ptr->childrenBoundingRectHelper(&x, &childRect); - return childRect; + d_ptr->childrenBoundingRect = QRectF(); + d_ptr->childrenBoundingRectHelper(0, &d_ptr->childrenBoundingRect); + d_ptr->dirtyChildrenBoundingRect = 0; + return d_ptr->childrenBoundingRect; } /*! @@ -4683,6 +4793,13 @@ void QGraphicsItem::update(const QRectF &rect) if (rect.isEmpty() && !rect.isNull()) return; + // Make sure we notify effects about invalidated source. + QGraphicsItem *item = this; + do { + if (item->d_ptr->graphicsEffect) + item->d_ptr->notifyInvalidated = 1; + } while ((item = item->d_ptr->parent)); + if (CacheMode(d_ptr->cacheMode) != NoCache) { QGraphicsItemCache *cache = d_ptr->extraItemCache(); if (d_ptr->discardUpdateRequest(/* ignoreVisibleBit = */ false, @@ -6022,6 +6139,7 @@ void QGraphicsItem::dropEvent(QGraphicsSceneDragDropEvent *event) void QGraphicsItem::focusInEvent(QFocusEvent *event) { Q_UNUSED(event); + update(); } /*! @@ -6033,6 +6151,7 @@ void QGraphicsItem::focusInEvent(QFocusEvent *event) void QGraphicsItem::focusOutEvent(QFocusEvent *event) { Q_UNUSED(event); + update(); } /*! @@ -6047,8 +6166,7 @@ void QGraphicsItem::focusOutEvent(QFocusEvent *event) void QGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event); - if (d_ptr->scene) - d_ptr->scene->d_func()->markDirty(this); + update(); } /*! @@ -6076,8 +6194,7 @@ void QGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) void QGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event); - if (d_ptr->scene) - d_ptr->scene->d_func()->markDirty(this); + update(); } /*! @@ -6578,6 +6695,7 @@ void QGraphicsItem::prepareGeometryChange() d_ptr->scene->d_func()->dirtyGrowingItemsBoundingRect = true; d_ptr->geometryChanged = 1; d_ptr->paintedViewBoundingRectsNeedRepaint = 1; + d_ptr->notifyBoundingRectChanged = !d_ptr->inSetPosHelper; QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); scenePrivate->index->prepareBoundingRectChange(this); @@ -6601,8 +6719,11 @@ void QGraphicsItem::prepareGeometryChange() } QGraphicsItem *parent = this; - while ((parent = parent->d_ptr->parent)) + while ((parent = parent->d_ptr->parent)) { parent->d_ptr->dirtyChildrenBoundingRect = 1; + // ### Only do this if the parent's effect applies to the entire subtree. + parent->d_ptr->notifyBoundingRectChanged = 1; + } if (d_ptr->inSetPosHelper) return; @@ -9957,6 +10078,125 @@ int QGraphicsItemGroup::type() const return Type; } +QRectF QGraphicsItemEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const +{ + const bool deviceCoordinates = (system == Qt::DeviceCoordinates); + if (!info && deviceCoordinates) { + // Device coordinates without info not yet supported. + qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context"); + return QRectF(); + } + + QRectF rect = item->boundingRect(); + if (!item->d_ptr->children.isEmpty()) + rect |= item->childrenBoundingRect(); + + if (deviceCoordinates) { + Q_ASSERT(info->painter); + rect = info->painter->worldTransform().mapRect(rect); + } + + return rect; +} + +void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter) +{ + if (!info) { + qWarning("QGraphicsEffectSource::draw: Can only begin as a result of QGraphicsEffect::draw"); + return; + } + + Q_ASSERT(item->d_ptr->scene); + QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); + if (painter == info->painter) { + scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion, + info->widget, info->opacity, info->effectTransform, info->wasDirtySceneTransform, + info->drawItem); + } else { + QTransform effectTransform = painter->worldTransform(); + effectTransform *= info->painter->worldTransform().inverted(); + if (info->effectTransform) + effectTransform *= *info->effectTransform; + scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion, + info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform, + info->drawItem); + } +} + +QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset) const +{ + const bool deviceCoordinates = (system == Qt::DeviceCoordinates); + if (!info && deviceCoordinates) { + // Device coordinates without info not yet supported. + qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context"); + return QPixmap(); + } + + if (!item->d_ptr->scene) + return QPixmap(); + QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); + + const QRectF sourceRect = boundingRect(system); + QRect effectRect = item->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect(); + if (offset) + *offset = effectRect.topLeft(); + + if (deviceCoordinates) { + // Clip to viewport rect. + int left, top, right, bottom; + effectRect.getCoords(&left, &top, &right, &bottom); + if (left < 0) { + if (offset) + offset->rx() += -left; + effectRect.setX(0); + } + if (top < 0) { + if (offset) + offset->ry() += -top; + effectRect.setY(0); + } + // NB! We use +-1 for historical reasons (see QRect documentation). + if (right + 1 > info->widget->width()) + effectRect.setRight(info->widget->width() - 1); + if (bottom + 1 > info->widget->height()) + effectRect.setBottom(info->widget->height() -1); + } + + if (effectRect.isEmpty()) + return QPixmap(); + + QPixmap pixmap(effectRect.size()); + pixmap.fill(Qt::transparent); + QPainter pixmapPainter(&pixmap); + pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing); + + QTransform effectTransform = QTransform::fromTranslate(-effectRect.x(), -effectRect.y()); + if (deviceCoordinates && info->effectTransform) + effectTransform *= *info->effectTransform; + + if (!info) { + // Logical coordinates without info. + QTransform sceneTransform = item->sceneTransform(); + QTransform newEffectTransform = sceneTransform.inverted(); + newEffectTransform *= effectTransform; + scened->draw(item, &pixmapPainter, 0, &sceneTransform, 0, 0, qreal(1.0), + &newEffectTransform, false, true); + } else if (deviceCoordinates) { + // Device coordinates with info. + scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion, + info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform, + info->drawItem); + } else { + // Item coordinates with info. + QTransform newEffectTransform = info->transformPtr->inverted(); + newEffectTransform *= effectTransform; + scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion, + info->widget, info->opacity, &newEffectTransform, info->wasDirtySceneTransform, + info->drawItem); + } + return pixmap; +} + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, QGraphicsItem *item) { diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 52b862e..216053d 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -62,6 +62,7 @@ QT_MODULE(Gui) class QBrush; class QCursor; class QFocusEvent; +class QGraphicsEffect; class QGraphicsItemGroup; class QGraphicsObject; class QGraphicsSceneContextMenuEvent; @@ -209,6 +210,10 @@ public: qreal effectiveOpacity() const; void setOpacity(qreal opacity); + // Effect + QGraphicsEffect *graphicsEffect() const; + void setGraphicsEffect(QGraphicsEffect *effect); + Qt::MouseButtons acceptedMouseButtons() const; void setAcceptedMouseButtons(Qt::MouseButtons buttons); @@ -446,6 +451,7 @@ private: friend class QGraphicsSceneIndexPrivate; friend class QGraphicsSceneBspTreeIndex; friend class QGraphicsSceneBspTreeIndexPrivate; + friend class QGraphicsItemEffectSourcePrivate; friend class QGraphicsTransformPrivate; friend class ::tst_QGraphicsItem; friend bool qt_closestLeaf(const QGraphicsItem *, const QGraphicsItem *); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 43d690f..cd5c595 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -60,6 +60,8 @@ #include "qgraphicstransform.h" #include "qgraphicstransform_p.h" +#include <private/qgraphicseffect_p.h> + #include <QtCore/qpoint.h> #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW @@ -104,7 +106,8 @@ public: ExtraCursor, ExtraCacheData, ExtraMaxDeviceCoordCacheSize, - ExtraBoundingRegionGranularity + ExtraBoundingRegionGranularity, + ExtraGestures }; enum AncestorFlag { @@ -121,6 +124,7 @@ public: scene(0), parent(0), transformData(0), + graphicsEffect(0), index(-1), siblingIndex(-1), depth(0), @@ -165,6 +169,8 @@ public: acceptedTouchBeginEvent(0), filtersDescendantEvents(0), sceneTransformTranslateOnly(0), + notifyBoundingRectChanged(0), + notifyInvalidated(0), mouseSetsFocus(1), globalStackingOrder(-1), q_ptr(0) @@ -216,6 +222,8 @@ public: void childrenBoundingRectHelper(QTransform *x, QRectF *rect); void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, const QRegion &exposedRegion, bool allItems = false) const; + QRectF effectiveBoundingRect() const; + QRectF sceneEffectiveBoundingRect() const; virtual void resolveFont(uint inheritedMask) { @@ -416,6 +424,7 @@ public: QList<QGraphicsItem *> children; struct TransformData; TransformData *transformData; + QGraphicsEffect *graphicsEffect; QTransform sceneTransform; int index; int siblingIndex; @@ -466,8 +475,10 @@ public: quint32 acceptedTouchBeginEvent : 1; quint32 filtersDescendantEvents : 1; quint32 sceneTransformTranslateOnly : 1; + quint32 notifyBoundingRectChanged : 1; + quint32 notifyInvalidated : 1; quint32 mouseSetsFocus : 1; - quint32 unused : 3; // feel free to use + quint32 unused : 1; // feel free to use // Optional stacking order int globalStackingOrder; @@ -513,6 +524,74 @@ struct QGraphicsItemPrivate::TransformData } }; +struct QGraphicsItemPaintInfo +{ + inline QGraphicsItemPaintInfo(const QTransform *const xform1, const QTransform *const xform2, + const QTransform *const xform3, + QRegion *r, QWidget *w, QStyleOptionGraphicsItem *opt, + QPainter *p, qreal o, bool b1, bool b2) + : viewTransform(xform1), transformPtr(xform2), effectTransform(xform3), exposedRegion(r), widget(w), + option(opt), painter(p), opacity(o), wasDirtySceneTransform(b1), drawItem(b2) + {} + + const QTransform *viewTransform; + const QTransform *transformPtr; + const QTransform *effectTransform; + QRegion *exposedRegion; + QWidget *widget; + QStyleOptionGraphicsItem *option; + QPainter *painter; + qreal opacity; + quint32 wasDirtySceneTransform : 1; + quint32 drawItem : 1; +}; + +class QGraphicsItemEffectSourcePrivate : public QGraphicsEffectSourcePrivate +{ +public: + QGraphicsItemEffectSourcePrivate(QGraphicsItem *i) + : QGraphicsEffectSourcePrivate(), item(i), info(0) + {} + + inline void detach() + { item->setGraphicsEffect(0); } + + inline const QGraphicsItem *graphicsItem() const + { return item; } + + inline const QWidget *widget() const + { return 0; } + + inline void update() + { item->update(); } + + inline bool isPixmap() const + { + return (item->type() == QGraphicsPixmapItem::Type); + //|| (item->d_ptr->isObject && qobject_cast<QFxImage *>(q_func())); + } + + inline const QStyleOption *styleOption() const + { return info ? info->option : 0; } + + inline QRect deviceRect() const + { + if (!info || !info->widget) { + qWarning("QGraphicsEffectSource::deviceRect: Not yet implemented, lacking device context"); + return QRect(); + } + return info->widget->rect(); + } + + QRectF boundingRect(Qt::CoordinateSystem system) const; + void draw(QPainter *); + QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset) const; + + QGraphicsItem *item; + QGraphicsItemPaintInfo *info; +}; + + /*! \internal */ diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 7fa565d..33b2ecd 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -244,11 +244,13 @@ #include <QtGui/qtransform.h> #include <QtGui/qgesture.h> #include <QtGui/qinputcontext.h> +#include <QtGui/qgraphicseffect.h> #include <private/qapplication_p.h> #include <private/qobject_p.h> #ifdef Q_WS_X11 #include <private/qt_x11_p.h> #endif +#include <private/qgraphicseffect_p.h> QT_BEGIN_NAMESPACE @@ -4302,7 +4304,7 @@ void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform, QRegion *exposedRegion, QWidget *widget, - qreal parentOpacity) + qreal parentOpacity, const QTransform *const effectTransform) { Q_ASSERT(item); @@ -4351,11 +4353,12 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); bool drawItem = itemHasContents && !itemIsFullyTransparent; if (drawItem) { - const QRectF brect = adjustedItemBoundingRect(item); + const QRectF brect = adjustedItemEffectiveBoundingRect(item); ENSURE_TRANSFORM_PTR QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect() : transformPtr->mapRect(brect).toRect(); - item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); + if (widget) + item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); viewBoundingRect.adjust(-1, -1, 1, 1); drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty(); if (!drawItem) { @@ -4369,14 +4372,51 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } } // else we know for sure this item has children we must process. + if (itemHasChildren && itemClipsChildrenToShape) + ENSURE_TRANSFORM_PTR; + + if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) { + ENSURE_TRANSFORM_PTR; + QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp, + painter, opacity, wasDirtyParentSceneTransform, drawItem); + QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source; + QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *> + (source->d_func()); + sourced->info = &info; + const QTransform restoreTransform = painter->worldTransform(); + if (effectTransform) + painter->setWorldTransform(*transformPtr * *effectTransform); + else + painter->setWorldTransform(*transformPtr); + item->d_ptr->graphicsEffect->draw(painter, source); + painter->setWorldTransform(restoreTransform); + sourced->info = 0; + } else { + draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity, + effectTransform, wasDirtyParentSceneTransform, drawItem); + } +} + +void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform, + const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget, + qreal opacity, const QTransform *effectTransform, + bool wasDirtyParentSceneTransform, bool drawItem) +{ + const bool itemIsFullyTransparent = (opacity < 0.0001); + const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); + const bool itemHasChildren = !item->d_ptr->children.isEmpty(); + int i = 0; if (itemHasChildren) { item->d_ptr->ensureSortedChildren(); if (itemClipsChildrenToShape) { painter->save(); - ENSURE_TRANSFORM_PTR - painter->setWorldTransform(*transformPtr); + Q_ASSERT(transformPtr); + if (effectTransform) + painter->setWorldTransform(*transformPtr * *effectTransform); + else + painter->setWorldTransform(*transformPtr); painter->setClipPath(item->shape(), Qt::IntersectClip); } @@ -4389,15 +4429,15 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * break; if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) continue; - drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity); + drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); } } // Draw item if (drawItem) { Q_ASSERT(!itemIsFullyTransparent); - Q_ASSERT(itemHasContents); - ENSURE_TRANSFORM_PTR + Q_ASSERT(!(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents)); + Q_ASSERT(transformPtr); item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion ? *exposedRegion : QRegion(), exposedRegion == 0); @@ -4406,8 +4446,12 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (savePainter) painter->save(); - if (!itemHasChildren || !itemClipsChildrenToShape) - painter->setWorldTransform(*transformPtr); + if (!itemHasChildren || !itemClipsChildrenToShape) { + if (effectTransform) + painter->setWorldTransform(*transformPtr * *effectTransform); + else + painter->setWorldTransform(*transformPtr); + } if (itemClipsToShape) painter->setClipPath(item->shape(), Qt::IntersectClip); @@ -4430,7 +4474,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * child->d_ptr->dirtySceneTransform = 1; if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) continue; - drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity); + drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); } } @@ -4513,8 +4557,12 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b item->d_ptr->ignoreOpacity = 1; QGraphicsItem *p = item->d_ptr->parent; - while (p && !p->d_ptr->dirtyChildren) { + while (p) { p->d_ptr->dirtyChildren = 1; + if (p->d_ptr->graphicsEffect && p->d_ptr->graphicsEffect->isEnabled()) { + p->d_ptr->dirty = 1; + p->d_ptr->fullUpdatePending = 1; + } p = p->d_ptr->parent; } } @@ -4623,7 +4671,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool // Process item. if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) { const bool useCompatUpdate = views.isEmpty() || isSignalConnected(changedSignalIndex); - const QRectF itemBoundingRect = adjustedItemBoundingRect(item); + const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item); if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) { // This block of code is kept for compatibility. Since 4.5, by default diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index 0ef9f04..26cb1c2 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -302,10 +302,12 @@ private: friend class QGraphicsViewPrivate; friend class QGraphicsWidget; friend class QGraphicsWidgetPrivate; + friend class QGraphicsEffect; friend class QGraphicsSceneIndex; friend class QGraphicsSceneIndexPrivate; friend class QGraphicsSceneBspTreeIndex; friend class QGraphicsSceneBspTreeIndexPrivate; + friend class QGraphicsItemEffectSourcePrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsScene::SceneLayers) diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index f1ddb5a..4b8791e 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -202,7 +202,11 @@ public: QRegion *exposedRegion, QWidget *widget); void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform *const, - QRegion *exposedRegion, QWidget *widget, qreal parentOpacity = qreal(1.0)); + QRegion *exposedRegion, QWidget *widget, qreal parentOpacity = qreal(1.0), + const QTransform *const effectTransform = 0); + void draw(QGraphicsItem *, QPainter *, const QTransform *const, const QTransform *const, + QRegion *, QWidget *, qreal, const QTransform *const, bool, bool); + void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false, bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false, bool removingItemFromScene = false); @@ -223,10 +227,21 @@ public: item->d_ptr->fullUpdatePending = 0; item->d_ptr->ignoreVisible = 0; item->d_ptr->ignoreOpacity = 0; + QGraphicsEffect::ChangeFlags flags; + if (item->d_ptr->notifyBoundingRectChanged) { + flags |= QGraphicsEffect::SourceBoundingRectChanged; + item->d_ptr->notifyBoundingRectChanged = 0; + } + if (item->d_ptr->notifyInvalidated) { + flags |= QGraphicsEffect::SourceInvalidated; + item->d_ptr->notifyInvalidated = 0; + } if (recursive) { for (int i = 0; i < item->d_ptr->children.size(); ++i) resetDirtyItem(item->d_ptr->children.at(i), recursive); } + if (flags && item->d_ptr->graphicsEffect) + item->d_ptr->graphicsEffect->sourceChanged(flags); } inline void ensureSortedTopLevelItems() @@ -280,6 +295,14 @@ static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item) return boundingRect; } +static inline QRectF adjustedItemEffectiveBoundingRect(const QGraphicsItem *item) +{ + Q_ASSERT(item); + QRectF boundingRect(QGraphicsItemPrivate::get(item)->effectiveBoundingRect()); + _q_adjustRect(&boundingRect); + return boundingRect; +} + QT_END_NAMESPACE #endif // QT_NO_GRAPHICSVIEW diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp index d68183c..1f5d106 100644 --- a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp +++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp @@ -172,7 +172,7 @@ void QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex() if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) continue; - bsp.insertItem(item, item->sceneBoundingRect()); + bsp.insertItem(item, item->d_ptr->sceneEffectiveBoundingRect()); } } unindexedItems.clear(); @@ -352,7 +352,7 @@ void QGraphicsSceneBspTreeIndexPrivate::removeItem(QGraphicsItem *item, bool rec purgePending = true; removedItems << item; } else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) { - bsp.removeItem(item, item->sceneBoundingRect()); + bsp.removeItem(item, item->d_ptr->sceneEffectiveBoundingRect()); } } else { unindexedItems.removeOne(item); |