Skip to content

Commit

Permalink
Add extended bindable property classes with convenience functions
Browse files Browse the repository at this point in the history
  • Loading branch information
oblivioncth committed Dec 7, 2024
1 parent b399b6a commit 32aa011
Show file tree
Hide file tree
Showing 3 changed files with 382 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ qx_add_component("Core"
qx-list.h
qx-processbider.h
qx-progressgroup.h
qx-property.h
qx-table.h
qx-threadsafesingleton.h
qx-versionnumber.h
Expand Down Expand Up @@ -99,6 +100,7 @@ qx_add_component("Core"
qx-setonce.dox
qx-table.dox
qx-threadsafesingleton.dox
qx-property.dox
LINKS
PUBLIC
${Qt}::Core
Expand Down
216 changes: 216 additions & 0 deletions lib/core/include/qx/core/qx-property.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
#ifndef QX_PROPERTY_H
#define QX_PROPERTY_H

// Qt Includes
#include <QProperty>
#include <QList>

/* Lots of repetition here that could be avoided using a CRTP class
* that the final Qx derived versions inherit from in addition
* to the originals, but that would make the interface documentation
* much more messy
*/

/*! @cond */
#define QX_OBJECT_BINDABLE_PROPERTY_3(Class, Type, name) \
static constexpr size_t _qx_property_##name##_offset() \
{ \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
return offsetof(Class, name); \
QT_WARNING_POP \
} \
Qx::ObjectBindableProperty<Class, Type, Class::_qx_property_##name##_offset, nullptr> name;

#define QX_OBJECT_BINDABLE_PROPERTY_4(Class, Type, name, Signal) \
static constexpr size_t _qx_property_##name##_offset() \
{ \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
return offsetof(Class, name); \
QT_WARNING_POP \
} \
Qx::ObjectBindableProperty<Class, Type, Class::_qx_property_##name##_offset, Signal> name;

#define QX_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_4(Class, Type, name, value) \
static constexpr size_t _qx_property_##name##_offset() \
{ \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
return offsetof(Class, name); \
QT_WARNING_POP \
} \
Qx::ObjectBindableProperty<Class, Type, Class::_qx_property_##name##_offset, nullptr> name = \
Qx::ObjectBindableProperty<Class, Type, Class::_qx_property_##name##_offset, nullptr>( \
value);

#define QX_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_5(Class, Type, name, valueignal) \
static constexpr size_t _qx_property_##name##_offset() \
{ \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
return offsetof(Class, name); \
QT_WARNING_POP \
} \
Qx::ObjectBindableProperty<Class, Type, Class::_qx_property_##name##_offset, Signal> name = \
Qx::ObjectBindableProperty<Class, Type, Class::_qx_property_##name##_offset, Signal>( \
value);
/*! @endcond */

#define QX_Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...) \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
QT_OVERLOADED_MACRO(QX_OBJECT_BINDABLE_PROPERTY_WITH_ARGS, __VA_ARGS__) \
QT_WARNING_POP

#define QX_Q_OBJECT_BINDABLE_PROPERTY(...) \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
QT_OVERLOADED_MACRO(QX_OBJECT_BINDABLE_PROPERTY, __VA_ARGS__) \
QT_WARNING_POP

#define QX_Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name, ...) \
static constexpr size_t _qx_property_##name##_offset() \
{ \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
return offsetof(Class, name); \
QT_WARNING_POP \
} \
Qx::ObjectComputedProperty<Class, Type, Class::_qx_property_##name##_offset, __VA_ARGS__> name;

