summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2020-08-25 12:28:11 +0200
committerLars Knoll <lars.knoll@qt.io>2020-09-02 22:44:29 +0200
commit918c61f275e8a9b46459f425df3b69961955a81d (patch)
treeee030bc5aaeda50650c5d3bf4486780e6e9405d5 /src
parent1e1b88809261854dee47c9bc105cf71e75b75cb9 (diff)
Add support for computed properties
Add a QObjectComputedProperty. This class doesn't store the data itself, instead relies on a getter method to compute it's value. As the property is read-only, one can not bind to it, but it can be used in other property bindings. Change-Id: I0f6bffdd9f80f1d0829826f93a47257f2b3127af Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/kernel/qproperty.h76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h
index c54d99f131..b3f4644031 100644
--- a/src/corelib/kernel/qproperty.h
+++ b/src/corelib/kernel/qproperty.h
@@ -929,6 +929,82 @@ private:
} \
QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, __VA_ARGS__> name;
+template<typename Class, typename T, auto Offset, auto Getter>
+class QObjectComputedProperty : public QUntypedPropertyData
+{
+ Class *owner()
+ {
+ char *that = reinterpret_cast<char *>(this);
+ return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
+ }
+ const Class *owner() const
+ {
+ char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
+ return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
+ }
+public:
+ using value_type = T;
+ using parameter_type = T;
+
+ QObjectComputedProperty() = default;
+
+ parameter_type value() const {
+ qGetBindingStorage(owner())->maybeUpdateBindingAndRegister(this);
+ return (owner()->*Getter)();
+ }
+
+ std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, parameter_type, void>
+ operator->() const
+ {
+ if constexpr (QTypeTraits::is_dereferenceable_v<T>)
+ return value();
+ else
+ return;
+ }
+
+ parameter_type operator*() const
+ {
+ return value();
+ }
+
+ operator parameter_type() const
+ {
+ return value();
+ }
+
+ constexpr bool hasBinding() const { return false; }
+
+ template<typename Functor>
+ QPropertyChangeHandler<Functor> onValueChanged(Functor f)
+ {
+ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
+ return QPropertyChangeHandler<Functor>(*this, f);
+ }
+
+ template<typename Functor>
+ QPropertyChangeHandler<Functor> subscribe(Functor f)
+ {
+ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
+ f();
+ return onValueChanged(f);
+ }
+
+ QtPrivate::QPropertyBindingData &bindingData() const
+ {
+ auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
+ return *storage->bindingData(const_cast<QObjectComputedProperty *>(this), true);
+ }
+private:
+};
+
+#define Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name, ...) \
+ static constexpr size_t _qt_property_##name##_offset() { \
+ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
+ return offsetof(Class, name); \
+ QT_WARNING_POP \
+ } \
+ QObjectComputedProperty<Class, Type, Class::_qt_property_##name##_offset, __VA_ARGS__> name;
+
QT_END_NAMESPACE
#endif // QPROPERTY_H