diff options
author | Colin Ogilvie <colin.ogilvie@kdab.com> | 2018-07-03 14:29:27 +0100 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2018-07-12 20:26:34 +0000 |
commit | eab3371b91a2a752a123c4995d977a36ff952168 (patch) | |
tree | ca15f0c6bb58634d3444bdbbe25e355e852c2cc7 /src | |
parent | 1c6751558668c3527233d8b2d2e252f2ea133624 (diff) |
Add LineStyle support to Context2d
Allow Context2D lines to be drawn as dashed, dotted etc.
[ChangeLog][QtQuick][Canvas] Added set/get lineDash and lineDashOffset to Context2D to allow non solid lines to be drawn.
Task-number: QTBUG-31807
Change-Id: I9ffcc5d93dc352dbd0aec4ac8a616c999239c48d
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/quick/doc/images/qml-item-canvas-lineDash.png | bin | 0 -> 6254 bytes | |||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2d.cpp | 127 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2d_p.h | 5 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp | 26 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h | 14 |
5 files changed, 172 insertions, 0 deletions
diff --git a/src/quick/doc/images/qml-item-canvas-lineDash.png b/src/quick/doc/images/qml-item-canvas-lineDash.png Binary files differnew file mode 100644 index 0000000000..a2a038abe0 --- /dev/null +++ b/src/quick/doc/images/qml-item-canvas-lineDash.png diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 8f21c3ec05..e4012941cd 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -563,6 +563,8 @@ struct QQuickJSContext2D : public QV4::Object static QV4::ReturnedValue method_set_lineWidth(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_get_miterLimit(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_set_miterLimit(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QV4::ReturnedValue method_set_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QV4::ReturnedValue method_get_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_get_shadowBlur(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_set_shadowBlur(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); @@ -641,6 +643,8 @@ public: o->defineDefaultProperty(QStringLiteral("createLinearGradient"), method_createLinearGradient, 0); o->defineDefaultProperty(QStringLiteral("strokeRect"), method_strokeRect, 0); o->defineDefaultProperty(QStringLiteral("closePath"), method_closePath, 0); + o->defineDefaultProperty(QStringLiteral("setLineDash"), method_setLineDash, 0); + o->defineDefaultProperty(QStringLiteral("getLineDash"), method_getLineDash, 0); o->defineAccessorProperty(QStringLiteral("canvas"), QQuickJSContext2DPrototype::method_get_canvas, nullptr); return o->d(); @@ -690,6 +694,8 @@ public: static QV4::ReturnedValue method_createImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_getImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_putImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QV4::ReturnedValue method_setLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QV4::ReturnedValue method_getLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); }; @@ -1963,6 +1969,122 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(const QV4::FunctionO RETURN_UNDEFINED(); } +/*! + \qmlmethod array QtQuick::Context2D::getLineDash() + \since QtQuick 2.11 + Returns an array of qreals representing the dash pattern of the line. + + \sa setLineDash() + */ +QV4::ReturnedValue QQuickJSContext2DPrototype::method_getLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) +{ + QV4::Scope scope(b); + QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); + CHECK_CONTEXT(r) + + const QVector<qreal> pattern = r->d()->context->state.lineDash; + QV4::ScopedArrayObject array(scope, scope.engine->newArrayObject(pattern.size())); + array->arrayReserve(pattern.size()); + for (int i = 0; i < pattern.size(); i++) + array->put(i, QV4::Primitive::fromDouble(pattern[i])); + + array->setArrayLengthUnchecked(pattern.size()); + + RETURN_RESULT(*array); +} + +/*! + \qmlmethod QtQuick::Context2D::setLineDash(array pattern) + \since QtQuick 2.11 + Sets the dash pattern to the given pattern + + \a pattern a list of numbers that specifies distances to alternately draw a line and a gap. + + If the number of elements in the array is odd, the elements of the array get copied + and concatenated. For example, [5, 15, 25] will become [5, 15, 25, 5, 15, 25]. + + \table 100% + \row + \li \inlineimage qml-item-canvas-lineDash.png + \li + \code + var space = 4 + ctx.setLineDash([1, space, 3, space, 9, space, 27, space, 9, space]) + ... + ctx.stroke(); + \endcode + \endtable + + \sa setLineDash + */ +QV4::ReturnedValue QQuickJSContext2DPrototype::method_setLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) +{ + QV4::Scope scope(b); + QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); + CHECK_CONTEXT_SETTER(r) + + if (!argc) + RETURN_UNDEFINED(); + + QV4::ScopedArrayObject array(scope, argv[0]); + if (!array) + RETURN_UNDEFINED(); + + QV4::ScopedValue v(scope); + const uint arrayLength = array->getLength(); + QVector<qreal> dashes; + dashes.reserve(arrayLength); + for (uint i = 0; i < arrayLength; ++i) { + v = array->get(i); + const double number = v->toNumber(); + + if (!qt_is_finite(number) || (number < 0)) + RETURN_UNDEFINED(); + + dashes.append(v->toNumber()); + } + if (dashes.size() % 2 != 0) { + dashes += dashes; + } + + r->d()->context->state.lineDash = dashes; + r->d()->context->buffer()->setLineDash(dashes); + + RETURN_UNDEFINED(); +} + +/*! + \qmlproperty real QtQuick::Context2D::lineDashOffset + \since QtQuick 2.11 + + Holds the current line dash offset + The default line dash ofset value is 0 + */ +QV4::ReturnedValue QQuickJSContext2D::method_get_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) +{ + QV4::Scope scope(b); + QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); + CHECK_CONTEXT(r) + + RETURN_RESULT(QV4::Encode(r->d()->context->state.lineDashOffset)); +} + +QV4::ReturnedValue QQuickJSContext2D::method_set_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) +{ + QV4::Scope scope(b); + QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); + CHECK_CONTEXT_SETTER(r) + + const qreal offset = argc ? argv[0].toNumber() : -1; + + if (qt_is_finite(offset) && offset != r->d()->context->state.lineDashOffset) { + r->d()->context->state.lineDashOffset = offset; + r->d()->context->buffer()->setLineDashOffset(offset); + } + RETURN_UNDEFINED(); +} + + // shadows /*! \qmlproperty real QtQuick::Context2D::shadowBlur @@ -4312,6 +4434,7 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV4::ExecutionEngine *v4) proto->defineAccessorProperty(QStringLiteral("lineWidth"), QQuickJSContext2D::method_get_lineWidth, QQuickJSContext2D::method_set_lineWidth); proto->defineAccessorProperty(QStringLiteral("textAlign"), QQuickJSContext2D::method_get_textAlign, QQuickJSContext2D::method_set_textAlign); proto->defineAccessorProperty(QStringLiteral("shadowBlur"), QQuickJSContext2D::method_get_shadowBlur, QQuickJSContext2D::method_set_shadowBlur); + proto->defineAccessorProperty(QStringLiteral("lineDashOffset"), QQuickJSContext2D::method_get_lineDashOffset, QQuickJSContext2D::method_set_lineDashOffset); contextPrototype = proto; proto = scope.engine->newObject(); @@ -4375,6 +4498,10 @@ void QQuickContext2D::popState() if (newState.shadowOffsetY != state.shadowOffsetY) buffer()->setShadowOffsetY(newState.shadowOffsetY); + + if (newState.lineDash != state.lineDash) + buffer()->setLineDash(newState.lineDash); + m_path = state.matrix.map(m_path); state = newState; m_path = state.matrix.inverted().map(m_path); diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h index 4cc07027b1..1ece6796f3 100644 --- a/src/quick/items/context2d/qquickcontext2d_p.h +++ b/src/quick/items/context2d/qquickcontext2d_p.h @@ -112,6 +112,8 @@ public: LineWidth, LineCap, LineJoin, + LineDash, + LineDashOffset, MiterLimit, ShadowOffsetX, ShadowOffsetY, @@ -142,6 +144,7 @@ public: , lineWidth(1) , lineCap(Qt::FlatCap) , lineJoin(Qt::MiterJoin) + , lineDashOffset(0) , miterLimit(10) , shadowOffsetX(0) , shadowOffsetY(0) @@ -170,6 +173,8 @@ public: qreal lineWidth; Qt::PenCapStyle lineCap; Qt::PenJoinStyle lineJoin; + QVector<qreal> lineDash; + qreal lineDashOffset; qreal miterLimit; qreal shadowOffsetX; qreal shadowOffsetY; diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp index 30895d9b0e..55ebbe907c 100644 --- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp +++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp @@ -192,6 +192,10 @@ QPen QQuickContext2DCommandBuffer::makePen(const QQuickContext2D::State& state) pen.setJoinStyle(state.lineJoin); pen.setMiterLimit(state.miterLimit); pen.setBrush(state.strokeStyle); + if (!state.lineDash.isEmpty()) { + pen.setDashPattern(state.lineDash); + } + pen.setDashOffset(state.lineDashOffset); return pen; } @@ -361,6 +365,28 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s p->setPen(nPen); break; } + case QQuickContext2D::LineDash: + { + const qreal count = takeReal(); + QVector<qreal> pattern; + pattern.reserve(count); + for (uint i = 0; i < count; i++) { + pattern.append(takeReal()); + } + state.lineDash = pattern; + QPen nPen = p->pen(); + nPen.setDashPattern(pattern); + p->setPen(nPen); + break; + } + case QQuickContext2D::LineDashOffset: + { + state.lineDashOffset = takeReal(); + QPen nPen = p->pen(); + nPen.setDashOffset(state.lineDashOffset); + p->setPen(nPen); + break; + } case QQuickContext2D::MiterLimit: { state.miterLimit = takeMiterLimit(); diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h index 2a1ac7304e..c3e844c929 100644 --- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h +++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h @@ -201,6 +201,20 @@ public: ints << join; } + inline void setLineDash(const QVector<qreal> &pattern) + { + commands << QQuickContext2D::LineDash; + reals << pattern.length(); + for (qreal r : pattern) + reals << r; + } + + inline void setLineDashOffset( qreal offset) + { + commands << QQuickContext2D::LineDashOffset; + reals << offset; + } + inline void setMiterLimit( qreal limit) { commands << QQuickContext2D::MiterLimit; |