diff --git a/src/runner/pythonrunner.cpp b/src/runner/pythonrunner.cpp index f898de1..f76fcc2 100644 --- a/src/runner/pythonrunner.cpp +++ b/src/runner/pythonrunner.cpp @@ -166,55 +166,6 @@ struct HANDLE_converters }; -template -struct QMap_converters -{ - struct QMap_to_python - { - static PyObject *convert(const QMap &map) { - bpy::dict result; - QMapIterator iter(map); - while (iter.hasNext()) { - iter.next(); - result[bpy::object(iter.key())] = bpy::object(iter.value()); - } - return bpy::incref(result.ptr()); - } - }; - - struct QMap_from_python - { - QMap_from_python() { - bpy::converter::registry::push_back(&convertible, &construct, bpy::type_id>()); - } - - static void *convertible(PyObject *objPtr) { - return PyDict_Check(objPtr) ? objPtr : nullptr; - } - - static void construct(PyObject *objPtr, bpy::converter::rvalue_from_python_stage1_data *data) { - void *storage = ((bpy::converter::rvalue_from_python_storage>*)data)->storage.bytes; - QMap *result = new (storage) QMap(); - bpy::dict source(bpy::handle<>(bpy::borrowed(objPtr))); - bpy::list keys = source.keys(); - int len = bpy::len(keys); - for (int i = 0; i < len; ++i) { - bpy::object pyKey = keys[i]; - (*result)[bpy::extract(pyKey)] = bpy::extract(source[pyKey]); - } - - data->convertible = storage; - } - }; - - QMap_converters() - { - QMap_from_python(); - bpy::to_python_converter, QMap_to_python >(); - } -}; - - struct QVariant_to_python_obj { static PyObject *convert(const QVariant &var) { @@ -295,76 +246,6 @@ struct QVariant_from_python_obj } }; - -template -struct QList_to_python_list -{ - static PyObject *convert(const QList &list) - { - bpy::list pyList; - - try { - for (const T &item : list) { - pyList.append(item); - } - } catch (const bpy::error_already_set&) { - reportPythonError(); - } - PyObject *res = bpy::incref(pyList.ptr()); - return res; - } -}; - - -template -struct QList_from_python_obj -{ - QList_from_python_obj() { - bpy::converter::registry::push_back( - &convertible, - &construct, - bpy::type_id >()); - } - - static void* convertible(PyObject *objPtr) { - if (PyList_Check(objPtr)) return objPtr; - return nullptr; - } - - static void construct(PyObject *objPtr, bpy::converter::rvalue_from_python_stage1_data *data) { - void *storage = ((bpy::converter::rvalue_from_python_storage >*)data)->storage.bytes; - QList *result = new (storage) QList(); - bpy::list source(bpy::handle<>(bpy::borrowed(objPtr))); - int length = bpy::len(source); - for (int i = 0; i < length; ++i) { - result->append(bpy::extract(source[i])); - } - - data->convertible = storage; - } -}; - - -template -struct std_vector_to_python_list -{ - static PyObject *convert(const std::vector &vector) - { - bpy::list pyList; - - try { - for (const T &item : vector) - pyList.append(item); - } - catch (const bpy::error_already_set&) { - reportPythonError(); - } - - return bpy::incref(pyList.ptr()); - } -}; - - template struct QFlags_from_python_obj { @@ -751,6 +632,48 @@ BOOST_PYTHON_MODULE(mobase) QClass_converters(); QInterface_converters(); + // Pointers: + bpy::register_ptr_to_python>(); + bpy::register_ptr_to_python>(); + bpy::register_ptr_to_python>(); + bpy::register_ptr_to_python>(); + + // Containers: + utils::register_sequence_container>(); + utils::register_sequence_container>(); + utils::register_sequence_container>(); + utils::register_sequence_container>(); + utils::register_sequence_container>(); + utils::register_sequence_container>(); + + utils::register_sequence_container>(); + utils::register_sequence_container>(); + + utils::register_set_container>(); + + utils::register_associative_container>(); + utils::register_associative_container>(); + + utils::register_associative_container(); + + // Tuple: + bpy::register_tuple, QString, int>>(); + + // Variants: + bpy::register_variant, boost::tuple, QString, int>>>(); + bpy::register_variant>(); + bpy::register_variant>(); + + // Functions: + Functor_converter(); // converter for the onRefreshed-callback + Functor_converter(); // converter for the onModStateChanged-callback + Functor_converter(); + Functor_converter(); + Functor_converter(); + Functor_converter(); + Functor_converter(QString const&)>(); + Functor_converter const&)>(); + bpy::def("toPyQt", &toPyQt); bpy::def("toPyQt", &toPyQt); @@ -819,11 +742,6 @@ BOOST_PYTHON_MODULE(mobase) // TODO: ISaveGameInfoWidget bindings - Functor_converter(); - Functor_converter(); - Functor_converter(); - Functor_converter(); - bpy::class_("FileInfo", bpy::init<>()) .def_readwrite("filePath", &IOrganizer::FileInfo::filePath) .def_readwrite("archive", &IOrganizer::FileInfo::archive) @@ -871,15 +789,6 @@ BOOST_PYTHON_MODULE(mobase) .def("modsSortedByProfilePriority", bpy::pure_virtual(&IOrganizer::modsSortedByProfilePriority)) ; - // FileTreeEntry and IFileTree are only managed by shared ptr. - bpy::register_ptr_to_python>(); - bpy::register_ptr_to_python>(); - bpy::register_ptr_to_python>(); - bpy::register_ptr_to_python>(); - - // For removeIf: - Functor_converter const&)>(); - // FileTreeEntry Scope: auto fileTreeEntryClass = bpy::class_("FileTreeEntry", bpy::no_init); { @@ -926,9 +835,6 @@ BOOST_PYTHON_MODULE(mobase) ; } - utils::register_associative_container(); - bpy::register_variant>(); - // IFileTree scope: auto iFileTreeClass = bpy::class_, boost::noncopyable>("IFileTree", bpy::no_init);; { @@ -991,6 +897,16 @@ BOOST_PYTHON_MODULE(mobase) .def("__len__", &IFileTree::size) .def("__bool__", +[](const IFileTree* tree) { return !tree->empty(); }) .def("__repr__", +[](const IFileTree* entry) { return "IFileTree(\"" + entry->name() + "\")"; }) + + .def("makeTree", +[]() -> std::shared_ptr { + struct MyTree : public IFileTree { + MyTree(std::shared_ptr parent = nullptr, QString name = "") : FileTreeEntry(parent, name), IFileTree() { } + protected: + std::shared_ptr makeDirectory(std::shared_ptr p, QString n) const override { return std::make_shared(p, n); } + void doPopulate(std::shared_ptr, std::vector> &) const override { } + }; + return std::make_shared(); + }).staticmethod("makeTree") ; } @@ -1086,10 +1002,6 @@ BOOST_PYTHON_MODULE(mobase) .value("USER", MOBase::GUESS_USER) ; - // For setFilter: - bpy::register_variant>(); - Functor_converter(QString const&)>(); - bpy::class_, boost::noncopyable>("GuessedString") .def(bpy::init<>()) .def(bpy::init()) @@ -1124,21 +1036,13 @@ BOOST_PYTHON_MODULE(mobase) }); }) - // Exposing the set does not work, but even if it worked, we would lose the order since it would be - // converted to a python set() so we expose a custom iterator. This works because variants() returns - // a reference, otherwize this would be more complex to do (also, needs to use references instead of - // pointers instead of the lambda due to the range() requirements): - .def("variants", bpy::range< - bpy::return_value_policy>( - +[](GuessedValue &gv) { return std::begin(gv.variants()); }, - +[](GuessedValue &gv) { return std::end(gv.variants()); } - )) + // This makes a copy in python but it more practical than exposing an iterator: + .def("variants", &GuessedValue::variants, bpy::return_value_policy()) .def("__str__", &MOBase::GuessedValue::operator const QString&, bpy::return_value_policy()) ; bpy::to_python_converter>(); QFlags_from_python_obj(); - Functor_converter(); // converter for the onRefreshed-callback bpy::enum_("PluginState") .value("missing", IPluginList::STATE_MISSING) @@ -1162,7 +1066,6 @@ BOOST_PYTHON_MODULE(mobase) bpy::to_python_converter>(); QFlags_from_python_obj(); - Functor_converter(); // converter for the onModStateChanged-callback bpy::enum_("ModState") .value("exists", IModList::STATE_EXISTS) @@ -1282,8 +1185,6 @@ BOOST_PYTHON_MODULE(mobase) .def("featureUnmanagedMods", &MOBase::IPluginGame::feature, bpy::return_value_policy()) ; - bpy::register_tuple, QString, int>>(); - bpy::register_variant, boost::tuple, QString, int>>>(); bpy::enum_("InstallResult") .value("SUCCESS", MOBase::IPluginInstaller::RESULT_SUCCESS) .value("FAILED", MOBase::IPluginInstaller::RESULT_FAILED) @@ -1319,26 +1220,6 @@ BOOST_PYTHON_MODULE(mobase) HANDLE_converters(); - //bpy::to_python_converter(); - - QList_from_python_obj(); - QList_from_python_obj(); - bpy::to_python_converter, - QList_to_python_list >(); - QList_from_python_obj(); - bpy::to_python_converter, - QList_to_python_list>(); - QList_from_python_obj(); - bpy::to_python_converter, - QList_to_python_list>(); - - QMap_converters(); - QMap_converters(); - - utils::register_sequence_container>(); - utils::register_sequence_container>(); - utils::register_set_container>(); - registerGameFeaturesPythonConverters(); } diff --git a/src/runner/pythonutils.h b/src/runner/pythonutils.h index 3cd85fc..2a404a7 100644 --- a/src/runner/pythonutils.h +++ b/src/runner/pythonutils.h @@ -7,12 +7,33 @@ namespace utils { namespace bpy = boost::python; + namespace details { + + template + struct is_stdmap_iterator : std::false_type {}; + + template + struct is_stdmap_iterator()->first)>> : std::true_type {}; + + // Note: QMap and standard maps do not have the same type of iterators: + template {}, int> = 0> + inline auto set_dict_entry(bpy::dict& result, It const& it) { + result[bpy::object{ it->first }] = bpy::object{ it->second }; + } + + template {}, int > = 0> + inline auto set_dict_entry(bpy::dict& result, It const& it) { + result[bpy::object{ it.key() }] = bpy::object{ it.value() }; + } + + } + template struct map_to_python { static PyObject* convert(const Map& map) { bpy::dict result; - for (auto& entry : map) { - result[bpy::object{ entry.first }] = bpy::object{ entry.second }; + for (auto it = map.begin(); it != map.end(); ++it) { + details::set_dict_entry(result, it); } return bpy::incref(result.ptr()); }