From c521178769cbcad572f6cffb1a92867cc8e295f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Mon, 15 Jun 2020 22:48:21 +0200 Subject: [PATCH] Update for new organizer callbacks. --- src/runner/converters.h | 86 ++++++++++++++++++++++++++++++------- src/runner/pythonrunner.cpp | 15 ++++--- 2 files changed, 80 insertions(+), 21 deletions(-) diff --git a/src/runner/converters.h b/src/runner/converters.h index 8419e81..ea7ffd2 100644 --- a/src/runner/converters.h +++ b/src/runner/converters.h @@ -196,6 +196,7 @@ namespace utils { template <> struct MetaData { static const char* className() { return "QObject"; } }; template <> struct MetaData { static const char* className() { return "QWidget"; } }; + template <> struct MetaData { static const char* className() { return "QMainWindow"; } }; template <> struct MetaData { static const char* className() { return "QDateTime"; } }; template <> struct MetaData { static const char* className() { return "QDir"; } }; template <> struct MetaData { static const char* className() { return "QFileInfo"; } }; @@ -295,8 +296,9 @@ namespace utils { } - namespace { - bool has_arity(PyObject* object, std::size_t arity) { + namespace details { + + inline bool has_arity(PyObject* object, std::size_t arity) { // Mostly from https://stackoverflow.com/a/36143796/2666289 bpy::object fn(bpy::handle<>(bpy::borrowed(object))); @@ -318,18 +320,55 @@ namespace utils { return required_count <= arity // Cannot require more parameters than given, && (args_count >= arity || varargs); // Must accept enough parameters. } + + template + struct wrap_impl; + + template <> + struct wrap_impl<> { + template + static decltype(auto) apply(T&& t) { return std::forward(t); } + }; + + template + struct wrap_impl, Ws... > { + static auto apply(T t) { + return boost::ref(t); + } + }; + + template + struct wrap_impl, Ws... > { + static auto apply(T t) { + return bpy::ptr(t); + } + }; + + template + struct wrap_impl { + template + static decltype(auto) apply(T&& t) { + return wrap::apply(std::forward(t)); + } + }; + } /** * @brief Convert a python callable to a valid C++ Callable object. Also works * for None. */ - template + template struct Functor_converter; - template - struct Functor_converter + template + struct Functor_converter { + + template + static decltype(auto) wrap(T&& t) { + return details::wrap_impl::apply(std::forward(t)); + } struct FunctorWrapper { @@ -341,13 +380,21 @@ namespace utils { m_Callable = bpy::object(); } - RET operator()(const PARAMS&...params) { + R operator()(Args... params) { GILock lock; - if constexpr (std::is_same_v) { - m_Callable(params...); + try { + if constexpr (std::is_same_v) { + m_Callable(wrap(params)... ); + } + else { + return bpy::extract(m_Callable(wrap(params)... )); + } } - else { - return bpy::extract(m_Callable(params...)); + catch (const boost::python::error_already_set&) { + throw pyexcept::PythonError(); + } + catch (...) { + throw pyexcept::UnknownException(); } } @@ -362,7 +409,7 @@ namespace utils { } // Otherwize we check that we have a callable object: - if (!PyCallable_Check(object) || !has_arity(object, sizeof...(PARAMS))) { + if (!PyCallable_Check(object) || !details::has_arity(object, sizeof...(Args))) { return nullptr; } return object; @@ -371,12 +418,12 @@ namespace utils { static void construct(PyObject* object, bpy::converter::rvalue_from_python_stage1_data* data) { bpy::object callable(bpy::handle<>(bpy::borrowed(object))); - void* storage =((bpy::converter::rvalue_from_python_storage>*)data)->storage.bytes; + void* storage =((bpy::converter::rvalue_from_python_storage>*)data)->storage.bytes; if (callable.is_none()) { - new (storage) std::function{}; + new (storage) std::function{}; } else { - new (storage) std::function(FunctorWrapper(callable)); + new (storage) std::function(FunctorWrapper(callable)); } data->convertible = storage; } @@ -466,9 +513,16 @@ namespace utils { bpy::to_python_converter(); } - template + /** + * @brief Register a functor converter. + * + * @tparam Fn The function type to register. + * @tparam Wrappers... A list of wrapper (boost::python::pointer_wrapper or boost::reference_wrapper) + * indicating if parameters of the given (wrapped) type must be wrapped. + */ + template inline void register_functor_converter() { - using Converter = Functor_converter; + using Converter = Functor_converter; bpy::converter::registry::push_back( &Converter::convertible, &Converter::construct, diff --git a/src/runner/pythonrunner.cpp b/src/runner/pythonrunner.cpp index a61d780..fed5cd7 100644 --- a/src/runner/pythonrunner.cpp +++ b/src/runner/pythonrunner.cpp @@ -75,6 +75,7 @@ BOOST_PYTHON_MODULE(mobase) utils::register_qclass_converter(); utils::register_qclass_converter(); utils::register_qclass_converter(); + utils::register_qclass_converter(); utils::register_qclass_converter(); utils::register_qclass_converter(); utils::register_qclass_converter(); @@ -130,6 +131,9 @@ BOOST_PYTHON_MODULE(mobase) utils::register_functor_converter(); utils::register_functor_converter(); utils::register_functor_converter(); // converter for the onModStateChanged-callback + utils::register_functor_converter(); + utils::register_functor_converter>(); + utils::register_functor_converter(); utils::register_functor_converter(); utils::register_functor_converter(); utils::register_functor_converter const&)>(); @@ -292,15 +296,16 @@ BOOST_PYTHON_MODULE(mobase) bool result = o->waitForApplication((HANDLE)handle, &returnCode); return std::make_tuple(result, returnCode); }) + .def("refreshModList", &IOrganizer::refreshModList, (bpy::arg("save_changes") = true)) + .def("managedGame", &IOrganizer::managedGame, bpy::return_value_policy()) + .def("modsSortedByProfilePriority", &IOrganizer::modsSortedByProfilePriority) .def("onModInstalled", &IOrganizer::onModInstalled) .def("onAboutToRun", &IOrganizer::onAboutToRun) .def("onFinishedRun", &IOrganizer::onFinishedRun) - .def("refreshModList", &IOrganizer::refreshModList, (bpy::arg("save_changes")=true)) - .def("managedGame", &IOrganizer::managedGame, bpy::return_value_policy()) - .def("modsSortedByProfilePriority", &IOrganizer::modsSortedByProfilePriority) - - Q_DELEGATE(IOrganizer, QObject, "_object") + .def("onUserInterfaceInitialized", &IOrganizer::onUserInterfaceInitialized) + .def("onProfileChanged", &IOrganizer::onProfileChanged) + .def("onPluginSettingChanged", &IOrganizer::onPluginSettingChanged) ; // FileTreeEntry Scope: