Allow invokable functions of value-type classes to be called
authorChris Adams <christopher.adams@nokia.com>
Mon, 16 Jul 2012 06:32:49 +0000 (16:32 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 9 Aug 2012 05:58:06 +0000 (07:58 +0200)
Previously, invokable functions of value-type classes were returned as
properties.  This commit fixes that bug by allowing such functions to
be invoked normally.  It also improves copy-value type handling.

This commit also ensures that QMatrix4x4 value types are constructed
with qreal values as this is the storage type used internally.

Change-Id: Iab0fe4c522ed53d60154e8a8d46dda925fb9f4de
Reviewed-by: Martin Jones <martin.jones@nokia.com>

14 files changed:
src/qml/qml/v8/qqmlbuiltinfunctions.cpp
src/qml/qml/v8/qv8qobjectwrapper.cpp
src/qml/qml/v8/qv8valuetypewrapper.cpp
src/quick/doc/src/qmltypereference.qdoc
src/quick/util/qquickglobal.cpp
src/quick/util/qquickvaluetypes.cpp
src/quick/util/qquickvaluetypes_p.h
tests/auto/qml/qqmlvaluetypeproviders/data/invokableFunctions.qml [new file with mode: 0644]
tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml [new file with mode: 0644]
tests/auto/qml/qqmlvaluetypes/data/vector2d_invokables.qml [new file with mode: 0644]
tests/auto/qml/qqmlvaluetypes/data/vector3d_invokables.qml [new file with mode: 0644]
tests/auto/qml/qqmlvaluetypes/data/vector4d_invokables.qml [new file with mode: 0644]
tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp

index ef1f3ea..c8508e7 100644 (file)
@@ -542,7 +542,7 @@ v8::Handle<v8::Value> vector2d(const v8::Arguments &args)
     if (args.Length() != 2)
         V8THROW_ERROR("Qt.vector2d(): Invalid arguments");
 
-    float xy[3];
+    float xy[3]; // qvector2d uses float internally
     xy[0] = args[0]->ToNumber()->Value();
     xy[1] = args[1]->ToNumber()->Value();
 
@@ -559,7 +559,7 @@ v8::Handle<v8::Value> vector3d(const v8::Arguments &args)
     if (args.Length() != 3)
         V8THROW_ERROR("Qt.vector3d(): Invalid arguments");
 
-    float xyz[3];
+    float xyz[3]; // qvector3d uses float internally
     xyz[0] = args[0]->ToNumber()->Value();
     xyz[1] = args[1]->ToNumber()->Value();
     xyz[2] = args[2]->ToNumber()->Value();
@@ -577,7 +577,7 @@ v8::Handle<v8::Value> vector4d(const v8::Arguments &args)
     if (args.Length() != 4)
         V8THROW_ERROR("Qt.vector4d(): Invalid arguments");
 
-    float xyzw[4];
+    float xyzw[4]; // qvector4d uses float internally
     xyzw[0] = args[0]->ToNumber()->Value();
     xyzw[1] = args[1]->ToNumber()->Value();
     xyzw[2] = args[2]->ToNumber()->Value();
@@ -596,7 +596,7 @@ v8::Handle<v8::Value> quaternion(const v8::Arguments &args)
     if (args.Length() != 4)
         V8THROW_ERROR("Qt.quaternion(): Invalid arguments");
 
-    double sxyz[4];
+    qreal sxyz[4]; // qquaternion uses qreal internally
     sxyz[0] = args[0]->ToNumber()->Value();
     sxyz[1] = args[1]->ToNumber()->Value();
     sxyz[2] = args[2]->ToNumber()->Value();
@@ -648,7 +648,7 @@ v8::Handle<v8::Value> matrix4x4(const v8::Arguments &args)
     if (args.Length() != 16)
         V8THROW_ERROR("Qt.matrix4x4(): Invalid arguments");
 
-    float vals[16];
+    qreal vals[16]; // qmatrix4x4 uses qreal internally
     vals[0] = args[0]->ToNumber()->Value();
     vals[1] = args[1]->ToNumber()->Value();
     vals[2] = args[2]->ToNumber()->Value();
index 01ab252..bee176f 100644 (file)
@@ -1552,16 +1552,29 @@ static v8::Handle<v8::Value> CallMethod(QObject *object, int index, int returnTy
 {
     if (argCount > 0) {
 
+        // Special handling is required for value types.
+        // We need to save the current value in a temporary,
+        // and reapply it after converting all arguments.
+        // This avoids the "overwriting copy-value-type-value"
+        // problem during Q_INVOKABLE function invocation.
+        QQmlValueType *valueTypeObject = qobject_cast<QQmlValueType*>(object);
+        QVariant valueTypeValue;
+        if (valueTypeObject)
+            valueTypeValue = valueTypeObject->value();
+
+        // Convert all arguments.
         QVarLengthArray<CallArgument, 9> args(argCount + 1);
         args[0].initAsType(returnType);
-
         for (int ii = 0; ii < argCount; ++ii)
             args[ii + 1].fromValue(argTypes[ii], engine, callArgs[ii]);
-
         QVarLengthArray<void *, 9> argData(args.count());
         for (int ii = 0; ii < args.count(); ++ii)
             argData[ii] = args[ii].dataPtr();
 
+        // Reinstate saved value type object value if required.
+        if (valueTypeObject)
+            valueTypeObject->setValue(valueTypeValue);
+
         QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
 
         return args[0].toValue(engine);
@@ -1664,6 +1677,11 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
         case QMetaType::QStringList:
         case QMetaType::QVariantList:
             return 5;
+        case QMetaType::QVector4D:
+        case QMetaType::QMatrix4x4:
+            return 6;
+        case QMetaType::QVector3D:
+            return 7;
         default:
             return 10;
         }
@@ -1699,6 +1717,10 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
                 return 0;
             else
                 return 10;
+        } else if (r && r->resourceType() == QV8ObjectResource::ValueTypeType) {
+            if (r->engine->toVariant(actual, -1).userType() == conversionType)
+                return 0;
+            return 10;
         } else if (conversionType == QMetaType::QJsonObject) {
             return 5;
         } else {
@@ -1831,6 +1853,16 @@ static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QQmlPropertyD
     int bestParameterScore = INT_MAX;
     int bestMatchScore = INT_MAX;
 
+    // Special handling is required for value types.
+    // We need to save the current value in a temporary,
+    // and reapply it after converting all arguments.
+    // This avoids the "overwriting copy-value-type-value"
+    // problem during Q_INVOKABLE function invocation.
+    QQmlValueType *valueTypeObject = qobject_cast<QQmlValueType*>(object);
+    QVariant valueTypeValue;
+    if (valueTypeObject)
+        valueTypeValue = valueTypeObject->value();
+
     QQmlPropertyData dummy;
     const QQmlPropertyData *attempt = &data;
 
@@ -1871,6 +1903,8 @@ static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QQmlPropertyD
     } while((attempt = RelatedMethod(object, attempt, dummy)) != 0);
 
     if (best) {
+        if (valueTypeObject)
+            valueTypeObject->setValue(valueTypeValue);
         return CallPrecise(object, *best, engine, callArgs);
     } else {
         QString error = QLatin1String("Unable to determine callable overload.  Candidates are:");
index cf6c530..fe58546 100644 (file)
@@ -235,6 +235,9 @@ bool QV8ValueTypeWrapper::isEqual(QV8ObjectResource *r, const QVariant& value)
     } else {
         Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
         QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
+        resource->type->setValue(copy->value);
+        if (resource->type->isEqual(value))
+            return true;
         return (value == copy->value);
     }
 }
@@ -260,11 +263,8 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::ToString(const v8::Arguments &args)
         } else {
             Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
             QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
-            QString result = copy->value.toString();
-            if (result.isEmpty() && !copy->value.canConvert(QVariant::String)) {
-                result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(copy->value.typeName()));
-            }
-            return resource->engine->toString(result);
+            resource->type->setValue(copy->value);
+            return resource->engine->toString(resource->type->toString());
         }
     } else {
         return v8::Undefined();
@@ -317,6 +317,11 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property
     if (!result)
         return v8::Handle<v8::Value>();
 
+    if (result->isFunction()) {
+        // calling a Q_INVOKABLE function of a value type
+        return r->engine->qobjectWrapper()->getProperty(r->type, propertystring, QV8QObjectWrapper::IgnoreRevision);
+    }
+
 #define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
     if (result->propType == metatype) { \
         cpptype v; \
index 241a59a..4019167 100644 (file)
@@ -418,6 +418,115 @@ Data Storage
     or define the components individually, or compose it with
     the Qt.vector2d() function.
 
+    The vector2d type has the following idempotent functions which can be
+    invoked in QML:
+    \table
+        \header
+        \li Function Signature
+        \li Description
+        \li Example
+
+        \row
+        \li real dotProduct(vector2d other)
+        \li Returns the scalar real result of the dot product of \c this vector2d with the \c other vector2d
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = Qt.vector2d(3,4);
+var c = a.dotProduct(b);
+console.log(c); // 11
+            \endcode
+
+        \row
+        \li vector2d times(vector2d other)
+        \li Returns the vector2d result of multiplying \c this vector2d with the \c other vector2d
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = Qt.vector2d(3,4);
+var c = a.times(b);
+console.log(c.toString()); // QVector2D(3, 8)
+            \endcode
+
+        \row
+        \li vector2d times(real factor)
+        \li Returns the vector2d result of multiplying \c this vector2d with the scalar \c factor
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = 4.48;
+var c = a.times(b);
+console.log(c.toString()); // QVector2D(4.48, 8.96)
+            \endcode
+
+        \row
+        \li vector2d plus(vector2d other)
+        \li Returns the vector2d result of the addition of \c this vector2d with the \c other vector2d
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = Qt.vector2d(3,4);
+var c = a.plus(b);
+console.log(c.toString()); // QVector2D(4, 6)
+            \endcode
+
+        \row
+        \li vector2d minus(vector2d other)
+        \li Returns the vector2d result of the subtraction of \c other vector2d from \c this vector2d
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = Qt.vector2d(3,4);
+var c = a.minus(b);
+console.log(c.toString()); // QVector2D(-2, -2)
+            \endcode
+
+        \row
+        \li vector2d normalized()
+        \li Returns the normalized form of \c this vector
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = a.normalized();
+console.log(b.toString()); // QVector2D(0.447214, 0.894427)
+            \endcode
+
+        \row
+        \li real length()
+        \li Returns the scalar real value of the length of \c this vector2d
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = a.length();
+console.log(b.toString()); // 2.23606797749979
+            \endcode
+
+        \row
+        \li vector3d toVector3d()
+        \li Returns the vector3d result of converting \c this vector2d to a vector3d
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = a.toVector3d();
+console.log(b.toString()); // QVector3D(1, 2, 0)
+            \endcode
+
+        \row
+        \li vector4d toVector4d()
+        \li Returns the vector4d result of converting \c this vector2d to a vector4d
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = a.toVector4d();
+console.log(b.toString()); // QVector4D(1, 2, 0, 0)
+            \endcode
+
+        \row
+        \li bool fuzzyEquals(vector2d other, real epsilon)
+        \li Returns true if \c this vector2d is approximately equal to the \c other vector2d.
+            The approximation will be true if each attribute of \c this is within \c epsilon
+            of \c other.  Note that \c epsilon is an optional argument, the default \c epsilon
+            is 0.00001.
+        \li \code
+var a = Qt.vector2d(1,2);
+var b = Qt.vector2d(1.0001, 1.9998);
+var c = a.fuzzyEquals(b);        // default epsilon
+var d = a.fuzzyEquals(b, 0.005); // supplied epsilon
+console.log(c + " " + d); // false true
+            \endcode
+\endtable
+
     This basic type is provided by the QtQuick import.
 
     \sa {QML Basic Types}
@@ -448,10 +557,143 @@ Data Storage
     Rotation { angle: 60; axis.x: 0; axis.y: 1; axis.z: 0 }
     \endqml
 
+    Each attribute of a vector3d value is stored internally as a
+    single-precision floating point number (\c float).
+
     When integrating with C++, note that any QVector3D value
     \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
     converted into a \c vector3d value, and vice-versa.
 
+    The vector3d type has the following idempotent functions which can be
+    invoked in QML:
+    \table
+        \header
+        \li Function Signature
+        \li Description
+        \li Example
+
+        \row
+        \li vector3d crossProduct(vector3d other)
+        \li Returns the vector3d result of the cross product of \c this vector3d with the \c other vector3d
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = Qt.vector3d(4,5,6);
+var c = a.crossProduct(b);
+console.log(c.toString()); // QVector3D(-3, 6, -3)
+            \endcode
+
+        \row
+        \li real dotProduct(vector3d other)
+        \li Returns the scalar real result of the dot product of \c this vector3d with the \c other vector3d
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = Qt.vector3d(4,5,6);
+var c = a.dotProduct(b);
+console.log(c); // 32
+            \endcode
+
+        \row
+        \li vector3d times(matrix4x4 matrix)
+        \li Returns the vector3d result of transforming \c this vector3d with
+            the 4x4 \c matrix with the matrix applied post-vector
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = Qt.matrix4x4(4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);
+var c = a.times(b);
+console.log(c.toString()); // QVector3D(0.774194, 0.849462, 0.924731)
+            \endcode
+
+        \row
+        \li vector3d times(vector3d other)
+        \li Returns the vector3d result of multiplying \c this vector3d with the \c other vector3d
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = Qt.vector3d(4,5,6);
+var c = a.times(b);
+console.log(c.toString()); // QVector3D(4, 10, 18)
+            \endcode
+
+        \row
+        \li vector3d times(real factor)
+        \li Returns the vector3d result of multiplying \c this vector3d with the scalar \c factor
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = 4.48;
+var c = a.times(b);
+console.log(c.toString()); // QVector3D(4.48, 8.96, 13.44)
+            \endcode
+
+        \row
+        \li vector3d plus(vector3d other)
+        \li Returns the vector3d result of the addition of \c this vector3d with the \c other vector3d
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = Qt.vector3d(4,5,6);
+var c = a.plus(b);
+console.log(c.toString()); // QVector3D(5, 7, 9)
+            \endcode
+
+        \row
+        \li vector3d minus(vector3d other)
+        \li Returns the vector3d result of the subtraction of \c other vector3d from \c this vector3d
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = Qt.vector3d(4,5,6);
+var c = a.minus(b);
+console.log(c.toString()); // QVector3D(-3, -3, -3)
+            \endcode
+
+        \row
+        \li vector3d normalized()
+        \li Returns the normalized form of \c this vector
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = a.normalized();
+console.log(b.toString()); // QVector3D(0.267261, 0.534522, 0.801784)
+            \endcode
+
+        \row
+        \li real length()
+        \li Returns the scalar real value of the length of \c this vector3d
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = a.length();
+console.log(b.toString()); // 3.7416573867739413
+            \endcode
+
+        \row
+        \li vector2d toVector2d()
+        \li Returns the vector2d result of converting \c this vector3d to a vector2d
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = a.toVector2d();
+console.log(b.toString()); // QVector2D(1, 2)
+            \endcode
+
+        \row
+        \li vector4d toVector4d()
+        \li Returns the vector4d result of converting \c this vector3d to a vector4d
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = a.toVector4d();
+console.log(b.toString()); // QVector4D(1, 2, 3, 0)
+            \endcode
+
+        \row
+        \li bool fuzzyEquals(vector3d other, real epsilon)
+        \li Returns true if \c this vector3d is approximately equal to the \c other vector3d.
+            The approximation will be true if each attribute of \c this is within \c epsilon
+            of \c other.  Note that \c epsilon is an optional argument, the default \c epsilon
+            is 0.00001.
+        \li \code
+var a = Qt.vector3d(1,2,3);
+var b = Qt.vector3d(1.0001, 1.9998, 2.0001);
+var c = a.fuzzyEquals(b);        // default epsilon
+var d = a.fuzzyEquals(b, 0.005); // supplied epsilon
+console.log(c + " " + d); // false true
+            \endcode
+\endtable
+
     This basic type is provided by the QtQuick import.
 
     \sa {QML Basic Types}
@@ -471,6 +713,126 @@ Data Storage
     or define the components individually, or compose it with
     the Qt.vector4d() function.
 
+    The vector4d type has the following idempotent functions which can be
+    invoked in QML:
+    \table
+        \header
+        \li Function Signature
+        \li Description
+        \li Example
+
+        \row
+        \li real dotProduct(vector4d other)
+        \li Returns the scalar real result of the dot product of \c this vector4d with the \c other vector4d
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = Qt.vector4d(5,6,7,8);
+var c = a.dotProduct(b);
+console.log(c); // 70
+            \endcode
+
+        \row
+        \li vector4d times(matrix4x4 matrix)
+        \li Returns the vector4d result of transforming \c this vector4d with
+            the 4x4 \c matrix with the matrix applied post-vector
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = Qt.matrix4x4(4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);
+var c = a.times(b);
+console.log(c.toString()); // QVector4D(120, 130, 140, 150)
+            \endcode
+
+        \row
+        \li vector4d times(vector4d other)
+        \li Returns the vector4d result of multiplying \c this vector4d with the \c other vector4d
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = Qt.vector4d(5,6,7,8);
+var c = a.times(b);
+console.log(c.toString()); // QVector4D(5, 12, 21, 32)
+            \endcode
+
+        \row
+        \li vector4d times(real factor)
+        \li Returns the vector4d result of multiplying \c this vector4d with the scalar \c factor
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = 4.48;
+var c = a.times(b);
+console.log(c.toString()); // QVector3D(4.48, 8.96, 13.44, 17.92)
+            \endcode
+
+        \row
+        \li vector4d plus(vector4d other)
+        \li Returns the vector4d result of the addition of \c this vector4d with the \c other vector4d
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = Qt.vector4d(5,6,7,8);
+var c = a.plus(b);
+console.log(c.toString()); // QVector4D(6, 8, 10, 12)
+            \endcode
+
+        \row
+        \li vector4d minus(vector4d other)
+        \li Returns the vector4d result of the subtraction of \c other vector4d from \c this vector4d
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = Qt.vector4d(5,6,7,8);
+var c = a.minus(b);
+console.log(c.toString()); // QVector4D(-4, -4, -4, -4)
+            \endcode
+
+        \row
+        \li vector4d normalized()
+        \li Returns the normalized form of \c this vector
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = a.normalized();
+console.log(b.toString()); // QVector4D(0.182574, 0.365148, 0.547723, 0.730297)
+            \endcode
+
+        \row
+        \li real length()
+        \li Returns the scalar real value of the length of \c this vector3d
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = a.length();
+console.log(b.toString()); // 5.477225575051661
+            \endcode
+
+        \row
+        \li vector2d toVector2d()
+        \li Returns the vector2d result of converting \c this vector4d to a vector2d
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = a.toVector2d();
+console.log(b.toString()); // QVector2D(1, 2)
+            \endcode
+
+        \row
+        \li vector3d toVector3d()
+        \li Returns the vector3d result of converting \c this vector4d to a vector3d
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = a.toVector3d();
+console.log(b.toString()); // QVector3D(1, 2, 3)
+            \endcode
+
+        \row
+        \li bool fuzzyEquals(vector4d other, real epsilon)
+        \li Returns true if \c this vector4d is approximately equal to the \c other vector4d.
+            The approximation will be true if each attribute of \c this is within \c epsilon
+            of \c other.  Note that \c epsilon is an optional argument, the default \c epsilon
+            is 0.00001.
+        \li \code
+var a = Qt.vector4d(1,2,3,4);
+var b = Qt.vector4d(1.0001, 1.9998, 2.0001, 3.9999);
+var c = a.fuzzyEquals(b);        // default epsilon
+var d = a.fuzzyEquals(b, 0.005); // supplied epsilon
+console.log(c + " " + d); // false true
+            \endcode
+\endtable
+
     This basic type is provided by the QtQuick import.
 
     \sa {QML Basic Types}
@@ -482,9 +844,7 @@ Data Storage
 
     \brief A quaternion type has scalar, x, y, and z attributes.
 
-    A \c quaternion type has \c scalar, \c x, \c y and \c z attributes,
-    otherwise it is similar to the \c vector3d type.  Please see the
-    documentation about the \c vector3d type for more information.
+    A \c quaternion type has \c scalar, \c x, \c y and \c z attributes.
 
     To create a \c quaternion value, specify it as a "scalar,x,y,z" string,
     or define the components individually, or compose it with
@@ -501,9 +861,148 @@ Data Storage
 
     \brief A matrix4x4 type is a 4-row and 4-column matrix
 
-    A \c matrix4x4 type has sixteen values, but these values are
-    largely opaque to QML.  Values of this type can be composed with
-    the Qt.matrix4x4() function.
+    A \c matrix4x4 type has sixteen values, each accessible via the properties
+    \c m11 through \c m44 in QML (in row/column order).  Values of this type
+    can be composed with the Qt.matrix4x4() function.  Each attribute in a
+    matrix4x4 is stored as a real (single-precision on ARM, double-precision
+    on x86).
+
+    The matrix4x4 type has the following idempotent functions which can be
+    invoked in QML:
+    \table
+        \header
+        \li Function Signature
+        \li Description
+        \li Example
+
+        \row
+        \li matrix4x4 times(matrix4x4 other)
+        \li Returns the matrix4x4 result of multiplying \c this matrix4x4 with
+            the \c other matrix4x4
+        \li \code
+var a = Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+var b = Qt.matrix4x4(4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);
+var c = a.times(b);
+console.log(c.toString()); // QMatrix4x4(120, 130, 140, 150, 280, 306, 332, 358, 440, 482, 524, 566, 600, 658, 716, 774)
+            \endcode
+
+        \row
+        \li vector4d times(vector4d vector)
+        \li Returns the vector4d result of transforming the \c vector
+            according to \c this matrix4x4 with the matrix applied
+            pre-vector
+        \li \code
+var a = Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+var b = Qt.vector4d(5,6,7,8);
+var c = a.times(b);
+console.log(c.toString()); // QVector4D(70, 174, 278, 382)
+            \endcode
+
+        \row
+        \li vector3d times(vector3d vector)
+        \li Returns the vector3d result of transforming the \c vector
+            according to \c this matrix4x4 with the matrix applied
+            pre-vector
+        \li \code
+var a = Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+var b = Qt.vector3d(5,6,7);
+var c = a.times(b);
+console.log(c.toString()); // QVector3D(0.155556, 0.437037, 0.718518)
+            \endcode
+
+        \row
+        \li matrix4x4 times(real factor)
+        \li Returns the matrix4x4 result of multiplying \c this matrix4x4 with the scalar \c factor
+        \li \code
+var a = Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+var b = 4.48;
+var c = a.times(b);
+console.log(c.toString()); // QMatrix4x4(4.48, 8.96, 13.44, 17.92, 22.4, 26.88, 31.36, 35.84, 40.32, 44.8, 49.28, 53.76, 58.24, 62.72, 67.2, 71.68)
+            \endcode
+
+        \row
+        \li matrix4x4 plus(matrix4x4 other)
+        \li Returns the matrix4x4 result of the addition of \c this matrix4x4 with the \c other matrix4x4
+        \li \code
+var a = Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+var b = Qt.matrix4x4(5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
+var c = a.plus(b);
+console.log(c.toString()); // QMatrix4x4(6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36)
+            \endcode
+
+        \row
+        \li matrix4x4 minus(matrix4x4 other)
+        \li Returns the matrix4x4 result of the subtraction of \c other matrix4x4 from \c this matrix4x4
+        \li \code
+var a = Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+var b = Qt.matrix4x4(5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
+var c = a.minus(b);
+console.log(c.toString()); // QMatrix4x4(-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4)
+            \endcode
+
+        \row
+        \li vector4d row(int which)
+        \li Returns the vector4d row of \c this specified by \c which.
+            Note: the \c which is 0-based access into the matrix.
+        \li \code
+var a = Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+var b = Qt.vector4d(a.m21, a.m22, a.m23, a.m24);
+var c = a.row(2); // zero based access!  so not equal to b
+console.log(b.toString() + " " + c.toString()); // QVector4D(5, 6, 7, 8) QVector4D(9, 10, 11, 12)
+            \endcode
+
+        \row
+        \li vector4d column(int which)
+        \li Returns the vector4d column of \c this specified by \c which.
+            Note: the \c which is 0-based access into the matrix.
+        \li \code
+var a = Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+var b = Qt.vector4d(a.m12, a.m22, a.m32, a.m42);
+var c = a.column(2); // zero based access!  so not equal to b
+console.log(b.toString() + " " + c.toString()); // QVector4D(2, 6, 10, 14) QVector4D(3, 7, 11, 15)
+            \endcode
+
+        \row
+        \li real determinant()
+        \li Returns the determinant of \c this matrix4x4
+        \li \code
+var a = Qt.matrix4x4(1,0,0,0,0,2,0,0,0,0,3,0,100,200,300,1);
+var b = a.determinant();
+console.log(b); // 6
+            \endcode
+
+        \row
+        \li matrix4x4 inverted()
+        \li Returns the inverse of \c this matrix4x4 if it exists, else the identity matrix.
+        \li \code
+var a = Qt.matrix4x4(1,0,0,0,0,2,0,0,0,0,3,0,100,200,300,1);
+var b = a.inverted();
+console.log(b.toString()); // QMatrix4x4(1, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0.333333, 0, -100, -100, -100, 1)
+            \endcode
+
+        \row
+        \li matrix4x4 transposed()
+        \li Returns the transpose of \c this matrix4x4
+        \li \code
+var a = Qt.matrix4x4(1,0,0,0,0,2,0,0,0,0,3,0,100,200,300,1);
+var b = a.transposed();
+console.log(b.toString()); // QMatrix4x4(1, 0, 0, 100, 0, 2, 0, 200, 0, 0, 3, 300, 0, 0, 0, 1)
+            \endcode
+
+        \row
+        \li bool fuzzyEquals(matrix4x4 other, real epsilon)
+        \li Returns true if \c this matrix4x4 is approximately equal to the \c other matrix4x4.
+            The approximation will be true if each attribute of \c this is within \c epsilon
+            of the respective attribute of \c other.  Note that \c epsilon is an optional
+            argument, the default \c epsilon is 0.00001.
+        \li \code
+var a = Qt.matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
+var b = Qt.matrix4x4(1.0001,2.0001,3.0002,4.0003,5.0001,6.0002,7.0002,8.0004,9.0001,10.0003,11.0003,12.0004,13.0001,14.0002,15.0003,16.0004);
+var c = a.fuzzyEquals(b);        // default epsilon
+var d = a.fuzzyEquals(b, 0.005); // supplied epsilon
+console.log(c + " " + d); // false true
+            \endcode
+\endtable
 
     This basic type is provided by the QtQuick import.
 
index 1708cf7..3d27e83 100644 (file)
@@ -203,8 +203,8 @@ public:
             int index = s.indexOf(QLatin1Char(','));
 
             bool xGood, yGood;
-            qreal xCoord = s.left(index).toDouble(&xGood);
-            qreal yCoord = s.mid(index+1).toDouble(&yGood);
+            float xCoord = s.left(index).toFloat(&xGood);
+            float yCoord = s.mid(index+1).toFloat(&yGood);
 
             if (xGood && yGood) {
                 if (ok) *ok = true;
@@ -223,9 +223,9 @@ public:
             int index2 = s.indexOf(QLatin1Char(','), index+1);
 
             bool xGood, yGood, zGood;
-            qreal xCoord = s.left(index).toDouble(&xGood);
-            qreal yCoord = s.mid(index+1, index2-index-1).toDouble(&yGood);
-            qreal zCoord = s.mid(index2+1).toDouble(&zGood);
+            float xCoord = s.left(index).toFloat(&xGood);
+            float yCoord = s.mid(index+1, index2-index-1).toFloat(&yGood);
+            float zCoord = s.mid(index2+1).toFloat(&zGood);
 
             if (xGood && yGood && zGood) {
                 if (ok) *ok = true;
@@ -245,10 +245,10 @@ public:
             int index3 = s.indexOf(QLatin1Char(','), index2+1);
 
             bool xGood, yGood, zGood, wGood;
-            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);
+            float xCoord = s.left(index).toFloat(&xGood);
+            float yCoord = s.mid(index+1, index2-index-1).toFloat(&yGood);
+            float zCoord = s.mid(index2+1, index3-index2-1).toFloat(&zGood);
+            float wCoord = s.mid(index3+1).toFloat(&wGood);
 
             if (xGood && yGood && zGood && wGood) {
                 if (ok) *ok = true;
@@ -582,7 +582,7 @@ public:
             break;
         case QMetaType::QQuaternion:
             if (argc == 1) {
-                const double *sxyz = reinterpret_cast<const double*>(argv[0]);
+                const qreal *sxyz = reinterpret_cast<const qreal*>(argv[0]);
                 QQuaternion q(sxyz[0], sxyz[1], sxyz[2], sxyz[3]);
                 *v = QVariant(q);
                 return true;
@@ -590,7 +590,7 @@ public:
             break;
         case QMetaType::QMatrix4x4:
             if (argc == 1) {
-                const float *vals = reinterpret_cast<const float*>(argv[0]);
+                const qreal *vals = reinterpret_cast<const qreal*>(argv[0]);
                 QMatrix4x4 m(vals[0], vals[1], vals[2], vals[3],
                              vals[4], vals[5], vals[6], vals[7],
                              vals[8], vals[9], vals[10], vals[11],
index 4224847..c0f7e62 100644 (file)
@@ -118,6 +118,15 @@ QString QQuickVector2DValueType::toString() const
     return QString(QLatin1String("QVector2D(%1, %2)")).arg(v.x()).arg(v.y());
 }
 
+bool QQuickVector2DValueType::isEqual(const QVariant &other) const
+{
+    if (other.userType() != QMetaType::QVector2D)
+        return false;
+
+    QVector2D otherVector = other.value<QVector2D>();
+    return (v == otherVector);
+}
+
 qreal QQuickVector2DValueType::x() const
 {
     return v.x();
@@ -138,6 +147,66 @@ void QQuickVector2DValueType::setY(qreal y)
     v.setY(y);
 }
 
+qreal QQuickVector2DValueType::dotProduct(const QVector2D &vec) const
+{
+    return QVector2D::dotProduct(v, vec);
+}
+
+QVector2D QQuickVector2DValueType::times(const QVector2D &vec) const
+{
+    return v * vec;
+}
+
+QVector2D QQuickVector2DValueType::times(qreal scalar) const
+{
+    return v * scalar;
+}
+
+QVector2D QQuickVector2DValueType::plus(const QVector2D &vec) const
+{
+    return v + vec;
+}
+
+QVector2D QQuickVector2DValueType::minus(const QVector2D &vec) const
+{
+    return v - vec;
+}
+
+QVector2D QQuickVector2DValueType::normalized() const
+{
+    return v.normalized();
+}
+
+qreal QQuickVector2DValueType::length() const
+{
+    return v.length();
+}
+
+QVector3D QQuickVector2DValueType::toVector3d() const
+{
+    return v.toVector3D();
+}
+
+QVector4D QQuickVector2DValueType::toVector4d() const
+{
+    return v.toVector4D();
+}
+
+bool QQuickVector2DValueType::fuzzyEquals(const QVector2D &vec, qreal epsilon) const
+{
+    qreal absEps = qAbs(epsilon);
+    if (qAbs(v.x() - vec.x()) > absEps)
+        return false;
+    if (qAbs(v.y() - vec.y()) > absEps)
+        return false;
+    return true;
+}
+
+bool QQuickVector2DValueType::fuzzyEquals(const QVector2D &vec) const
+{
+    return qFuzzyCompare(v, vec);
+}
+
 
 QQuickVector3DValueType::QQuickVector3DValueType(QObject *parent)
     : QQmlValueTypeBase<QVector3D>(QMetaType::QVector3D, parent)
@@ -149,6 +218,15 @@ QString QQuickVector3DValueType::toString() const
     return QString(QLatin1String("QVector3D(%1, %2, %3)")).arg(v.x()).arg(v.y()).arg(v.z());
 }
 
+bool QQuickVector3DValueType::isEqual(const QVariant &other) const
+{
+    if (other.userType() != QMetaType::QVector3D)
+        return false;
+
+    QVector3D otherVector = other.value<QVector3D>();
+    return (v == otherVector);
+}
+
 qreal QQuickVector3DValueType::x() const
 {
     return v.x();
@@ -179,6 +257,78 @@ void QQuickVector3DValueType::setZ(qreal z)
     v.setZ(z);
 }
 
+QVector3D QQuickVector3DValueType::crossProduct(const QVector3D &vec) const
+{
+    return QVector3D::crossProduct(v, vec);
+}
+
+qreal QQuickVector3DValueType::dotProduct(const QVector3D &vec) const
+{
+    return QVector3D::dotProduct(v, vec);
+}
+
+QVector3D QQuickVector3DValueType::times(const QMatrix4x4 &m) const
+{
+    return v * m;
+}
+
+QVector3D QQuickVector3DValueType::times(const QVector3D &vec) const
+{
+    return v * vec;
+}
+
+QVector3D QQuickVector3DValueType::times(qreal scalar) const
+{
+    return v * scalar;
+}
+
+QVector3D QQuickVector3DValueType::plus(const QVector3D &vec) const
+{
+    return v + vec;
+}
+
+QVector3D QQuickVector3DValueType::minus(const QVector3D &vec) const
+{
+    return v - vec;
+}
+
+QVector3D QQuickVector3DValueType::normalized() const
+{
+    return v.normalized();
+}
+
+qreal QQuickVector3DValueType::length() const
+{
+    return v.length();
+}
+
+QVector2D QQuickVector3DValueType::toVector2d() const
+{
+    return v.toVector2D();
+}
+
+QVector4D QQuickVector3DValueType::toVector4d() const
+{
+    return v.toVector4D();
+}
+
+bool QQuickVector3DValueType::fuzzyEquals(const QVector3D &vec, qreal epsilon) const
+{
+    qreal absEps = qAbs(epsilon);
+    if (qAbs(v.x() - vec.x()) > absEps)
+        return false;
+    if (qAbs(v.y() - vec.y()) > absEps)
+        return false;
+    if (qAbs(v.z() - vec.z()) > absEps)
+        return false;
+    return true;
+}
+
+bool QQuickVector3DValueType::fuzzyEquals(const QVector3D &vec) const
+{
+    return qFuzzyCompare(v, vec);
+}
+
 
 QQuickVector4DValueType::QQuickVector4DValueType(QObject *parent)
     : QQmlValueTypeBase<QVector4D>(QMetaType::QVector4D, parent)
@@ -190,6 +340,15 @@ QString QQuickVector4DValueType::toString() const
     return QString(QLatin1String("QVector4D(%1, %2, %3, %4)")).arg(v.x()).arg(v.y()).arg(v.z()).arg(v.w());
 }
 
+bool QQuickVector4DValueType::isEqual(const QVariant &other) const
+{
+    if (other.userType() != QMetaType::QVector4D)
+        return false;
+
+    QVector4D otherVector = other.value<QVector4D>();
+    return (v == otherVector);
+}
+
 qreal QQuickVector4DValueType::x() const
 {
     return v.x();
@@ -230,6 +389,74 @@ void QQuickVector4DValueType::setW(qreal w)
     v.setW(w);
 }
 
+qreal QQuickVector4DValueType::dotProduct(const QVector4D &vec) const
+{
+    return QVector4D::dotProduct(v, vec);
+}
+
+QVector4D QQuickVector4DValueType::times(const QVector4D &vec) const
+{
+    return v * vec;
+}
+
+QVector4D QQuickVector4DValueType::times(const QMatrix4x4 &m) const
+{
+    return v * m;
+}
+
+QVector4D QQuickVector4DValueType::times(qreal scalar) const
+{
+    return v * scalar;
+}
+
+QVector4D QQuickVector4DValueType::plus(const QVector4D &vec) const
+{
+    return v + vec;
+}
+
+QVector4D QQuickVector4DValueType::minus(const QVector4D &vec) const
+{
+    return v - vec;
+}
+
+QVector4D QQuickVector4DValueType::normalized() const
+{
+    return v.normalized();
+}
+
+qreal QQuickVector4DValueType::length() const
+{
+    return v.length();
+}
+
+QVector2D QQuickVector4DValueType::toVector2d() const
+{
+    return v.toVector2D();
+}
+
+QVector3D QQuickVector4DValueType::toVector3d() const
+{
+    return v.toVector3D();
+}
+
+bool QQuickVector4DValueType::fuzzyEquals(const QVector4D &vec, qreal epsilon) const
+{
+    qreal absEps = qAbs(epsilon);
+    if (qAbs(v.x() - vec.x()) > absEps)
+        return false;
+    if (qAbs(v.y() - vec.y()) > absEps)
+        return false;
+    if (qAbs(v.z() - vec.z()) > absEps)
+        return false;
+    if (qAbs(v.w() - vec.w()) > absEps)
+        return false;
+    return true;
+}
+
+bool QQuickVector4DValueType::fuzzyEquals(const QVector4D &vec) const
+{
+    return qFuzzyCompare(v, vec);
+}
 
 QQuickQuaternionValueType::QQuickQuaternionValueType(QObject *parent)
     : QQmlValueTypeBase<QQuaternion>(QMetaType::QQuaternion, parent)
@@ -287,6 +514,79 @@ QQuickMatrix4x4ValueType::QQuickMatrix4x4ValueType(QObject *parent)
 {
 }
 
+QMatrix4x4 QQuickMatrix4x4ValueType::times(const QMatrix4x4 &m) const
+{
+    return v * m;
+}
+
+QVector4D QQuickMatrix4x4ValueType::times(const QVector4D &vec) const
+{
+    return v * vec;
+}
+
+QVector3D QQuickMatrix4x4ValueType::times(const QVector3D &vec) const
+{
+    return v * vec;
+}
+
+QMatrix4x4 QQuickMatrix4x4ValueType::times(qreal factor) const
+{
+    return v * factor;
+}
+
+QMatrix4x4 QQuickMatrix4x4ValueType::plus(const QMatrix4x4 &m) const
+{
+    return v + m;
+}
+
+QMatrix4x4 QQuickMatrix4x4ValueType::minus(const QMatrix4x4 &m) const
+{
+    return v - m;
+}
+
+QVector4D QQuickMatrix4x4ValueType::row(int n) const
+{
+    return v.row(n);
+}
+
+QVector4D QQuickMatrix4x4ValueType::column(int m) const
+{
+    return v.column(m);
+}
+
+qreal QQuickMatrix4x4ValueType::determinant() const
+{
+    return v.determinant();
+}
+
+QMatrix4x4 QQuickMatrix4x4ValueType::inverted() const
+{
+    return v.inverted();
+}
+
+QMatrix4x4 QQuickMatrix4x4ValueType::transposed() const
+{
+    return v.transposed();
+}
+
+bool QQuickMatrix4x4ValueType::fuzzyEquals(const QMatrix4x4 &m, qreal epsilon) const
+{
+    qreal absEps = qAbs(epsilon);
+    for (int i = 0; i < 4; ++i) {
+        for (int j = 0; j < 4; ++j) {
+            if (qAbs(v(i,j) - m(i,j)) > absEps) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool QQuickMatrix4x4ValueType::fuzzyEquals(const QMatrix4x4 &m) const
+{
+    return qFuzzyCompare(v, m);
+}
+
 QString QQuickMatrix4x4ValueType::toString() const
 {
     return QString(QLatin1String("QMatrix4x4(%1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16)"))
@@ -296,6 +596,15 @@ QString QQuickMatrix4x4ValueType::toString() const
             .arg(v(3, 0)).arg(v(3, 1)).arg(v(3, 2)).arg(v(3, 3));
 }
 
+bool QQuickMatrix4x4ValueType::isEqual(const QVariant &other) const
+{
+    if (other.userType() != qMetaTypeId<QMatrix4x4>())
+        return false;
+
+    QMatrix4x4 otherMatrix = other.value<QMatrix4x4>();
+    return (v == otherMatrix);
+
+}
 
 QQuickFontValueType::QQuickFontValueType(QObject *parent)
     : QQmlValueTypeBase<QFont>(QMetaType::QFont, parent),
index d2767db..09c91d3 100644 (file)
@@ -95,11 +95,24 @@ public:
     QQuickVector2DValueType(QObject *parent = 0);
 
     virtual QString toString() const;
+    virtual bool isEqual(const QVariant &other) const;
 
     qreal x() const;
     qreal y() const;
     void setX(qreal);
     void setY(qreal);
+
+    Q_INVOKABLE qreal dotProduct(const QVector2D &vec) const;
+    Q_INVOKABLE QVector2D times(const QVector2D &vec) const;
+    Q_INVOKABLE QVector2D times(qreal scalar) const;
+    Q_INVOKABLE QVector2D plus(const QVector2D &vec) const;
+    Q_INVOKABLE QVector2D minus(const QVector2D &vec) const;
+    Q_INVOKABLE QVector2D normalized() const;
+    Q_INVOKABLE qreal length() const;
+    Q_INVOKABLE QVector3D toVector3d() const;
+    Q_INVOKABLE QVector4D toVector4d() const;
+    Q_INVOKABLE bool fuzzyEquals(const QVector2D &vec, qreal epsilon) const;
+    Q_INVOKABLE bool fuzzyEquals(const QVector2D &vec) const;
 };
 
 class Q_AUTOTEST_EXPORT QQuickVector3DValueType : public QQmlValueTypeBase<QVector3D>
@@ -112,6 +125,7 @@ public:
     QQuickVector3DValueType(QObject *parent = 0);
 
     virtual QString toString() const;
+    virtual bool isEqual(const QVariant &other) const;
 
     qreal x() const;
     qreal y() const;
@@ -119,6 +133,20 @@ public:
     void setX(qreal);
     void setY(qreal);
     void setZ(qreal);
+
+    Q_INVOKABLE QVector3D crossProduct(const QVector3D &vec) const;
+    Q_INVOKABLE qreal dotProduct(const QVector3D &vec) const;
+    Q_INVOKABLE QVector3D times(const QMatrix4x4 &m) const;
+    Q_INVOKABLE QVector3D times(const QVector3D &vec) const;
+    Q_INVOKABLE QVector3D times(qreal scalar) const;
+    Q_INVOKABLE QVector3D plus(const QVector3D &vec) const;
+    Q_INVOKABLE QVector3D minus(const QVector3D &vec) const;
+    Q_INVOKABLE QVector3D normalized() const;
+    Q_INVOKABLE qreal length() const;
+    Q_INVOKABLE QVector2D toVector2d() const;
+    Q_INVOKABLE QVector4D toVector4d() const;
+    Q_INVOKABLE bool fuzzyEquals(const QVector3D &vec, qreal epsilon) const;
+    Q_INVOKABLE bool fuzzyEquals(const QVector3D &vec) const;
 };
 
 class Q_AUTOTEST_EXPORT QQuickVector4DValueType : public QQmlValueTypeBase<QVector4D>
@@ -132,6 +160,7 @@ public:
     QQuickVector4DValueType(QObject *parent = 0);
 
     virtual QString toString() const;
+    virtual bool isEqual(const QVariant &other) const;
 
     qreal x() const;
     qreal y() const;
@@ -141,6 +170,19 @@ public:
     void setY(qreal);
     void setZ(qreal);
     void setW(qreal);
+
+    Q_INVOKABLE qreal dotProduct(const QVector4D &vec) const;
+    Q_INVOKABLE QVector4D times(const QVector4D &vec) const;
+    Q_INVOKABLE QVector4D times(const QMatrix4x4 &m) const;
+    Q_INVOKABLE QVector4D times(qreal scalar) const;
+    Q_INVOKABLE QVector4D plus(const QVector4D &vec) const;
+    Q_INVOKABLE QVector4D minus(const QVector4D &vec) const;
+    Q_INVOKABLE QVector4D normalized() const;
+    Q_INVOKABLE qreal length() const;
+    Q_INVOKABLE QVector2D toVector2d() const;
+    Q_INVOKABLE QVector3D toVector3d() const;
+    Q_INVOKABLE bool fuzzyEquals(const QVector4D &vec, qreal epsilon) const;
+    Q_INVOKABLE bool fuzzyEquals(const QVector4D &vec) const;
 };
 
 class Q_AUTOTEST_EXPORT QQuickQuaternionValueType : public QQmlValueTypeBase<QQuaternion>
@@ -188,6 +230,7 @@ public:
     QQuickMatrix4x4ValueType(QObject *parent = 0);
 
     virtual QString toString() const;
+    virtual bool isEqual(const QVariant &other) const;
 
     qreal m11() const { return v(0, 0); }
     qreal m12() const { return v(0, 1); }
@@ -222,6 +265,23 @@ public:
     void setM42(qreal value) { v(3, 1) = value; }
     void setM43(qreal value) { v(3, 2) = value; }
     void setM44(qreal value) { v(3, 3) = value; }
+
+    Q_INVOKABLE QMatrix4x4 times(const QMatrix4x4 &m) const;
+    Q_INVOKABLE QVector4D times(const QVector4D &vec) const;
+    Q_INVOKABLE QVector3D times(const QVector3D &vec) const;
+    Q_INVOKABLE QMatrix4x4 times(qreal factor) const;
+    Q_INVOKABLE QMatrix4x4 plus(const QMatrix4x4 &m) const;
+    Q_INVOKABLE QMatrix4x4 minus(const QMatrix4x4 &m) const;
+
+    Q_INVOKABLE QVector4D row(int n) const;
+    Q_INVOKABLE QVector4D column(int m) const;
+
+    Q_INVOKABLE qreal determinant() const;
+    Q_INVOKABLE QMatrix4x4 inverted() const;
+    Q_INVOKABLE QMatrix4x4 transposed() const;
+
+    Q_INVOKABLE bool fuzzyEquals(const QMatrix4x4 &m, qreal epsilon) const;
+    Q_INVOKABLE bool fuzzyEquals(const QMatrix4x4 &m) const;
 };
 
 class Q_AUTOTEST_EXPORT QQuickFontValueType : public QQmlValueTypeBase<QFont>
diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/invokableFunctions.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/invokableFunctions.qml
new file mode 100644 (file)
index 0000000..85e87e9
--- /dev/null
@@ -0,0 +1,52 @@
+import QtQuick 2.0
+
+Item {
+    property bool success: false
+    property bool complete: false
+
+    property matrix4x4 m1: Qt.matrix4x4(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4)
+    property matrix4x4 m2: Qt.matrix4x4(5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8)
+    property vector4d v1: Qt.vector4d(1,2,3,4)
+    property vector4d v2: Qt.vector4d(5,6,7,8)
+    property real scalar: 5
+
+    Component.onCompleted: {
+        // test that invokable functions of non-qml module value types work
+        complete = false;
+        success = true;
+        var result;
+
+        result = v1.plus(v2);
+        if (result != Qt.vector4d(6, 8, 10, 12)) success = false;
+
+        result = v1.times(scalar);
+        if (result != Qt.vector4d(5, 10, 15, 20)) success = false;
+
+        result = v1.times(v2);
+        if (result != Qt.vector4d(5, 12, 21, 32)) success = false;
+
+        // ensure that side-effects don't cause overwrite of valuetype-copy values.
+        result = Qt.vector4d(1,2,3,4).times(Qt.vector4d(5,6,7,8), Qt.vector4d(9,9,9,9).toString());
+        if (result != Qt.vector4d(5, 12, 21, 32)) success = false;
+
+        result = v1.times(m2);
+        if (result != Qt.vector4d(70,70,70,70)) success = false;
+
+        result = m1.times(v2);
+        if (result != Qt.vector4d(26, 52, 78, 104)) success = false;
+
+        result = m1.times(m2);
+        if (result != Qt.matrix4x4(26,26,26,26,52,52,52,52,78,78,78,78,104,104,104,104)) success = false;
+
+        result = m1.plus(m2);
+        if (result != Qt.matrix4x4(6,6,6,6,8,8,8,8,10,10,10,10,12,12,12,12)) success = false;
+
+        result = m1.row(2);    // zero-based
+        if (result != Qt.vector4d(3, 3, 3, 3)) success = false;
+
+        result = m1.column(2); // zero-based
+        if (result != Qt.vector4d(1, 2, 3, 4)) success = false;
+
+        complete = true;
+    }
+}
index d811767..20cc93b 100644 (file)
@@ -70,6 +70,7 @@ private slots:
     void comparisonSemantics();
     void cppIntegration();
     void jsObjectConversion();
+    void invokableFunctions();
 };
 
 void tst_qqmlvaluetypeproviders::initTestCase()
@@ -168,6 +169,19 @@ void tst_qqmlvaluetypeproviders::jsObjectConversion()
     delete object;
 }
 
+void tst_qqmlvaluetypeproviders::invokableFunctions()
+{
+    QQmlEngine e;
+    QQmlComponent component(&e, testFileUrl("invokableFunctions.qml"));
+    QVERIFY(!component.isError());
+    QVERIFY(component.errors().isEmpty());
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+    QVERIFY(object->property("complete").toBool());
+    QVERIFY(object->property("success").toBool());
+    delete object;
+}
+
 QTEST_MAIN(tst_qqmlvaluetypeproviders)
 
 #include "tst_qqmlvaluetypeproviders.moc"
diff --git a/tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml b/tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml
new file mode 100644 (file)
index 0000000..aa26956
--- /dev/null
@@ -0,0 +1,31 @@
+import QtQuick 2.0
+
+Item {
+    property bool success: false
+
+    property variant m1: Qt.matrix4x4(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4)
+    property variant m2: Qt.matrix4x4(5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8)
+    property variant m3: Qt.matrix4x4(123,22,6,42,55,54,67,77,777,1,112,22,55,6696,77,777)
+    property variant v1: Qt.vector4d(1,2,3,4)
+    property variant v2: Qt.vector3d(1,2,3)
+    property real factor: 2.23
+
+    Component.onCompleted: {
+        success = true;
+        if (m1.times(m2) != Qt.matrix4x4(26, 26, 26, 26, 52, 52, 52, 52, 78, 78, 78, 78, 104, 104, 104, 104)) success = false;
+        if (m1.times(v1) != Qt.vector4d(10, 20, 30, 40)) success = false;
+        if (m1.times(v2) != Qt.vector3d(0.25, 0.5, 0.75)) success = false;
+        if (!m1.times(factor).fuzzyEquals(Qt.matrix4x4(2.23, 2.23, 2.23, 2.23, 4.46, 4.46, 4.46, 4.46, 6.69, 6.69, 6.69, 6.69, 8.92, 8.92, 8.92, 8.92))) success = false;
+        if (m1.plus(m2) != Qt.matrix4x4(6, 6, 6, 6, 8, 8, 8, 8, 10, 10, 10, 10, 12, 12, 12, 12)) success = false;
+        if (m2.minus(m1) != Qt.matrix4x4(4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4)) success = false;
+        if (m1.row(2) != Qt.vector4d(3,3,3,3)) success = false;
+        if (m1.column(2) != Qt.vector4d(1,2,3,4)) success = false;
+        if (m1.determinant() != 0) success = false;
+        if (m3.determinant() != -15260238498) success = false;
+        if (m1.inverted() != Qt.matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)) success = false; // non-invertible
+        if (!m3.inverted().fuzzyEquals(Qt.matrix4x4(0.0028384, -0.00188321, 0.000970577, 0.00000571656, -0.00206701, -0.000598587, 0.000358192, 0.000160908, -0.0235917, 0.0122695, 0.00286765, -0.0000218643, 0.01995, 0.00407588, -0.00343969, -0.000097903), 0.00001)) success = false;
+        if (m1.transposed() != Qt.matrix4x4(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4)) success = false;
+        if (m1.fuzzyEquals(m2)) success = false;
+        if (!m1.fuzzyEquals(m2, 10)) success = false;
+    }
+}
diff --git a/tests/auto/qml/qqmlvaluetypes/data/vector2d_invokables.qml b/tests/auto/qml/qqmlvaluetypes/data/vector2d_invokables.qml
new file mode 100644 (file)
index 0000000..9f84a50
--- /dev/null
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Item {
+    property bool success: false
+
+    property variant v1: Qt.vector2d(1,2)
+    property variant v2: Qt.vector2d(5,6)
+    property real factor: 2.23
+
+    Component.onCompleted: {
+        success = true;
+        if (v1.times(v2) != Qt.vector2d(5, 12)) success = false;
+        if (v1.times(factor) != Qt.vector2d(2.23, 4.46)) success = false;
+        if (v1.plus(v2) != Qt.vector2d(6, 8)) success = false;
+        if (v2.minus(v1) != Qt.vector2d(4, 4)) success = false;
+        if (!v1.normalized().fuzzyEquals(Qt.vector2d(0.447214, 0.894427), 0.000001)) success = false;
+        if ((v1.length() == v2.length()) || (v1.length() != Qt.vector2d(2,1).length())) success = false;
+        if (v1.toVector3d() != Qt.vector3d(1,2,0)) success = false;
+        if (v1.toVector4d() != Qt.vector4d(1,2,0,0)) success = false;
+        if (v1.fuzzyEquals(v2)) success = false;
+        if (!v1.fuzzyEquals(v2, 4)) success = false;
+    }
+}
diff --git a/tests/auto/qml/qqmlvaluetypes/data/vector3d_invokables.qml b/tests/auto/qml/qqmlvaluetypes/data/vector3d_invokables.qml
new file mode 100644 (file)
index 0000000..48185f9
--- /dev/null
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+
+Item {
+    property bool success: false
+
+    property variant v1: Qt.vector3d(1,2,3)
+    property variant v2: Qt.vector3d(5,6,7)
+    property variant m1: Qt.matrix4x4(5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8)
+    property real factor: 2.23
+
+    Component.onCompleted: {
+        success = true;
+        if (v1.times(v2) != Qt.vector3d(5, 12, 21)) success = false;
+        if (v1.times(m1) != Qt.vector3d(1, 1, 1)) success = false;
+        if (v1.times(factor) != Qt.vector3d(2.23, 4.46, 6.69)) success = false;
+        if (v1.plus(v2) != Qt.vector3d(6, 8, 10)) success = false;
+        if (v2.minus(v1) != Qt.vector3d(4, 4, 4)) success = false;
+        if (!v1.normalized().fuzzyEquals(Qt.vector3d(0.267261, 0.534522, 0.801784), 0.00001)) success = false;
+        if ((v1.length() == v2.length()) || (v1.length() != Qt.vector3d(3,2,1).length())) success = false;
+        if (v1.toVector2d() != Qt.vector2d(1,2)) success = false;
+        if (v1.toVector4d() != Qt.vector4d(1,2,3,0)) success = false;
+        if (v1.fuzzyEquals(v2)) success = false;
+        if (!v1.fuzzyEquals(v2, 4)) success = false;
+    }
+}
diff --git a/tests/auto/qml/qqmlvaluetypes/data/vector4d_invokables.qml b/tests/auto/qml/qqmlvaluetypes/data/vector4d_invokables.qml
new file mode 100644 (file)
index 0000000..c80ee0d
--- /dev/null
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+
+Item {
+    property bool success: false
+
+    property variant v1: Qt.vector4d(1,2,3,4)
+    property variant v2: Qt.vector4d(5,6,7,8)
+    property variant m1: Qt.matrix4x4(5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8)
+    property real factor: 2.23
+
+    Component.onCompleted: {
+        success = true;
+        if (v1.times(v2) != Qt.vector4d(5, 12, 21, 32)) success = false;
+        if (v1.times(m1) != Qt.vector4d(70, 70, 70, 70)) success = false;
+        if (v1.times(factor) != Qt.vector4d(2.23, 4.46, 6.69, 8.92)) success = false;
+        if (v1.plus(v2) != Qt.vector4d(6, 8, 10, 12)) success = false;
+        if (v2.minus(v1) != Qt.vector4d(4, 4, 4, 4)) success = false;
+        if (!v1.normalized().fuzzyEquals(Qt.vector4d(0.182574, 0.365148, 0.547723, 0.730297), 0.00001)) success = false;
+        if ((v1.length() == v2.length()) || (v1.length() != Qt.vector4d(4,3,2,1).length())) success = false;
+        if (v1.toVector2d() != Qt.vector2d(1,2)) success = false;
+        if (v1.toVector3d() != Qt.vector3d(1,2,3)) success = false;
+        if (v1.fuzzyEquals(v2)) success = false;
+        if (!v1.fuzzyEquals(v2, 4)) success = false;
+    }
+}
index a323db5..cf8eb34 100644 (file)
@@ -303,8 +303,6 @@ void tst_qqmlvaluetypes::variant()
     }
 
     {
-    QString w1 = testFileUrl("variant_write.1.qml").toString() + QLatin1String(":9: TypeError: Object QVector2D(8, 2) has no method 'plus'");
-    QTest::ignoreMessage(QtWarningMsg, qPrintable(w1));
     QQmlComponent component(&engine, testFileUrl("variant_write.1.qml"));
     QObject *object = component.create();
     QVERIFY(object != 0);
@@ -502,6 +500,14 @@ void tst_qqmlvaluetypes::vector2d()
 
         delete object;
     }
+
+    {
+        QQmlComponent component(&engine, testFileUrl("vector2d_invokables.qml"));
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        QVERIFY(object->property("success").toBool());
+        delete object;
+    }
 }
 
 void tst_qqmlvaluetypes::vector3d()
@@ -547,6 +553,14 @@ void tst_qqmlvaluetypes::vector3d()
 
         delete object;
     }
+
+    {
+        QQmlComponent component(&engine, testFileUrl("vector3d_invokables.qml"));
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        QVERIFY(object->property("success").toBool());
+        delete object;
+    }
 }
 
 void tst_qqmlvaluetypes::vector4d()
@@ -592,6 +606,14 @@ void tst_qqmlvaluetypes::vector4d()
 
         delete object;
     }
+
+    {
+        QQmlComponent component(&engine, testFileUrl("vector4d_invokables.qml"));
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        QVERIFY(object->property("success").toBool());
+        delete object;
+    }
 }
 
 void tst_qqmlvaluetypes::quaternion()
@@ -701,6 +723,14 @@ void tst_qqmlvaluetypes::matrix4x4()
 
         delete object;
     }
+
+    {
+        QQmlComponent component(&engine, testFileUrl("matrix4x4_invokables.qml"));
+        QObject *object = component.create();
+        QVERIFY(object != 0);
+        QCOMPARE(object->property("success").toBool(), true);
+        delete object;
+    }
 }
 
 void tst_qqmlvaluetypes::font()