diff options
author | Jens Bache-Wiig <jbache@trolltech.com> | 2010-09-17 12:48:59 +0200 |
---|---|---|
committer | Jens Bache-Wiig <jbache@trolltech.com> | 2010-09-17 12:48:59 +0200 |
commit | f4eea04c2d2fc155d5033bfee9f5472f8b2f4397 (patch) | |
tree | b5276b9d3bfdb0d076154e7e63ee214a1bdd9fbf | |
parent | 0664730693381ac05fa96e0f2604e726dc5e1bb3 (diff) |
Add support for drop shadow and image copy
The shadow is a bit experimental still...
-rw-r--r-- | src/canvas.cpp | 8 | ||||
-rw-r--r-- | src/canvas.h | 5 | ||||
-rw-r--r-- | src/context2d.cpp | 93 | ||||
-rw-r--r-- | src/context2d.h | 8 |
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; |