Make QColor a value type
authorChris Adams <christopher.adams@nokia.com>
Tue, 2 Aug 2011 23:20:18 +0000 (09:20 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 18 Aug 2011 03:10:14 +0000 (05:10 +0200)
This commit allows direct access to the r, g, b and a components
of a color (in floating point format: 0 <= v <= 1). Since conversion
from color to string is a common operation, this commit also adds
unit tests to ensure that the previous behaviour is maintained in
other cases (comparison with toString value, etc).

Task-number: QTBUG-14731
Change-Id: I87b521dd4f9c1e96dfe5b20cf8053293cb14cfe4
Reviewed-on: http://codereview.qt.nokia.com/2527
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>

src/declarative/qml/qdeclarativevaluetype.cpp
src/declarative/qml/qdeclarativevaluetype_p.h
tests/auto/declarative/qdeclarativevaluetypes/data/color_compare.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativevaluetypes/data/color_read.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativevaluetypes/data/color_write.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativevaluetypes/testtypes.h
tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp

index 4aedf3e..3e77f4b 100644 (file)
@@ -152,6 +152,9 @@ QDeclarativeValueType *QDeclarativeValueTypeFactory::valueType(int t)
     case QVariant::Font:
         rv = new QDeclarativeFontValueType;
         break;
+    case QVariant::Color:
+        rv = new QDeclarativeColorValueType;
+        break;
     default:
         break;
     }
@@ -1143,4 +1146,83 @@ void QDeclarativeFontValueType::setWordSpacing(qreal size)
     font.setWordSpacing(size);
 }
 
+QDeclarativeColorValueType::QDeclarativeColorValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeColorValueType::read(QObject *obj, int idx)
+{
+    void *a[] = { &color, 0 };
+    QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeColorValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+    int status = -1;
+    void *a[] = { &color, 0, &status, &flags };
+    QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeColorValueType::value()
+{
+    return QVariant(color);
+}
+
+void QDeclarativeColorValueType::setValue(QVariant value)
+{
+    color = qvariant_cast<QColor>(value);
+}
+
+QString QDeclarativeColorValueType::toString() const
+{
+    // special case - to maintain behaviour with QtQuick 1.0, we just output normal toString() value.
+    return QVariant(color).toString();
+}
+
+bool QDeclarativeColorValueType::isEqual(const QVariant &value) const
+{
+    return (QVariant(color) == value);
+}
+
+qreal QDeclarativeColorValueType::r() const
+{
+    return color.redF();
+}
+
+qreal QDeclarativeColorValueType::g() const
+{
+    return color.greenF();
+}
+
+qreal QDeclarativeColorValueType::b() const
+{
+    return color.blueF();
+}
+
+qreal QDeclarativeColorValueType::a() const
+{
+    return color.alphaF();
+}
+
+void QDeclarativeColorValueType::setR(qreal r)
+{
+    color.setRedF(r);
+}
+
+void QDeclarativeColorValueType::setG(qreal g)
+{
+    color.setGreenF(g);
+}
+
+void QDeclarativeColorValueType::setB(qreal b)
+{
+    color.setBlueF(b);
+}
+
+void QDeclarativeColorValueType::setA(qreal a)
+{
+    color.setAlphaF(a);
+}
+
 QT_END_NAMESPACE
index 01a1765..03cb83f 100644 (file)
@@ -582,6 +582,36 @@ private:
     mutable QDeclarativeNullableValue<int> dpi;
 };
 
+class Q_AUTOTEST_EXPORT QDeclarativeColorValueType : public QDeclarativeValueType
+{
+    Q_PROPERTY(qreal r READ r WRITE setR)
+    Q_PROPERTY(qreal g READ g WRITE setG)
+    Q_PROPERTY(qreal b READ b WRITE setB)
+    Q_PROPERTY(qreal a READ a WRITE setA)
+    Q_OBJECT
+public:
+    QDeclarativeColorValueType(QObject *parent = 0);
+
+    virtual void read(QObject *, int);
+    virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+    virtual QVariant value();
+    virtual void setValue(QVariant value);
+    virtual QString toString() const;
+    virtual bool isEqual(const QVariant &value) const;
+
+    qreal r() const;
+    qreal g() const;
+    qreal b() const;
+    qreal a() const;
+    void setR(qreal);
+    void setG(qreal);
+    void setB(qreal);
+    void setA(qreal);
+
+private:
+    QColor color;
+};
+
 QT_END_NAMESPACE
 
 #endif  // QDECLARATIVEVALUETYPE_P_H
