From 123f698c5bbf23ad816bf2274620ab4f0a82ed2f Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 6 Jun 2017 15:51:14 +0200 Subject: Allow freely mixing non-ShapePath objects in Shape The own list property must be kept. However, we can reuse QQuickItemPrivate's data accessors in order to start supporting code like: Shape { .. ShapePath { ... } ShapePath { ... } Rectangle { ... } Image { ... } // any other visual type // or non-visual: Timer { ... } } Change-Id: I6d502d697cae37bf16857770273a749cee1b3aa3 Reviewed-by: J-P Nurmi --- examples/quick/shapes/content/item1.qml | 17 +++++++ examples/quick/shapes/content/pathiteminteract.qml | 8 ++-- src/imports/shapes/qquickshape.cpp | 52 +++++++++++----------- src/imports/shapes/qquickshape_p.h | 6 +-- tests/auto/quick/qquickshape/tst_qquickshape.cpp | 10 ++--- 5 files changed, 55 insertions(+), 38 deletions(-) diff --git a/examples/quick/shapes/content/item1.qml b/examples/quick/shapes/content/item1.qml index 584a310af4..9328979324 100644 --- a/examples/quick/shapes/content/item1.qml +++ b/examples/quick/shapes/content/item1.qml @@ -74,5 +74,22 @@ Rectangle { PathLine { x: 30; y: ctr.height - 30 } PathLine { x: 30; y: 30 } } + + // Besides ShapePath, Shape supports visual and non-visual objects too, allowing + // free mixing without going through extra hoops: + Rectangle { + id: testRect + color: "green" + opacity: 0.3 + width: 20 + height: 20 + anchors.right: parent.right + } + Timer { + interval: 100 + repeat: true + onTriggered: testRect.width = testRect.width > 1 ? testRect.width - 1 : 20 + running: true + } } } diff --git a/examples/quick/shapes/content/pathiteminteract.qml b/examples/quick/shapes/content/pathiteminteract.qml index b1c9cdf123..55a1d16299 100644 --- a/examples/quick/shapes/content/pathiteminteract.qml +++ b/examples/quick/shapes/content/pathiteminteract.qml @@ -195,7 +195,7 @@ Rectangle { 'startX: ' + x + '; startY: ' + y + ';' + 'PathLine { x: ' + x + ' + 1; y: ' + y + ' + 1 } }', root, "dynamic_visual_path"); - shape.elements.push(p); + shape.data.push(p); activePath = p; }, "move": function(x, y) { if (!activePath) @@ -218,7 +218,7 @@ Rectangle { 'PathCubic { x: ' + x + ' + 1; y: ' + y + ' + 1;' + 'control1X: ' + x + ' + 50; control1Y: ' + y + ' + 50; control2X: ' + x + ' + 150; control2Y: ' + y + ' + 50; } }', root, "dynamic_visual_path"); - shape.elements.push(p); + shape.data.push(p); activePath = p; }, "move": function(x, y) { if (!activePath) @@ -243,7 +243,7 @@ Rectangle { 'PathQuad { x: ' + x + ' + 1; y: ' + y + ' + 1;' + 'controlX: ' + x + ' + 50; controlY: ' + y + ' + 50 } }', root, "dynamic_visual_path"); - shape.elements.push(p); + shape.data.push(p); activePath = p; }, "move": function(x, y) { if (!activePath) @@ -279,7 +279,7 @@ Rectangle { id: shape anchors.fill: parent - elements: [] + data: [] } } } diff --git a/src/imports/shapes/qquickshape.cpp b/src/imports/shapes/qquickshape.cpp index 3c253eabd4..0d060242b4 100644 --- a/src/imports/shapes/qquickshape.cpp +++ b/src/imports/shapes/qquickshape.cpp @@ -588,6 +588,11 @@ void QQuickShapePath::resetFillGradient() \image pathitem-code-example.png + Like \l Item, Shape also allows any visual or non-visual objects to be + declared as children. ShapePath objects are handled specially. This is + useful since it allows adding visual items, like \l Rectangle or \l Image, + and non-visual objects, like \l Timer directly as children of Shape. + \note It is important to be aware of performance implications, in particular when the application is running on the generic Shape implementation due to not having support for accelerated path rendering. The geometry generation @@ -788,31 +793,23 @@ QQuickShape::Status QQuickShape::status() const return d->status; } -static QQuickShapePath *vpe_at(QQmlListProperty *property, int index) -{ - QQuickShapePrivate *d = QQuickShapePrivate::get(static_cast(property->object)); - return d->qmlData.sp.at(index); -} - -static void vpe_append(QQmlListProperty *property, QQuickShapePath *obj) +static void vpe_append(QQmlListProperty *property, QObject *obj) { QQuickShape *item = static_cast(property->object); QQuickShapePrivate *d = QQuickShapePrivate::get(item); - d->qmlData.sp.append(obj); + QQuickShapePath *path = qobject_cast(obj); + if (path) + d->qmlData.sp.append(path); + + QQuickItemPrivate::data_append(property, obj); - if (d->componentComplete) { - QObject::connect(obj, SIGNAL(shapePathChanged()), item, SLOT(_q_shapePathChanged())); + if (path && d->componentComplete) { + QObject::connect(path, SIGNAL(shapePathChanged()), item, SLOT(_q_shapePathChanged())); d->_q_shapePathChanged(); } } -static int vpe_count(QQmlListProperty *property) -{ - QQuickShapePrivate *d = QQuickShapePrivate::get(static_cast(property->object)); - return d->qmlData.sp.count(); -} - -static void vpe_clear(QQmlListProperty *property) +static void vpe_clear(QQmlListProperty *property) { QQuickShape *item = static_cast(property->object); QQuickShapePrivate *d = QQuickShapePrivate::get(item); @@ -822,27 +819,30 @@ static void vpe_clear(QQmlListProperty *property) d->qmlData.sp.clear(); + QQuickItemPrivate::data_clear(property); + if (d->componentComplete) d->_q_shapePathChanged(); } /*! - \qmlproperty list QtQuick.Shapes::Shape::elements + \qmlproperty list QtQuick.Shapes::Shape::data This property holds the ShapePath objects that define the contents of the - Shape. + Shape. It can also contain any other type of objects, since Shape, like Item, + allows adding any visual or non-visual objects as children. \default */ -QQmlListProperty QQuickShape::elements() +QQmlListProperty QQuickShape::data() { - return QQmlListProperty(this, - nullptr, - vpe_append, - vpe_count, - vpe_at, - vpe_clear); + return QQmlListProperty(this, + nullptr, + vpe_append, + QQuickItemPrivate::data_count, + QQuickItemPrivate::data_at, + vpe_clear); } void QQuickShape::classBegin() diff --git a/src/imports/shapes/qquickshape_p.h b/src/imports/shapes/qquickshape_p.h index 50b242e492..c5096be229 100644 --- a/src/imports/shapes/qquickshape_p.h +++ b/src/imports/shapes/qquickshape_p.h @@ -227,8 +227,8 @@ class QQuickShape : public QQuickItem Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged) Q_PROPERTY(bool enableVendorExtensions READ enableVendorExtensions WRITE setEnableVendorExtensions NOTIFY enableVendorExtensionsChanged) Q_PROPERTY(Status status READ status NOTIFY statusChanged) - Q_PROPERTY(QQmlListProperty elements READ elements) - Q_CLASSINFO("DefaultProperty", "elements") + Q_PROPERTY(QQmlListProperty data READ data) + Q_CLASSINFO("DefaultProperty", "data") public: enum RendererType { @@ -259,7 +259,7 @@ public: Status status() const; - QQmlListProperty elements(); + QQmlListProperty data(); protected: QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override; diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp index a984c28732..4f220cf801 100644 --- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp +++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp @@ -80,7 +80,7 @@ void tst_QQuickShape::initValues() QVERIFY(!obj->asynchronous()); QVERIFY(obj->enableVendorExtensions()); QVERIFY(obj->status() == QQuickShape::Null); - auto vps = obj->elements(); + auto vps = obj->data(); QVERIFY(vps.count(&vps) == 0); delete obj; @@ -97,10 +97,10 @@ void tst_QQuickShape::vpInitValues() QVERIFY(!obj->asynchronous()); QVERIFY(obj->enableVendorExtensions()); QVERIFY(obj->status() == QQuickShape::Null); - auto vps = obj->elements(); + auto vps = obj->data(); QVERIFY(vps.count(&vps) == 2); - QQuickShapePath *vp = vps.at(&vps, 0); + QQuickShapePath *vp = qobject_cast(vps.at(&vps, 0)); QVERIFY(vp != nullptr); QQmlListReference pathList(vp, "pathElements"); QCOMPARE(pathList.count(), 0); @@ -128,7 +128,7 @@ void tst_QQuickShape::basicShape() QQuickShape *obj = findItem(window->rootObject(), "pathItem"); QVERIFY(obj != nullptr); - QQmlListReference list(obj, "elements"); + QQmlListReference list(obj, "data"); QCOMPARE(list.count(), 1); QQuickShapePath *vp = qobject_cast(list.at(0)); QVERIFY(vp != nullptr); @@ -168,7 +168,7 @@ void tst_QQuickShape::changeSignals() obj->setAsynchronous(false); QCOMPARE(asyncPropSpy.count(), 2); - QQmlListReference list(obj, "elements"); + QQmlListReference list(obj, "data"); QQuickShapePath *vp = qobject_cast(list.at(0)); QVERIFY(vp != nullptr); -- cgit v1.2.3