diff options
author | Jens Bache-Wiig <jens.bache-wiig@nokia.com> | 2010-09-03 10:48:40 +0200 |
---|---|---|
committer | Jens Bache-Wiig <jens.bache-wiig@nokia.com> | 2010-09-03 10:48:40 +0200 |
commit | 99e845301a6e5a3b560e90835238553c140959ab (patch) | |
tree | 989026f347882b167b3e7178cd1899a76a423f2b /src | |
parent | 85e3e09aa6d04d5c857cc1388c1c9dfc3f06aaae (diff) |
Allow getting the context everywhere. No more onPaint.
Diffstat (limited to 'src')
-rw-r--r-- | src/canvas.cpp | 68 | ||||
-rw-r--r-- | src/canvas.h | 36 | ||||
-rw-r--r-- | src/canvasplugin.cpp | 2 | ||||
-rw-r--r-- | src/context2d.cpp | 162 | ||||
-rw-r--r-- | src/context2d.h | 22 |
5 files changed, 220 insertions, 70 deletions
diff --git a/src/canvas.cpp b/src/canvas.cpp index a657948..05cde71 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -38,15 +38,40 @@ ****************************************************************************/ #include "canvas.h" +#include "context2d.h" #include <QPainter> Canvas::Canvas(QDeclarativeItem *parent) - : QDeclarativeItem(parent) + : QDeclarativeItem(parent), + m_context(new Context2D(this)), + m_canvasWidth(0), + m_canvasHeight(0) { setFlag(QGraphicsItem::ItemHasNoContents, false); - setCacheMode(QGraphicsItem::ItemCoordinateCache); - setSmooth(true); +} + + +void Canvas::componentComplete() +{ + if (m_canvasWidth == 0 && m_canvasHeight == 0) + m_context->setSize(width(), height()); + else + m_context->setSize(m_canvasWidth, m_canvasHeight); + + connect(m_context, SIGNAL(changed()), this, SLOT(updateCanvas())); +} + +void Canvas::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + painter->setRenderHint(QPainter::SmoothPixmapTransform, smooth()); + if (!m_context->pixmap().isNull()) + painter->drawPixmap(0, 0, width(), height(), m_context->pixmap()); +} + +Context2D *Canvas::getContext() +{ + return m_context; } void Canvas::updateCanvas() @@ -54,12 +79,37 @@ void Canvas::updateCanvas() update(); } -void Canvas::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +void Canvas::geometryChanged(const QRectF &newGeometry, const QRectF &) +{ + if (m_canvasWidth == 0 && m_canvasHeight == 0 + && newGeometry.width() > 0 && newGeometry.height() > 0) { + m_context->setSize(width(), height()); + } +} + +void Canvas::setCanvasWidth(int newWidth) { - painter->save(); - painter->setRenderHint(QPainter::Antialiasing, smooth()); - Context2D context(this, painter); - emit paint(&context); - painter->restore(); + if (m_canvasWidth != newWidth) { + m_canvasWidth = newWidth; + m_context->setSize(m_canvasWidth, m_canvasHeight); + emit canvasWidthChanged(); + } } +void Canvas::setCanvasHeight(int newHeight) +{ + if (m_canvasHeight != newHeight) { + m_canvasHeight = newHeight; + m_context->setSize(m_canvasWidth, m_canvasHeight); + emit canvasHeightChanged(); + } +} + +void Canvas::setFillMode(FillMode mode) +{ + if (m_fillMode == mode) + return; + m_fillMode = mode; + update(); + emit fillModeChanged(); +} diff --git a/src/canvas.h b/src/canvas.h index c20f29f..b492f80 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -43,25 +43,47 @@ #include <QDeclarativeItem> #include "context2d.h" -class Context2D; - class Canvas : public QDeclarativeItem { Q_OBJECT + Q_ENUMS(FillMode) + Q_PROPERTY(int canvasWidth READ canvasWidth WRITE setCanvasWidth NOTIFY canvasWidthChanged); + Q_PROPERTY(int canvasHeight READ canvasHeight WRITE setCanvasHeight NOTIFY canvasHeightChanged); + Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) + public: + Canvas(QDeclarativeItem *parent = 0); + enum FillMode { Stretch, PreserveAspectFit, PreserveAspectCrop, Tile, TileVertically, TileHorizontally }; + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - Canvas(QDeclarativeItem *parent = 0); + void setCanvasWidth(int newWidth); + int canvasWidth() {return m_canvasWidth;} + + void setCanvasHeight(int canvasHeight); + int canvasHeight() {return m_canvasHeight;} -public slots: + void componentComplete(); + +public Q_SLOTS: + Context2D *getContext(); void updateCanvas(); -signals: - void paint(Context2D *ctx); + FillMode fillMode() const; + void setFillMode(FillMode); + +Q_SIGNALS: + void fillModeChanged(); + void canvasWidthChanged(); + void canvasHeightChanged(); private: - QPixmap m_cache; + Context2D *m_context; + int m_canvasWidth; + int m_canvasHeight; + FillMode m_fillMode; }; #endif diff --git a/src/canvasplugin.cpp b/src/canvasplugin.cpp index 8a67d3d..14948d1 100644 --- a/src/canvasplugin.cpp +++ b/src/canvasplugin.cpp @@ -39,11 +39,11 @@ #include <qdeclarative.h> #include "canvasplugin.h" +#include "context2d.h" #include "canvas.h" void CanvasPlugin::registerTypes(const char *uri) { - qDebug("test %s", uri); qmlRegisterType<Canvas>(uri, 1, 0, "Canvas"); qmlRegisterType<Context2D>(uri, 1, 0, "Context2D"); qmlRegisterUncreatableType<CanvasImage>(uri, 1, 0, "CanvasImage", QString()); diff --git a/src/context2d.cpp b/src/context2d.cpp index c1e5708..97c25e7 100644 --- a/src/context2d.cpp +++ b/src/context2d.cpp @@ -460,20 +460,22 @@ QString Context2D::shadowColor() const void Context2D::clearRect(qreal x, qreal y, qreal w, qreal h) { beginPainting(); - m_painter->save(); - m_painter->setMatrix(m_state.matrix, false); - m_painter->setCompositionMode(QPainter::CompositionMode_Source); - m_painter->fillRect(QRectF(x, y, w, h), QColor(0, 0, 0, 0)); - m_painter->restore(); + m_painter.save(); + m_painter.setMatrix(m_state.matrix, false); + m_painter.setCompositionMode(QPainter::CompositionMode_Source); + m_painter.fillRect(QRectF(x, y, w, h), QColor(0, 0, 0, 0)); + m_painter.restore(); + scheduleChange(); } void Context2D::fillRect(qreal x, qreal y, qreal w, qreal h) { beginPainting(); - m_painter->save(); - m_painter->setMatrix(m_state.matrix, false); - m_painter->fillRect(QRectF(x, y, w, h), m_painter->brush()); - m_painter->restore(); + m_painter.save(); + m_painter.setMatrix(m_state.matrix, false); + m_painter.fillRect(QRectF(x, y, w, h), m_painter.brush()); + m_painter.restore(); + scheduleChange(); } void Context2D::strokeRect(qreal x, qreal y, qreal w, qreal h) @@ -481,10 +483,11 @@ void Context2D::strokeRect(qreal x, qreal y, qreal w, qreal h) QPainterPath path; path.addRect(x, y, w, h); beginPainting(); - m_painter->save(); - m_painter->setMatrix(m_state.matrix, false); - m_painter->strokePath(path, m_painter->pen()); - m_painter->restore(); + m_painter.save(); + m_painter.setMatrix(m_state.matrix, false); + m_painter.strokePath(path, m_painter.pen()); + m_painter.restore(); + scheduleChange(); } @@ -599,18 +602,20 @@ void Context2D::arc(qreal xc, qreal yc, qreal radius, void Context2D::fill() { beginPainting(); - m_painter->fillPath(m_path, m_painter->brush()); + m_painter.fillPath(m_path, m_painter.brush()); + scheduleChange(); } void Context2D::stroke() { beginPainting(); - m_painter->save(); - m_painter->setMatrix(m_state.matrix, false); + m_painter.save(); + m_painter.setMatrix(m_state.matrix, false); QPainterPath tmp = m_state.matrix.inverted().map(m_path); - m_painter->strokePath(tmp, m_painter->pen()); - m_painter->restore(); + m_painter.strokePath(tmp, m_painter.pen()); + m_painter.restore(); + scheduleChange(); } @@ -644,42 +649,74 @@ void Context2D::putImageData(ImageData image, qreal dx, qreal dy) Q_UNUSED(dy); } -Context2D::Context2D(QObject *parent, QPainter *painter) - : QObject(parent), m_changeTimerId(-1), m_painter(painter) +Context2D::Context2D(QObject *parent) + : QObject(parent), m_changeTimerId(-1), m_width(0), m_height(0) { reset(); } void Context2D::beginPainting() { - if ((m_state.flags & DirtyClippingRegion) && !m_state.clipPath.isEmpty()) - m_painter->setClipPath(m_state.clipPath); - if (m_state.flags & DirtyFillStyle) - m_painter->setBrush(m_state.fillStyle); - if (m_state.flags & DirtyGlobalAlpha) - m_painter->setOpacity(m_state.globalAlpha); - if (m_state.flags & DirtyGlobalCompositeOperation) - m_painter->setCompositionMode(m_state.globalCompositeOperation); - if (m_state.flags & MDirtyPen) { - QPen pen = m_painter->pen(); - if (m_state.flags & DirtyStrokeStyle) - pen.setBrush(m_state.strokeStyle); - if (m_state.flags & DirtyLineWidth) - pen.setWidthF(m_state.lineWidth); - if (m_state.flags & DirtyLineCap) - pen.setCapStyle(m_state.lineCap); - if (m_state.flags & DirtyLineJoin) - pen.setJoinStyle(m_state.lineJoin); - if (m_state.flags & DirtyMiterLimit) - pen.setMiterLimit(m_state.miterLimit); - m_painter->setPen(pen); + if (m_width <= 0 || m_height <=0) + return; + + if (m_pixmap.width() != m_width || m_pixmap.height() != m_height) { + m_pixmap = QPixmap(m_width, m_height); + m_pixmap.fill(Qt::transparent); + } + + if (!m_painter.isActive()) { + m_painter.begin(&m_pixmap); + m_painter.setRenderHint(QPainter::Antialiasing); + if (!m_state.clipPath.isEmpty()) + m_painter.setClipPath(m_state.clipPath); + m_painter.setBrush(m_state.fillStyle); + m_painter.setOpacity(m_state.globalAlpha); + QPen pen; + pen.setBrush(m_state.strokeStyle); + if (pen.style() == Qt::NoPen) + pen.setStyle(Qt::SolidLine); + pen.setCapStyle(m_state.lineCap); + pen.setJoinStyle(m_state.lineJoin); + pen.setWidthF(m_state.lineWidth); + pen.setMiterLimit(m_state.miterLimit); + m_painter.setPen(pen); + } else { + if ((m_state.flags & DirtyClippingRegion) && !m_state.clipPath.isEmpty()) + m_painter.setClipPath(m_state.clipPath); + if (m_state.flags & DirtyFillStyle) + m_painter.setBrush(m_state.fillStyle); + if (m_state.flags & DirtyGlobalAlpha) + m_painter.setOpacity(m_state.globalAlpha); + if (m_state.flags & DirtyGlobalCompositeOperation) + m_painter.setCompositionMode(m_state.globalCompositeOperation); + if (m_state.flags & MDirtyPen) { + QPen pen = m_painter.pen(); + if (m_state.flags & DirtyStrokeStyle) + pen.setBrush(m_state.strokeStyle); + if (m_state.flags & DirtyLineWidth) + pen.setWidthF(m_state.lineWidth); + if (m_state.flags & DirtyLineCap) + pen.setCapStyle(m_state.lineCap); + if (m_state.flags & DirtyLineJoin) + pen.setJoinStyle(m_state.lineJoin); + if (m_state.flags & DirtyMiterLimit) + pen.setMiterLimit(m_state.miterLimit); + m_painter.setPen(pen); + } + m_state.flags = 0; } - m_state.flags = 0; +} + +void Context2D::endPainting() +{ + if (m_painter.isActive()) + m_painter.end(); } void Context2D::clear() { - m_painter->fillRect(QRect(QPoint(0,0), size()), Qt::white); +// m_painter.fillRect(QRect(QPoint(0,0), size()), Qt::white); } void Context2D::reset() @@ -711,12 +748,45 @@ void Context2D::drawImage(const QVariant &var, qreal sx, qreal sy, return; beginPainting(); if (sw == sh) - m_painter->drawImage(QPointF(sx, sy), image->value()); + m_painter.drawImage(QPointF(sx, sy), image->value()); else - m_painter->drawImage(QRectF(sx, sy, sw, sh), image->value()); + m_painter.drawImage(QRectF(sx, sy, sw, sh), image->value()); + scheduleChange(); +} + +void Context2D::setSize(int width, int height) +{ + endPainting(); + m_width = width; + m_height = height; + + scheduleChange(); +} + +void Context2D::setSize(const QSize &size) +{ + setSize(size.width(), size.height()); } QSize Context2D::size() const { - return m_painter->viewport().size(); + return m_pixmap.size(); +} + +void Context2D::scheduleChange() +{ + if (m_changeTimerId == -1) + m_changeTimerId = startTimer(0); +} + +void Context2D::timerEvent(QTimerEvent *e) +{ + if (e->timerId() == m_changeTimerId) { + killTimer(m_changeTimerId); + m_changeTimerId = -1; + endPainting(); + emit changed(); + } else { + QObject::timerEvent(e); + } } diff --git a/src/context2d.h b/src/context2d.h index a4c2421..8bdf10e 100644 --- a/src/context2d.h +++ b/src/context2d.h @@ -47,6 +47,7 @@ #include <QMetaType> #include <QTimerEvent> #include <QVariant> + #include <qdebug.h> QColor colorFromString(const QString &name); @@ -99,10 +100,8 @@ Q_DECLARE_METATYPE(CanvasImage*) class ImageData { }; -class QContext2DCanvas; - class Context2D : public QObject -{ + { Q_OBJECT // compositing Q_PROPERTY(qreal globalAlpha READ globalAlpha WRITE setGlobalAlpha) @@ -121,12 +120,19 @@ class Context2D : public QObject Q_PROPERTY(QString shadowColor READ shadowColor WRITE setShadowColor) public: - Context2D(QObject *parent = 0, QPainter *painter = 0); + Context2D(QObject *parent = 0); + void setSize(int width, int height); + void setSize(const QSize &size); QSize size() const; + void scheduleChange(); + void timerEvent(QTimerEvent *e); + void clear(); void reset(); + QPixmap pixmap() { return m_pixmap; } + // compositing qreal globalAlpha() const; // (default 1.0) QString globalCompositeOperation() const; // (default over) @@ -160,7 +166,6 @@ public: void setShadowBlur(qreal b); void setShadowColor(const QString &str); - //! [1] public slots: void save(); // push state on state stack void restore(); // pop state stack and restore state @@ -212,13 +217,13 @@ public slots: void putImageData(ImageData image, qreal dx, qreal dy); signals: - void changed(const QImage &image); + void changed(); private: void beginPainting(); + void endPainting(); int m_changeTimerId; - QPainter *m_painter; QPainterPath m_path; enum DirtyFlag { @@ -270,6 +275,9 @@ private: }; State m_state; QStack<State> m_stateStack; + QPixmap m_pixmap; + QPainter m_painter; + int m_width, m_height; }; #endif |