summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-08-21 13:26:33 (GMT)
committerBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-08-21 13:26:33 (GMT)
commitef93943579210dffaa83185cea99146fa9f3f9b6 (patch)
treeca1a4bf586a54dedd6d8e85d086a8f7cd8c3dbcd /src/gui
parent00ba962d428dcdff70fcde74a9e5cb316545cef6 (diff)
parent1b305c739979f7d0e8cb6ebbac6d29ca2e6b060d (diff)
downloadQt-ef93943579210dffaa83185cea99146fa9f3f9b6.zip
Qt-ef93943579210dffaa83185cea99146fa9f3f9b6.tar.gz
Qt-ef93943579210dffaa83185cea99146fa9f3f9b6.tar.bz2
Merge commit 'qt-kinetic/kinetic-graphicseffect'
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/effects/effects.pri4
-rw-r--r--src/gui/effects/qgraphicseffect.cpp572
-rw-r--r--src/gui/effects/qgraphicseffect.h277
-rw-r--r--src/gui/effects/qgraphicseffect_p.h166
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp284
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h6
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h80
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp74
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h2
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h25
-rw-r--r--src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp4
-rw-r--r--src/gui/gui.pro1
-rw-r--r--src/gui/image/qpixmapfilter.cpp271
-rw-r--r--src/gui/image/qpixmapfilter_p.h29
-rw-r--r--src/gui/kernel/qwidget.cpp203
-rw-r--r--src/gui/kernel/qwidget.h4
-rw-r--r--src/gui/kernel/qwidget_mac.mm8
-rw-r--r--src/gui/kernel/qwidget_p.h60
-rw-r--r--src/gui/kernel/qwidget_qws.cpp8
-rw-r--r--src/gui/kernel/qwidget_win.cpp4
-rw-r--r--src/gui/kernel/qwidget_x11.cpp4
-rw-r--r--src/gui/painting/qbackingstore.cpp37
-rw-r--r--src/gui/painting/qbackingstore_p.h8
-rw-r--r--src/gui/painting/qpaintengine.h1
-rw-r--r--src/gui/painting/qpaintengine_p.h4
25 files changed, 2023 insertions, 113 deletions
diff --git a/src/gui/effects/effects.pri b/src/gui/effects/effects.pri
new file mode 100644
index 0000000..0ebf96f
--- /dev/null
+++ b/src/gui/effects/effects.pri
@@ -0,0 +1,4 @@
+HEADERS += effects/qgraphicseffect.h \
+ effects/qgraphicseffect_p.h
+
+SOURCES += effects/qgraphicseffect.cpp
diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp
new file mode 100644
index 0000000..949922a
--- /dev/null
+++ b/src/gui/effects/qgraphicseffect.cpp
@@ -0,0 +1,572 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QGraphicsEffect
+ \brief The QGraphicsEffect class is the base class for all graphics effects.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ Effects alter the appearance of elements by hooking into the rendering
+ pipeline and operating between the source (e.g., a QGraphicsPixmapItem),
+ and the destination device (e.g., QGraphicsView's viewport). Effects can be
+ disabled by calling setEnabled(); if the effect is disabled, the source is
+ rendered directly.
+
+ If you want to add a visual effect to a QGraphicsItem, you can either use
+ one of the standard effects, or create your own effect by making a subclass
+ of QGraphicsEffect.
+
+ Qt provides several standard effects, including:
+
+ \list
+ \o QGraphicsGrayScaleEffect - renders the item in shades of gray
+ \o QGraphicsColorizeEffect - renders the item in shades of any given color
+ \o QGraphicsPixelizeEffect - pixelizes the item with any pixel size
+ \o QGraphicsBlurEffect - blurs the item by a given radius
+ \o QGraphicsDropShadowEffect - renders a dropshadow behind the item
+ \endlist
+
+ If all you want is to add an effect to an item, you should visit the
+ documentation for the specific effect to learn more about how each effect
+ can be used.
+
+ If you want to create your own custom effect, you can start by creating a
+ subclass of QGraphicsEffect (or any of the existing effects), and
+ reimplement the virtual function draw(). This function is called whenever
+ the effect needs to redraw. draw() has two arguments: the painter, and a
+ pointer to the source (QGraphicsEffectSource). The source provides extra
+ context information, such as a pointer to the item that is rendering the
+ effect, any cached pixmap data, and the device rect bounds. See the draw()
+ documentation for more details. You can also get a pointer to the current
+ source by calling source().
+
+ If your effect changes, you can call update() to request a redraw. If your
+ custom effect changes the bounding rectangle of the source (e.g., a radial
+ glow effect may need to apply an extra margin), you can reimplement the
+ virtual boundingRectFor() function, and call updateBoundingRect() to notify
+ the framework whenever this rectangle changes. The virtual
+ sourceBoundingRectChanged() function is called to notify the effects that
+ the source's bounding rectangle has changed (e.g., if the source is a
+ QGraphicsRectItem, then if the rectangle parameters have changed).
+
+ \sa QGraphicsItem::setGraphicsEffect()
+*/
+
+#include "qgraphicseffect_p.h"
+
+#include <QtGui/qimage.h>
+#include <QtGui/qpainter.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{}
+
+QGraphicsEffectSource::~QGraphicsEffectSource()
+{}
+
+QRect QGraphicsEffectSource::deviceRect() const
+{
+ return d_func()->deviceRect();
+}
+
+QRectF QGraphicsEffectSource::boundingRect(Qt::CoordinateSystem system) const
+{
+ return d_func()->boundingRect(system);
+}
+
+const QGraphicsItem *QGraphicsEffectSource::graphicsItem() const
+{
+ return d_func()->graphicsItem();
+}
+
+const QWidget *QGraphicsEffectSource::widget() const
+{
+ return d_func()->widget();
+}
+
+const QStyleOption *QGraphicsEffectSource::styleOption() const
+{
+ return d_func()->styleOption();
+}
+
+void QGraphicsEffectSource::draw(QPainter *painter)
+{
+ d_func()->draw(painter);
+}
+
+void QGraphicsEffectSource::update()
+{
+ d_func()->update();
+}
+
+bool QGraphicsEffectSource::isPixmap() const
+{
+ return d_func()->isPixmap();
+}
+
+QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset) const
+{
+ return d_func()->pixmap(system, offset);
+}
+
+/*!
+ Constructs a new QGraphicsEffect instance.
+*/
+QGraphicsEffect::QGraphicsEffect(QObject *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 bounding rectangle for this effect (i.e., the bounding
+ rectangle of the source, adjusted by any margins applied by the effect
+ itself).
+
+ \sa boundingRectFor(), updateBoundingRect()
+*/
+QRectF QGraphicsEffect::boundingRect() const
+{
+ Q_D(const QGraphicsEffect);
+ if (d->source)
+ return boundingRectFor(d->source->boundingRect());
+ return QRectF();
+}
+
+/*!
+ Returns the bounding rectangle for this effect, given the provided source
+ \a rect. When writing you own custom effect, you must call
+ updateBoundingRect() whenever any parameters are changed that may cause
+ this this function to return a different value.
+
+ \sa boundingRect()
+*/
+QRectF QGraphicsEffect::boundingRectFor(const QRectF &rect) const
+{
+ return rect;
+}
+
+/*!
+ \property QGraphicsEffect::enabled
+ \brief whether the effect is enabled or not.
+
+ If an effect is disabled, the source will be rendered with as normal, with
+ no interference from the effect. If the effect is enabled (default), the
+ source will be rendered with the effect applied.
+
+ This property is provided so that you can disable certain effects on slow
+ platforms, in order to ensure that the user interface is responsive.
+*/
+bool QGraphicsEffect::isEnabled() const
+{
+ Q_D(const QGraphicsEffect);
+ return d->isEnabled;
+}
+
+void QGraphicsEffect::setEnabled(bool enable)
+{
+ Q_D(QGraphicsEffect);
+ if (d->isEnabled == enable)
+ return;
+
+ d->isEnabled = enable;
+ if (d->source)
+ d->source->update();
+ emit enabledChanged(enable);
+}
+
+/*!
+ Returns a pointer to the source, which provides extra context information
+ that can be useful for the effect.
+
+ \sa draw()
+*/
+QGraphicsEffectSource *QGraphicsEffect::source() const
+{
+ Q_D(const QGraphicsEffect);
+ return d->source;
+}
+
+/*!
+ This function notifies the effect framework that the effect's bounding
+ rectangle has changed. As a custom effect author, you must call this
+ function whenever you change any parameters that will cause the virtual
+ boundingRectFor() function to return a different value.
+
+ \sa boundingRectFor(), boundingRect()
+*/
+void QGraphicsEffect::updateBoundingRect()
+{
+ Q_D(QGraphicsEffect);
+ if (d->source)
+ d->source->update();
+}
+
+/*!
+ This virtual function is called by QGraphicsEffect to notify the effect
+ that the source has changed. If the effect applies any cache, then this
+ cache must be purged in order to reflect the new appearance of the source.
+
+ The \a flags describes what has changed.
+*/
+void QGraphicsEffect::sourceChanged(ChangeFlags flags)
+{
+ Q_UNUSED(flags);
+}
+
+QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsGrayscaleEffectPrivate, parent)
+{
+}
+
+QGraphicsGrayscaleEffect::~QGraphicsGrayscaleEffect()
+{
+}
+
+void QGraphicsGrayscaleEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
+{
+ Q_D(QGraphicsGrayscaleEffect);
+ QPoint offset;
+ if (source->isPixmap()) {
+ // No point in drawing in device coordinates (pixmap will be scaled anyways).
+ const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
+ d->filter->draw(painter, offset, pixmap);
+ return;
+ }
+
+ // Draw pixmap in device coordinates to avoid pixmap scaling;
+ const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ d->filter->draw(painter, offset, pixmap);
+ painter->setWorldTransform(restoreTransform);
+
+}
+
+QGraphicsColorizeEffect::QGraphicsColorizeEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsColorizeEffectPrivate, parent)
+{
+}
+
+QGraphicsColorizeEffect::~QGraphicsColorizeEffect()
+{
+}
+
+QColor QGraphicsColorizeEffect::color() const
+{
+ Q_D(const QGraphicsColorizeEffect);
+ return d->filter->color();
+}
+
+void QGraphicsColorizeEffect::setColor(const QColor &c)
+{
+ Q_D(QGraphicsColorizeEffect);
+ if (d->filter->color() == c)
+ return;
+
+ d->filter->setColor(c);
+ emit colorChanged(c);
+}
+
+void QGraphicsColorizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
+{
+ Q_D(QGraphicsColorizeEffect);
+ QPoint offset;
+ if (source->isPixmap()) {
+ // No point in drawing in device coordinates (pixmap will be scaled anyways).
+ const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
+ d->filter->draw(painter, offset, pixmap);
+ return;
+ }
+
+ // Draw pixmap in deviceCoordinates to avoid pixmap scaling.
+ const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ d->filter->draw(painter, offset, pixmap);
+ painter->setWorldTransform(restoreTransform);
+}
+
+QGraphicsPixelizeEffect::QGraphicsPixelizeEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsPixelizeEffectPrivate, parent)
+{
+}
+
+QGraphicsPixelizeEffect::~QGraphicsPixelizeEffect()
+{
+}
+
+int QGraphicsPixelizeEffect::pixelSize() const
+{
+ Q_D(const QGraphicsPixelizeEffect);
+ return d->pixelSize;
+}
+
+void QGraphicsPixelizeEffect::setPixelSize(int size)
+{
+ Q_D(QGraphicsPixelizeEffect);
+ if (d->pixelSize == size)
+ return;
+
+ d->pixelSize = size;
+ emit pixelSizeChanged(size);
+}
+
+static inline void pixelize(QImage *image, int pixelSize)
+{
+ Q_ASSERT(pixelSize > 0);
+ Q_ASSERT(image);
+ int width = image->width();
+ int height = image->height();
+ for (int y = 0; y < height; y += pixelSize) {
+ int ys = qMin(height - 1, y + pixelSize / 2);
+ QRgb *sbuf = reinterpret_cast<QRgb*>(image->scanLine(ys));
+ for (int x = 0; x < width; x += pixelSize) {
+ int xs = qMin(width - 1, x + pixelSize / 2);
+ QRgb color = sbuf[xs];
+ for (int yi = 0; yi < qMin(pixelSize, height - y); ++yi) {
+ QRgb *buf = reinterpret_cast<QRgb*>(image->scanLine(y + yi));
+ for (int xi = 0; xi < qMin(pixelSize, width - x); ++xi)
+ buf[x + xi] = color;
+ }
+ }
+ }
+}
+
+void QGraphicsPixelizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
+{
+ Q_D(QGraphicsPixelizeEffect);
+ if (d->pixelSize <= 0) {
+ source->draw(painter);
+ return;
+ }
+
+ QPoint offset;
+ if (source->isPixmap()) {
+ const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
+ QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ pixelize(&image, d->pixelSize);
+ painter->drawImage(offset, image);
+ return;
+ }
+
+ // Draw pixmap in device coordinates to avoid pixmap scaling.
+ const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
+
+ // pixelize routine
+ QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ pixelize(&image, d->pixelSize);
+
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ painter->drawImage(offset, image);
+ painter->setWorldTransform(restoreTransform);
+}
+
+QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsBlurEffectPrivate, parent)
+{
+}
+
+QGraphicsBlurEffect::~QGraphicsBlurEffect()
+{
+}
+
+int QGraphicsBlurEffect::blurRadius() const
+{
+ Q_D(const QGraphicsBlurEffect);
+ return d->filter->radius();
+}
+
+void QGraphicsBlurEffect::setBlurRadius(int radius)
+{
+ Q_D(QGraphicsBlurEffect);
+ if (d->filter->radius() == radius)
+ return;
+
+ d->filter->setRadius(radius);
+ updateBoundingRect();
+ emit blurRadiusChanged(radius);
+}
+
+QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const
+{
+ Q_D(const QGraphicsBlurEffect);
+ return d->filter->boundingRectFor(rect);
+}
+
+void QGraphicsBlurEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
+{
+ Q_D(QGraphicsBlurEffect);
+ if (d->filter->radius() <= 0) {
+ source->draw(painter);
+ return;
+ }
+
+ QPoint offset;
+ if (source->isPixmap()) {
+ // No point in drawing in device coordinates (pixmap will be scaled anyways).
+ const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
+ d->filter->draw(painter, offset, pixmap);
+ return;
+ }
+
+ // Draw pixmap in device coordinates to avoid pixmap scaling.
+ const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ d->filter->draw(painter, offset, pixmap);
+ painter->setWorldTransform(restoreTransform);
+}
+
+QGraphicsDropShadowEffect::QGraphicsDropShadowEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsDropShadowEffectPrivate, parent)
+{
+}
+
+QGraphicsDropShadowEffect::~QGraphicsDropShadowEffect()
+{
+}
+
+QPointF QGraphicsDropShadowEffect::offset() const
+{
+ Q_D(const QGraphicsDropShadowEffect);
+ return d->filter->offset();
+}
+
+void QGraphicsDropShadowEffect::setOffset(const QPointF &ofs)
+{
+ Q_D(QGraphicsDropShadowEffect);
+ if (d->filter->offset() == ofs)
+ return;
+
+ d->filter->setOffset(ofs);
+ updateBoundingRect();
+ emit offsetChanged(ofs);
+}
+
+int QGraphicsDropShadowEffect::blurRadius() const
+{
+ Q_D(const QGraphicsDropShadowEffect);
+ return d->filter->blurRadius();
+}
+
+void QGraphicsDropShadowEffect::setBlurRadius(int blurRadius)
+{
+ Q_D(QGraphicsDropShadowEffect);
+ if (d->filter->blurRadius() == blurRadius)
+ return;
+
+ d->filter->setBlurRadius(blurRadius);
+ updateBoundingRect();
+ emit blurRadiusChanged(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);
+ emit colorChanged(color);
+}
+
+QRectF QGraphicsDropShadowEffect::boundingRectFor(const QRectF &rect) const
+{
+ Q_D(const QGraphicsDropShadowEffect);
+ return d->filter->boundingRectFor(rect);
+}
+
+void QGraphicsDropShadowEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
+{
+ Q_D(QGraphicsDropShadowEffect);
+ if (d->filter->blurRadius() <= 0 && d->filter->offset().isNull()) {
+ source->draw(painter);
+ return;
+ }
+
+ QPoint offset;
+ if (source->isPixmap()) {
+ // No point in drawing in device coordinates (pixmap will be scaled anyways).
+ const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
+ d->filter->draw(painter, offset, pixmap);
+ return;
+ }
+
+ // Draw pixmap in device coordinates to avoid pixmap scaling.
+ const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ d->filter->draw(painter, offset, pixmap);
+ painter->setWorldTransform(restoreTransform);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/gui/effects/qgraphicseffect.h b/src/gui/effects/qgraphicseffect.h
new file mode 100644
index 0000000..99d8548
--- /dev/null
+++ b/src/gui/effects/qgraphicseffect.h
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSEFFECT_H
+#define QGRAPHICSEFFECT_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QGraphicsItem;
+class QStyleOption;
+class QPainter;
+class QPixmap;
+
+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) 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 QWidget;
+ friend class QWidgetPrivate;
+};
+
+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);
+
+ QGraphicsEffect(QObject *parent = 0);
+ virtual ~QGraphicsEffect();
+
+ virtual QRectF boundingRectFor(const QRectF &rect) const;
+ QRectF boundingRect() const;
+
+ QGraphicsEffectSource *source() const;
+
+ bool isEnabled() const;
+
+public Q_SLOTS:
+ void setEnabled(bool enable);
+ // ### add update() slot
+
+Q_SIGNALS:
+ void enabledChanged(bool enabled);
+
+protected:
+ QGraphicsEffect(QGraphicsEffectPrivate &d, QObject *parent = 0);
+ virtual void draw(QPainter *painter, QGraphicsEffectSource *source) = 0;
+ virtual void sourceChanged(ChangeFlags flags);
+ void updateBoundingRect();
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsEffect)
+ Q_DISABLE_COPY(QGraphicsEffect)
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+ friend class QGraphicsScenePrivate;
+ friend class QWidget;
+ friend class QWidgetPrivate;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsEffect::ChangeFlags);
+
+class QGraphicsGrayscaleEffectPrivate;
+class Q_GUI_EXPORT QGraphicsGrayscaleEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+public:
+ QGraphicsGrayscaleEffect(QObject *parent = 0);
+ ~QGraphicsGrayscaleEffect();
+
+protected:
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsGrayscaleEffect)
+ Q_DISABLE_COPY(QGraphicsGrayscaleEffect)
+};
+
+class QGraphicsColorizeEffectPrivate;
+class Q_GUI_EXPORT QGraphicsColorizeEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+public:
+ QGraphicsColorizeEffect(QObject *parent = 0);
+ ~QGraphicsColorizeEffect();
+
+ QColor color() const;
+
+public Q_SLOTS:
+ void setColor(const QColor &c);
+
+Q_SIGNALS:
+ void colorChanged(const QColor &color);
+
+protected:
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsColorizeEffect)
+ Q_DISABLE_COPY(QGraphicsColorizeEffect)
+};
+
+class QGraphicsPixelizeEffectPrivate;
+class Q_GUI_EXPORT QGraphicsPixelizeEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+ Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize NOTIFY pixelSizeChanged)
+public:
+ QGraphicsPixelizeEffect(QObject *parent = 0);
+ ~QGraphicsPixelizeEffect();
+
+ int pixelSize() const;
+
+public Q_SLOTS:
+ void setPixelSize(int pixelSize);
+
+Q_SIGNALS:
+ void pixelSizeChanged(int pixelSize);
+
+protected:
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsPixelizeEffect)
+ Q_DISABLE_COPY(QGraphicsPixelizeEffect)
+};
+
+class QGraphicsBlurEffectPrivate;
+class Q_GUI_EXPORT QGraphicsBlurEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+ Q_PROPERTY(int blurRadius READ blurRadius WRITE setBlurRadius NOTIFY blurRadiusChanged)
+public:
+ QGraphicsBlurEffect(QObject *parent = 0);
+ ~QGraphicsBlurEffect();
+
+ QRectF boundingRectFor(const QRectF &rect) const;
+ int blurRadius() const;
+
+public Q_SLOTS:
+ void setBlurRadius(int blurRadius);
+
+Q_SIGNALS:
+ void blurRadiusChanged(int blurRadius);
+
+protected:
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsBlurEffect)
+ Q_DISABLE_COPY(QGraphicsBlurEffect)
+};
+
+class QGraphicsDropShadowEffectPrivate;
+class Q_GUI_EXPORT QGraphicsDropShadowEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+ Q_PROPERTY(QPointF offset READ offset WRITE setOffset NOTIFY offsetChanged)
+ Q_PROPERTY(int 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;
+ int 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)); }
+ void setBlurRadius(int blurRadius);
+ void setColor(const QColor &color);
+
+Q_SIGNALS:
+ void offsetChanged(const QPointF &offset);
+ void blurRadiusChanged(int blurRadius);
+ void colorChanged(const QColor &color);
+
+protected:
+ void draw(QPainter *painter, QGraphicsEffectSource *source);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsDropShadowEffect)
+ Q_DISABLE_COPY(QGraphicsDropShadowEffect)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGRAPHICSEFFECT_H
+
diff --git a/src/gui/effects/qgraphicseffect_p.h b/src/gui/effects/qgraphicseffect_p.h
new file mode 100644
index 0000000..35f2d40
--- /dev/null
+++ b/src/gui/effects/qgraphicseffect_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSEFFECT_P_H
+#define QGRAPHICSEFFECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgraphicseffect.h"
+
+#include <private/qobject_p.h>
+#include <private/qpixmapfilter_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsEffectSourcePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsEffectSource)
+public:
+ QGraphicsEffectSourcePrivate() : QObjectPrivate() {}
+ virtual ~QGraphicsEffectSourcePrivate() {}
+ virtual void detach() = 0;
+ virtual QRectF boundingRect(Qt::CoordinateSystem system) const = 0;
+ virtual QRect deviceRect() const = 0;
+ virtual const QGraphicsItem *graphicsItem() const = 0;
+ virtual const 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) const = 0;
+ friend class QGraphicsScenePrivate;
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+};
+
+class Q_GUI_EXPORT QGraphicsEffectPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsEffect)
+public:
+ QGraphicsEffectPrivate() : source(0), isEnabled(1) {}
+
+ inline void setGraphicsEffectSource(QGraphicsEffectSource *newSource)
+ {
+ QGraphicsEffect::ChangeFlags flags;
+ if (source) {
+ flags |= QGraphicsEffect::SourceDetached;
+ source->d_func()->detach();
+ delete source;
+ }
+ source = newSource;
+ if (newSource)
+ flags |= QGraphicsEffect::SourceAttached;
+ q_func()->sourceChanged(flags);
+ }
+
+ QGraphicsEffectSource *source;
+ QRectF boundingRect;
+ quint32 isEnabled : 1;
+ quint32 padding : 31; // feel free to use
+};
+
+class QGraphicsGrayscaleEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsGrayscaleEffect)
+public:
+ QGraphicsGrayscaleEffectPrivate()
+ {
+ filter = new QPixmapColorizeFilter;
+ filter->setColor(Qt::black);
+ }
+ ~QGraphicsGrayscaleEffectPrivate() { delete filter; }
+
+ QPixmapColorizeFilter *filter;
+};
+
+class QGraphicsColorizeEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsColorizeEffect)
+public:
+ QGraphicsColorizeEffectPrivate() { filter = new QPixmapColorizeFilter; }
+ ~QGraphicsColorizeEffectPrivate() { delete filter; }
+
+ QPixmapColorizeFilter *filter;
+};
+
+class QGraphicsPixelizeEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsPixelizeEffect)
+public:
+ QGraphicsPixelizeEffectPrivate() : pixelSize(3) {}
+
+ int pixelSize;
+};
+
+class QGraphicsBlurEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsBlurEffect)
+public:
+ QGraphicsBlurEffectPrivate() : filter(new QPixmapBlurFilter) {}
+ ~QGraphicsBlurEffectPrivate() { delete filter; }
+
+ QPixmapBlurFilter *filter;
+};
+
+class QGraphicsDropShadowEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsDropShadowEffect)
+public:
+ QGraphicsDropShadowEffectPrivate() : filter(new QPixmapDropShadowFilter) {}
+ ~QGraphicsDropShadowEffectPrivate() { delete filter; }
+
+ QPixmapDropShadowFilter *filter;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGRAPHICSEFFECT_P_H
+
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 1d52182..db24c77 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -581,6 +581,7 @@
#include <QtGui/qpixmapcache.h>
#include <QtGui/qstyleoption.h>
#include <QtGui/qevent.h>
+#include <QtGui/qgraphicseffect.h>
#include <private/qgraphicsitem_p.h>
#include <private/qgraphicswidget_p.h>
@@ -1042,11 +1043,6 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
*/
void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect)
{
- if (!dirtyChildrenBoundingRect) {
- *rect |= x->mapRect(childrenBoundingRect);
- return;
- }
-
for (int i = 0; i < children.size(); ++i) {
QGraphicsItem *child = children.at(i);
QGraphicsItemPrivate *childd = child->d_ptr;
@@ -1054,19 +1050,20 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec
if (hasPos || childd->transformData) {
// COMBINE
QTransform matrix = childd->transformToParent();
- matrix *= *x;
+ if (x)
+ matrix *= *x;
*rect |= matrix.mapRect(child->boundingRect());
if (!childd->children.isEmpty())
childd->childrenBoundingRectHelper(&matrix, rect);
} else {
- *rect |= x->mapRect(child->boundingRect());
+ if (x)
+ *rect |= x->mapRect(child->boundingRect());
+ else
+ *rect |= child->boundingRect();
if (!childd->children.isEmpty())
childd->childrenBoundingRectHelper(x, rect);
}
}
-
- childrenBoundingRect = *rect;
- dirtyChildrenBoundingRect = 0;
}
void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
@@ -1210,6 +1207,7 @@ QGraphicsItem::~QGraphicsItem()
d_ptr->setParentItemHelper(0);
}
+ delete d_ptr->graphicsEffect;
if (d_ptr->transformData) {
for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) {
QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i);
@@ -2018,8 +2016,8 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo
enabled = newEnabledVariant.toBool();
// Schedule redraw.
- if (update && scene)
- scene->d_func()->markDirty(q_ptr);
+ if (update)
+ q_ptr->update();
foreach (QGraphicsItem *child, children) {
if (!newEnabled || !child->d_ptr->explicitlyDisabled)
@@ -2123,8 +2121,8 @@ void QGraphicsItem::setSelected(bool selected)
return;
d_ptr->selected = newSelected;
+ update();
if (d_ptr->scene) {
- d_ptr->scene->d_func()->markDirty(this);
QGraphicsScenePrivate *sceneD = d_ptr->scene->d_func();
if (selected) {
sceneD->selectedItems << this;
@@ -2231,6 +2229,118 @@ void QGraphicsItem::setOpacity(qreal opacity)
}
/*!
+ Returns a pointer to this item's effect if it has one; otherwise 0.
+
+ \since 4.6
+*/
+QGraphicsEffect *QGraphicsItem::graphicsEffect() const
+{
+ return d_ptr->graphicsEffect;
+}
+
+/*!
+ Sets \a effect as the item's effect. If there already is an effect installed
+ on this item, QGraphicsItem will delete the existing effect before installing
+ the new \a effect.
+
+ If \a effect is the installed on a different item, setGraphicsEffect() will remove
+ the effect from the item and install it on this item.
+
+ \note This function will apply the effect on itself and all its children.
+
+ \since 4.6
+*/
+void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect)
+{
+ if (d_ptr->graphicsEffect == effect)
+ return;
+
+ if (d_ptr->graphicsEffect && effect) {
+ delete d_ptr->graphicsEffect;
+ d_ptr->graphicsEffect = 0;
+ }
+
+ if (!effect) {
+ // Unset current effect.
+ QGraphicsEffectPrivate *oldEffectPrivate = d_ptr->graphicsEffect->d_func();
+ d_ptr->graphicsEffect = 0;
+ if (oldEffectPrivate) {
+ oldEffectPrivate->setGraphicsEffectSource(0); // deletes the current source.
+ if (d_ptr->scene) // Update the views directly.
+ d_ptr->scene->d_func()->markDirty(this, QRectF(), false, false, false, false, true);
+ }
+ } else {
+ // Set new effect.
+ QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this);
+ QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced);
+ d_ptr->graphicsEffect = effect;
+ effect->d_func()->setGraphicsEffectSource(source);
+ }
+
+ prepareGeometryChange();
+}
+
+/*!
+ \internal
+ \since 4.6
+ Returns the effective bounding rect of the item.
+ If the item has no effect, this is the same as the item's bounding rect.
+ If the item has an effect, the effective rect can be larger than the item's
+ bouding rect, depending on the effect.
+
+ \sa boundingRect()
+*/
+QRectF QGraphicsItemPrivate::effectiveBoundingRect() const
+{
+ QGraphicsEffect *effect = graphicsEffect;
+ QRectF brect = effect && effect->isEnabled() ? effect->boundingRect() : q_ptr->boundingRect();
+ if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
+ return brect;
+
+ const QGraphicsItem *effectParent = parent;
+ while (effectParent) {
+ effect = effectParent->d_ptr->graphicsEffect;
+ if (effect && effect->isEnabled())
+ brect = effect->boundingRectFor(brect);
+ if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
+ return brect;
+ effectParent = effectParent->d_ptr->parent;
+ }
+
+ return brect;
+}
+
+/*!
+ \internal
+ \since 4.6
+ Returns the effective bounding rect of this item in scene coordinates,
+ by combining sceneTransform() with boundingRect(), taking into account
+ the effect that the item might have.
+
+ If the item has no effect, this is the same as sceneBoundingRect().
+
+ \sa effectiveBoundingRect(), sceneBoundingRect()
+*/
+QRectF QGraphicsItemPrivate::sceneEffectiveBoundingRect() const
+{
+ // Find translate-only offset
+ // COMBINE
+ QPointF offset;
+ const QGraphicsItem *parentItem = q_ptr;
+ const QGraphicsItemPrivate *itemd;
+ do {
+ itemd = parentItem->d_ptr;
+ if (itemd->transformData)
+ break;
+ offset += itemd->pos;
+ } while ((parentItem = itemd->parent));
+
+ QRectF br = effectiveBoundingRect();
+ br.translate(offset);
+ return !parentItem ? br : parentItem->sceneTransform().mapRect(br);
+}
+
+/*!
Returns true if this item can accept drag and drop events; otherwise,
returns false. By default, items do not accept drag and drop events; items
are transparent to drag and drop.
@@ -3757,10 +3867,10 @@ QRectF QGraphicsItem::childrenBoundingRect() const
if (!d_ptr->dirtyChildrenBoundingRect)
return d_ptr->childrenBoundingRect;
- QRectF childRect;
- QTransform x;
- d_ptr->childrenBoundingRectHelper(&x, &childRect);
- return childRect;
+ d_ptr->childrenBoundingRect = QRectF();
+ d_ptr->childrenBoundingRectHelper(0, &d_ptr->childrenBoundingRect);
+ d_ptr->dirtyChildrenBoundingRect = 0;
+ return d_ptr->childrenBoundingRect;
}
/*!
@@ -4711,6 +4821,13 @@ void QGraphicsItem::update(const QRectF &rect)
if (rect.isEmpty() && !rect.isNull())
return;
+ // Make sure we notify effects about invalidated source.
+ QGraphicsItem *item = this;
+ do {
+ if (item->d_ptr->graphicsEffect)
+ item->d_ptr->notifyInvalidated = 1;
+ } while ((item = item->d_ptr->parent));
+
if (CacheMode(d_ptr->cacheMode) != NoCache) {
QGraphicsItemCache *cache = d_ptr->extraItemCache();
if (d_ptr->discardUpdateRequest(/* ignoreVisibleBit = */ false,
@@ -6050,6 +6167,7 @@ void QGraphicsItem::dropEvent(QGraphicsSceneDragDropEvent *event)
void QGraphicsItem::focusInEvent(QFocusEvent *event)
{
Q_UNUSED(event);
+ update();
}
/*!
@@ -6061,6 +6179,7 @@ void QGraphicsItem::focusInEvent(QFocusEvent *event)
void QGraphicsItem::focusOutEvent(QFocusEvent *event)
{
Q_UNUSED(event);
+ update();
}
/*!
@@ -6075,8 +6194,7 @@ void QGraphicsItem::focusOutEvent(QFocusEvent *event)
void QGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
- if (d_ptr->scene)
- d_ptr->scene->d_func()->markDirty(this);
+ update();
}
/*!
@@ -6104,8 +6222,7 @@ void QGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
void QGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
- if (d_ptr->scene)
- d_ptr->scene->d_func()->markDirty(this);
+ update();
}
/*!
@@ -6606,6 +6723,7 @@ void QGraphicsItem::prepareGeometryChange()
d_ptr->scene->d_func()->dirtyGrowingItemsBoundingRect = true;
d_ptr->geometryChanged = 1;
d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
+ d_ptr->notifyBoundingRectChanged = !d_ptr->inSetPosHelper;
QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
scenePrivate->index->prepareBoundingRectChange(this);
@@ -6629,8 +6747,11 @@ void QGraphicsItem::prepareGeometryChange()
}
QGraphicsItem *parent = this;
- while ((parent = parent->d_ptr->parent))
+ while ((parent = parent->d_ptr->parent)) {
parent->d_ptr->dirtyChildrenBoundingRect = 1;
+ // ### Only do this if the parent's effect applies to the entire subtree.
+ parent->d_ptr->notifyBoundingRectChanged = 1;
+ }
if (d_ptr->inSetPosHelper)
return;
@@ -9985,6 +10106,125 @@ int QGraphicsItemGroup::type() const
return Type;
}
+QRectF QGraphicsItemEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const
+{
+ const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
+ if (!info && deviceCoordinates) {
+ // Device coordinates without info not yet supported.
+ qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context");
+ return QRectF();
+ }
+
+ QRectF rect = item->boundingRect();
+ if (!item->d_ptr->children.isEmpty())
+ rect |= item->childrenBoundingRect();
+
+ if (deviceCoordinates) {
+ Q_ASSERT(info->painter);
+ rect = info->painter->worldTransform().mapRect(rect);
+ }
+
+ return rect;
+}
+
+void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter)
+{
+ if (!info) {
+ qWarning("QGraphicsEffectSource::draw: Can only begin as a result of QGraphicsEffect::draw");
+ return;
+ }
+
+ Q_ASSERT(item->d_ptr->scene);
+ QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+ if (painter == info->painter) {
+ scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, info->effectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ } else {
+ QTransform effectTransform = painter->worldTransform();
+ effectTransform *= info->painter->worldTransform().inverted();
+ if (info->effectTransform)
+ effectTransform *= *info->effectTransform;
+ scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ }
+}
+
+QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset) const
+{
+ const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
+ if (!info && deviceCoordinates) {
+ // Device coordinates without info not yet supported.
+ qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
+ return QPixmap();
+ }
+
+ if (!item->d_ptr->scene)
+ return QPixmap();
+ QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+
+ const QRectF sourceRect = boundingRect(system);
+ QRect effectRect = item->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect();
+ if (offset)
+ *offset = effectRect.topLeft();
+
+ if (deviceCoordinates) {
+ // Clip to viewport rect.
+ int left, top, right, bottom;
+ effectRect.getCoords(&left, &top, &right, &bottom);
+ if (left < 0) {
+ if (offset)
+ offset->rx() += -left;
+ effectRect.setX(0);
+ }
+ if (top < 0) {
+ if (offset)
+ offset->ry() += -top;
+ effectRect.setY(0);
+ }
+ // NB! We use +-1 for historical reasons (see QRect documentation).
+ if (right + 1 > info->widget->width())
+ effectRect.setRight(info->widget->width() - 1);
+ if (bottom + 1 > info->widget->height())
+ effectRect.setBottom(info->widget->height() -1);
+ }
+
+ if (effectRect.isEmpty())
+ return QPixmap();
+
+ QPixmap pixmap(effectRect.size());
+ pixmap.fill(Qt::transparent);
+ QPainter pixmapPainter(&pixmap);
+ pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing);
+
+ QTransform effectTransform = QTransform::fromTranslate(-effectRect.x(), -effectRect.y());
+ if (deviceCoordinates && info->effectTransform)
+ effectTransform *= *info->effectTransform;
+
+ if (!info) {
+ // Logical coordinates without info.
+ QTransform sceneTransform = item->sceneTransform();
+ QTransform newEffectTransform = sceneTransform.inverted();
+ newEffectTransform *= effectTransform;
+ scened->draw(item, &pixmapPainter, 0, &sceneTransform, 0, 0, qreal(1.0),
+ &newEffectTransform, false, true);
+ } else if (deviceCoordinates) {
+ // Device coordinates with info.
+ scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ } else {
+ // Item coordinates with info.
+ QTransform newEffectTransform = info->transformPtr->inverted();
+ newEffectTransform *= effectTransform;
+ scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion,
+ info->widget, info->opacity, &newEffectTransform, info->wasDirtySceneTransform,
+ info->drawItem);
+ }
+ return pixmap;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, QGraphicsItem *item)
{
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index 52b862e..216053d 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -62,6 +62,7 @@ QT_MODULE(Gui)
class QBrush;
class QCursor;
class QFocusEvent;
+class QGraphicsEffect;
class QGraphicsItemGroup;
class QGraphicsObject;
class QGraphicsSceneContextMenuEvent;
@@ -209,6 +210,10 @@ public:
qreal effectiveOpacity() const;
void setOpacity(qreal opacity);
+ // Effect
+ QGraphicsEffect *graphicsEffect() const;
+ void setGraphicsEffect(QGraphicsEffect *effect);
+
Qt::MouseButtons acceptedMouseButtons() const;
void setAcceptedMouseButtons(Qt::MouseButtons buttons);
@@ -446,6 +451,7 @@ private:
friend class QGraphicsSceneIndexPrivate;
friend class QGraphicsSceneBspTreeIndex;
friend class QGraphicsSceneBspTreeIndexPrivate;
+ friend class QGraphicsItemEffectSourcePrivate;
friend class QGraphicsTransformPrivate;
friend class ::tst_QGraphicsItem;
friend bool qt_closestLeaf(const QGraphicsItem *, const QGraphicsItem *);
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index a41cab5..77f203f 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -60,6 +60,8 @@
#include "qgraphicstransform.h"
#include "qgraphicstransform_p.h"
+#include <private/qgraphicseffect_p.h>
+
#include <QtCore/qpoint.h>
#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
@@ -121,6 +123,7 @@ public:
scene(0),
parent(0),
transformData(0),
+ graphicsEffect(0),
index(-1),
siblingIndex(-1),
itemDepth(-1),
@@ -165,6 +168,8 @@ public:
acceptedTouchBeginEvent(0),
filtersDescendantEvents(0),
sceneTransformTranslateOnly(0),
+ notifyBoundingRectChanged(0),
+ notifyInvalidated(0),
mouseSetsFocus(1),
globalStackingOrder(-1),
q_ptr(0)
@@ -218,6 +223,8 @@ public:
void childrenBoundingRectHelper(QTransform *x, QRectF *rect);
void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
const QRegion &exposedRegion, bool allItems = false) const;
+ QRectF effectiveBoundingRect() const;
+ QRectF sceneEffectiveBoundingRect() const;
virtual void resolveFont(uint inheritedMask)
{
@@ -418,6 +425,7 @@ public:
QList<QGraphicsItem *> children;
struct TransformData;
TransformData *transformData;
+ QGraphicsEffect *graphicsEffect;
QTransform sceneTransform;
int index;
int siblingIndex;
@@ -468,8 +476,10 @@ public:
quint32 acceptedTouchBeginEvent : 1;
quint32 filtersDescendantEvents : 1;
quint32 sceneTransformTranslateOnly : 1;
+ quint32 notifyBoundingRectChanged : 1;
+ quint32 notifyInvalidated : 1;
quint32 mouseSetsFocus : 1;
- quint32 unused : 3; // feel free to use
+ quint32 unused : 1; // feel free to use
// Optional stacking order
int globalStackingOrder;
@@ -516,6 +526,74 @@ struct QGraphicsItemPrivate::TransformData
}
};
+struct QGraphicsItemPaintInfo
+{
+ inline QGraphicsItemPaintInfo(const QTransform *const xform1, const QTransform *const xform2,
+ const QTransform *const xform3,
+ QRegion *r, QWidget *w, QStyleOptionGraphicsItem *opt,
+ QPainter *p, qreal o, bool b1, bool b2)
+ : viewTransform(xform1), transformPtr(xform2), effectTransform(xform3), exposedRegion(r), widget(w),
+ option(opt), painter(p), opacity(o), wasDirtySceneTransform(b1), drawItem(b2)
+ {}
+
+ const QTransform *viewTransform;
+ const QTransform *transformPtr;
+ const QTransform *effectTransform;
+ QRegion *exposedRegion;
+ QWidget *widget;
+ QStyleOptionGraphicsItem *option;
+ QPainter *painter;
+ qreal opacity;
+ quint32 wasDirtySceneTransform : 1;
+ quint32 drawItem : 1;
+};
+
+class QGraphicsItemEffectSourcePrivate : public QGraphicsEffectSourcePrivate
+{
+public:
+ QGraphicsItemEffectSourcePrivate(QGraphicsItem *i)
+ : QGraphicsEffectSourcePrivate(), item(i), info(0)
+ {}
+
+ inline void detach()
+ { item->setGraphicsEffect(0); }
+
+ inline const QGraphicsItem *graphicsItem() const
+ { return item; }
+
+ inline const QWidget *widget() const
+ { return 0; }
+
+ inline void update()
+ { item->update(); }
+
+ inline bool isPixmap() const
+ {
+ return (item->type() == QGraphicsPixmapItem::Type);
+ //|| (item->d_ptr->isObject && qobject_cast<QFxImage *>(q_func()));
+ }
+
+ inline const QStyleOption *styleOption() const
+ { return info ? info->option : 0; }
+
+ inline QRect deviceRect() const
+ {
+ if (!info || !info->widget) {
+ qWarning("QGraphicsEffectSource::deviceRect: Not yet implemented, lacking device context");
+ return QRect();
+ }
+ return info->widget->rect();
+ }
+
+ QRectF boundingRect(Qt::CoordinateSystem system) const;
+ void draw(QPainter *);
+ QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset) const;
+
+ QGraphicsItem *item;
+ QGraphicsItemPaintInfo *info;
+};
+
+
/*!
\internal
*/
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 7fa565d..33b2ecd 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -244,11 +244,13 @@
#include <QtGui/qtransform.h>
#include <QtGui/qgesture.h>
#include <QtGui/qinputcontext.h>
+#include <QtGui/qgraphicseffect.h>
#include <private/qapplication_p.h>
#include <private/qobject_p.h>
#ifdef Q_WS_X11
#include <private/qt_x11_p.h>
#endif
+#include <private/qgraphicseffect_p.h>
QT_BEGIN_NAMESPACE
@@ -4302,7 +4304,7 @@ void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const
void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter,
const QTransform *const viewTransform,
QRegion *exposedRegion, QWidget *widget,
- qreal parentOpacity)
+ qreal parentOpacity, const QTransform *const effectTransform)
{
Q_ASSERT(item);
@@ -4351,11 +4353,12 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
bool drawItem = itemHasContents && !itemIsFullyTransparent;
if (drawItem) {
- const QRectF brect = adjustedItemBoundingRect(item);
+ const QRectF brect = adjustedItemEffectiveBoundingRect(item);
ENSURE_TRANSFORM_PTR
QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect()
: transformPtr->mapRect(brect).toRect();
- item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
+ if (widget)
+ item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
viewBoundingRect.adjust(-1, -1, 1, 1);
drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty();
if (!drawItem) {
@@ -4369,14 +4372,51 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
}
} // else we know for sure this item has children we must process.
+ if (itemHasChildren && itemClipsChildrenToShape)
+ ENSURE_TRANSFORM_PTR;
+
+ if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) {
+ ENSURE_TRANSFORM_PTR;
+ QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp,
+ painter, opacity, wasDirtyParentSceneTransform, drawItem);
+ QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source;
+ QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *>
+ (source->d_func());
+ sourced->info = &info;
+ const QTransform restoreTransform = painter->worldTransform();
+ if (effectTransform)
+ painter->setWorldTransform(*transformPtr * *effectTransform);
+ else
+ painter->setWorldTransform(*transformPtr);
+ item->d_ptr->graphicsEffect->draw(painter, source);
+ painter->setWorldTransform(restoreTransform);
+ sourced->info = 0;
+ } else {
+ draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity,
+ effectTransform, wasDirtyParentSceneTransform, drawItem);
+ }
+}
+
+void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
+ const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
+ qreal opacity, const QTransform *effectTransform,
+ bool wasDirtyParentSceneTransform, bool drawItem)
+{
+ const bool itemIsFullyTransparent = (opacity < 0.0001);
+ const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
+ const bool itemHasChildren = !item->d_ptr->children.isEmpty();
+
int i = 0;
if (itemHasChildren) {
item->d_ptr->ensureSortedChildren();
if (itemClipsChildrenToShape) {
painter->save();
- ENSURE_TRANSFORM_PTR
- painter->setWorldTransform(*transformPtr);
+ Q_ASSERT(transformPtr);
+ if (effectTransform)
+ painter->setWorldTransform(*transformPtr * *effectTransform);
+ else
+ painter->setWorldTransform(*transformPtr);
painter->setClipPath(item->shape(), Qt::IntersectClip);
}
@@ -4389,15 +4429,15 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
break;
if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
continue;
- drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity);
+ drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
}
}
// Draw item
if (drawItem) {
Q_ASSERT(!itemIsFullyTransparent);
- Q_ASSERT(itemHasContents);
- ENSURE_TRANSFORM_PTR
+ Q_ASSERT(!(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents));
+ Q_ASSERT(transformPtr);
item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion
? *exposedRegion : QRegion(), exposedRegion == 0);
@@ -4406,8 +4446,12 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
if (savePainter)
painter->save();
- if (!itemHasChildren || !itemClipsChildrenToShape)
- painter->setWorldTransform(*transformPtr);
+ if (!itemHasChildren || !itemClipsChildrenToShape) {
+ if (effectTransform)
+ painter->setWorldTransform(*transformPtr * *effectTransform);
+ else
+ painter->setWorldTransform(*transformPtr);
+ }
if (itemClipsToShape)
painter->setClipPath(item->shape(), Qt::IntersectClip);
@@ -4430,7 +4474,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
child->d_ptr->dirtySceneTransform = 1;
if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
continue;
- drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity);
+ drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
}
}
@@ -4513,8 +4557,12 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b
item->d_ptr->ignoreOpacity = 1;
QGraphicsItem *p = item->d_ptr->parent;
- while (p && !p->d_ptr->dirtyChildren) {
+ while (p) {
p->d_ptr->dirtyChildren = 1;
+ if (p->d_ptr->graphicsEffect && p->d_ptr->graphicsEffect->isEnabled()) {
+ p->d_ptr->dirty = 1;
+ p->d_ptr->fullUpdatePending = 1;
+ }
p = p->d_ptr->parent;
}
}
@@ -4623,7 +4671,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
// Process item.
if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
const bool useCompatUpdate = views.isEmpty() || isSignalConnected(changedSignalIndex);
- const QRectF itemBoundingRect = adjustedItemBoundingRect(item);
+ const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item);
if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
// This block of code is kept for compatibility. Since 4.5, by default
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
index 0ef9f04..26cb1c2 100644
--- a/src/gui/graphicsview/qgraphicsscene.h
+++ b/src/gui/graphicsview/qgraphicsscene.h
@@ -302,10 +302,12 @@ private:
friend class QGraphicsViewPrivate;
friend class QGraphicsWidget;
friend class QGraphicsWidgetPrivate;
+ friend class QGraphicsEffect;
friend class QGraphicsSceneIndex;
friend class QGraphicsSceneIndexPrivate;
friend class QGraphicsSceneBspTreeIndex;
friend class QGraphicsSceneBspTreeIndexPrivate;
+ friend class QGraphicsItemEffectSourcePrivate;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsScene::SceneLayers)
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index f1ddb5a..4b8791e 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -202,7 +202,11 @@ public:
QRegion *exposedRegion, QWidget *widget);
void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform *const,
- QRegion *exposedRegion, QWidget *widget, qreal parentOpacity = qreal(1.0));
+ QRegion *exposedRegion, QWidget *widget, qreal parentOpacity = qreal(1.0),
+ const QTransform *const effectTransform = 0);
+ void draw(QGraphicsItem *, QPainter *, const QTransform *const, const QTransform *const,
+ QRegion *, QWidget *, qreal, const QTransform *const, bool, bool);
+
void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false,
bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false,
bool removingItemFromScene = false);
@@ -223,10 +227,21 @@ public:
item->d_ptr->fullUpdatePending = 0;
item->d_ptr->ignoreVisible = 0;
item->d_ptr->ignoreOpacity = 0;
+ QGraphicsEffect::ChangeFlags flags;
+ if (item->d_ptr->notifyBoundingRectChanged) {
+ flags |= QGraphicsEffect::SourceBoundingRectChanged;
+ item->d_ptr->notifyBoundingRectChanged = 0;
+ }
+ if (item->d_ptr->notifyInvalidated) {
+ flags |= QGraphicsEffect::SourceInvalidated;
+ item->d_ptr->notifyInvalidated = 0;
+ }
if (recursive) {
for (int i = 0; i < item->d_ptr->children.size(); ++i)
resetDirtyItem(item->d_ptr->children.at(i), recursive);
}
+ if (flags && item->d_ptr->graphicsEffect)
+ item->d_ptr->graphicsEffect->sourceChanged(flags);
}
inline void ensureSortedTopLevelItems()
@@ -280,6 +295,14 @@ static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item)
return boundingRect;
}
+static inline QRectF adjustedItemEffectiveBoundingRect(const QGraphicsItem *item)
+{
+ Q_ASSERT(item);
+ QRectF boundingRect(QGraphicsItemPrivate::get(item)->effectiveBoundingRect());
+ _q_adjustRect(&boundingRect);
+ return boundingRect;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp
index a80cdca..fcd127a 100644
--- a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp
+++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp
@@ -172,7 +172,7 @@ void QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex()
if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
continue;
- bsp.insertItem(item, item->sceneBoundingRect());
+ bsp.insertItem(item, item->d_ptr->sceneEffectiveBoundingRect());
}
}
unindexedItems.clear();
@@ -352,7 +352,7 @@ void QGraphicsSceneBspTreeIndexPrivate::removeItem(QGraphicsItem *item, bool rec
purgePending = true;
removedItems << item;
} else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
- bsp.removeItem(item, item->sceneBoundingRect());
+ bsp.removeItem(item, item->d_ptr->sceneEffectiveBoundingRect());
}
} else {
unindexedItems.removeOne(item);
diff --git a/src/gui/gui.pro b/src/gui/gui.pro
index a49d680..90ac3ce 100644
--- a/src/gui/gui.pro
+++ b/src/gui/gui.pro
@@ -34,6 +34,7 @@ include(graphicsview/graphicsview.pri)
include(util/util.pri)
include(statemachine/statemachine.pri)
include(math3d/math3d.pri)
+include(effects/effects.pri)
contains(QT_CONFIG, egl): include(egl/egl.pri)
diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp
index 968ecd7..0bb948b 100644
--- a/src/gui/image/qpixmapfilter.cpp
+++ b/src/gui/image/qpixmapfilter.cpp
@@ -93,6 +93,9 @@ public:
\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.
@@ -475,6 +478,227 @@ void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const Q
}
}
+/*!
+ \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 the 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), quality(Qt::FastTransformation) {}
+
+ int radius;
+ Qt::TransformationMode quality;
+};
+
+
+/*!
+ 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(int radius)
+{
+ Q_D(QPixmapBlurFilter);
+ d->radius = radius;
+}
+
+/*!
+ Gets the radius of the blur filter.
+
+ \internal
+*/
+int QPixmapBlurFilter::radius() const
+{
+ Q_D(const QPixmapBlurFilter);
+ return d->radius;
+}
+
+/*!
+ Setting the quality to FastTransformation causes the implementation
+ to trade off visual quality to blur the image faster. Setting the
+ quality to SmoothTransformation causes the implementation to improve
+ visual quality at the expense of speed. The implementation is free
+ to ignore this value if it only has a single blur algorithm.
+
+ \internal
+*/
+void QPixmapBlurFilter::setQuality(Qt::TransformationMode quality)
+{
+ Q_D(QPixmapBlurFilter);
+ d->quality = quality;
+}
+
+/*!
+ Gets the quality of the blur filter.
+
+ \internal
+*/
+Qt::TransformationMode QPixmapBlurFilter::quality() const
+{
+ Q_D(const QPixmapBlurFilter);
+ return d->quality;
+}
+
+/*!
+ \reimp
+
+ \internal
+*/
+QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const
+{
+ Q_D(const QPixmapBlurFilter);
+ const qreal delta = d->radius * 2;
+ return rect.adjusted(-delta, -delta, delta, delta);
+}
+
+// Blur the image according to the blur radius
+// Based on exponential blur algorithm by Jani Huhtanen
+// (maximum radius is set to 16)
+static QImage blurred(const QImage& image, const QRect& rect, int radius)
+{
+ int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
+ int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
+
+ QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ int r1 = rect.top();
+ int r2 = rect.bottom();
+ int c1 = rect.left();
+ int c2 = rect.right();
+
+ int bpl = result.bytesPerLine();
+ int rgba[4];
+ unsigned char* p;
+
+ for (int col = c1; col <= c2; col++) {
+ p = result.scanLine(r1) + col * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p += bpl;
+ for (int j = r1; j < r2; j++, p += bpl)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ for (int row = r1; row <= r2; row++) {
+ p = result.scanLine(row) + c1 * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p += 4;
+ for (int j = c1; j < c2; j++, p += 4)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ for (int col = c1; col <= c2; col++) {
+ p = result.scanLine(r2) + col * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p -= bpl;
+ for (int j = r1; j < r2; j++, p -= bpl)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ for (int row = r1; row <= r2; row++) {
+ p = result.scanLine(row) + c2 * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p -= 4;
+ for (int j = c1; j < c2; j++, p -= 4)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ return result;
+}
+
+/*!
+ \reimp
+
+ \internal
+*/
+void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &srcRect) const
+{
+ Q_D(const QPixmapBlurFilter);
+ if (!painter->isActive())
+ return;
+
+ if (d->radius == 0) {
+ painter->drawPixmap(srcRect.translated(p), src, srcRect);
+ return;
+ }
+
+ QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
+ static_cast<QPaintEngineEx *>(painter->paintEngine())->createPixmapFilter(type()) : 0;
+ QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter);
+ if (blurFilter) {
+ blurFilter->setRadius(d->radius);
+ blurFilter->setQuality(d->quality);
+ blurFilter->draw(painter, p, src, srcRect);
+ delete blurFilter;
+ return;
+ }
+
+ QImage srcImage;
+ QImage destImage;
+
+ if (srcRect.isNull()) {
+ srcImage = src.toImage();
+ destImage = blurred(srcImage, srcImage.rect(), d->radius);
+ } else {
+ QRect rect = srcRect.toAlignedRect().intersected(src.rect());
+
+ srcImage = src.copy(rect).toImage();
+ destImage = blurred(srcImage, srcImage.rect(), d->radius);
+ }
+
+ painter->drawImage(p, destImage);
+}
+
// 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.
@@ -626,16 +850,11 @@ class QPixmapDropShadowFilterPrivate : public QPixmapFilterPrivate
{
public:
QPixmapDropShadowFilterPrivate()
- : offset(8, 8),
- radius(1),
- color(63, 63, 63, 255) {
- }
+ : offset(8, 8), color(63, 63, 63, 180), blurFilter(new QPixmapBlurFilter) {}
QPointF offset;
- qreal radius;
QColor color;
-
- QPixmapConvolutionFilter *convolution;
+ QPixmapBlurFilter *blurFilter;
};
/*!
@@ -680,9 +899,7 @@ QPixmapDropShadowFilter::QPixmapDropShadowFilter(QObject *parent)
: QPixmapFilter(*new QPixmapDropShadowFilterPrivate, DropShadowFilter, parent)
{
Q_D(QPixmapDropShadowFilter);
- d->convolution = new QPixmapConvolutionFilter;
-
- setBlurRadius(1);
+ d->blurFilter->setRadius(1);
}
/*!
@@ -693,7 +910,7 @@ QPixmapDropShadowFilter::QPixmapDropShadowFilter(QObject *parent)
QPixmapDropShadowFilter::~QPixmapDropShadowFilter()
{
Q_D(QPixmapDropShadowFilter);
- delete d->convolution;
+ delete d->blurFilter;
}
/*!
@@ -705,10 +922,10 @@ QPixmapDropShadowFilter::~QPixmapDropShadowFilter()
\internal
*/
-qreal QPixmapDropShadowFilter::blurRadius() const
+int QPixmapDropShadowFilter::blurRadius() const
{
Q_D(const QPixmapDropShadowFilter);
- return d->radius;
+ return d->blurFilter->radius();
}
/*!
@@ -720,18 +937,10 @@ qreal QPixmapDropShadowFilter::blurRadius() const
\internal
*/
-void QPixmapDropShadowFilter::setBlurRadius(qreal radius)
+void QPixmapDropShadowFilter::setBlurRadius(int radius)
{
Q_D(QPixmapDropShadowFilter);
-
- d->radius = radius;
-
- int dim = 2 * qRound(radius) + 1;
- QVarLengthArray<qreal> arr(dim * dim);
- qreal f = 1 / qreal(dim * dim);
- for (int i = 0; i < dim * dim; ++i)
- arr[i] = f;
- d->convolution->setConvolutionKernel(arr.data(), dim, dim);
+ d->blurFilter->setRadius(radius);
}
/*!
@@ -805,10 +1014,11 @@ QRectF QPixmapDropShadowFilter::boundingRectFor(const QRectF &rect) const
{
Q_D(const QPixmapDropShadowFilter);
- qreal x1 = qMin(rect.left(), rect.left() + d->offset.x() - d->radius);
- qreal y1 = qMin(rect.top(), rect.top() + d->offset.y() - d->radius);
- qreal x2 = qMax(rect.right(), rect.right() + d->offset.x() + d->radius);
- qreal y2 = qMax(rect.bottom(), rect.bottom() + d->offset.y() + d->radius);
+ const qreal delta = qreal(d->blurFilter->radius() * 2);
+ qreal x1 = qMin(rect.left(), rect.left() + d->offset.x() - delta);
+ qreal y1 = qMin(rect.top(), rect.top() + d->offset.y() - delta);
+ qreal x2 = qMax(rect.right(), rect.right() + d->offset.x() + delta);
+ qreal y2 = qMax(rect.bottom(), rect.bottom() + d->offset.y() + delta);
return QRectF(x1, y1, x2 - x1, y2 - y1);
}
@@ -823,7 +1033,7 @@ void QPixmapDropShadowFilter::draw(QPainter *p,
{
Q_D(const QPixmapDropShadowFilter);
- QPixmap tmp = src.isNull() ? px : px.copy(src.toRect());
+ QImage tmp = src.isNull() ? px : px.copy(src.toRect()).toImage();
QPainter tmpPainter(&tmp);
// blacken the image...
@@ -831,10 +1041,13 @@ void QPixmapDropShadowFilter::draw(QPainter *p,
tmpPainter.fillRect(0, 0, tmp.width(), tmp.height(), d->color);
tmpPainter.end();
+ const QPixmap pixTmp = QPixmap::fromImage(tmp);
+
// draw the blurred drop shadow...
- d->convolution->draw(p, pos + d->offset, tmp);
+ d->blurFilter->draw(p, pos + d->offset, pixTmp);
// Draw the actual pixmap...
p->drawPixmap(pos, px, src);
}
+
QT_END_NAMESPACE
diff --git a/src/gui/image/qpixmapfilter_p.h b/src/gui/image/qpixmapfilter_p.h
index b8588bd..29d919d 100644
--- a/src/gui/image/qpixmapfilter_p.h
+++ b/src/gui/image/qpixmapfilter_p.h
@@ -78,6 +78,7 @@ public:
ConvolutionFilter,
ColorizeFilter,
DropShadowFilter,
+ BlurFilter,
UserFilter = 1024
};
@@ -117,6 +118,30 @@ private:
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(int radius);
+ void setQuality(Qt::TransformationMode mode);
+
+ int radius() const;
+ Qt::TransformationMode quality() 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
@@ -147,8 +172,8 @@ public:
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);
+ int blurRadius() const;
+ void setBlurRadius(int radius);
QColor color() const;
void setColor(const QColor &color);
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 515eed9..6928761 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -182,6 +182,7 @@ QWidgetPrivate::QWidgetPrivate(int version)
, widgetItem(0)
, extraPaintEngine(0)
, polished(0)
+ , graphicsEffect(0)
, inheritedFontResolveMask(0)
, inheritedPaletteResolveMask(0)
, leftmargin(0)
@@ -237,6 +238,8 @@ QWidgetPrivate::~QWidgetPrivate()
if (extra)
deleteExtra();
+
+ delete graphicsEffect;
}
QWindowSurface *QWidgetPrivate::createDefaultWindowSurface()
@@ -1548,9 +1551,9 @@ bool QWidgetPrivate::isOverlapped(const QRect &rect) const
continue;
}
- if (qRectIntersects(sibling->data->crect, r)) {
+ if (qRectIntersects(sibling->d_func()->effectiveRectFor(sibling->data->crect), r)) {
const QWExtra *siblingExtra = sibling->d_func()->extra;
- if (siblingExtra && siblingExtra->hasMask
+ if (siblingExtra && siblingExtra->hasMask && !sibling->d_func()->graphicsEffect
&& !siblingExtra->mask.translated(sibling->data->crect.topLeft()).intersects(r)) {
continue;
}
@@ -1649,7 +1652,7 @@ QRect QWidgetPrivate::clipRect() const
const QWidget * w = q;
if (!w->isVisible())
return QRect();
- QRect r = q->rect();
+ QRect r = effectiveRectFor(q->rect());
int ox = 0;
int oy = 0;
while (w
@@ -1791,12 +1794,14 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
break;
QWidgetPrivate *pd = w->parentWidget()->d_func();
const int myIndex = pd->children.indexOf(const_cast<QWidget *>(w));
+ const QRect widgetGeometry = w->d_func()->effectiveRectFor(w->data->crect);
for (int i = myIndex + 1; i < pd->children.size(); ++i) {
QWidget *sibling = qobject_cast<QWidget *>(pd->children.at(i));
if (!sibling || !sibling->isVisible() || sibling->isWindow())
continue;
- if (!qRectIntersects(sibling->data->crect, w->data->crect))
+ const QRect siblingGeometry = sibling->d_func()->effectiveRectFor(sibling->data->crect);
+ if (!qRectIntersects(siblingGeometry, widgetGeometry))
continue;
if (dirtyClipBoundingRect) {
@@ -1804,7 +1809,7 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
dirtyClipBoundingRect = false;
}
- if (!qRectIntersects(sibling->data->crect, clipBoundingRect.translated(parentOffset)))
+ if (!qRectIntersects(siblingGeometry, clipBoundingRect.translated(parentOffset)))
continue;
if (dirtyParentClip) {
@@ -1816,7 +1821,8 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
const QRect siblingClipRect(sibling->d_func()->clipRect());
QRegion siblingDirty(parentClip);
siblingDirty &= (siblingClipRect.translated(siblingPos));
- const bool hasMask = sibling->d_func()->extra && sibling->d_func()->extra->hasMask;
+ const bool hasMask = sibling->d_func()->extra && sibling->d_func()->extra->hasMask
+ && !sibling->d_func()->graphicsEffect;
if (hasMask)
siblingDirty &= sibling->d_func()->extra->mask.translated(siblingPos);
if (siblingDirty.isEmpty())
@@ -1827,7 +1833,7 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
siblingDirty.translate(-parentOffset);
sourceRegion -= siblingDirty;
} else {
- sourceRegion -= sibling->data->crect.translated(-parentOffset);
+ sourceRegion -= siblingGeometry.translated(-parentOffset);
}
} else {
if (hasDirtySiblingsAbove)
@@ -1858,6 +1864,11 @@ void QWidgetPrivate::clipToEffectiveMask(QRegion &region) const
const QWidget *w = q;
QPoint offset;
+ if (graphicsEffect) {
+ w = q->parentWidget();
+ offset -= data.crect.topLeft();
+ }
+
while (w) {
const QWidgetPrivate *wd = w->d_func();
if (wd->extra && wd->extra->hasMask)
@@ -1891,6 +1902,12 @@ void QWidgetPrivate::updateIsOpaque()
// hw: todo: only needed if opacity actually changed
setDirtyOpaqueRegion();
+ if (graphicsEffect) {
+ // ### We should probably add QGraphicsEffect::isOpaque at some point.
+ setOpaque(false);
+ return;
+ }
+
Q_Q(QWidget);
#ifdef Q_WS_X11
if (q->testAttribute(Qt::WA_X11OpenGLOverlay)) {
@@ -4847,6 +4864,54 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
d->extra->inRenderWithPainter = false;
}
+QGraphicsEffect *QWidget::graphicsEffect() const
+{
+ Q_D(const QWidget);
+ return d->graphicsEffect;
+}
+
+/*!
+ Sets \a effect as the widget's effect. If there already is an effect installed
+ on this widget, QWidget will delete the existing effect before installing
+ the new \a effect.
+
+ If \a effect is the installed on a different widget, setGraphicsEffect() will remove
+ the effect from the widget and install it on this widget.
+
+ \note This function will apply the effect on itself and all its children.
+
+ \since 4.6
+*/
+void QWidget::setGraphicsEffect(QGraphicsEffect *effect)
+{
+ Q_D(QWidget);
+ if (d->graphicsEffect == effect)
+ return;
+
+ if (d->graphicsEffect && effect) {
+ delete d->graphicsEffect;
+ d->graphicsEffect = 0;
+ }
+
+ if (!effect) {
+ // Unset current effect.
+ QGraphicsEffectPrivate *oldEffectPrivate = d->graphicsEffect->d_func();
+ d->graphicsEffect = 0;
+ if (oldEffectPrivate) {
+ oldEffectPrivate->setGraphicsEffectSource(0); // deletes the current source.
+ }
+ } else {
+ // Set new effect.
+ QGraphicsEffectSourcePrivate *sourced = new QWidgetEffectSourcePrivate(this);
+ QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced);
+ d->graphicsEffect = effect;
+ effect->d_func()->setGraphicsEffectSource(source);
+ }
+
+ d->updateIsOpaque();
+ update();
+}
+
bool QWidgetPrivate::isAboutToShow() const
{
if (data.in_show)
@@ -4991,6 +5056,33 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
return;
Q_Q(QWidget);
+ if (graphicsEffect && graphicsEffect->isEnabled()) {
+ QGraphicsEffectSource *source = graphicsEffect->d_func()->source;
+ QWidgetEffectSourcePrivate *sourced = static_cast<QWidgetEffectSourcePrivate *>
+ (source->d_func());
+ if (!sourced->context) {
+ QWidgetPaintContext context(pdev, rgn, offset, flags, sharedPainter, backingStore);
+ sourced->context = &context;
+ if (!sharedPainter) {
+ QPaintEngine *paintEngine = pdev->paintEngine();
+ paintEngine->d_func()->systemClip = rgn.translated(offset);
+ QPainter p(pdev);
+ p.translate(offset);
+ context.painter = &p;
+ graphicsEffect->draw(&p, source);
+ paintEngine->d_func()->systemClip = QRegion();
+ } else {
+ context.painter = sharedPainter;
+ sharedPainter->save();
+ sharedPainter->translate(offset);
+ graphicsEffect->draw(sharedPainter, source);
+ sharedPainter->restore();
+ }
+ sourced->context = 0;
+ return;
+ }
+ }
+
const bool asRoot = flags & DrawAsRoot;
const bool alsoOnScreen = flags & DrawPaintOnScreen;
const bool recursive = flags & DrawRecursive;
@@ -5023,7 +5115,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
if (sharedPainter)
paintEngine->d_func()->systemClip = toBePainted;
else
- paintEngine->setSystemRect(q->data->crect);
+ paintEngine->d_func()->systemRect = q->data->crect;
//paint the background
if ((asRoot || q->autoFillBackground() || onScreen || q->testAttribute(Qt::WA_StyledBackground))
@@ -5062,7 +5154,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
if (paintEngine) {
restoreRedirected();
if (!sharedPainter)
- paintEngine->setSystemRect(QRect());
+ paintEngine->d_func()->systemRect = QRect();
else
paintEngine->d_func()->currentClipWidget = 0;
paintEngine->d_func()->systemClip = QRegion();
@@ -5125,7 +5217,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
dirtyBoundingRect = false;
}
- if (qRectIntersects(boundingRect, x->data->crect)) {
+ if (qRectIntersects(boundingRect, x->d_func()->effectiveRectFor(x->data->crect))) {
#ifdef Q_BACKINGSTORE_SUBSURFACES
if (x->windowSurface() == currentSurface)
#endif
@@ -5143,7 +5235,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
QWidgetPrivate *wd = w->d_func();
const QPoint widgetPos(w->data->crect.topLeft());
- const bool hasMask = wd->extra && wd->extra->hasMask;
+ const bool hasMask = wd->extra && wd->extra->hasMask && !wd->graphicsEffect;
if (index > 0) {
QRegion wr(rgn);
@@ -5158,7 +5250,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
if (w->updatesEnabled() && (!w->d_func()->extra || !w->d_func()->extra->proxyWidget)) {
QRegion wRegion(rgn);
- wRegion &= w->data->crect;
+ wRegion &= wd->effectiveRectFor(w->data->crect);
wRegion.translate(-widgetPos);
if (hasMask)
wRegion &= wd->extra->mask;
@@ -5166,6 +5258,93 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
}
}
+QRectF QWidgetEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const
+{
+ if (system != Qt::DeviceCoordinates)
+ return m_widget->rect();
+
+ if (!context) {
+ // Device coordinates without context not yet supported.
+ qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context");
+ return QRectF();
+ }
+
+ return context->painter->worldTransform().mapRect(m_widget->rect());
+}
+
+void QWidgetEffectSourcePrivate::draw(QPainter *painter)
+{
+ if (!context || context->painter != painter) {
+ m_widget->render(painter);
+ return;
+ }
+
+ // The region saved in the context is neither clipped to the rect
+ // nor the mask, so we have to clip it here before calling drawWidget.
+ QRegion toBePainted = context->rgn;
+ toBePainted &= m_widget->rect();
+ QWidgetPrivate *wd = qt_widget_private(m_widget);
+ if (wd->extra && wd->extra->hasMask)
+ toBePainted &= wd->extra->mask;
+
+ wd->drawWidget(context->pdev, toBePainted, context->offset, context->flags,
+ context->sharedPainter, context->backingStore);
+}
+
+QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset) const
+{
+ const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
+ if (!context && deviceCoordinates) {
+ // Device coordinates without context not yet supported.
+ qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
+ return QPixmap();
+ }
+
+ QPoint pixmapOffset;
+ QRectF sourceRect = m_widget->rect();
+
+ if (deviceCoordinates) {
+ const QTransform &painterTransform = context->painter->worldTransform();
+ sourceRect = painterTransform.mapRect(sourceRect);
+ pixmapOffset = painterTransform.map(pixmapOffset);
+ }
+
+ QRect effectRect = m_widget->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect();
+ if (offset)
+ *offset = effectRect.topLeft();
+
+ if (deviceCoordinates) {
+ // Clip to device rect.
+ int left, top, right, bottom;
+ effectRect.getCoords(&left, &top, &right, &bottom);
+ if (left < 0) {
+ if (offset)
+ offset->rx() += -left;
+ effectRect.setX(0);
+ }
+ if (top < 0) {
+ if (offset)
+ offset->ry() += -top;
+ effectRect.setY(0);
+ }
+ // NB! We use +-1 for historical reasons (see QRect documentation).
+ QPaintDevice *device = context->painter->device();
+ const int deviceWidth = device->width();
+ const int deviceHeight = device->height();
+ if (right + 1 > deviceWidth)
+ effectRect.setRight(deviceWidth - 1);
+ if (bottom + 1 > deviceHeight)
+ effectRect.setBottom(deviceHeight -1);
+ }
+
+ pixmapOffset -= effectRect.topLeft();
+
+ QPixmap pixmap(effectRect.size());
+ pixmap.fill(Qt::transparent);
+ m_widget->render(&pixmap, pixmapOffset);
+ return pixmap;
+}
+
/*!
\internal
diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h
index 6f30883..4f14a53 100644
--- a/src/gui/kernel/qwidget.h
+++ b/src/gui/kernel/qwidget.h
@@ -96,6 +96,7 @@ class QWindowSurface;
class QLocale;
class QGraphicsProxyWidget;
class QGestureManager;
+class QGraphicsEffect;
#if defined(Q_WS_X11)
class QX11Info;
#endif
@@ -352,6 +353,9 @@ public:
const QRegion &sourceRegion = QRegion(),
RenderFlags renderFlags = RenderFlags(DrawWindowBackground | DrawChildren));
+ QGraphicsEffect *graphicsEffect() const;
+ void setGraphicsEffect(QGraphicsEffect *effect);
+
public Q_SLOTS:
void setWindowTitle(const QString &);
#ifndef QT_NO_STYLE_STYLESHEET
diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm
index 71571e4..3ccb7c2 100644
--- a/src/gui/kernel/qwidget_mac.mm
+++ b/src/gui/kernel/qwidget_mac.mm
@@ -2567,7 +2567,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
{
Q_D(QWidget);
if (!isWindow() && parentWidget())
- parentWidget()->d_func()->invalidateBuffer(geometry());
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
d->deactivateWidgetCleanup();
qt_mac_event_release(this);
if(testAttribute(Qt::WA_WState_Created)) {
@@ -2669,7 +2669,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
OSViewRef old_id = 0;
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
- q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
// Maintain the glWidgets list on parent change: remove "our" gl widgets
// from the list on the old parent and grandparents.
@@ -4165,12 +4165,12 @@ void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isM
setWSGeometry(false, oldRect);
if (isResize && QApplicationPrivate::graphicsSystem()) {
invalidateBuffer(q->rect());
- if (extra && !extra->mask.isEmpty()) {
+ if (extra && !graphicsEffect && !extra->mask.isEmpty()) {
QRegion oldRegion(extra->mask.translated(oldp));
oldRegion &= oldRect;
q->parentWidget()->d_func()->invalidateBuffer(oldRegion);
} else {
- q->parentWidget()->d_func()->invalidateBuffer(oldRect);
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(oldRect));
}
}
}
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index a3f4f6f..69fcbbc 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -61,6 +61,7 @@
#include "QtGui/qregion.h"
#include "QtGui/qsizepolicy.h"
#include "QtGui/qstyle.h"
+#include <private/qgraphicseffect_p.h>
#ifdef Q_WS_WIN
#include "QtCore/qt_windows.h"
@@ -443,6 +444,13 @@ public:
return extra ? extra->nativeChildrenForced : false;
}
+ inline QRect effectiveRectFor(const QRect &rect) const
+ {
+ if (graphicsEffect && graphicsEffect->isEnabled())
+ return graphicsEffect->boundingRectFor(rect).toAlignedRect();
+ return rect;
+ }
+
QSize adjustedSize() const;
#ifndef Q_WS_QWS // Almost cross-platform :-)
@@ -473,6 +481,7 @@ public:
QWidgetItemV2 *widgetItem;
QPaintEngine *extraPaintEngine;
mutable const QMetaObject *polished;
+ QGraphicsEffect *graphicsEffect;
// All widgets are initially added into the uncreatedWidgets set. Once
// they receive a window id they are removed and added to the mapper
static QWidgetMapper *mapper;
@@ -642,6 +651,57 @@ public:
#endif
};
+struct QWidgetPaintContext
+{
+ inline QWidgetPaintContext(QPaintDevice *d, const QRegion &r, const QPoint &o, int f,
+ QPainter *p, QWidgetBackingStore *b)
+ : pdev(d), rgn(r), offset(o), flags(f), sharedPainter(p), backingStore(b), painter(0) {}
+
+ QPaintDevice *pdev;
+ QRegion rgn;
+ QPoint offset;
+ int flags;
+ QPainter *sharedPainter;
+ QWidgetBackingStore *backingStore;
+ QPainter *painter;
+};
+
+class QWidgetEffectSourcePrivate : public QGraphicsEffectSourcePrivate
+{
+public:
+ QWidgetEffectSourcePrivate(QWidget *widget)
+ : QGraphicsEffectSourcePrivate(), m_widget(widget), context(0)
+ {}
+
+ inline void detach()
+ { m_widget->setGraphicsEffect(0); }
+
+ inline const QGraphicsItem *graphicsItem() const
+ { return 0; }
+
+ inline const QWidget *widget() const
+ { return m_widget; }
+
+ inline void update()
+ { m_widget->update(); }
+
+ inline bool isPixmap() const
+ { return false; }
+
+ inline const QStyleOption *styleOption() const
+ { return 0; }
+
+ inline QRect deviceRect() const
+ { return m_widget->window()->rect(); }
+
+ QRectF boundingRect(Qt::CoordinateSystem system) const;
+ void draw(QPainter *p);
+ QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset) const;
+
+ QWidget *m_widget;
+ QWidgetPaintContext *context;
+};
+
inline QWExtra *QWidgetPrivate::extraData() const
{
return extra;
diff --git a/src/gui/kernel/qwidget_qws.cpp b/src/gui/kernel/qwidget_qws.cpp
index 9fad9bf..dda5e2b 100644
--- a/src/gui/kernel/qwidget_qws.cpp
+++ b/src/gui/kernel/qwidget_qws.cpp
@@ -258,7 +258,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
Q_D(QWidget);
if (!isWindow() && parentWidget())
- parentWidget()->d_func()->invalidateBuffer(geometry());
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
d->deactivateWidgetCleanup();
if (testAttribute(Qt::WA_WState_Created)) {
@@ -312,7 +312,7 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
Q_Q(QWidget);
bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
- q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
#ifndef QT_NO_CURSOR
QCursor oldcurs;
bool setcurs=q->testAttribute(Qt::WA_SetCursor);
@@ -808,7 +808,7 @@ void QWidgetPrivate::lower_sys()
QWSChangeAltitudeCommand::Lower);
} else if (QWidget *p = q->parentWidget()) {
setDirtyOpaqueRegion();
- p->d_func()->invalidateBuffer(q->geometry());
+ p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
}
}
@@ -817,7 +817,7 @@ void QWidgetPrivate::stackUnder_sys(QWidget*)
Q_Q(QWidget);
if (QWidget *p = q->parentWidget()) {
setDirtyOpaqueRegion();
- p->d_func()->invalidateBuffer(q->geometry());
+ p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
}
}
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index ef0fe6a..b55f5a6 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -535,7 +535,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
{
Q_D(QWidget);
if (!isWindow() && parentWidget())
- parentWidget()->d_func()->invalidateBuffer(geometry());
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
d->deactivateWidgetCleanup();
if (testAttribute(Qt::WA_WState_Created)) {
setAttribute(Qt::WA_WState_Created, false);
@@ -597,7 +597,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
Q_Q(QWidget);
bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
- q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
WId old_winid = data.winid;
// hide and reparent our own window away. Otherwise we might get
diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp
index de38b4c..a4ee21b 100644
--- a/src/gui/kernel/qwidget_x11.cpp
+++ b/src/gui/kernel/qwidget_x11.cpp
@@ -971,7 +971,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
{
Q_D(QWidget);
if (!isWindow() && parentWidget())
- parentWidget()->d_func()->invalidateBuffer(geometry());
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
d->deactivateWidgetCleanup();
if (testAttribute(Qt::WA_WState_Created)) {
setAttribute(Qt::WA_WState_Created, false);
@@ -1050,7 +1050,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
QTLWExtra *topData = maybeTopData();
bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
- q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
extern void qPRCreate(const QWidget *, Window);
#ifndef QT_NO_CURSOR
QCursor oldcurs;
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index fdbdef0..1c31e33 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -559,7 +559,8 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
}
const QPoint offset = widget->mapTo(tlw, QPoint());
- if (qt_region_strictContains(dirty, widget->rect().translated(offset))) {
+ const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect());
+ if (qt_region_strictContains(dirty, widgetRect.translated(offset))) {
if (updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
return; // Already dirty.
@@ -567,7 +568,10 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
if (invalidateBuffer) {
const bool eventAlreadyPosted = !dirty.isEmpty();
- dirty += rgn.translated(offset);
+ if (widget->d_func()->graphicsEffect)
+ dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset);
+ else
+ dirty += rgn.translated(offset);
if (!eventAlreadyPosted || updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
return;
@@ -580,8 +584,12 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
}
if (widget->d_func()->inDirtyList) {
- if (!qt_region_strictContains(widget->d_func()->dirty, widget->rect()))
- widget->d_func()->dirty += rgn;
+ if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) {
+ if (widget->d_func()->graphicsEffect)
+ widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect());
+ else
+ widget->d_func()->dirty += rgn;
+ }
} else {
addDirtyWidget(widget, rgn);
}
@@ -625,7 +633,8 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd
return;
}
- const QRect translatedRect(rect.translated(widget->mapTo(tlw, QPoint())));
+ const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
+ const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
if (qt_region_strictContains(dirty, translatedRect)) {
if (updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
@@ -647,8 +656,8 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd
}
if (widget->d_func()->inDirtyList) {
- if (!qt_region_strictContains(widget->d_func()->dirty, rect))
- widget->d_func()->dirty += rect;
+ if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect))
+ widget->d_func()->dirty += widgetRect;
} else {
addDirtyWidget(widget, rect);
}
@@ -880,7 +889,7 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
&& !isOverlapped(sourceRect) && !isOverlapped(destRect);
if (!accelerateMove) {
- QRegion parentR(parentRect);
+ QRegion parentR(effectiveRectFor(parentRect));
if (!extra || !extra->hasMask) {
parentR -= newRect;
} else {
@@ -1384,7 +1393,7 @@ void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const Q
const QRect newWidgetRect(q->rect());
const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height());
- if (!staticContents) {
+ if (!staticContents || graphicsEffect) {
QRegion staticChildren;
QWidgetBackingStore *bs = 0;
if (offset.isNull() && (bs = maybeBackingStore()))
@@ -1404,19 +1413,19 @@ void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const Q
return;
// Invalidate newly exposed area of the parent.
- if (extra && extra->hasMask) {
+ if (!graphicsEffect && extra && extra->hasMask) {
QRegion parentExpose(extra->mask.translated(oldPos));
parentExpose &= QRect(oldPos, oldSize);
if (hasStaticChildren)
parentExpose -= data.crect; // Offset is unchanged, safe to do this.
q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
} else {
- if (hasStaticChildren) {
+ if (hasStaticChildren && !graphicsEffect) {
QRegion parentExpose(QRect(oldPos, oldSize));
parentExpose -= data.crect; // Offset is unchanged, safe to do this.
q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
} else {
- q->parentWidget()->d_func()->invalidateBuffer(QRect(oldPos, oldSize));
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize)));
}
}
return;
@@ -1474,7 +1483,7 @@ void QWidgetPrivate::invalidateBuffer(const QRegion &rgn)
QRegion wrgn(rgn);
wrgn &= clipRect();
- if (extra && extra->hasMask)
+ if (!graphicsEffect && extra && extra->hasMask)
wrgn &= extra->mask;
if (wrgn.isEmpty())
return;
@@ -1502,7 +1511,7 @@ void QWidgetPrivate::invalidateBuffer(const QRect &rect)
if (wRect.isEmpty())
return;
- if (!extra || !extra->hasMask) {
+ if (graphicsEffect || !extra || !extra->hasMask) {
tlwExtra->backingStore->markDirty(wRect, q, false, true);
return;
}
diff --git a/src/gui/painting/qbackingstore_p.h b/src/gui/painting/qbackingstore_p.h
index ddc0a59..b21d504 100644
--- a/src/gui/painting/qbackingstore_p.h
+++ b/src/gui/painting/qbackingstore_p.h
@@ -144,9 +144,13 @@ private:
inline void addDirtyWidget(QWidget *widget, const QRegion &rgn)
{
if (widget && !widget->d_func()->inDirtyList && !widget->data->in_destructor) {
- widget->d_func()->dirty = rgn;
+ QWidgetPrivate *widgetPrivate = widget->d_func();
+ if (widgetPrivate->graphicsEffect)
+ widgetPrivate->dirty = widgetPrivate->effectiveRectFor(rgn.boundingRect());
+ else
+ widgetPrivate->dirty = rgn;
dirtyWidgets.append(widget);
- widget->d_func()->inDirtyList = true;
+ widgetPrivate->inDirtyList = true;
}
}
diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h
index 0347842..4acc9be 100644
--- a/src/gui/painting/qpaintengine.h
+++ b/src/gui/painting/qpaintengine.h
@@ -210,6 +210,7 @@ public:
Direct3D,
Pdf,
OpenVG,
+ OpenGL2,
User = 50, // first user type id
MaxUser = 100 // last user type id
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
index 7ea68d2..d3cd6f9 100644
--- a/src/gui/painting/qpaintengine_p.h
+++ b/src/gui/painting/qpaintengine_p.h
@@ -72,6 +72,7 @@ public:
QPaintDevice *pdev;
QPaintEngine *q_ptr;
QRegion systemClip;
+ QRect systemRect;
QRegion systemViewport;
QTransform systemTransform;
QWidget *currentClipWidget;
@@ -117,9 +118,6 @@ public:
virtual void systemStateChanged() { }
void drawBoxTextItem(const QPointF &p, const QTextItemInt &ti);
-
-private:
- QRect systemRect;
};
QT_END_NAMESPACE