diff options
author | Lars Knoll <lars.knoll@qt.io> | 2020-08-25 12:28:11 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2020-09-02 22:44:29 +0200 |
commit | 918c61f275e8a9b46459f425df3b69961955a81d (patch) | |
tree | ee030bc5aaeda50650c5d3bf4486780e6e9405d5 /src/corelib | |
parent | 1e1b88809261854dee47c9bc105cf71e75b75cb9 (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/corelib')
-rw-r--r-- | src/corelib/kernel/qproperty.h | 76 |
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 |