diff options
35 files changed, 2418 insertions, 5 deletions
diff --git a/examples/graphicsview/blurpicker/blureffect.cpp b/examples/graphicsview/blurpicker/blureffect.cpp new file mode 100644 index 0000000..8345d0b --- /dev/null +++ b/examples/graphicsview/blurpicker/blureffect.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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$ +** +****************************************************************************/ + +#include "blureffect.h" + +#include <QDebug> + +BlurEffect::BlurEffect(QObject *parent) + : QGraphicsBlurEffect() + , m_baseLine(200) +{ +} + +void BlurEffect::adjustForItem(const QGraphicsItem *item) +{ + qreal y = m_baseLine - item->pos().y(); + qreal radius = qBound(0.0, y / 32, 16.0); + setBlurRadius(radius); +} + +QRectF BlurEffect::boundingRectFor(const QGraphicsItem *item) +{ + adjustForItem(item); + return QGraphicsBlurEffect::boundingRectFor(item); +} + +void BlurEffect::drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + adjustForItem(item); + QGraphicsBlurEffect::drawItem(item, painter, option, widget); +} diff --git a/examples/graphicsview/blurpicker/blureffect.h b/examples/graphicsview/blurpicker/blureffect.h new file mode 100644 index 0000000..24a6867 --- /dev/null +++ b/examples/graphicsview/blurpicker/blureffect.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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 BLUREFFECT_H +#define BLUREFFECT_H + +#include <QGraphicsEffect> +#include <QGraphicsItem> + +class BlurEffect: public QGraphicsBlurEffect +{ +public: + BlurEffect(QObject *parent = 0); + + void setBaseLine(qreal y) { m_baseLine = y; } + + QRectF boundingRectFor(const QGraphicsItem *item); + + void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0); + +private: + void adjustForItem(const QGraphicsItem *item); + +private: + qreal m_baseLine; +}; + +#endif // BLUREFFECT_H diff --git a/examples/graphicsview/blurpicker/blurpicker.cpp b/examples/graphicsview/blurpicker/blurpicker.cpp new file mode 100644 index 0000000..887d7ef --- /dev/null +++ b/examples/graphicsview/blurpicker/blurpicker.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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$ +** +****************************************************************************/ + +#include "blurpicker.h" + +#include <QtGui> + +#include "blureffect.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +BlurPicker::BlurPicker(QWidget *parent): QGraphicsView(parent), m_index(0.0) +{ + setBackgroundBrush(QPixmap(":/images/background.jpg")); + setScene(&m_scene); + + setupScene(); + updateIconPositions(); + + connect(&m_timeLine, SIGNAL(valueChanged(qreal)), SLOT(updateIconPositions())); + m_timeLine.setDuration(400); + + setRenderHint(QPainter::Antialiasing, true); + setFrameStyle(QFrame::NoFrame); +} + +void BlurPicker::updateIconPositions() +{ + m_index = m_timeLine.currentFrame() / 1000.0; + + qreal baseline = 0; + for (int i = 0; i < m_icons.count(); ++i) { + QGraphicsItem *icon = m_icons[i]; + qreal a = ((i + m_index) * 2 * M_PI) / m_icons.count(); + qreal xs = 170 * sin(a); + qreal ys = 100 * cos(a); + QPointF pos(xs, ys); + pos = QTransform().rotate(-20).map(pos); + pos -= QPointF(40, 40); + icon->setPos(pos); + baseline = qMax(baseline, ys); + } + + m_blurEffect->setBaseLine(baseline); + m_scene.update(); +} + +void BlurPicker::setupScene() +{ + m_scene.setSceneRect(-200, -120, 400, 240); + + m_blurEffect = new BlurEffect(this); + + QStringList names; + names << ":/images/accessories-calculator.png"; + names << ":/images/accessories-text-editor.png"; + names << ":/images/help-browser.png"; + names << ":/images/internet-group-chat.png"; + names << ":/images/internet-mail.png"; + names << ":/images/internet-web-browser.png"; + names << ":/images/office-calendar.png"; + names << ":/images/system-users.png"; + + for (int i = 0; i < names.count(); i++) { + QPixmap pixmap(names[i]); + QGraphicsPixmapItem *icon = m_scene.addPixmap(pixmap); + icon->setZValue(1); + icon->setEffect(m_blurEffect); + m_icons << icon; + } + + QGraphicsPixmapItem *bg = m_scene.addPixmap(QPixmap(":/images/background.jpg")); + bg->setZValue(0); + bg->setPos(-200, -150); +} + +void BlurPicker::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Left) { + if (m_timeLine.state() == QTimeLine::NotRunning) { + m_timeLine.setFrameRange(m_index * 1000, m_index * 1000 - 1000); + m_timeLine.start(); + event->accept(); + } + } + + if (event->key() == Qt::Key_Right) { + if (m_timeLine.state() == QTimeLine::NotRunning) { + m_timeLine.setFrameRange(m_index * 1000, m_index * 1000 + 1000); + m_timeLine.start(); + event->accept(); + } + } +} diff --git a/examples/graphicsview/blurpicker/blurpicker.h b/examples/graphicsview/blurpicker/blurpicker.h new file mode 100644 index 0000000..e41c608 --- /dev/null +++ b/examples/graphicsview/blurpicker/blurpicker.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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 BLURPICKER_H +#define BLURPICKER_H + +#include <QGraphicsEffect> +#include <QGraphicsView> +#include <QTimeLine> + +#include "blureffect.h" + +class BlurPicker: public QGraphicsView +{ + Q_OBJECT + +public: + BlurPicker(QWidget *parent = 0); + +protected: + void keyPressEvent(QKeyEvent *event); + +private slots: + void updateIconPositions(); + +private: + void setupScene(); + +private: + qreal m_index; + QGraphicsScene m_scene; + BlurEffect *m_blurEffect; + QList<QGraphicsItem*> m_icons; + QTimeLine m_timeLine; +}; + +#endif // BLURPICKER_H diff --git a/examples/graphicsview/blurpicker/blurpicker.pro b/examples/graphicsview/blurpicker/blurpicker.pro new file mode 100644 index 0000000..e42cc0f --- /dev/null +++ b/examples/graphicsview/blurpicker/blurpicker.pro @@ -0,0 +1,9 @@ +SOURCES += main.cpp blurpicker.cpp blureffect.cpp +HEADERS += blurpicker.h blureffect.h +RESOURCES += blurpicker.qrc + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/graphicsview/blurpicker +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS blurpicker.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/graphicsview/blurpicker +INSTALLS += target sources diff --git a/examples/graphicsview/blurpicker/blurpicker.qrc b/examples/graphicsview/blurpicker/blurpicker.qrc new file mode 100644 index 0000000..e88eaca --- /dev/null +++ b/examples/graphicsview/blurpicker/blurpicker.qrc @@ -0,0 +1,14 @@ +<RCC> + <qresource prefix="/" > + <file>images/background.jpg</file> + <file>images/accessories-calculator.png</file> + <file>images/accessories-text-editor.png</file> + <file>images/help-browser.png</file> + <file>images/internet-group-chat.png</file> + <file>images/internet-mail.png</file> + <file>images/internet-web-browser.png</file> + <file>images/office-calendar.png</file> + <file>images/system-users.png</file> + </qresource> +</RCC> + diff --git a/examples/graphicsview/blurpicker/images/README.txt b/examples/graphicsview/blurpicker/images/README.txt new file mode 100644 index 0000000..0927e17 --- /dev/null +++ b/examples/graphicsview/blurpicker/images/README.txt @@ -0,0 +1,5 @@ +The background is taken from a public domain photo at: +http://www.photos8.com/view/computer_board2-800x600.html + +All other icons are from the Tango Desktop project: +http://tango.freedesktop.org/Tango_Desktop_Project diff --git a/examples/graphicsview/blurpicker/images/accessories-calculator.png b/examples/graphicsview/blurpicker/images/accessories-calculator.png Binary files differnew file mode 100644 index 0000000..4e7661f --- /dev/null +++ b/examples/graphicsview/blurpicker/images/accessories-calculator.png diff --git a/examples/graphicsview/blurpicker/images/accessories-text-editor.png b/examples/graphicsview/blurpicker/images/accessories-text-editor.png Binary files differnew file mode 100644 index 0000000..33bef0b --- /dev/null +++ b/examples/graphicsview/blurpicker/images/accessories-text-editor.png diff --git a/examples/graphicsview/blurpicker/images/background.jpg b/examples/graphicsview/blurpicker/images/background.jpg Binary files differnew file mode 100644 index 0000000..e75b388 --- /dev/null +++ b/examples/graphicsview/blurpicker/images/background.jpg diff --git a/examples/graphicsview/blurpicker/images/help-browser.png b/examples/graphicsview/blurpicker/images/help-browser.png Binary files differnew file mode 100644 index 0000000..8ef4fae --- /dev/null +++ b/examples/graphicsview/blurpicker/images/help-browser.png diff --git a/examples/graphicsview/blurpicker/images/internet-group-chat.png b/examples/graphicsview/blurpicker/images/internet-group-chat.png Binary files differnew file mode 100644 index 0000000..dd92d93 --- /dev/null +++ b/examples/graphicsview/blurpicker/images/internet-group-chat.png diff --git a/examples/graphicsview/blurpicker/images/internet-mail.png b/examples/graphicsview/blurpicker/images/internet-mail.png Binary files differnew file mode 100644 index 0000000..7e6b93b --- /dev/null +++ b/examples/graphicsview/blurpicker/images/internet-mail.png diff --git a/examples/graphicsview/blurpicker/images/internet-web-browser.png b/examples/graphicsview/blurpicker/images/internet-web-browser.png Binary files differnew file mode 100644 index 0000000..a979a92 --- /dev/null +++ b/examples/graphicsview/blurpicker/images/internet-web-browser.png diff --git a/examples/graphicsview/blurpicker/images/office-calendar.png b/examples/graphicsview/blurpicker/images/office-calendar.png Binary files differnew file mode 100644 index 0000000..e095906 --- /dev/null +++ b/examples/graphicsview/blurpicker/images/office-calendar.png diff --git a/examples/graphicsview/blurpicker/images/system-users.png b/examples/graphicsview/blurpicker/images/system-users.png Binary files differnew file mode 100644 index 0000000..a7f630a --- /dev/null +++ b/examples/graphicsview/blurpicker/images/system-users.png diff --git a/examples/graphicsview/blurpicker/main.cpp b/examples/graphicsview/blurpicker/main.cpp new file mode 100644 index 0000000..b88a51d --- /dev/null +++ b/examples/graphicsview/blurpicker/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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$ +** +****************************************************************************/ + +#include "blurpicker.h" +#include <QApplication> + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + BlurPicker blurPicker; + blurPicker.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Application Picker")); + blurPicker.setFixedSize(400, 300); + blurPicker.show(); + + return app.exec(); +} diff --git a/examples/graphicsview/graphicsview.pro b/examples/graphicsview/graphicsview.pro index 66eb0b4..185c856 100644 --- a/examples/graphicsview/graphicsview.pro +++ b/examples/graphicsview/graphicsview.pro @@ -6,6 +6,8 @@ SUBDIRS = \ diagramscene \ dragdroprobot \ padnavigator \ + lighting \ + blurpicker \ basicgraphicslayouts contains(QT_CONFIG, qt3support):SUBDIRS += portedcanvas portedasteroids diff --git a/examples/graphicsview/lighting/lighting.cpp b/examples/graphicsview/lighting/lighting.cpp new file mode 100644 index 0000000..445d7f9 --- /dev/null +++ b/examples/graphicsview/lighting/lighting.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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$ +** +****************************************************************************/ + +#include "lighting.h" + +#include <QtGui> + +#include "shadoweffect.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +Lighting::Lighting(QWidget *parent): QGraphicsView(parent), angle(0.0) +{ + setScene(&m_scene); + + setupScene(); + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), SLOT(animate())); + timer->setInterval(30); + timer->start(); + + setRenderHint(QPainter::Antialiasing, true); + setFrameStyle(QFrame::NoFrame); +} + +void Lighting::setupScene() +{ + m_scene.setSceneRect(-300, -200, 600, 460); + + QLinearGradient linearGrad(QPointF(-100, -100), QPointF(100, 100)); + linearGrad.setColorAt(0, QColor(255, 255, 255)); + linearGrad.setColorAt(1, QColor(192, 192, 255)); + setBackgroundBrush(linearGrad); + + QRadialGradient radialGrad(30, 30, 30); + radialGrad.setColorAt(0, Qt::yellow); + radialGrad.setColorAt(0.2, Qt::yellow); + radialGrad.setColorAt(1, Qt::transparent); + QPixmap pixmap(60, 60); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + painter.setPen(Qt::NoPen); + painter.setBrush(radialGrad); + painter.drawEllipse(0, 0, 60, 60); + painter.end(); + + m_lightSource = m_scene.addPixmap(pixmap); + m_lightSource->setZValue(2); + + m_shadowEffect = new ShadowEffect(m_lightSource, this); + + for (int i = -2; i < 3; ++i) + for (int j = -2; j < 3; ++j) { + QAbstractGraphicsShapeItem *item; + if ((i + j) & 1) + item = new QGraphicsEllipseItem(0, 0, 50, 50); + else + item = new QGraphicsRectItem(0, 0, 50, 50); + + item->setPen(QPen(Qt::black)); + item->setBrush(QBrush(Qt::white)); + item->setEffect(m_shadowEffect); + item->setZValue(1); + item->setPos(i * 80, j * 80); + m_scene.addItem(item); + m_items << item; + } + + +} + +void Lighting::animate() +{ + angle += (M_PI / 30); + qreal xs = 200 * sin(angle) - 40 + 25; + qreal ys = 200 * cos(angle) - 40 + 25; + m_lightSource->setPos(xs, ys); + m_scene.update(); +} + diff --git a/examples/graphicsview/lighting/lighting.h b/examples/graphicsview/lighting/lighting.h new file mode 100644 index 0000000..66237f6 --- /dev/null +++ b/examples/graphicsview/lighting/lighting.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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 LIGHTING_H +#define LIGHTING_H + +#include <QGraphicsEffect> +#include <QGraphicsView> + +#include "shadoweffect.h" + +class Lighting: public QGraphicsView +{ + Q_OBJECT + +public: + Lighting(QWidget *parent = 0); + +private slots: + void animate(); + +private: + void setupScene(); + +private: + qreal angle; + QGraphicsScene m_scene; + QGraphicsItem *m_lightSource; + ShadowEffect *m_shadowEffect; + QList<QGraphicsItem*> m_items; +}; + +#endif // LIGHTING_H diff --git a/examples/graphicsview/lighting/lighting.pro b/examples/graphicsview/lighting/lighting.pro new file mode 100644 index 0000000..440bb53 --- /dev/null +++ b/examples/graphicsview/lighting/lighting.pro @@ -0,0 +1,8 @@ +SOURCES += main.cpp lighting.cpp shadoweffect.cpp +HEADERS += lighting.h shadoweffect.h + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/graphicsview/lighting +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS lighting.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/graphicsview/lighting +INSTALLS += target sources diff --git a/examples/graphicsview/lighting/main.cpp b/examples/graphicsview/lighting/main.cpp new file mode 100644 index 0000000..07415f6 --- /dev/null +++ b/examples/graphicsview/lighting/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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$ +** +****************************************************************************/ + +#include "lighting.h" +#include <QApplication> + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + Lighting lighting; + lighting.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Lighting and Shadows")); + lighting.resize(640, 480); + lighting.show(); + + return app.exec(); +} diff --git a/examples/graphicsview/lighting/shadoweffect.cpp b/examples/graphicsview/lighting/shadoweffect.cpp new file mode 100644 index 0000000..726cbd0 --- /dev/null +++ b/examples/graphicsview/lighting/shadoweffect.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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$ +** +****************************************************************************/ + +#include "shadoweffect.h" + +#include <math.h> + +ShadowEffect::ShadowEffect(QGraphicsItem *source, QObject *parent) + : QGraphicsShadowEffect(parent) + , m_lightSource(source) +{ + setBlurRadius(8); +} + +void ShadowEffect::adjustForItem(const QGraphicsItem *item) +{ + QPointF delta = item->pos() - m_lightSource->pos(); + setShadowOffset(delta.toPoint() / 30); + + qreal dx = delta.x(); + qreal dy = delta.y(); + qreal dd = sqrt(dx * dx + dy * dy); + setOpacity(qBound(0.4, 1 - dd / 200.0, 0.7)); +} + +QRectF ShadowEffect::boundingRectFor(const QGraphicsItem *item) +{ + adjustForItem(item); + return QGraphicsShadowEffect::boundingRectFor(item); +} + +void ShadowEffect::drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + adjustForItem(item); + QGraphicsShadowEffect::drawItem(item, painter, option, widget); +} diff --git a/examples/graphicsview/lighting/shadoweffect.h b/examples/graphicsview/lighting/shadoweffect.h new file mode 100644 index 0000000..02d0bf1 --- /dev/null +++ b/examples/graphicsview/lighting/shadoweffect.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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 SHADOWEFFECT_H +#define SHADOWEFFECT_H + +#include <QGraphicsEffect> +#include <QGraphicsItem> + +class ShadowEffect: public QGraphicsShadowEffect +{ +public: + ShadowEffect(QGraphicsItem *source, QObject *parent = 0); + + QRectF boundingRectFor(const QGraphicsItem *item); + + void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0); + +private: + void adjustForItem(const QGraphicsItem *item); + +private: + QGraphicsItem *m_lightSource; +}; + +#endif // SHADOWEFFECT_H diff --git a/src/gui/graphicsview/graphicsview.pri b/src/gui/graphicsview/graphicsview.pri index 0c0747e..c3cb574 100644 --- a/src/gui/graphicsview/graphicsview.pri +++ b/src/gui/graphicsview/graphicsview.pri @@ -20,7 +20,8 @@ HEADERS += graphicsview/qgraphicsgridlayout.h \ graphicsview/qgraphicsview_p.h \ graphicsview/qgraphicswidget.h \ graphicsview/qgraphicswidget_p.h \ - graphicsview/qgridlayoutengine_p.h + graphicsview/qgridlayoutengine_p.h \ + graphicsview/qgraphicseffect.h SOURCES += graphicsview/qgraphicsgridlayout.cpp \ graphicsview/qgraphicsitem.cpp \ @@ -39,4 +40,5 @@ SOURCES += graphicsview/qgraphicsgridlayout.cpp \ graphicsview/qgraphicsview.cpp \ graphicsview/qgraphicswidget.cpp \ graphicsview/qgraphicswidget_p.cpp \ - graphicsview/qgridlayoutengine.cpp + graphicsview/qgridlayoutengine.cpp \ + graphicsview/qgraphicseffect.cpp diff --git a/src/gui/graphicsview/qgraphicseffect.cpp b/src/gui/graphicsview/qgraphicseffect.cpp new file mode 100644 index 0000000..6b1f12a --- /dev/null +++ b/src/gui/graphicsview/qgraphicseffect.cpp @@ -0,0 +1,823 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "qgraphicseffect.h" + +#ifndef QT_NO_GRAPHICSVIEW + +#include <QtGui/qimage.h> +#include <QtGui/qgraphicsitem.h> +#include <QtGui/qgraphicsscene.h> +#include <QtGui/qpainter.h> + +#include <private/qobject_p.h> +#include <private/qpixmapfilter_p.h> + +/* + + List of known drawbacks which are being discussed: + + * No d-pointer yet. + + * No auto test yet. + + * No API documentation yet. + + * The API is far from being finalized. + + * Most of the effect implementation is not efficient, + as this is still a proof of concept only. + + * Painting artifacts occasionally occur when e.g. moving + an item over another item that has a large effective + bounding rect. + + * Item transformation is not taken into account. + For example, the effective bounding rect is calculated at + item coordinate (fast), but the painting is mostly + done at device coordinate. + + * Coordinate mode: item vs device. Most effects make sense only + in device coordinate. Should we keep both options open? + See also above transformation issue. + + * Right now the pixmap for effect drawing is stored in each item. + There can be problems with coordinates, see above. + + * There is a lot of duplication in drawItems() for each effect. + + * Port to use the new layer feature in QGraphicsView. + This should solve the above pixmap problem. + + * Frame effect is likely useless. However it is very useful + to check than the effective bounding rect is handled properly. + + * Proper exposed region and rect for style option are missing. + + * Pixelize effect is using raster only, because there is no + pixmap filter for it. We need to implement the missing pixmap filter. + + * Blur effect is using raster only, with exponential blur algorithm. + Perhaps use stack blur (better approximate Gaussian blur) instead? + QPixmapConvolutionFilter is too slow for this simple blur effect. + + * Bloom and shadow effect are also raster only. Same reason as above. + + * Make it work with widgets (QGraphicsWidget). + +*/ + +/*! + \internal +*/ +class QGraphicsEffectPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsEffect) +public: + QGraphicsEffectPrivate() {} +}; + +QGraphicsEffect::QGraphicsEffect(QObject *parent) + : QObject(*new QGraphicsEffectPrivate, parent) +{ +} + +QGraphicsEffect::~QGraphicsEffect() +{ +} + +QRectF QGraphicsEffect::boundingRectFor(const QGraphicsItem *item) +{ + // default is to give the item's bounding rect + // do NOT call item->effectiveBoundRect() because + // that function will call this one (infinite loop) + return item->boundingRect(); +} + +/*! \internal +*/ +QGraphicsEffect::QGraphicsEffect(QGraphicsEffectPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + +// this helper function is only for subclasses of QGraphicsEffect +// the implementation is trivial, but this allows us to keep +// QGraphicsScene::drawItem() as a protected function +// (since QGraphicsEffect is a friend of QGraphicsScene) +QPixmap* QGraphicsEffect::drawItemOnPixmap(QPainter *painter, QGraphicsItem *item, + const QStyleOptionGraphicsItem *option, QWidget *widget, int flags) +{ + if (!item->scene()) + return 0; + return item->scene()->drawItemOnPixmap(painter, item, option, widget, flags); +} + +/*! + \internal +*/ +class QGraphicsGrayscaleEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsGrayscaleEffect) +public: + QGraphicsGrayscaleEffectPrivate() { + filter = new QPixmapColorizeFilter; + filter->setColor(Qt::black); + } + + ~QGraphicsGrayscaleEffectPrivate() { + delete filter; + } + + QPixmapColorizeFilter *filter; +}; + +QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect(QObject *parent) + : QGraphicsEffect(*new QGraphicsGrayscaleEffectPrivate, parent) +{ +} + +QGraphicsGrayscaleEffect::~QGraphicsGrayscaleEffect() +{ +} + +void QGraphicsGrayscaleEffect::drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsGrayscaleEffect); + + // Find the item's bounds in device coordinates. + QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); + if (deviceRect.isEmpty()) + return; + + QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); + if (!pixmap) + return; + + // Draw the pixmap with the filter using an untransformed painter. + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + d->filter->draw(painter, deviceRect.topLeft(), *pixmap, pixmap->rect()); + painter->setWorldTransform(restoreTransform); +} + +/*! + \internal +*/ +class QGraphicsColorizeEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsColorizeEffect) +public: + QGraphicsColorizeEffectPrivate() { + filter = new QPixmapColorizeFilter; + } + + ~QGraphicsColorizeEffectPrivate() { + delete filter; + } + + QPixmapColorizeFilter *filter; +}; + +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); + d->filter->setColor(c); +} + +void QGraphicsColorizeEffect::drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsColorizeEffect); + + // Find the item's bounds in device coordinates. + QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); + if (deviceRect.isEmpty()) + return; + + QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); + if (!pixmap) + return; + + // Draw the pixmap with the filter using an untransformed painter. + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + d->filter->draw(painter, deviceRect.topLeft(), *pixmap, pixmap->rect()); + painter->setWorldTransform(restoreTransform); +} + +/*! + \internal +*/ +class QGraphicsPixelizeEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsPixelizeEffect) +public: + QGraphicsPixelizeEffectPrivate() + : pixelSize(3) { } + + int pixelSize; +}; + +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); + d->pixelSize = size; +} + +void QGraphicsPixelizeEffect::drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsPixelizeEffect); + + // Find the item's bounds in device coordinates. + QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); + if (deviceRect.isEmpty()) + return; + + QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); + if (!pixmap) + return; + + // pixelize routine + QImage img = pixmap->toImage().convertToFormat(QImage::Format_ARGB32); + if (d->pixelSize > 0) { + int width = img.width(); + int height = img.height(); + for (int y = 0; y < height; y += d->pixelSize) { + int ys = qMin(height - 1, y + d->pixelSize / 2); + QRgb *sbuf = reinterpret_cast<QRgb*>(img.scanLine(ys)); + for (int x = 0; x < width; x += d->pixelSize) { + int xs = qMin(width - 1, x + d->pixelSize / 2); + QRgb color = sbuf[xs]; + for (int yi = 0; yi < qMin(d->pixelSize, height - y); ++yi) { + QRgb *buf = reinterpret_cast<QRgb*>(img.scanLine(y + yi)); + for (int xi = 0; xi < qMin(d->pixelSize, width - x); ++xi) + buf[x + xi] = color; + } + } + } + } + + // Draw using an untransformed painter. + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + painter->drawImage(deviceRect.topLeft(), img); + painter->setWorldTransform(restoreTransform); +} + +/*! + \internal +*/ +class QGraphicsBlurEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsBlurEffect) +public: + QGraphicsBlurEffectPrivate() + { + filter = new QPixmapBlurFilter; + } + ~QGraphicsBlurEffectPrivate() + { + delete filter; + } + + QPixmapBlurFilter *filter; +}; + +QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent) + : QGraphicsEffect(*new QGraphicsBlurEffectPrivate, parent) +{ +} + +QGraphicsBlurEffect::~QGraphicsBlurEffect() +{ +} + +// Blur the image according to the blur radius +// Based on exponential blur algorithm by Jani Huhtanen +// (maximum radius is set to 16) +static QImage blurred(const QImage& image, const QRect& rect, int radius) +{ + int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; + int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; + + QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + int r1 = rect.top(); + int r2 = rect.bottom(); + int c1 = rect.left(); + int c2 = rect.right(); + + int bpl = result.bytesPerLine(); + int rgba[4]; + unsigned char* p; + + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r1) + col * 4; + for (int i = 0; i < 4; i++) + rgba[i] = p[i] << 4; + + p += bpl; + for (int j = r1; j < r2; j++, p += bpl) + for (int i = 0; i < 4; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } + + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c1 * 4; + for (int i = 0; i < 4; i++) + rgba[i] = p[i] << 4; + + p += 4; + for (int j = c1; j < c2; j++, p += 4) + for (int i = 0; i < 4; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } + + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r2) + col * 4; + for (int i = 0; i < 4; i++) + rgba[i] = p[i] << 4; + + p -= bpl; + for (int j = r1; j < r2; j++, p -= bpl) + for (int i = 0; i < 4; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } + + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c2 * 4; + for (int i = 0; i < 4; i++) + rgba[i] = p[i] << 4; + + p -= 4; + for (int j = c1; j < c2; j++, p -= 4) + for (int i = 0; i < 4; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } + + return result; +} + +int QGraphicsBlurEffect::blurRadius() const +{ + Q_D(const QGraphicsBlurEffect); + return int(d->filter->blurRadius()); +} + +void QGraphicsBlurEffect::setBlurRadius(int radius) +{ + Q_D(QGraphicsBlurEffect); + d->filter->setBlurRadius(radius); +} + +QRectF QGraphicsBlurEffect::boundingRectFor(const QGraphicsItem *item) +{ + Q_D(const QGraphicsBlurEffect); + return d->filter->boundingRectFor(item->boundingRect()); +} + +void QGraphicsBlurEffect::drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsBlurEffect); + + // Find the item's bounds in device coordinates. + QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); + if (deviceRect.isEmpty()) + return; + + QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); + if (!pixmap) + return; + + // Draw the pixmap with the filter using an untransformed painter. + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + d->filter->draw(painter, deviceRect.topLeft(), *pixmap, pixmap->rect()); + painter->setWorldTransform(restoreTransform); +} + +/*! + \internal +*/ +class QGraphicsBloomEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsBlurEffect) +public: + QGraphicsBloomEffectPrivate() + : blurRadius(6) + , opacity(0.7) { } + + int blurRadius; + qreal opacity; +}; + +QGraphicsBloomEffect::QGraphicsBloomEffect(QObject *parent) + : QGraphicsEffect(*new QGraphicsBloomEffectPrivate, parent) +{ +} + +QGraphicsBloomEffect::~QGraphicsBloomEffect() +{ +} + +int QGraphicsBloomEffect::blurRadius() const +{ + Q_D(const QGraphicsBloomEffect); + return d->blurRadius; +} + +void QGraphicsBloomEffect::setBlurRadius(int radius) +{ + Q_D(QGraphicsBloomEffect); + d->blurRadius = radius; +} + +qreal QGraphicsBloomEffect::opacity() const +{ + Q_D(const QGraphicsBloomEffect); + return d->opacity; +} + +void QGraphicsBloomEffect::setOpacity(qreal alpha) +{ + Q_D(QGraphicsBloomEffect); + d->opacity = alpha; +} + +QRectF QGraphicsBloomEffect::boundingRectFor(const QGraphicsItem *item) +{ + Q_D(QGraphicsBloomEffect); + qreal delta = d->blurRadius * 3; + QRectF blurRect = item->boundingRect(); + blurRect.adjust(-delta, -delta, delta, delta); + return blurRect; +} + +// Change brightness (positive integer) of each pixel +static QImage brightened(const QImage& image, int brightness) +{ + int tab[ 256 ]; + for (int i = 0; i < 256; ++i) + tab[i] = qMin(i + brightness, 255); + + QImage img = image.convertToFormat(QImage::Format_ARGB32); + for (int y = 0; y < img.height(); y++) { + QRgb* line = (QRgb*)(img.scanLine(y)); + for (int x = 0; x < img.width(); x++) { + QRgb c = line[x]; + line[x] = qRgba(tab[qRed(c)], tab[qGreen(c)], tab[qBlue(c)], qAlpha(c)); + } + } + + return img; +} + +// Composite two QImages using given composition mode and opacity +static QImage composited(const QImage& img1, const QImage& img2, qreal opacity, QPainter::CompositionMode mode) +{ + QImage result = img1.convertToFormat(QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(mode); + painter.setOpacity(opacity); + painter.drawImage(0, 0, img2); + painter.end(); + return result; +} + +void QGraphicsBloomEffect::drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsBloomEffect); + + // Find the item's bounds in device coordinates. + QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); + if (deviceRect.isEmpty()) + return; + + QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); + if (!pixmap) + return; + + // bloom routine + int radius = d->blurRadius; + QImage img = pixmap->toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); + QImage overlay = blurred(img, img.rect(), radius); + overlay = brightened(overlay, 70); + img = composited(img, overlay, d->opacity, QPainter::CompositionMode_Overlay); + + // Draw using an untransformed painter. + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + painter->drawImage(deviceRect.topLeft() - QPointF(radius * 3, radius * 3), img); + painter->setWorldTransform(restoreTransform); +} + +/*! + \internal +*/ +class QGraphicsFrameEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsFrameEffect) +public: + QGraphicsFrameEffectPrivate() + : color(Qt::blue) + , width(5) + , alpha(0.6) + { + } + + QColor color; + qreal width; + qreal alpha; +}; + +QGraphicsFrameEffect::QGraphicsFrameEffect(QObject *parent) + : QGraphicsEffect(*new QGraphicsFrameEffectPrivate, parent) +{ +} + +QGraphicsFrameEffect::~QGraphicsFrameEffect() +{ +} + +QColor QGraphicsFrameEffect::frameColor() const +{ + Q_D(const QGraphicsFrameEffect); + return d->color; +} + +void QGraphicsFrameEffect::setFrameColor(const QColor &c) +{ + Q_D(QGraphicsFrameEffect); + d->color = c; +} + +qreal QGraphicsFrameEffect::frameWidth() const +{ + Q_D(const QGraphicsFrameEffect); + return d->width; +} + +void QGraphicsFrameEffect::setFrameWidth(qreal frameWidth) +{ + Q_D(QGraphicsFrameEffect); + d->width = frameWidth; +} + +qreal QGraphicsFrameEffect::frameOpacity() const +{ + Q_D(const QGraphicsFrameEffect); + return d->alpha; +} + +void QGraphicsFrameEffect::setFrameOpacity(qreal opacity) +{ + Q_D(QGraphicsFrameEffect); + d->alpha = opacity; +} + +QRectF QGraphicsFrameEffect::boundingRectFor(const QGraphicsItem *item) +{ + Q_D(QGraphicsFrameEffect); + QRectF frameRect = item->boundingRect(); + frameRect.adjust(-d->width, -d->width, d->width, d->width); + return frameRect; +} + +void QGraphicsFrameEffect::drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsFrameEffect); + + // Find the item's bounds in device coordinates. + QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); + if (deviceRect.isEmpty()) + return; + + QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); + if (!pixmap) + return; + + QRectF frameRect = deviceBounds; + frameRect.adjust(-d->width, -d->width, d->width, d->width); + + painter->save(); + painter->setWorldTransform(QTransform()); + + painter->save(); + painter->setOpacity(painter->opacity() * d->alpha); + painter->setPen(Qt::NoPen); + painter->setBrush(d->color); + painter->drawRoundedRect(frameRect, 20, 20, Qt::RelativeSize); + painter->restore(); + + painter->drawPixmap(frameRect.topLeft(), *pixmap); + + painter->restore(); +} + + +/*! + \internal +*/ +class QGraphicsShadowEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsShadowEffect) +public: + QGraphicsShadowEffectPrivate() + : offset(4,4) + , radius(8) + , alpha(0.7) + { + } + + QPointF offset; + int radius; + qreal alpha; +}; + +QGraphicsShadowEffect::QGraphicsShadowEffect(QObject *parent) + : QGraphicsEffect(*new QGraphicsShadowEffectPrivate, parent) +{ +} + +QGraphicsShadowEffect::~QGraphicsShadowEffect() +{ +} + +QPointF QGraphicsShadowEffect::shadowOffset() const +{ + Q_D(const QGraphicsShadowEffect); + return d->offset; +} + +void QGraphicsShadowEffect::setShadowOffset(const QPointF &ofs) +{ + Q_D(QGraphicsShadowEffect); + d->offset = ofs; +} + +int QGraphicsShadowEffect::blurRadius() const +{ + Q_D(const QGraphicsShadowEffect); + return d->radius; +} + +void QGraphicsShadowEffect::setBlurRadius(int blurRadius) +{ + Q_D(QGraphicsShadowEffect); + d->radius = blurRadius; +} + +qreal QGraphicsShadowEffect::opacity() const +{ + Q_D(const QGraphicsShadowEffect); + return d->alpha; +} + +void QGraphicsShadowEffect::setOpacity(qreal opacity) +{ + Q_D(QGraphicsShadowEffect); + d->alpha = opacity; +} + +QRectF QGraphicsShadowEffect::boundingRectFor(const QGraphicsItem *item) +{ + Q_D(QGraphicsShadowEffect); + QRectF shadowRect = item->boundingRect(); + shadowRect.adjust(d->offset.x(), d->offset.y(), d->offset.x(), d->offset.y()); + QRectF blurRect = shadowRect; + qreal delta = d->radius * 3; + blurRect.adjust(-delta, -delta, delta, delta); + QRectF totalRect = blurRect.united(item->boundingRect()); + return totalRect; +} + +void QGraphicsShadowEffect::drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsShadowEffect); + + // Find the item's bounds in device coordinates. + QRectF deviceBounds = painter->worldTransform().mapRect(item->boundingRect()); + QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); + if (deviceRect.isEmpty()) + return; + + QRectF shadowRect = deviceBounds; + shadowRect.adjust(d->offset.x(), d->offset.y(), d->offset.x(), d->offset.y()); + QRectF blurRect = shadowRect; + qreal delta = d->radius * 3; + blurRect.adjust(-delta, -delta, delta, delta); + QRectF totalRect = blurRect.united(deviceRect); + + QPixmap *pixmap = QGraphicsEffect::drawItemOnPixmap(painter, item, option, widget, 0); + if (!pixmap) + return; + + QImage img = pixmap->toImage(); + QImage shadowImage(img.size(), QImage::Format_ARGB32); + shadowImage.fill(qRgba(0, 0, 0, d->alpha * 255)); + shadowImage.setAlphaChannel(img.alphaChannel()); + shadowImage = blurred(shadowImage, shadowImage.rect(), d->radius); + + // Draw using an untransformed painter. + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + + QRect shadowAlignedRect = shadowRect.toAlignedRect(); + + qreal shadowx = blurRect.x() + delta; + qreal shadowy = blurRect.y() + delta; + if (blurRect.x() < deviceRect.x()) + shadowx = blurRect.x() + d->offset.x(); + if (blurRect.y() < deviceRect.y()) + shadowy = blurRect.y() + d->offset.y(); + painter->drawImage(shadowx, shadowy, shadowImage); + + qreal itemx = qMin(blurRect.x(), deviceBounds.x()); + qreal itemy = qMin(blurRect.y(), deviceBounds.y()); + painter->drawPixmap(itemx, itemy, *pixmap); + + painter->setWorldTransform(restoreTransform); +} + + +#endif diff --git a/src/gui/graphicsview/qgraphicseffect.h b/src/gui/graphicsview/qgraphicseffect.h new file mode 100644 index 0000000..29d97a6 --- /dev/null +++ b/src/gui/graphicsview/qgraphicseffect.h @@ -0,0 +1,279 @@ +/**************************************************************************** +** +** 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/qglobal.h> +#include <QtCore/qpoint.h> +#include <QtCore/qvariant.h> +#include <QtGui/qcolor.h> + +QT_FORWARD_DECLARE_CLASS(QGraphicsItem); +QT_FORWARD_DECLARE_CLASS(QStyleOptionGraphicsItem); +QT_FORWARD_DECLARE_CLASS(QPainter); +QT_FORWARD_DECLARE_CLASS(QPixmap); +QT_FORWARD_DECLARE_CLASS(QWidget); +QT_FORWARD_DECLARE_CLASS(QPixmapColorizeFilter); + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW + +class QGraphicsEffectPrivate; +class Q_GUI_EXPORT QGraphicsEffect : public QObject +{ + Q_OBJECT + +public: + + QGraphicsEffect(QObject *parent = 0); + virtual ~QGraphicsEffect(); + + virtual QRectF boundingRectFor(const QGraphicsItem *item); + + virtual void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0) = 0; + +protected: + QGraphicsEffect(QGraphicsEffectPrivate &d, QObject* parent); + QPixmap* drawItemOnPixmap(QPainter *painter, QGraphicsItem *item, + const QStyleOptionGraphicsItem *option, QWidget *widget, int flags); + +private: + Q_DECLARE_PRIVATE(QGraphicsEffect) + Q_DISABLE_COPY(QGraphicsEffect) +}; + +class QGraphicsGrayscaleEffectPrivate; +class Q_GUI_EXPORT QGraphicsGrayscaleEffect: public QGraphicsEffect +{ + Q_OBJECT + +public: + + QGraphicsGrayscaleEffect(QObject *parent = 0); + ~QGraphicsGrayscaleEffect(); + + void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0); + +private: + Q_DECLARE_PRIVATE(QGraphicsGrayscaleEffect) + Q_DISABLE_COPY(QGraphicsGrayscaleEffect) +}; + +class QGraphicsColorizeEffectPrivate; +class Q_GUI_EXPORT QGraphicsColorizeEffect: public QGraphicsEffect { + Q_OBJECT + +public: + + QGraphicsColorizeEffect(QObject *parent = 0); + ~QGraphicsColorizeEffect(); + + QColor color() const; + void setColor(const QColor &c); + + void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0); + +private: + Q_DECLARE_PRIVATE(QGraphicsColorizeEffect) + Q_DISABLE_COPY(QGraphicsColorizeEffect) +}; + +class QGraphicsPixelizeEffectPrivate; +class Q_GUI_EXPORT QGraphicsPixelizeEffect: public QGraphicsEffect { + Q_OBJECT + +public: + + QGraphicsPixelizeEffect(QObject *parent = 0); + ~QGraphicsPixelizeEffect(); + + int pixelSize() const; + void setPixelSize(int pixelSize); + + void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0); + +private: + Q_DECLARE_PRIVATE(QGraphicsPixelizeEffect) + Q_DISABLE_COPY(QGraphicsPixelizeEffect) +}; + +class QGraphicsBlurEffectPrivate; +class Q_GUI_EXPORT QGraphicsBlurEffect: public QGraphicsEffect { + Q_OBJECT + +public: + + QGraphicsBlurEffect(QObject *parent = 0); + ~QGraphicsBlurEffect(); + + int blurRadius() const; + void setBlurRadius(int blurRadius); + + QRectF boundingRectFor(const QGraphicsItem *item); + + void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0); + +private: + Q_DECLARE_PRIVATE(QGraphicsBlurEffect) + Q_DISABLE_COPY(QGraphicsBlurEffect) +}; + +class QGraphicsBloomEffectPrivate; +class Q_GUI_EXPORT QGraphicsBloomEffect: public QGraphicsEffect { + Q_OBJECT + +public: + + QGraphicsBloomEffect(QObject *parent = 0); + ~QGraphicsBloomEffect(); + + int blurRadius() const; + void setBlurRadius(int blurRadius); + + qreal opacity() const; + void setOpacity(qreal opacity); + + QRectF boundingRectFor(const QGraphicsItem *item); + + void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0); + +private: + Q_DECLARE_PRIVATE(QGraphicsBloomEffect) + Q_DISABLE_COPY(QGraphicsBloomEffect) +}; + +class QGraphicsFrameEffectPrivate; +class Q_GUI_EXPORT QGraphicsFrameEffect: public QGraphicsEffect { + Q_OBJECT + +public: + + QGraphicsFrameEffect(QObject *parent = 0); + ~QGraphicsFrameEffect(); + + QColor frameColor() const; + void setFrameColor(const QColor &c); + + qreal frameWidth() const; + void setFrameWidth(qreal frameWidth); + + qreal frameOpacity() const; + void setFrameOpacity(qreal opacity); + + QRectF boundingRectFor(const QGraphicsItem *item); + + void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0); +private: + Q_DECLARE_PRIVATE(QGraphicsFrameEffect) + Q_DISABLE_COPY(QGraphicsFrameEffect) +}; + +class QGraphicsShadowEffectPrivate; +class Q_GUI_EXPORT QGraphicsShadowEffect: public QGraphicsEffect { + Q_OBJECT + +public: + + QGraphicsShadowEffect(QObject *parent = 0); + ~QGraphicsShadowEffect(); + + QPointF shadowOffset() const; + void setShadowOffset(const QPointF &ofs); + inline void setShadowOffset(qreal dx, qreal dy) { setShadowOffset(QPointF(dx, dy)); } + inline void setShadowOffset(qreal d) { setShadowOffset(QPointF(d, d)); } + + int blurRadius() const; + void setBlurRadius(int blurRadius); + + qreal opacity() const; + void setOpacity(qreal opacity); + + QRectF boundingRectFor(const QGraphicsItem *item); + + void drawItem(QGraphicsItem *item, QPainter *painter, + const QStyleOptionGraphicsItem *option = 0, + QWidget *widget = 0); + +protected: + +private: + Q_DECLARE_PRIVATE(QGraphicsShadowEffect) + Q_DISABLE_COPY(QGraphicsShadowEffect) +}; + +Q_DECLARE_METATYPE(QGraphicsEffect *) +Q_DECLARE_METATYPE(QGraphicsGrayscaleEffect *) +Q_DECLARE_METATYPE(QGraphicsColorizeEffect *) +Q_DECLARE_METATYPE(QGraphicsPixelizeEffect *) +Q_DECLARE_METATYPE(QGraphicsBlurEffect *) +Q_DECLARE_METATYPE(QGraphicsBloomEffect *) +Q_DECLARE_METATYPE(QGraphicsFrameEffect *) +Q_DECLARE_METATYPE(QGraphicsShadowEffect *) + +#endif // QT_NO_GRAPHICSVIEW + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QGRAPHICSEFFECT_H diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 4e3677a..c395e21 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -552,6 +552,7 @@ #ifndef QT_NO_GRAPHICSVIEW +#include "qgraphicseffect.h" #include "qgraphicsscene.h" #include "qgraphicsscene_p.h" #include "qgraphicssceneevent.h" @@ -2189,6 +2190,125 @@ void QGraphicsItem::setOpacity(qreal opacity) } /*! + \since 4.6 + Returns this item's \e effect if it has one; otherwise, + returns 0. +*/ +QGraphicsEffect *QGraphicsItem::effect() const +{ + QGraphicsEffect *fx = 0; + if (d_ptr->hasEffect) + fx = d_ptr->extra(QGraphicsItemPrivate::ExtraEffect).value<QGraphicsEffect*>(); + + return fx; +} + +/*! + \since 4.6 + Sets \e effect as the item's effect. It will replace the previous effect + the item might have. +*/ +void QGraphicsItem::setEffect(QGraphicsEffect *effect) +{ + if (effect) { + d_ptr->hasEffect = true; + d_ptr->setExtra(QGraphicsItemPrivate::ExtraEffect, QVariant::fromValue(effect)); + } else { + d_ptr->hasEffect = false; + d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraEffect); + void *ptr = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectPixmap).value<void*>(); + QPixmap *pixmap = reinterpret_cast<QPixmap*>(ptr); + delete pixmap; + d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraEffectPixmap); + } + + update(); +} + +/*! + \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 QGraphicsItem::effectiveBoundingRect() const +{ + QGraphicsEffect *fx = effect(); + if (fx) + return fx->boundingRectFor(this); + + return boundingRect(); +} + +/*! + \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 QGraphicsItem::sceneEffectiveBoundingRect() const +{ + // Find translate-only offset + // COMBINE + QPointF offset; + const QGraphicsItem *parentItem = this; + 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); +} + +/*! + \internal + + Used by QGraphicsScene. +*/ +QPixmap *QGraphicsItem::effectPixmap() +{ + if (!d_ptr->hasEffect) + return 0; + + // the exact size of the pixmap is not a big deal + // as long as it contains the effective bounding rect + // TODO: use smart resizing etc + // TODO: store per device and do everything in device coordinate? + // TODO: use layer + QRect rect = effectiveBoundingRect().toAlignedRect(); + + void *ptr = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectPixmap).value<void*>(); + QPixmap *pixmap = reinterpret_cast<QPixmap*>(ptr); + bool avail = true; + if (!pixmap) + avail = false; + if (avail && pixmap->size() != rect.size()) + avail = false; + + if (!avail) { + delete pixmap; + pixmap = new QPixmap(rect.size()); + pixmap->fill(Qt::transparent); + ptr = reinterpret_cast<void*>(pixmap); + d_ptr->setExtra(QGraphicsItemPrivate::ExtraEffectPixmap, QVariant::fromValue(ptr)); + } + + return pixmap; +} + +/*! 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. diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 5c9297f..4cb94bf 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; @@ -206,6 +207,12 @@ public: qreal effectiveOpacity() const; void setOpacity(qreal opacity); + // Effect + QGraphicsEffect *effect() const; + void setEffect(QGraphicsEffect *effect); + QRectF effectiveBoundingRect() const; + QRectF sceneEffectiveBoundingRect() const; + Qt::MouseButtons acceptedMouseButtons() const; void setAcceptedMouseButtons(Qt::MouseButtons buttons); @@ -436,6 +443,8 @@ protected: void removeFromIndex(); void prepareGeometryChange(); + QPixmap *effectPixmap(); + private: Q_DISABLE_COPY(QGraphicsItem) Q_DECLARE_PRIVATE(QGraphicsItem) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 1cf188e..3f02560 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -102,7 +102,10 @@ public: ExtraCursor, ExtraCacheData, ExtraMaxDeviceCoordCacheSize, - ExtraBoundingRegionGranularity + ExtraBoundingRegionGranularity, + ExtraEffect, + ExtraEffectPixmap, + ExtraGestures }; enum AncestorFlag { @@ -149,6 +152,7 @@ public: allChildrenDirty(0), fullUpdatePending(0), flags(0), + hasEffect(0), dirtyChildrenBoundingRect(1), paintedViewBoundingRectsNeedRepaint(0), dirtySceneTransform(1), @@ -440,7 +444,8 @@ public: // New 32 bits quint32 fullUpdatePending : 1; - quint32 flags : 13; + quint32 flags : 12; + quint32 hasEffect : 1; quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 4796436..b2b9ebd 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -208,6 +208,7 @@ #ifndef QT_NO_GRAPHICSVIEW +#include "qgraphicseffect.h" #include "qgraphicsitem.h" #include "qgraphicsitem_p.h" #include "qgraphicslayout.h" @@ -3962,6 +3963,19 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte QGraphicsItemPrivate *itemd = item->d_ptr; QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode); + bool noCache = cacheMode == QGraphicsItem::NoCache || +#ifdef Q_WS_X11 + !X11->use_xrender; +#else + false; +#endif + + // Render using effect, works now only for no cache mode + if (noCache && itemd->hasEffect && item->effect()) { + item->effect()->drawItem(item, painter, option, widget); + return; + } + // Render directly, using no cache. if (cacheMode == QGraphicsItem::NoCache #ifdef Q_WS_X11 @@ -4257,6 +4271,62 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } } +// FIXME: merge this with drawItems (needs refactoring) +QPixmap* QGraphicsScene::drawItemOnPixmap(QPainter *painter, + QGraphicsItem *item, + const QStyleOptionGraphicsItem *option, + QWidget *widget, + int flags) +{ + // TODO: use for choosing item or device coordinate + // FIXME: how about source, dest, and exposed rects? + Q_UNUSED(flags); + + // Item's (local) bounding rect, including the effect + QRectF brect = item->effectiveBoundingRect(); + QRectF adjustedBrect(brect); + _q_adjustRect(&adjustedBrect); + if (adjustedBrect.isEmpty()) + return 0; + + // Find the item's bounds in device coordinates. + QRectF deviceBounds = painter->worldTransform().mapRect(brect); + QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1); + if (deviceRect.isEmpty()) + return 0; + + // If widget, check if it intersects or not + QRect viewRect = widget ? widget->rect() : QRect(); + if (widget && !viewRect.intersects(deviceRect)) + return 0; + + // Create offscreen pixmap + // TODO: use the pixmap from the layer + QPixmap *targetPixmap = item->effectPixmap(); + if (!targetPixmap) + targetPixmap = new QPixmap(deviceRect.size()); + + // FIXME: this is brute force + QRegion pixmapExposed; + pixmapExposed += targetPixmap->rect(); + + // Construct an item-to-pixmap transform. + QPointF p = deviceRect.topLeft(); + QTransform itemToPixmap = painter->worldTransform(); + if (!p.isNull()) + itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y()); + + // Calculate the style option's exposedRect. + QStyleOptionGraphicsItem fxOption = *option; + fxOption.exposedRect = brect.adjusted(-1, -1, 1, 1); + + // Render + _q_paintIntoCache(targetPixmap, item, pixmapExposed, itemToPixmap, painter->renderHints(), + &fxOption, false); + + return targetPixmap; +} + void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const viewTransform, QRegion *exposedRegion, QWidget *widget) { @@ -4385,7 +4455,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * painter->setClipPath(item->shape(), Qt::IntersectClip); painter->setOpacity(opacity); - if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget) + if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget && !item->d_ptr->hasEffect) item->paint(painter, &styleOptionTmp, widget); else drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection); diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index c0c6e75..6292afa 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -282,6 +282,11 @@ protected: const QStyleOptionGraphicsItem options[], QWidget *widget = 0); + QPixmap* drawItemOnPixmap(QPainter *painter, QGraphicsItem *item, + const QStyleOptionGraphicsItem *option, QWidget *widget, int flags); + + + protected Q_SLOTS: bool focusNextPrevChild(bool next); @@ -302,6 +307,7 @@ private: friend class QGraphicsViewPrivate; friend class QGraphicsWidget; friend class QGraphicsWidgetPrivate; + friend class QGraphicsEffect; friend class QGraphicsSceneIndex; friend class QGraphicsSceneIndexPrivate; friend class QGraphicsSceneBspTreeIndex; diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index a4bbdd2..7e95f70 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -280,6 +280,14 @@ static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item) return boundingRect; } +static inline QRectF adjustedItemEffectiveBoundingRect(const QGraphicsItem *item) +{ + Q_ASSERT(item); + QRectF boundingRect(item->effectiveBoundingRect()); + _q_adjustRect(&boundingRect); + return boundingRect; +} + QT_END_NAMESPACE #endif // QT_NO_GRAPHICSVIEW diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp index 184bd65..2b275a3 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. @@ -837,4 +840,236 @@ void QPixmapDropShadowFilter::draw(QPainter *p, // Draw the actual pixmap... p->drawPixmap(pos, px, src); } + +/*! + \class QPixmapBlurFilter + \since 4.6 + \ingroup multimedia + + \brief The QPixmapBlurFilter class is a convenience class + for drawing pixmaps with blur effects. + + 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 QPixmapConvolutionFilter + + \internal + */ + +class QPixmapBlurFilterPrivate : public QPixmapFilterPrivate +{ +public: + QPixmapBlurFilterPrivate() + : quality(QPixmapBlurFilter::High), radius(1) {} + + QPixmapBlurFilter::BlurQuality quality; + qreal radius; +}; + +/*! + Constructs blur filter and attaches it to \a parent. + + \internal +*/ +QPixmapBlurFilter::QPixmapBlurFilter(QObject *parent) + : QPixmapFilter(*new QPixmapBlurFilterPrivate, BlurFilter, parent) +{ + Q_D(QPixmapBlurFilter); + setBlurRadius(4); +} + +/*! + Destroys blur filter. + + \internal +*/ +QPixmapBlurFilter::~QPixmapBlurFilter() +{ +} + +/*! + \enum QPixmapFilter::BlurQuality + \since 4.6 + \ingroup multimedia + This enum describes the quality of blur to apply to pixmaps. + + \value Fast Blur faster, potentially losing some quality. + \value High Produce the best high-quality blur possible, even if slower. + + \internal +*/ + +/*! + Returns the quality of the blur. The default value is High. + + \sa blurRadius() + \internal +*/ +QPixmapBlurFilter::BlurQuality QPixmapBlurFilter::blurQuality() const +{ + Q_D(const QPixmapBlurFilter); + return d->quality; +} + +/*! + Sets the quality of the blur to the \a blurQuality specified. + + Setting the quality to Faster causes the implementation to trade + off visual quality to blur the image faster. Setting the quality + to High 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. + + \sa setBlurRadius() + \internal +*/ +void QPixmapBlurFilter::setBlurQuality(BlurQuality blurQuality) +{ + Q_D(QPixmapBlurFilter); + d->quality = blurQuality; +} + +/*! + Returns the radius in pixels of the blur. The default value is 4. + + A smaller radius results in a sharper image. + + \sa blurQuality() + \internal +*/ +qreal QPixmapBlurFilter::blurRadius() const +{ + Q_D(const QPixmapBlurFilter); + return d->radius; +} + +/*! + Sets the radius in pixels of the blur to the \a radius specified. + + Using a smaller radius results in a sharper image. + + \sa setBlurQuality() + \internal +*/ +void QPixmapBlurFilter::setBlurRadius(qreal blurRadius) +{ + Q_D(QPixmapBlurFilter); + d->radius = blurRadius; +} + +/*! + \internal + */ +QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const +{ + Q_D(const QPixmapBlurFilter); + qreal delta = d->radius * 3; + QRectF blurRect(rect); + blurRect.adjust(-delta, -delta, delta, delta); + return blurRect; +} + +// 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; +} + +/*! + \internal + */ +void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const +{ + Q_D(const QPixmapBlurFilter); + + QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ? + static_cast<QPaintEngineEx *>(painter->paintEngine())->createPixmapFilter(type()) : 0; + QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter); + if (blurFilter) { + blurFilter->setBlurQuality(d->quality); + blurFilter->setBlurRadius(d->radius); + blurFilter->draw(painter, dest, src, srcRect); + delete blurFilter; + return; + } + + QImage srcImage; + QImage destImage; + + if (srcRect.isNull()) { + srcImage = src.toImage(); + destImage = blurred(srcImage, srcImage.rect(), int(d->radius + 0.5)); + } else { + QRect rect = srcRect.toAlignedRect().intersected(src.rect()); + + srcImage = src.copy(rect).toImage(); + destImage = blurred(srcImage, srcImage.rect(), int(d->radius + 0.5)); + } + + qreal delta = d->radius * 3; + painter->drawImage(dest - QPointF(delta, delta), destImage); +} + QT_END_NAMESPACE diff --git a/src/gui/image/qpixmapfilter_p.h b/src/gui/image/qpixmapfilter_p.h index 51292b3..ca27cbf 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 }; @@ -158,6 +159,33 @@ public: inline void setOffset(qreal dx, qreal dy) { setOffset(QPointF(dx, dy)); } }; +class QPixmapBlurFilterPrivate; + +class Q_GUI_EXPORT QPixmapBlurFilter : public QPixmapFilter +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPixmapBlurFilter) + +public: + QPixmapBlurFilter(QObject *parent = 0); + ~QPixmapBlurFilter(); + + enum BlurQuality + { + Fast, + High + }; + + BlurQuality blurQuality() const; + void setBlurQuality(BlurQuality blurQuality); + + qreal blurRadius() const; + void setBlurRadius(qreal blurRadius); + + QRectF boundingRectFor(const QRectF &rect) const; + void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect = QRectF()) const; +}; + QT_END_NAMESPACE QT_END_HEADER |