diff options
author | Ian Walters <ian.walters@nokia.com> | 2009-05-05 05:46:31 (GMT) |
---|---|---|
committer | Ian Walters <ian.walters@nokia.com> | 2009-05-05 05:46:31 (GMT) |
commit | d1bb572b9fb5b0286df992c8ae560d91c9dc3388 (patch) | |
tree | d79063da3fa40a431da5ce795753eb27c9c8d2a1 /src/declarative/fx/qfxpainteditem.cpp | |
parent | 872c45c272ca71e8618475060aa28075e83fffce (diff) | |
download | Qt-d1bb572b9fb5b0286df992c8ae560d91c9dc3388.zip Qt-d1bb572b9fb5b0286df992c8ae560d91c9dc3388.tar.gz Qt-d1bb572b9fb5b0286df992c8ae560d91c9dc3388.tar.bz2 |
Rename QFxImageItem to QFxPaintedItem.
Done to avoid confusion with QFxImage and QFxAnimatedImage(Item)
Diffstat (limited to 'src/declarative/fx/qfxpainteditem.cpp')
-rw-r--r-- | src/declarative/fx/qfxpainteditem.cpp | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/src/declarative/fx/qfxpainteditem.cpp b/src/declarative/fx/qfxpainteditem.cpp new file mode 100644 index 0000000..950b468 --- /dev/null +++ b/src/declarative/fx/qfxpainteditem.cpp @@ -0,0 +1,346 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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 "qfxpainteditem.h" +#include "qfxpainteditem_p.h" + +#include <QDebug> +#include <QPen> +#include <QFile> +#include <QEvent> +#include <QApplication> +#include <QGraphicsSceneMouseEvent> + +#if defined(QFX_RENDER_OPENGL2) +#include <QtOpenGL/qglframebufferobject.h> +#include <glsave.h> +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QFxPaintedItem + \brief The QFxPaintedItem class is an abstract base class for QFxView items that want cached painting. + \ingroup group_coreitems + + This is a convenience class for implementing items that paint their contents + using a QPainter. The contents of the item are are cached behind the scenes. + The dirtyCache() function should be called if the contents change to + ensure the cache is refreshed the next time painting occurs. + + To subclass QFxPaintedItem, you must reimplement drawContents() to draw + the contents of the item. +*/ + +/*! + \fn void QFxPaintedItem::drawContents(QPainter *painter, const QRect &rect) + + This function is called when the cache needs to be refreshed. When + sub-classing QFxPaintedItem this function should be implemented so as to + paint the contents of the item using the given \a painter for the + area of the contents specified by \a rect. +*/ + +/*! + \property QFxPaintedItem::contentsSize + \brief The size of the contents + + The contents size is the size of the item in regards to how it is painted + using the drawContents() function. This is distinct from the size of the + item in regards to height() and width(). +*/ + +/*! + \property QFxPaintedItem::smooth + \brief Setting for whether smooth scaling is enabled. +*/ + +/*! + Marks areas of the cache that intersect with the given \a rect as dirty and + in need of being refreshed. + + \sa clearCache() +*/ +void QFxPaintedItem::dirtyCache(const QRect& rect) +{ + Q_D(QFxPaintedItem); + for (int i=0; i < d->imagecache.count(); ) { + if (d->imagecache[i]->area.intersects(rect)) { + d->imagecache.removeAt(i); + } else { + ++i; + } + } +} + +/*! + Marks the entirety of the contents cache as dirty. + + \sa dirtyCache() +*/ +void QFxPaintedItem::clearCache() +{ + Q_D(QFxPaintedItem); + qDeleteAll(d->imagecache); + d->imagecache.clear(); +} + +/*! + Returns if smooth scaling of the cache contents is enabled. + + \sa setSmooth() +*/ +bool QFxPaintedItem::isSmooth() const +{ + Q_D(const QFxPaintedItem); + return d->smooth; +} + +/*! + Returns the size of the contents. + + \sa setContentsSize() +*/ +QSize QFxPaintedItem::contentsSize() const +{ + Q_D(const QFxPaintedItem); + return d->contentsSize; +} + +/*! + If \a smooth is true sets the image item to enable smooth scaling of + the cache contents. + + \sa isSmooth() +*/ +void QFxPaintedItem::setSmooth(bool smooth) +{ + Q_D(QFxPaintedItem); + if (d->smooth == smooth) return; + d->smooth = smooth; + clearCache(); + update(); +} + +/*! + Sets the size of the contents to the given \a size. + + \sa contentsSize() +*/ +void QFxPaintedItem::setContentsSize(const QSize &size) +{ + Q_D(QFxPaintedItem); + if (d->contentsSize == size) return; + d->contentsSize = size; + clearCache(); + update(); +} + +/*! + Constructs a new QFxPaintedItem with the given \a parent. +*/ +QFxPaintedItem::QFxPaintedItem(QFxItem *parent) + : QFxItem(*(new QFxPaintedItemPrivate), parent) +{ + init(); +} + +/*! + \internal + Constructs a new QFxPaintedItem with the given \a parent and + initialized private data member \a dd. +*/ +QFxPaintedItem::QFxPaintedItem(QFxPaintedItemPrivate &dd, QFxItem *parent) + : QFxItem(dd, parent) +{ + init(); +} + +/*! + Destroys the image item. +*/ +QFxPaintedItem::~QFxPaintedItem() +{ +} + +/*! + \internal +*/ +void QFxPaintedItem::init() +{ + connect(this,SIGNAL(widthChanged()),this,SLOT(clearCache())); + connect(this,SIGNAL(heightChanged()),this,SLOT(clearCache())); + connect(this,SIGNAL(visibleChanged()),this,SLOT(clearCache())); +} + +#if defined(QFX_RENDER_QPAINTER) +/*! + \reimp +*/ +void QFxPaintedItem::paintContents(QPainter &p) +#elif defined(QFX_RENDER_OPENGL) +/*! + \reimp +*/ +void QFxPaintedItem::paintGLContents(GLPainter &p) +#else +#error "What render?" +#endif +{ + Q_D(QFxPaintedItem); + const QRect content(QPoint(0,0),d->contentsSize); + if (content.width() <= 0 || content.height() <= 0) + return; + +#if defined(QFX_RENDER_QPAINTER) + bool oldAntiAliasing = p.testRenderHint(QPainter::Antialiasing); + bool oldSmoothPixmap = p.testRenderHint(QPainter::SmoothPixmapTransform); + if (d->smooth) { + p.setRenderHints(QPainter::Antialiasing, true); + p.setRenderHints(QPainter::SmoothPixmapTransform, true); + } + QRectF clipf = p.clipRegion().boundingRect(); + if (clipf.isEmpty()) + clipf = mapToScene(content); // ### Inefficient: Maps toScene and then fromScene + else + clipf = mapToScene(clipf); + +#elif defined(QFX_RENDER_OPENGL2) + p.useTextureShader(); + const QRectF clipf = p.sceneClipRect; + +#elif defined(QFX_RENDER_OPENGL1) + p.useTextureShader(); + const QRectF clipf = p.sceneClipRect; +#endif + + qreal hscale = widthValid() ? qreal(width()) / content.width() : heightValid() ? qreal(height()) / content.height() : 1.0; + qreal vscale = heightValid() ? qreal(height()) / content.height() : widthValid() ? qreal(width()) / content.width() : 1.0; + const QRect clip = mapFromScene(QRectF(clipf.x()/hscale,clipf.y()/vscale,clipf.width()/hscale,clipf.height()/vscale)).toRect(); + + QRegion topaint(clip); + topaint &= content; + QRegion uncached(content); + +#if defined(QFX_RENDER_OPENGL2) + glEnableVertexAttribArray(SingleTextureShader::Vertices); + glEnableVertexAttribArray(SingleTextureShader::TextureCoords); +#elif defined(QFX_RENDER_OPENGL1) + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +#endif + + int cachesize=0; + for (int i=0; i<d->imagecache.count(); ++i) { + QRect area = d->imagecache[i]->area; + if (topaint.contains(area)) { + QRectF target(area.x()*hscale, area.y()*vscale, area.width()*hscale, area.height()*vscale); + p.drawImage(target.toRect(), d->imagecache[i]->image); + topaint -= area; + d->imagecache[i]->age=0; + } else { + d->imagecache[i]->age++; + } + cachesize += area.width()*area.height(); + uncached -= area; + } + + if (!topaint.isEmpty()) { + // Find a sensible larger area, otherwise will paint lots of tiny images. + QRect biggerrect = topaint.boundingRect().adjusted(-64,-64,128,128); + cachesize += biggerrect.width() * biggerrect.height(); + while (d->imagecache.count() && cachesize > d->max_imagecache_size) { + int oldest=-1; + int age=-1; + for (int i=0; i<d->imagecache.count(); ++i) { + int a = d->imagecache[i]->age; + if (a > age) { + oldest = i; + age = a; + } + } + cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height(); + uncached += d->imagecache[oldest]->area; + d->imagecache.removeAt(oldest); + } + const QRegion bigger = QRegion(biggerrect) & uncached; + const QVector<QRect> rects = bigger.rects(); + for (int i = 0; i < rects.count(); ++i) { + const QRect &r = rects.at(i); +#if defined(QFX_RENDER_QPAINTER) + QImage img(r.size(),QImage::Format_ARGB32_Premultiplied); +#else + QImage img(r.size(),QImage::Format_ARGB32); +#endif + img.fill(0); + { + QPainter qp(&img); + qp.translate(-r.x(),-r.y()); + drawContents(&qp, r); + } + QFxPaintedItemPrivate::ImageCacheItem *newitem = new QFxPaintedItemPrivate::ImageCacheItem; + newitem->area = r; +#if defined(QFX_RENDER_QPAINTER) + newitem->image = QSimpleCanvasConfig::Image(QSimpleCanvasConfig::toImage(img)); +#else + newitem->image.setImage(img); +#endif + d->imagecache.append(newitem); + QRectF target(r.x()*hscale, r.y()*vscale, r.width()*hscale, r.height()*vscale); + p.drawImage(target.toRect(), newitem->image); + } + } +#if defined(QFX_RENDER_OPENGL2) + glDisableVertexAttribArray(SingleTextureShader::Vertices); + glDisableVertexAttribArray(SingleTextureShader::TextureCoords); +#elif defined(QFX_RENDER_OPENGL1) + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +#endif +#if defined(QFX_RENDER_QPAINTER) + if (d->smooth) { + p.setRenderHints(QPainter::Antialiasing, oldAntiAliasing); + p.setRenderHints(QPainter::SmoothPixmapTransform, oldSmoothPixmap); + } +#endif +} + +QT_END_NAMESPACE |