diff --git a/tests/auto/declarative/qdeclarativevaluetypes/data/color_compare.qml b/tests/auto/declarative/qdeclarativevaluetypes/data/color_compare.qml
new file mode 100644 (file)
index 0000000..8701dae
--- /dev/null
@@ -0,0 +1,37 @@
+import Test 1.0
+
+MyTypeObject {
+    property real v_r: color.r
+    property real v_g: color.g
+    property real v_b: color.b
+    property real v_a: color.a
+    property variant copy: color
+    property string colorToString: color.toString()
+
+    // compare different colors
+    property bool colorEqualsIdenticalRgba: (color == Qt.rgba(0.2, 0.88, 0.6, 0.34))  // true
+    property bool colorEqualsDifferentAlpha: (color == Qt.rgba(0.2, 0.88, 0.6, 0.44)) // false
+    property bool colorEqualsDifferentRgba: (color == Qt.rgba(0.3, 0.98, 0.7, 0.44))  // false
+
+    // compare different color.toString()s
+    property bool colorToStringEqualsColorString: (color.toString() == colorToString)                                     // true
+    property bool colorToStringEqualsDifferentAlphaString: (color.toString() == Qt.rgba(0.2, 0.88, 0.6, 0.44).toString()) // true
+    property bool colorToStringEqualsDifferentRgbaString: (color.toString() == Qt.rgba(0.3, 0.98, 0.7, 0.44).toString())  // false
+
+    // compare colors to strings
+    property bool colorEqualsColorString: (color == colorToString)                                     // false
+    property bool colorEqualsDifferentAlphaString: (color == Qt.rgba(0.2, 0.88, 0.6, 0.44).toString()) // false
+    property bool colorEqualsDifferentRgbaString: (color == Qt.rgba(0.3, 0.98, 0.7, 0.44).toString())  // false
+
+    // compare colors to various value types
+    property bool equalsColor: (color == Qt.rgba(0.2, 0.88, 0.6, 0.34)) // true
+    property bool equalsVector3d: (color == Qt.vector3d(1, 2, 3))       // false
+    property bool equalsSize: (color == Qt.size(1912, 1913))            // false
+    property bool equalsPoint: (color == Qt.point(10, 4))               // false
+    property bool equalsRect: (color == Qt.rect(2, 3, 109, 102))        // false
+
+    // ensure comparison directionality doesn't matter
+    property bool equalsColorRHS: (Qt.rgba(0.2, 0.88, 0.6, 0.34) == color) // true
+    property bool colorEqualsCopy: (color == copy) // true
+    property bool copyEqualsColor: (copy == color) // true
+}
diff --git a/tests/auto/declarative/qdeclarativevaluetypes/data/color_read.qml b/tests/auto/declarative/qdeclarativevaluetypes/data/color_read.qml
new file mode 100644 (file)
index 0000000..bc92b1e
--- /dev/null
@@ -0,0 +1,9 @@
+import Test 1.0
+
+MyTypeObject {
+    property real v_r: color.r
+    property real v_g: color.g
+    property real v_b: color.b
+    property real v_a: color.a
+    property variant copy: color
+}
diff --git a/tests/auto/declarative/qdeclarativevaluetypes/data/color_write.qml b/tests/auto/declarative/qdeclarativevaluetypes/data/color_write.qml
new file mode 100644 (file)
index 0000000..3f1bad4
--- /dev/null
@@ -0,0 +1,8 @@
+import Test 1.0
+
+MyTypeObject {
+    color.r: if (true) 0.5
+    color.g: if (true) 0.38
+    color.b: if (true) 0.3
+    color.a: if (true) 0.7
+}
index 1efab0c..5eb6bf6 100644 (file)
@@ -54,6 +54,7 @@
 #include <QQuaternion>
 #include <QMatrix4x4>
 #include <QFont>
+#include <QColor>
 #include <qdeclarative.h>
 #include <QDeclarativePropertyValueSource>
 #include <QDeclarativeProperty>
@@ -79,6 +80,7 @@ class MyTypeObject : public QObject
     Q_PROPERTY(QQuaternion quaternion READ quaternion WRITE setQuaternion NOTIFY changed)
     Q_PROPERTY(QMatrix4x4 matrix READ matrix WRITE setMatrix NOTIFY changed)
     Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY changed)
+    Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed)
     Q_PROPERTY(QVariant variant READ variant NOTIFY changed)
 
 public:
@@ -109,6 +111,10 @@ public:
         m_font.setCapitalization(QFont::AllLowercase);
         m_font.setLetterSpacing(QFont::AbsoluteSpacing, 10.2);
         m_font.setWordSpacing(19.7);
+        m_color.setRedF(0.2);
+        m_color.setGreenF(0.88);
+        m_color.setBlueF(0.6);
+        m_color.setAlphaF(0.34);
     }
 
     QPoint m_point;
@@ -171,6 +177,10 @@ public:
     QFont font() const { return m_font; }
     void setFont(const QFont &v) { m_font = v; emit changed(); }
 
+    QColor m_color;
+    QColor color() const { return m_color; }
+    void setColor(const QColor &v) { m_color = v; emit changed(); }
+
     QVariant variant() const { return sizef(); }
 
     void emitRunScript() { emit runScript(); }
index 5869310..89d0e7e 100644 (file)
@@ -77,6 +77,7 @@ private slots:
     void quaternion();
     void matrix4x4();
     void font();
+    void color();
     void variant();
 
     void bindingAssignment();
@@ -807,6 +808,73 @@ void tst_qdeclarativevaluetypes::font()
     }
 }
 
+void tst_qdeclarativevaluetypes::color()
+{
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("color_read.qml"));
+        MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+        QVERIFY(object != 0);
+
+        QCOMPARE((float)object->property("v_r").toDouble(), (float)0.2);
+        QCOMPARE((float)object->property("v_g").toDouble(), (float)0.88);
+        QCOMPARE((float)object->property("v_b").toDouble(), (float)0.6);
+        QCOMPARE((float)object->property("v_a").toDouble(), (float)0.34);
+        QColor comparison;
+        comparison.setRedF(0.2);
+        comparison.setGreenF(0.88);
+        comparison.setBlueF(0.6);
+        comparison.setAlphaF(0.34);
+        QCOMPARE(object->property("copy"), QVariant(comparison));
+
+        delete object;
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("color_write.qml"));
+        MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+        QVERIFY(object != 0);
+
+        QColor newColor;
+        newColor.setRedF(0.5);
+        newColor.setGreenF(0.38);
+        newColor.setBlueF(0.3);
+        newColor.setAlphaF(0.7);
+        QCOMPARE(object->color(), newColor);
+
+        delete object;
+    }
+
+    {
+        QDeclarativeComponent component(&engine, TEST_FILE("color_compare.qml"));
+        MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+        QVERIFY(object != 0);
+        QString colorString("#33e199");
+        QCOMPARE(object->property("colorToString").toString(), colorString);
+        QCOMPARE(object->property("colorEqualsIdenticalRgba").toBool(), true);
+        QCOMPARE(object->property("colorEqualsDifferentAlpha").toBool(), false);
+        QCOMPARE(object->property("colorEqualsDifferentRgba").toBool(), false);
+        QCOMPARE(object->property("colorToStringEqualsColorString").toBool(), true);
+        QCOMPARE(object->property("colorToStringEqualsDifferentAlphaString").toBool(), true);
+        QCOMPARE(object->property("colorToStringEqualsDifferentRgbaString").toBool(), false);
+        QCOMPARE(object->property("colorEqualsColorString").toBool(), true);          // maintaining behaviour with QtQuick 1.0
+        QCOMPARE(object->property("colorEqualsDifferentAlphaString").toBool(), true); // maintaining behaviour with QtQuick 1.0
+        QCOMPARE(object->property("colorEqualsDifferentRgbaString").toBool(), false);
+
+        QCOMPARE(object->property("equalsColor").toBool(), true);
+        QCOMPARE(object->property("equalsVector3d").toBool(), false);
+        QCOMPARE(object->property("equalsSize").toBool(), false);
+        QCOMPARE(object->property("equalsPoint").toBool(), false);
+        QCOMPARE(object->property("equalsRect").toBool(), false);
+
+        // Color == Property and Property == Color should return the same result.
+        QCOMPARE(object->property("equalsColorRHS").toBool(), object->property("equalsColor").toBool());
+        QCOMPARE(object->property("colorEqualsCopy").toBool(), true);
+        QCOMPARE(object->property("copyEqualsColor").toBool(), object->property("colorEqualsCopy").toBool());
+
+        delete object;
+    }
+}
+
 // Test bindings can write to value types
 void tst_qdeclarativevaluetypes::bindingAssignment()
 {