namespace Qx
{

template<typename T>
class Property : public QProperty<T>
{
//-Instance Members------------------------------------------------------------------------------------------
private:
QList<QPropertyNotifier> mManagedNotifiers;

//-Constructor----------------------------------------------------------------------------------------------
public:
using QProperty<T>::QProperty;

//-Instance Functions----------------------------------------------------------------------------------------------
public:
template<typename Functor>
QPropertyNotifier addSubscription(Functor f) const
{
f();
return addNotifier(std::forward<Functor>(f));
}

template<typename Functor>
void lifetimeSubscribe(Functor f) const
{
f();
mManagedNotifiers.append(addNotifier(std::forward<Functor>(f)));
}

template<typename Functor>
void lifetimeOnValueChanged(Functor f) const
{
mManagedNotifiers.append(addNotifier(std::forward<Functor>(f)));
}
};

template<typename T>
class Bindable : public QBindable<T>
{
//-Instance Members------------------------------------------------------------------------------------------
private:
QList<QPropertyNotifier> mManagedNotifiers;

//-Constructor----------------------------------------------------------------------------------------------
public:
using QBindable<T>::QBindable;

//-Instance Functions----------------------------------------------------------------------------------------------
public:
template<typename Functor>
QPropertyNotifier addSubscription(Functor f) const
{
f();
return addNotifier(std::forward<Functor>(f));
}

template<typename Functor>
void lifetimeSubscribe(Functor f) const
{
f();
mManagedNotifiers.append(addNotifier(std::forward<Functor>(f)));
}

template<typename Functor>
void lifetimeOnValueChanged(Functor f) const
{
mManagedNotifiers.append(addNotifier(std::forward<Functor>(f)));
}
};

template<typename Class, typename T, auto Offset, auto Signal = nullptr>
class ObjectBindableProperty : public QObjectBindableProperty<Class, T, Offset, Signal>
{
//-Instance Members------------------------------------------------------------------------------------------
private:
QList<QPropertyNotifier> mManagedNotifiers;

//-Constructor----------------------------------------------------------------------------------------------
public:
using QObjectBindableProperty<Class, T, Offset, Signal>::QObjectBindableProperty;

//-Instance Functions----------------------------------------------------------------------------------------------
public:
template<typename Functor>
QPropertyNotifier addSubscription(Functor f) const
{
f();
return addNotifier(std::forward<Functor>(f));
}

template<typename Functor>
void lifetimeSubscribe(Functor f) const
{
f();
mManagedNotifiers.append(addNotifier(std::forward<Functor>(f)));
}

template<typename Functor>
void lifetimeOnValueChanged(Functor f) const
{
mManagedNotifiers.append(addNotifier(std::forward<Functor>(f)));
}
};

template<typename Class, typename T, auto Offset, auto Getter>
class ObjectComputedProperty : public QObjectComputedProperty<Class, T, Offset, Getter>
{
//-Instance Members------------------------------------------------------------------------------------------
private:
QList<QPropertyNotifier> mManagedNotifiers;

//-Constructor----------------------------------------------------------------------------------------------
public:
using QObjectBindableProperty<Class, T, Offset, Getter>::QObjectBindableProperty;

//-Instance Functions----------------------------------------------------------------------------------------------
public:
template<typename Functor>
QPropertyNotifier addSubscription(Functor f) const
{
f();
return addNotifier(std::forward<Functor>(f));
}

template<typename Functor>
void lifetimeSubscribe(Functor f) const
{
f();
mManagedNotifiers.append(addNotifier(std::forward<Functor>(f)));
}

template<typename Functor>
void lifetimeOnValueChanged(Functor f) const
{
mManagedNotifiers.append(addNotifier(std::forward<Functor>(f)));
}
};

}

#endif // QX_PROPERTY_H
164 changes: 164 additions & 0 deletions lib/core/src/qx-property.dox
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*!
* @file qx-property.h
* @ingroup qx-core
*
* @brief The qx-property.h header file provides access to extended bindable property types.
*/

//-Macros----------------------------------------------------------------------------------------------------------
/*!
* @def QX_Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...)
*
* Same as Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS, but uses Qx::ObjectBindableProperty.
*/

/*!
* @def QX_Q_OBJECT_BINDABLE_PROPERTY(...)
*
* Same as Q_OBJECT_BINDABLE_PROPERTY, but uses Qx::ObjectBindableProperty.
*/

/*!
* @def QX_Q_OBJECT_COMPUTED_PROPERTY(...)
*
* Same as Q_OBJECT_COMPUTED_PROPERTY, but uses Qx::ObjectComputedProperty.
*/

