diff options
author | Bjørn Erik Nilsen <bjorn.nilsen@nokia.com> | 2009-08-21 09:33:44 (GMT) |
---|---|---|
committer | Bjørn Erik Nilsen <bjorn.nilsen@nokia.com> | 2009-08-21 11:51:32 (GMT) |
commit | 00d7d50cde5d1e491039149d58502e17dba9b3b7 (patch) | |
tree | ba59ef8f83677c0c7c74b7db2f3f7a55c2887c16 | |
parent | 487f636523dfded4c07a39e4d96ab3e83c64f95e (diff) | |
download | Qt-00d7d50cde5d1e491039149d58502e17dba9b3b7.zip Qt-00d7d50cde5d1e491039149d58502e17dba9b3b7.tar.gz Qt-00d7d50cde5d1e491039149d58502e17dba9b3b7.tar.bz2 |
Use pixmap filter for the drop shadow effect.
-rw-r--r-- | examples/effects/lighting/shadoweffect.cpp | 6 | ||||
-rw-r--r-- | examples/effects/lighting/shadoweffect.h | 1 | ||||
-rw-r--r-- | src/gui/effects/qgraphicseffect.cpp | 155 | ||||
-rw-r--r-- | src/gui/effects/qgraphicseffect.h | 24 | ||||
-rw-r--r-- | src/gui/effects/qgraphicseffect_p.h | 10 | ||||
-rw-r--r-- | tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 2 |
6 files changed, 48 insertions, 150 deletions
diff --git a/examples/effects/lighting/shadoweffect.cpp b/examples/effects/lighting/shadoweffect.cpp index 9545815..8a41aaa 100644 --- a/examples/effects/lighting/shadoweffect.cpp +++ b/examples/effects/lighting/shadoweffect.cpp @@ -48,17 +48,19 @@ ShadowEffect::ShadowEffect(QGraphicsItem *item, QGraphicsItem *source) , item(item), m_lightSource(source) { setBlurRadius(8); + m_color = color(); } void ShadowEffect::adjustForItem() { QPointF delta = item->pos() - m_lightSource->pos(); - setShadowOffset(delta.toPoint() / 30); + setOffset(delta.toPoint() / 30); qreal dx = delta.x(); qreal dy = delta.y(); qreal dd = sqrt(dx * dx + dy * dy); - setOpacity(qBound(0.4, 1 - dd / 200.0, 0.7)); + m_color.setAlphaF(qBound(0.4, 1 - dd / 200.0, 0.7)); + setColor(m_color); } QRectF ShadowEffect::boundingRectFor(const QRectF &rect) const diff --git a/examples/effects/lighting/shadoweffect.h b/examples/effects/lighting/shadoweffect.h index b20f647..7ea409e 100644 --- a/examples/effects/lighting/shadoweffect.h +++ b/examples/effects/lighting/shadoweffect.h @@ -58,6 +58,7 @@ private: void adjustForItem(); private: + QColor m_color; QGraphicsItem *item; QGraphicsItem *m_lightSource; }; diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index 3d363f1..949922a 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -432,71 +432,6 @@ QGraphicsBlurEffect::~QGraphicsBlurEffect() { } -// Blur the image according to the blur radius -// Based on exponential blur algorithm by Jani Huhtanen -// (maximum radius is set to 16) -static QImage blurred(const QImage& image, const QRect& rect, int radius) -{ - int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; - int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; - - QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); - int r1 = rect.top(); - int r2 = rect.bottom(); - int c1 = rect.left(); - int c2 = rect.right(); - - int bpl = result.bytesPerLine(); - int rgba[4]; - unsigned char* p; - - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r1) + col * 4; - for (int i = 0; i < 4; i++) - rgba[i] = p[i] << 4; - - p += bpl; - for (int j = r1; j < r2; j++, p += bpl) - for (int i = 0; i < 4; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c1 * 4; - for (int i = 0; i < 4; i++) - rgba[i] = p[i] << 4; - - p += 4; - for (int j = c1; j < c2; j++, p += 4) - for (int i = 0; i < 4; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r2) + col * 4; - for (int i = 0; i < 4; i++) - rgba[i] = p[i] << 4; - - p -= bpl; - for (int j = r1; j < r2; j++, p -= bpl) - for (int i = 0; i < 4; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c2 * 4; - for (int i = 0; i < 4; i++) - rgba[i] = p[i] << 4; - - p -= 4; - for (int j = c1; j < c2; j++, p -= 4) - for (int i = 0; i < 4; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - return result; -} - int QGraphicsBlurEffect::blurRadius() const { Q_D(const QGraphicsBlurEffect); @@ -553,121 +488,83 @@ QGraphicsDropShadowEffect::~QGraphicsDropShadowEffect() { } -QPointF QGraphicsDropShadowEffect::shadowOffset() const +QPointF QGraphicsDropShadowEffect::offset() const { Q_D(const QGraphicsDropShadowEffect); - return d->offset; + return d->filter->offset(); } -void QGraphicsDropShadowEffect::setShadowOffset(const QPointF &ofs) +void QGraphicsDropShadowEffect::setOffset(const QPointF &ofs) { Q_D(QGraphicsDropShadowEffect); - if (d->offset == ofs) + if (d->filter->offset() == ofs) return; - d->offset = ofs; + d->filter->setOffset(ofs); updateBoundingRect(); - emit shadowOffsetChanged(ofs); + emit offsetChanged(ofs); } int QGraphicsDropShadowEffect::blurRadius() const { Q_D(const QGraphicsDropShadowEffect); - return d->radius; + return d->filter->blurRadius(); } void QGraphicsDropShadowEffect::setBlurRadius(int blurRadius) { Q_D(QGraphicsDropShadowEffect); - if (d->radius == blurRadius) + if (d->filter->blurRadius() == blurRadius) return; - d->radius = blurRadius; + d->filter->setBlurRadius(blurRadius); updateBoundingRect(); emit blurRadiusChanged(blurRadius); } -qreal QGraphicsDropShadowEffect::opacity() const +QColor QGraphicsDropShadowEffect::color() const { Q_D(const QGraphicsDropShadowEffect); - return d->alpha; + return d->filter->color(); } -void QGraphicsDropShadowEffect::setOpacity(qreal opacity) +void QGraphicsDropShadowEffect::setColor(const QColor &color) { Q_D(QGraphicsDropShadowEffect); - if (qFuzzyCompare(d->alpha, opacity)) + if (d->filter->color() == color) return; - d->alpha = opacity; - emit opacityChanged(opacity); + d->filter->setColor(color); + emit colorChanged(color); } QRectF QGraphicsDropShadowEffect::boundingRectFor(const QRectF &rect) const { Q_D(const QGraphicsDropShadowEffect); - QRectF shadowRect = rect.translated(d->offset); - QRectF blurRect = shadowRect; - qreal delta = d->radius * 3; - blurRect.adjust(-delta, -delta, delta, delta); - blurRect |= rect; - return blurRect; + return d->filter->boundingRectFor(rect); } void QGraphicsDropShadowEffect::draw(QPainter *painter, QGraphicsEffectSource *source) { Q_D(QGraphicsDropShadowEffect); - if (d->radius <= 0 && d->offset.isNull()) { + if (d->filter->blurRadius() <= 0 && d->filter->offset().isNull()) { source->draw(painter); return; } - const QTransform &transform = painter->worldTransform(); - const QPointF offset(d->offset.x() * transform.m11(), d->offset.y() * transform.m22()); - const QPoint shadowOffset = offset.toPoint(); - const QRectF sourceRect = source->boundingRect(Qt::DeviceCoordinates); - const QRectF shadowRect = sourceRect.translated(offset); - - QRectF blurRect = shadowRect; - qreal delta = d->radius * 3; - blurRect.adjust(-delta, -delta, delta, delta); - blurRect |= sourceRect; - - QRect effectRect = blurRect.toAlignedRect(); - const QRect deviceRect = source->deviceRect(); - const bool fullyInsideDeviceRect = effectRect.x() >= deviceRect.x() - && effectRect.right() <= deviceRect.right() - && effectRect.y() >= deviceRect.y() - && effectRect.bottom() <= deviceRect.bottom(); - if (!fullyInsideDeviceRect) { - // Clip to device rect to avoid huge pixmaps. - effectRect &= source->deviceRect(); - effectRect |= effectRect.translated(-shadowOffset); - if (effectRect.isEmpty()) - return; // nothing to paint; + QPoint offset; + if (source->isPixmap()) { + // No point in drawing in device coordinates (pixmap will be scaled anyways). + const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); + d->filter->draw(painter, offset, pixmap); + return; } - QPixmap pixmap(effectRect.size()); - pixmap.fill(Qt::transparent); - QPainter pixmapPainter(&pixmap); - pixmapPainter.setRenderHints(painter->renderHints()); - pixmapPainter.setWorldTransform(painter->worldTransform()); - if (effectRect.x() != 0 || effectRect.y() != 0) - pixmapPainter.translate(-effectRect.topLeft()); - source->draw(&pixmapPainter); - pixmapPainter.end(); - - QImage img = pixmap.toImage(); - QImage shadowImage(img.size(), QImage::Format_ARGB32); - shadowImage.fill(qRgba(0, 0, 0, d->alpha * 255)); - shadowImage.setAlphaChannel(img.alphaChannel()); - shadowImage = blurred(shadowImage, shadowImage.rect(), d->radius); - - // Draw using an untransformed painter. + // Draw pixmap in device coordinates to avoid pixmap scaling. + const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); QTransform restoreTransform = painter->worldTransform(); painter->setWorldTransform(QTransform()); - painter->drawImage(effectRect.topLeft() + shadowOffset, shadowImage); - painter->drawPixmap(effectRect.topLeft(), pixmap); + d->filter->draw(painter, offset, pixmap); painter->setWorldTransform(restoreTransform); } diff --git a/src/gui/effects/qgraphicseffect.h b/src/gui/effects/qgraphicseffect.h index f6c47d7..99d8548 100644 --- a/src/gui/effects/qgraphicseffect.h +++ b/src/gui/effects/qgraphicseffect.h @@ -235,31 +235,31 @@ class QGraphicsDropShadowEffectPrivate; class Q_GUI_EXPORT QGraphicsDropShadowEffect: public QGraphicsEffect { Q_OBJECT - Q_PROPERTY(QPointF shadowOffset READ shadowOffset WRITE setShadowOffset NOTIFY shadowOffsetChanged) + Q_PROPERTY(QPointF offset READ offset WRITE setOffset NOTIFY offsetChanged) Q_PROPERTY(int blurRadius READ blurRadius WRITE setBlurRadius NOTIFY blurRadiusChanged) - Q_PROPERTY(int opacity READ opacity WRITE setOpacity NOTIFY opacityChanged) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) public: QGraphicsDropShadowEffect(QObject *parent = 0); ~QGraphicsDropShadowEffect(); QRectF boundingRectFor(const QRectF &rect) const; - QPointF shadowOffset() const; + QPointF offset() const; int blurRadius() const; - qreal opacity() const; + QColor color() const; public Q_SLOTS: - void setShadowOffset(const QPointF &ofs); - inline void setShadowOffset(qreal dx, qreal dy) - { setShadowOffset(QPointF(dx, dy)); } - inline void setShadowOffset(qreal d) - { setShadowOffset(QPointF(d, d)); } + void setOffset(const QPointF &ofs); + inline void setOffset(qreal dx, qreal dy) + { setOffset(QPointF(dx, dy)); } + inline void setOffset(qreal d) + { setOffset(QPointF(d, d)); } void setBlurRadius(int blurRadius); - void setOpacity(qreal opacity); + void setColor(const QColor &color); Q_SIGNALS: - void shadowOffsetChanged(const QPointF &offset); + void offsetChanged(const QPointF &offset); void blurRadiusChanged(int blurRadius); - void opacityChanged(int opacity); + void colorChanged(const QColor &color); protected: void draw(QPainter *painter, QGraphicsEffectSource *source); diff --git a/src/gui/effects/qgraphicseffect_p.h b/src/gui/effects/qgraphicseffect_p.h index 25397c3..35f2d40 100644 --- a/src/gui/effects/qgraphicseffect_p.h +++ b/src/gui/effects/qgraphicseffect_p.h @@ -144,22 +144,20 @@ class QGraphicsBlurEffectPrivate : public QGraphicsEffectPrivate { Q_DECLARE_PUBLIC(QGraphicsBlurEffect) public: - QGraphicsBlurEffectPrivate() : filter(new QPixmapBlurFilter), blurRadius(4) {} + QGraphicsBlurEffectPrivate() : filter(new QPixmapBlurFilter) {} ~QGraphicsBlurEffectPrivate() { delete filter; } QPixmapBlurFilter *filter; - int blurRadius; }; class QGraphicsDropShadowEffectPrivate : public QGraphicsEffectPrivate { Q_DECLARE_PUBLIC(QGraphicsDropShadowEffect) public: - QGraphicsDropShadowEffectPrivate() : offset(4, 4), radius(8), alpha(0.7) {} + QGraphicsDropShadowEffectPrivate() : filter(new QPixmapDropShadowFilter) {} + ~QGraphicsDropShadowEffectPrivate() { delete filter; } - QPointF offset; - int radius; - qreal alpha; + QPixmapDropShadowFilter *filter; }; QT_END_NAMESPACE diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 931e2d3..c335f16 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -7420,7 +7420,7 @@ void tst_QGraphicsItem::hitTestGraphicsEffectItem() // Apply shadow effect to the entire sub-tree. QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect; - shadow->setShadowOffset(-20, -20); + shadow->setOffset(-20, -20); item1->setGraphicsEffect(shadow); QTest::qWait(50); |