diff options
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/graphicsview/qgraphicseffect.cpp | 234 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicseffect.h | 58 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicseffect_p.h | 27 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 91 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.h | 2 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 45 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 72 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.h | 5 |
8 files changed, 266 insertions, 268 deletions
diff --git a/src/gui/graphicsview/qgraphicseffect.cpp b/src/gui/graphicsview/qgraphicseffect.cpp index c173d1b..8d2c416 100644 --- a/src/gui/graphicsview/qgraphicseffect.cpp +++ b/src/gui/graphicsview/qgraphicseffect.cpp @@ -104,83 +104,90 @@ QGraphicsEffect::QGraphicsEffect() : QObject(*new QGraphicsEffectPrivate, 0) +{} + +/*! + \internal +*/ +QGraphicsEffect::QGraphicsEffect(QGraphicsEffectPrivate &dd) + : QObject(dd, 0) +{} + +QGraphicsEffect::~QGraphicsEffect() { Q_D(QGraphicsEffect); - d->parentItem = 0; + d->setGraphicsEffectSource(0); } -QGraphicsEffect::~QGraphicsEffect() +QRectF QGraphicsEffect::boundingRect() const { + return sourceBoundingRect(); } -QRectF QGraphicsEffect::boundingRectFor(const QGraphicsItem *item) +QRectF QGraphicsEffect::sourceBoundingRect() const { - // default is to give the item's bounding rect - // do NOT call item->effectiveBoundRect() because - // that function will call this one (infinite loop) - return item->boundingRect(); + Q_D(const QGraphicsEffect); + if (d->source) + return d->source->boundingRect(); + return QRectF(); } -/*! \internal -*/ -QGraphicsEffect::QGraphicsEffect(QGraphicsEffectPrivate &dd) - : QObject(dd, 0) +void QGraphicsEffect::drawSource(QPainter *painter) { Q_D(QGraphicsEffect); - d->parentItem = 0; + if (d->source) + d->source->draw(painter); } -// this helper function is only for subclasses of QGraphicsEffect -// the implementation is trivial, but this allows us to keep -// QGraphicsScene::drawItem() as a protected function -// (since QGraphicsEffect is a friend of QGraphicsScene) -QPixmap* QGraphicsEffect::drawItemOnPixmap(QPainter *painter, QGraphicsItem *item, - const QStyleOptionGraphicsItem *option, QWidget *widget, int flags) +bool QGraphicsEffect::drawSourceIntoPixmap(QPixmap *pixmap, const QTransform &itemToPixmapTransform) { - if (!item->scene()) - return 0; - return item->scene()->drawItemOnPixmap(painter, item, option, widget, flags); + Q_D(QGraphicsEffect); + if (d->source) + return d->source->drawIntoPixmap(pixmap, itemToPixmapTransform); + return false; } QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect() : QGraphicsEffect(*new QGraphicsGrayscaleEffectPrivate) -{ -} +{} QGraphicsGrayscaleEffect::~QGraphicsGrayscaleEffect() -{ -} +{} -void QGraphicsGrayscaleEffect::drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option, QWidget *widget) +void QGraphicsGrayscaleEffect::draw(QPainter *painter) { Q_D(QGraphicsGrayscaleEffect); + if (!d->source) + return; // Find the item's bounds in device coordinates. - QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QTransform itemToPixmapTransform(painter->worldTransform()); + QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); if (deviceRect.isEmpty()) return; - QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); - if (!pixmap) + if (deviceRect.x() != 0 || deviceRect.y() != 0) + itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y()); + + QPixmap pixmap(deviceRect.size()); + if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) return; // Draw the pixmap with the filter using an untransformed painter. QTransform restoreTransform = painter->worldTransform(); painter->setWorldTransform(QTransform()); - d->filter->draw(painter, deviceRect.topLeft(), *pixmap, pixmap->rect()); + d->filter->draw(painter, deviceRect.topLeft(), pixmap, pixmap.rect()); painter->setWorldTransform(restoreTransform); + } QGraphicsColorizeEffect::QGraphicsColorizeEffect() : QGraphicsEffect(*new QGraphicsColorizeEffectPrivate) -{ -} +{} QGraphicsColorizeEffect::~QGraphicsColorizeEffect() -{ -} +{} QColor QGraphicsColorizeEffect::color() const { @@ -194,25 +201,30 @@ void QGraphicsColorizeEffect::setColor(const QColor &c) d->filter->setColor(c); } -void QGraphicsColorizeEffect::drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option, QWidget *widget) +void QGraphicsColorizeEffect::draw(QPainter *painter) { Q_D(QGraphicsColorizeEffect); + if (!d->source) + return; // Find the item's bounds in device coordinates. - QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QTransform itemToPixmapTransform(painter->worldTransform()); + QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); if (deviceRect.isEmpty()) return; - QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); - if (!pixmap) + if (deviceRect.x() != 0 || deviceRect.y() != 0) + itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y()); + + QPixmap pixmap(deviceRect.size()); + if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) return; // Draw the pixmap with the filter using an untransformed painter. QTransform restoreTransform = painter->worldTransform(); painter->setWorldTransform(QTransform()); - d->filter->draw(painter, deviceRect.topLeft(), *pixmap, pixmap->rect()); + d->filter->draw(painter, deviceRect.topLeft(), pixmap, pixmap.rect()); painter->setWorldTransform(restoreTransform); } @@ -237,23 +249,28 @@ void QGraphicsPixelizeEffect::setPixelSize(int size) d->pixelSize = size; } -void QGraphicsPixelizeEffect::drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option, QWidget *widget) +void QGraphicsPixelizeEffect::draw(QPainter *painter) { Q_D(QGraphicsPixelizeEffect); + if (!d->source) + return; // Find the item's bounds in device coordinates. - QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QTransform itemToPixmapTransform(painter->worldTransform()); + QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); if (deviceRect.isEmpty()) return; - QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); - if (!pixmap) + if (deviceRect.x() != 0 || deviceRect.y() != 0) + itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y()); + + QPixmap pixmap(deviceRect.size()); + if (!d->source->drawIntoPixmap(&pixmap)) return; // pixelize routine - QImage img = pixmap->toImage().convertToFormat(QImage::Format_ARGB32); + QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); if (d->pixelSize > 0) { int width = img.width(); int height = img.height(); @@ -365,31 +382,42 @@ void QGraphicsBlurEffect::setBlurRadius(int radius) d->filter->setBlurRadius(radius); } -QRectF QGraphicsBlurEffect::boundingRectFor(const QGraphicsItem *item) +QRectF QGraphicsBlurEffect::boundingRect() const { Q_D(const QGraphicsBlurEffect); - return d->filter->boundingRectFor(item->boundingRect()); + if (d->source) + return d->filter->boundingRectFor(d->source->boundingRect()); + return QRectF(); } -void QGraphicsBlurEffect::drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option, QWidget *widget) +void QGraphicsBlurEffect::draw(QPainter *painter) { Q_D(QGraphicsBlurEffect); + if (!d->source) + return; // Find the item's bounds in device coordinates. - QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QTransform itemToPixmapTransform(painter->worldTransform()); + QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); if (deviceRect.isEmpty()) return; - QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); - if (!pixmap) + // ### Potentially big rect; must be clipped to the viewport rect. + const qreal delta = d->blurRadius * 3; + const QRect effectRect = deviceBounds.adjusted(-delta, -delta, delta, delta) + .toRect().adjusted(-1, -1, 1, 1); + if (effectRect.x() != 0 || effectRect.y() != 0) + itemToPixmapTransform *= QTransform::fromTranslate(-effectRect.x(), -effectRect.y()); + + QPixmap pixmap(effectRect.size()); + if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) return; // Draw the pixmap with the filter using an untransformed painter. QTransform restoreTransform = painter->worldTransform(); painter->setWorldTransform(QTransform()); - d->filter->draw(painter, deviceRect.topLeft(), *pixmap, pixmap->rect()); + d->filter->draw(painter, deviceRect.topLeft(), pixmap, pixmap.rect()); painter->setWorldTransform(restoreTransform); } @@ -426,13 +454,13 @@ void QGraphicsBloomEffect::setOpacity(qreal alpha) d->opacity = alpha; } -QRectF QGraphicsBloomEffect::boundingRectFor(const QGraphicsItem *item) +QRectF QGraphicsBloomEffect::boundingRect() const { - Q_D(QGraphicsBloomEffect); + Q_D(const QGraphicsBloomEffect); + if (!d->source) + return QRectF(); qreal delta = d->blurRadius * 3; - QRectF blurRect = item->boundingRect(); - blurRect.adjust(-delta, -delta, delta, delta); - return blurRect; + return d->source->boundingRect().adjusted(-delta, -delta, delta, delta); } // Change brightness (positive integer) of each pixel @@ -466,24 +494,29 @@ static QImage composited(const QImage& img1, const QImage& img2, qreal opacity, return result; } -void QGraphicsBloomEffect::drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option, QWidget *widget) +void QGraphicsBloomEffect::draw(QPainter *painter) { Q_D(QGraphicsBloomEffect); + if (!d->source) + return; // Find the item's bounds in device coordinates. - QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QTransform itemToPixmapTransform(painter->worldTransform()); + QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); if (deviceRect.isEmpty()) return; - QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); - if (!pixmap) + if (deviceRect.x() != 0 || deviceRect.y() != 0) + itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y()); + + QPixmap pixmap(deviceRect.size()); + if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) return; // bloom routine int radius = d->blurRadius; - QImage img = pixmap->toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); + QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); QImage overlay = blurred(img, img.rect(), radius); overlay = brightened(overlay, 70); img = composited(img, overlay, d->opacity, QPainter::CompositionMode_Overlay); @@ -540,31 +573,35 @@ void QGraphicsFrameEffect::setFrameOpacity(qreal opacity) d->alpha = opacity; } -QRectF QGraphicsFrameEffect::boundingRectFor(const QGraphicsItem *item) +QRectF QGraphicsFrameEffect::boundingRect() const { - Q_D(QGraphicsFrameEffect); - QRectF frameRect = item->boundingRect(); - frameRect.adjust(-d->width, -d->width, d->width, d->width); - return frameRect; + Q_D(const QGraphicsFrameEffect); + if (!d->source) + return QRectF(); + return d->source->boundingRect().adjusted(-d->width, -d->width, d->width, d->width); } -void QGraphicsFrameEffect::drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option, QWidget *widget) +void QGraphicsFrameEffect::draw(QPainter *painter) { Q_D(QGraphicsFrameEffect); + if (!d->source) + return; // Find the item's bounds in device coordinates. - QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); - QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); - if (deviceRect.isEmpty()) + QTransform itemToPixmapTransform(painter->worldTransform()); + QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); + if (deviceBounds.isEmpty()) return; - QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); - if (!pixmap) - return; + QRect frameRect = deviceBounds.adjusted(-d->width, -d->width, d->width, d->width) + .toRect().adjusted(-1, -1, 1, 1); + + if (frameRect.x() != 0 || frameRect.y() != 0) + itemToPixmapTransform *= QTransform::fromTranslate(-frameRect.x(), -frameRect.y()); - QRectF frameRect = deviceBounds; - frameRect.adjust(-d->width, -d->width, d->width, d->width); + QPixmap pixmap(frameRect.size()); + if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) + return; painter->save(); painter->setWorldTransform(QTransform()); @@ -576,7 +613,7 @@ void QGraphicsFrameEffect::drawItem(QGraphicsItem *item, QPainter *painter, painter->drawRoundedRect(frameRect, 20, 20, Qt::RelativeSize); painter->restore(); - painter->drawPixmap(frameRect.topLeft(), *pixmap); + painter->drawPixmap(frameRect.topLeft(), pixmap); painter->restore(); } @@ -626,25 +663,30 @@ void QGraphicsShadowEffect::setOpacity(qreal opacity) d->alpha = opacity; } -QRectF QGraphicsShadowEffect::boundingRectFor(const QGraphicsItem *item) +QRectF QGraphicsShadowEffect::boundingRect() const { - Q_D(QGraphicsShadowEffect); - QRectF shadowRect = item->boundingRect(); + Q_D(const QGraphicsShadowEffect); + if (!d->source) + return QRectF(); + const QRectF srcBrect = d->source->boundingRect(); + QRectF shadowRect = srcBrect; shadowRect.adjust(d->offset.x(), d->offset.y(), d->offset.x(), d->offset.y()); QRectF blurRect = shadowRect; qreal delta = d->radius * 3; blurRect.adjust(-delta, -delta, delta, delta); - QRectF totalRect = blurRect.united(item->boundingRect()); + QRectF totalRect = blurRect.united(srcBrect); return totalRect; } -void QGraphicsShadowEffect::drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option, QWidget *widget) +void QGraphicsShadowEffect::draw(QPainter *painter) { Q_D(QGraphicsShadowEffect); + if (!d->source) + return; // Find the item's bounds in device coordinates. - QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QTransform itemToPixmapTransform(painter->worldTransform()); + QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); if (deviceRect.isEmpty()) return; @@ -654,13 +696,16 @@ void QGraphicsShadowEffect::drawItem(QGraphicsItem *item, QPainter *painter, QRectF blurRect = shadowRect; qreal delta = d->radius * 3; blurRect.adjust(-delta, -delta, delta, delta); - QRectF totalRect = blurRect.united(deviceRect); + QRect totalRect = blurRect.united(deviceRect).toRect().adjusted(-1, -1, 1, 1); - QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); - if (!pixmap) + if (totalRect.x() != 0 || totalRect.y() != 0) + itemToPixmapTransform *= QTransform::fromTranslate(-totalRect.x(), -totalRect.y()); + + QPixmap pixmap(totalRect.size()); + if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) return; - QImage img = pixmap->toImage(); + QImage img = pixmap.toImage(); QImage shadowImage(img.size(), QImage::Format_ARGB32); shadowImage.fill(qRgba(0, 0, 0, d->alpha * 255)); shadowImage.setAlphaChannel(img.alphaChannel()); @@ -682,10 +727,9 @@ void QGraphicsShadowEffect::drawItem(QGraphicsItem *item, QPainter *painter, qreal itemx = qMin(blurRect.x(), deviceBounds.x()); qreal itemy = qMin(blurRect.y(), deviceBounds.y()); - painter->drawPixmap(itemx, itemy, *pixmap); + painter->drawPixmap(itemx, itemy, pixmap); painter->setWorldTransform(restoreTransform); } - #endif diff --git a/src/gui/graphicsview/qgraphicseffect.h b/src/gui/graphicsview/qgraphicseffect.h index 9f6e342..74a8430 100644 --- a/src/gui/graphicsview/qgraphicseffect.h +++ b/src/gui/graphicsview/qgraphicseffect.h @@ -46,6 +46,7 @@ #include <QtCore/qglobal.h> #include <QtCore/qpoint.h> #include <QtCore/qvariant.h> +#include <QtGui/qtransform.h> #include <QtGui/qcolor.h> QT_FORWARD_DECLARE_CLASS(QGraphicsItem); @@ -71,18 +72,17 @@ public: QGraphicsEffect(); virtual ~QGraphicsEffect(); - virtual QRectF boundingRectFor(const QGraphicsItem *item); - - virtual void drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option = 0, - QWidget *widget = 0) = 0; + virtual QRectF boundingRect() const; protected: QGraphicsEffect(QGraphicsEffectPrivate &d); - QPixmap* drawItemOnPixmap(QPainter *painter, QGraphicsItem *item, - const QStyleOptionGraphicsItem *option, QWidget *widget, int flags); + virtual void draw(QPainter *painter) = 0; + void drawSource(QPainter *painter); + bool drawSourceIntoPixmap(QPixmap *pixmap, const QTransform &xform = QTransform()); + QRectF sourceBoundingRect() const; private: + friend class QGraphicsScenePrivate; friend class QGraphicsItem; Q_DECLARE_PRIVATE(QGraphicsEffect) Q_DISABLE_COPY(QGraphicsEffect) @@ -96,9 +96,8 @@ public: QGraphicsGrayscaleEffect(); ~QGraphicsGrayscaleEffect(); - void drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option = 0, - QWidget *widget = 0); +protected: + void draw(QPainter *painter); private: Q_DECLARE_PRIVATE(QGraphicsGrayscaleEffect) @@ -115,9 +114,8 @@ public: QColor color() const; void setColor(const QColor &c); - void drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option = 0, - QWidget *widget = 0); +protected: + void draw(QPainter *painter); private: Q_DECLARE_PRIVATE(QGraphicsColorizeEffect) @@ -134,9 +132,8 @@ public: int pixelSize() const; void setPixelSize(int pixelSize); - void drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option = 0, - QWidget *widget = 0); +protected: + void draw(QPainter *painter); private: Q_DECLARE_PRIVATE(QGraphicsPixelizeEffect) @@ -153,11 +150,10 @@ public: int blurRadius() const; void setBlurRadius(int blurRadius); - QRectF boundingRectFor(const QGraphicsItem *item); + QRectF boundingRect() const; - void drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option = 0, - QWidget *widget = 0); +protected: + void draw(QPainter *painter); private: Q_DECLARE_PRIVATE(QGraphicsBlurEffect) @@ -177,11 +173,10 @@ public: qreal opacity() const; void setOpacity(qreal opacity); - QRectF boundingRectFor(const QGraphicsItem *item); + QRectF boundingRect() const; - void drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option = 0, - QWidget *widget = 0); +protected: + void draw(QPainter *painter); private: Q_DECLARE_PRIVATE(QGraphicsBloomEffect) @@ -204,11 +199,11 @@ public: qreal frameOpacity() const; void setFrameOpacity(qreal opacity); - QRectF boundingRectFor(const QGraphicsItem *item); + QRectF boundingRect() const; + +protected: + void draw(QPainter *painter); - void drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option = 0, - QWidget *widget = 0); private: Q_DECLARE_PRIVATE(QGraphicsFrameEffect) Q_DISABLE_COPY(QGraphicsFrameEffect) @@ -232,11 +227,10 @@ public: qreal opacity() const; void setOpacity(qreal opacity); - QRectF boundingRectFor(const QGraphicsItem *item); + QRectF boundingRect() const; - void drawItem(QGraphicsItem *item, QPainter *painter, - const QStyleOptionGraphicsItem *option = 0, - QWidget *widget = 0); +protected: + void draw(QPainter *painter); private: Q_DECLARE_PRIVATE(QGraphicsShadowEffect) diff --git a/src/gui/graphicsview/qgraphicseffect_p.h b/src/gui/graphicsview/qgraphicseffect_p.h index 999e013..9204789 100644 --- a/src/gui/graphicsview/qgraphicseffect_p.h +++ b/src/gui/graphicsview/qgraphicseffect_p.h @@ -61,12 +61,31 @@ QT_BEGIN_NAMESPACE +class QGraphicsEffectSource +{ +public: + QGraphicsEffectSource() {} + virtual ~QGraphicsEffectSource() {} + virtual void detach() = 0; + virtual QRectF boundingRect() = 0; + virtual void draw(QPainter *p) = 0; + virtual bool drawIntoPixmap(QPixmap *, const QTransform & = QTransform()) = 0; +}; + class QGraphicsEffectPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QGraphicsEffect) public: - QGraphicsEffectPrivate(): parentItem(0) {} - QGraphicsItem *parentItem; + QGraphicsEffectPrivate() : source(0) {} + QGraphicsEffectSource *source; + inline void setGraphicsEffectSource(QGraphicsEffectSource *newSource) + { + if (source) { + source->detach(); + delete source; + } + source = newSource; + } }; class QGraphicsGrayscaleEffectPrivate : public QGraphicsEffectPrivate @@ -106,8 +125,10 @@ class QGraphicsBlurEffectPrivate : public QGraphicsEffectPrivate { Q_DECLARE_PUBLIC(QGraphicsBlurEffect) public: - QGraphicsBlurEffectPrivate() : blurRadius(4) {} + QGraphicsBlurEffectPrivate() : filter(new QPixmapBlurFilter), blurRadius(4) {} + ~QGraphicsBlurEffectPrivate() { delete filter; } + QPixmapBlurFilter *filter; int blurRadius; }; diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 3a350e0..1d271c9 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -552,7 +552,6 @@ #ifndef QT_NO_GRAPHICSVIEW -#include "qgraphicseffect_p.h" #include "qgraphicsscene.h" #include "qgraphicsscene_p.h" #include "qgraphicssceneevent.h" @@ -1180,8 +1179,7 @@ QGraphicsItem::~QGraphicsItem() else d_ptr->setParentItemHelper(0); - QGraphicsEffect *e = graphicsEffect(); - delete e; + delete d_ptr->graphicsEffect; delete d_ptr->transformData; delete d_ptr; @@ -2198,11 +2196,7 @@ void QGraphicsItem::setOpacity(qreal opacity) */ QGraphicsEffect *QGraphicsItem::graphicsEffect() const { - QGraphicsEffect *fx = 0; - if (d_ptr->hasEffect) - fx = d_ptr->extra(QGraphicsItemPrivate::ExtraEffect).value<QGraphicsEffect*>(); - - return fx; + return d_ptr->graphicsEffect; } /*! @@ -2220,30 +2214,29 @@ QGraphicsEffect *QGraphicsItem::graphicsEffect() const */ void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) { - if (effect) { - if (QGraphicsEffect *currentEffect = this->graphicsEffect()) { - if (currentEffect != effect) { - qWarning("QGraphicsItem::setEffect: Attempting to set QGraphicsEffect " - "%p on %p, which already has an effect", effect, this); - } - return; - } + if (d_ptr->graphicsEffect == effect) + return; - if (effect->d_func()->parentItem) - effect->d_func()->parentItem->setGraphicsEffect(0); - effect->d_func()->parentItem = this; - d_ptr->hasEffect = true; - d_ptr->setExtra(QGraphicsItemPrivate::ExtraEffect, QVariant::fromValue(effect)); + if (d_ptr->graphicsEffect && effect) { + qWarning("QGraphicsItem::setGraphicsEffect: Attempting to set QGraphicsEffect " + "%p on %p, which already has an effect installed", effect, this); + return; + } + + 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. } else { - d_ptr->hasEffect = false; - d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraEffect); - void *ptr = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectPixmap).value<void*>(); - QPixmap *pixmap = reinterpret_cast<QPixmap*>(ptr); - delete pixmap; - d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraEffectPixmap); + // Set new effect. + effect->d_func()->setGraphicsEffectSource(new QGraphicsItemEffectSource(this)); + d_ptr->graphicsEffect = effect; } - update(); + if (d_ptr->scene) + d_ptr->scene->d_func()->markDirty(this); } /*! @@ -2257,10 +2250,8 @@ void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) */ QRectF QGraphicsItem::effectiveBoundingRect() const { - QGraphicsEffect *fx = graphicsEffect(); - if (fx) - return fx->boundingRectFor(this); - + if (d_ptr->graphicsEffect) + return d_ptr->graphicsEffect->boundingRect(); return boundingRect(); } @@ -2294,42 +2285,6 @@ QRectF QGraphicsItem::sceneEffectiveBoundingRect() const } /*! - \internal - - Used by QGraphicsScene. -*/ -QPixmap *QGraphicsItem::effectPixmap() -{ - if (!d_ptr->hasEffect) - return 0; - - // the exact size of the pixmap is not a big deal - // as long as it contains the effective bounding rect - // TODO: use smart resizing etc - // TODO: store per device and do everything in device coordinate? - // TODO: use layer - QRect rect = effectiveBoundingRect().toAlignedRect(); - - void *ptr = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectPixmap).value<void*>(); - QPixmap *pixmap = reinterpret_cast<QPixmap*>(ptr); - bool avail = true; - if (!pixmap) - avail = false; - if (avail && pixmap->size() != rect.size()) - avail = false; - - if (!avail) { - delete pixmap; - pixmap = new QPixmap(rect.size()); - pixmap->fill(Qt::transparent); - ptr = reinterpret_cast<void*>(pixmap); - d_ptr->setExtra(QGraphicsItemPrivate::ExtraEffectPixmap, QVariant::fromValue(ptr)); - } - - return pixmap; -} - -/*! 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. diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 0beb07c..0c0b341 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -440,8 +440,6 @@ protected: void removeFromIndex(); void prepareGeometryChange(); - QPixmap *effectPixmap(); - private: Q_DISABLE_COPY(QGraphicsItem) Q_DECLARE_PRIVATE(QGraphicsItem) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 09f296a..dc875f7 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -57,6 +57,7 @@ #include "qset.h" #include "qpixmapcache.h" #include "qgraphicsview_p.h" +#include "qgraphicseffect_p.h" #include <QtCore/qpoint.h> @@ -103,8 +104,6 @@ public: ExtraCacheData, ExtraMaxDeviceCoordCacheSize, ExtraBoundingRegionGranularity, - ExtraEffect, - ExtraEffectPixmap, ExtraGestures }; @@ -122,6 +121,7 @@ public: scene(0), parent(0), transformData(0), + graphicsEffect(0), index(-1), siblingIndex(-1), depth(0), @@ -151,7 +151,6 @@ public: allChildrenDirty(0), fullUpdatePending(0), flags(0), - hasEffect(0), dirtyChildrenBoundingRect(1), paintedViewBoundingRectsNeedRepaint(0), dirtySceneTransform(1), @@ -409,6 +408,7 @@ public: QList<QGraphicsItem *> children; struct TransformData; TransformData *transformData; + QGraphicsEffect *graphicsEffect; QTransform sceneTransform; int index; int siblingIndex; @@ -443,7 +443,6 @@ public: // New 32 bits quint32 fullUpdatePending : 1; quint32 flags : 12; - quint32 hasEffect : 1; quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; @@ -511,6 +510,44 @@ struct QGraphicsItemPrivate::TransformData { } }; +class QGraphicsItemEffectSource : public QGraphicsEffectSource +{ +public: + QGraphicsItemEffectSource(QGraphicsItem *i) + : QGraphicsEffectSource(), item(i), option(0), widget(0) + {} + + inline void detach() + { item->setGraphicsEffect(0); } + + inline QRectF boundingRect() + { return item->boundingRect(); } + + inline void draw(QPainter *painter) + { item->paint(painter, option, widget); } + + inline bool drawIntoPixmap(QPixmap *pixmap, const QTransform &itemToPixmapTransform) + { + pixmap->fill(Qt::transparent); + QPainter pixmapPainter(pixmap); + if (!itemToPixmapTransform.isIdentity()) + pixmapPainter.setWorldTransform(itemToPixmapTransform); + item->paint(&pixmapPainter, option, widget); + return true; + } + + inline void setPaintInfo(const QStyleOptionGraphicsItem *o, QWidget *w) + { option = o; widget = w; } + + void resetPaintInfo() + { option = 0; widget = 0; } + +private: + QGraphicsItem *item; + const QStyleOptionGraphicsItem *option; + QWidget *widget; +}; + /*! \internal */ diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index c56f34c..f4fd4ce 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -3928,8 +3928,8 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte #endif // Render using effect, works now only for no cache mode - if (noCache && itemd->hasEffect && item->graphicsEffect()) { - item->graphicsEffect()->drawItem(item, painter, option, widget); + if (noCache && itemd->graphicsEffect) { + itemd->graphicsEffect->draw(painter); return; } @@ -4228,62 +4228,6 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } } -// FIXME: merge this with drawItems (needs refactoring) -QPixmap* QGraphicsScene::drawItemOnPixmap(QPainter *painter, - QGraphicsItem *item, - const QStyleOptionGraphicsItem *option, - QWidget *widget, - int flags) -{ - // TODO: use for choosing item or device coordinate - // FIXME: how about source, dest, and exposed rects? - Q_UNUSED(flags); - - // Item's (local) bounding rect, including the effect - QRectF brect = item->effectiveBoundingRect(); - QRectF adjustedBrect(brect); - _q_adjustRect(&adjustedBrect); - if (adjustedBrect.isEmpty()) - return 0; - - // Find the item's bounds in device coordinates. - QRectF deviceBounds = painter->worldTransform().mapRect(brect); - QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); - if (deviceRect.isEmpty()) - return 0; - - // If widget, check if it intersects or not - QRect viewRect = widget ? widget->rect() : QRect(); - if (widget && !viewRect.intersects(deviceRect)) - return 0; - - // Create offscreen pixmap - // TODO: use the pixmap from the layer - QPixmap *targetPixmap = item->effectPixmap(); - if (!targetPixmap) - targetPixmap = new QPixmap(deviceRect.size()); - - // FIXME: this is brute force - QRegion pixmapExposed; - pixmapExposed += targetPixmap->rect(); - - // Construct an item-to-pixmap transform. - QPointF p = deviceRect.topLeft(); - QTransform itemToPixmap = painter->worldTransform(); - if (!p.isNull()) - itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y()); - - // Calculate the style option's exposedRect. - QStyleOptionGraphicsItem fxOption = *option; - fxOption.exposedRect = brect.adjusted(-1, -1, 1, 1); - - // Render - _q_paintIntoCache(targetPixmap, item, pixmapExposed, itemToPixmap, painter->renderHints(), - &fxOption, false); - - return targetPixmap; -} - void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const viewTransform, QRegion *exposedRegion, QWidget *widget) { @@ -4412,11 +4356,21 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * painter->setClipPath(item->shape(), Qt::IntersectClip); painter->setOpacity(opacity); - if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget && !item->d_ptr->hasEffect) + QGraphicsItemEffectSource *source = item->d_ptr->graphicsEffect + ? static_cast<QGraphicsItemEffectSource *> + (item->d_ptr->graphicsEffect->d_func()->source) + : 0; + if (source) + source->setPaintInfo(&styleOptionTmp, widget); + + if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget && !source) item->paint(painter, &styleOptionTmp, widget); else drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection); + if (source) + source->resetPaintInfo(); + if (savePainter) painter->restore(); } diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index 68bd3e1..1606053 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -281,11 +281,6 @@ protected: const QStyleOptionGraphicsItem options[], QWidget *widget = 0); - QPixmap* drawItemOnPixmap(QPainter *painter, QGraphicsItem *item, - const QStyleOptionGraphicsItem *option, QWidget *widget, int flags); - - - protected Q_SLOTS: bool focusNextPrevChild(bool next); |