summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Bache-Wiig <jbache@trolltech.com>2010-09-17 12:48:59 +0200
committerJens Bache-Wiig <jbache@trolltech.com>2010-09-17 12:48:59 +0200
commitf4eea04c2d2fc155d5033bfee9f5472f8b2f4397 (patch)
treeb5276b9d3bfdb0d076154e7e63ee214a1bdd9fbf
parent0664730693381ac05fa96e0f2604e726dc5e1bb3 (diff)
Add support for drop shadow and image copy
The shadow is a bit experimental still...
-rw-r--r--src/canvas.cpp8
-rw-r--r--src/canvas.h5
-rw-r--r--src/context2d.cpp93
-rw-r--r--src/context2d.h8
4 files changed, 101 insertions, 13 deletions
diff --git a/src/canvas.cpp b/src/canvas.cpp
index 5fe8408..e5c6bf8 100644
--- a/src/canvas.cpp
+++ b/src/canvas.cpp
@@ -166,7 +166,7 @@ void Canvas::requestPaint()
void Canvas::geometryChanged(const QRectF &newGeometry, const QRectF &)
{
if (m_canvasWidth == 0 && m_canvasHeight == 0
- && newGeometry.width() > 0 && newGeometry.height() > 0) {
+ && newGeometry.width() > 0 && newGeometry.height() > 0) {
m_context->setSize(width(), height());
}
}
@@ -222,6 +222,11 @@ bool Canvas::save(const QString &filename) const
return m_context->pixmap().save(filename);
}
+CanvasImage *Canvas::toImage() const
+{
+ return new CanvasImage(m_context->pixmap());
+}
+
void Canvas::setTimeout(const QScriptValue &handler, long timeout)
{
if (handler.isFunction())
@@ -243,4 +248,3 @@ void Canvas::clearInterval(const QScriptValue &handler)
{
CanvasTimer::removeTimer(handler);
}
-
diff --git a/src/canvas.h b/src/canvas.h
index 7f5c286..718e3df 100644
--- a/src/canvas.h
+++ b/src/canvas.h
@@ -82,14 +82,15 @@ public Q_SLOTS:
// Save current canvas to disk
bool save(const QString& filename) const;
+ // Return canvas contents as a drawable image
+ CanvasImage *toImage() const;
+
// Timers
void setInterval(const QScriptValue &handler, long timeout);
void setTimeout(const QScriptValue &handler, long timeout);
void clearInterval(const QScriptValue &handler);
void clearTimeout(const QScriptValue &handler);
- bool save(const QString& filename) const;
-
Q_SIGNALS:
void fillModeChanged();
void canvasWidthChanged();
diff --git a/src/context2d.cpp b/src/context2d.cpp
index 3f1c2ef..52d0864 100644
--- a/src/context2d.cpp
+++ b/src/context2d.cpp
@@ -42,6 +42,21 @@
#include <math.h>
static const double Q_PI = 3.14159265358979323846; // pi
+#include <QGraphicsItem>
+#include <QStyleOptionGraphicsItem>
+#include <QGraphicsDropShadowEffect>
+
+class CustomDropShadowEffect : public QGraphicsDropShadowEffect
+{
+public:
+ void draw(QPainter *painter) { QGraphicsDropShadowEffect::draw(painter);}
+ void drawSource(QPainter *painter) { QGraphicsDropShadowEffect::drawSource(painter);}
+};
+
+// Note, this is exported but in a private header as qtopengl depends on it.
+// But it really should be considered private API
+void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0);
+
#define DEGREES(t) ((t) * 180.0 / Q_PI)
#define qClamp(val, min, max) qMin(qMax(val, min), max)
@@ -108,7 +123,7 @@ QColor colorFromString(const QString &name)
return QColor();
}
return QColor::fromHslF(compo[0], compo[1],
- compo[2], compo[3]);
+ compo[2], compo[3]);
} else if (name.startsWith("hsl(")){
++itr; ++itr; ++itr; ++itr; ++itr;
compo = parseNumbersList(itr);
@@ -116,7 +131,7 @@ QColor colorFromString(const QString &name)
return QColor();
}
return QColor::fromHslF(compo[0], compo[1],
- compo[2]);
+ compo[2]);
} else {
//QRgb color;
//CSSParser::parseColor(name, color);
@@ -480,6 +495,7 @@ void Context2D::clearRect(qreal x, qreal y, qreal w, qreal h)
m_painter.setMatrix(m_state.matrix, false);
m_painter.setCompositionMode(QPainter::CompositionMode_Source);
QColor fillColor = parent()->property("color").value<QColor>();
+
m_painter.fillRect(QRectF(x, y, w, h), fillColor);
m_painter.restore();
scheduleChange();
@@ -682,8 +698,18 @@ void Context2D::beginPainting()
m_pixmap.fill(parent()->property("color").value<QColor>());
}
+ if (m_state.shadowBlur > 0) {
+ if (m_shadowbuffer.width() != m_width || m_shadowbuffer.height() != m_height)
+ m_shadowbuffer = QPixmap(m_width, m_height);
+ m_shadowbuffer.fill(Qt::transparent);
+ }
+
if (!m_painter.isActive()) {
- m_painter.begin(&m_pixmap);
+ if (m_state.shadowBlur == 0)
+ m_painter.begin(&m_pixmap);
+ else
+ m_painter.begin(&m_shadowbuffer);
+
m_painter.setRenderHint(QPainter::Antialiasing);
if (!m_state.clipPath.isEmpty())
m_painter.setClipPath(m_state.clipPath);
@@ -699,7 +725,6 @@ void Context2D::beginPainting()
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)
@@ -730,6 +755,60 @@ void Context2D::endPainting()
{
if (m_painter.isActive())
m_painter.end();
+
+ if (m_state.shadowBlur > 0) {
+ m_painter.begin(&m_pixmap);
+
+ // Draw shadow
+ QImage tmp(m_shadowbuffer.size(), QImage::Format_ARGB32_Premultiplied);
+ tmp.fill(Qt::transparent);
+
+ QRect imageRect = m_pixmap.rect();
+
+ QPainter tmpPainter(&tmp);
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ tmpPainter.drawPixmap(0, 0, m_shadowbuffer);
+ tmpPainter.end();
+
+ // blur the alpha channel
+ QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
+ blurred.fill(Qt::transparent);
+ QPainter blurPainter(&blurred);
+ qt_blurImage(&blurPainter, tmp, m_state.shadowBlur, false, true);
+ blurPainter.end();
+
+ tmp = blurred;
+
+ // blacken the image...
+ tmpPainter.begin(&tmp);
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ tmpPainter.fillRect(imageRect, m_state.shadowColor);
+ tmpPainter.end();
+
+ tmpPainter.begin(&tmp);
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ tmpPainter.fillRect(imageRect, m_state.shadowColor);
+ tmpPainter.end();
+
+ // draw the blurred drop shadow...
+ m_painter.drawImage(QRect(m_state.shadowOffsetX, m_state.shadowOffsetY, imageRect.width(), imageRect.height()), tmp);
+
+ // draw source
+ m_painter.drawPixmap(0, 0, m_shadowbuffer);
+ /*
+ CustomDropShadowEffect *effect = new CustomDropShadowEffect;
+ effect->setBlurRadius(m_state.shadowBlur);
+ effect->setColor(m_state.shadowColor);
+ effect->setOffset(m_state.shadowOffsetX, m_state.shadowOffsetY);
+ effect->setEnabled(true);
+*/ // QStyleOptionGraphicsItem option;
+ // QGraphicsPixmapItem *item = new QGraphicsPixmapItem(m_shadowbuffer, 0, 0);
+ // item->setGraphicsEffect(effect);
+ // effect->drawSource(&m_painter);
+ // option.rect = QRect(0, 0, m_pixmap.width(), m_pixmap.height());
+ // item->setGraphicsEffect(0);
+ // item->paint(&m_painter, &option, 0);
+ }
}
void Context2D::clear()
@@ -765,10 +844,10 @@ void Context2D::drawImage(const QVariant &var, qreal sx, qreal sy,
if (!image)
return;
beginPainting();
- if (sw == sh)
- m_painter.drawImage(QPointF(sx, sy), image->value());
+ if (sw == sh && sh == 0)
+ m_painter.drawPixmap(QPointF(sx, sy), image->value());
else
- m_painter.drawImage(QRectF(sx, sy, sw, sh), image->value());
+ m_painter.drawPixmap(QRect(sx, sy, sw, sh), image->value());
scheduleChange();
}
diff --git a/src/context2d.h b/src/context2d.h
index 354943f..a8da860 100644
--- a/src/context2d.h
+++ b/src/context2d.h
@@ -50,6 +50,8 @@
#include <qdebug.h>
+#include <QPixmap>
+
QColor colorFromString(const QString &name);
class CanvasGradient : public QObject
@@ -79,18 +81,19 @@ class CanvasImage: public QObject
public:
CanvasImage() {}
CanvasImage(const QString &url) : m_image(url), m_src(url) {}
+ CanvasImage(const QPixmap &pixmap) {m_image = pixmap;}
public slots:
int width() { return m_image.width(); }
int height() { return m_image.height(); }
- QImage value() { return m_image; }
+ QPixmap &value() { return m_image; }
QString src() { return m_src; }
void setSrc(const QString &src) { m_src = src; m_image.load(src); emit sourceChanged();}
signals:
void sourceChanged();
private:
- QImage m_image;
+ QPixmap m_image;
QString m_src;
};
@@ -277,6 +280,7 @@ private:
State m_state;
QStack<State> m_stateStack;
QPixmap m_pixmap;
+ QPixmap m_shadowbuffer;
QPainter m_painter;
int m_width, m_height;
bool m_inPaint;