From 4aa48368667bee64e48f7c9d6b3a935411d5f23c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 11 Jun 2025 11:06:31 +0200 Subject: 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 --- sources/pyside6/libpyside/pysideqenum.cpp | 108 +++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) (limited to 'sources/pyside6/libpyside/pysideqenum.cpp') 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 +#include #include #include #include @@ -11,6 +12,8 @@ #include #include +#include +#include /////////////////////////////////////////////////////////////// // @@ -101,6 +104,59 @@ static bool is_module_code() } // extern "C" +// Helper code for dynamically creating QMetaType's for @QEnum + +template +static void defaultCtr(const QtPrivate::QMetaTypeInterface *, void *addr) +{ + auto *i = reinterpret_cast(addr); + *i = 0; +} + +template +static void debugOp(const QtPrivate::QMetaTypeInterface *mti, QDebug &debug, const void *addr) +{ + const auto value = *reinterpret_cast(addr); + QDebugStateSaver saver(debug); + debug << mti->name << '('; + if constexpr (std::is_unsigned()) { + debug << Qt::showbase << Qt::hex; + } else { + if (value >= 0) + debug << Qt::showbase << Qt::hex; + } + debug << value << ')'; +} + +template +QMetaType createEnumMetaTypeHelper(const QByteArray &name) +{ + auto *mti = new QtPrivate::QMetaTypeInterface { + 1, // revision + ushort(std::alignment_of()), + sizeof(UnderlyingInt), + uint(QMetaType::fromType().flags() | QMetaType::IsEnumeration), + {}, // typeId + nullptr, // metaObjectFn + qstrdup(name.constData()), + defaultCtr, + nullptr, // copyCtr + nullptr, // moveCtr + nullptr, // dtor + QtPrivate::QEqualityOperatorForType::equals, + QtPrivate::QLessThanOperatorForType::lessThan, + debugOp, + nullptr, // dataStreamOut + nullptr, // dataStreamIn + nullptr // legacyRegisterOp + }; + + QMetaType metaType(mti); + + metaType.id(); // enforce registration + return metaType; +} + namespace PySide::QEnum { static std::map enumCollector; @@ -210,7 +266,57 @@ QByteArray getTypeName(PyTypeObject *type) ? result : QByteArray{}; } -} // namespace Shiboken::Enum +using GenericEnumType = int; + +using GenericEnumTypeList = QList; + +Q_GLOBAL_STATIC(GenericEnumTypeList, genericEnumTypeList) + +} // namespace PySide::QEnum + +extern "C" +{ + +static void genericEnumPythonToCpp(PyObject *pyIn, void *cppOut) +{ + const auto value = static_cast(Shiboken::Enum::getValue(pyIn)); + *reinterpret_cast(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(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(name); +} + +} // namespace PySide::QEnum // /////////////////////////////////////////////////////////////// -- cgit v1.2.3