summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJens Bache-Wiig <jens.bache-wiig@nokia.com>2010-09-03 10:48:40 +0200
committerJens Bache-Wiig <jens.bache-wiig@nokia.com>2010-09-03 10:48:40 +0200
commit99e845301a6e5a3b560e90835238553c140959ab (patch)
tree989026f347882b167b3e7178cd1899a76a423f2b /src
parent85e3e09aa6d04d5c857cc1388c1c9dfc3f06aaae (diff)
Allow getting the context everywhere. No more onPaint.
Diffstat (limited to 'src')
-rw-r--r--src/canvas.cpp68
-rw-r--r--src/canvas.h36
-rw-r--r--src/canvasplugin.cpp2
-rw-r--r--src/context2d.cpp162
-rw-r--r--src/context2d.h22
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