From e7019763076cbbe3d52c2a03133c3ded5558f017 Mon Sep 17 00:00:00 2001 From: Nikita Kostovsky Date: Fri, 19 Sep 2025 20:54:13 +0200 Subject: initial commit --- g_property.h | 420 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 g_property.h (limited to 'g_property.h') diff --git a/g_property.h b/g_property.h new file mode 100644 index 0000000..fa743cd --- /dev/null +++ b/g_property.h @@ -0,0 +1,420 @@ +#pragma once + +// qt +#include +#include +#include +#include +#include +#include +#include + +#ifndef STRINGIFY +#define STRINGIFY(var) (#var) +#endif + +class GlobalSettings; +class GlobalSettings : public QSettings +{ + Q_OBJECT + +public: + static QSharedPointer instance(); + +private: + GlobalSettings( + GlobalSettings::Format format, + GlobalSettings::Scope scope, + const QString& organization, + const QString& application = QString() + ); + static QSharedPointer m_instance; +}; + +#define QML_DECLARATION(type, name) \ +protected: \ + Q_PROPERTY( \ + type name READ get_##name WRITE set_##name NOTIFY name##Changed FINAL \ + ) + +#define G_PROPERTY_DECL(type, name) \ +QML_DECLARATION(type, name) protected : type m_##name; + +#define G_PROPERTY_DECL_DEFAULT(type, name, default) \ +QML_DECLARATION(type, name) protected : type m_##name = default; + +#define G_PROPERTY_SIGNAL(type, name) \ +Q_SIGNALS: \ + void name##Changed(); \ + void name##Changed(type value) + +#define G_PROPERTY_GET(type, name) \ +public: \ + Q_INVOKABLE virtual type& get_##name() \ + { \ + return m_##name; \ + } \ + Q_INVOKABLE virtual type get_##name() const \ + { \ + return m_##name; \ + } + +#define G_PROPERTY_GET_DEBUG(type, name) \ +public: \ + virtual type get_##name() const \ + { \ + qDebug() << "PROPERTY: GET" << #name << m_##name; \ + return m_##name; \ + } + +#define G_PROPERTY_SET(type, name) \ +public Q_SLOTS: \ + virtual void set_##name(type a) \ + { \ + if (m_##name == a) \ + return; \ + m_##name = a; \ + emit name##Changed(); \ + emit name##Changed(m_##name); \ + } + +#define G_PROPERTY_SET_DEBUG(type, name) \ +public Q_SLOTS: \ + virtual void set_##name(type a) \ + { \ + DEBUG_INFO("PROPERTY: SET" << #name << a); \ + m_##name = a; \ + emit name##Changed(); \ + emit name##Changed(m_##name); \ + } + +#define G_PROPERTY(type, name) \ + G_PROPERTY_DECL(type, name) \ + G_PROPERTY_SET(type, name) \ + G_PROPERTY_GET(type, name) \ + G_PROPERTY_SIGNAL(type, name) + +#define G_PROPERTY_DEFAULT(type, name, default) \ + G_PROPERTY_DECL_DEFAULT(type, name, default) \ + G_PROPERTY_SET(type, name) \ + G_PROPERTY_GET(type, name) \ + G_PROPERTY_SIGNAL(type, name) + +#define G_PROPERTY_CUSTOM_SET(type, name) \ + G_PROPERTY_DECL(type, name) \ + G_PROPERTY_GET(type, name) \ + G_PROPERTY_SIGNAL(type, name) \ +public Q_SLOTS: \ + virtual void set_##name(type a); + +#define G_PROPERTY_DEBUG(type, name) \ + G_PROPERTY_DECL(type, name) \ + G_PROPERTY_SET_DEBUG(type, name) \ + G_PROPERTY_GET_DEBUG(type, name) \ + G_PROPERTY_SIGNAL(type, name) + +#define PROPERTY(type, name) \ + G_PROPERTY_SET(type, name) \ + G_PROPERTY_GET(type, name) \ + G_PROPERTY_SIGNAL(type, name) + +#define G_PROPERTY_BASE(type, name) \ + G_PROPERTY_DECL(type, name) \ + G_PROPERTY_SIGNAL(type, name) + +#define G_PROPERTY_WRAP(type, name) \ + QML_DECLARATION(type, name) \ +public Q_SLOTS: \ + virtual void set_##name(type a) \ + { \ + *(type*)&name = a; \ + emit name##Changed(); \ + emit name##Changed(name); \ + } \ + \ +public: \ + virtual type get_##name() const \ + { \ + return name; \ + } \ + G_PROPERTY_SIGNAL(type, name) + +#define INI_PROPERTY_SET(type, name) \ +public Q_SLOTS: \ + virtual void set_##name(const type& a) \ + { \ + auto old = get_##name(); \ + if (old == a) \ + { \ + return; \ + } \ + auto n = QString(this->staticMetaObject.className()) + "/" + #name; \ + GlobalSettings::instance()->setValue(n, QVariant::fromValue(a)); \ + GlobalSettings::instance()->sync(); \ + emit name##Changed(); \ + emit name##Changed(a); \ + } + +#define INI_PROPERTY_GET(type, name, defaultValue) \ +public: \ + virtual type get_##name() const \ + { \ + return static_cast( \ + GlobalSettings::instance() \ + ->value( \ + QString(this->staticMetaObject.className()) + "/" + #name, \ + defaultValue \ + ) \ + .value() \ + ); \ + } + +#define INI_PROPERTY_GET_CAST(type, name, defaultValue) \ +public: \ + virtual type get_##name() const \ + { \ + return GlobalSettings::instance()->value( \ + QString(this->staticMetaObject.className()) + "/" + #name, \ + defaultValue \ + ); \ + } + +#define INI_PROPERTY_GET_VAR(type, name, defaultValue) \ +public: \ + virtual type get_##name() \ + { \ + return GlobalSettings::instance() \ + ->value( \ + QString(this->staticMetaObject.className()) + "/" + #name, \ + QVariant::fromValue(defaultValue) \ + ) \ + .value(); \ + } + +#define INI_PROPERTY(type, name, defaultValue) \ + INI_PROPERTY_SET(type, name) \ + INI_PROPERTY_GET(type, name, defaultValue) \ + QML_DECLARATION(type, name) \ + G_PROPERTY_SIGNAL(type, name) + +#define INI_PROPERTY_CAST(type, name, defaultValue) \ + INI_PROPERTY_SET(type, name) \ + INI_PROPERTY_GET_CAST(type, name, defaultValue) \ + QML_DECLARATION(type, name) \ + G_PROPERTY_SIGNAL(type, name) + +#define INI_PROPERTY_VAR(type, name, defaultValue) \ + INI_PROPERTY_SET(type, name) \ + INI_PROPERTY_GET_VAR(type, name, defaultValue) \ + QML_DECLARATION(type, name) \ + G_PROPERTY_SIGNAL(type, name) + +#define INI_PROPERTY_DEBUG(name) \ + INI_PROPERTY_SET(name) \ + INI_PROPERTY_GET(name) \ + QML_DECLARATION(type, name) \ + G_PROPERTY_SIGNAL(type, name) + +#define RO_PROPERTY(type, name, value) \ +protected: \ + Q_PROPERTY(type name READ get_##name NOTIFY name##Changed) \ +public: \ + inline bool get_##name() \ + { \ + return m_##value; \ + } \ +Q_SIGNALS: \ + void name##Changed(); \ + \ +protected: \ + type m_##name; + +#define STATIC_PROPERTY(type, name) \ +public: \ + static inline type get_##name() \ + { \ + return m_##name; \ + } \ + static inline void set_##name(type value) \ + { \ + m_##name = value; \ + } \ + \ +private: \ + static type m_##name + +// there must be QJsonObject json in scope; +// TODO: use QVariant::value() +#define READ_FROM_JSON(type, name, default) \ + set_##name( \ + json[#name] == QJsonValue::Undefined \ + ? default \ + : json[#name].toVariant().value() \ + ) + +#define INIT_FROM_JSON(type, var, default) \ + m_##var( \ + (json.contains(#var)) \ + ? (json[STRINGIFY(var)].toVariant().value()) \ + : (default) \ + ) + +#define INIT_OBJECT_JSON(var, default) \ + m_##var((json.contains(#var)) ? (json[STRINGIFY(var)]) : (default)) + +// for QJsonObject(std::initializer_list > args) +// TODO: make type first argument +#define WRITE_TO_JSON(var, cast) (#var), cast(m_##var) + +#define WRITE_ENUM_TO_JSON(var) (#var), QVariant(m_##var).toJsonValue() + +#define WRITE_ENUM_KEY_TO_JSON(var) \ + (#var), \ + QString( \ + QMetaEnum::fromType().valueToKey(int(m_##var)) \ + ) + +#define WRITE_VARIANT_TO_JSON(var) (#var), QJsonValue::fromVariant(m_##var) + +#define WRITE_ARRAY_TO_JSON(var) (#var), QJsonArray(m_##var) + +#define WRITE_STRINGLIST_TO_JSON(var) \ + (#var), QJsonArray::fromStringList(m_##var) + +#define WRITE_TO_JSON_NO_CAST(var) (#var), (m_##var) + +#define WRITE_PTR_TO_JSON(var) (#var), QJsonObject(*m_##var) + +// without 's' in the end of name please +#define G_QML_LIST_PROPERTY(classname, type, name) \ +protected: \ + Q_PROPERTY( \ + QQmlListProperty name##s READ name##s NOTIFY name##sChanged \ + ) \ +public: \ + QQmlListProperty name##s() \ + { \ + return QQmlListProperty( \ + this, \ + this, \ + &classname ::append_##name, \ + &classname ::name##sCount, \ + &classname ::name, \ + &classname ::clear_##name##s \ + ); \ + } \ + void append_##name(type* item) \ + { \ + m_##name##s.append(item); \ + emit name##sChanged(); \ + emit name##sChanged(m_##name##s); \ + } \ + int name##sCount() const \ + { \ + return m_##name##s.count(); \ + } \ + type* name(int index) const \ + { \ + return m_##name##s.at(index); \ + } \ + void clear_##name##s() \ + { \ + while (!m_##name##s.isEmpty()) \ + { \ + auto tmp = m_##name##s.takeLast(); \ + if (tmp->parent() == this) \ + delete tmp; \ + } \ + emit name##sChanged(); \ + emit name##sChanged(m_##name##s); \ + } \ + inline QList& get_##name##s() \ + { \ + return m_##name##s; \ + } \ +Q_SIGNALS: \ + void name##sChanged(); \ + \ +protected: \ + static void append_##name(QQmlListProperty* list, type* item) \ + { \ + reinterpret_cast(list->data)->append_##name(item); \ + } \ + static int name##sCount(QQmlListProperty* list) \ + { \ + return reinterpret_cast(list->data)->name##sCount(); \ + } \ + static type* name(QQmlListProperty* list, int index) \ + { \ + return reinterpret_cast(list->data)->name(index); \ + } \ + static void clear_##name##s(QQmlListProperty* list) \ + { \ + reinterpret_cast(list->data)->clear_##name##s(); \ + } \ + QList m_##name##s + +#define INIT_FIELD(name) m_##name(name) + +#define INIT_FROM_OTHER(name) m_##name(other.m_##name) + +#define SET_FROM_OTHER(name) set_##name(other.m_##name) + +#define SET_FROM_OTHER_PTR(name) \ + *m_##name = *other.m_##name; \ + emit name##Changed(); \ + emit name##Changed(m_##name) + +#define SET_FROM_JSON(type, name, default) \ + set_##name( \ + json.contains(#name) ? json[#name].toVariant().value() : default \ + ) + +#define SET_FROM_JSON_ENUM_KEY(name, default) \ + set_##name( \ + json.contains(#name) \ + ? (typeof(m_##name))(QMetaEnum::fromType() \ + .keyToValue( \ + json[#name] \ + .toString() \ + .toStdString() \ + .c_str() \ + )) \ + : default \ + ) + +#define COMPARE_WITH_OTHER(name) (get_##name() == other.get_##name()) + +template static QJsonArray listToJson(const QList& list) +{ + QJsonArray result; + + for (const auto& item : list) + { + result << QJsonValue(*item); + } + + return result; +} + +template +static QList listFromJson( + const QJsonArray& array, + QObject* parent = nullptr +) +{ + QList result; + + for (const auto& jsonItem : array) + { + result << new T(jsonItem.toObject(), parent); + } + + return result; +} + +#define INIT_LIST_FROM_JSON(listName, className, parent) \ + m_##listName(listFromJson(json[#listName].toArray(), parent)) + +#define WRITE_LIST_TO_JSON(listName, className) \ + #listName, listToJson(m_##listName) -- cgit v1.2.3-70-g09d2