diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2020-03-27 14:02:59 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2020-04-06 14:25:12 +0200 |
commit | 549712830ba6e8cfe603d22a47190b15f60c7072 (patch) | |
tree | f4ce74b351c8b2d58d80b6b611e050498d1eae2c /src/corelib/kernel/qproperty.h | |
parent | bee2bfc6c6b0d075eb4ba5cc2f158b2eabcbcbb6 (diff) |
QProperty: Add support for member function change handlers
When a class has multiple QProperty members to implement functionality,
it is common to have functions in the class that react to changes. For
example to emit a compatibility signal, in case of Qt Quick to mark the
scene graph as dirty, etc. etc.
To faciliate this use-case, this patch adds an internal
QPropertyMemberChangeHandler template that allows connecting a QProperty
field to a member function callback.
At the moment that callback is still 3 * sizeof(pointer). This could in
theory be reduced to 2 by eliminating the back-pointer (prev) as the
observer lives as long as the property. That however belongs into maybe
a future patch.
In order to get a pointer back to the surrounding object that holds the
QProperty as well as provides the callback function, the property system
was changed to pass through the address of the QProperty member at
run-time, and at compile time the delta from the QProperty member to the
beginning of the surrounding class is calculated. Through subtraction we
obtain the pointer to the owning object.
Change-Id: Ia2976357053f474ff44d0d6f60527c3b8e1f613a
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib/kernel/qproperty.h')
-rw-r--r-- | src/corelib/kernel/qproperty.h | 33 |
1 files changed, 28 insertions, 5 deletions
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h index 338c7bbeec..609bb85221 100644 --- a/src/corelib/kernel/qproperty.h +++ b/src/corelib/kernel/qproperty.h @@ -348,7 +348,7 @@ public: private: void notify() { - d.priv.notifyObservers(); + d.priv.notifyObservers(&d); } Q_DISABLE_COPY(QProperty) @@ -403,7 +403,7 @@ public: { setSource(property.d.priv); } protected: - QPropertyObserver(void (*callback)(QPropertyObserver*)); + QPropertyObserver(void (*callback)(QPropertyObserver*, void *)); private: void setSource(QtPrivate::QPropertyBase &property); @@ -415,7 +415,7 @@ private: union { QPropertyBindingPrivate *bindingToMarkDirty = nullptr; - void (*changeHandler)(QPropertyObserver*); + void (*changeHandler)(QPropertyObserver*, void *); }; QPropertyObserver(const QPropertyObserver &) = delete; @@ -434,7 +434,7 @@ class QPropertyChangeHandler : public QPropertyObserver Functor m_handler; public: QPropertyChangeHandler(Functor handler) - : QPropertyObserver([](QPropertyObserver *self) { + : QPropertyObserver([](QPropertyObserver *self, void *) { auto This = static_cast<QPropertyChangeHandler<Functor>*>(self); This->m_handler(); }) @@ -444,7 +444,7 @@ public: template <typename PropertyType> QPropertyChangeHandler(const QProperty<PropertyType> &property, Functor handler) - : QPropertyObserver([](QPropertyObserver *self) { + : QPropertyObserver([](QPropertyObserver *self, void *) { auto This = static_cast<QPropertyChangeHandler<Functor>*>(self); This->m_handler(); }) @@ -475,6 +475,29 @@ QPropertyChangeHandler<Functor> QProperty<T>::subscribe(Functor f) return onValueChanged(f); } +template <auto propertyMember, auto callbackMember> +struct QPropertyMemberChangeHandler; + +template<typename Class, typename PropertyType, PropertyType Class::* PropertyMember, void(Class::*Callback)()> +struct QPropertyMemberChangeHandler<PropertyMember, Callback> : public QPropertyObserver +{ + QPropertyMemberChangeHandler(Class *obj) + : QPropertyObserver(notify) + { + setSource(obj->*PropertyMember); + } + + static void notify(QPropertyObserver *, void *propertyDataPtr) + { + // memberOffset is the offset of the QProperty<> member within the class. We get the absolute address + // of that member and subtracting the relative offset gives us the address of the class instance. + const size_t memberOffset = reinterpret_cast<size_t>(&(static_cast<Class *>(nullptr)->*PropertyMember)); + Class *obj = reinterpret_cast<Class *>(reinterpret_cast<char *>(propertyDataPtr) - memberOffset); + (obj->*Callback)(); + } +}; + + QT_END_NAMESPACE #endif // QPROPERTY_H |