diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2018-06-27 16:16:19 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2018-07-10 04:33:05 +0000 |
commit | 1771d298f33543a3fe47decfe0fff10609b01ab1 (patch) | |
tree | 2f19e74f00c458a7a31afa6fe9ce21abba20f61a | |
parent | ffbf089addcaab3e132f5dbb0685c1a46bd6d1ab (diff) |
Teach Rectangle's gradient property to accept QGradient::Preset
Change-Id: Id640b596c1d8d52221f2f2be8807d6e245971bdc
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
8 files changed, 136 insertions, 28 deletions
diff --git a/src/quick/doc/snippets/qml/rectangle/rectangle-gradient.qml b/src/quick/doc/snippets/qml/rectangle/rectangle-gradient.qml index 031bee960d..e52a0ce0ef 100644 --- a/src/quick/doc/snippets/qml/rectangle/rectangle-gradient.qml +++ b/src/quick/doc/snippets/qml/rectangle/rectangle-gradient.qml @@ -80,5 +80,17 @@ Rectangle { } } //! [rectangles] + +//! [presets] +Rectangle { + y: 0; width: 80; height: 80 + gradient: Gradient.NightFade +} + +Rectangle { + y: 0; width: 80; height: 80 + gradient: "NightFade" +} +//! [presets] } } diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp index ab8203d0a8..5e217dcd0c 100644 --- a/src/quick/items/qquickrectangle.cpp +++ b/src/quick/items/qquickrectangle.cpp @@ -40,9 +40,13 @@ #include "qquickrectangle_p.h" #include "qquickrectangle_p_p.h" +#include <QtQml/qqmlinfo.h> + #include <QtQuick/private/qsgcontext_p.h> #include <private/qsgadaptationlayer_p.h> +#include <private/qqmlmetatype_p.h> + #include <QtGui/qpixmapcache.h> #include <QtCore/qmath.h> #include <QtCore/qmetaobject.h> @@ -393,7 +397,7 @@ QQuickPen *QQuickRectangle::border() } /*! - \qmlproperty Gradient QtQuick::Rectangle::gradient + \qmlproperty any QtQuick::Rectangle::gradient The gradient to use to fill the rectangle. @@ -407,37 +411,66 @@ QQuickPen *QQuickRectangle::border() \snippet qml/rectangle/rectangle-gradient.qml rectangles \clearfloat + The property also accepts gradient presets from QGradient::Preset. Note however + that due to Rectangle only supporting simple vertical or horizontal gradients, + any preset with an unsupported angle will revert to the closest representation. + + \snippet qml/rectangle/rectangle-gradient.qml presets + \clearfloat + If both a gradient and a color are specified, the gradient will be used. \sa Gradient, color */ -QQuickGradient *QQuickRectangle::gradient() const +QJSValue QQuickRectangle::gradient() const { Q_D(const QQuickRectangle); return d->gradient; } -void QQuickRectangle::setGradient(QQuickGradient *gradient) +void QQuickRectangle::setGradient(const QJSValue &gradient) { Q_D(QQuickRectangle); - if (d->gradient == gradient) + if (d->gradient.equals(gradient)) return; - static int updatedSignalIdx = -1; - if (updatedSignalIdx < 0) - updatedSignalIdx = QMetaMethod::fromSignal(&QQuickGradient::updated).methodIndex(); + + static int updatedSignalIdx = QMetaMethod::fromSignal(&QQuickGradient::updated).methodIndex(); if (d->doUpdateSlotIdx < 0) d->doUpdateSlotIdx = QQuickRectangle::staticMetaObject.indexOfSlot("doUpdate()"); - if (d->gradient) - QMetaObject::disconnect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx); - d->gradient = gradient; - if (d->gradient) - QMetaObject::connect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx); + + if (auto oldGradient = qobject_cast<QQuickGradient*>(d->gradient.toQObject())) + QMetaObject::disconnect(oldGradient, updatedSignalIdx, this, d->doUpdateSlotIdx); + + if (gradient.isQObject()) { + if (auto newGradient = qobject_cast<QQuickGradient*>(gradient.toQObject())) { + d->gradient = gradient; + QMetaObject::connect(newGradient, updatedSignalIdx, this, d->doUpdateSlotIdx); + } else { + qmlWarning(this) << "Can't assign " + << QQmlMetaType::prettyTypeName(gradient.toQObject()) << " to gradient property"; + d->gradient = QJSValue(); + } + } else if (gradient.isNumber() || gradient.isString()) { + QGradient preset(gradient.toVariant().value<QGradient::Preset>()); + if (preset.type() != QGradient::NoGradient) { + d->gradient = gradient; + } else { + qmlWarning(this) << "No such gradient preset '" << gradient.toString() << "'"; + d->gradient = QJSValue(); + } + } else if (gradient.isNull() || gradient.isUndefined()) { + d->gradient = gradient; + } else { + qmlWarning(this) << "Unknown gradient type. Expected int, string, or Gradient"; + d->gradient = QJSValue(); + } + update(); } void QQuickRectangle::resetGradient() { - setGradient(nullptr); + setGradient(QJSValue()); } /*! @@ -534,9 +567,31 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData QGradientStops stops; bool vertical = true; - if (d->gradient) { - stops = d->gradient->gradientStops(); - vertical = d->gradient->orientation() == QQuickGradient::Vertical; + if (d->gradient.isQObject()) { + auto gradient = qobject_cast<QQuickGradient*>(d->gradient.toQObject()); + Q_ASSERT(gradient); + stops = gradient->gradientStops(); + vertical = gradient->orientation() == QQuickGradient::Vertical; + } else if (d->gradient.isNumber() || d->gradient.isString()) { + QGradient preset(d->gradient.toVariant().value<QGradient::Preset>()); + if (preset.type() == QGradient::LinearGradient) { + auto linearGradient = static_cast<QLinearGradient&>(preset); + const QPointF start = linearGradient.start(); + const QPointF end = linearGradient.finalStop(); + vertical = qAbs(start.y() - end.y()) >= qAbs(start.x() - end.x()); + stops = linearGradient.stops(); + if ((vertical && start.y() > end.y()) || (!vertical && start.x() > end.x())) { + // QSGInternalRectangleNode doesn't support stops in the wrong order, + // so we need to manually reverse them here. + QGradientStops reverseStops; + for (auto it = stops.rbegin(); it != stops.rend(); ++it) { + auto stop = *it; + stop.first = 1 - stop.first; + reverseStops.append(stop); + } + stops = reverseStops; + } + } } rectangle->setGradientStops(stops); rectangle->setGradientVertical(vertical); diff --git a/src/quick/items/qquickrectangle_p.h b/src/quick/items/qquickrectangle_p.h index ddafaafb28..d56a03d22d 100644 --- a/src/quick/items/qquickrectangle_p.h +++ b/src/quick/items/qquickrectangle_p.h @@ -122,6 +122,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickGradient : public QObject Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged REVISION 12) Q_CLASSINFO("DefaultProperty", "stops") + Q_ENUMS(QGradient::Preset) public: QQuickGradient(QObject *parent=nullptr); ~QQuickGradient() override; @@ -157,7 +158,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRectangle : public QQuickItem Q_OBJECT Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) - Q_PROPERTY(QQuickGradient *gradient READ gradient WRITE setGradient RESET resetGradient) + Q_PROPERTY(QJSValue gradient READ gradient WRITE setGradient RESET resetGradient) Q_PROPERTY(QQuickPen * border READ border CONSTANT) Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged) public: @@ -168,8 +169,8 @@ public: QQuickPen *border(); - QQuickGradient *gradient() const; - void setGradient(QQuickGradient *gradient); + QJSValue gradient() const; + void setGradient(const QJSValue &gradient); void resetGradient(); qreal radius() const; diff --git a/src/quick/items/qquickrectangle_p_p.h b/src/quick/items/qquickrectangle_p_p.h index 3c1aaf7661..c7c5293f9b 100644 --- a/src/quick/items/qquickrectangle_p_p.h +++ b/src/quick/items/qquickrectangle_p_p.h @@ -73,7 +73,7 @@ public: } QColor color; - QQuickGradient *gradient; + QJSValue gradient; QQuickPen *pen; qreal radius; static int doUpdateSlotIdx; diff --git a/tests/auto/quick/qquickdesignersupport/data/test.qml b/tests/auto/quick/qquickdesignersupport/data/test.qml index 1d43cb3b7e..6c89f15257 100644 --- a/tests/auto/quick/qquickdesignersupport/data/test.qml +++ b/tests/auto/quick/qquickdesignersupport/data/test.qml @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick 2.11 Rectangle { objectName: "rootItem" @@ -13,7 +13,7 @@ Rectangle { Rectangle { objectName: "rectangleItem" - gradient: Gradient { + containmentMask: Item { } } diff --git a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp index 96a11e16e9..3e0765552a 100644 --- a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp +++ b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp @@ -209,15 +209,15 @@ void tst_qquickdesignersupport::objectProperties() //Read gradient property as QObject - int propertyIndex = rectangleItem->metaObject()->indexOfProperty("gradient"); + int propertyIndex = rectangleItem->metaObject()->indexOfProperty("containmentMask"); QVERIFY(propertyIndex > 0); QMetaProperty metaProperty = rectangleItem->metaObject()->property(propertyIndex); QVERIFY(metaProperty.isValid()); QVERIFY(QQuickDesignerSupportProperties::isPropertyQObject(metaProperty)); - QObject*gradient = QQuickDesignerSupportProperties::readQObjectProperty(metaProperty, rectangleItem); - QVERIFY(gradient); + QObject *containmentItem = QQuickDesignerSupportProperties::readQObjectProperty(metaProperty, rectangleItem); + QVERIFY(containmentItem); //The width property is not a QObject @@ -450,7 +450,7 @@ void tst_qquickdesignersupport::testNotifyPropertyChangeCallBack() QQuickDesignerSupportMetaInfo::registerNotifyPropertyChangeCallBack(notifyPropertyChangeCallBackPointer); - rectangle->setProperty("gradient", QVariant::fromValue<QQuickGradient *>(gradient)); + rectangle->setProperty("gradient", QVariant::fromValue<QJSValue>(view->engine()->newQObject(gradient))); QVERIFY(s_object); QCOMPARE(s_object, rootItem); diff --git a/tests/auto/quick/qquickrectangle/data/gradient-preset.qml b/tests/auto/quick/qquickrectangle/data/gradient-preset.qml new file mode 100644 index 0000000000..b740bdd610 --- /dev/null +++ b/tests/auto/quick/qquickrectangle/data/gradient-preset.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +Item { + Rectangle { + objectName: "enum" + gradient: Gradient.NightFade + } + Rectangle { + objectName: "string" + gradient: "NightFade" + } + Rectangle { + objectName: "invalid" + gradient: -1 + } +} diff --git a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp index 2aaad867bf..f6ca999cf5 100644 --- a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp +++ b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp @@ -49,6 +49,7 @@ private slots: void gradient_border(); void gradient_separate(); void gradient_multiple(); + void gradient_preset(); void antialiasing(); private: @@ -84,7 +85,7 @@ void tst_qquickrectangle::gradient() QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(component.create()); QVERIFY(rect); - QQuickGradient *grad = rect->gradient(); + QQuickGradient *grad = qobject_cast<QQuickGradient *>(rect->gradient().toQObject()); QVERIFY(grad); QQmlListProperty<QQuickGradientStop> stops = grad->stops(); @@ -103,7 +104,7 @@ void tst_qquickrectangle::gradient() QMetaObject::invokeMethod(rect, "resetGradient"); - grad = rect->gradient(); + grad = qobject_cast<QQuickGradient *>(rect->gradient().toQObject()); QVERIFY(!grad); delete rect; @@ -174,6 +175,29 @@ void tst_qquickrectangle::gradient_multiple() QVERIFY(secondIsDirty); } +void tst_qquickrectangle::gradient_preset() +{ + QQuickView view; + view.setSource(testFileUrl("gradient-preset.qml")); + view.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QQuickRectangle *enumRect = view.rootObject()->findChild<QQuickRectangle *>("enum"); + QVERIFY(enumRect); + QVERIFY(enumRect->gradient().isNumber()); + QCOMPARE(enumRect->gradient().toUInt(), QGradient::NightFade); + + QQuickRectangle *stringRect = view.rootObject()->findChild<QQuickRectangle *>("string"); + QVERIFY(stringRect); + QVERIFY(stringRect->gradient().isString()); + QCOMPARE(stringRect->gradient().toString(), QLatin1String("NightFade")); + + QQuickRectangle *invalidRect = view.rootObject()->findChild<QQuickRectangle *>("invalid"); + QVERIFY(invalidRect); + QVERIFY(invalidRect->gradient().isUndefined()); +} + void tst_qquickrectangle::antialiasing() { QQmlComponent component(&engine); |