summaryrefslogtreecommitdiffstats
path: root/src/widgets/effects
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2011-05-07 00:02:01 +0200
committerLars Knoll <lars.knoll@nokia.com>2011-05-07 00:02:01 +0200
commitf67b8df3ebdba2d398b9cce686b7c644adffff08 (patch)
tree062dd469f7cf8daa01a32d3e7b767b8fbdb7573a /src/widgets/effects
parent32ce4fe9e6a94e77828e976776cf08da85254ff2 (diff)
library split
Diffstat (limited to 'src/widgets/effects')
-rw-r--r--src/widgets/effects/effects.pri6
-rw-r--r--src/widgets/effects/qgraphicseffect.cpp1235
-rw-r--r--src/widgets/effects/qgraphicseffect.h289
-rw-r--r--src/widgets/effects/qgraphicseffect_p.h231
-rw-r--r--src/widgets/effects/qpixmapfilter.cpp1381
-rw-r--r--src/widgets/effects/qpixmapfilter_p.h196
6 files changed, 3338 insertions, 0 deletions
diff --git a/src/widgets/effects/effects.pri b/src/widgets/effects/effects.pri
new file mode 100644
index 0000000000..a21f941866
--- /dev/null
+++ b/src/widgets/effects/effects.pri
@@ -0,0 +1,6 @@
+HEADERS += effects/qgraphicseffect.h \
+ effects/qgraphicseffect_p.h \
+ effects/qpixmapfilter_p.h
+
+SOURCES += effects/qgraphicseffect.cpp \
+ effects/qpixmapfilter.cpp
diff --git a/src/widgets/effects/qgraphicseffect.cpp b/src/widgets/effects/qgraphicseffect.cpp
new file mode 100644
index 0000000000..7ba38f6d3a
--- /dev/null
+++ b/src/widgets/effects/qgraphicseffect.cpp
@@ -0,0 +1,1235 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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(false). If effects are disabled, the source
+ is rendered directly.
+
+ To add a visual effect to a QGraphicsItem, for example, you can use one of
+ the standard effects, or alternately, create your own effect by creating a
+ subclass of QGraphicsEffect. The effect can then be installed on the item
+ using QGraphicsItem::setGraphicsEffect().
+
+ Qt provides the following standard effects:
+
+ \list
+ \o QGraphicsBlurEffect - blurs the item by a given radius
+ \o QGraphicsDropShadowEffect - renders a dropshadow behind the item
+ \o QGraphicsColorizeEffect - renders the item in shades of any given color
+ \o QGraphicsOpacityEffect - renders the item with an opacity
+ \endlist
+
+ \table
+ \row
+ \o{2,1} \img graphicseffect-plain.png
+ \row
+ \o \img graphicseffect-blur.png
+ \o \img graphicseffect-colorize.png
+ \row
+ \o \img graphicseffect-opacity.png
+ \o \img graphicseffect-drop-shadow.png
+ \endtable
+
+ \img graphicseffect-widget.png
+
+ For more information on how to use each effect, refer to the specific
+ effect's documentation.
+
+ To create your own custom effect, create a subclass of QGraphicsEffect (or
+ any other existing effects) and reimplement the virtual function draw().
+ This function is called whenever the effect needs to redraw. The draw()
+ function takes the painter with which to draw as an argument. For more
+ information, refer to the documenation for draw(). In the draw() function
+ you can call sourcePixmap() to get a pixmap of the graphics effect source
+ which you can then process.
+
+ If your effect changes, use update() to request for 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
+ sourceChanged() function is called to notify the effects that
+ the source has changed in some way - e.g., if the source is a
+ QGraphicsRectItem and its rectangle parameters have changed.
+
+ \sa QGraphicsItem::setGraphicsEffect(), QWidget::setGraphicsEffect()
+*/
+
+#include "qgraphicseffect_p.h"
+#include "private/qgraphicsitem_p.h"
+
+#include <QtGui/qgraphicsitem.h>
+
+#include <QtGui/qimage.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpaintengine.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qdebug.h>
+#include <private/qdrawhelper_p.h>
+
+#ifndef QT_NO_GRAPHICSEFFECT
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QGraphicsEffectSource
+ \brief The QGraphicsEffectSource class represents the source on which a
+ QGraphicsEffect is installed on.
+
+ When a QGraphicsEffect is installed on a QGraphicsItem, for example, this
+ class will act as a wrapper around QGraphicsItem. Then, calling update() is
+ effectively the same as calling QGraphicsItem::update().
+
+ QGraphicsEffectSource also provides a pixmap() function which creates a
+ pixmap with the source painted into it.
+
+ \sa QGraphicsItem::setGraphicsEffect(), QWidget::setGraphicsEffect().
+*/
+
+/*!
+ \internal
+*/
+QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{}
+
+/*!
+ Destroys the effect source.
+*/
+QGraphicsEffectSource::~QGraphicsEffectSource()
+{}
+
+/*!
+ Returns the bounding rectangle of the source mapped to the given \a system.
+
+ \sa draw()
+*/
+QRectF QGraphicsEffectSource::boundingRect(Qt::CoordinateSystem system) const
+{
+ return d_func()->boundingRect(system);
+}
+
+/*!
+ Returns the bounding rectangle of the source mapped to the given \a system.
+
+ Calling this function with Qt::DeviceCoordinates outside of
+ QGraphicsEffect::draw() will give undefined results, as there is no device
+ context available.
+
+ \sa draw()
+*/
+QRectF QGraphicsEffect::sourceBoundingRect(Qt::CoordinateSystem system) const
+{
+ Q_D(const QGraphicsEffect);
+ if (d->source)
+ return d->source->boundingRect(system);
+ return QRectF();
+}
+
+/*!
+ Returns a pointer to the item if this source is a QGraphicsItem; otherwise
+ returns 0.
+
+ \sa widget()
+*/
+const QGraphicsItem *QGraphicsEffectSource::graphicsItem() const
+{
+ return d_func()->graphicsItem();
+}
+
+/*!
+ Returns a pointer to the widget if this source is a QWidget; otherwise
+ returns 0.
+
+ \sa graphicsItem()
+*/
+const QWidget *QGraphicsEffectSource::widget() const
+{
+ return d_func()->widget();
+}
+
+/*!
+ Returns a pointer to the style options (used when drawing the source) if
+ available; otherwise returns 0.
+
+ \sa graphicsItem(), widget()
+*/
+const QStyleOption *QGraphicsEffectSource::styleOption() const
+{
+ return d_func()->styleOption();
+}
+
+/*!
+ Draws the source using the given \a painter.
+
+ This function should only be called from QGraphicsEffect::draw().
+
+ \sa QGraphicsEffect::draw()
+*/
+void QGraphicsEffectSource::draw(QPainter *painter)
+{
+ Q_D(const QGraphicsEffectSource);
+
+ QPixmap pm;
+ if (QPixmapCache::find(d->m_cacheKey, &pm)) {
+ QTransform restoreTransform;
+ if (d->m_cachedSystem == Qt::DeviceCoordinates) {
+ restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ }
+
+ painter->drawPixmap(d->m_cachedOffset, pm);
+
+ if (d->m_cachedSystem == Qt::DeviceCoordinates)
+ painter->setWorldTransform(restoreTransform);
+ } else {
+ d_func()->draw(painter);
+ }
+}
+
+/*!
+ Draws the source directly using the given \a painter.
+
+ This function should only be called from QGraphicsEffect::draw().
+
+ For example:
+
+ \snippet doc/src/snippets/code/src_gui_effects_qgraphicseffect.cpp 0
+
+ \sa QGraphicsEffect::draw()
+*/
+void QGraphicsEffect::drawSource(QPainter *painter)
+{
+ Q_D(const QGraphicsEffect);
+ if (d->source)
+ d->source->draw(painter);
+}
+
+/*!
+ Schedules a redraw of the source. Call this function whenever the source
+ needs to be redrawn.
+
+ \sa QGraphicsEffect::updateBoundingRect(), QWidget::update(),
+ QGraphicsItem::update(),
+*/
+void QGraphicsEffectSource::update()
+{
+ d_func()->update();
+}
+
+/*!
+ Returns true if the source effectively is a pixmap, e.g., a
+ QGraphicsPixmapItem.
+
+ This function is useful for optimization purposes. For instance, there's no
+ point in drawing the source in device coordinates to avoid pixmap scaling
+ if this function returns true - the source pixmap will be scaled anyways.
+*/
+bool QGraphicsEffectSource::isPixmap() const
+{
+ return d_func()->isPixmap();
+}
+
+/*!
+ Returns true if the source effectively is a pixmap, e.g., a
+ QGraphicsPixmapItem.
+
+ This function is useful for optimization purposes. For instance, there's no
+ point in drawing the source in device coordinates to avoid pixmap scaling
+ if this function returns true - the source pixmap will be scaled anyways.
+*/
+bool QGraphicsEffect::sourceIsPixmap() const
+{
+ return source() ? source()->isPixmap() : false;
+}
+
+/*!
+ Returns a pixmap with the source painted into it.
+
+ The \a system specifies which coordinate system to be used for the source.
+ The optional \a offset parameter returns the offset where the pixmap should
+ be painted at using the current painter.
+
+ The \a mode determines how much of the effect the pixmap will contain.
+ By default, the pixmap will contain the whole effect.
+
+ The returned pixmap is bound to the current painter's device rectangle when
+ \a system is Qt::DeviceCoordinates.
+
+ \sa QGraphicsEffect::draw(), boundingRect()
+*/
+QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const
+{
+ Q_D(const QGraphicsEffectSource);
+
+ // Shortcut, no cache for childless pixmap items...
+ const QGraphicsItem *item = graphicsItem();
+ if (system == Qt::LogicalCoordinates && mode == QGraphicsEffect::NoPad && item && isPixmap()) {
+ const QGraphicsPixmapItem *pixmapItem = static_cast<const QGraphicsPixmapItem *>(item);
+ if (offset)
+ *offset = pixmapItem->offset().toPoint();
+ return pixmapItem->pixmap();
+ }
+
+ if (system == Qt::DeviceCoordinates && item
+ && !static_cast<const QGraphicsItemEffectSourcePrivate *>(d_func())->info) {
+ qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
+ return QPixmap();
+ }
+
+ QPixmap pm;
+ if (item && d->m_cachedSystem == system && d->m_cachedMode == mode)
+ QPixmapCache::find(d->m_cacheKey, &pm);
+
+ if (pm.isNull()) {
+ pm = d->pixmap(system, &d->m_cachedOffset, mode);
+ d->m_cachedSystem = system;
+ d->m_cachedMode = mode;
+
+ d->invalidateCache();
+ d->m_cacheKey = QPixmapCache::insert(pm);
+ }
+
+ if (offset)
+ *offset = d->m_cachedOffset;
+
+ return pm;
+}
+
+/*!
+ Returns a pixmap with the source painted into it.
+
+ The \a system specifies which coordinate system to be used for the source.
+ The optional \a offset parameter returns the offset where the pixmap should
+ be painted at using the current painter. For control on how the pixmap is
+ padded use the \a mode parameter.
+
+ The returned pixmap is clipped to the current painter's device rectangle when
+ \a system is Qt::DeviceCoordinates.
+
+ Calling this function with Qt::DeviceCoordinates outside of
+ QGraphicsEffect::draw() will give undefined results, as there is no device
+ context available.
+
+ \sa draw(), boundingRect()
+*/
+QPixmap QGraphicsEffect::sourcePixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const
+{
+ Q_D(const QGraphicsEffect);
+ if (d->source)
+ return d->source->pixmap(system, offset, mode);
+ return QPixmap();
+}
+
+QGraphicsEffectSourcePrivate::~QGraphicsEffectSourcePrivate()
+{
+ invalidateCache();
+}
+
+void QGraphicsEffectSourcePrivate::setCachedOffset(const QPoint &offset)
+{
+ m_cachedOffset = offset;
+}
+
+void QGraphicsEffectSourcePrivate::invalidateCache(InvalidateReason reason) const
+{
+ if (m_cachedMode != QGraphicsEffect::PadToEffectiveBoundingRect
+ && (reason == EffectRectChanged
+ || (reason == TransformChanged && m_cachedSystem == Qt::LogicalCoordinates))) {
+ return;
+ }
+
+ QPixmapCache::remove(m_cacheKey);
+}
+
+/*!
+ Constructs a new QGraphicsEffect instance having the
+ specified \a parent.
+*/
+QGraphicsEffect::QGraphicsEffect(QObject *parent)
+ : QObject(*new QGraphicsEffectPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QGraphicsEffect::QGraphicsEffect(QGraphicsEffectPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ Removes the effect from the source, and destroys the graphics effect.
+*/
+QGraphicsEffect::~QGraphicsEffect()
+{
+ Q_D(QGraphicsEffect);
+ d->setGraphicsEffectSource(0);
+}
+
+/*!
+ Returns the effective bounding rectangle for this effect, i.e., the
+ bounding rectangle of the source in device coordinates, 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 effective bounding rectangle for this effect, given the
+ provided \a rect in the device coordinates. 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 sourceBoundingRect()
+*/
+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, the source will
+ be rendered with the effect applied.
+
+ This property is enabled by default.
+
+ Using this property, 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->d_func()->effectBoundingRectChanged();
+ d->source->d_func()->invalidateCache();
+ }
+ emit enabledChanged(enable);
+}
+
+/*!
+ \fn void QGraphicsEffect::enabledChanged(bool enabled)
+
+ This signal is emitted whenever the effect is enabled or disabled.
+ The \a enabled parameter holds the effects's new enabled state.
+
+ \sa isEnabled()
+*/
+
+/*!
+ Schedules a redraw of the effect. Call this function whenever the effect
+ needs to be redrawn. This function does not trigger a redraw of the source.
+
+ \sa updateBoundingRect()
+*/
+void QGraphicsEffect::update()
+{
+ Q_D(QGraphicsEffect);
+ if (d->source)
+ d->source->update();
+}
+
+/*!
+ \internal
+
+ 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 when 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.
+
+ This function will call update() if this is necessary.
+
+ \sa boundingRectFor(), boundingRect(), sourceBoundingRect()
+*/
+void QGraphicsEffect::updateBoundingRect()
+{
+ Q_D(QGraphicsEffect);
+ if (d->source) {
+ d->source->d_func()->effectBoundingRectChanged();
+ d->source->d_func()->invalidateCache(QGraphicsEffectSourcePrivate::EffectRectChanged);
+ }
+}
+
+/*!
+ \fn virtual void QGraphicsEffect::draw(QPainter *painter) = 0
+
+ This pure virtual function draws the effect and is called whenever the
+ source needs to be drawn.
+
+ Reimplement this function in a QGraphicsEffect subclass to provide the
+ effect's drawing implementation, using \a painter.
+
+ For example:
+
+ \snippet doc/src/snippets/code/src_gui_effects_qgraphicseffect.cpp 1
+
+ This function should not be called explicitly by the user, since it is
+ meant for reimplementation purposes only.
+*/
+
+/*!
+ \enum QGraphicsEffect::ChangeFlag
+
+ This enum describes what has changed in QGraphicsEffectSource.
+
+ \value SourceAttached The effect is installed on a source.
+ \value SourceDetached The effect is uninstalled on a source.
+ \value SourceBoundingRectChanged The bounding rect of the source has
+ changed.
+ \value SourceInvalidated The visual appearance of the source has changed.
+*/
+
+/*!
+ \enum QGraphicsEffect::PixmapPadMode
+
+ This enum describes how the pixmap returned from sourcePixmap should be
+ padded.
+
+ \value NoPad The pixmap should not receive any additional
+ padding.
+ \value PadToTransparentBorder The pixmap should be padded
+ to ensure it has a completely transparent border.
+ \value PadToEffectiveBoundingRect The pixmap should be padded to
+ match the effective bounding rectangle of the effect.
+*/
+
+/*!
+ 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);
+}
+
+/*!
+ \class QGraphicsColorizeEffect
+ \brief The QGraphicsColorizeEffect class provides a colorize effect.
+ \since 4.6
+
+ A colorize effect renders the source with a tint of its color(). The color
+ can be modified using the setColor() function.
+
+ By default, the color is light blue (QColor(0, 0, 192)).
+
+ \img graphicseffect-colorize.png
+
+ \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsOpacityEffect
+*/
+
+/*!
+ Constructs a new QGraphicsColorizeEffect instance.
+ The \a parent parameter is passed to QGraphicsEffect's constructor.
+*/
+QGraphicsColorizeEffect::QGraphicsColorizeEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsColorizeEffectPrivate, parent)
+{
+}
+
+/*!
+ Destroys the effect.
+*/
+QGraphicsColorizeEffect::~QGraphicsColorizeEffect()
+{
+}
+
+/*!
+ \property QGraphicsColorizeEffect::color
+ \brief the color of the effect.
+
+ By default, the color is light blue (QColor(0, 0, 192)).
+*/
+QColor QGraphicsColorizeEffect::color() const
+{
+ Q_D(const QGraphicsColorizeEffect);
+ return d->filter->color();
+}
+
+void QGraphicsColorizeEffect::setColor(const QColor &color)
+{
+ Q_D(QGraphicsColorizeEffect);
+ if (d->filter->color() == color)
+ return;
+
+ d->filter->setColor(color);
+ update();
+ emit colorChanged(color);
+}
+
+/*!
+ \property QGraphicsColorizeEffect::strength
+ \brief the strength of the effect.
+
+ By default, the strength is 1.0.
+ A strength 0.0 equals to no effect, while 1.0 means full colorization.
+*/
+qreal QGraphicsColorizeEffect::strength() const
+{
+ Q_D(const QGraphicsColorizeEffect);
+ return d->filter->strength();
+}
+
+void QGraphicsColorizeEffect::setStrength(qreal strength)
+{
+ Q_D(QGraphicsColorizeEffect);
+ if (qFuzzyCompare(d->filter->strength(), strength))
+ return;
+
+ d->filter->setStrength(strength);
+ d->opaque = !qFuzzyIsNull(strength);
+ update();
+ emit strengthChanged(strength);
+}
+
+/*! \fn void QGraphicsColorizeEffect::strengthChanged(qreal strength)
+ This signal is emitted whenever setStrength() changes the colorize
+ strength property. \a strength contains the new strength value of
+ the colorize effect.
+ */
+
+/*!
+ \fn void QGraphicsColorizeEffect::colorChanged(const QColor &color)
+
+ This signal is emitted whenever the effect's color changes.
+ The \a color parameter holds the effect's new color.
+*/
+
+/*!
+ \reimp
+*/
+void QGraphicsColorizeEffect::draw(QPainter *painter)
+{
+ Q_D(QGraphicsColorizeEffect);
+
+ if (!d->opaque) {
+ drawSource(painter);
+ return;
+ }
+
+ QPoint offset;
+ if (sourceIsPixmap()) {
+ // No point in drawing in device coordinates (pixmap will be scaled anyways).
+ const QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, NoPad);
+ if (!pixmap.isNull())
+ d->filter->draw(painter, offset, pixmap);
+
+ return;
+ }
+
+ // Draw pixmap in deviceCoordinates to avoid pixmap scaling.
+ const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset);
+ if (pixmap.isNull())
+ return;
+
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ d->filter->draw(painter, offset, pixmap);
+ painter->setWorldTransform(restoreTransform);
+}
+
+/*!
+ \class QGraphicsBlurEffect
+ \brief The QGraphicsBlurEffect class provides a blur effect.
+ \since 4.6
+
+ A blur effect blurs the source. This effect is useful for reducing details,
+ such as when the source loses focus and you want to draw attention to other
+ elements. The level of detail can be modified using the setBlurRadius()
+ function. Use setBlurHints() to choose the blur hints.
+
+ By default, the blur radius is 5 pixels. The blur radius is specified in
+ device coordinates.
+
+ \img graphicseffect-blur.png
+
+ \sa QGraphicsDropShadowEffect, QGraphicsColorizeEffect, QGraphicsOpacityEffect
+*/
+
+/*!
+ \enum QGraphicsBlurEffect::BlurHint
+ \since 4.6
+
+ This enum describes the possible hints that can be used to control how
+ blur effects are applied. The hints might not have an effect in all the
+ paint engines.
+
+ \value PerformanceHint Indicates that rendering performance is the most important factor,
+ at the potential cost of lower quality.
+
+ \value QualityHint Indicates that rendering quality is the most important factor,
+ at the potential cost of lower performance.
+
+ \value AnimationHint Indicates that the blur radius is going to be animated, hinting
+ that the implementation can keep a cache of blurred verisons of the source.
+ Do not use this hint if the source is going to be dynamically changing.
+
+ \sa blurHints(), setBlurHints()
+*/
+
+
+/*!
+ Constructs a new QGraphicsBlurEffect instance.
+ The \a parent parameter is passed to QGraphicsEffect's constructor.
+*/
+QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsBlurEffectPrivate, parent)
+{
+ Q_D(QGraphicsBlurEffect);
+ d->filter->setBlurHints(QGraphicsBlurEffect::PerformanceHint);
+}
+
+/*!
+ Destroys the effect.
+*/
+QGraphicsBlurEffect::~QGraphicsBlurEffect()
+{
+}
+
+/*!
+ \property QGraphicsBlurEffect::blurRadius
+ \brief the blur radius of the effect.
+
+ Using a smaller radius results in a sharper appearance, whereas a bigger
+ radius results in a more blurred appearance.
+
+ By default, the blur radius is 5 pixels.
+
+ The radius is given in device coordinates, meaning it is
+ unaffected by scale.
+*/
+qreal QGraphicsBlurEffect::blurRadius() const
+{
+ Q_D(const QGraphicsBlurEffect);
+ return d->filter->radius();
+}
+
+void QGraphicsBlurEffect::setBlurRadius(qreal radius)
+{
+ Q_D(QGraphicsBlurEffect);
+ if (qFuzzyCompare(d->filter->radius(), radius))
+ return;
+
+ d->filter->setRadius(radius);
+ updateBoundingRect();
+ emit blurRadiusChanged(radius);
+}
+
+/*!
+ \fn void QGraphicsBlurEffect::blurRadiusChanged(qreal radius)
+
+ This signal is emitted whenever the effect's blur radius changes.
+ The \a radius parameter holds the effect's new blur radius.
+*/
+
+/*!
+ \property QGraphicsBlurEffect::blurHints
+ \brief the blur hint of the effect.
+
+ Use the PerformanceHint hint to say that you want a faster blur,
+ the QualityHint hint to say that you prefer a higher quality blur,
+ or the AnimationHint when you want to animate the blur radius.
+
+ By default, the blur hint is PerformanceHint.
+*/
+QGraphicsBlurEffect::BlurHints QGraphicsBlurEffect::blurHints() const
+{
+ Q_D(const QGraphicsBlurEffect);
+ return d->filter->blurHints();
+}
+
+void QGraphicsBlurEffect::setBlurHints(QGraphicsBlurEffect::BlurHints hints)
+{
+ Q_D(QGraphicsBlurEffect);
+ if (d->filter->blurHints() == hints)
+ return;
+
+ d->filter->setBlurHints(hints);
+ emit blurHintsChanged(hints);
+}
+
+/*!
+ \fn void QGraphicsBlurEffect::blurHintsChanged(QGraphicsBlurEffect::BlurHints hints)
+
+ This signal is emitted whenever the effect's blur hints changes.
+ The \a hints parameter holds the effect's new blur hints.
+*/
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const
+{
+ Q_D(const QGraphicsBlurEffect);
+ return d->filter->boundingRectFor(rect);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsBlurEffect::draw(QPainter *painter)
+{
+ Q_D(QGraphicsBlurEffect);
+ if (d->filter->radius() < 1) {
+ drawSource(painter);
+ return;
+ }
+
+ PixmapPadMode mode = PadToEffectiveBoundingRect;
+ if (painter->paintEngine()->type() == QPaintEngine::OpenGL2)
+ mode = NoPad;
+
+ QPoint offset;
+ QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, mode);
+ if (pixmap.isNull())
+ return;
+
+ d->filter->draw(painter, offset, pixmap);
+}
+
+/*!
+ \class QGraphicsDropShadowEffect
+ \brief The QGraphicsDropShadowEffect class provides a drop shadow effect.
+ \since 4.6
+
+ A drop shadow effect renders the source with a drop shadow. The color of
+ the drop shadow can be modified using the setColor() function. The drop
+ shadow offset can be modified using the setOffset() function and the blur
+ radius of the drop shadow can be changed with the setBlurRadius()
+ function.
+
+ By default, the drop shadow is a semi-transparent dark gray
+ (QColor(63, 63, 63, 180)) shadow, blurred with a radius of 1 at an offset
+ of 8 pixels towards the lower right. The drop shadow offset is specified
+ in device coordinates.
+
+ \img graphicseffect-drop-shadow.png
+
+ \sa QGraphicsBlurEffect, QGraphicsColorizeEffect, QGraphicsOpacityEffect
+*/
+
+/*!
+ Constructs a new QGraphicsDropShadowEffect instance.
+ The \a parent parameter is passed to QGraphicsEffect's constructor.
+*/
+QGraphicsDropShadowEffect::QGraphicsDropShadowEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsDropShadowEffectPrivate, parent)
+{
+}
+
+/*!
+ Destroys the effect.
+*/
+QGraphicsDropShadowEffect::~QGraphicsDropShadowEffect()
+{
+}
+
+/*!
+ \property QGraphicsDropShadowEffect::offset
+ \brief the shadow offset in pixels.
+
+ By default, the offset is 8 pixels towards the lower right.
+
+ The offset is given in device coordinates, which means it is
+ unaffected by scale.
+
+ \sa xOffset(), yOffset(), blurRadius(), color()
+*/
+QPointF QGraphicsDropShadowEffect::offset() const
+{
+ Q_D(const QGraphicsDropShadowEffect);
+ return d->filter->offset();
+}
+
+void QGraphicsDropShadowEffect::setOffset(const QPointF &offset)
+{
+ Q_D(QGraphicsDropShadowEffect);
+ if (d->filter->offset() == offset)
+ return;
+
+ d->filter->setOffset(offset);
+ updateBoundingRect();
+ emit offsetChanged(offset);
+}
+
+/*!
+ \property QGraphicsDropShadowEffect::xOffset
+ \brief the horizontal shadow offset in pixels.
+
+ By default, the horizontal shadow offset is 8 pixels.
+
+
+
+ \sa yOffset(), offset()
+*/
+
+/*!
+ \property QGraphicsDropShadowEffect::yOffset
+ \brief the vertical shadow offset in pixels.
+
+ By default, the vertical shadow offset is 8 pixels.
+
+ \sa xOffset(), offset()
+*/
+
+/*!
+ \fn void QGraphicsDropShadowEffect::offsetChanged(const QPointF &offset)
+
+ This signal is emitted whenever the effect's shadow offset changes.
+ The \a offset parameter holds the effect's new shadow offset.
+*/
+
+/*!
+ \property QGraphicsDropShadowEffect::blurRadius
+ \brief the blur radius in pixels of the drop shadow.
+
+ Using a smaller radius results in a sharper shadow, whereas using a bigger
+ radius results in a more blurred shadow.
+
+ By default, the blur radius is 1 pixel.
+
+ \sa color(), offset().
+*/
+qreal QGraphicsDropShadowEffect::blurRadius() const
+{
+ Q_D(const QGraphicsDropShadowEffect);
+ return d->filter->blurRadius();
+}
+
+void QGraphicsDropShadowEffect::setBlurRadius(qreal blurRadius)
+{
+ Q_D(QGraphicsDropShadowEffect);
+ if (qFuzzyCompare(d->filter->blurRadius(), blurRadius))
+ return;
+
+ d->filter->setBlurRadius(blurRadius);
+ updateBoundingRect();
+ emit blurRadiusChanged(blurRadius);
+}
+
+/*!
+ \fn void QGraphicsDropShadowEffect::blurRadiusChanged(qreal blurRadius)
+
+ This signal is emitted whenever the effect's blur radius changes.
+ The \a blurRadius parameter holds the effect's new blur radius.
+*/
+
+/*!
+ \property QGraphicsDropShadowEffect::color
+ \brief the color of the drop shadow.
+
+ By default, the drop color is a semi-transparent dark gray
+ (QColor(63, 63, 63, 180)).
+
+ \sa offset(), blurRadius()
+*/
+QColor QGraphicsDropShadowEffect::color() const
+{
+ Q_D(const QGraphicsDropShadowEffect);
+ return d->filter->color();
+}
+
+void QGraphicsDropShadowEffect::setColor(const QColor &color)
+{
+ Q_D(QGraphicsDropShadowEffect);
+ if (d->filter->color() == color)
+ return;
+
+ d->filter->setColor(color);
+ update();
+ emit colorChanged(color);
+}
+
+/*!
+ \fn void QGraphicsDropShadowEffect::colorChanged(const QColor &color)
+
+ This signal is emitted whenever the effect's color changes.
+ The \a color parameter holds the effect's new color.
+*/
+
+/*!
+ \reimp
+*/
+QRectF QGraphicsDropShadowEffect::boundingRectFor(const QRectF &rect) const
+{
+ Q_D(const QGraphicsDropShadowEffect);
+ return d->filter->boundingRectFor(rect);
+}
+
+/*!
+ \reimp
+*/
+void QGraphicsDropShadowEffect::draw(QPainter *painter)
+{
+ Q_D(QGraphicsDropShadowEffect);
+ if (d->filter->blurRadius() <= 0 && d->filter->offset().isNull()) {
+ drawSource(painter);
+ return;
+ }
+
+ PixmapPadMode mode = PadToEffectiveBoundingRect;
+ if (painter->paintEngine()->type() == QPaintEngine::OpenGL2)
+ mode = NoPad;
+
+ // Draw pixmap in device coordinates to avoid pixmap scaling.
+ QPoint offset;
+ const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset, mode);
+ if (pixmap.isNull())
+ return;
+
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ d->filter->draw(painter, offset, pixmap);
+ painter->setWorldTransform(restoreTransform);
+}
+
+/*!
+ \class QGraphicsOpacityEffect
+ \brief The QGraphicsOpacityEffect class provides an opacity effect.
+ \since 4.6
+
+ An opacity effect renders the source with an opacity. This effect is useful
+ for making the source semi-transparent, similar to a fade-in/fade-out
+ sequence. The opacity can be modified using the setOpacity() function.
+
+ By default, the opacity is 0.7.
+
+ \img graphicseffect-opacity.png
+
+ \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsColorizeEffect
+*/
+
+/*!
+ Constructs a new QGraphicsOpacityEffect instance.
+ The \a parent parameter is passed to QGraphicsEffect's constructor.
+*/
+QGraphicsOpacityEffect::QGraphicsOpacityEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsOpacityEffectPrivate, parent)
+{
+}
+
+/*!
+ Destroys the effect.
+*/
+QGraphicsOpacityEffect::~QGraphicsOpacityEffect()
+{
+}
+
+/*!
+ \property QGraphicsOpacityEffect::opacity
+ \brief the opacity of the effect.
+
+ The value should be in the range of 0.0 to 1.0, where 0.0 is
+ fully transparent and 1.0 is fully opaque.
+
+ By default, the opacity is 0.7.
+
+ \sa setOpacityMask()
+*/
+qreal QGraphicsOpacityEffect::opacity() const
+{
+ Q_D(const QGraphicsOpacityEffect);
+ return d->opacity;
+}
+
+void QGraphicsOpacityEffect::setOpacity(qreal opacity)
+{
+ Q_D(QGraphicsOpacityEffect);
+ opacity = qBound(qreal(0.0), opacity, qreal(1.0));
+
+ if (qFuzzyCompare(d->opacity, opacity))
+ return;
+
+ d->opacity = opacity;
+ if ((d->isFullyTransparent = qFuzzyIsNull(d->opacity)))
+ d->isFullyOpaque = 0;
+ else
+ d->isFullyOpaque = qFuzzyIsNull(d->opacity - 1);
+ update();
+ emit opacityChanged(opacity);
+}
+
+/*!
+ \fn void QGraphicsOpacityEffect::opacityChanged(qreal opacity)
+
+ This signal is emitted whenever the effect's opacity changes.
+ The \a opacity parameter holds the effect's new opacity.
+*/
+
+/*!
+ \property QGraphicsOpacityEffect::opacityMask
+ \brief the opacity mask of the effect.
+
+ An opacity mask allows you apply opacity to portions of an element.
+
+ For example:
+
+ \snippet doc/src/snippets/code/src_gui_effects_qgraphicseffect.cpp 2
+
+ There is no opacity mask by default.
+
+ \sa setOpacity()
+*/
+QBrush QGraphicsOpacityEffect::opacityMask() const
+{
+ Q_D(const QGraphicsOpacityEffect);
+ return d->opacityMask;
+}
+
+void QGraphicsOpacityEffect::setOpacityMask(const QBrush &mask)
+{
+ Q_D(QGraphicsOpacityEffect);
+ if (d->opacityMask == mask)
+ return;
+
+ d->opacityMask = mask;
+ d->hasOpacityMask = (mask.style() != Qt::NoBrush);
+ update();
+
+ emit opacityMaskChanged(mask);
+}
+
+/*!
+ \fn void QGraphicsOpacityEffect::opacityMaskChanged(const QBrush &mask)
+
+ This signal is emitted whenever the effect's opacity mask changes.
+ The \a mask parameter holds the effect's new opacity mask.
+*/
+
+/*!
+ \reimp
+*/
+void QGraphicsOpacityEffect::draw(QPainter *painter)
+{
+ Q_D(QGraphicsOpacityEffect);
+
+ // Transparent; nothing to draw.
+ if (d->isFullyTransparent)
+ return;
+
+ // Opaque; draw directly without going through a pixmap.
+ if (d->isFullyOpaque && !d->hasOpacityMask) {
+ drawSource(painter);
+ return;
+ }
+
+ QPoint offset;
+ Qt::CoordinateSystem system = sourceIsPixmap() ? Qt::LogicalCoordinates : Qt::DeviceCoordinates;
+ QPixmap pixmap = sourcePixmap(system, &offset, QGraphicsEffect::NoPad);
+ if (pixmap.isNull())
+ return;
+
+ painter->save();
+ painter->setOpacity(d->opacity);
+
+ if (d->hasOpacityMask) {
+ QPainter pixmapPainter(&pixmap);
+ pixmapPainter.setRenderHints(painter->renderHints());
+ pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ if (system == Qt::DeviceCoordinates) {
+ QTransform worldTransform = painter->worldTransform();
+ worldTransform *= QTransform::fromTranslate(-offset.x(), -offset.y());
+ pixmapPainter.setWorldTransform(worldTransform);
+ pixmapPainter.fillRect(sourceBoundingRect(), d->opacityMask);
+ } else {
+ pixmapPainter.translate(-offset);
+ pixmapPainter.fillRect(pixmap.rect(), d->opacityMask);
+ }
+ }
+
+ if (system == Qt::DeviceCoordinates)
+ painter->setWorldTransform(QTransform());
+
+ painter->drawPixmap(offset, pixmap);
+ painter->restore();
+}
+
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSEFFECT
diff --git a/src/widgets/effects/qgraphicseffect.h b/src/widgets/effects/qgraphicseffect.h
new file mode 100644
index 0000000000..9f5e94db89
--- /dev/null
+++ b/src/widgets/effects/qgraphicseffect.h
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSEFFECT_H
+#define QGRAPHICSEFFECT_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qbrush.h>
+
+#ifndef QT_NO_GRAPHICSEFFECT
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QGraphicsItem;
+class QStyleOption;
+class QPainter;
+class QPixmap;
+
+class QGraphicsEffectSource;
+
+class QGraphicsEffectPrivate;
+class Q_GUI_EXPORT QGraphicsEffect : public QObject
+{
+ Q_OBJECT
+ Q_FLAGS(ChangeFlags)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+public:
+ enum ChangeFlag {
+ SourceAttached = 0x1,
+ SourceDetached = 0x2,
+ SourceBoundingRectChanged = 0x4,
+ SourceInvalidated = 0x8
+ };
+ Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag)
+
+ enum PixmapPadMode {
+ NoPad,
+ PadToTransparentBorder,
+ PadToEffectiveBoundingRect
+ };
+
+ QGraphicsEffect(QObject *parent = 0);
+ virtual ~QGraphicsEffect();
+
+ virtual QRectF boundingRectFor(const QRectF &sourceRect) const;
+ QRectF boundingRect() const;
+
+ bool isEnabled() const;
+
+public Q_SLOTS:
+ void setEnabled(bool enable);
+ void update();
+
+Q_SIGNALS:
+ void enabledChanged(bool enabled);
+
+protected:
+ QGraphicsEffect(QGraphicsEffectPrivate &d, QObject *parent = 0);
+ virtual void draw(QPainter *painter) = 0;
+ virtual void sourceChanged(ChangeFlags flags);
+ void updateBoundingRect();
+
+ bool sourceIsPixmap() const;
+ QRectF sourceBoundingRect(Qt::CoordinateSystem system = Qt::LogicalCoordinates) const;
+ void drawSource(QPainter *painter);
+ QPixmap sourcePixmap(Qt::CoordinateSystem system = Qt::LogicalCoordinates,
+ QPoint *offset = 0,
+ PixmapPadMode mode = PadToEffectiveBoundingRect) const;
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsEffect)
+ Q_DISABLE_COPY(QGraphicsEffect)
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+ friend class QGraphicsScenePrivate;
+ friend class QWidget;
+ friend class QWidgetPrivate;
+
+public:
+ QGraphicsEffectSource *source() const; // internal
+
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsEffect::ChangeFlags)
+
+class QGraphicsColorizeEffectPrivate;
+class Q_GUI_EXPORT QGraphicsColorizeEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
+public:
+ QGraphicsColorizeEffect(QObject *parent = 0);
+ ~QGraphicsColorizeEffect();
+
+ QColor color() const;
+ qreal strength() const;
+
+public Q_SLOTS:
+ void setColor(const QColor &c);
+ void setStrength(qreal strength);
+
+Q_SIGNALS:
+ void colorChanged(const QColor &color);
+ void strengthChanged(qreal strength);
+
+protected:
+ void draw(QPainter *painter);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsColorizeEffect)
+ Q_DISABLE_COPY(QGraphicsColorizeEffect)
+};
+
+class QGraphicsBlurEffectPrivate;
+class Q_GUI_EXPORT QGraphicsBlurEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+ Q_FLAGS(BlurHint BlurHints)
+ Q_PROPERTY(qreal blurRadius READ blurRadius WRITE setBlurRadius NOTIFY blurRadiusChanged)
+ Q_PROPERTY(BlurHints blurHints READ blurHints WRITE setBlurHints NOTIFY blurHintsChanged)
+public:
+ enum BlurHint {
+ PerformanceHint = 0x00,
+ QualityHint = 0x01,
+ AnimationHint = 0x02
+ };
+ Q_DECLARE_FLAGS(BlurHints, BlurHint)
+
+ QGraphicsBlurEffect(QObject *parent = 0);
+ ~QGraphicsBlurEffect();
+
+ QRectF boundingRectFor(const QRectF &rect) const;
+ qreal blurRadius() const;
+ BlurHints blurHints() const;
+
+public Q_SLOTS:
+ void setBlurRadius(qreal blurRadius);
+ void setBlurHints(BlurHints hints);
+
+Q_SIGNALS:
+ void blurRadiusChanged(qreal blurRadius);
+ void blurHintsChanged(BlurHints hints);
+
+protected:
+ void draw(QPainter *painter);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsBlurEffect)
+ Q_DISABLE_COPY(QGraphicsBlurEffect)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsBlurEffect::BlurHints)
+
+class QGraphicsDropShadowEffectPrivate;
+class Q_GUI_EXPORT QGraphicsDropShadowEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+ Q_PROPERTY(QPointF offset READ offset WRITE setOffset NOTIFY offsetChanged)
+ Q_PROPERTY(qreal xOffset READ xOffset WRITE setXOffset NOTIFY offsetChanged)
+ Q_PROPERTY(qreal yOffset READ yOffset WRITE setYOffset NOTIFY offsetChanged)
+ Q_PROPERTY(qreal blurRadius READ blurRadius WRITE setBlurRadius NOTIFY blurRadiusChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+public:
+ QGraphicsDropShadowEffect(QObject *parent = 0);
+ ~QGraphicsDropShadowEffect();
+
+ QRectF boundingRectFor(const QRectF &rect) const;
+ QPointF offset() const;
+
+ inline qreal xOffset() const
+ { return offset().x(); }
+
+ inline qreal yOffset() const
+ { return offset().y(); }
+
+ qreal blurRadius() const;
+ QColor color() const;
+
+public Q_SLOTS:
+ 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)); }
+
+ inline void setXOffset(qreal dx)
+ { setOffset(QPointF(dx, yOffset())); }
+
+ inline void setYOffset(qreal dy)
+ { setOffset(QPointF(xOffset(), dy)); }
+
+ void setBlurRadius(qreal blurRadius);
+ void setColor(const QColor &color);
+
+Q_SIGNALS:
+ void offsetChanged(const QPointF &offset);
+ void blurRadiusChanged(qreal blurRadius);
+ void colorChanged(const QColor &color);
+
+protected:
+ void draw(QPainter *painter);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsDropShadowEffect)
+ Q_DISABLE_COPY(QGraphicsDropShadowEffect)
+};
+
+class QGraphicsOpacityEffectPrivate;
+class Q_GUI_EXPORT QGraphicsOpacityEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged)
+ Q_PROPERTY(QBrush opacityMask READ opacityMask WRITE setOpacityMask NOTIFY opacityMaskChanged)
+public:
+ QGraphicsOpacityEffect(QObject *parent = 0);
+ ~QGraphicsOpacityEffect();
+
+ qreal opacity() const;
+ QBrush opacityMask() const;
+
+public Q_SLOTS:
+ void setOpacity(qreal opacity);
+ void setOpacityMask(const QBrush &mask);
+
+Q_SIGNALS:
+ void opacityChanged(qreal opacity);
+ void opacityMaskChanged(const QBrush &mask);
+
+protected:
+ void draw(QPainter *painter);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsOpacityEffect)
+ Q_DISABLE_COPY(QGraphicsOpacityEffect)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif //QT_NO_GRAPHICSEFFECT
+
+#endif // QGRAPHICSEFFECT_H
+
diff --git a/src/widgets/effects/qgraphicseffect_p.h b/src/widgets/effects/qgraphicseffect_p.h
new file mode 100644
index 0000000000..cd1ae38ff8
--- /dev/null
+++ b/src/widgets/effects/qgraphicseffect_p.h
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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"
+
+#include <QPixmapCache>
+
+#include <private/qobject_p.h>
+#include <private/qpixmapfilter_p.h>
+
+#ifndef QT_NO_GRAPHICSEFFECT
+QT_BEGIN_NAMESPACE
+
+class QGraphicsEffectSourcePrivate;
+class Q_GUI_EXPORT QGraphicsEffectSource : public QObject
+{
+ Q_OBJECT
+public:
+ ~QGraphicsEffectSource();
+ const QGraphicsItem *graphicsItem() const;
+ const QWidget *widget() 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,
+ QGraphicsEffect::PixmapPadMode mode = QGraphicsEffect::PadToEffectiveBoundingRect) 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;
+ friend class QGraphicsItemPrivate;
+ friend class QWidget;
+ friend class QWidgetPrivate;
+};
+
+class QGraphicsEffectSourcePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsEffectSource)
+public:
+ QGraphicsEffectSourcePrivate()
+ : QObjectPrivate()
+ , m_cachedSystem(Qt::DeviceCoordinates)
+ , m_cachedMode(QGraphicsEffect::PadToTransparentBorder)
+ {}
+
+ enum InvalidateReason
+ {
+ TransformChanged,
+ EffectRectChanged,
+ SourceChanged
+ };
+
+ 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 QWidget *widget() 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,
+ QGraphicsEffect::PixmapPadMode mode = QGraphicsEffect::PadToTransparentBorder) const = 0;
+ virtual void effectBoundingRectChanged() = 0;
+
+ void setCachedOffset(const QPoint &offset);
+ void invalidateCache(InvalidateReason reason = SourceChanged) const;
+ Qt::CoordinateSystem currentCachedSystem() const { return m_cachedSystem; }
+ QGraphicsEffect::PixmapPadMode currentCachedMode() const { return m_cachedMode; }
+
+ friend class QGraphicsScenePrivate;
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+
+private:
+ mutable Qt::CoordinateSystem m_cachedSystem;
+ mutable QGraphicsEffect::PixmapPadMode m_cachedMode;
+ mutable QPoint m_cachedOffset;
+ mutable QPixmapCache::Key m_cacheKey;
+};
+
+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()->invalidateCache();
+ 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 QGraphicsColorizeEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsColorizeEffect)
+public:
+ QGraphicsColorizeEffectPrivate()
+ : opaque(true)
+ {
+ filter = new QPixmapColorizeFilter;
+ }
+ ~QGraphicsColorizeEffectPrivate() { delete filter; }
+
+ QPixmapColorizeFilter *filter;
+ quint32 opaque : 1;
+ quint32 padding : 31;
+};
+
+class QGraphicsBlurEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsBlurEffect)
+public:
+ QGraphicsBlurEffectPrivate() : filter(new QPixmapBlurFilter) {}
+ ~QGraphicsBlurEffectPrivate() { delete filter; }
+
+ QPixmapBlurFilter *filter;
+};
+
+class QGraphicsDropShadowEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsDropShadowEffect)
+public:
+ QGraphicsDropShadowEffectPrivate() : filter(new QPixmapDropShadowFilter) {}
+ ~QGraphicsDropShadowEffectPrivate() { delete filter; }
+
+ QPixmapDropShadowFilter *filter;
+};
+
+class QGraphicsOpacityEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsOpacityEffect)
+public:
+ QGraphicsOpacityEffectPrivate()
+ : opacity(qreal(0.7)), isFullyTransparent(0), isFullyOpaque(0), hasOpacityMask(0) {}
+ ~QGraphicsOpacityEffectPrivate() {}
+
+ qreal opacity;
+ QBrush opacityMask;
+ uint isFullyTransparent : 1;
+ uint isFullyOpaque : 1;
+ uint hasOpacityMask : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSEFFECT
+#endif // QGRAPHICSEFFECT_P_H
+
diff --git a/src/widgets/effects/qpixmapfilter.cpp b/src/widgets/effects/qpixmapfilter.cpp
new file mode 100644
index 0000000000..ecab3d7a41
--- /dev/null
+++ b/src/widgets/effects/qpixmapfilter.cpp
@@ -0,0 +1,1381 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qglobal.h>
+
+#include <QDebug>
+
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qpixmapfilter_p.h"
+#include "qvarlengtharray.h"
+
+#include "private/qguiapplication_p.h"
+#include "private/qpaintengineex_p.h"
+#include "private/qpaintengine_raster_p.h"
+#include "qmath.h"
+#include "private/qmath_p.h"
+#include "private/qmemrotate_p.h"
+#include "private/qdrawhelper_p.h"
+
+#ifndef QT_NO_GRAPHICSEFFECT
+QT_BEGIN_NAMESPACE
+
+class QPixmapFilterPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QPixmapFilter)
+public:
+ QPixmapFilter::FilterType type;
+};
+
+/*!
+ \class QPixmapFilter
+ \since 4.5
+ \ingroup painting
+
+ \brief The QPixmapFilter class provides the basic functionality for
+ pixmap filter classes. Pixmap filter can be for example colorize or blur.
+
+ QPixmapFilter is the base class for every pixmap filter. QPixmapFilter is
+ an abstract class and cannot itself be instantiated. It provides a standard
+ interface for filter processing.
+
+ \internal
+*/
+
+/*!
+ \enum QPixmapFilter::FilterType
+
+ \internal
+
+ This enum describes the types of filter that can be applied to pixmaps.
+
+ \value ConvolutionFilter A filter that is used to calculate the convolution
+ of the image with a kernel. See
+ QPixmapConvolutionFilter for more information.
+ \value ColorizeFilter A filter that is used to change the overall color
+ of an image. See QPixmapColorizeFilter for more
+ information.
+ \value DropShadowFilter A filter that is used to add a drop shadow to an
+ image. See QPixmapDropShadowFilter for more
+ information.
+ \value BlurFilter A filter that is used to blur an image using
+ a simple blur radius. See QPixmapBlurFilter
+ for more information.
+
+ \value UserFilter The first filter type that can be used for
+ application-specific purposes.
+*/
+
+
+/*!
+ Constructs a default QPixmapFilter with the given \a type.
+
+ This constructor should be used when subclassing QPixmapFilter to
+ create custom user filters.
+
+ \internal
+*/
+QPixmapFilter::QPixmapFilter(FilterType type, QObject *parent)
+ : QObject(*new QPixmapFilterPrivate, parent)
+{
+ d_func()->type = type;
+}
+
+
+
+/*!
+ \internal
+*/
+QPixmapFilter::QPixmapFilter(QPixmapFilterPrivate&d, QPixmapFilter::FilterType type, QObject *parent)
+ : QObject(d, parent)
+{
+ d_func()->type = type;
+}
+
+
+/*!
+ Destroys the pixmap filter.
+
+ \internal
+*/
+QPixmapFilter::~QPixmapFilter()
+{
+}
+
+/*!
+ Returns the type of the filter. All standard pixmap filter classes
+ are associated with a unique value.
+
+ \internal
+*/
+QPixmapFilter::FilterType QPixmapFilter::type() const
+{
+ Q_D(const QPixmapFilter);
+ return d->type;
+}
+
+/*!
+ Returns the bounding rectangle that is affected by the pixmap
+ filter if the filter is applied to the specified \a rect.
+
+ \internal
+*/
+QRectF QPixmapFilter::boundingRectFor(const QRectF &rect) const
+{
+ return rect;
+}
+
+/*!
+ \fn void QPixmapFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF& srcRect) const
+
+ Uses \a painter to draw filtered result of \a src at the point
+ specified by \a p. If \a srcRect is specified the it will
+ be used as a source rectangle to only draw a part of the source.
+
+ draw() will affect the area which boundingRectFor() returns.
+
+ \internal
+*/
+
+/*!
+ \class QPixmapConvolutionFilter
+ \since 4.5
+ \ingroup painting
+
+ \brief The QPixmapConvolutionFilter class provides convolution
+ filtering for pixmaps.
+
+ QPixmapConvolutionFilter implements a convolution pixmap filter,
+ which is applied when \l{QPixmapFilter::}{draw()} is called. A
+ convolution filter lets you distort an image by setting the values
+ of a matrix of qreal values called its
+ \l{setConvolutionKernel()}{kernel}. The matrix's values are
+ usually between -1.0 and 1.0.
+
+ \omit
+ In convolution filtering, the pixel value is calculated from the
+ neighboring pixels based on the weighting convolution kernel.
+ This needs explaining to be useful.
+ \endomit
+
+ Example:
+ \snippet doc/src/snippets/code/src_gui_image_qpixmapfilter.cpp 1
+
+ \sa {Pixmap Filters Example}, QPixmapColorizeFilter, QPixmapDropShadowFilter
+
+
+ \internal
+*/
+
+class QPixmapConvolutionFilterPrivate : public QPixmapFilterPrivate
+{
+public:
+ QPixmapConvolutionFilterPrivate(): convolutionKernel(0), kernelWidth(0), kernelHeight(0), convoluteAlpha(false) {}
+ ~QPixmapConvolutionFilterPrivate() {
+ delete[] convolutionKernel;
+ }
+
+ qreal *convolutionKernel;
+ int kernelWidth;
+ int kernelHeight;
+ bool convoluteAlpha;
+};
+
+
+/*!
+ Constructs a pixmap convolution filter.
+
+ By default there is no convolution kernel.
+
+ \internal
+*/
+QPixmapConvolutionFilter::QPixmapConvolutionFilter(QObject *parent)
+ : QPixmapFilter(*new QPixmapConvolutionFilterPrivate, ConvolutionFilter, parent)
+{
+ Q_D(QPixmapConvolutionFilter);
+ d->convoluteAlpha = true;
+}
+
+/*!
+ Destructor of pixmap convolution filter.
+
+ \internal
+*/
+QPixmapConvolutionFilter::~QPixmapConvolutionFilter()
+{
+}
+
+/*!
+ Sets convolution kernel with the given number of \a rows and \a columns.
+ Values from \a kernel are copied to internal data structure.
+
+ To preserve the intensity of the pixmap, the sum of all the
+ values in the convolution kernel should add up to 1.0. A sum
+ greater than 1.0 produces a lighter result and a sum less than 1.0
+ produces a darker and transparent result.
+
+ \internal
+*/
+void QPixmapConvolutionFilter::setConvolutionKernel(const qreal *kernel, int rows, int columns)
+{
+ Q_D(QPixmapConvolutionFilter);
+ delete [] d->convolutionKernel;
+ d->convolutionKernel = new qreal[rows * columns];
+ memcpy(d->convolutionKernel, kernel, sizeof(qreal) * rows * columns);
+ d->kernelWidth = columns;
+ d->kernelHeight = rows;
+}
+
+/*!
+ Gets the convolution kernel data.
+
+ \internal
+*/
+const qreal *QPixmapConvolutionFilter::convolutionKernel() const
+{
+ Q_D(const QPixmapConvolutionFilter);
+ return d->convolutionKernel;
+}
+
+/*!
+ Gets the number of rows in the convolution kernel.
+
+ \internal
+*/
+int QPixmapConvolutionFilter::rows() const
+{
+ Q_D(const QPixmapConvolutionFilter);
+ return d->kernelHeight;
+}
+
+/*!
+ Gets the number of columns in the convolution kernel.
+
+ \internal
+*/
+int QPixmapConvolutionFilter::columns() const
+{
+ Q_D(const QPixmapConvolutionFilter);
+ return d->kernelWidth;
+}
+
+
+/*!
+ \internal
+*/
+QRectF QPixmapConvolutionFilter::boundingRectFor(const QRectF &rect) const
+{
+ Q_D(const QPixmapConvolutionFilter);
+ return rect.adjusted(-d->kernelWidth / 2, -d->kernelHeight / 2, (d->kernelWidth - 1) / 2, (d->kernelHeight - 1) / 2);
+}
+
+// Convolutes the image
+static void convolute(
+ QImage *destImage,
+ const QPointF &pos,
+ const QImage &srcImage,
+ const QRectF &srcRect,
+ QPainter::CompositionMode mode,
+ qreal *kernel,
+ int kernelWidth,
+ int kernelHeight )
+{
+ const QImage processImage = (srcImage.format() != QImage::Format_ARGB32_Premultiplied ) ? srcImage.convertToFormat(QImage::Format_ARGB32_Premultiplied) : srcImage;
+ // TODO: support also other formats directly without copying
+
+ int *fixedKernel = new int[kernelWidth*kernelHeight];
+ for(int i = 0; i < kernelWidth*kernelHeight; i++)
+ {
+ fixedKernel[i] = (int)(65536 * kernel[i]);
+ }
+ QRectF trect = srcRect.isNull() ? processImage.rect() : srcRect;
+ trect.moveTo(pos);
+ QRectF bounded = trect.adjusted(-kernelWidth / 2, -kernelHeight / 2, (kernelWidth - 1) / 2, (kernelHeight - 1) / 2);
+ QRect rect = bounded.toAlignedRect();
+ QRect targetRect = rect.intersected(destImage->rect());
+
+ QRectF srect = srcRect.isNull() ? processImage.rect() : srcRect;
+ QRectF sbounded = srect.adjusted(-kernelWidth / 2, -kernelHeight / 2, (kernelWidth - 1) / 2, (kernelHeight - 1) / 2);
+ QPoint srcStartPoint = sbounded.toAlignedRect().topLeft()+(targetRect.topLeft()-rect.topLeft());
+
+ const uint *sourceStart = (uint*)processImage.scanLine(0);
+ uint *outputStart = (uint*)destImage->scanLine(0);
+
+ int yk = srcStartPoint.y();
+ for (int y = targetRect.top(); y <= targetRect.bottom(); y++) {
+ uint* output = outputStart + (destImage->bytesPerLine()/sizeof(uint))*y+targetRect.left();
+ int xk = srcStartPoint.x();
+ for(int x = targetRect.left(); x <= targetRect.right(); x++) {
+ int r = 0;
+ int g = 0;
+ int b = 0;
+ int a = 0;
+
+ // some out of bounds pre-checking to avoid inner-loop ifs
+ int kernely = -kernelHeight/2;
+ int starty = 0;
+ int endy = kernelHeight;
+ if(yk+kernely+endy >= srcImage.height())
+ endy = kernelHeight-((yk+kernely+endy)-srcImage.height())-1;
+ if(yk+kernely < 0)
+ starty = -(yk+kernely);
+
+ int kernelx = -kernelWidth/2;
+ int startx = 0;
+ int endx = kernelWidth;
+ if(xk+kernelx+endx >= srcImage.width())
+ endx = kernelWidth-((xk+kernelx+endx)-srcImage.width())-1;
+ if(xk+kernelx < 0)
+ startx = -(xk+kernelx);
+
+ for (int ys = starty; ys < endy; ys ++) {
+ const uint *pix = sourceStart + (processImage.bytesPerLine()/sizeof(uint))*(yk+kernely+ys) + ((xk+kernelx+startx));
+ const uint *endPix = pix+endx-startx;
+ int kernelPos = ys*kernelWidth+startx;
+ while (pix < endPix) {
+ int factor = fixedKernel[kernelPos++];
+ a += (((*pix) & 0xff000000)>>24) * factor;
+ r += (((*pix) & 0x00ff0000)>>16) * factor;
+ g += (((*pix) & 0x0000ff00)>>8 ) * factor;
+ b += (((*pix) & 0x000000ff) ) * factor;
+ pix++;
+ }
+ }
+
+ r = qBound((int)0, r >> 16, (int)255);
+ g = qBound((int)0, g >> 16, (int)255);
+ b = qBound((int)0, b >> 16, (int)255);
+ a = qBound((int)0, a >> 16, (int)255);
+ // composition mode checking could be moved outside of loop
+ if(mode == QPainter::CompositionMode_Source) {
+ uint color = (a<<24)+(r<<16)+(g<<8)+b;
+ *output++ = color;
+ } else {
+ uint current = *output;
+ uchar ca = (current&0xff000000)>>24;
+ uchar cr = (current&0x00ff0000)>>16;
+ uchar cg = (current&0x0000ff00)>>8;
+ uchar cb = (current&0x000000ff);
+ uint color =
+ (((ca*(255-a) >> 8)+a) << 24)+
+ (((cr*(255-a) >> 8)+r) << 16)+
+ (((cg*(255-a) >> 8)+g) << 8)+
+ (((cb*(255-a) >> 8)+b));
+ *output++ = color;;
+ }
+ xk++;
+ }
+ yk++;
+ }
+ delete[] fixedKernel;
+}
+
+/*!
+ \internal
+*/
+void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF& srcRect) const
+{
+ Q_D(const QPixmapConvolutionFilter);
+ if (!painter->isActive())
+ return;
+
+ if(d->kernelWidth<=0 || d->kernelHeight <= 0)
+ return;
+
+ if (src.isNull())
+ return;
+
+ QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
+ static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0;
+ QPixmapConvolutionFilter *convolutionFilter = static_cast<QPixmapConvolutionFilter*>(filter);
+ if (convolutionFilter) {
+ convolutionFilter->setConvolutionKernel(d->convolutionKernel, d->kernelWidth, d->kernelHeight);
+ convolutionFilter->d_func()->convoluteAlpha = d->convoluteAlpha;
+ convolutionFilter->draw(painter, p, src, srcRect);
+ return;
+ }
+
+ // falling back to raster implementation
+
+ QImage *target = 0;
+ if (painter->paintEngine()->paintDevice()->devType() == QInternal::Image) {
+ target = static_cast<QImage *>(painter->paintEngine()->paintDevice());
+
+ QTransform mat = painter->combinedTransform();
+
+ if (mat.type() > QTransform::TxTranslate) {
+ // Disabled because of transformation...
+ target = 0;
+ } else {
+ QRasterPaintEngine *pe = static_cast<QRasterPaintEngine *>(painter->paintEngine());
+ if (pe->clipType() == QRasterPaintEngine::ComplexClip)
+ // disabled because of complex clipping...
+ target = 0;
+ else {
+ QRectF clip = pe->clipBoundingRect();
+ QRectF rect = boundingRectFor(srcRect.isEmpty() ? src.rect() : srcRect);
+ QTransform x = painter->deviceTransform();
+ if (!clip.contains(rect.translated(x.dx() + p.x(), x.dy() + p.y()))) {
+ target = 0;
+ }
+
+ }
+ }
+ }
+
+ if (target) {
+ QTransform x = painter->deviceTransform();
+ QPointF offset(x.dx(), x.dy());
+
+ convolute(target, p+offset, src.toImage(), srcRect, QPainter::CompositionMode_SourceOver, d->convolutionKernel, d->kernelWidth, d->kernelHeight);
+ } else {
+ QRect srect = srcRect.isNull() ? src.rect() : srcRect.toRect();
+ QRect rect = boundingRectFor(srect).toRect();
+ QImage result = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
+ QPoint offset = srect.topLeft() - rect.topLeft();
+ convolute(&result,
+ offset,
+ src.toImage(),
+ srect,
+ QPainter::CompositionMode_Source,
+ d->convolutionKernel,
+ d->kernelWidth,
+ d->kernelHeight);
+ painter->drawImage(p - offset, result);
+ }
+}
+
+/*!
+ \class QPixmapBlurFilter
+ \since 4.6
+ \ingroup multimedia
+
+ \brief The QPixmapBlurFilter class provides blur filtering
+ for pixmaps.
+
+ QPixmapBlurFilter implements a blur pixmap filter,
+ which is applied when \l{QPixmapFilter::}{draw()} is called.
+
+ The filter lets you specialize the radius of the blur as well
+ as hints as to whether to prefer performance or quality.
+
+ By default, the blur effect is produced by applying an exponential
+ filter generated from the specified blurRadius(). Paint engines
+ may override this with a custom blur that is faster on the
+ underlying hardware.
+
+ \sa {Pixmap Filters Example}, QPixmapConvolutionFilter, QPixmapDropShadowFilter
+
+ \internal
+*/
+
+class QPixmapBlurFilterPrivate : public QPixmapFilterPrivate
+{
+public:
+ QPixmapBlurFilterPrivate() : radius(5), hints(QGraphicsBlurEffect::PerformanceHint) {}
+
+ qreal radius;
+ QGraphicsBlurEffect::BlurHints hints;
+};
+
+
+/*!
+ Constructs a pixmap blur filter.
+
+ \internal
+*/
+QPixmapBlurFilter::QPixmapBlurFilter(QObject *parent)
+ : QPixmapFilter(*new QPixmapBlurFilterPrivate, BlurFilter, parent)
+{
+}
+
+/*!
+ Destructor of pixmap blur filter.
+
+ \internal
+*/
+QPixmapBlurFilter::~QPixmapBlurFilter()
+{
+}
+
+/*!
+ Sets the radius of the blur filter. Higher radius produces increased blurriness.
+
+ \internal
+*/
+void QPixmapBlurFilter::setRadius(qreal radius)
+{
+ Q_D(QPixmapBlurFilter);
+ d->radius = radius;
+}
+
+/*!
+ Gets the radius of the blur filter.
+
+ \internal
+*/
+qreal QPixmapBlurFilter::radius() const
+{
+ Q_D(const QPixmapBlurFilter);
+ return d->radius;
+}
+
+/*!
+ Setting the blur hints to PerformanceHint causes the implementation
+ to trade off visual quality to blur the image faster. Setting the
+ blur hints to QualityHint causes the implementation to improve
+ visual quality at the expense of speed.
+
+ AnimationHint causes the implementation to optimize for animating
+ the blur radius, possibly by caching blurred versions of the source
+ pixmap.
+
+ The implementation is free to ignore this value if it only has a single
+ blur algorithm.
+
+ \internal
+*/
+void QPixmapBlurFilter::setBlurHints(QGraphicsBlurEffect::BlurHints hints)
+{
+ Q_D(QPixmapBlurFilter);
+ d->hints = hints;
+}
+
+/*!
+ Gets the blur hints of the blur filter.
+
+ \internal
+*/
+QGraphicsBlurEffect::BlurHints QPixmapBlurFilter::blurHints() const
+{
+ Q_D(const QPixmapBlurFilter);
+ return d->hints;
+}
+
+const qreal radiusScale = qreal(2.5);
+
+/*!
+ \internal
+*/
+QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const
+{
+ Q_D(const QPixmapBlurFilter);
+ const qreal delta = radiusScale * d->radius + 1;
+ return rect.adjusted(-delta, -delta, delta, delta);
+}
+
+template <int shift>
+inline int qt_static_shift(int value)
+{
+ if (shift == 0)
+ return value;
+ else if (shift > 0)
+ return value << (uint(shift) & 0x1f);
+ else
+ return value >> (uint(-shift) & 0x1f);
+}
+
+template<int aprec, int zprec>
+inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
+{
+ QRgb *pixel = (QRgb *)bptr;
+
+#define Z_MASK (0xff << zprec)
+ const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK;
+ const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK;
+ const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK;
+ const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK;
+#undef Z_MASK
+
+ const int zR_zprec = zR >> aprec;
+ const int zG_zprec = zG >> aprec;
+ const int zB_zprec = zB >> aprec;
+ const int zA_zprec = zA >> aprec;
+
+ zR += alpha * (R_zprec - zR_zprec);
+ zG += alpha * (G_zprec - zG_zprec);
+ zB += alpha * (B_zprec - zB_zprec);
+ zA += alpha * (A_zprec - zA_zprec);
+
+#define ZA_MASK (0xff << (zprec + aprec))
+ *pixel =
+ qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
+ | qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
+ | qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
+ | qt_static_shift<-zprec - aprec>(zB & ZA_MASK);
+#undef ZA_MASK
+}
+
+const int alphaIndex = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
+
+template<int aprec, int zprec>
+inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, int alpha)
+{
+ const int A_zprec = int(*(bptr)) << zprec;
+ const int z_zprec = z >> aprec;
+ z += alpha * (A_zprec - z_zprec);
+ *(bptr) = z >> (zprec + aprec);
+}
+
+template<int aprec, int zprec, bool alphaOnly>
+inline void qt_blurrow(QImage & im, int line, int alpha)
+{
+ uchar *bptr = im.scanLine(line);
+
+ int zR = 0, zG = 0, zB = 0, zA = 0;
+
+ if (alphaOnly && im.format() != QImage::Format_Indexed8)
+ bptr += alphaIndex;
+
+ const int stride = im.depth() >> 3;
+ const int im_width = im.width();
+ for (int index = 0; index < im_width; ++index) {
+ if (alphaOnly)
+ qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
+ else
+ qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
+ bptr += stride;
+ }
+
+ bptr -= stride;
+
+ for (int index = im_width - 2; index >= 0; --index) {
+ bptr -= stride;
+ if (alphaOnly)
+ qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
+ else
+ qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
+ }
+}
+
+/*
+* expblur(QImage &img, int radius)
+*
+* Based on exponential blur algorithm by Jani Huhtanen
+*
+* In-place blur of image 'img' with kernel
+* of approximate radius 'radius'.
+*
+* Blurs with two sided exponential impulse
+* response.
+*
+* aprec = precision of alpha parameter
+* in fixed-point format 0.aprec
+*
+* zprec = precision of state parameters
+* zR,zG,zB and zA in fp format 8.zprec
+*/
+template <int aprec, int zprec, bool alphaOnly>
+void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transposed = 0)
+{
+ // halve the radius if we're using two passes
+ if (improvedQuality)
+ radius *= qreal(0.5);
+
+ Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied
+ || img.format() == QImage::Format_RGB32
+ || img.format() == QImage::Format_Indexed8);
+
+ // choose the alpha such that pixels at radius distance from a fully
+ // saturated pixel will have an alpha component of no greater than
+ // the cutOffIntensity
+ const qreal cutOffIntensity = 2;
+ int alpha = radius <= qreal(1e-5)
+ ? ((1 << aprec)-1)
+ : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius)));
+
+ int img_height = img.height();
+ for (int row = 0; row < img_height; ++row) {
+ for (int i = 0; i <= int(improvedQuality); ++i)
+ qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
+ }
+
+ QImage temp(img.height(), img.width(), img.format());
+ if (transposed >= 0) {
+ if (img.depth() == 8) {
+ qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint8*>(temp.bits()),
+ temp.bytesPerLine());
+ } else {
+ qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint32*>(temp.bits()),
+ temp.bytesPerLine());
+ }
+ } else {
+ if (img.depth() == 8) {
+ qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint8*>(temp.bits()),
+ temp.bytesPerLine());
+ } else {
+ qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint32*>(temp.bits()),
+ temp.bytesPerLine());
+ }
+ }
+
+ img_height = temp.height();
+ for (int row = 0; row < img_height; ++row) {
+ for (int i = 0; i <= int(improvedQuality); ++i)
+ qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
+ }
+
+ if (transposed == 0) {
+ if (img.depth() == 8) {
+ qt_memrotate90(reinterpret_cast<const quint8*>(temp.bits()),
+ temp.width(), temp.height(), temp.bytesPerLine(),
+ reinterpret_cast<quint8*>(img.bits()),
+ img.bytesPerLine());
+ } else {
+ qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()),
+ temp.width(), temp.height(), temp.bytesPerLine(),
+ reinterpret_cast<quint32*>(img.bits()),
+ img.bytesPerLine());
+ }
+ } else {
+ img = temp;
+ }
+}
+#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
+#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
+
+Q_GUI_EXPORT QImage qt_halfScaled(const QImage &source)
+{
+ if (source.width() < 2 || source.height() < 2)
+ return QImage();
+
+ QImage srcImage = source;
+
+ if (source.format() == QImage::Format_Indexed8) {
+ // assumes grayscale
+ QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
+
+ const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
+ int sx = srcImage.bytesPerLine();
+ int sx2 = sx << 1;
+
+ uchar *dst = reinterpret_cast<uchar*>(dest.bits());
+ int dx = dest.bytesPerLine();
+ int ww = dest.width();
+ int hh = dest.height();
+
+ for (int y = hh; y; --y, dst += dx, src += sx2) {
+ const uchar *p1 = src;
+ const uchar *p2 = src + sx;
+ uchar *q = dst;
+ for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2)
+ *q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2;
+ }
+
+ return dest;
+ } else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
+ QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
+
+ const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
+ int sx = srcImage.bytesPerLine();
+ int sx2 = sx << 1;
+
+ uchar *dst = reinterpret_cast<uchar*>(dest.bits());
+ int dx = dest.bytesPerLine();
+ int ww = dest.width();
+ int hh = dest.height();
+
+ for (int y = hh; y; --y, dst += dx, src += sx2) {
+ const uchar *p1 = src;
+ const uchar *p2 = src + sx;
+ uchar *q = dst;
+ for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
+ // alpha
+ q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
+ // rgb
+ const quint16 p16_1 = (p1[2] << 8) | p1[1];
+ const quint16 p16_2 = (p1[5] << 8) | p1[4];
+ const quint16 p16_3 = (p2[2] << 8) | p2[1];
+ const quint16 p16_4 = (p2[5] << 8) | p2[4];
+ const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
+ q[1] = result & 0xff;
+ q[2] = result >> 8;
+ }
+ }
+
+ return dest;
+ } else if (source.format() != QImage::Format_ARGB32_Premultiplied
+ && source.format() != QImage::Format_RGB32)
+ {
+ srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ }
+
+ QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
+
+ const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits());
+ int sx = srcImage.bytesPerLine() >> 2;
+ int sx2 = sx << 1;
+
+ quint32 *dst = reinterpret_cast<quint32*>(dest.bits());
+ int dx = dest.bytesPerLine() >> 2;
+ int ww = dest.width();
+ int hh = dest.height();
+
+ for (int y = hh; y; --y, dst += dx, src += sx2) {
+ const quint32 *p1 = src;
+ const quint32 *p2 = src + sx;
+ quint32 *q = dst;
+ for (int x = ww; x; --x, q++, p1 += 2, p2 += 2)
+ *q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
+ }
+
+ return dest;
+}
+
+Q_GUI_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0)
+{
+ if (blurImage.format() != QImage::Format_ARGB32_Premultiplied
+ && blurImage.format() != QImage::Format_RGB32)
+ {
+ blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ }
+
+ qreal scale = 1;
+ if (radius >= 4 && blurImage.width() >= 2 && blurImage.height() >= 2) {
+ blurImage = qt_halfScaled(blurImage);
+ scale = 2;
+ radius *= qreal(0.5);
+ }
+
+ if (alphaOnly)
+ expblur<12, 10, true>(blurImage, radius, quality, transposed);
+ else
+ expblur<12, 10, false>(blurImage, radius, quality, transposed);
+
+ if (p) {
+ p->scale(scale, scale);
+ p->setRenderHint(QPainter::SmoothPixmapTransform);
+ p->drawImage(QRect(0, 0, blurImage.width(), blurImage.height()), blurImage);
+ }
+}
+
+Q_GUI_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0)
+{
+ if (blurImage.format() == QImage::Format_Indexed8)
+ expblur<12, 10, true>(blurImage, radius, quality, transposed);
+ else
+ expblur<12, 10, false>(blurImage, radius, quality, transposed);
+}
+
+Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
+
+/*!
+ \internal
+*/
+void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &rect) const
+{
+ Q_D(const QPixmapBlurFilter);
+ if (!painter->isActive())
+ return;
+
+ if (src.isNull())
+ return;
+
+ QRectF srcRect = rect;
+ if (srcRect.isNull())
+ srcRect = src.rect();
+
+ if (d->radius <= 1) {
+ painter->drawPixmap(srcRect.translated(p), src, srcRect);
+ return;
+ }
+
+ qreal scaledRadius = radiusScale * d->radius;
+ qreal scale;
+ if (qt_scaleForTransform(painter->transform(), &scale))
+ scaledRadius /= scale;
+
+ QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
+ static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0;
+ QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter);
+ if (blurFilter) {
+ blurFilter->setRadius(scaledRadius);
+ blurFilter->setBlurHints(d->hints);
+ blurFilter->draw(painter, p, src, srcRect);
+ return;
+ }
+
+ QImage srcImage;
+ QImage destImage;
+
+ if (srcRect == src.rect()) {
+ srcImage = src.toImage();
+ } else {
+ QRect rect = srcRect.toAlignedRect().intersected(src.rect());
+ srcImage = src.copy(rect).toImage();
+ }
+
+ QTransform transform = painter->worldTransform();
+ painter->translate(p);
+ qt_blurImage(painter, srcImage, scaledRadius, (d->hints & QGraphicsBlurEffect::QualityHint), false);
+ painter->setWorldTransform(transform);
+}
+
+// grayscales the image to dest (could be same). If rect isn't defined
+// destination image size is used to determine the dimension of grayscaling
+// process.
+static void grayscale(const QImage &image, QImage &dest, const QRect& rect = QRect())
+{
+ QRect destRect = rect;
+ QRect srcRect = rect;
+ if (rect.isNull()) {
+ srcRect = dest.rect();
+ destRect = dest.rect();
+ }
+ if (&image != &dest) {
+ destRect.moveTo(QPoint(0, 0));
+ }
+
+ unsigned int *data = (unsigned int *)image.bits();
+ unsigned int *outData = (unsigned int *)dest.bits();
+
+ if (dest.size() == image.size() && image.rect() == srcRect) {
+ // a bit faster loop for grayscaling everything
+ int pixels = dest.width() * dest.height();
+ for (int i = 0; i < pixels; ++i) {
+ int val = qGray(data[i]);
+ outData[i] = qRgba(val, val, val, qAlpha(data[i]));
+ }
+ } else {
+ int yd = destRect.top();
+ for (int y = srcRect.top(); y <= srcRect.bottom() && y < image.height(); y++) {
+ data = (unsigned int*)image.scanLine(y);
+ outData = (unsigned int*)dest.scanLine(yd++);
+ int xd = destRect.left();
+ for (int x = srcRect.left(); x <= srcRect.right() && x < image.width(); x++) {
+ int val = qGray(data[x]);
+ outData[xd++] = qRgba(val, val, val, qAlpha(data[x]));
+ }
+ }
+ }
+}
+
+/*!
+ \class QPixmapColorizeFilter
+ \since 4.5
+ \ingroup painting
+
+ \brief The QPixmapColorizeFilter class provides colorizing
+ filtering for pixmaps.
+
+ A colorize filter gives the pixmap a tint of its color(). The
+ filter first grayscales the pixmap and then converts those to
+ colorized values using QPainter::CompositionMode_Screen with the
+ chosen color. The alpha-channel is not changed.
+
+ Example:
+ \snippet doc/src/snippets/code/src_gui_image_qpixmapfilter.cpp 0
+
+ \sa QPainter::CompositionMode
+
+ \internal
+*/
+class QPixmapColorizeFilterPrivate : public QPixmapFilterPrivate
+{
+ Q_DECLARE_PUBLIC(QPixmapColorizeFilter)
+public:
+ QColor color;
+ qreal strength;
+ quint32 opaque : 1;
+ quint32 alphaBlend : 1;
+ quint32 padding : 30;
+};
+
+/*!
+ Constructs an pixmap colorize filter.
+
+ Default color value for colorizing is QColor(0, 0, 192).
+
+ \internal
+*/
+QPixmapColorizeFilter::QPixmapColorizeFilter(QObject *parent)
+ : QPixmapFilter(*new QPixmapColorizeFilterPrivate, ColorizeFilter, parent)
+{
+ Q_D(QPixmapColorizeFilter);
+ d->color = QColor(0, 0, 192);
+ d->strength = qreal(1);
+ d->opaque = true;
+ d->alphaBlend = false;
+}
+
+/*!
+ Gets the color of the colorize filter.
+
+ \internal
+*/
+QColor QPixmapColorizeFilter::color() const
+{
+ Q_D(const QPixmapColorizeFilter);
+ return d->color;
+}
+
+/*!
+ Sets the color of the colorize filter to the \a color specified.
+
+ \internal
+*/
+void QPixmapColorizeFilter::setColor(const QColor &color)
+{
+ Q_D(QPixmapColorizeFilter);
+ d->color = color;
+}
+
+/*!
+ Gets the strength of the colorize filter, 1.0 means full colorized while
+ 0.0 equals to no filtering at all.
+
+ \internal
+*/
+qreal QPixmapColorizeFilter::strength() const
+{
+ Q_D(const QPixmapColorizeFilter);
+ return d->strength;
+}
+
+/*!
+ Sets the strength of the colorize filter to \a strength.
+
+ \internal
+*/
+void QPixmapColorizeFilter::setStrength(qreal strength)
+{
+ Q_D(QPixmapColorizeFilter);
+ d->strength = qBound(qreal(0), strength, qreal(1));
+ d->opaque = !qFuzzyIsNull(d->strength);
+ d->alphaBlend = !qFuzzyIsNull(d->strength - 1);
+}
+
+/*!
+ \internal
+*/
+void QPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const
+{
+ Q_D(const QPixmapColorizeFilter);
+
+ if (src.isNull())
+ return;
+
+ QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
+ static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0;
+ QPixmapColorizeFilter *colorizeFilter = static_cast<QPixmapColorizeFilter*>(filter);
+ if (colorizeFilter) {
+ colorizeFilter->setColor(d->color);
+ colorizeFilter->setStrength(d->strength);
+ colorizeFilter->draw(painter, dest, src, srcRect);
+ return;
+ }
+
+ // falling back to raster implementation
+
+ if (!d->opaque) {
+ painter->drawPixmap(dest, src, srcRect);
+ return;
+ }
+
+ QImage srcImage;
+ QImage destImage;
+
+ if (srcRect.isNull()) {
+ srcImage = src.toImage();
+ srcImage = srcImage.convertToFormat(srcImage.hasAlphaChannel() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
+ destImage = QImage(srcImage.size(), srcImage.format());
+ } else {
+ QRect rect = srcRect.toAlignedRect().intersected(src.rect());
+
+ srcImage = src.copy(rect).toImage();
+ srcImage = srcImage.convertToFormat(srcImage.hasAlphaChannel() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
+ destImage = QImage(rect.size(), srcImage.format());
+ }
+
+ // do colorizing
+ QPainter destPainter(&destImage);
+ grayscale(srcImage, destImage, srcImage.rect());
+ destPainter.setCompositionMode(QPainter::CompositionMode_Screen);
+ destPainter.fillRect(srcImage.rect(), d->color);
+ destPainter.end();
+
+ if (d->alphaBlend) {
+ // alpha blending srcImage and destImage
+ QImage buffer = srcImage;
+ QPainter bufPainter(&buffer);
+ bufPainter.setOpacity(d->strength);
+ bufPainter.drawImage(0, 0, destImage);
+ bufPainter.end();
+ destImage = buffer;
+ }
+
+ if (srcImage.hasAlphaChannel())
+ destImage.setAlphaChannel(srcImage.alphaChannel());
+
+ painter->drawImage(dest, destImage);
+}
+
+class QPixmapDropShadowFilterPrivate : public QPixmapFilterPrivate
+{
+public:
+ QPixmapDropShadowFilterPrivate()
+ : offset(8, 8), color(63, 63, 63, 180), radius(1) {}
+
+ QPointF offset;
+ QColor color;
+ qreal radius;
+};
+
+/*!
+ \class QPixmapDropShadowFilter
+ \since 4.5
+ \ingroup painting
+
+ \brief The QPixmapDropShadowFilter class is a convenience class
+ for drawing pixmaps with drop shadows.
+
+ The drop shadow is produced by taking a copy of the source pixmap
+ and applying a color to the copy using a
+ QPainter::CompositionMode_DestinationIn operation. This produces a
+ homogeneously-colored pixmap which is then drawn using a
+ QPixmapConvolutionFilter at an offset. The original pixmap is
+ drawn on top.
+
+ The QPixmapDropShadowFilter class provides some customization
+ options to specify how the drop shadow should appear. The color of
+ the drop shadow can be modified using the setColor() function, the
+ drop shadow offset can be modified using the setOffset() function,
+ and the blur radius of the drop shadow can be changed through the
+ setBlurRadius() function.
+
+ By default, the drop shadow is a dark gray shadow, blurred with a
+ radius of 1 at an offset of 8 pixels towards the lower right.
+
+ Example:
+ \snippet doc/src/snippets/code/src_gui_image_qpixmapfilter.cpp 2
+
+ \sa QPixmapColorizeFilter, QPixmapConvolutionFilter
+
+ \internal
+ */
+
+/*!
+ Constructs drop shadow filter.
+
+ \internal
+*/
+QPixmapDropShadowFilter::QPixmapDropShadowFilter(QObject *parent)
+ : QPixmapFilter(*new QPixmapDropShadowFilterPrivate, DropShadowFilter, parent)
+{
+}
+
+/*!
+ Destroys drop shadow filter.
+
+ \internal
+*/
+QPixmapDropShadowFilter::~QPixmapDropShadowFilter()
+{
+}
+
+/*!
+ Returns the radius in pixels of the blur on the drop shadow.
+
+ A smaller radius results in a sharper shadow.
+
+ \sa color(), offset()
+
+ \internal
+*/
+qreal QPixmapDropShadowFilter::blurRadius() const
+{
+ Q_D(const QPixmapDropShadowFilter);
+ return d->radius;
+}
+
+/*!
+ Sets the radius in pixels of the blur on the drop shadow to the \a radius specified.
+
+ Using a smaller radius results in a sharper shadow.
+
+ \sa setColor(), setOffset()
+
+ \internal
+*/
+void QPixmapDropShadowFilter::setBlurRadius(qreal radius)
+{
+ Q_D(QPixmapDropShadowFilter);
+ d->radius = radius;
+}
+
+/*!
+ Returns the color of the drop shadow.
+
+ \sa blurRadius(), offset()
+
+ \internal
+*/
+QColor QPixmapDropShadowFilter::color() const
+{
+ Q_D(const QPixmapDropShadowFilter);
+ return d->color;
+}
+
+/*!
+ Sets the color of the drop shadow to the \a color specified.
+
+ \sa setBlurRadius(), setOffset()
+
+ \internal
+*/
+void QPixmapDropShadowFilter::setColor(const QColor &color)
+{
+ Q_D(QPixmapDropShadowFilter);
+ d->color = color;
+}
+
+/*!
+ Returns the shadow offset in pixels.
+
+ \sa blurRadius(), color()
+
+ \internal
+*/
+QPointF QPixmapDropShadowFilter::offset() const
+{
+ Q_D(const QPixmapDropShadowFilter);
+ return d->offset;
+}
+
+/*!
+ Sets the shadow offset in pixels to the \a offset specified.
+
+ \sa setBlurRadius(), setColor()
+
+ \internal
+*/
+void QPixmapDropShadowFilter::setOffset(const QPointF &offset)
+{
+ Q_D(QPixmapDropShadowFilter);
+ d->offset = offset;
+}
+
+/*!
+ \fn void QPixmapDropShadowFilter::setOffset(qreal dx, qreal dy)
+ \overload
+
+ Sets the shadow offset in pixels to be the displacement specified by the
+ horizontal \a dx and vertical \a dy coordinates.
+
+ \sa setBlurRadius(), setColor()
+
+ \internal
+*/
+
+/*!
+ \internal
+ */
+QRectF QPixmapDropShadowFilter::boundingRectFor(const QRectF &rect) const
+{
+ Q_D(const QPixmapDropShadowFilter);
+ return rect.united(rect.translated(d->offset).adjusted(-d->radius, -d->radius, d->radius, d->radius));
+}
+
+/*!
+ \internal
+ */
+void QPixmapDropShadowFilter::draw(QPainter *p,
+ const QPointF &pos,
+ const QPixmap &px,
+ const QRectF &src) const
+{
+ Q_D(const QPixmapDropShadowFilter);
+
+ if (px.isNull())
+ return;
+
+ QPixmapFilter *filter = p->paintEngine() && p->paintEngine()->isExtended() ?
+ static_cast<QPaintEngineEx *>(p->paintEngine())->pixmapFilter(type(), this) : 0;
+ QPixmapDropShadowFilter *dropShadowFilter = static_cast<QPixmapDropShadowFilter*>(filter);
+ if (dropShadowFilter) {
+ dropShadowFilter->setColor(d->color);
+ dropShadowFilter->setBlurRadius(d->radius);
+ dropShadowFilter->setOffset(d->offset);
+ dropShadowFilter->draw(p, pos, px, src);
+ return;
+ }
+
+ QImage tmp(px.size(), QImage::Format_ARGB32_Premultiplied);
+ tmp.fill(0);
+ QPainter tmpPainter(&tmp);
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ tmpPainter.drawPixmap(d->offset, px);
+ tmpPainter.end();
+
+ // blur the alpha channel
+ QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
+ blurred.fill(0);
+ QPainter blurPainter(&blurred);
+ qt_blurImage(&blurPainter, tmp, d->radius, false, true);
+ blurPainter.end();
+
+ tmp = blurred;
+
+ // blacken the image...
+ tmpPainter.begin(&tmp);
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ tmpPainter.fillRect(tmp.rect(), d->color);
+ tmpPainter.end();
+
+ // draw the blurred drop shadow...
+ p->drawImage(pos, tmp);
+
+ // Draw the actual pixmap...
+ p->drawPixmap(pos, px, src);
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_GRAPHICSEFFECT
diff --git a/src/widgets/effects/qpixmapfilter_p.h b/src/widgets/effects/qpixmapfilter_p.h
new file mode 100644
index 0000000000..961866c19b
--- /dev/null
+++ b/src/widgets/effects/qpixmapfilter_p.h
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPIXMAPFILTER_H
+#define QPIXMAPFILTER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qnamespace.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qgraphicseffect.h>
+
+#ifndef QT_NO_GRAPHICSEFFECT
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QPainter;
+class QPixmapData;
+
+class QPixmapFilterPrivate;
+
+class Q_GUI_EXPORT QPixmapFilter : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPixmapFilter)
+public:
+ virtual ~QPixmapFilter() = 0;
+
+ enum FilterType {
+ ConvolutionFilter,
+ ColorizeFilter,
+ DropShadowFilter,
+ BlurFilter,
+
+ UserFilter = 1024
+ };
+
+ FilterType type() const;
+
+ virtual QRectF boundingRectFor(const QRectF &rect) const;
+
+ virtual void draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &srcRect = QRectF()) const = 0;
+
+protected:
+ QPixmapFilter(QPixmapFilterPrivate &d, FilterType type, QObject *parent);
+ QPixmapFilter(FilterType type, QObject *parent);
+};
+
+class QPixmapConvolutionFilterPrivate;
+
+class Q_GUI_EXPORT QPixmapConvolutionFilter : public QPixmapFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPixmapConvolutionFilter)
+
+public:
+ QPixmapConvolutionFilter(QObject *parent = 0);
+ ~QPixmapConvolutionFilter();
+
+ void setConvolutionKernel(const qreal *matrix, int rows, int columns);
+
+ QRectF boundingRectFor(const QRectF &rect) const;
+ void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect = QRectF()) const;
+
+private:
+ friend class QGLPixmapConvolutionFilter;
+ friend class QVGPixmapConvolutionFilter;
+ const qreal *convolutionKernel() const;
+ int rows() const;
+ int columns() const;
+};
+
+class QPixmapBlurFilterPrivate;
+
+class Q_GUI_EXPORT QPixmapBlurFilter : public QPixmapFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPixmapBlurFilter)
+
+public:
+ QPixmapBlurFilter(QObject *parent = 0);
+ ~QPixmapBlurFilter();
+
+ void setRadius(qreal radius);
+ void setBlurHints(QGraphicsBlurEffect::BlurHints hints);
+
+ qreal radius() const;
+ QGraphicsBlurEffect::BlurHints blurHints() const;
+
+ QRectF boundingRectFor(const QRectF &rect) const;
+ void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect = QRectF()) const;
+
+private:
+ friend class QGLPixmapBlurFilter;
+};
+
+class QPixmapColorizeFilterPrivate;
+
+class Q_GUI_EXPORT QPixmapColorizeFilter : public QPixmapFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPixmapColorizeFilter)
+
+public:
+ QPixmapColorizeFilter(QObject *parent = 0);
+
+ void setColor(const QColor& color);
+ QColor color() const;
+
+ void setStrength(qreal strength);
+ qreal strength() const;
+
+ void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect = QRectF()) const;
+};
+
+class QPixmapDropShadowFilterPrivate;
+
+class Q_GUI_EXPORT QPixmapDropShadowFilter : public QPixmapFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPixmapDropShadowFilter)
+
+public:
+ QPixmapDropShadowFilter(QObject *parent = 0);
+ ~QPixmapDropShadowFilter();
+
+ QRectF boundingRectFor(const QRectF &rect) const;
+ void draw(QPainter *p, const QPointF &pos, const QPixmap &px, const QRectF &src = QRectF()) const;
+
+ qreal blurRadius() const;
+ void setBlurRadius(qreal radius);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ QPointF offset() const;
+ void setOffset(const QPointF &offset);
+ inline void setOffset(qreal dx, qreal dy) { setOffset(QPointF(dx, dy)); }
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QT_NO_GRAPHICSEFFECT
+#endif // QPIXMAPFILTER_H