summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Strømme <christian.stromme@qt.io>2018-08-20 15:29:41 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2018-08-28 13:01:30 +0000
commit29f22c2e0444f00c62667437c64ccceb85d2951a (patch)
treedca463f124f68369dddc8c31338ae9e531bb9319
parent7aed790d66a468dbd5c58813fafe1cef2630333b (diff)
Add infrastructure to connect properties from Quick API to the Q3DS API
Removes the syncProperties() function, as it's strictly not needed anymore. If there's a need to intercept one or more property change, two different options are provided: 1. Add a property on the target object that is prefixed with "qq_" or 2. Re-implement the propertChanged() function. Change-Id: If2ef181f09f17916b0d2d9606663175958e46e77 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r--src/runtime/aping/q3dsgroup3d.cpp9
-rw-r--r--src/runtime/aping/q3dsgroup3d_p.h1
-rw-r--r--src/runtime/aping/q3dslayer3d.cpp7
-rw-r--r--src/runtime/aping/q3dslayer3d_p.h2
-rw-r--r--src/runtime/aping/q3dsnode3d.cpp7
-rw-r--r--src/runtime/aping/q3dsnode3d_p.h2
-rw-r--r--src/runtime/aping/q3dsobject3d.cpp39
-rw-r--r--src/runtime/aping/q3dsobject3d_p.h85
-rw-r--r--src/runtime/q3dsuippresentation.cpp7
9 files changed, 129 insertions, 30 deletions
diff --git a/src/runtime/aping/q3dsgroup3d.cpp b/src/runtime/aping/q3dsgroup3d.cpp
index 98f83fe..76d45a3 100644
--- a/src/runtime/aping/q3dsgroup3d.cpp
+++ b/src/runtime/aping/q3dsgroup3d.cpp
@@ -58,16 +58,7 @@ Q3DSGraphObject *Q3DSGroup3D::createObject(Q3DSUipPresentation *presentation)
Q3DSGraphObject *obj = presentation->newObject<Q3DSGroupNode>(id);
obj->setName(QString::fromLatin1(id));
- syncProperties();
-
return obj;
}
-void Q3DSGroup3D::syncProperties()
-{
- Q3DSNode3D::syncProperties();
-
- // ###
-}
-
QT_END_NAMESPACE
diff --git a/src/runtime/aping/q3dsgroup3d_p.h b/src/runtime/aping/q3dsgroup3d_p.h
index 506b08d..de8f3f4 100644
--- a/src/runtime/aping/q3dsgroup3d_p.h
+++ b/src/runtime/aping/q3dsgroup3d_p.h
@@ -56,7 +56,6 @@ public:
Q3DSGroupNode *groupNode() const { return static_cast<Q3DSGroupNode *>(object()); }
Q3DSGraphObject *createObject(Q3DSUipPresentation *presentation) override;
- void syncProperties() override;
};
QT_END_NAMESPACE
diff --git a/src/runtime/aping/q3dslayer3d.cpp b/src/runtime/aping/q3dslayer3d.cpp
index e783198..50f9eb4 100644
--- a/src/runtime/aping/q3dslayer3d.cpp
+++ b/src/runtime/aping/q3dslayer3d.cpp
@@ -243,8 +243,6 @@ void Q3DSLayer3D::sync()
m_engine->handleViewGeometryChange(this, sz);
}
- syncProperties();
-
// Notify the waiting Object3D, if there is one, to create its subtree
// and parent it to our m_layer3DS.
emit layerNodeCreated();
@@ -380,9 +378,4 @@ void Q3DSLayer3D::touchEvent(QTouchEvent *event)
m_engine->engine()->handleTouchEvent(event, m_layer3DS);
}
-void Q3DSLayer3D::syncProperties()
-{
- // ###
-}
-
QT_END_NAMESPACE
diff --git a/src/runtime/aping/q3dslayer3d_p.h b/src/runtime/aping/q3dslayer3d_p.h
index 571a83e..f1f43bb 100644
--- a/src/runtime/aping/q3dslayer3d_p.h
+++ b/src/runtime/aping/q3dslayer3d_p.h
@@ -78,8 +78,6 @@ public:
bool isLive() const { return layerNode() && presentation(); }
- void syncProperties();
-
signals:
void engineChanged();
void layerNodeCreated();
diff --git a/src/runtime/aping/q3dsnode3d.cpp b/src/runtime/aping/q3dsnode3d.cpp
index 58873c3..a885491 100644
--- a/src/runtime/aping/q3dsnode3d.cpp
+++ b/src/runtime/aping/q3dsnode3d.cpp
@@ -50,11 +50,4 @@ Q3DSNode3D::~Q3DSNode3D()
{
}
-void Q3DSNode3D::syncProperties()
-{
- Q3DSObject3D::syncProperties();
-
- // ###
-}
-
QT_END_NAMESPACE
diff --git a/src/runtime/aping/q3dsnode3d_p.h b/src/runtime/aping/q3dsnode3d_p.h
index 9ec5d77..88e61c8 100644
--- a/src/runtime/aping/q3dsnode3d_p.h
+++ b/src/runtime/aping/q3dsnode3d_p.h
@@ -54,8 +54,6 @@ public:
~Q3DSNode3D();
Q3DSNode *node() const { return static_cast<Q3DSNode *>(object()); }
-
- void syncProperties() override;
};
QT_END_NAMESPACE
diff --git a/src/runtime/aping/q3dsobject3d.cpp b/src/runtime/aping/q3dsobject3d.cpp
index 54dfcd8..256845e 100644
--- a/src/runtime/aping/q3dsobject3d.cpp
+++ b/src/runtime/aping/q3dsobject3d.cpp
@@ -179,6 +179,17 @@ void Q3DSObject3D::activate()
// Connect the object and its children to the Q3DSLayerNode. If that is
// parented to a scene then the subtree becomes alive now.
m_layer->layerNode()->appendChildNode(m_object);
+
+ // Sync the properties and make sure they continue being updated.
+ syncProperties();
+ Q3DSPropertyBinder *binder = nullptr;
+ const QVariant v = property(Q3DSPropertyBinder::binderName());
+ if (v.isValid())
+ binder = v.value<Q3DSPropertyBinder *>();
+
+ if (!binder)
+ binder = new Q3DSPropertyBinder(this);
+ binder->bind(this, m_object);
}
void Q3DSObject3D::setLayer_recursive(Q3DSLayer3D *layer)
@@ -215,9 +226,35 @@ QByteArray Q3DSObject3D::makeIdAndName() const
return id;
}
+void Q3DSObject3D::propertyChanged(const QMetaProperty &sp,
+ Q3DSGraphObject *target,
+ const QMetaProperty &tp)
+{
+ if (!target || !tp.isValid())
+ return;
+
+ const QVariant &v = sp.read(this);
+ if (!tp.writeOnGadget(target, v)) {
+ qWarning("Failed to write property %s on %s", sp.name(), target->id().constData());
+ return;
+ }
+ const QString propName = QString::fromLatin1((!::strncmp(tp.name(), "qq_", 3)) ? tp.name() + 3 : tp.name());
+ target->notifyPropertyChanges({propName, QString()});
+}
+
void Q3DSObject3D::syncProperties()
{
- // ###
+ Q_ASSERT(m_object);
+ // This is a bit crude, but it's only called once, so it's good enough for now.
+ const int propCount = metaObject()->propertyCount();
+ for (int i = 0; i != propCount; ++i) {
+ const auto property = metaObject()->property(i);
+ const QByteArray name = QByteArrayLiteral("qq_") + property.name();
+ int idx = m_object->metaObject()->indexOfProperty(name.constData());
+ if (idx < 0)
+ idx = m_object->metaObject()->indexOfProperty(name.constData() + 3);
+ propertyChanged(property, m_object, (idx >= 0) ? m_object->metaObject()->property(idx) : QMetaProperty());
+ }
}
QT_END_NAMESPACE
diff --git a/src/runtime/aping/q3dsobject3d_p.h b/src/runtime/aping/q3dsobject3d_p.h
index e588fdc..f055cef 100644
--- a/src/runtime/aping/q3dsobject3d_p.h
+++ b/src/runtime/aping/q3dsobject3d_p.h
@@ -58,7 +58,6 @@ public:
~Q3DSObject3D();
virtual Q3DSGraphObject *createObject(Q3DSUipPresentation *presentation) = 0;
- virtual void syncProperties();
Q3DSGraphObject *object() const { return m_object; }
Q3DSLayer3D *layer() const { return m_layer; }
@@ -74,11 +73,15 @@ public:
protected:
void itemChange(ItemChange, const ItemChangeData &) override;
QByteArray makeIdAndName() const;
+ virtual void propertyChanged(const QMetaProperty &sp,
+ Q3DSGraphObject *target,
+ const QMetaProperty &tp);
private:
void activate();
void activate_helper(Q3DSLayer3D *layer);
void setLayer_recursive(Q3DSLayer3D *layer);
+ void syncProperties();
Q3DSGraphObject *m_object = nullptr;
Q3DSLayer3D *m_layer = nullptr;
@@ -87,10 +90,90 @@ private:
QMetaObject::Connection m_layerConn;
friend class Q3DSLayer3D;
+ friend class Q3DSPropertyBinder;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSObject3D::InvalidateFlags)
+class Q3DSPropertyBinder : public QObject
+{
+public:
+ ~Q3DSPropertyBinder() { unbind(); }
+ static QByteArray binderName() { return QByteArrayLiteral("_q3dsbinding"); }
+ static QByteArray propertyPrefix() { return QByteArrayLiteral("qq_"); }
+
+ Q3DSPropertyBinder(QObject *p = nullptr) : QObject(p) {}
+ int qt_metacall(QMetaObject::Call call, int methodId, void **args) override
+ {
+ methodId = QObject::qt_metacall(call, methodId, args);
+ if (methodId < 0)
+ return methodId;
+
+ if (!m_dst || !m_src)
+ return methodId;
+
+ if (call == QMetaObject::InvokeMetaMethod) {
+ QMetaProperty sp = m_src->metaObject()->property(methodId);
+ const int dstIdx = m_propMap[methodId];
+ QMetaProperty tp = (dstIdx >= 0) ? m_dst->metaObject()->property(dstIdx)
+ : QMetaProperty();
+ m_src->propertyChanged(sp, m_dst, tp);
+ return -1;
+ }
+ return methodId;
+ }
+
+ void bind(Q3DSObject3D *src, Q3DSGraphObject *dst)
+ {
+ if (src == m_src && dst == m_dst)
+ return;
+
+ unbind();
+
+ m_src = src;
+ m_src->setProperty(binderName(), QVariant::fromValue(this));
+ m_dst = dst;
+ m_dst->setProperty(binderName(), QVariant::fromValue(this));
+ const int propCount = src->metaObject()->propertyCount();
+ for (int i = 0; i != propCount; ++i) {
+ const auto property = src->metaObject()->property(i);
+ if (!property.hasNotifySignal())
+ continue;
+ const QByteArray name = propertyPrefix() + property.name();
+ int idx = dst->metaObject()->indexOfProperty(name.constData());
+ if (idx < 0)
+ idx = dst->metaObject()->indexOfProperty(name.constData() + 3);
+ m_propMap[i] = idx;
+ QMetaObject::connect(src, property.notifySignalIndex(), this, i + metaObject()->methodCount(), Qt::DirectConnection, nullptr);
+ }
+ }
+
+ Q_INVOKABLE void unbind()
+ {
+ if (m_src) {
+ const QVariant h = m_src->property(binderName());
+ Q_ASSERT(this == h.value<Q3DSPropertyBinder *>());
+ m_src->setProperty(binderName(), QVariant());
+ }
+
+ if (m_dst) {
+ const QVariant h = m_dst->property(binderName());
+ Q_ASSERT(this == h.value<Q3DSPropertyBinder *>());
+ m_dst->setProperty(binderName(), QVariant());
+ }
+
+ disconnect();
+ m_propMap.clear();
+ m_src = nullptr;
+ m_dst = nullptr;
+ }
+
+private:
+ QMap<int, int> m_propMap;
+ Q3DSObject3D *m_src = nullptr;
+ Q3DSGraphObject *m_dst = nullptr;
+};
+
QT_END_NAMESPACE
#endif // Q3DSOBJECT3D_P_H
diff --git a/src/runtime/q3dsuippresentation.cpp b/src/runtime/q3dsuippresentation.cpp
index 23836f0..11c2aa6 100644
--- a/src/runtime/q3dsuippresentation.cpp
+++ b/src/runtime/q3dsuippresentation.cpp
@@ -40,6 +40,7 @@
#include <QtMath>
#include <QImage>
+#include <QtCore/qobject.h>
#include <QtCore/qmetaobject.h>
QT_BEGIN_NAMESPACE
@@ -411,6 +412,12 @@ Q3DSGraphObject::Q3DSGraphObject(Q3DSGraphObject::Type type)
Q3DSGraphObject::~Q3DSGraphObject()
{
+ const QVariant v = property(QByteArrayLiteral("_q3dsbinding"));
+ if (v.isValid()) {
+ QObject *src = v.value<QObject *>();
+ QMetaObject::invokeMethod(src, "unbind", Qt::DirectConnection);
+ }
+
destroyGraph();
delete m_attached;
}