diff options
-rw-r--r-- | examples/graphicsview/dragdroprobot/main.cpp | 102 | ||||
-rw-r--r-- | examples/graphicsview/dragdroprobot/robot.cpp | 7 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicseffect.cpp | 304 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicseffect.h | 64 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicseffect_p.h | 19 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 64 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.h | 1 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 56 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 73 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.h | 1 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene_p.h | 6 |
11 files changed, 440 insertions, 257 deletions
diff --git a/examples/graphicsview/dragdroprobot/main.cpp b/examples/graphicsview/dragdroprobot/main.cpp index 30b8b70..b00bf72 100644 --- a/examples/graphicsview/dragdroprobot/main.cpp +++ b/examples/graphicsview/dragdroprobot/main.cpp @@ -46,6 +46,100 @@ #include <math.h> +Robot *robot = 0; + +class MyGraphicsEffect : public QGraphicsEffect +{ +public: + void draw(QPainter *painter, QGraphicsEffectSource *source) + { + painter->save(); + + QPen pen; + static int color = Qt::black; + pen.setColor(Qt::GlobalColor(color)); + if (color++ >= Qt::darkYellow) + color = Qt::black; + pen.setWidth(3); + painter->setPen(pen); + + source->draw(painter); + + painter->restore(); + } +}; + +class MyWidget : public QWidget +{ + Q_OBJECT +public: + MyWidget(QWidget *parent = 0) : QWidget(parent) + { + setLayout(new QVBoxLayout); + QComboBox *box = new QComboBox; + box->addItem("None"); + box->addItem("Blur"); + box->addItem("Colorize"); + box->addItem("Pixelize"); + box->addItem("Grayscale"); + box->addItem("Bloom"); + box->addItem("Shadow"); + box->addItem("Custom"); + layout()->addWidget(box); + connect(box, SIGNAL(currentIndexChanged(int)), this, SLOT(changeEffect(int))); + } + +public slots: + void changeEffect(int index) + { + switch (index) { + case 0: + delete robot->graphicsEffect(); + robot->setGraphicsEffect(0); + break; + case 1: + delete robot->graphicsEffect(); + robot->setGraphicsEffect(new QGraphicsBlurEffect); + break; + case 2: + delete robot->graphicsEffect(); + robot->setGraphicsEffect(new QGraphicsColorizeEffect); + break; + case 3: + delete robot->graphicsEffect(); + robot->setGraphicsEffect(new QGraphicsPixelizeEffect); + break; + case 4: + delete robot->graphicsEffect(); + robot->setGraphicsEffect(new QGraphicsGrayscaleEffect); + break; + case 5: + delete robot->graphicsEffect(); + robot->setGraphicsEffect(new QGraphicsBloomEffect); + break; + case 6: + delete robot->graphicsEffect(); + robot->setGraphicsEffect(new QGraphicsShadowEffect); + break; + case 7: + delete robot->graphicsEffect(); + robot->setGraphicsEffect(new MyGraphicsEffect); + break; + default: + break; + } + } +protected: + void paintEvent(QPaintEvent *) {} + void mousePressEvent(QMouseEvent *) {} + void mouseReleaseEvent(QMouseEvent *) {} + +private: +}; + +#include "main.moc" + + int main(int argc, char **argv) { QApplication app(argc, argv); @@ -62,17 +156,21 @@ int main(int argc, char **argv) scene.addItem(item); } - Robot *robot = new Robot; + robot = new Robot; robot->scale(1.2, 1.2); robot->setPos(0, -20); scene.addItem(robot); QGraphicsView view(&scene); view.setRenderHint(QPainter::Antialiasing); - view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate); view.setBackgroundBrush(QColor(230, 200, 167)); view.setWindowTitle("Drag and Drop Robot"); + // view.rotate(45); view.show(); + MyWidget widget; + widget.show(); + return app.exec(); } diff --git a/examples/graphicsview/dragdroprobot/robot.cpp b/examples/graphicsview/dragdroprobot/robot.cpp index 029a2ce..796336a 100644 --- a/examples/graphicsview/dragdroprobot/robot.cpp +++ b/examples/graphicsview/dragdroprobot/robot.cpp @@ -164,6 +164,13 @@ void RobotLimb::paint(QPainter *painter, Robot::Robot() { QGraphicsItem *torsoItem = new RobotTorso(this); + // torsoItem->setGraphicsEffect(new QGraphicsBloomEffect); + // torsoItem->setGraphicsEffect(new QGraphicsBlurEffect); + // torsoItem->setGraphicsEffect(new QGraphicsFrameEffect); + // torsoItem->setGraphicsEffect(new QGraphicsShadowEffect); + // torsoItem->setGraphicsEffect(new QGraphicsColorizeEffect); + // torsoItem->setGraphicsEffect(new QGraphicsPixelizeEffect); + // torsoItem->setGraphicsEffect(new QGraphicsGrayscaleEffect); QGraphicsItem *headItem = new RobotHead(torsoItem); QGraphicsItem *upperLeftArmItem = new RobotLimb(torsoItem); QGraphicsItem *lowerLeftArmItem = new RobotLimb(upperLeftArmItem); diff --git a/src/gui/graphicsview/qgraphicseffect.cpp b/src/gui/graphicsview/qgraphicseffect.cpp index 8d2c416..ed529db 100644 --- a/src/gui/graphicsview/qgraphicseffect.cpp +++ b/src/gui/graphicsview/qgraphicseffect.cpp @@ -102,6 +102,29 @@ */ +QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent) + : QObject(dd, parent) +{} + +QGraphicsEffectSource::~QGraphicsEffectSource() +{} + +QRectF QGraphicsEffectSource::boundingRect(bool deviceCoordinates) const +{ return d_func()->boundingRect(deviceCoordinates); } + +const QGraphicsItem *QGraphicsEffectSource::graphicsItem() const +{ return d_func()->graphicsItem(); } + +const QStyleOption *QGraphicsEffectSource::styleOption() const +{ return d_func()->styleOption(); } + +void QGraphicsEffectSource::draw(QPainter *painter) +{ d_func()->draw(painter); } + +bool QGraphicsEffectSource::drawIntoPixmap(QPixmap *pixmap, const QPoint &offset) +{ return d_func()->drawIntoPixmap(pixmap, offset); } + + QGraphicsEffect::QGraphicsEffect() : QObject(*new QGraphicsEffectPrivate, 0) {} @@ -121,31 +144,40 @@ QGraphicsEffect::~QGraphicsEffect() QRectF QGraphicsEffect::boundingRect() const { - return sourceBoundingRect(); -} - -QRectF QGraphicsEffect::sourceBoundingRect() const -{ Q_D(const QGraphicsEffect); + // return d->boundingRect; if (d->source) - return d->source->boundingRect(); + return boundingRectFor(d->source->boundingRect()); return QRectF(); } -void QGraphicsEffect::drawSource(QPainter *painter) +QRectF QGraphicsEffect::boundingRectFor(const QRectF &rect) const { - Q_D(QGraphicsEffect); - if (d->source) - d->source->draw(painter); + return rect; } -bool QGraphicsEffect::drawSourceIntoPixmap(QPixmap *pixmap, const QTransform &itemToPixmapTransform) -{ - Q_D(QGraphicsEffect); - if (d->source) - return d->source->drawIntoPixmap(pixmap, itemToPixmapTransform); - return false; -} +//QRectF QGraphicsEffect::sourceBoundingRect(bool deviceCoordinates) const +//{ +// Q_D(const QGraphicsEffect); +// if (d->source) +// return d->source->boundingRect(deviceCoordinates); +// return QRectF(); +//} + +//void QGraphicsEffect::drawSource(QPainter *painter) +//{ +// Q_D(QGraphicsEffect); +// if (d->source) +// d->source->d_func()->draw(painter); +//} + +//bool QGraphicsEffect::drawSourceIntoPixmap(QPixmap *pixmap, const QPoint &offset) +//{ +// Q_D(QGraphicsEffect); +// if (d->source) +// return d->source->d_func()->drawIntoPixmap(pixmap, offset); +// return false; +//} QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect() : QGraphicsEffect(*new QGraphicsGrayscaleEffectPrivate) @@ -154,30 +186,20 @@ QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect() QGraphicsGrayscaleEffect::~QGraphicsGrayscaleEffect() {} -void QGraphicsGrayscaleEffect::draw(QPainter *painter) +void QGraphicsGrayscaleEffect::draw(QPainter *painter, QGraphicsEffectSource *source) { Q_D(QGraphicsGrayscaleEffect); - if (!d->source) - return; - // Find the item's bounds in device coordinates. - QTransform itemToPixmapTransform(painter->worldTransform()); - QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); - QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); - if (deviceRect.isEmpty()) - return; - - if (deviceRect.x() != 0 || deviceRect.y() != 0) - itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y()); - - QPixmap pixmap(deviceRect.size()); - if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) + const QRect sourceRect = source->boundingRect(/*deviceCoordinates=*/true) + .toRect().adjusted(-1, -1, 1, 1); + QPixmap pixmap(sourceRect.size()); + if (!source->drawIntoPixmap(&pixmap, sourceRect.topLeft())) 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, sourceRect.topLeft(), pixmap, pixmap.rect()); painter->setWorldTransform(restoreTransform); } @@ -201,30 +223,19 @@ void QGraphicsColorizeEffect::setColor(const QColor &c) d->filter->setColor(c); } -void QGraphicsColorizeEffect::draw(QPainter *painter) +void QGraphicsColorizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source) { Q_D(QGraphicsColorizeEffect); - if (!d->source) - return; - - // Find the item's bounds in device coordinates. - QTransform itemToPixmapTransform(painter->worldTransform()); - QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); - QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); - if (deviceRect.isEmpty()) - return; - - if (deviceRect.x() != 0 || deviceRect.y() != 0) - itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y()); - - QPixmap pixmap(deviceRect.size()); - if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) + const QRect sourceRect = source->boundingRect(/*deviceCoordinates=*/true) + .toRect().adjusted(-1, -1, 1, 1); + QPixmap pixmap(sourceRect.size()); + if (!source->drawIntoPixmap(&pixmap, sourceRect.topLeft())) 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, sourceRect.topLeft(), pixmap, pixmap.rect()); painter->setWorldTransform(restoreTransform); } @@ -249,24 +260,14 @@ void QGraphicsPixelizeEffect::setPixelSize(int size) d->pixelSize = size; } -void QGraphicsPixelizeEffect::draw(QPainter *painter) +void QGraphicsPixelizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source) { Q_D(QGraphicsPixelizeEffect); - if (!d->source) - return; - // Find the item's bounds in device coordinates. - QTransform itemToPixmapTransform(painter->worldTransform()); - QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); - QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); - if (deviceRect.isEmpty()) - return; - - if (deviceRect.x() != 0 || deviceRect.y() != 0) - itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y()); - - QPixmap pixmap(deviceRect.size()); - if (!d->source->drawIntoPixmap(&pixmap)) + const QRect sourceRect = source->boundingRect(/*deviceCoordinates=*/true) + .toRect().adjusted(-1, -1, 1, 1); + QPixmap pixmap(sourceRect.size()); + if (!source->drawIntoPixmap(&pixmap, sourceRect.topLeft())) return; // pixelize routine @@ -292,7 +293,7 @@ void QGraphicsPixelizeEffect::draw(QPainter *painter) // Draw using an untransformed painter. QTransform restoreTransform = painter->worldTransform(); painter->setWorldTransform(QTransform()); - painter->drawImage(deviceRect.topLeft(), img); + painter->drawImage(sourceRect.topLeft(), img); painter->setWorldTransform(restoreTransform); } @@ -382,42 +383,32 @@ void QGraphicsBlurEffect::setBlurRadius(int radius) d->filter->setBlurRadius(radius); } -QRectF QGraphicsBlurEffect::boundingRect() const +QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const { Q_D(const QGraphicsBlurEffect); - if (d->source) - return d->filter->boundingRectFor(d->source->boundingRect()); - return QRectF(); + return d->filter->boundingRectFor(rect); } -void QGraphicsBlurEffect::draw(QPainter *painter) +//QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const +//{ +// Q_D(const QGraphicsBlurEffect); +// return d->filter->boundingRectFor(rect); +//} + +void QGraphicsBlurEffect::draw(QPainter *painter, QGraphicsEffectSource *source) { Q_D(QGraphicsBlurEffect); - if (!d->source) - return; - - // Find the item's bounds in device coordinates. - QTransform itemToPixmapTransform(painter->worldTransform()); - QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); - QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); - if (deviceRect.isEmpty()) - return; - - // ### 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()); + const QRectF sourceRect = source->boundingRect(/*deviceCoordinates=*/true); + const QRect effectRect = d->filter->boundingRectFor(sourceRect).toRect().adjusted(-1, -1, 1, 1); QPixmap pixmap(effectRect.size()); - if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) + if (!source->drawIntoPixmap(&pixmap, effectRect.topLeft())) 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, sourceRect.topLeft(), pixmap, pixmap.rect()); painter->setWorldTransform(restoreTransform); } @@ -454,13 +445,20 @@ void QGraphicsBloomEffect::setOpacity(qreal alpha) d->opacity = alpha; } -QRectF QGraphicsBloomEffect::boundingRect() const +//QRectF QGraphicsBloomEffect::boundingRectFor(nst QGraphicsEffectSource *source) const +//{ +// Q_D(const QGraphicsBloomEffect); +// if (!d->source) +// return QRectF(); +// const qreal delta = d->blurRadius * 3; +// return sourceBoundingRect().adjusted(-delta, -delta, delta, delta); +//} + +QRectF QGraphicsBloomEffect::boundingRectFor(const QRectF &rect) const { Q_D(const QGraphicsBloomEffect); - if (!d->source) - return QRectF(); - qreal delta = d->blurRadius * 3; - return d->source->boundingRect().adjusted(-delta, -delta, delta, delta); + const qreal delta = d->blurRadius * 3; + return rect.adjusted(-delta, -delta, delta, delta); } // Change brightness (positive integer) of each pixel @@ -494,24 +492,14 @@ static QImage composited(const QImage& img1, const QImage& img2, qreal opacity, return result; } -void QGraphicsBloomEffect::draw(QPainter *painter) +void QGraphicsBloomEffect::draw(QPainter *painter, QGraphicsEffectSource *source) { Q_D(QGraphicsBloomEffect); - if (!d->source) - return; - - // Find the item's bounds in device coordinates. - QTransform itemToPixmapTransform(painter->worldTransform()); - QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); - QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); - if (deviceRect.isEmpty()) - return; - - if (deviceRect.x() != 0 || deviceRect.y() != 0) - itemToPixmapTransform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y()); + const QRectF sourceRect = source->boundingRect(/*deviceCoordinates=*/true); + const QRect effectRect = boundingRectFor(sourceRect).toRect().adjusted(-1, -1, 1, 1); - QPixmap pixmap(deviceRect.size()); - if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) + QPixmap pixmap(effectRect.size()); + if (!source->drawIntoPixmap(&pixmap, effectRect.topLeft())) return; // bloom routine @@ -524,7 +512,7 @@ void QGraphicsBloomEffect::draw(QPainter *painter) // Draw using an untransformed painter. QTransform restoreTransform = painter->worldTransform(); painter->setWorldTransform(QTransform()); - painter->drawImage(deviceRect.topLeft() - QPointF(radius * 3, radius * 3), img); + painter->drawImage(effectRect.topLeft(), img); painter->setWorldTransform(restoreTransform); } @@ -573,49 +561,31 @@ void QGraphicsFrameEffect::setFrameOpacity(qreal opacity) d->alpha = opacity; } -QRectF QGraphicsFrameEffect::boundingRect() const +//QRectF QGraphicsFrameEffect::boundingRect() const +//{ +// Q_D(const QGraphicsFrameEffect); +// if (!d->source) +// return QRectF(); +// return d->source->boundingRect().adjusted(-d->width, -d->width, d->width, d->width); +//} + +QRectF QGraphicsFrameEffect::boundingRectFor(const QRectF &rect) const { Q_D(const QGraphicsFrameEffect); - if (!d->source) - return QRectF(); - return d->source->boundingRect().adjusted(-d->width, -d->width, d->width, d->width); + return rect.adjusted(-d->width, -d->width, d->width, d->width); } -void QGraphicsFrameEffect::draw(QPainter *painter) +void QGraphicsFrameEffect::draw(QPainter *painter, QGraphicsEffectSource *source) { Q_D(QGraphicsFrameEffect); - if (!d->source) - return; - - // Find the item's bounds in device coordinates. - QTransform itemToPixmapTransform(painter->worldTransform()); - QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); - if (deviceBounds.isEmpty()) - 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()); - - QPixmap pixmap(frameRect.size()); - if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) - return; - - painter->save(); - painter->setWorldTransform(QTransform()); - painter->save(); painter->setOpacity(painter->opacity() * d->alpha); painter->setPen(Qt::NoPen); painter->setBrush(d->color); - painter->drawRoundedRect(frameRect, 20, 20, Qt::RelativeSize); + painter->drawRoundedRect(boundingRect(), 20, 20, Qt::RelativeSize); painter->restore(); - painter->drawPixmap(frameRect.topLeft(), pixmap); - - painter->restore(); + source->draw(painter); } QGraphicsShadowEffect::QGraphicsShadowEffect() @@ -663,46 +633,50 @@ void QGraphicsShadowEffect::setOpacity(qreal opacity) d->alpha = opacity; } -QRectF QGraphicsShadowEffect::boundingRect() const +//QRectF QGraphicsShadowEffect::boundingRect() const +//{ +// 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(srcBrect); +// return totalRect; +//} + +QRectF QGraphicsShadowEffect::boundingRectFor(const QRectF &rect) const { Q_D(const QGraphicsShadowEffect); - if (!d->source) - return QRectF(); - const QRectF srcBrect = d->source->boundingRect(); - QRectF shadowRect = srcBrect; + QRectF shadowRect = rect; 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(srcBrect); + QRectF totalRect = blurRect.united(rect); return totalRect; } -void QGraphicsShadowEffect::draw(QPainter *painter) +void QGraphicsShadowEffect::draw(QPainter *painter, QGraphicsEffectSource *source) { Q_D(QGraphicsShadowEffect); if (!d->source) return; - // Find the item's bounds in device coordinates. - QTransform itemToPixmapTransform(painter->worldTransform()); - QRectF deviceBounds = itemToPixmapTransform.mapRect(d->source->boundingRect()); - QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); - if (deviceRect.isEmpty()) - return; + const QRectF sourceRect = source->boundingRect(/*deviceCoordinates=*/true); - QRectF shadowRect = deviceBounds; + QRectF shadowRect = sourceRect; 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); - QRect totalRect = blurRect.united(deviceRect).toRect().adjusted(-1, -1, 1, 1); - - if (totalRect.x() != 0 || totalRect.y() != 0) - itemToPixmapTransform *= QTransform::fromTranslate(-totalRect.x(), -totalRect.y()); + QRect totalRect = blurRect.united(sourceRect).toRect().adjusted(-1, -1, 1, 1); QPixmap pixmap(totalRect.size()); - if (!d->source->drawIntoPixmap(&pixmap, itemToPixmapTransform)) + if (!source->drawIntoPixmap(&pixmap, totalRect.topLeft())) return; QImage img = pixmap.toImage(); @@ -719,14 +693,14 @@ void QGraphicsShadowEffect::draw(QPainter *painter) qreal shadowx = blurRect.x() + delta; qreal shadowy = blurRect.y() + delta; - if (blurRect.x() < deviceRect.x()) - shadowx = blurRect.x() + d->offset.x(); - if (blurRect.y() < deviceRect.y()) + if (blurRect.x() < sourceRect.x()) + shadowx = sourceRect.x() + d->offset.x(); + if (blurRect.y() < sourceRect.y()) shadowy = blurRect.y() + d->offset.y(); painter->drawImage(shadowx, shadowy, shadowImage); - qreal itemx = qMin(blurRect.x(), deviceBounds.x()); - qreal itemy = qMin(blurRect.y(), deviceBounds.y()); + qreal itemx = qMin(blurRect.x(), sourceRect.x()); + qreal itemy = qMin(blurRect.y(), sourceRect.y()); painter->drawPixmap(itemx, itemy, pixmap); painter->setWorldTransform(restoreTransform); diff --git a/src/gui/graphicsview/qgraphicseffect.h b/src/gui/graphicsview/qgraphicseffect.h index 74a8430..c13461e 100644 --- a/src/gui/graphicsview/qgraphicseffect.h +++ b/src/gui/graphicsview/qgraphicseffect.h @@ -64,6 +64,30 @@ QT_MODULE(Gui) #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW +class QGraphicsEffectSourcePrivate; +class Q_GUI_EXPORT QGraphicsEffectSource : public QObject +{ + Q_OBJECT +public: + ~QGraphicsEffectSource(); + QRectF boundingRect(bool deviceCoordinates = false) const; + const QGraphicsItem *graphicsItem() const; + const QStyleOption *styleOption() const; + void draw(QPainter *painter); + bool drawIntoPixmap(QPixmap *pixmap, const QPoint &offset = QPoint()); + +protected: + QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent = 0); + +private: + Q_DECLARE_PRIVATE(QGraphicsEffectSource); + Q_DISABLE_COPY(QGraphicsEffectSource); + friend class QGraphicsEffect; + friend class QGraphicsEffectPrivate; + friend class QGraphicsScenePrivate; + friend class QGraphicsItem; +}; + class QGraphicsEffectPrivate; class Q_GUI_EXPORT QGraphicsEffect : public QObject { @@ -71,21 +95,19 @@ class Q_GUI_EXPORT QGraphicsEffect : public QObject public: QGraphicsEffect(); virtual ~QGraphicsEffect(); - - virtual QRectF boundingRect() const; + QRectF boundingRect() const; protected: QGraphicsEffect(QGraphicsEffectPrivate &d); - virtual void draw(QPainter *painter) = 0; - void drawSource(QPainter *painter); - bool drawSourceIntoPixmap(QPixmap *pixmap, const QTransform &xform = QTransform()); - QRectF sourceBoundingRect() const; + virtual QRectF boundingRectFor(const QRectF &rect) const; + virtual void draw(QPainter *painter, QGraphicsEffectSource *source) = 0; private: - friend class QGraphicsScenePrivate; - friend class QGraphicsItem; Q_DECLARE_PRIVATE(QGraphicsEffect) Q_DISABLE_COPY(QGraphicsEffect) + friend class QGraphicsItem; + friend class QGraphicsItemPrivate; + friend class QGraphicsScenePrivate; }; class QGraphicsGrayscaleEffectPrivate; @@ -97,7 +119,7 @@ public: ~QGraphicsGrayscaleEffect(); protected: - void draw(QPainter *painter); + void draw(QPainter *painter, QGraphicsEffectSource *source); private: Q_DECLARE_PRIVATE(QGraphicsGrayscaleEffect) @@ -115,7 +137,7 @@ public: void setColor(const QColor &c); protected: - void draw(QPainter *painter); + void draw(QPainter *painter, QGraphicsEffectSource *source); private: Q_DECLARE_PRIVATE(QGraphicsColorizeEffect) @@ -133,7 +155,7 @@ public: void setPixelSize(int pixelSize); protected: - void draw(QPainter *painter); + void draw(QPainter *painter, QGraphicsEffectSource *source); private: Q_DECLARE_PRIVATE(QGraphicsPixelizeEffect) @@ -150,10 +172,11 @@ public: int blurRadius() const; void setBlurRadius(int blurRadius); - QRectF boundingRect() const; + // QRectF boundingRect() const; protected: - void draw(QPainter *painter); + QRectF boundingRectFor(const QRectF &rect) const; + void draw(QPainter *painter, QGraphicsEffectSource *source); private: Q_DECLARE_PRIVATE(QGraphicsBlurEffect) @@ -173,10 +196,11 @@ public: qreal opacity() const; void setOpacity(qreal opacity); - QRectF boundingRect() const; + // QRectF boundingRect() const; protected: - void draw(QPainter *painter); + QRectF boundingRectFor(const QRectF &rect) const; + void draw(QPainter *painter, QGraphicsEffectSource *source); private: Q_DECLARE_PRIVATE(QGraphicsBloomEffect) @@ -199,10 +223,11 @@ public: qreal frameOpacity() const; void setFrameOpacity(qreal opacity); - QRectF boundingRect() const; + // QRectF boundingRect() const; protected: - void draw(QPainter *painter); + QRectF boundingRectFor(const QRectF &rect) const; + void draw(QPainter *painter, QGraphicsEffectSource *source); private: Q_DECLARE_PRIVATE(QGraphicsFrameEffect) @@ -227,10 +252,11 @@ public: qreal opacity() const; void setOpacity(qreal opacity); - QRectF boundingRect() const; + // QRectF boundingRect() const; protected: - void draw(QPainter *painter); + QRectF boundingRectFor(const QRectF &rect) const; + void draw(QPainter *painter, QGraphicsEffectSource *source); private: Q_DECLARE_PRIVATE(QGraphicsShadowEffect) diff --git a/src/gui/graphicsview/qgraphicseffect_p.h b/src/gui/graphicsview/qgraphicseffect_p.h index 9204789..ce90193 100644 --- a/src/gui/graphicsview/qgraphicseffect_p.h +++ b/src/gui/graphicsview/qgraphicseffect_p.h @@ -61,15 +61,21 @@ QT_BEGIN_NAMESPACE -class QGraphicsEffectSource +class QGraphicsEffectSourcePrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QGraphicsEffectSource) public: - QGraphicsEffectSource() {} - virtual ~QGraphicsEffectSource() {} + QGraphicsEffectSourcePrivate() : QObjectPrivate() {} + virtual ~QGraphicsEffectSourcePrivate() {} virtual void detach() = 0; - virtual QRectF boundingRect() = 0; + virtual QRectF boundingRect(bool deviceCoordinates = false) const = 0; + virtual const QGraphicsItem *graphicsItem() const = 0; + virtual const QStyleOption *styleOption() const = 0; virtual void draw(QPainter *p) = 0; - virtual bool drawIntoPixmap(QPixmap *, const QTransform & = QTransform()) = 0; + virtual bool drawIntoPixmap(QPixmap *, const QPoint &offset = QPoint()) = 0; + friend class QGraphicsScenePrivate; + friend class QGraphicsItem; + friend class QGraphicsItemPrivate; }; class QGraphicsEffectPrivate : public QObjectPrivate @@ -81,11 +87,12 @@ public: inline void setGraphicsEffectSource(QGraphicsEffectSource *newSource) { if (source) { - source->detach(); + source->d_func()->detach(); delete source; } source = newSource; } + QRectF boundingRect; }; class QGraphicsGrayscaleEffectPrivate : public QGraphicsEffectPrivate diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 1d271c9..b46abd4 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1016,10 +1016,10 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent) */ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect) { - if (!dirtyChildrenBoundingRect) { - *rect |= x->mapRect(childrenBoundingRect); - return; - } + // if (!dirtyChildrenBoundingRect) { + // *rect |= x->mapRect(childrenBoundingRect); + // return; + // } for (int i = 0; i < children.size(); ++i) { QGraphicsItem *child = children.at(i); @@ -2231,7 +2231,9 @@ void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) oldEffectPrivate->setGraphicsEffectSource(0); // deletes the current source. } else { // Set new effect. - effect->d_func()->setGraphicsEffectSource(new QGraphicsItemEffectSource(this)); + QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this); + QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced); + effect->d_func()->setGraphicsEffectSource(source); d_ptr->graphicsEffect = effect; } @@ -3843,8 +3845,8 @@ void QGraphicsItem::setZValue(qreal z) */ QRectF QGraphicsItem::childrenBoundingRect() const { - if (!d_ptr->dirtyChildrenBoundingRect) - return d_ptr->childrenBoundingRect; + // if (!d_ptr->dirtyChildrenBoundingRect) + // return d_ptr->childrenBoundingRect; QRectF childRect; QTransform x; @@ -9924,6 +9926,54 @@ int QGraphicsItemGroup::type() const return Type; } +QRectF QGraphicsItemEffectSourcePrivate::boundingRect(bool deviceCoordinates) const +{ + QRectF rect = item->boundingRect(); + rect |= item->childrenBoundingRect(); + if (deviceCoordinates && info) { + Q_ASSERT(info->transformPtr); + return info->transformPtr->mapRect(rect); + } + return rect; +} + +void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter) +{ + QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); + scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion, + info->widget, info->opacity, 0, info->wasDirtySceneTransform, info->drawItem); +} + +bool QGraphicsItemEffectSourcePrivate::drawIntoPixmap(QPixmap *pixmap, const QPoint &offset) +{ + QPoint effectOffset(offset); + + QTransform viewTransform(Qt::Uninitialized); + if (info->viewTransform) { + viewTransform = *info->viewTransform; + viewTransform *= QTransform::fromTranslate(-effectOffset.x(), -effectOffset.y()); + } else { + viewTransform = QTransform::fromTranslate(-effectOffset.x(), -effectOffset.y()); + } + + *info->transformPtr *= QTransform::fromTranslate(-effectOffset.x(), -effectOffset.y()); + + QRegion exposedRegion; + if (info->exposedRegion) { + exposedRegion = *info->exposedRegion; + exposedRegion.translate(-effectOffset.x(), -effectOffset.y()); + } + + pixmap->fill(Qt::transparent); + QPainter pixmapPainter(pixmap); + pixmapPainter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing); + QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); + scened->draw(item, &pixmapPainter, &viewTransform, info->transformPtr, &exposedRegion, + info->widget, info->opacity, &effectOffset, info->wasDirtySceneTransform, + info->drawItem); + return true; +} + #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 0c0b341..0c20829 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -457,6 +457,7 @@ private: friend class QGraphicsSceneIndexPrivate; friend class QGraphicsSceneBspTreeIndex; friend class QGraphicsSceneBspTreeIndexPrivate; + friend class QGraphicsItemEffectSourcePrivate; friend class ::tst_QGraphicsItem; friend bool qt_closestLeaf(const QGraphicsItem *, const QGraphicsItem *); friend bool qt_closestItemFirst(const QGraphicsItem *, const QGraphicsItem *); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index dc875f7..0823e51 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -510,44 +510,50 @@ struct QGraphicsItemPrivate::TransformData { } }; -class QGraphicsItemEffectSource : public QGraphicsEffectSource +struct QGraphicsItemPaintInfo +{ + inline QGraphicsItemPaintInfo(const QTransform *const xform1, QTransform *xform2, + QRegion *r, QWidget *w, QStyleOptionGraphicsItem *opt, + qreal o, bool b1, bool b2) + : viewTransform(xform1), transformPtr(xform2), exposedRegion(r), widget(w), + option(opt), opacity(o), wasDirtySceneTransform(b1), drawItem(b2) + {} + + const QTransform *viewTransform; + QTransform *transformPtr; + QRegion *exposedRegion; + QWidget *widget; + QStyleOptionGraphicsItem *option; + qreal opacity; + quint32 wasDirtySceneTransform : 1; + quint32 drawItem : 1; +}; + +class QGraphicsItemEffectSourcePrivate : public QGraphicsEffectSourcePrivate { public: - QGraphicsItemEffectSource(QGraphicsItem *i) - : QGraphicsEffectSource(), item(i), option(0), widget(0) + QGraphicsItemEffectSourcePrivate(QGraphicsItem *i) + : QGraphicsEffectSourcePrivate(), item(i), info(0) {} inline void detach() { item->setGraphicsEffect(0); } - inline QRectF boundingRect() - { return item->boundingRect(); } + inline const QGraphicsItem *graphicsItem() const + { return item; } - inline void draw(QPainter *painter) - { item->paint(painter, option, widget); } + inline const QStyleOption *styleOption() const + { return info ? info->option : 0; } - 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; } + QRectF boundingRect(bool deviceCoordinates) const; + void draw(QPainter *); + bool drawIntoPixmap(QPixmap *pixmap, const QPoint &offset); - void resetPaintInfo() - { option = 0; widget = 0; } - -private: QGraphicsItem *item; - const QStyleOptionGraphicsItem *option; - QWidget *widget; + QGraphicsItemPaintInfo *info; }; + /*! \internal */ diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index f4fd4ce..31ec1ba 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -208,7 +208,7 @@ #ifndef QT_NO_GRAPHICSVIEW -#include "qgraphicseffect.h" +#include "qgraphicseffect_p.h" #include "qgraphicsitem.h" #include "qgraphicsitem_p.h" #include "qgraphicslayout.h" @@ -3920,19 +3920,6 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte QGraphicsItemPrivate *itemd = item->d_ptr; QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode); - bool noCache = cacheMode == QGraphicsItem::NoCache || -#ifdef Q_WS_X11 - !X11->use_xrender; -#else - false; -#endif - - // Render using effect, works now only for no cache mode - if (noCache && itemd->graphicsEffect) { - itemd->graphicsEffect->draw(painter); - return; - } - // Render directly, using no cache. if (cacheMode == QGraphicsItem::NoCache #ifdef Q_WS_X11 @@ -4245,7 +4232,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, QPoint *effectOffset) { Q_ASSERT(item); @@ -4298,7 +4285,10 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * 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, effectOffset ? + viewBoundingRect.translated(*effectOffset) : viewBoundingRect); + } viewBoundingRect.adjust(-1, -1, 1, 1); drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty(); if (!drawItem) { @@ -4312,13 +4302,42 @@ 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) { + ENSURE_TRANSFORM_PTR; + QGraphicsItemPaintInfo info(viewTransform, transformPtr, exposedRegion, widget, &styleOptionTmp, + 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(); + painter->setWorldTransform(*transformPtr); + item->d_ptr->graphicsEffect->draw(painter, source); + painter->setWorldTransform(restoreTransform); + } else { + draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity, + effectOffset, wasDirtyParentSceneTransform, drawItem); + } +} + +void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform, + const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget, qreal opacity, + QPoint *effectOffset, 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 + Q_ASSERT(transformPtr); painter->setWorldTransform(*transformPtr); painter->setClipPath(item->shape(), Qt::IntersectClip); } @@ -4332,15 +4351,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, effectOffset); } } // 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); @@ -4356,21 +4375,11 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * painter->setClipPath(item->shape(), Qt::IntersectClip); painter->setOpacity(opacity); - 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) + if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget) item->paint(painter, &styleOptionTmp, widget); else drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection); - if (source) - source->resetPaintInfo(); - if (savePainter) painter->restore(); } @@ -4383,7 +4392,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, effectOffset); } } diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index 1606053..813e000 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -306,6 +306,7 @@ private: 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 38f5682..b602758 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -200,7 +200,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), + QPoint *effectOffset = 0); + void draw(QGraphicsItem *, QPainter *, const QTransform *const, const QTransform *const, + QRegion *, QWidget *, qreal, QPoint *, 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); |