Add support for a vector4d type in QML
authorChris Adams <christopher.adams@nokia.com>
Thu, 14 Jul 2011 05:40:30 +0000 (15:40 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 18 Aug 2011 07:25:04 +0000 (09:25 +0200)
QVector4D is a value-type which is supported but was not able to be
constructed using a Qt object function.  This commit allows properties
of vector4d type to be constructed, and adds a function to the global
Qt object and adds unit tests to ensure that it behaves correctly.

Task-number: QTBUG-18559
Change-Id: I96509a4f496b644d20fdb1d977d0afe430d89e13
Reviewed-on: http://codereview.qt.nokia.com/1626
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
15 files changed:
src/declarative/qml/qdeclarativecompiler.cpp
src/declarative/qml/qdeclarativeinstruction.cpp
src/declarative/qml/qdeclarativeinstruction_p.h
src/declarative/qml/qdeclarativestringconverters.cpp
src/declarative/qml/qdeclarativestringconverters_p.h
src/declarative/qml/qdeclarativevme.cpp
src/declarative/qml/v8/qv8engine.cpp
src/declarative/qml/v8/qv8engine_p.h
tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp
tests/auto/declarative/qdeclarativelanguage/data/assignBasicTypes.qml
tests/auto/declarative/qdeclarativelanguage/data/assignLiteralToVariant.qml
tests/auto/declarative/qdeclarativelanguage/testtypes.h
tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
tests/auto/declarative/qdeclarativeqt/data/vector4.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp

index f39e1ab..7cc8422 100644 (file)
@@ -312,6 +312,13 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
             }
             break;
+        case QVariant::Vector4D:
+            {
+            bool ok;
+            QDeclarativeStringConverters::vector4DFromString(string, &ok);
+            if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
+            }
+            break;
         default:
             {
             int t = prop.userType();
@@ -554,6 +561,18 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
             instr.storeVector3D.vector.zp = vector.z();
             }
             break;
+    case QVariant::Vector4D:
+            {
+            bool ok;
+            QVector4D vector = QDeclarativeStringConverters::vector4DFromString(string, &ok);
+            instr.setType(QDeclarativeInstruction::StoreVector4D);
+            instr.storeVector4D.propertyIndex = prop.propertyIndex();
+            instr.storeVector4D.vector.xp = vector.x();
+            instr.storeVector4D.vector.yp = vector.y();
+            instr.storeVector4D.vector.zp = vector.z();
+            instr.storeVector4D.vector.wp = vector.w();
+            }
+            break;
         default:
             {
             int t = prop.userType();
index f99351b..f5bd6e9 100644 (file)
@@ -132,6 +132,9 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx)
     case QDeclarativeInstruction::StoreVector3D:
         qWarning().nospace() << idx << "\t\t" << "STORE_VECTOR3D\t\t" << instr->storeVector3D.propertyIndex << "\t" << instr->storeVector3D.vector.xp << "\t" << instr->storeVector3D.vector.yp << "\t" << instr->storeVector3D.vector.zp;
         break;
+    case QDeclarativeInstruction::StoreVector4D:
+        qWarning().nospace() << idx << "\t\t" << "STORE_VECTOR4D\t\t" << instr->storeVector4D.propertyIndex << "\t" << instr->storeVector4D.vector.xp << "\t" << instr->storeVector4D.vector.yp << "\t" << instr->storeVector4D.vector.zp << "\t" << instr->storeVector4D.vector.wp;
+        break;
     case QDeclarativeInstruction::StoreVariant:
         qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
         break;
index a48c44c..f980027 100644 (file)
@@ -88,6 +88,7 @@ QT_BEGIN_NAMESPACE
     F(StoreRect, storeRect) \
     F(StoreRectF, storeRectF) \
     F(StoreVector3D, storeVector3D) \
+    F(StoreVector4D, storeVector4D) \
     F(StoreObject, storeObject) \
     F(AssignCustomType, assignCustomType) \
     F(AssignSignalObject, assignSignalObject) \
@@ -405,6 +406,16 @@ union QDeclarativeInstruction
             float zp;
         } vector;
     };
+    struct instr_storeVector4D {
+        QML_INSTR_HEADER
+        int propertyIndex;
+        struct QVector4D {
+            float xp;
+            float yp;
+            float zp;
+            float wp;
+        } vector;
+    };
 
     instr_common common;
     instr_init init;
@@ -440,6 +451,7 @@ union QDeclarativeInstruction
     instr_storeRect storeRect;
     instr_storeRectF storeRectF;
     instr_storeVector3D storeVector3D;
+    instr_storeVector4D storeVector4D;
     instr_storeObject storeObject;
     instr_assignCustomType assignCustomType;
     instr_storeSignal storeSignal;
