diff options
| author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2025-06-11 11:06:31 +0200 |
|---|---|---|
| committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2025-06-17 12:04:42 +0200 |
| commit | 4aa48368667bee64e48f7c9d6b3a935411d5f23c (patch) | |
| tree | c19be3cd8624322bcee32272f1d4d410218e6abf /sources/pyside6/libpyside/pysideqenum.cpp | |
| parent | 7ae471b49d0f38d7ac1c367bcfa3378f309c6b94 (diff) | |
Enable using @QEnum/@QFlag-decorated enums as custom widget properties
Create a dynamic QMetaType for @QEnum-decorated enumerations so that Qt
Widgets Designer is able to recognize the properties.
[ChangeLog][PySide6] It is now possible to use @QEnum/@QFlag-decorated
enumerations as properties of custom widgets in Qt Widgets Designer.
Task-number: PYSIDE-2840
Change-Id: I58a16002f89678856b7f33d687cf99f00c6f0cc7
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/pyside6/libpyside/pysideqenum.cpp')
| -rw-r--r-- | sources/pyside6/libpyside/pysideqenum.cpp | 108 |
1 files changed, 107 insertions, 1 deletions
diff --git a/sources/pyside6/libpyside/pysideqenum.cpp b/sources/pyside6/libpyside/pysideqenum.cpp index 8fc33d5db..70dd1d6da 100644 --- a/sources/pyside6/libpyside/pysideqenum.cpp +++ b/sources/pyside6/libpyside/pysideqenum.cpp @@ -4,6 +4,7 @@ #include "pysideqenum.h" #include <autodecref.h> +#include <sbkconverter.h> #include <sbkenum.h> #include <sbkstaticstrings.h> #include <sbkstring.h> @@ -11,6 +12,8 @@ #include <map> #include <QtCore/qmetatype.h> +#include <QtCore/qdebug.h> +#include <QtCore/qlist.h> /////////////////////////////////////////////////////////////// // @@ -101,6 +104,59 @@ static bool is_module_code() } // extern "C" +// Helper code for dynamically creating QMetaType's for @QEnum + +template <class UnderlyingInt> +static void defaultCtr(const QtPrivate::QMetaTypeInterface *, void *addr) +{ + auto *i = reinterpret_cast<UnderlyingInt *>(addr); + *i = 0; +} + +template <class UnderlyingInt> +static void debugOp(const QtPrivate::QMetaTypeInterface *mti, QDebug &debug, const void *addr) +{ + const auto value = *reinterpret_cast<const UnderlyingInt *>(addr); + QDebugStateSaver saver(debug); + debug << mti->name << '('; + if constexpr (std::is_unsigned<UnderlyingInt>()) { + debug << Qt::showbase << Qt::hex; + } else { + if (value >= 0) + debug << Qt::showbase << Qt::hex; + } + debug << value << ')'; +} + +template <class UnderlyingInt> +QMetaType createEnumMetaTypeHelper(const QByteArray &name) +{ + auto *mti = new QtPrivate::QMetaTypeInterface { + 1, // revision + ushort(std::alignment_of<UnderlyingInt>()), + sizeof(UnderlyingInt), + uint(QMetaType::fromType<UnderlyingInt>().flags() | QMetaType::IsEnumeration), + {}, // typeId + nullptr, // metaObjectFn + qstrdup(name.constData()), + defaultCtr<UnderlyingInt>, + nullptr, // copyCtr + nullptr, // moveCtr + nullptr, // dtor + QtPrivate::QEqualityOperatorForType<UnderlyingInt>::equals, + QtPrivate::QLessThanOperatorForType<UnderlyingInt>::lessThan, + debugOp<UnderlyingInt>, + nullptr, // dataStreamOut + nullptr, // dataStreamIn + nullptr // legacyRegisterOp + }; + + QMetaType metaType(mti); + + metaType.id(); // enforce registration + return metaType; +} + namespace PySide::QEnum { static std::map<int, PyObject *> enumCollector; @@ -210,7 +266,57 @@ QByteArray getTypeName(PyTypeObject *type) ? result : QByteArray{}; } -} // namespace Shiboken::Enum +using GenericEnumType = int; + +using GenericEnumTypeList = QList<PyTypeObject *>; + +Q_GLOBAL_STATIC(GenericEnumTypeList, genericEnumTypeList) + +} // namespace PySide::QEnum + +extern "C" +{ + +static void genericEnumPythonToCpp(PyObject *pyIn, void *cppOut) +{ + const auto value = static_cast<PySide::QEnum::GenericEnumType>(Shiboken::Enum::getValue(pyIn)); + *reinterpret_cast<int *>(cppOut) = value; +} + +static PythonToCppFunc isGenericEnumToCppConvertible(PyObject *pyIn) +{ + + if (PySide::QEnum::genericEnumTypeList()->contains(Py_TYPE(pyIn))) + return genericEnumPythonToCpp; + return {}; +} + +static PyObject *genericEnumCppToPython(PyTypeObject *pyType, const void *cppIn) +{ + const auto value = *reinterpret_cast<const PySide::QEnum::GenericEnumType *>(cppIn); + return Shiboken::Enum::newItem(pyType, value); +} + +} // extern "C" + +namespace PySide::QEnum +{ + +QMetaType createGenericEnumMetaType(const QByteArray &name, PyTypeObject *pyType) +{ + SbkConverter *converter = Shiboken::Conversions::createConverter(pyType, + genericEnumCppToPython); + Shiboken::Conversions::addPythonToCppValueConversion(converter, + genericEnumPythonToCpp, + isGenericEnumToCppConvertible); + Shiboken::Conversions::registerConverterName(converter, name.constData()); + Shiboken::Enum::setTypeConverter(pyType, converter, nullptr); + + genericEnumTypeList()->append(pyType); + return createEnumMetaTypeHelper<GenericEnumType>(name); +} + +} // namespace PySide::QEnum // /////////////////////////////////////////////////////////////// |
