From 7ee008e150bc5bcf76082d726f719ee0fdfda982 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Wed, 11 Feb 2026 02:37:39 -0600 Subject: Fluorine Manager: full Linux port of Mod Organizer 2 Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 --- .../include/pybind11_qt/details/pybind11_qt_enum.h | 59 ++++++ .../pybind11_qt/details/pybind11_qt_qlist.h | 52 +++++ .../include/pybind11_qt/details/pybind11_qt_qmap.h | 70 +++++++ .../include/pybind11_qt/details/pybind11_qt_sip.h | 221 +++++++++++++++++++++ .../pybind11_qt/details/pybind11_qt_utils.h | 47 +++++ .../pybind11-qt/include/pybind11_qt/pybind11_qt.h | 88 ++++++++ .../include/pybind11_qt/pybind11_qt_basic.h | 36 ++++ .../include/pybind11_qt/pybind11_qt_containers.h | 51 +++++ .../include/pybind11_qt/pybind11_qt_enums.h | 115 +++++++++++ .../include/pybind11_qt/pybind11_qt_holder.h | 59 ++++++ .../include/pybind11_qt/pybind11_qt_objects.h | 62 ++++++ .../include/pybind11_qt/pybind11_qt_qflags.h | 56 ++++++ 12 files changed, 916 insertions(+) create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_enum.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qlist.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qmap.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_sip.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_utils.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_basic.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_containers.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_enums.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_holder.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_objects.h create mode 100644 libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_qflags.h (limited to 'libs/plugin_python/src/pybind11-qt/include') diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_enum.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_enum.h new file mode 100644 index 0000000..45afd0c --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_enum.h @@ -0,0 +1,59 @@ +#ifndef PYTHON_PYBIND11_QT_DETAILS_ENUM_HPP +#define PYTHON_PYBIND11_QT_DETAILS_ENUM_HPP + +#include + +#include + +#include "pybind11_qt_utils.h" + +namespace pybind11::detail::qt { + + // EnumData, with static members (const char[]) + // - package: name of the Python package containing the enum (e.g., + // PyQt6.QtCore) + // - name: full path to the enum, e.g. Qt.QGlobalColor + // + template + struct EnumData; + + // template class for most Qt types that have Python equivalent (QWidget, + // etc.) + // + template + struct qt_enum_caster { + + public: + PYBIND11_TYPE_CASTER(Enum, EnumData::package + const_name(".") + + EnumData::name); + + bool load(pybind11::handle src, bool) + { + if (PyLong_Check(src.ptr())) { + value = static_cast(PyLong_AsLong(src.ptr())); + return true; + } + + auto pyenum = + get_attr_rec(EnumData::package.text, EnumData::name.text); + + if (isinstance(src, pyenum)) { + value = static_cast(src.attr("value").cast()); + return true; + } + + return false; + } + + static pybind11::handle cast(Enum src, + pybind11::return_value_policy /* policy */, + pybind11::handle /* parent */) + { + auto pyenum = + get_attr_rec(EnumData::package.text, EnumData::name.text); + return pyenum(static_cast(src)); + } + }; +} // namespace pybind11::detail::qt + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qlist.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qlist.h new file mode 100644 index 0000000..e640725 --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qlist.h @@ -0,0 +1,52 @@ +#ifndef PYTHON_PYBIND11_QT_DETAILS_QLIST_HPP +#define PYTHON_PYBIND11_QT_DETAILS_QLIST_HPP + +#include +#include + +namespace pybind11::detail::qt { + + // helper class for QList to construct from any proper iterable + // + template + struct qlist_caster { + using value_conv = make_caster; + + bool load(handle src, bool convert) + { + if (!isinstance(src) || isinstance(src) || + isinstance(src)) { + return false; + } + auto s = reinterpret_borrow(src); + value.clear(); + + if (isinstance(src)) { + value.reserve(s.cast().size()); + } + for (auto it : s) { + value_conv conv; + if (!conv.load(it, convert)) { + return false; + } + value.push_back(cast_op(std::move(conv))); + } + return true; + } + + template + static handle cast(T&& src, return_value_policy policy, handle parent) + { + return list_caster, Value>{}.cast(std::forward(src), policy, + parent); + } + + // we type these as "Sequence" even if these can be constructed from Iterable, + // otherwise the return type will be typed as "Iterable" which is problematic + PYBIND11_TYPE_CASTER(Type, const_name("Sequence[") + value_conv::name + + const_name("]")); + }; + +} // namespace pybind11::detail::qt + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qmap.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qmap.h new file mode 100644 index 0000000..ea743b7 --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_qmap.h @@ -0,0 +1,70 @@ +#ifndef PYTHON_PYBIND11_QT_DETAILS_QMAP_HPP +#define PYTHON_PYBIND11_QT_DETAILS_QMAP_HPP + +#include + +namespace pybind11::detail::qt { + + // helper class for QMap because QMap do not follow the standard std:: maps + // interface, for other containers, the pybind11 built-in xxx_caster works + // + // this code is basically a copy/paste from the pybind11 stl stuff with + // minor modifications + // + template + struct qmap_caster { + using key_conv = make_caster; + using value_conv = make_caster; + + bool load(handle src, bool convert) + { + if (!isinstance(src)) { + return false; + } + auto d = reinterpret_borrow(src); + value.clear(); + for (auto it : d) { + key_conv kconv; + value_conv vconv; + if (!kconv.load(it.first.ptr(), convert) || + !vconv.load(it.second.ptr(), convert)) { + return false; + } + value[cast_op(std::move(kconv))] = + cast_op(std::move(vconv)); + } + return true; + } + + template + static handle cast(T&& src, return_value_policy policy, handle parent) + { + dict d; + return_value_policy policy_key = policy; + return_value_policy policy_value = policy; + if (!std::is_lvalue_reference::value) { + policy_key = return_value_policy_override::policy(policy_key); + policy_value = + return_value_policy_override::policy(policy_value); + } + for (auto it = src.begin(); it != src.end(); ++it) { + auto key = reinterpret_steal( + key_conv::cast(forward_like(it.key()), policy_key, parent)); + auto value = reinterpret_steal(value_conv::cast( + forward_like(it.value()), policy_value, parent)); + if (!key || !value) { + return handle(); + } + d[key] = value; + } + return d.release(); + } + + PYBIND11_TYPE_CASTER(Type, const_name("Dict[") + key_conv::name + + const_name(", ") + value_conv::name + + const_name("]")); + }; + +} // namespace pybind11::detail::qt + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_sip.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_sip.h new file mode 100644 index 0000000..556a980 --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_sip.h @@ -0,0 +1,221 @@ +#ifndef PYTHON_PYBIND11_QT_DETAILS_SIP_HPP +#define PYTHON_PYBIND11_QT_DETAILS_SIP_HPP + +#include + +#include + +#include +#include + +#include "../pybind11_qt_holder.h" + +struct _sipTypeDef; +typedef struct _sipTypeDef sipTypeDef; + +struct _sipSimpleWrapper; +typedef struct _sipSimpleWrapper sipSimpleWrapper; + +struct _sipWrapper; +typedef struct _sipWrapper sipWrapper; + +namespace pybind11::detail::qt { + + // helper functions to avoid bringing in this header + namespace sip { + + // extract the underlying data if present from the equivalent PyQt object + void* extract_data(PyObject*); + + const sipTypeDef* api_find_type(const char* type); + int api_can_convert_to_type(PyObject* pyObj, const sipTypeDef* td, int flags); + + void api_transfer_to(PyObject* self, PyObject* owner); + void api_transfer_back(PyObject* self); + PyObject* api_convert_from_type(void* cpp, const sipTypeDef* td, + PyObject* transferObj); + } // namespace sip + + template + struct MetaData; + + template + struct MetaData>> + : MetaData> {}; + + // template class for most Qt types that have Python equivalent (QWidget, + // etc.) + // + template + struct qt_type_caster { + + static constexpr bool is_pointer = std::is_pointer_v; + using pointer = std::conditional_t; + + QClass value; + + public: + static constexpr auto name = MetaData::python_name; + + operator pointer() + { + if constexpr (is_pointer) { + return value; + } + else { + return &value; + } + } + + // pybind11 requires operator T&() & and operator T&&() && but here we want to + // use SFINAE with is_pointer so we need to template the operator + // + // having a template operator U&&() does not work since it will not + // deduce the proper return type for QClass&& or QClass& so we have two separate + // overloads, and in each one, U is actually a reference type (lvalue or rvalue) + // + + template , QClass> && + std::is_lvalue_reference_v && !is_pointer, + int> = 0> + operator U() + { + return value; + } + + template , QClass> && + std::is_rvalue_reference_v && !is_pointer, + int> = 0> + operator U() && + { + return std::move(value); + } + + template + using cast_op_type = + std::conditional_t>; + + bool load(pybind11::handle src, bool) + { + // special check for none for pointer classes + if constexpr (is_pointer) { + if (src.is_none()) { + value = nullptr; + return true; + } + } + + const auto* type = sip::api_find_type(MetaData::class_name); + if (type == nullptr) { + return false; + } + if (!sip::api_can_convert_to_type(src.ptr(), type, 0)) { + return false; + } + + // this would transfer responsibility for deconstructing the + // object to C++, but pybind11 assumes l-value converters (such + // as this) don't do that instead, this should be called within + // the wrappers for functions which return deletable pointers. + // + // sipAPI()->api_transfer_to(objPtr, Py_None); + // + void* const data = sip::extract_data(src.ptr()); + + if (data) { + if constexpr (is_pointer) { + value = reinterpret_cast(data); + + // transfer ownership + sip::api_transfer_to(src.ptr(), Py_None); + + // tie the py::object to the C++ one + new pybind11::detail::qt::qobject_holder_impl(value); + } + else { + value = *reinterpret_cast(data); + } + return true; + } + else { + return false; + } + } + + template < + typename T, + std::enable_if_t>::value, int> = 0> + static handle cast(T* src, return_value_policy policy, handle parent) + { + // note: when QClass is a pointer type, e.g. a QWidget*, T is a + // pointer to pointer, so we can defer to the standard cast() + + if (!src) { + return none().release(); + } + + if (!is_pointer && policy == return_value_policy::take_ownership) { + auto h = cast(std::move(*src), policy, parent); + delete src; + return h; + } + return cast(*src, policy, parent); + } + + static pybind11::handle cast(QClass src, pybind11::return_value_policy policy, + pybind11::handle /* parent */) + { + if constexpr (is_pointer) { + if (!src) { + return none().release(); + } + } + + const sipTypeDef* type = sip::api_find_type(MetaData::class_name); + if (type == nullptr) { + return Py_None; + } + + PyObject* sipObj; + void* sipData; + + if constexpr (is_pointer) { + sipData = src; + } + else if (std::is_copy_assignable_v) { + // we send to SIP a newly allocated object, and transfer the + // owernship to it + sipData = + new QClass(policy == ::pybind11::return_value_policy::take_ownership + ? std::move(src) + : src); + } + else { + sipData = &src; + } + + sipObj = sip::api_convert_from_type(sipData, type, 0); + + if (sipObj == nullptr) { + return Py_None; + } + + // ensure Python deletes the C++ component + if constexpr (!is_pointer) { + sip::api_transfer_back(sipObj); + } + else { + if (policy == return_value_policy::take_ownership) { + sip::api_transfer_back(sipObj); + } + } + + return sipObj; + } + }; + +} // namespace pybind11::detail::qt + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_utils.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_utils.h new file mode 100644 index 0000000..c877c15 --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/details/pybind11_qt_utils.h @@ -0,0 +1,47 @@ +#ifndef PYTHON_PYBIND11_QT_DETAILS_UTILS_HPP +#define PYTHON_PYBIND11_QT_DETAILS_UTILS_HPP + +#include +#include + +#include + +namespace pybind11::detail::qt { + + /** + * @brief Convert a XXX::YYY compile time string to a XXX.YYY compile time + * string. Only one :: is allowed. + * + */ + template + constexpr descr qt_name_cpp2py(const char (&name)[N]) + { + descr res; + for (std::size_t i = 0, j = 0; i < N - 2; ++i) { + + res.text[i] = name[j]; + + if (res.text[i] == ':') { + res.text[i] = '.'; + j += 2; + } + else { + ++j; + } + } + return res; + } + + /** + * @brief Retrieve the class from the given package at the given path + * + * @param package Name of the module. + * @param path Path to the class/object in the module. + * + * @return the object at the given path in the given module + */ + pybind11::object get_attr_rec(std::string_view package, std::string_view path); + +} // namespace pybind11::detail::qt + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt.h new file mode 100644 index 0000000..e803e9f --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt.h @@ -0,0 +1,88 @@ +#ifndef PYTHON_PYBIND11_QT_HPP +#define PYTHON_PYBIND11_QT_HPP + +// this header defines many type casters for Qt types, including: +// - basic Qt types such as QString and QVariant - those do not have PyQt6 equivalent +// - QFlags<> class templates +// - containers such as QList<>, QSet<>, etc., the QList<> casters is more flexible than +// the std::vector<> or std::list<> ones as it accepts any iterable +// - many Qt enumeration types (see pybind11_qt_enums) +// - many Qt classes with PyQt6 equivalent +// - copyable type are copied between Python and C++ +// - non-copyable type (QObject, QWidget, QMainWindow) are always owned by the C++ +// side, even when constructed on the Python side, and owned their corresponding +// Python object, e.g., an instance of a class inheriting QWidget created on the +// Python side can be safely used in C++ since the Python object will be owned by +// the C++ QWidget object +// + +#include "pybind11_qt_basic.h" +#include "pybind11_qt_containers.h" +#include "pybind11_qt_enums.h" +#include "pybind11_qt_holder.h" +#include "pybind11_qt_objects.h" +#include "pybind11_qt_qflags.h" + +namespace pybind11::qt { + + /** + * @brief Tie the lifetime of the Python object to the lifetime of the given + * QObject. + * + * @param owner QObject that will own the python object. + * @param child Python object that the QObject will own. + */ + inline void set_qt_owner(QObject* owner, object child) + { + new detail::qt::qobject_holder_impl{owner, child}; + } + + /** + * @brief Tie the lifetime of the given object to the lifetime of the corresponding + * Python object. + * + * This object must have been created from Python and must inherit QObject. + * + * @param object Object to tie. + */ + template + void set_qt_owner(Class* object) + { + static_assert(std::is_base_of_v); + new detail::qt::qobject_holder_impl{object}; + } + + /** + * @brief Add Qt "delegate" to the given class. + * + * This function defines two methods: __getattr__ and name, where name will + * simply return the PyQtX object as a QClass* object, while __getattr__ + * will delegate to the underlying QClass object when required. + * + * This allow access to Qt interface for object exposed using pybind11 + * (e.g., signals, methods from QObject or QWidget, etc.). + * + * @param pyclass Python class to define the methods on. + * @param name Name of the method to retrieve the underlying object. + * + * @tparam QClass Name of the Qt class, cannot be deduced. + * @tparam Class Class being wrapped, deduced. + * @tparam Args... Arguments of the class template parameters, deduced. + */ + template + auto& add_qt_delegate(pybind11::class_& pyclass, const char* name) + { + return pyclass + .def(name, + [](Class* w) -> QClass* { + return w; + }) + .def( + "__getattr__", +[](Class* w, pybind11::str str) -> pybind11::object { + return pybind11::cast((QClass*)w).attr(str); + }); + } + +} // namespace pybind11::qt + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_basic.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_basic.h new file mode 100644 index 0000000..911de34 --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_basic.h @@ -0,0 +1,36 @@ +#ifndef PYTHON_PYBIND11_QT_BASIC_HPP +#define PYTHON_PYBIND11_QT_BASIC_HPP + +#include +#include + +#include + +namespace pybind11::detail { + + // QString + // + template <> + struct type_caster { + PYBIND11_TYPE_CASTER(QString, const_name("str")); + + bool load(handle src, bool); + + static handle cast(QString src, return_value_policy policy, handle parent); + }; + + // QVariant - this needs to be defined BEFORE QVariantList + // + template <> + struct type_caster { + public: + PYBIND11_TYPE_CASTER(QVariant, const_name("MoVariant")); + + bool load(handle src, bool); + + static handle cast(QVariant var, return_value_policy policy, handle parent); + }; + +} // namespace pybind11::detail + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_containers.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_containers.h new file mode 100644 index 0000000..120b5e8 --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_containers.h @@ -0,0 +1,51 @@ +#ifndef PYTHON_PYBIND11_QT_CONTAINERS_HPP +#define PYTHON_PYBIND11_QT_CONTAINERS_HPP + +#include +#include +#include + +#include +#include + +// this needs to be included here to get proper QVariantList and QVariantMap +#include "details/pybind11_qt_qlist.h" +#include "details/pybind11_qt_qmap.h" +#include "pybind11_qt_basic.h" + +namespace pybind11::detail { + + // QList + // + template + struct type_caster> : qt::qlist_caster, T> {}; + + // QSet + // + template + struct type_caster> : set_caster, T> {}; + + // QMap + // + template + struct type_caster> : qt::qmap_caster, K, V> {}; + + // QStringList + // + template <> + struct type_caster : qt::qlist_caster {}; + + // QVariantList + // + template <> + struct type_caster : qt::qlist_caster {}; + + // QVariantMap + // + template <> + struct type_caster : qt::qmap_caster { + }; + +} // namespace pybind11::detail + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_enums.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_enums.h new file mode 100644 index 0000000..b58cc41 --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_enums.h @@ -0,0 +1,115 @@ +#ifndef PYTHON_PYBIND11_QT_ENUMS_HPP +#define PYTHON_PYBIND11_QT_ENUMS_HPP + +#include +#include + +#include "details/pybind11_qt_enum.h" +#include "details/pybind11_qt_utils.h" + +#define PYQT_ENUM(QPackage, QEnum) \ + namespace pybind11::detail { \ + namespace qt { \ + template <> \ + struct EnumData { \ + constexpr static const auto package = \ + const_name("PyQt6.") + const_name(#QPackage); \ + constexpr static const auto name = qt_name_cpp2py(#QEnum); \ + }; \ + } \ + template <> \ + struct type_caster : qt::qt_enum_caster {}; \ + } + +PYQT_ENUM(QtCore, Qt::AlignmentFlag); +PYQT_ENUM(QtCore, Qt::AnchorPoint); +PYQT_ENUM(QtCore, Qt::ApplicationAttribute); +PYQT_ENUM(QtCore, Qt::ApplicationState); +PYQT_ENUM(QtCore, Qt::ArrowType); +PYQT_ENUM(QtCore, Qt::AspectRatioMode); +PYQT_ENUM(QtCore, Qt::Axis); +PYQT_ENUM(QtCore, Qt::BGMode); +PYQT_ENUM(QtCore, Qt::BrushStyle); +PYQT_ENUM(QtCore, Qt::CaseSensitivity); +PYQT_ENUM(QtCore, Qt::CheckState); +PYQT_ENUM(QtCore, Qt::ChecksumType); +PYQT_ENUM(QtCore, Qt::ClipOperation); +PYQT_ENUM(QtCore, Qt::ConnectionType); +PYQT_ENUM(QtCore, Qt::ContextMenuPolicy); +PYQT_ENUM(QtCore, Qt::CoordinateSystem); +PYQT_ENUM(QtCore, Qt::Corner); +PYQT_ENUM(QtCore, Qt::CursorMoveStyle); +PYQT_ENUM(QtCore, Qt::CursorShape); +PYQT_ENUM(QtCore, Qt::DateFormat); +PYQT_ENUM(QtCore, Qt::DayOfWeek); +PYQT_ENUM(QtCore, Qt::DockWidgetArea); +PYQT_ENUM(QtCore, Qt::DropAction); +PYQT_ENUM(QtCore, Qt::Edge); +PYQT_ENUM(QtCore, Qt::EnterKeyType); +PYQT_ENUM(QtCore, Qt::EventPriority); +PYQT_ENUM(QtCore, Qt::FillRule); +PYQT_ENUM(QtCore, Qt::FindChildOption); +PYQT_ENUM(QtCore, Qt::FocusPolicy); +PYQT_ENUM(QtCore, Qt::FocusReason); +PYQT_ENUM(QtCore, Qt::GestureFlag); +PYQT_ENUM(QtCore, Qt::GestureState); +PYQT_ENUM(QtCore, Qt::GestureType); +PYQT_ENUM(QtCore, Qt::GlobalColor); +PYQT_ENUM(QtCore, Qt::HitTestAccuracy); +PYQT_ENUM(QtCore, Qt::ImageConversionFlag); +PYQT_ENUM(QtCore, Qt::InputMethodHint); +PYQT_ENUM(QtCore, Qt::InputMethodQuery); +PYQT_ENUM(QtCore, Qt::ItemDataRole); +PYQT_ENUM(QtCore, Qt::ItemFlag); +PYQT_ENUM(QtCore, Qt::ItemSelectionMode); +PYQT_ENUM(QtCore, Qt::ItemSelectionOperation); +PYQT_ENUM(QtCore, Qt::Key); +PYQT_ENUM(QtCore, Qt::KeyboardModifier); +PYQT_ENUM(QtCore, Qt::LayoutDirection); +PYQT_ENUM(QtCore, Qt::MaskMode); +PYQT_ENUM(QtCore, Qt::MatchFlag); +PYQT_ENUM(QtCore, Qt::Modifier); +PYQT_ENUM(QtCore, Qt::MouseButton); +PYQT_ENUM(QtCore, Qt::MouseEventFlag); +PYQT_ENUM(QtCore, Qt::MouseEventSource); +PYQT_ENUM(QtCore, Qt::NativeGestureType); +PYQT_ENUM(QtCore, Qt::NavigationMode); +PYQT_ENUM(QtCore, Qt::Orientation); +PYQT_ENUM(QtCore, Qt::PenCapStyle); +PYQT_ENUM(QtCore, Qt::PenJoinStyle); +PYQT_ENUM(QtCore, Qt::PenStyle); +PYQT_ENUM(QtCore, Qt::ScreenOrientation); +PYQT_ENUM(QtCore, Qt::ScrollBarPolicy); +PYQT_ENUM(QtCore, Qt::ScrollPhase); +PYQT_ENUM(QtCore, Qt::ShortcutContext); +PYQT_ENUM(QtCore, Qt::SizeHint); +PYQT_ENUM(QtCore, Qt::SizeMode); +PYQT_ENUM(QtCore, Qt::SortOrder); +PYQT_ENUM(QtCore, Qt::TabFocusBehavior); +PYQT_ENUM(QtCore, Qt::TextElideMode); +PYQT_ENUM(QtCore, Qt::TextFlag); +PYQT_ENUM(QtCore, Qt::TextFormat); +PYQT_ENUM(QtCore, Qt::TextInteractionFlag); +PYQT_ENUM(QtCore, Qt::TileRule); +PYQT_ENUM(QtCore, Qt::TimeSpec); +PYQT_ENUM(QtCore, Qt::TimerType); +PYQT_ENUM(QtCore, Qt::ToolBarArea); +PYQT_ENUM(QtCore, Qt::ToolButtonStyle); +PYQT_ENUM(QtCore, Qt::TransformationMode); +PYQT_ENUM(QtCore, Qt::WhiteSpaceMode); +PYQT_ENUM(QtCore, Qt::WidgetAttribute); +PYQT_ENUM(QtCore, Qt::WindowFrameSection); +PYQT_ENUM(QtCore, Qt::WindowModality); +PYQT_ENUM(QtCore, Qt::WindowState); +PYQT_ENUM(QtCore, Qt::WindowType); + +PYQT_ENUM(QtWidgets, QMessageBox::ButtonRole); +PYQT_ENUM(QtWidgets, QMessageBox::DialogCode); +PYQT_ENUM(QtWidgets, QMessageBox::Icon); +PYQT_ENUM(QtWidgets, QMessageBox::PaintDeviceMetric); +PYQT_ENUM(QtWidgets, QMessageBox::RenderFlag); +PYQT_ENUM(QtWidgets, QMessageBox::StandardButton); + +#undef PYQT_ENUM + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_holder.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_holder.h new file mode 100644 index 0000000..39200d5 --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_holder.h @@ -0,0 +1,59 @@ +#ifndef PYTHON_PYBIND11_QT_HOLDER_HPP +#define PYTHON_PYBIND11_QT_HOLDER_HPP + +#include + +#include + +namespace pybind11::detail::qt { + + class qobject_holder_impl : public QObject { + object p_; + + public: + /** + * @brief Construct a new qobject holder linked to the given QObject and + * maintaining the given python object alive. + * + * @param p Parent of this holder. + * @param o Python object to keep alive. + */ + qobject_holder_impl(QObject* p, object o) : p_{o} { setParent(p); } + + template + qobject_holder_impl(U* p) + : qobject_holder_impl{p, reinterpret_borrow(cast(p))} + { + } + + ~qobject_holder_impl() + { + gil_scoped_acquire s; + p_ = object(); + } + }; + +} // namespace pybind11::detail::qt + +namespace pybind11::qt { + + template + class qobject_holder { + using type = Type; + + type* qobj_; + + public: + qobject_holder(type* qobj) : qobj_{qobj} + { + new detail::qt::qobject_holder_impl(qobj_); + } + + type* get() { return qobj_; } + }; + +} // namespace pybind11::qt + +PYBIND11_DECLARE_HOLDER_TYPE(T, ::pybind11::qt::qobject_holder) + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_objects.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_objects.h new file mode 100644 index 0000000..e16b5ea --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_objects.h @@ -0,0 +1,62 @@ +#ifndef PYTHON_PYBIND11_QT_OBJECTS_HPP +#define PYTHON_PYBIND11_QT_OBJECTS_HPP + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "details/pybind11_qt_sip.h" +#include "details/pybind11_qt_utils.h" + +#define PYQT_CLASS(QModule, QClass) \ + namespace pybind11::detail { \ + namespace qt { \ + template <> \ + struct MetaData { \ + constexpr static const auto class_name = #QClass; \ + constexpr static const auto python_name = \ + const_name("PyQt6.") + const_name(#QModule) + const_name(".") + \ + const_name(#QClass); \ + }; \ + } \ + template <> \ + struct type_caster \ + : std::conditional_t, \ + type_caster_generic, qt::qt_type_caster> {}; \ + template <> \ + struct type_caster \ + : std::conditional_t, \ + qt::qt_type_caster, type_caster> {}; \ + } + +// add declarations below to create bindings - the first argument is simply +// the name of the PyQt6 package containing the class, and is only used for +// the python signature + +PYQT_CLASS(QtCore, QByteArray); +PYQT_CLASS(QtCore, QDateTime); +PYQT_CLASS(QtCore, QDir); +PYQT_CLASS(QtCore, QFileInfo); +PYQT_CLASS(QtCore, QObject); +PYQT_CLASS(QtCore, QSize); +PYQT_CLASS(QtCore, QUrl); + +PYQT_CLASS(QtGui, QColor); +PYQT_CLASS(QtGui, QIcon); +PYQT_CLASS(QtGui, QPixmap); + +PYQT_CLASS(QtWidgets, QMainWindow); +PYQT_CLASS(QtWidgets, QWidget); + +#undef METADATA + +#endif diff --git a/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_qflags.h b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_qflags.h new file mode 100644 index 0000000..f246ed3 --- /dev/null +++ b/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt_qflags.h @@ -0,0 +1,56 @@ +#ifndef PYTHON_PYBIND11_QT_QFLAGS_HPP +#define PYTHON_PYBIND11_QT_QFLAGS_HPP + +#include + +#include + +namespace pybind11::detail { + + // QFlags + // + template + struct type_caster> { + PYBIND11_TYPE_CASTER(QFlags, const_name("QFlags[") + make_caster::name + + const_name("]")); + + /** + * Conversion part 1 (Python->C++): convert a PyObject into a QString + * instance or return false upon failure. The second argument + * indicates whether implicit conversions should be applied. + */ + bool load(handle src, bool) + { + PyObject* tmp = PyNumber_Long(src.ptr()); + + if (!tmp) { + return false; + } + + // we do an intermediate extraction to T but this actually + // can contains multiple values + T flag_value = static_cast(PyLong_AsLong(tmp)); + Py_DECREF(tmp); + + value = QFlags(flag_value); + + return !PyErr_Occurred(); + } + + /** + * Conversion part 2 (C++ -> Python): convert an QString instance into + * a Python object. The second and third arguments are used to + * indicate the return value policy and parent object (for + * ``return_value_policy::reference_internal``) and are generally + * ignored by implicit casters. + */ + static handle cast(QFlags const& src, return_value_policy /* policy */, + handle /* parent */) + { + return PyLong_FromLong(static_cast(src)); + } + }; + +} // namespace pybind11::detail + +#endif -- cgit v1.3.1