namespace Qx
{
//===============================================================================================================
// Property
//===============================================================================================================

/*!
* @class Property qx/core/qx-property.h
* @ingroup qx-core
*
* @brief The Property class extends QProperty<T> with additional convenience functions.
*/

//-Class Functions----------------------------------------------------------------------------------------------
//Public:
/*!
* @fn template<typename Functor> QPropertyNotifier Property::addSubscription(Functor f) const
*
* Equivalent to calling f(), followed by addNotifier(f).
*
* Returns a QPropertyNotifier, which is easier to store than QPropertyChangeHandler since it isn't a template.
*/

/*!
* @fn template<typename Functor> void Property::lifetimeSubscribe(Functor f) const
*
* Same as subscribe(), except that the lifetime of the subscription is tied to the lifetime
* of the property, such that it's canceled when the property is destroyed as does not need to be managed
* by the user.
*/

/*!
* @fn template<typename Functor> void Property::lifetimeOnValueChanged(Functor f) const
*
* Same as onValueChanged(), except that the lifetime of the subscription is tied to the lifetime
* of the property, such that it's canceled when the property is destroyed as does not need to be managed
* by the user.
*/

//===============================================================================================================
// Bindable
//===============================================================================================================

/*!
* @class Bindable qx/core/qx-property.h
* @ingroup qx-core
*
* @brief The Bindable class extends QBindable<T> with additional convenience functions.
*/

//-Class Functions----------------------------------------------------------------------------------------------
//Public:
/*!
* @fn template<typename Functor> QPropertyNotifier Bindable::addSubscription(Functor f) const
*
* @copydoc Property::addSubscription()
*/

/*!
* @fn template<typename Functor> void Bindable::lifetimeSubscribe(Functor f) const
*
* @copydoc Property::lifetimeSubscribe()
*/

/*!
* @fn template<typename Functor> void Bindable::lifetimeOnValueChanged(Functor f) const
*
* @copydoc Property::lifetimeOnValueChanged()
*/

//===============================================================================================================
// ObjectBindableProperty
//===============================================================================================================

/*!
* @class ObjectBindableProperty qx/core/qx-property.h
* @ingroup qx-core
*
* @brief The ObjectBindableProperty class extends QObjectBindableProperty<T> with additional convenience functions.
*
* @note This class should not be instantiated directly, but instead with QX_Q_OBJECT_BINDABLE_PROPERTY()
* or QX_Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS().
*/

//-Class Functions----------------------------------------------------------------------------------------------
//Public:
/*!
* @fn template<typename Functor> QPropertyNotifier ObjectBindableProperty::addSubscription(Functor f) const
*
* @copydoc Property::addSubscription()
*/

/*!
* @fn template<typename Functor> void ObjectBindableProperty::lifetimeSubscribe(Functor f) const
*
* @copydoc Property::lifetimeSubscribe()
*/

/*!
* @fn template<typename Functor> void ObjectBindableProperty::lifetimeOnValueChanged(Functor f) const
*
* @copydoc Property::lifetimeOnValueChanged()
*/

//===============================================================================================================
// ObjectComputedProperty
//===============================================================================================================

/*!
* @class ObjectComputedProperty qx/core/qx-property.h
* @ingroup qx-core
*
* @brief The ObjectComputedProperty class extends QObjectComputedProperty<T> with additional convenience functions.
*
* @note This class should not be instantiated directly, but instead with QX_Q_OBJECT_COMPUTED_PROPERTY().
*/

//-Class Functions----------------------------------------------------------------------------------------------
//Public:
/*!
* @fn template<typename Functor> QPropertyNotifier ObjectComputedProperty::addSubscription(Functor f) const
*
* @copydoc Property::addSubscription()
*/

/*!
* @fn template<typename Functor> void ObjectComputedProperty::lifetimeSubscribe(Functor f) const
*
* @copydoc Property::lifetimeSubscribe()
*/

/*!
* @fn template<typename Functor> void ObjectComputedProperty::lifetimeOnValueChanged(Functor f) const
*
* @copydoc Property::lifetimeOnValueChanged()
*/

}

0 comments on commit 32aa011

Please sign in to comment.