From: Chris Adams Date: Mon, 16 Jul 2012 06:32:49 +0000 (+1000) Subject: Allow invokable functions of value-type classes to be called X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=42f9444e983b5257241c17242471ca63f208c3f6;p=konrad%2Fqtdeclarative.git Allow invokable functions of value-type classes to be called 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 --- diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index ef1f3ea..c8508e7 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -542,7 +542,7 @@ v8::Handle 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 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 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 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 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(); diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index 01ab252..bee176f 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -1552,16 +1552,29 @@ static v8::Handle 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(object); + QVariant valueTypeValue; + if (valueTypeObject) + valueTypeValue = valueTypeObject->value(); + + // Convert all arguments. QVarLengthArray args(argCount + 1); args[0].initAsType(returnType); - for (int ii = 0; ii < argCount; ++ii) args[ii + 1].fromValue(argTypes[ii], engine, callArgs[ii]); - QVarLengthArray 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 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 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 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(object); + QVariant valueTypeValue; + if (valueTypeObject) + valueTypeValue = valueTypeObject->value(); + QQmlPropertyData dummy; const QQmlPropertyData *attempt = &data; @@ -1871,6 +1903,8 @@ static v8::Handle 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:"); diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp index cf6c530..fe58546 100644 --- a/src/qml/qml/v8/qv8valuetypewrapper.cpp +++ b/src/qml/qml/v8/qv8valuetypewrapper.cpp @@ -235,6 +235,9 @@ bool QV8ValueTypeWrapper::isEqual(QV8ObjectResource *r, const QVariant& value) } else { Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy); QV8ValueTypeCopyResource *copy = static_cast(resource); + resource->type->setValue(copy->value); + if (resource->type->isEqual(value)) + return true; return (value == copy->value); } } @@ -260,11 +263,8 @@ v8::Handle QV8ValueTypeWrapper::ToString(const v8::Arguments &args) } else { Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy); QV8ValueTypeCopyResource *copy = static_cast(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 QV8ValueTypeWrapper::Getter(v8::Local property if (!result) return v8::Handle(); + 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; \ diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc index 241a59a..4019167 100644 --- a/src/quick/doc/src/qmltypereference.qdoc +++ b/src/quick/doc/src/qmltypereference.qdoc @@ -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. diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 1708cf7..3d27e83 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -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(argv[0]); + const qreal *sxyz = reinterpret_cast(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(argv[0]); + const qreal *vals = reinterpret_cast(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], diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp index 4224847..c0f7e62 100644 --- a/src/quick/util/qquickvaluetypes.cpp +++ b/src/quick/util/qquickvaluetypes.cpp @@ -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(); + 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(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(); + 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(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(); + 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(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()) + return false; + + QMatrix4x4 otherMatrix = other.value(); + return (v == otherMatrix); + +} QQuickFontValueType::QQuickFontValueType(QObject *parent) : QQmlValueTypeBase(QMetaType::QFont, parent), diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h index d2767db..09c91d3 100644 --- a/src/quick/util/qquickvaluetypes_p.h +++ b/src/quick/util/qquickvaluetypes_p.h @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/invokableFunctions.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/invokableFunctions.qml new file mode 100644 index 0000000..85e87e9 --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypeproviders/data/invokableFunctions.qml @@ -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; + } +} diff --git a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp index d811767..20cc93b 100644 --- a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp +++ b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp @@ -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 index 0000000..aa26956 --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml @@ -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 index 0000000..9f84a50 --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/vector2d_invokables.qml @@ -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 index 0000000..48185f9 --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/vector3d_invokables.qml @@ -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 index 0000000..c80ee0d --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/vector4d_invokables.qml @@ -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; + } +} diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index a323db5..cf8eb34 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -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()