index d7cfe2e..b949adf 100644 (file)
@@ -43,6 +43,7 @@
 
 #include <QtGui/qcolor.h>
 #include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
 #include <QtCore/qpoint.h>
 #include <QtCore/qrect.h>
 #include <QtCore/qsize.h>
@@ -93,6 +94,8 @@ QVariant QDeclarativeStringConverters::variantFromString(const QString &s)
     if (ok) return QVariant(sz);
     QVector3D v = vector3DFromString(s, &ok);
     if (ok) return QVariant::fromValue(v);
+    QVector4D v4 = vector4DFromString(s, &ok);
+    if (ok) return QVariant::fromValue(v4);
 
     return QVariant(s);
 }
@@ -128,6 +131,8 @@ QVariant QDeclarativeStringConverters::variantFromString(const QString &s, int p
         return QVariant::fromValue(rectFFromString(s, ok).toRect());
     case QMetaType::QVector3D:
         return QVariant::fromValue(vector3DFromString(s, ok));
+    case QMetaType::QVector4D:
+        return QVariant::fromValue(vector4DFromString(s, ok));
     default:
         if (ok) *ok = false;
         return QVariant();
@@ -275,4 +280,32 @@ QVector3D QDeclarativeStringConverters::vector3DFromString(const QString &s, boo
     return QVector3D(xCoord, yCoord, zCoord);
 }
 
+//expects input of "x,y,z,w"
+QVector4D QDeclarativeStringConverters::vector4DFromString(const QString &s, bool *ok)
+{
+    if (s.count(QLatin1Char(',')) != 3) {
+        if (ok)
+            *ok = false;
+        return QVector4D();
+    }
+
+    bool xGood, yGood, zGood, wGood;
+    int index = s.indexOf(QLatin1Char(','));
+    int index2 = s.indexOf(QLatin1Char(','), index+1);
+    int index3 = s.indexOf(QLatin1Char(','), index2+1);
+    qreal xCoord = s.left(index).toDouble(&xGood);
+    qreal yCoord = s.mid(index+1, index2-index-1).toDouble(&yGood);
+    qreal zCoord = s.mid(index2+1, index3-index2-1).toDouble(&zGood);
+    qreal wCoord = s.mid(index3+1).toDouble(&wGood);
+    if (!xGood || !yGood || !zGood || !wGood) {
+        if (ok)
+            *ok = false;
+        return QVector4D();
+    }
+
+    if (ok)
+        *ok = true;
+    return QVector4D(xCoord, yCoord, zCoord, wCoord);
+}
+
 QT_END_NAMESPACE
index a8c6359..2f93cd7 100644 (file)
@@ -67,6 +67,7 @@ class QRectF;
 class QString;
 class QByteArray;
 class QVector3D;
+class QVector4D;
 
 // XXX - Bauhaus currently uses these methods which is why they're exported
 namespace QDeclarativeStringConverters
@@ -84,6 +85,7 @@ namespace QDeclarativeStringConverters
     QSizeF Q_DECLARATIVE_PRIVATE_EXPORT sizeFFromString(const QString &, bool *ok = 0);
     QRectF Q_DECLARATIVE_PRIVATE_EXPORT rectFFromString(const QString &, bool *ok = 0);
     QVector3D Q_DECLARATIVE_PRIVATE_EXPORT vector3DFromString(const QString &, bool *ok = 0);
+    QVector4D Q_DECLARATIVE_PRIVATE_EXPORT vector4DFromString(const QString &, bool *ok = 0);
 }
 
 QT_END_NAMESPACE
index 45e4745..6708b60 100644 (file)
@@ -586,6 +586,16 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
                                   instr.propertyIndex, a);
         QML_END_INSTR(StoreVector3D)
 
+        QML_BEGIN_INSTR(StoreVector4D)
+            QObject *target = stack.top();
+            CLEAN_PROPERTY(target, instr.propertyIndex);
+
+            QVector4D *v = (QVector4D *)&instr.vector;
+            void *a[] = { v, 0, &status, &flags };
+            QMetaObject::metacall(target, QMetaObject::WriteProperty,
+                                  instr.propertyIndex, a);
+        QML_END_INSTR(StoreVector4D)
+
         QML_BEGIN_INSTR(StoreObject)
             QObject *assignObj = stack.pop();
             QObject *target = stack.top();
