From 19e01c93f9421a8db6c8a93ac103a7df2b93d9ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Wed, 19 Aug 2009 15:18:22 +0200 Subject: Move QGraphicsEffect from src/gui/graphicsview to src/gui/effects. --- src/gui/effects/qgraphicseffect.cpp | 876 +++++++++++++++++++++++++++++++ src/gui/effects/qgraphicseffect.h | 291 ++++++++++ src/gui/effects/qgraphicseffect_p.h | 195 +++++++ src/gui/graphicsview/graphicsview.pri | 5 +- src/gui/graphicsview/qgraphicseffect.cpp | 876 ------------------------------- src/gui/graphicsview/qgraphicseffect.h | 291 ---------- src/gui/graphicsview/qgraphicseffect_p.h | 195 ------- src/gui/graphicsview/qgraphicsitem_p.h | 3 +- src/gui/graphicsview/qgraphicsscene.cpp | 2 +- src/gui/gui.pro | 1 + 10 files changed, 1367 insertions(+), 1368 deletions(-) create mode 100644 src/gui/effects/qgraphicseffect.cpp create mode 100644 src/gui/effects/qgraphicseffect.h create mode 100644 src/gui/effects/qgraphicseffect_p.h delete mode 100644 src/gui/graphicsview/qgraphicseffect.cpp delete mode 100644 src/gui/graphicsview/qgraphicseffect.h delete mode 100644 src/gui/graphicsview/qgraphicseffect_p.h diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp new file mode 100644 index 0000000..b04af7a --- /dev/null +++ b/src/gui/effects/qgraphicseffect.cpp @@ -0,0 +1,876 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QGraphicsEffect + \brief The QGraphicsEffect class is the base class for all graphics effects. + \since 4.6 + \ingroup multimedia + \ingroup graphicsview-api + + Effects alter the appearance of elements by hooking into the rendering + pipeline and operating between the source (e.g., a QGraphicsPixmapItem), + and the destination device (e.g., QGraphicsView's viewport). Effects can be + disabled by calling setEnabled(); if the effect is disabled, the source is + rendered directly. + + If you want to add a visual effect to a QGraphicsItem, you can either use + one of the standard effects, or create your own effect by making a subclass + of QGraphicsEffect. + + Qt provides several standard effects, including: + + \list + \o QGraphicsGrayScaleEffect - renders the item in shades of gray + \o QGraphicsColorizeEffect - renders the item in shades of any given color + \o QGraphicsPixelizeEffect - pixelizes the item with any pixel size + \o QGraphicsBlurEffect - blurs the item by a given radius + \o QGraphicsBloomEffect - applies a blooming / glowing effect + \o QGraphicsFrameEffect - adds a frame to the item + \o QGraphicsShadowEffect - renders a dropshadow behind the item + \endlist + + If all you want is to add an effect to an item, you should visit the + documentation for the specific effect to learn more about how each effect + can be used. + + If you want to create your own custom effect, you can start by creating a + subclass of QGraphicsEffect (or any of the existing effects), and + reimplement the virtual function draw(). This function is called whenever + the effect needs to redraw. draw() has two arguments: the painter, and a + pointer to the source (QGraphicsEffectSource). The source provides extra + context information, such as a pointer to the item that is rendering the + effect, any cached pixmap data, and the device rect bounds. See the draw() + documentation for more details. You can also get a pointer to the current + source by calling source(). + + If your effect changes, you can call update() to request a redraw. If your + custom effect changes the bounding rectangle of the source (e.g., a radial + glow effect may need to apply an extra margin), you can reimplement the + virtual boundingRectFor() function, and call updateBoundingRect() to notify + the framework whenever this rectangle changes. The virtual + sourceBoundingRectChanged() function is called to notify the effects that + the source's bounding rectangle has changed (e.g., if the source is a + QGraphicsRectItem, then if the rectangle parameters have changed). + + \sa QGraphicsItem::setGraphicsEffect() +*/ + +#include "qgraphicseffect_p.h" + +#ifndef QT_NO_GRAPHICSVIEW + +#include +#include +#include + +/* + + List of known drawbacks which are being discussed: + + * No d-pointer yet. + + * No auto test yet. + + * No API documentation yet. + + * The API is far from being finalized. + + * Most of the effect implementation is not efficient, + as this is still a proof of concept only. + + * Painting artifacts occasionally occur when e.g. moving + an item over another item that has a large effective + bounding rect. + + * Item transformation is not taken into account. + For example, the effective bounding rect is calculated at + item coordinate (fast), but the painting is mostly + done at device coordinate. + + * Coordinate mode: item vs device. Most effects make sense only + in device coordinate. Should we keep both options open? + See also above transformation issue. + + * Right now the pixmap for effect drawing is stored in each item. + There can be problems with coordinates, see above. + + * There is a lot of duplication in drawItems() for each effect. + + * Port to use the new layer feature in QGraphicsView. + This should solve the above pixmap problem. + + * Frame effect is likely useless. However it is very useful + to check than the effective bounding rect is handled properly. + + * Proper exposed region and rect for style option are missing. + + * Pixelize effect is using raster only, because there is no + pixmap filter for it. We need to implement the missing pixmap filter. + + * Blur effect is using raster only, with exponential blur algorithm. + Perhaps use stack blur (better approximate Gaussian blur) instead? + QPixmapConvolutionFilter is too slow for this simple blur effect. + + * Bloom and shadow effect are also raster only. Same reason as above. + + * Make it work with widgets (QGraphicsWidget). + +*/ + +QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent) + : QObject(dd, parent) +{} + +QGraphicsEffectSource::~QGraphicsEffectSource() +{} + +QRect QGraphicsEffectSource::deviceRect() const +{ + return d_func()->deviceRect(); +} + +QRectF QGraphicsEffectSource::boundingRect(Qt::CoordinateSystem system) const +{ + return d_func()->boundingRect(system); +} + +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); +} + +void QGraphicsEffectSource::update() +{ + d_func()->update(); +} + +bool QGraphicsEffectSource::isPixmap() const +{ + return d_func()->isPixmap(); +} + +QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset) const +{ + return d_func()->pixmap(system, offset); +} + +/*! + Constructs a new QGraphicsEffect instance. +*/ +QGraphicsEffect::QGraphicsEffect() + : QObject(*new QGraphicsEffectPrivate, 0) +{ + // ### parent? +} + +/*! + \internal +*/ +QGraphicsEffect::QGraphicsEffect(QGraphicsEffectPrivate &dd) + : QObject(dd, 0) +{ +} + +/*! + Removes the effect from the source, and destroys the graphics effect. +*/ +QGraphicsEffect::~QGraphicsEffect() +{ + Q_D(QGraphicsEffect); + d->setGraphicsEffectSource(0); +} + +/*! + Returns the bounding rectangle for this effect (i.e., the bounding + rectangle of the source, adjusted by any margins applied by the effect + itself). + + \sa boundingRectFor(), updateBoundingRect() +*/ +QRectF QGraphicsEffect::boundingRect() const +{ + Q_D(const QGraphicsEffect); + if (d->source) + return boundingRectFor(d->source->boundingRect()); + return QRectF(); +} + +/*! + Returns the bounding rectangle for this effect, given the provided source + \a rect. When writing you own custom effect, you must call + updateBoundingRect() whenever any parameters are changed that may cause + this this function to return a different value. + + \sa boundingRect() +*/ +QRectF QGraphicsEffect::boundingRectFor(const QRectF &rect) const +{ + return rect; +} + +/*! + \property QGraphicsEffect::enabled + \brief whether the effect is enabled or not. + + If an effect is disabled, the source will be rendered with as normal, with + no interference from the effect. If the effect is enabled (default), the + source will be rendered with the effect applied. + + This property is provided so that you can disable certain effects on slow + platforms, in order to ensure that the user interface is responsive. +*/ +bool QGraphicsEffect::isEnabled() const +{ + Q_D(const QGraphicsEffect); + return d->isEnabled; +} +void QGraphicsEffect::setEnabled(bool enable) +{ + Q_D(QGraphicsEffect); + if (d->isEnabled == enable) + return; + + d->isEnabled = enable; + + if (d->source) + d->source->update(); +} + +/*! + Returns a pointer to the source, which provides extra context information + that can be useful for the effect. + + \sa draw() +*/ +QGraphicsEffectSource *QGraphicsEffect::source() const +{ + Q_D(const QGraphicsEffect); + return d->source; +} + +/*! + This function notifies the effect framework that the effect's bounding + rectangle has changed. As a custom effect author, you must call this + function whenever you change any parameters that will cause the virtual + boundingRectFor() function to return a different value. + + \sa boundingRectFor(), boundingRect() +*/ +void QGraphicsEffect::updateBoundingRect() +{ + Q_D(QGraphicsEffect); + if (d->source) + d->source->update(); +} + +/*! + This virtual function is called by QGraphicsEffect to notify the effect + that the source has changed. If the effect applies any cache, then this + cache must be purged in order to reflect the new appearance of the source. + + The \a flags describes what has changed. +*/ +void QGraphicsEffect::sourceChanged(ChangeFlags flags) +{ + Q_UNUSED(flags); +} + +QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect() + : QGraphicsEffect(*new QGraphicsGrayscaleEffectPrivate) +{ +} + +QGraphicsGrayscaleEffect::~QGraphicsGrayscaleEffect() +{ +} + +void QGraphicsGrayscaleEffect::draw(QPainter *painter, QGraphicsEffectSource *source) +{ + Q_D(QGraphicsGrayscaleEffect); + 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; + } + + // Draw pixmap in device coordinates to avoid pixmap scaling; + const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + d->filter->draw(painter, offset, pixmap); + painter->setWorldTransform(restoreTransform); + +} + +QGraphicsColorizeEffect::QGraphicsColorizeEffect() + : QGraphicsEffect(*new QGraphicsColorizeEffectPrivate) +{} + +QGraphicsColorizeEffect::~QGraphicsColorizeEffect() +{} + +QColor QGraphicsColorizeEffect::color() const +{ + Q_D(const QGraphicsColorizeEffect); + return d->filter->color(); +} + +void QGraphicsColorizeEffect::setColor(const QColor &c) +{ + Q_D(QGraphicsColorizeEffect); + d->filter->setColor(c); +} + +void QGraphicsColorizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source) +{ + Q_D(QGraphicsColorizeEffect); + 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; + } + + // Draw pixmap in deviceCoordinates to avoid pixmap scaling. + const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + d->filter->draw(painter, offset, pixmap); + painter->setWorldTransform(restoreTransform); +} + +QGraphicsPixelizeEffect::QGraphicsPixelizeEffect() + : QGraphicsEffect(*new QGraphicsPixelizeEffectPrivate) +{ +} + +QGraphicsPixelizeEffect::~QGraphicsPixelizeEffect() +{ +} + +int QGraphicsPixelizeEffect::pixelSize() const +{ + Q_D(const QGraphicsPixelizeEffect); + return d->pixelSize; +} + +void QGraphicsPixelizeEffect::setPixelSize(int size) +{ + Q_D(QGraphicsPixelizeEffect); + d->pixelSize = size; +} + +static inline void pixelize(QImage *image, int pixelSize) +{ + Q_ASSERT(pixelSize > 0); + Q_ASSERT(image); + int width = image->width(); + int height = image->height(); + for (int y = 0; y < height; y += pixelSize) { + int ys = qMin(height - 1, y + pixelSize / 2); + QRgb *sbuf = reinterpret_cast(image->scanLine(ys)); + for (int x = 0; x < width; x += pixelSize) { + int xs = qMin(width - 1, x + pixelSize / 2); + QRgb color = sbuf[xs]; + for (int yi = 0; yi < qMin(pixelSize, height - y); ++yi) { + QRgb *buf = reinterpret_cast(image->scanLine(y + yi)); + for (int xi = 0; xi < qMin(pixelSize, width - x); ++xi) + buf[x + xi] = color; + } + } + } +} + +void QGraphicsPixelizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source) +{ + Q_D(QGraphicsPixelizeEffect); + if (d->pixelSize <= 0) { + source->draw(painter); + return; + } + + QPoint offset; + if (source->isPixmap()) { + const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); + QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); + pixelize(&image, d->pixelSize); + painter->drawImage(offset, image); + return; + } + + // Draw pixmap in device coordinates to avoid pixmap scaling. + const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); + + // pixelize routine + QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); + pixelize(&image, d->pixelSize); + + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + painter->drawImage(offset, image); + painter->setWorldTransform(restoreTransform); +} + +QGraphicsBlurEffect::QGraphicsBlurEffect() + : QGraphicsEffect(*new QGraphicsBlurEffectPrivate) +{ +} + +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); + return d->filter->radius(); +} + +void QGraphicsBlurEffect::setBlurRadius(int radius) +{ + Q_D(QGraphicsBlurEffect); + d->filter->setRadius(radius); + updateBoundingRect(); +} + +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->filter->radius() <= 0) { + source->draw(painter); + return; + } + + 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; + } + + // Draw pixmap in device coordinates to avoid pixmap scaling. + const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + d->filter->draw(painter, offset, pixmap); + painter->setWorldTransform(restoreTransform); +} + +QGraphicsBloomEffect::QGraphicsBloomEffect() + : QGraphicsEffect(*new QGraphicsBloomEffectPrivate) +{ +} + +QGraphicsBloomEffect::~QGraphicsBloomEffect() +{ +} + +int QGraphicsBloomEffect::blurRadius() const +{ + Q_D(const QGraphicsBloomEffect); + return d->blurRadius; +} + +void QGraphicsBloomEffect::setBlurRadius(int radius) +{ + Q_D(QGraphicsBloomEffect); + d->blurRadius = radius; + updateBoundingRect(); +} + +qreal QGraphicsBloomEffect::opacity() const +{ + Q_D(const QGraphicsBloomEffect); + return d->opacity; +} + +void QGraphicsBloomEffect::setOpacity(qreal alpha) +{ + Q_D(QGraphicsBloomEffect); + d->opacity = alpha; +} + +QRectF QGraphicsBloomEffect::boundingRectFor(const QRectF &rect) const +{ + Q_D(const QGraphicsBloomEffect); + const qreal delta = d->blurRadius * 3; + return rect.adjusted(-delta, -delta, delta, delta); +} + +// Change brightness (positive integer) of each pixel +static QImage brightened(const QImage& image, int brightness) +{ + int tab[ 256 ]; + for (int i = 0; i < 256; ++i) + tab[i] = qMin(i + brightness, 255); + + QImage img = image.convertToFormat(QImage::Format_ARGB32); + for (int y = 0; y < img.height(); y++) { + QRgb* line = (QRgb*)(img.scanLine(y)); + for (int x = 0; x < img.width(); x++) { + QRgb c = line[x]; + line[x] = qRgba(tab[qRed(c)], tab[qGreen(c)], tab[qBlue(c)], qAlpha(c)); + } + } + + return img; +} + +// Composite two QImages using given composition mode and opacity +static QImage composited(const QImage& img1, const QImage& img2, qreal opacity, QPainter::CompositionMode mode) +{ + QImage result = img1.convertToFormat(QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(mode); + painter.setOpacity(opacity); + painter.drawImage(0, 0, img2); + painter.end(); + return result; +} + +void QGraphicsBloomEffect::draw(QPainter *painter, QGraphicsEffectSource *source) +{ + Q_D(QGraphicsBloomEffect); + if (d->blurRadius <= 0) { + source->draw(painter); + return; + } + + QPoint offset; + const int radius = d->blurRadius; + + if (source->isPixmap()) { + // No point in drawing in device coordinates (pixmap will be scaled anyways). + const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); + + // bloom routine + 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); + + painter->drawImage(offset, img); + return; + } + + // Draw pixmap in device coordinates to avoid pixmap scaling. + const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); + + // bloom routine + 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); + + // Draw using an untransformed painter. + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + painter->drawImage(offset, img); + painter->setWorldTransform(restoreTransform); +} + +QGraphicsFrameEffect::QGraphicsFrameEffect() + : QGraphicsEffect(*new QGraphicsFrameEffectPrivate) +{ +} + +QGraphicsFrameEffect::~QGraphicsFrameEffect() +{ +} + +QColor QGraphicsFrameEffect::frameColor() const +{ + Q_D(const QGraphicsFrameEffect); + return d->color; +} + +void QGraphicsFrameEffect::setFrameColor(const QColor &c) +{ + Q_D(QGraphicsFrameEffect); + d->color = c; +} + +qreal QGraphicsFrameEffect::frameWidth() const +{ + Q_D(const QGraphicsFrameEffect); + return d->width; +} + +void QGraphicsFrameEffect::setFrameWidth(qreal frameWidth) +{ + Q_D(QGraphicsFrameEffect); + d->width = frameWidth; + updateBoundingRect(); +} + +qreal QGraphicsFrameEffect::frameOpacity() const +{ + Q_D(const QGraphicsFrameEffect); + return d->alpha; +} + +void QGraphicsFrameEffect::setFrameOpacity(qreal opacity) +{ + Q_D(QGraphicsFrameEffect); + d->alpha = opacity; +} + +QRectF QGraphicsFrameEffect::boundingRectFor(const QRectF &rect) const +{ + Q_D(const QGraphicsFrameEffect); + return rect.adjusted(-d->width, -d->width, d->width, d->width); +} + +void QGraphicsFrameEffect::draw(QPainter *painter, QGraphicsEffectSource *source) +{ + Q_D(QGraphicsFrameEffect); + painter->save(); + painter->setOpacity(painter->opacity() * d->alpha); + painter->setPen(Qt::NoPen); + painter->setBrush(d->color); + painter->drawRoundedRect(boundingRect(), 20, 20, Qt::RelativeSize); + painter->restore(); + + source->draw(painter); +} + +QGraphicsShadowEffect::QGraphicsShadowEffect() + : QGraphicsEffect(*new QGraphicsShadowEffectPrivate) +{ +} + +QGraphicsShadowEffect::~QGraphicsShadowEffect() +{ +} + +QPointF QGraphicsShadowEffect::shadowOffset() const +{ + Q_D(const QGraphicsShadowEffect); + return d->offset; +} + +void QGraphicsShadowEffect::setShadowOffset(const QPointF &ofs) +{ + Q_D(QGraphicsShadowEffect); + d->offset = ofs; + updateBoundingRect(); +} + +int QGraphicsShadowEffect::blurRadius() const +{ + Q_D(const QGraphicsShadowEffect); + return d->radius; +} + +void QGraphicsShadowEffect::setBlurRadius(int blurRadius) +{ + Q_D(QGraphicsShadowEffect); + d->radius = blurRadius; + updateBoundingRect(); +} + +qreal QGraphicsShadowEffect::opacity() const +{ + Q_D(const QGraphicsShadowEffect); + return d->alpha; +} + +void QGraphicsShadowEffect::setOpacity(qreal opacity) +{ + Q_D(QGraphicsShadowEffect); + d->alpha = opacity; +} + +QRectF QGraphicsShadowEffect::boundingRectFor(const QRectF &rect) const +{ + Q_D(const QGraphicsShadowEffect); + QRectF shadowRect = rect.translated(d->offset); + QRectF blurRect = shadowRect; + qreal delta = d->radius * 3; + blurRect.adjust(-delta, -delta, delta, delta); + blurRect |= rect; + return blurRect; +} + +void QGraphicsShadowEffect::draw(QPainter *painter, QGraphicsEffectSource *source) +{ + Q_D(QGraphicsShadowEffect); + if (d->radius <= 0 && d->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; + } + + 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. + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + painter->drawImage(effectRect.topLeft() + shadowOffset, shadowImage); + painter->drawPixmap(effectRect.topLeft(), pixmap); + painter->setWorldTransform(restoreTransform); +} + +#endif diff --git a/src/gui/effects/qgraphicseffect.h b/src/gui/effects/qgraphicseffect.h new file mode 100644 index 0000000..d171b1b --- /dev/null +++ b/src/gui/effects/qgraphicseffect.h @@ -0,0 +1,291 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSEFFECT_H +#define QGRAPHICSEFFECT_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW + +class QGraphicsItem; +class QStyleOption; +class QColor; +class QPainter; +class QRectF; +class QRect; +class QPixmap; + +class QGraphicsEffectSourcePrivate; +class Q_GUI_EXPORT QGraphicsEffectSource : public QObject +{ + Q_OBJECT +public: + ~QGraphicsEffectSource(); + const QGraphicsItem *graphicsItem() const; + const QStyleOption *styleOption() const; + + bool isPixmap() const; + void draw(QPainter *painter); + void update(); + + QRectF boundingRect(Qt::CoordinateSystem coordinateSystem = Qt::LogicalCoordinates) const; + QRect deviceRect() const; + QPixmap pixmap(Qt::CoordinateSystem system = Qt::LogicalCoordinates, QPoint *offset = 0) const; + +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 +{ + Q_OBJECT + Q_FLAGS(ChangeFlags) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) +public: + enum ChangeFlag { + SourceAttached = 0x1, + SourceDetached = 0x2, + SourceBoundingRectChanged = 0x4, + SourceInvalidated = 0x8 + }; + Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag); + + QGraphicsEffect(); + virtual ~QGraphicsEffect(); + + // ### make protected? + virtual QRectF boundingRectFor(const QRectF &rect) const; + QRectF boundingRect() const; + + QGraphicsEffectSource *source() const; + + bool isEnabled() const; + +public Q_SLOTS: + void setEnabled(bool enable); + // ### add update() slot + +protected: + QGraphicsEffect(QGraphicsEffectPrivate &d); + virtual void draw(QPainter *painter, QGraphicsEffectSource *source) = 0; + virtual void sourceChanged(ChangeFlags flags); + void updateBoundingRect(); + +private: + Q_DECLARE_PRIVATE(QGraphicsEffect) + Q_DISABLE_COPY(QGraphicsEffect) + friend class QGraphicsItem; + friend class QGraphicsItemPrivate; + friend class QGraphicsScenePrivate; +}; + +class QGraphicsGrayscaleEffectPrivate; +class Q_GUI_EXPORT QGraphicsGrayscaleEffect: public QGraphicsEffect +{ + Q_OBJECT +public: + QGraphicsGrayscaleEffect(); + ~QGraphicsGrayscaleEffect(); + +protected: + void draw(QPainter *painter, QGraphicsEffectSource *source); + +private: + Q_DECLARE_PRIVATE(QGraphicsGrayscaleEffect) + Q_DISABLE_COPY(QGraphicsGrayscaleEffect) +}; + +class QGraphicsColorizeEffectPrivate; +class Q_GUI_EXPORT QGraphicsColorizeEffect: public QGraphicsEffect { + Q_OBJECT +public: + QGraphicsColorizeEffect(); + ~QGraphicsColorizeEffect(); + + QColor color() const; + void setColor(const QColor &c); + +protected: + void draw(QPainter *painter, QGraphicsEffectSource *source); + +private: + Q_DECLARE_PRIVATE(QGraphicsColorizeEffect) + Q_DISABLE_COPY(QGraphicsColorizeEffect) +}; + +class QGraphicsPixelizeEffectPrivate; +class Q_GUI_EXPORT QGraphicsPixelizeEffect: public QGraphicsEffect { + Q_OBJECT +public: + QGraphicsPixelizeEffect(); + ~QGraphicsPixelizeEffect(); + + int pixelSize() const; + void setPixelSize(int pixelSize); + +protected: + void draw(QPainter *painter, QGraphicsEffectSource *source); + +private: + Q_DECLARE_PRIVATE(QGraphicsPixelizeEffect) + Q_DISABLE_COPY(QGraphicsPixelizeEffect) +}; + +class QGraphicsBlurEffectPrivate; +class Q_GUI_EXPORT QGraphicsBlurEffect: public QGraphicsEffect { + Q_OBJECT +public: + QGraphicsBlurEffect(); + ~QGraphicsBlurEffect(); + + int blurRadius() const; + void setBlurRadius(int blurRadius); + +protected: + QRectF boundingRectFor(const QRectF &rect) const; + void draw(QPainter *painter, QGraphicsEffectSource *source); + +private: + Q_DECLARE_PRIVATE(QGraphicsBlurEffect) + Q_DISABLE_COPY(QGraphicsBlurEffect) +}; + +class QGraphicsBloomEffectPrivate; +class Q_GUI_EXPORT QGraphicsBloomEffect: public QGraphicsEffect { + Q_OBJECT +public: + QGraphicsBloomEffect(); + ~QGraphicsBloomEffect(); + + int blurRadius() const; + void setBlurRadius(int blurRadius); + + qreal opacity() const; + void setOpacity(qreal opacity); + +protected: + QRectF boundingRectFor(const QRectF &rect) const; + void draw(QPainter *painter, QGraphicsEffectSource *source); + +private: + Q_DECLARE_PRIVATE(QGraphicsBloomEffect) + Q_DISABLE_COPY(QGraphicsBloomEffect) +}; + +class QGraphicsFrameEffectPrivate; +class Q_GUI_EXPORT QGraphicsFrameEffect: public QGraphicsEffect { + Q_OBJECT +public: + QGraphicsFrameEffect(); + ~QGraphicsFrameEffect(); + + QColor frameColor() const; + void setFrameColor(const QColor &c); + + qreal frameWidth() const; + void setFrameWidth(qreal frameWidth); + + qreal frameOpacity() const; + void setFrameOpacity(qreal opacity); + +protected: + QRectF boundingRectFor(const QRectF &rect) const; + void draw(QPainter *painter, QGraphicsEffectSource *source); + +private: + Q_DECLARE_PRIVATE(QGraphicsFrameEffect) + Q_DISABLE_COPY(QGraphicsFrameEffect) +}; + +class QGraphicsShadowEffectPrivate; +class Q_GUI_EXPORT QGraphicsShadowEffect: public QGraphicsEffect { + Q_OBJECT +public: + QGraphicsShadowEffect(); + ~QGraphicsShadowEffect(); + + QPointF shadowOffset() const; + 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)); } + + int blurRadius() const; + void setBlurRadius(int blurRadius); + + qreal opacity() const; + void setOpacity(qreal opacity); + +protected: + QRectF boundingRectFor(const QRectF &rect) const; + void draw(QPainter *painter, QGraphicsEffectSource *source); + +private: + Q_DECLARE_PRIVATE(QGraphicsShadowEffect) + Q_DISABLE_COPY(QGraphicsShadowEffect) +}; + +#endif // QT_NO_GRAPHICSVIEW + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QGRAPHICSEFFECT_H diff --git a/src/gui/effects/qgraphicseffect_p.h b/src/gui/effects/qgraphicseffect_p.h new file mode 100644 index 0000000..6d546cc --- /dev/null +++ b/src/gui/effects/qgraphicseffect_p.h @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSEFFECT_P_H +#define QGRAPHICSEFFECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qgraphicseffect.h" + +#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QGraphicsEffectSourcePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsEffectSource) +public: + QGraphicsEffectSourcePrivate() : QObjectPrivate() {} + virtual ~QGraphicsEffectSourcePrivate() {} + virtual void detach() = 0; + virtual QRectF boundingRect(Qt::CoordinateSystem system) const = 0; + virtual QRect deviceRect() const = 0; + virtual const QGraphicsItem *graphicsItem() const = 0; + virtual const QStyleOption *styleOption() const = 0; + virtual void draw(QPainter *p) = 0; + virtual void update() = 0; + virtual bool isPixmap() const = 0; + virtual QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset = 0) const = 0; + friend class QGraphicsScenePrivate; + friend class QGraphicsItem; + friend class QGraphicsItemPrivate; +}; + +class Q_GUI_EXPORT QGraphicsEffectPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsEffect) +public: + QGraphicsEffectPrivate() : source(0), isEnabled(1) {} + + inline void setGraphicsEffectSource(QGraphicsEffectSource *newSource) + { + QGraphicsEffect::ChangeFlags flags; + if (source) { + flags |= QGraphicsEffect::SourceDetached; + source->d_func()->detach(); + delete source; + } + source = newSource; + if (newSource) + flags |= QGraphicsEffect::SourceAttached; + q_func()->sourceChanged(flags); + } + + QGraphicsEffectSource *source; + QRectF boundingRect; + quint32 isEnabled : 1; + quint32 padding : 31; // feel free to use +}; + +class QGraphicsGrayscaleEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsGrayscaleEffect) +public: + QGraphicsGrayscaleEffectPrivate() + { + filter = new QPixmapColorizeFilter; + filter->setColor(Qt::black); + } + ~QGraphicsGrayscaleEffectPrivate() { delete filter; } + + QPixmapColorizeFilter *filter; +}; + +class QGraphicsColorizeEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsColorizeEffect) +public: + QGraphicsColorizeEffectPrivate() { filter = new QPixmapColorizeFilter; } + ~QGraphicsColorizeEffectPrivate() { delete filter; } + + QPixmapColorizeFilter *filter; +}; + +class QGraphicsPixelizeEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsPixelizeEffect) +public: + QGraphicsPixelizeEffectPrivate() : pixelSize(3) {} + + int pixelSize; +}; + +class QGraphicsBlurEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsBlurEffect) +public: + QGraphicsBlurEffectPrivate() : filter(new QPixmapBlurFilter), blurRadius(4) {} + ~QGraphicsBlurEffectPrivate() { delete filter; } + + QPixmapBlurFilter *filter; + int blurRadius; +}; + +class QGraphicsBloomEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsBlurEffect) +public: + QGraphicsBloomEffectPrivate() : blurRadius(6), opacity(0.7) {} + + int blurRadius; + qreal opacity; +}; + +class QGraphicsFrameEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsFrameEffect) +public: + QGraphicsFrameEffectPrivate() : color(Qt::blue), width(5), alpha(0.6) {} + + QColor color; + qreal width; + qreal alpha; +}; + +class QGraphicsShadowEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsShadowEffect) +public: + QGraphicsShadowEffectPrivate() : offset(4, 4), radius(8), alpha(0.7) {} + + QPointF offset; + int radius; + qreal alpha; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_GRAPHICSVIEW + +#endif // QGRAPHICSEFFECT_P_H diff --git a/src/gui/graphicsview/graphicsview.pri b/src/gui/graphicsview/graphicsview.pri index a3095e7..15b86b5 100644 --- a/src/gui/graphicsview/graphicsview.pri +++ b/src/gui/graphicsview/graphicsview.pri @@ -22,8 +22,6 @@ HEADERS += graphicsview/qgraphicsgridlayout.h \ graphicsview/qgraphicsview_p.h \ graphicsview/qgraphicswidget.h \ graphicsview/qgraphicswidget_p.h \ - graphicsview/qgraphicseffect.h \ - graphicsview/qgraphicseffect_p.h \ graphicsview/qgridlayoutengine_p.h SOURCES += graphicsview/qgraphicsgridlayout.cpp \ @@ -44,5 +42,4 @@ SOURCES += graphicsview/qgraphicsgridlayout.cpp \ graphicsview/qgraphicsview.cpp \ graphicsview/qgraphicswidget.cpp \ graphicsview/qgraphicswidget_p.cpp \ - graphicsview/qgridlayoutengine.cpp \ - graphicsview/qgraphicseffect.cpp + graphicsview/qgridlayoutengine.cpp diff --git a/src/gui/graphicsview/qgraphicseffect.cpp b/src/gui/graphicsview/qgraphicseffect.cpp deleted file mode 100644 index b04af7a..0000000 --- a/src/gui/graphicsview/qgraphicseffect.cpp +++ /dev/null @@ -1,876 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \class QGraphicsEffect - \brief The QGraphicsEffect class is the base class for all graphics effects. - \since 4.6 - \ingroup multimedia - \ingroup graphicsview-api - - Effects alter the appearance of elements by hooking into the rendering - pipeline and operating between the source (e.g., a QGraphicsPixmapItem), - and the destination device (e.g., QGraphicsView's viewport). Effects can be - disabled by calling setEnabled(); if the effect is disabled, the source is - rendered directly. - - If you want to add a visual effect to a QGraphicsItem, you can either use - one of the standard effects, or create your own effect by making a subclass - of QGraphicsEffect. - - Qt provides several standard effects, including: - - \list - \o QGraphicsGrayScaleEffect - renders the item in shades of gray - \o QGraphicsColorizeEffect - renders the item in shades of any given color - \o QGraphicsPixelizeEffect - pixelizes the item with any pixel size - \o QGraphicsBlurEffect - blurs the item by a given radius - \o QGraphicsBloomEffect - applies a blooming / glowing effect - \o QGraphicsFrameEffect - adds a frame to the item - \o QGraphicsShadowEffect - renders a dropshadow behind the item - \endlist - - If all you want is to add an effect to an item, you should visit the - documentation for the specific effect to learn more about how each effect - can be used. - - If you want to create your own custom effect, you can start by creating a - subclass of QGraphicsEffect (or any of the existing effects), and - reimplement the virtual function draw(). This function is called whenever - the effect needs to redraw. draw() has two arguments: the painter, and a - pointer to the source (QGraphicsEffectSource). The source provides extra - context information, such as a pointer to the item that is rendering the - effect, any cached pixmap data, and the device rect bounds. See the draw() - documentation for more details. You can also get a pointer to the current - source by calling source(). - - If your effect changes, you can call update() to request a redraw. If your - custom effect changes the bounding rectangle of the source (e.g., a radial - glow effect may need to apply an extra margin), you can reimplement the - virtual boundingRectFor() function, and call updateBoundingRect() to notify - the framework whenever this rectangle changes. The virtual - sourceBoundingRectChanged() function is called to notify the effects that - the source's bounding rectangle has changed (e.g., if the source is a - QGraphicsRectItem, then if the rectangle parameters have changed). - - \sa QGraphicsItem::setGraphicsEffect() -*/ - -#include "qgraphicseffect_p.h" - -#ifndef QT_NO_GRAPHICSVIEW - -#include -#include -#include - -/* - - List of known drawbacks which are being discussed: - - * No d-pointer yet. - - * No auto test yet. - - * No API documentation yet. - - * The API is far from being finalized. - - * Most of the effect implementation is not efficient, - as this is still a proof of concept only. - - * Painting artifacts occasionally occur when e.g. moving - an item over another item that has a large effective - bounding rect. - - * Item transformation is not taken into account. - For example, the effective bounding rect is calculated at - item coordinate (fast), but the painting is mostly - done at device coordinate. - - * Coordinate mode: item vs device. Most effects make sense only - in device coordinate. Should we keep both options open? - See also above transformation issue. - - * Right now the pixmap for effect drawing is stored in each item. - There can be problems with coordinates, see above. - - * There is a lot of duplication in drawItems() for each effect. - - * Port to use the new layer feature in QGraphicsView. - This should solve the above pixmap problem. - - * Frame effect is likely useless. However it is very useful - to check than the effective bounding rect is handled properly. - - * Proper exposed region and rect for style option are missing. - - * Pixelize effect is using raster only, because there is no - pixmap filter for it. We need to implement the missing pixmap filter. - - * Blur effect is using raster only, with exponential blur algorithm. - Perhaps use stack blur (better approximate Gaussian blur) instead? - QPixmapConvolutionFilter is too slow for this simple blur effect. - - * Bloom and shadow effect are also raster only. Same reason as above. - - * Make it work with widgets (QGraphicsWidget). - -*/ - -QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent) - : QObject(dd, parent) -{} - -QGraphicsEffectSource::~QGraphicsEffectSource() -{} - -QRect QGraphicsEffectSource::deviceRect() const -{ - return d_func()->deviceRect(); -} - -QRectF QGraphicsEffectSource::boundingRect(Qt::CoordinateSystem system) const -{ - return d_func()->boundingRect(system); -} - -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); -} - -void QGraphicsEffectSource::update() -{ - d_func()->update(); -} - -bool QGraphicsEffectSource::isPixmap() const -{ - return d_func()->isPixmap(); -} - -QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset) const -{ - return d_func()->pixmap(system, offset); -} - -/*! - Constructs a new QGraphicsEffect instance. -*/ -QGraphicsEffect::QGraphicsEffect() - : QObject(*new QGraphicsEffectPrivate, 0) -{ - // ### parent? -} - -/*! - \internal -*/ -QGraphicsEffect::QGraphicsEffect(QGraphicsEffectPrivate &dd) - : QObject(dd, 0) -{ -} - -/*! - Removes the effect from the source, and destroys the graphics effect. -*/ -QGraphicsEffect::~QGraphicsEffect() -{ - Q_D(QGraphicsEffect); - d->setGraphicsEffectSource(0); -} - -/*! - Returns the bounding rectangle for this effect (i.e., the bounding - rectangle of the source, adjusted by any margins applied by the effect - itself). - - \sa boundingRectFor(), updateBoundingRect() -*/ -QRectF QGraphicsEffect::boundingRect() const -{ - Q_D(const QGraphicsEffect); - if (d->source) - return boundingRectFor(d->source->boundingRect()); - return QRectF(); -} - -/*! - Returns the bounding rectangle for this effect, given the provided source - \a rect. When writing you own custom effect, you must call - updateBoundingRect() whenever any parameters are changed that may cause - this this function to return a different value. - - \sa boundingRect() -*/ -QRectF QGraphicsEffect::boundingRectFor(const QRectF &rect) const -{ - return rect; -} - -/*! - \property QGraphicsEffect::enabled - \brief whether the effect is enabled or not. - - If an effect is disabled, the source will be rendered with as normal, with - no interference from the effect. If the effect is enabled (default), the - source will be rendered with the effect applied. - - This property is provided so that you can disable certain effects on slow - platforms, in order to ensure that the user interface is responsive. -*/ -bool QGraphicsEffect::isEnabled() const -{ - Q_D(const QGraphicsEffect); - return d->isEnabled; -} -void QGraphicsEffect::setEnabled(bool enable) -{ - Q_D(QGraphicsEffect); - if (d->isEnabled == enable) - return; - - d->isEnabled = enable; - - if (d->source) - d->source->update(); -} - -/*! - Returns a pointer to the source, which provides extra context information - that can be useful for the effect. - - \sa draw() -*/ -QGraphicsEffectSource *QGraphicsEffect::source() const -{ - Q_D(const QGraphicsEffect); - return d->source; -} - -/*! - This function notifies the effect framework that the effect's bounding - rectangle has changed. As a custom effect author, you must call this - function whenever you change any parameters that will cause the virtual - boundingRectFor() function to return a different value. - - \sa boundingRectFor(), boundingRect() -*/ -void QGraphicsEffect::updateBoundingRect() -{ - Q_D(QGraphicsEffect); - if (d->source) - d->source->update(); -} - -/*! - This virtual function is called by QGraphicsEffect to notify the effect - that the source has changed. If the effect applies any cache, then this - cache must be purged in order to reflect the new appearance of the source. - - The \a flags describes what has changed. -*/ -void QGraphicsEffect::sourceChanged(ChangeFlags flags) -{ - Q_UNUSED(flags); -} - -QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect() - : QGraphicsEffect(*new QGraphicsGrayscaleEffectPrivate) -{ -} - -QGraphicsGrayscaleEffect::~QGraphicsGrayscaleEffect() -{ -} - -void QGraphicsGrayscaleEffect::draw(QPainter *painter, QGraphicsEffectSource *source) -{ - Q_D(QGraphicsGrayscaleEffect); - 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; - } - - // Draw pixmap in device coordinates to avoid pixmap scaling; - const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); - QTransform restoreTransform = painter->worldTransform(); - painter->setWorldTransform(QTransform()); - d->filter->draw(painter, offset, pixmap); - painter->setWorldTransform(restoreTransform); - -} - -QGraphicsColorizeEffect::QGraphicsColorizeEffect() - : QGraphicsEffect(*new QGraphicsColorizeEffectPrivate) -{} - -QGraphicsColorizeEffect::~QGraphicsColorizeEffect() -{} - -QColor QGraphicsColorizeEffect::color() const -{ - Q_D(const QGraphicsColorizeEffect); - return d->filter->color(); -} - -void QGraphicsColorizeEffect::setColor(const QColor &c) -{ - Q_D(QGraphicsColorizeEffect); - d->filter->setColor(c); -} - -void QGraphicsColorizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source) -{ - Q_D(QGraphicsColorizeEffect); - 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; - } - - // Draw pixmap in deviceCoordinates to avoid pixmap scaling. - const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); - QTransform restoreTransform = painter->worldTransform(); - painter->setWorldTransform(QTransform()); - d->filter->draw(painter, offset, pixmap); - painter->setWorldTransform(restoreTransform); -} - -QGraphicsPixelizeEffect::QGraphicsPixelizeEffect() - : QGraphicsEffect(*new QGraphicsPixelizeEffectPrivate) -{ -} - -QGraphicsPixelizeEffect::~QGraphicsPixelizeEffect() -{ -} - -int QGraphicsPixelizeEffect::pixelSize() const -{ - Q_D(const QGraphicsPixelizeEffect); - return d->pixelSize; -} - -void QGraphicsPixelizeEffect::setPixelSize(int size) -{ - Q_D(QGraphicsPixelizeEffect); - d->pixelSize = size; -} - -static inline void pixelize(QImage *image, int pixelSize) -{ - Q_ASSERT(pixelSize > 0); - Q_ASSERT(image); - int width = image->width(); - int height = image->height(); - for (int y = 0; y < height; y += pixelSize) { - int ys = qMin(height - 1, y + pixelSize / 2); - QRgb *sbuf = reinterpret_cast(image->scanLine(ys)); - for (int x = 0; x < width; x += pixelSize) { - int xs = qMin(width - 1, x + pixelSize / 2); - QRgb color = sbuf[xs]; - for (int yi = 0; yi < qMin(pixelSize, height - y); ++yi) { - QRgb *buf = reinterpret_cast(image->scanLine(y + yi)); - for (int xi = 0; xi < qMin(pixelSize, width - x); ++xi) - buf[x + xi] = color; - } - } - } -} - -void QGraphicsPixelizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source) -{ - Q_D(QGraphicsPixelizeEffect); - if (d->pixelSize <= 0) { - source->draw(painter); - return; - } - - QPoint offset; - if (source->isPixmap()) { - const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); - QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); - pixelize(&image, d->pixelSize); - painter->drawImage(offset, image); - return; - } - - // Draw pixmap in device coordinates to avoid pixmap scaling. - const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); - - // pixelize routine - QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); - pixelize(&image, d->pixelSize); - - QTransform restoreTransform = painter->worldTransform(); - painter->setWorldTransform(QTransform()); - painter->drawImage(offset, image); - painter->setWorldTransform(restoreTransform); -} - -QGraphicsBlurEffect::QGraphicsBlurEffect() - : QGraphicsEffect(*new QGraphicsBlurEffectPrivate) -{ -} - -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); - return d->filter->radius(); -} - -void QGraphicsBlurEffect::setBlurRadius(int radius) -{ - Q_D(QGraphicsBlurEffect); - d->filter->setRadius(radius); - updateBoundingRect(); -} - -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->filter->radius() <= 0) { - source->draw(painter); - return; - } - - 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; - } - - // Draw pixmap in device coordinates to avoid pixmap scaling. - const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); - QTransform restoreTransform = painter->worldTransform(); - painter->setWorldTransform(QTransform()); - d->filter->draw(painter, offset, pixmap); - painter->setWorldTransform(restoreTransform); -} - -QGraphicsBloomEffect::QGraphicsBloomEffect() - : QGraphicsEffect(*new QGraphicsBloomEffectPrivate) -{ -} - -QGraphicsBloomEffect::~QGraphicsBloomEffect() -{ -} - -int QGraphicsBloomEffect::blurRadius() const -{ - Q_D(const QGraphicsBloomEffect); - return d->blurRadius; -} - -void QGraphicsBloomEffect::setBlurRadius(int radius) -{ - Q_D(QGraphicsBloomEffect); - d->blurRadius = radius; - updateBoundingRect(); -} - -qreal QGraphicsBloomEffect::opacity() const -{ - Q_D(const QGraphicsBloomEffect); - return d->opacity; -} - -void QGraphicsBloomEffect::setOpacity(qreal alpha) -{ - Q_D(QGraphicsBloomEffect); - d->opacity = alpha; -} - -QRectF QGraphicsBloomEffect::boundingRectFor(const QRectF &rect) const -{ - Q_D(const QGraphicsBloomEffect); - const qreal delta = d->blurRadius * 3; - return rect.adjusted(-delta, -delta, delta, delta); -} - -// Change brightness (positive integer) of each pixel -static QImage brightened(const QImage& image, int brightness) -{ - int tab[ 256 ]; - for (int i = 0; i < 256; ++i) - tab[i] = qMin(i + brightness, 255); - - QImage img = image.convertToFormat(QImage::Format_ARGB32); - for (int y = 0; y < img.height(); y++) { - QRgb* line = (QRgb*)(img.scanLine(y)); - for (int x = 0; x < img.width(); x++) { - QRgb c = line[x]; - line[x] = qRgba(tab[qRed(c)], tab[qGreen(c)], tab[qBlue(c)], qAlpha(c)); - } - } - - return img; -} - -// Composite two QImages using given composition mode and opacity -static QImage composited(const QImage& img1, const QImage& img2, qreal opacity, QPainter::CompositionMode mode) -{ - QImage result = img1.convertToFormat(QImage::Format_ARGB32_Premultiplied); - QPainter painter(&result); - painter.setCompositionMode(mode); - painter.setOpacity(opacity); - painter.drawImage(0, 0, img2); - painter.end(); - return result; -} - -void QGraphicsBloomEffect::draw(QPainter *painter, QGraphicsEffectSource *source) -{ - Q_D(QGraphicsBloomEffect); - if (d->blurRadius <= 0) { - source->draw(painter); - return; - } - - QPoint offset; - const int radius = d->blurRadius; - - if (source->isPixmap()) { - // No point in drawing in device coordinates (pixmap will be scaled anyways). - const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); - - // bloom routine - 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); - - painter->drawImage(offset, img); - return; - } - - // Draw pixmap in device coordinates to avoid pixmap scaling. - const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); - - // bloom routine - 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); - - // Draw using an untransformed painter. - QTransform restoreTransform = painter->worldTransform(); - painter->setWorldTransform(QTransform()); - painter->drawImage(offset, img); - painter->setWorldTransform(restoreTransform); -} - -QGraphicsFrameEffect::QGraphicsFrameEffect() - : QGraphicsEffect(*new QGraphicsFrameEffectPrivate) -{ -} - -QGraphicsFrameEffect::~QGraphicsFrameEffect() -{ -} - -QColor QGraphicsFrameEffect::frameColor() const -{ - Q_D(const QGraphicsFrameEffect); - return d->color; -} - -void QGraphicsFrameEffect::setFrameColor(const QColor &c) -{ - Q_D(QGraphicsFrameEffect); - d->color = c; -} - -qreal QGraphicsFrameEffect::frameWidth() const -{ - Q_D(const QGraphicsFrameEffect); - return d->width; -} - -void QGraphicsFrameEffect::setFrameWidth(qreal frameWidth) -{ - Q_D(QGraphicsFrameEffect); - d->width = frameWidth; - updateBoundingRect(); -} - -qreal QGraphicsFrameEffect::frameOpacity() const -{ - Q_D(const QGraphicsFrameEffect); - return d->alpha; -} - -void QGraphicsFrameEffect::setFrameOpacity(qreal opacity) -{ - Q_D(QGraphicsFrameEffect); - d->alpha = opacity; -} - -QRectF QGraphicsFrameEffect::boundingRectFor(const QRectF &rect) const -{ - Q_D(const QGraphicsFrameEffect); - return rect.adjusted(-d->width, -d->width, d->width, d->width); -} - -void QGraphicsFrameEffect::draw(QPainter *painter, QGraphicsEffectSource *source) -{ - Q_D(QGraphicsFrameEffect); - painter->save(); - painter->setOpacity(painter->opacity() * d->alpha); - painter->setPen(Qt::NoPen); - painter->setBrush(d->color); - painter->drawRoundedRect(boundingRect(), 20, 20, Qt::RelativeSize); - painter->restore(); - - source->draw(painter); -} - -QGraphicsShadowEffect::QGraphicsShadowEffect() - : QGraphicsEffect(*new QGraphicsShadowEffectPrivate) -{ -} - -QGraphicsShadowEffect::~QGraphicsShadowEffect() -{ -} - -QPointF QGraphicsShadowEffect::shadowOffset() const -{ - Q_D(const QGraphicsShadowEffect); - return d->offset; -} - -void QGraphicsShadowEffect::setShadowOffset(const QPointF &ofs) -{ - Q_D(QGraphicsShadowEffect); - d->offset = ofs; - updateBoundingRect(); -} - -int QGraphicsShadowEffect::blurRadius() const -{ - Q_D(const QGraphicsShadowEffect); - return d->radius; -} - -void QGraphicsShadowEffect::setBlurRadius(int blurRadius) -{ - Q_D(QGraphicsShadowEffect); - d->radius = blurRadius; - updateBoundingRect(); -} - -qreal QGraphicsShadowEffect::opacity() const -{ - Q_D(const QGraphicsShadowEffect); - return d->alpha; -} - -void QGraphicsShadowEffect::setOpacity(qreal opacity) -{ - Q_D(QGraphicsShadowEffect); - d->alpha = opacity; -} - -QRectF QGraphicsShadowEffect::boundingRectFor(const QRectF &rect) const -{ - Q_D(const QGraphicsShadowEffect); - QRectF shadowRect = rect.translated(d->offset); - QRectF blurRect = shadowRect; - qreal delta = d->radius * 3; - blurRect.adjust(-delta, -delta, delta, delta); - blurRect |= rect; - return blurRect; -} - -void QGraphicsShadowEffect::draw(QPainter *painter, QGraphicsEffectSource *source) -{ - Q_D(QGraphicsShadowEffect); - if (d->radius <= 0 && d->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; - } - - 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. - QTransform restoreTransform = painter->worldTransform(); - painter->setWorldTransform(QTransform()); - painter->drawImage(effectRect.topLeft() + shadowOffset, shadowImage); - painter->drawPixmap(effectRect.topLeft(), pixmap); - painter->setWorldTransform(restoreTransform); -} - -#endif diff --git a/src/gui/graphicsview/qgraphicseffect.h b/src/gui/graphicsview/qgraphicseffect.h deleted file mode 100644 index d171b1b..0000000 --- a/src/gui/graphicsview/qgraphicseffect.h +++ /dev/null @@ -1,291 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGRAPHICSEFFECT_H -#define QGRAPHICSEFFECT_H - -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW - -class QGraphicsItem; -class QStyleOption; -class QColor; -class QPainter; -class QRectF; -class QRect; -class QPixmap; - -class QGraphicsEffectSourcePrivate; -class Q_GUI_EXPORT QGraphicsEffectSource : public QObject -{ - Q_OBJECT -public: - ~QGraphicsEffectSource(); - const QGraphicsItem *graphicsItem() const; - const QStyleOption *styleOption() const; - - bool isPixmap() const; - void draw(QPainter *painter); - void update(); - - QRectF boundingRect(Qt::CoordinateSystem coordinateSystem = Qt::LogicalCoordinates) const; - QRect deviceRect() const; - QPixmap pixmap(Qt::CoordinateSystem system = Qt::LogicalCoordinates, QPoint *offset = 0) const; - -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 -{ - Q_OBJECT - Q_FLAGS(ChangeFlags) - Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) -public: - enum ChangeFlag { - SourceAttached = 0x1, - SourceDetached = 0x2, - SourceBoundingRectChanged = 0x4, - SourceInvalidated = 0x8 - }; - Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag); - - QGraphicsEffect(); - virtual ~QGraphicsEffect(); - - // ### make protected? - virtual QRectF boundingRectFor(const QRectF &rect) const; - QRectF boundingRect() const; - - QGraphicsEffectSource *source() const; - - bool isEnabled() const; - -public Q_SLOTS: - void setEnabled(bool enable); - // ### add update() slot - -protected: - QGraphicsEffect(QGraphicsEffectPrivate &d); - virtual void draw(QPainter *painter, QGraphicsEffectSource *source) = 0; - virtual void sourceChanged(ChangeFlags flags); - void updateBoundingRect(); - -private: - Q_DECLARE_PRIVATE(QGraphicsEffect) - Q_DISABLE_COPY(QGraphicsEffect) - friend class QGraphicsItem; - friend class QGraphicsItemPrivate; - friend class QGraphicsScenePrivate; -}; - -class QGraphicsGrayscaleEffectPrivate; -class Q_GUI_EXPORT QGraphicsGrayscaleEffect: public QGraphicsEffect -{ - Q_OBJECT -public: - QGraphicsGrayscaleEffect(); - ~QGraphicsGrayscaleEffect(); - -protected: - void draw(QPainter *painter, QGraphicsEffectSource *source); - -private: - Q_DECLARE_PRIVATE(QGraphicsGrayscaleEffect) - Q_DISABLE_COPY(QGraphicsGrayscaleEffect) -}; - -class QGraphicsColorizeEffectPrivate; -class Q_GUI_EXPORT QGraphicsColorizeEffect: public QGraphicsEffect { - Q_OBJECT -public: - QGraphicsColorizeEffect(); - ~QGraphicsColorizeEffect(); - - QColor color() const; - void setColor(const QColor &c); - -protected: - void draw(QPainter *painter, QGraphicsEffectSource *source); - -private: - Q_DECLARE_PRIVATE(QGraphicsColorizeEffect) - Q_DISABLE_COPY(QGraphicsColorizeEffect) -}; - -class QGraphicsPixelizeEffectPrivate; -class Q_GUI_EXPORT QGraphicsPixelizeEffect: public QGraphicsEffect { - Q_OBJECT -public: - QGraphicsPixelizeEffect(); - ~QGraphicsPixelizeEffect(); - - int pixelSize() const; - void setPixelSize(int pixelSize); - -protected: - void draw(QPainter *painter, QGraphicsEffectSource *source); - -private: - Q_DECLARE_PRIVATE(QGraphicsPixelizeEffect) - Q_DISABLE_COPY(QGraphicsPixelizeEffect) -}; - -class QGraphicsBlurEffectPrivate; -class Q_GUI_EXPORT QGraphicsBlurEffect: public QGraphicsEffect { - Q_OBJECT -public: - QGraphicsBlurEffect(); - ~QGraphicsBlurEffect(); - - int blurRadius() const; - void setBlurRadius(int blurRadius); - -protected: - QRectF boundingRectFor(const QRectF &rect) const; - void draw(QPainter *painter, QGraphicsEffectSource *source); - -private: - Q_DECLARE_PRIVATE(QGraphicsBlurEffect) - Q_DISABLE_COPY(QGraphicsBlurEffect) -}; - -class QGraphicsBloomEffectPrivate; -class Q_GUI_EXPORT QGraphicsBloomEffect: public QGraphicsEffect { - Q_OBJECT -public: - QGraphicsBloomEffect(); - ~QGraphicsBloomEffect(); - - int blurRadius() const; - void setBlurRadius(int blurRadius); - - qreal opacity() const; - void setOpacity(qreal opacity); - -protected: - QRectF boundingRectFor(const QRectF &rect) const; - void draw(QPainter *painter, QGraphicsEffectSource *source); - -private: - Q_DECLARE_PRIVATE(QGraphicsBloomEffect) - Q_DISABLE_COPY(QGraphicsBloomEffect) -}; - -class QGraphicsFrameEffectPrivate; -class Q_GUI_EXPORT QGraphicsFrameEffect: public QGraphicsEffect { - Q_OBJECT -public: - QGraphicsFrameEffect(); - ~QGraphicsFrameEffect(); - - QColor frameColor() const; - void setFrameColor(const QColor &c); - - qreal frameWidth() const; - void setFrameWidth(qreal frameWidth); - - qreal frameOpacity() const; - void setFrameOpacity(qreal opacity); - -protected: - QRectF boundingRectFor(const QRectF &rect) const; - void draw(QPainter *painter, QGraphicsEffectSource *source); - -private: - Q_DECLARE_PRIVATE(QGraphicsFrameEffect) - Q_DISABLE_COPY(QGraphicsFrameEffect) -}; - -class QGraphicsShadowEffectPrivate; -class Q_GUI_EXPORT QGraphicsShadowEffect: public QGraphicsEffect { - Q_OBJECT -public: - QGraphicsShadowEffect(); - ~QGraphicsShadowEffect(); - - QPointF shadowOffset() const; - 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)); } - - int blurRadius() const; - void setBlurRadius(int blurRadius); - - qreal opacity() const; - void setOpacity(qreal opacity); - -protected: - QRectF boundingRectFor(const QRectF &rect) const; - void draw(QPainter *painter, QGraphicsEffectSource *source); - -private: - Q_DECLARE_PRIVATE(QGraphicsShadowEffect) - Q_DISABLE_COPY(QGraphicsShadowEffect) -}; - -#endif // QT_NO_GRAPHICSVIEW - -QT_END_NAMESPACE - -QT_END_HEADER - - -#endif // QGRAPHICSEFFECT_H diff --git a/src/gui/graphicsview/qgraphicseffect_p.h b/src/gui/graphicsview/qgraphicseffect_p.h deleted file mode 100644 index 6d546cc..0000000 --- a/src/gui/graphicsview/qgraphicseffect_p.h +++ /dev/null @@ -1,195 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGRAPHICSEFFECT_P_H -#define QGRAPHICSEFFECT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header -// file may change from version to version without notice, or even be removed. -// -// We mean it. -// - -#include "qgraphicseffect.h" - -#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW - -#include -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QGraphicsEffectSourcePrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QGraphicsEffectSource) -public: - QGraphicsEffectSourcePrivate() : QObjectPrivate() {} - virtual ~QGraphicsEffectSourcePrivate() {} - virtual void detach() = 0; - virtual QRectF boundingRect(Qt::CoordinateSystem system) const = 0; - virtual QRect deviceRect() const = 0; - virtual const QGraphicsItem *graphicsItem() const = 0; - virtual const QStyleOption *styleOption() const = 0; - virtual void draw(QPainter *p) = 0; - virtual void update() = 0; - virtual bool isPixmap() const = 0; - virtual QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset = 0) const = 0; - friend class QGraphicsScenePrivate; - friend class QGraphicsItem; - friend class QGraphicsItemPrivate; -}; - -class Q_GUI_EXPORT QGraphicsEffectPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QGraphicsEffect) -public: - QGraphicsEffectPrivate() : source(0), isEnabled(1) {} - - inline void setGraphicsEffectSource(QGraphicsEffectSource *newSource) - { - QGraphicsEffect::ChangeFlags flags; - if (source) { - flags |= QGraphicsEffect::SourceDetached; - source->d_func()->detach(); - delete source; - } - source = newSource; - if (newSource) - flags |= QGraphicsEffect::SourceAttached; - q_func()->sourceChanged(flags); - } - - QGraphicsEffectSource *source; - QRectF boundingRect; - quint32 isEnabled : 1; - quint32 padding : 31; // feel free to use -}; - -class QGraphicsGrayscaleEffectPrivate : public QGraphicsEffectPrivate -{ - Q_DECLARE_PUBLIC(QGraphicsGrayscaleEffect) -public: - QGraphicsGrayscaleEffectPrivate() - { - filter = new QPixmapColorizeFilter; - filter->setColor(Qt::black); - } - ~QGraphicsGrayscaleEffectPrivate() { delete filter; } - - QPixmapColorizeFilter *filter; -}; - -class QGraphicsColorizeEffectPrivate : public QGraphicsEffectPrivate -{ - Q_DECLARE_PUBLIC(QGraphicsColorizeEffect) -public: - QGraphicsColorizeEffectPrivate() { filter = new QPixmapColorizeFilter; } - ~QGraphicsColorizeEffectPrivate() { delete filter; } - - QPixmapColorizeFilter *filter; -}; - -class QGraphicsPixelizeEffectPrivate : public QGraphicsEffectPrivate -{ - Q_DECLARE_PUBLIC(QGraphicsPixelizeEffect) -public: - QGraphicsPixelizeEffectPrivate() : pixelSize(3) {} - - int pixelSize; -}; - -class QGraphicsBlurEffectPrivate : public QGraphicsEffectPrivate -{ - Q_DECLARE_PUBLIC(QGraphicsBlurEffect) -public: - QGraphicsBlurEffectPrivate() : filter(new QPixmapBlurFilter), blurRadius(4) {} - ~QGraphicsBlurEffectPrivate() { delete filter; } - - QPixmapBlurFilter *filter; - int blurRadius; -}; - -class QGraphicsBloomEffectPrivate : public QGraphicsEffectPrivate -{ - Q_DECLARE_PUBLIC(QGraphicsBlurEffect) -public: - QGraphicsBloomEffectPrivate() : blurRadius(6), opacity(0.7) {} - - int blurRadius; - qreal opacity; -}; - -class QGraphicsFrameEffectPrivate : public QGraphicsEffectPrivate -{ - Q_DECLARE_PUBLIC(QGraphicsFrameEffect) -public: - QGraphicsFrameEffectPrivate() : color(Qt::blue), width(5), alpha(0.6) {} - - QColor color; - qreal width; - qreal alpha; -}; - -class QGraphicsShadowEffectPrivate : public QGraphicsEffectPrivate -{ - Q_DECLARE_PUBLIC(QGraphicsShadowEffect) -public: - QGraphicsShadowEffectPrivate() : offset(4, 4), radius(8), alpha(0.7) {} - - QPointF offset; - int radius; - qreal alpha; -}; - -QT_END_NAMESPACE - -#endif // QT_NO_GRAPHICSVIEW - -#endif // QGRAPHICSEFFECT_P_H diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index a5854b1..a7b48fc 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -57,10 +57,11 @@ #include "qset.h" #include "qpixmapcache.h" #include "qgraphicsview_p.h" -#include "qgraphicseffect_p.h" #include "qgraphicstransform.h" #include "qgraphicstransform_p.h" +#include + #include #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index db783ad..ff8445f 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -207,7 +207,6 @@ #ifndef QT_NO_GRAPHICSVIEW -#include "qgraphicseffect_p.h" #include "qgraphicsitem.h" #include "qgraphicsitem_p.h" #include "qgraphicslayout.h" @@ -250,6 +249,7 @@ #ifdef Q_WS_X11 #include #endif +#include QT_BEGIN_NAMESPACE diff --git a/src/gui/gui.pro b/src/gui/gui.pro index a49d680..90ac3ce 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -34,6 +34,7 @@ include(graphicsview/graphicsview.pri) include(util/util.pri) include(statemachine/statemachine.pri) include(math3d/math3d.pri) +include(effects/effects.pri) contains(QT_CONFIG, egl): include(egl/egl.pri) -- cgit v0.12