aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Adams <christopher.adams@nokia.com>2012-07-16 16:32:49 +1000
committerQt by Nokia <qt-info@nokia.com>2012-08-09 07:58:06 +0200
commit42f9444e983b5257241c17242471ca63f208c3f6 (patch)
tree4847ae743a0e05b0ff9d3d4ab6003ea257a6c682
parentf09517bd9c907698a05ee92ccf158a06db3340b8 (diff)
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 <martin.jones@nokia.com>
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp10
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp38
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper.cpp15
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc511
-rw-r--r--src/quick/util/qquickglobal.cpp22
-rw-r--r--src/quick/util/qquickvaluetypes.cpp309
-rw-r--r--src/quick/util/qquickvaluetypes_p.h60
-rw-r--r--tests/auto/qml/qqmlvaluetypeproviders/data/invokableFunctions.qml52
-rw-r--r--tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp14
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml31
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/vector2d_invokables.qml23
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/vector3d_invokables.qml25
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/vector4d_invokables.qml25
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp34
14 files changed, 1138 insertions, 31 deletions
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index ef1f3ea597..c8508e7ecd 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -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();
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
index 01ab252d7b..bee176f829 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -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:");
diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp
index cf6c530f5b..fe58546522 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<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; \
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index 241a59a92b..40191671bb 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 1708cf7331..3d27e832ee 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<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],
diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp
index 4224847311..c0f7e62c15 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<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),
diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h
index d2767db329..09c91d3bdf 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<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
index 0000000000..85e87e91cf
--- /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 d811767489..20cc93bb7b 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 0000000000..aa26956922
--- /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 0000000000..9f84a50950
--- /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 0000000000..48185f9089
--- /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 0000000000..c80ee0dc54
--- /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 a323db5d5f..cf8eb34fd6 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()