index b2f98ac..db58aab 100644 (file)
@@ -477,6 +477,7 @@ QVariant QV8Engine::toBasicVariant(v8::Handle<v8::Value> value)
 
 
 #include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
 
 struct StaticQtMetaObject : public QObject
 {
@@ -511,6 +512,7 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
     qt->Set(v8::String::New("point"), V8FUNCTION(point, this));
     qt->Set(v8::String::New("size"), V8FUNCTION(size, this));
     qt->Set(v8::String::New("vector3d"), V8FUNCTION(vector3d, this));
+    qt->Set(v8::String::New("vector4d"), V8FUNCTION(vector4d, this));
 
     qt->Set(v8::String::New("formatDate"), V8FUNCTION(formatDate, this));
     qt->Set(v8::String::New("formatTime"), V8FUNCTION(formatTime, this));
@@ -846,6 +848,23 @@ v8::Handle<v8::Value> QV8Engine::vector3d(const v8::Arguments &args)
 }
 
 /*!
+\qmlmethod Qt::vector4d(real x, real y, real z, real w)
+Returns a Vector4D with the specified \c x, \c y, \c z and \c w.
+*/
+v8::Handle<v8::Value> QV8Engine::vector4d(const v8::Arguments &args)
+{
+    if (args.Length() != 4)
+        V8THROW_ERROR("Qt.vector4d(): Invalid arguments");
+
+    double x = args[0]->NumberValue();
+    double y = args[1]->NumberValue();
+    double z = args[2]->NumberValue();
+    double w = args[3]->NumberValue();
+
+    return V8ENGINE()->fromVariant(QVariant::fromValue(QVector4D(x, y, z, w)));
+}
+
+/*!
 \qmlmethod color Qt::lighter(color baseColor, real factor)
 Returns a color lighter than \c baseColor by the \c factor provided.
 
index b3cc023..f493c67 100644 (file)
@@ -435,6 +435,7 @@ protected:
     static v8::Handle<v8::Value> point(const v8::Arguments &args);
     static v8::Handle<v8::Value> size(const v8::Arguments &args);
     static v8::Handle<v8::Value> vector3d(const v8::Arguments &args);
+    static v8::Handle<v8::Value> vector4d(const v8::Arguments &args);
     static v8::Handle<v8::Value> lighter(const v8::Arguments &args);
     static v8::Handle<v8::Value> darker(const v8::Arguments &args);
     static v8::Handle<v8::Value> tint(const v8::Arguments &args);
index e6e87d1..f432cbf 100644 (file)
@@ -63,6 +63,7 @@ private slots:
     void rect();
     void rectf();
     void vector3d();
+    void vector4d();
     void time();
 };
 
@@ -682,6 +683,24 @@ void tst_qdeclarativeinstruction::vector3d()
     QCOMPARE(vector.z(), (qreal)(float)12.0);
 }
 
+void tst_qdeclarativeinstruction::vector4d()
+{
+    QCOMPARE(sizeof(QDeclarativeInstruction::instr_storeVector4D::QVector4D), sizeof(QVector4D));
+    QCOMPARE(Q_ALIGNOF(QDeclarativeInstruction::instr_storeVector4D::QVector4D), Q_ALIGNOF(QVector4D));
+
+    QDeclarativeInstruction i;
+    i.storeVector4D.vector.xp = 8.2;
+    i.storeVector4D.vector.yp = 99.3;
+    i.storeVector4D.vector.zp = 12.0;
+    i.storeVector4D.vector.wp = 121.1;
+
+    const QVector4D &vector = (const QVector4D &)(i.storeVector4D.vector);
+    QCOMPARE(vector.x(), (qreal)(float)8.2);
+    QCOMPARE(vector.y(), (qreal)(float)99.3);
+    QCOMPARE(vector.z(), (qreal)(float)12.0);
+    QCOMPARE(vector.w(), (qreal)(float)121.1);
+}
+
 void tst_qdeclarativeinstruction::time()
 {
     QCOMPARE(sizeof(QDeclarativeInstruction::instr_storeTime::QTime), sizeof(QTime));
index 9fe0ded..2313499 100644 (file)
@@ -21,6 +21,7 @@ MyTypeObject {
     boolProperty: true
     variantProperty: "Hello World!"
     vectorProperty: "10,1,2.2"
+    vector4Property: "10,1,2.2,2.3"
     urlProperty: "main.qml"
 
     objectProperty: MyTypeObject { intProperty: 8 }
index de476ae..f6f9a13 100644 (file)
@@ -12,5 +12,6 @@ QtObject {
     property variant test9: String("#FF008800")
     property variant test10: true
     property variant test11: false
+    property variant test12: "100,100,100,100"
 }
 
index c11bc33..dad0e23 100644 (file)
@@ -47,6 +47,7 @@
 #include <QtGui/qmatrix.h>
 #include <QtGui/qcolor.h>
 #include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
 #include <QtDeclarative/qdeclarative.h>
 #include <QtDeclarative/qdeclarativecomponent.h>
 #include <QtDeclarative/qdeclarativeparserstatus.h>
@@ -224,6 +225,7 @@ class MyTypeObject : public QObject
     Q_PROPERTY(bool boolProperty READ boolProperty WRITE setBoolProperty)
     Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
     Q_PROPERTY(QVector3D vectorProperty READ vectorProperty WRITE setVectorProperty)
+    Q_PROPERTY(QVector4D vector4Property READ vector4Property WRITE setVector4Property)
     Q_PROPERTY(QUrl urlProperty READ urlProperty WRITE setUrlProperty)
 
     Q_PROPERTY(QDeclarativeScriptString scriptProperty READ scriptProperty WRITE setScriptProperty)
@@ -442,6 +444,14 @@ public:
         vectorPropertyValue = v;
     }
 
+    QVector4D vector4PropertyValue;
+    QVector4D vector4Property() const {
+        return vector4PropertyValue;
+    }
+    void setVector4Property(const QVector4D &v) {
+        vector4PropertyValue = v;
+    }
+
     QUrl urlPropertyValue;
     QUrl urlProperty() const {
         return urlPropertyValue;
index dfaf3d1..5e9bc41 100644 (file)
@@ -564,6 +564,7 @@ void tst_qdeclarativelanguage::assignBasicTypes()
     QCOMPARE(object->boolProperty(), true);
     QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
     QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
+    QCOMPARE(object->vector4Property(), QVector4D(10, 1, 2.2, 2.3));
     QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
     QVERIFY(object->objectProperty() != 0);
     MyTypeObject *child = qobject_cast<MyTypeObject *>(object->objectProperty());
@@ -610,6 +611,7 @@ void tst_qdeclarativelanguage::assignLiteralToVariant()
     QCOMPARE(object->property("test9").userType(), (int)QVariant::String);
     QCOMPARE(object->property("test10").userType(), (int)QVariant::Bool);
     QCOMPARE(object->property("test11").userType(), (int)QVariant::Bool);
+    QCOMPARE(object->property("test12").userType(), (int)QVariant::Vector4D);
 
     QVERIFY(object->property("test1") == QVariant(1));
     QVERIFY(object->property("test2") == QVariant((double)1.7));
@@ -622,6 +624,7 @@ void tst_qdeclarativelanguage::assignLiteralToVariant()
     QVERIFY(object->property("test9") == QVariant(QString(QLatin1String("#FF008800"))));
     QVERIFY(object->property("test10") == QVariant(bool(true)));
     QVERIFY(object->property("test11") == QVariant(bool(false)));
+    QVERIFY(object->property("test12") == QVariant(QVector4D(100, 100, 100, 100)));
 
     delete object;
 }
diff --git a/tests/auto/declarative/qdeclarativeqt/data/vector4.qml b/tests/auto/declarative/qdeclarativeqt/data/vector4.qml
new file mode 100644 (file)
index 0000000..554dd1e
--- /dev/null
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+QtObject {
+    property variant test1: Qt.vector4d(1, 0, 0.9, 0.6);
+    property variant test2: Qt.vector4d(102, -10, -982.1, 10);
+    property variant test3: Qt.vector4d(102, -10, -982.1);
+    property variant test4: Qt.vector4d(102, -10, -982.1, 10, 15);
+}
index 4a9bb45..d9cd2b8 100644 (file)
@@ -72,6 +72,7 @@ private slots:
     void point();
     void size();
     void vector();
+    void vector4d();
     void lighter();
     void darker();
     void tint();
@@ -243,6 +244,26 @@ void tst_qdeclarativeqt::vector()
     delete object;
 }
 
+void tst_qdeclarativeqt::vector4d()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("vector4.qml"));
+
+    QString warning1 = component.url().toString() + ":6: Error: Qt.vector4d(): Invalid arguments";
+    QString warning2 = component.url().toString() + ":7: Error: Qt.vector4d(): Invalid arguments";
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+
+    QCOMPARE(qvariant_cast<QVector4D>(object->property("test1")), QVector4D(1, 0, 0.9, 0.6));
+    QCOMPARE(qvariant_cast<QVector4D>(object->property("test2")), QVector4D(102, -10, -982.1, 10));
+    QCOMPARE(qvariant_cast<QVector4D>(object->property("test3")), QVector4D());
+    QCOMPARE(qvariant_cast<QVector4D>(object->property("test4")), QVector4D());
+
+    delete object;
+}
+
 void tst_qdeclarativeqt::lighter()
 {
     QDeclarativeComponent component(&engine, TEST_FILE("lighter.qml"));