mirror of
https://github.com/ModOrganizer2/modorganizer-plugin_python.git
synced 2026-07-27 14:03:33 -07:00
Merge pull request #78 from Holt59/iplugin-isactive-refactoring
IPlugin::isActive refactoring
This commit is contained in:
@@ -117,7 +117,7 @@ bool ProxyPython::init(IOrganizer *moInfo)
|
||||
{
|
||||
m_MOInfo = moInfo;
|
||||
|
||||
if (m_MOInfo && !m_MOInfo->pluginSetting(name(), "enabled").toBool()) {
|
||||
if (m_MOInfo && !m_MOInfo->isPluginEnabled(this)) {
|
||||
m_LoadFailure = FAIL_NONE;
|
||||
return false;
|
||||
}
|
||||
@@ -197,9 +197,14 @@ QString ProxyPython::name() const
|
||||
return "Python Proxy";
|
||||
}
|
||||
|
||||
QString ProxyPython::localizedName() const
|
||||
{
|
||||
return tr("Python Proxy");
|
||||
}
|
||||
|
||||
QString ProxyPython::author() const
|
||||
{
|
||||
return "Tannin";
|
||||
return "AnyOldName3, Holt59, Silarn, Tannin";
|
||||
}
|
||||
|
||||
QString ProxyPython::description() const
|
||||
@@ -212,11 +217,6 @@ VersionInfo ProxyPython::version() const
|
||||
return VersionInfo(2, 1, 0, VersionInfo::RELEASE_FINAL);
|
||||
}
|
||||
|
||||
bool ProxyPython::isActive() const
|
||||
{
|
||||
return m_LoadFailure == FAIL_NOTINIT;
|
||||
}
|
||||
|
||||
QList<PluginSetting> ProxyPython::settings() const
|
||||
{
|
||||
QList<PluginSetting> result;
|
||||
|
||||
@@ -42,10 +42,10 @@ public:
|
||||
|
||||
virtual bool init(MOBase::IOrganizer *moInfo);
|
||||
virtual QString name() const;
|
||||
virtual QString localizedName() const;
|
||||
virtual QString author() const;
|
||||
virtual QString description() const;
|
||||
virtual MOBase::VersionInfo version() const;
|
||||
virtual bool isActive() const;
|
||||
virtual QList<MOBase::PluginSetting> settings() const;
|
||||
|
||||
QStringList pluginList(const QString &pluginPath) const;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace utils {
|
||||
struct QString_to_python_str
|
||||
{
|
||||
static PyObject* convert(const QString& str) {
|
||||
// It's safer to explicitly convert to unicode as if we don't, this can return
|
||||
// It's safer to explicitly convert to unicode as if we don't, this can return
|
||||
// either str or unicode without it being easy to know which to expect
|
||||
bpy::object pyStr = bpy::object(qUtf8Printable(str));
|
||||
if (SIPBytes_Check(pyStr.ptr()))
|
||||
@@ -368,7 +368,7 @@ namespace utils {
|
||||
template <typename R, typename... Args, typename... Wrappers>
|
||||
struct Functor_converter<R(Args...), Wrappers... >
|
||||
{
|
||||
|
||||
|
||||
template <class T>
|
||||
static decltype(auto) wrap(T&& t) {
|
||||
return details::wrap_impl<Wrappers... >::apply(std::forward<T>(t));
|
||||
@@ -483,8 +483,8 @@ namespace utils {
|
||||
using namespace QString_converter;
|
||||
bpy::to_python_converter<QString, QString_to_python_str>();
|
||||
bpy::converter::registry::push_back(
|
||||
&QString_from_python_str::convertible,
|
||||
&QString_from_python_str::construct,
|
||||
&QString_from_python_str::convertible,
|
||||
&QString_from_python_str::construct,
|
||||
bpy::type_id<QString>());
|
||||
}
|
||||
|
||||
@@ -492,8 +492,8 @@ namespace utils {
|
||||
using namespace QVariant_converter;
|
||||
bpy::to_python_converter<QVariant, QVariant_to_python_obj>();
|
||||
bpy::converter::registry::push_back(
|
||||
&QVariant_from_python_obj::convertible,
|
||||
&QVariant_from_python_obj::construct,
|
||||
&QVariant_from_python_obj::convertible,
|
||||
&QVariant_from_python_obj::construct,
|
||||
bpy::type_id<QVariant>());
|
||||
}
|
||||
|
||||
@@ -528,8 +528,8 @@ namespace utils {
|
||||
inline void register_functor_converter() {
|
||||
using Converter = Functor_converter<Fn, Wrappers... >;
|
||||
bpy::converter::registry::push_back(
|
||||
&Converter::convertible,
|
||||
&Converter::construct,
|
||||
&Converter::convertible,
|
||||
&Converter::construct,
|
||||
bpy::type_id<std::function<Fn>>());
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,9 @@ namespace boost
|
||||
|
||||
using namespace MOBase;
|
||||
|
||||
|
||||
#define COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(class_name) \
|
||||
// See COMMON_I_PLUGIN_WRAPPER_DECLARATIONS__IMPL in proxypluginwrappers.h for explanation on
|
||||
// the "include_requirements".
|
||||
#define COMMON_I_PLUGIN_WRAPPER_DEFINITIONS_IMPL(class_name, include_requirements) \
|
||||
bool class_name::init(MOBase::IOrganizer *moInfo) \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<bool>(this, "init", boost::python::ptr(moInfo)); \
|
||||
@@ -43,9 +44,9 @@ QString class_name::localizedName() const \
|
||||
return basicWrapperFunctionImplementationWithDefault<QString>(this, &class_name::localizedName_Default, "localizedName"); \
|
||||
} \
|
||||
\
|
||||
IPlugin* class_name::master() const \
|
||||
QString class_name::master() const \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementationWithDefault<IPlugin*>(this, &class_name::master_Default, "master"); \
|
||||
return basicWrapperFunctionImplementationWithDefault<QString>(this, &class_name::master_Default, "master"); \
|
||||
} \
|
||||
\
|
||||
QString class_name::author() const \
|
||||
@@ -63,17 +64,20 @@ MOBase::VersionInfo class_name::version() const \
|
||||
return basicWrapperFunctionImplementation<MOBase::VersionInfo>(this, "version"); \
|
||||
} \
|
||||
\
|
||||
bool class_name::isActive() const \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<bool>(this, "isActive"); \
|
||||
} \
|
||||
\
|
||||
QList<MOBase::PluginSetting> class_name::settings() const \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<QList<MOBase::PluginSetting>>(this, "settings"); \
|
||||
} \
|
||||
QString class_name::localizedName_Default() const { return IPlugin::localizedName(); } \
|
||||
IPlugin* class_name::master_Default() const { return IPlugin::master(); }
|
||||
QString class_name::master_Default() const { return IPlugin::master(); } \
|
||||
BOOST_PP_EXPR_IF(include_requirements, \
|
||||
QList<IPluginRequirement*> class_name::requirements() const { \
|
||||
return basicWrapperFunctionImplementationWithDefault<QList<IPluginRequirement*>>( \
|
||||
this, &class_name::requirements_Default, m_Requirements, "requirements"); \
|
||||
} \
|
||||
QList<IPluginRequirement*> class_name::requirements_Default() const { return IPlugin::requirements(); })
|
||||
|
||||
#define COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(class_name) COMMON_I_PLUGIN_WRAPPER_DEFINITIONS_IMPL(class_name, 1)
|
||||
|
||||
/// end COMMON_I_PLUGIN_WRAPPER_DEFINITIONS
|
||||
/////////////////////////////
|
||||
@@ -293,7 +297,7 @@ QString IPluginGameWrapper::getLauncherName() const
|
||||
return basicWrapperFunctionImplementation<QString>(this, "getLauncherName");
|
||||
}
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginGameWrapper)
|
||||
COMMON_I_PLUGIN_WRAPPER_DEFINITIONS_IMPL(IPluginGameWrapper, 0)
|
||||
|
||||
std::map<std::type_index, boost::any> IPluginGameWrapper::featureList() const
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define PROXYPLUGINWRAPPERS_H
|
||||
|
||||
|
||||
#include <iplugin.h>
|
||||
#include <iplugindiagnose.h>
|
||||
#include <ipluginfilemapper.h>
|
||||
#include <iplugingame.h>
|
||||
@@ -15,19 +16,27 @@
|
||||
#include <boost/python.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
#define COMMON_I_PLUGIN_WRAPPER_DECLARATIONS public: \
|
||||
// The wrapper for IPluginGame cannot override requirements() since it's final,
|
||||
// so we need to be able to exclude the declarations.
|
||||
#define COMMON_I_PLUGIN_WRAPPER_DECLARATIONS_IMPL(include_requirements) \
|
||||
BOOST_PP_EXPR_IF(include_requirements, \
|
||||
private: mutable boost::python::object m_Requirements; ) \
|
||||
public: \
|
||||
virtual bool init(MOBase::IOrganizer *moInfo) override; \
|
||||
virtual QString name() const override; \
|
||||
virtual QString localizedName() const override; \
|
||||
virtual IPlugin* master() const override; \
|
||||
virtual QString master() const override; \
|
||||
virtual QString author() const override; \
|
||||
virtual QString description() const override; \
|
||||
virtual MOBase::VersionInfo version() const override; \
|
||||
virtual bool isActive() const override; \
|
||||
virtual QList<MOBase::PluginSetting> settings() const override; \
|
||||
QString localizedName_Default() const; \
|
||||
IPlugin* master_Default() const;
|
||||
QString master_Default() const; \
|
||||
BOOST_PP_EXPR_IF(include_requirements, \
|
||||
virtual QList<MOBase::IPluginRequirement*> requirements() const override; \
|
||||
QList<MOBase::IPluginRequirement*> requirements_Default() const;)
|
||||
|
||||
#define COMMON_I_PLUGIN_WRAPPER_DECLARATIONS COMMON_I_PLUGIN_WRAPPER_DECLARATIONS_IMPL(1)
|
||||
|
||||
// Even though the base interface is not a QObject, this has to be because we have no way to pass Mod Organizer a plugin that implements multiple interfaces.
|
||||
// QObject must be the first base class because moc assumes the first base class is a QObject
|
||||
@@ -126,7 +135,7 @@ public:
|
||||
virtual QString gameVersion() const override;
|
||||
virtual QString getLauncherName() const override;
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS_IMPL(0)
|
||||
|
||||
protected:
|
||||
// Apparently, Python developers interpret an underscore in a function name as it being protected
|
||||
|
||||
+81
-13
@@ -95,18 +95,18 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
|
||||
// Containers:
|
||||
utils::register_sequence_container<std::vector<int>>();
|
||||
utils::register_sequence_container<std::vector<unsigned int>>();
|
||||
utils::register_sequence_container<QList<ExecutableInfo>>();
|
||||
utils::register_sequence_container<QList<ExecutableForcedLoadSetting>>();
|
||||
utils::register_sequence_container<QList<PluginSetting>>();
|
||||
utils::register_sequence_container<QList<ModRepositoryFileInfo>>();
|
||||
utils::register_sequence_container<QList<IPluginRequirement*>>();
|
||||
utils::register_sequence_container<QStringList>();
|
||||
utils::register_sequence_container<QList<QString>>();
|
||||
utils::register_sequence_container<QList<QFileInfo>>();
|
||||
utils::register_sequence_container<QList<QVariant>>(); // Required for QVariant since this is QVariantList.
|
||||
utils::register_sequence_container<std::vector<std::shared_ptr<const MOBase::FileTreeEntry>>>();
|
||||
utils::register_sequence_container<std::vector<ModDataContent::Content>>();
|
||||
|
||||
utils::register_sequence_container<std::vector<unsigned int>>();
|
||||
utils::register_sequence_container<std::vector<Mapping>>();
|
||||
|
||||
utils::register_set_container<std::set<QString>>();
|
||||
@@ -118,6 +118,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
|
||||
utils::register_associative_container<IFileTree::OverwritesType>();
|
||||
|
||||
utils::register_optional<std::optional<IPluginRequirement::Problem>>();
|
||||
|
||||
// Tuple:
|
||||
bpy::register_tuple<std::tuple<bool, DWORD>>(); // IOrganizer::waitForApplication
|
||||
bpy::register_tuple<std::tuple<bool, bool>>(); // IProfile::invalidationActive
|
||||
@@ -150,6 +152,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
utils::register_functor_converter<bool(std::shared_ptr<FileTreeEntry> const&)>();
|
||||
utils::register_functor_converter<std::variant<QString, bool>(QString const&)>();
|
||||
utils::register_functor_converter<void(IModInterface *), bpy::pointer_wrapper<IModInterface*>>();
|
||||
utils::register_functor_converter<bool(IOrganizer*), bpy::pointer_wrapper<IOrganizer*>>();
|
||||
utils::register_functor_converter<void(const IPlugin*), bpy::pointer_wrapper<const IPlugin*>>();
|
||||
|
||||
// This one is kept for backward-compatibility while we deprecate onModStateChanged for singl mod.
|
||||
utils::register_functor_converter<void(const QString&, IModList::ModStates)>(); // converter for the onModStateChanged-callback (IModList).
|
||||
@@ -262,6 +266,48 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
Q_DELEGATE(ISaveGameInfoWidget, QWidget, "_widget")
|
||||
;
|
||||
|
||||
// Plugin requirements:
|
||||
auto iPluginRequirementClass = bpy::class_<
|
||||
IPluginRequirementWrapper, bpy::bases<>, IPluginRequirementWrapper*, boost::noncopyable>("IPluginRequirement");
|
||||
{
|
||||
bpy::scope scope = iPluginRequirementClass;
|
||||
|
||||
bpy::class_<IPluginRequirement::Problem>("Problem",
|
||||
bpy::init<QString, QString>((bpy::arg("short_description"), bpy::arg("long_description") = "")))
|
||||
.def("shortDescription", &IPluginRequirement::Problem::shortDescription)
|
||||
.def("longDescription", &IPluginRequirement::Problem::longDescription);
|
||||
|
||||
iPluginRequirementClass
|
||||
.def("check", bpy::pure_virtual(&IPluginRequirement::check))
|
||||
;
|
||||
}
|
||||
|
||||
bpy::class_<PluginRequirementFactory, boost::noncopyable>("PluginRequirementFactory")
|
||||
// pluginDependency
|
||||
.def("pluginDependency", +[](QStringList const& pluginNames) {
|
||||
return PluginRequirementFactory::pluginDependency(pluginNames);
|
||||
}, bpy::return_value_policy<bpy::reference_existing_object>(), bpy::arg("plugins"))
|
||||
.def("pluginDependency", +[](QString const& pluginName) {
|
||||
return PluginRequirementFactory::pluginDependency(pluginName);
|
||||
}, bpy::return_value_policy<bpy::reference_existing_object>(), bpy::arg("plugin"))
|
||||
.staticmethod("pluginDependency")
|
||||
// gameDependency
|
||||
.def("gameDependency", +[](QStringList const& gameNames) {
|
||||
return PluginRequirementFactory::gameDependency(gameNames);
|
||||
}, bpy::return_value_policy<bpy::reference_existing_object>(), bpy::arg("games"))
|
||||
.def("gameDependency", +[](QString const& gameNames) {
|
||||
return PluginRequirementFactory::gameDependency(gameNames);
|
||||
}, bpy::return_value_policy<bpy::reference_existing_object>(), bpy::arg("game"))
|
||||
.staticmethod("gameDependency")
|
||||
// diagnose
|
||||
.def("diagnose", &PluginRequirementFactory::diagnose,
|
||||
bpy::return_value_policy<bpy::reference_existing_object>(), bpy::arg("diagnose"))
|
||||
.staticmethod("diagnose")
|
||||
// basic
|
||||
.def("basic", &PluginRequirementFactory::basic,
|
||||
bpy::return_value_policy<bpy::reference_existing_object>(), (bpy::arg("checker"), "description"))
|
||||
.staticmethod("basic");
|
||||
|
||||
bpy::class_<IOrganizer::FileInfo>("FileInfo", bpy::init<>())
|
||||
.def_readwrite("filePath", &IOrganizer::FileInfo::filePath)
|
||||
.def_readwrite("archive", &IOrganizer::FileInfo::archive)
|
||||
@@ -280,6 +326,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("createMod", &IOrganizer::createMod, bpy::return_value_policy<bpy::reference_existing_object>(), bpy::arg("name"))
|
||||
.def("getGame", &IOrganizer::getGame, bpy::return_value_policy<bpy::reference_existing_object>(), bpy::arg("name"))
|
||||
.def("modDataChanged", &IOrganizer::modDataChanged, bpy::arg("mod"))
|
||||
.def("isPluginEnabled", +[](IOrganizer* o, IPlugin* plugin) { return o->isPluginEnabled(plugin); }, bpy::arg("plugin"))
|
||||
.def("isPluginEnabled", +[](IOrganizer* o, QString const& plugin) { return o->isPluginEnabled(plugin); }, bpy::arg("plugin"))
|
||||
.def("pluginSetting", &IOrganizer::pluginSetting, (bpy::arg("plugin_name"), "key"))
|
||||
.def("setPluginSetting", &IOrganizer::setPluginSetting, (bpy::arg("plugin_name"), "key", "value"))
|
||||
.def("persistent", &IOrganizer::persistent, (bpy::arg("plugin_name"), "key", bpy::arg("default") = QVariant()))
|
||||
@@ -333,7 +381,20 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("onProfileRenamed", &IOrganizer::onProfileRenamed, bpy::arg("callback"))
|
||||
.def("onProfileRemoved", &IOrganizer::onProfileRemoved, bpy::arg("callback"))
|
||||
.def("onProfileChanged", &IOrganizer::onProfileChanged, bpy::arg("callback"))
|
||||
|
||||
.def("onPluginSettingChanged", &IOrganizer::onPluginSettingChanged, bpy::arg("callback"))
|
||||
.def("onPluginEnabled", +[](IOrganizer* o, std::function<void(const IPlugin*)> const& func) {
|
||||
o->onPluginEnabled(func);
|
||||
}, bpy::arg("callback"))
|
||||
.def("onPluginEnabled", +[](IOrganizer* o, QString const& name, std::function<void()> const& func) {
|
||||
o->onPluginEnabled(name, func);
|
||||
}, (bpy::arg("name"), bpy::arg("callback")))
|
||||
.def("onPluginDisabled", +[](IOrganizer* o, std::function<void(const IPlugin*)> const& func) {
|
||||
o->onPluginDisabled(func);
|
||||
}, bpy::arg("callback"))
|
||||
.def("onPluginDisabled", +[](IOrganizer* o, QString const& name, std::function<void()> const& func) {
|
||||
o->onPluginDisabled(name, func);
|
||||
}, (bpy::arg("name"), bpy::arg("callback")))
|
||||
|
||||
// DEPRECATED:
|
||||
.def("getMod", +[](IOrganizer* o, QString const& name) {
|
||||
@@ -772,24 +833,25 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("onModMoved", &MOBase::IModList::onModMoved, bpy::arg("callback"))
|
||||
;
|
||||
|
||||
// Note: localizedName() and master() have to go in all the plugin wrappers declaration,
|
||||
// Note: localizedName(), master() and requirements have to go in all the plugin wrappers declaration,
|
||||
// since the default functions are specific to each wrapper, otherwise in turns into an
|
||||
// infinite recursion mess.
|
||||
bpy::class_<IPluginWrapper, boost::noncopyable>("IPlugin")
|
||||
.def("init", bpy::pure_virtual(&MOBase::IPlugin::init), bpy::arg("organizer"))
|
||||
.def("name", bpy::pure_virtual(&MOBase::IPlugin::name))
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName, &IPluginWrapper::localizedName_Default)
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginWrapper::master_Default, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default)
|
||||
.def("author", bpy::pure_virtual(&MOBase::IPlugin::author))
|
||||
.def("description", bpy::pure_virtual(&MOBase::IPlugin::description))
|
||||
.def("version", bpy::pure_virtual(&MOBase::IPlugin::version))
|
||||
.def("isActive", bpy::pure_virtual(&MOBase::IPlugin::isActive))
|
||||
.def("requirements", &MOBase::IPlugin::requirements, &IPluginWrapper::requirements_Default)
|
||||
.def("settings", bpy::pure_virtual(&MOBase::IPlugin::settings))
|
||||
;
|
||||
|
||||
bpy::class_<IPluginDiagnoseWrapper, bpy::bases<IPlugin>, boost::noncopyable>("IPluginDiagnose")
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName, &IPluginDiagnoseWrapper::localizedName_Default)
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginDiagnoseWrapper::master_Default, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default)
|
||||
.def("requirements", &MOBase::IPlugin::requirements, &IPluginDiagnoseWrapper::requirements_Default)
|
||||
|
||||
.def("activeProblems", bpy::pure_virtual(&MOBase::IPluginDiagnose::activeProblems))
|
||||
.def("shortDescription", bpy::pure_virtual(&MOBase::IPluginDiagnose::shortDescription), bpy::arg("key"))
|
||||
@@ -815,7 +877,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
|
||||
bpy::class_<IPluginFileMapperWrapper, bpy::bases<IPlugin>, boost::noncopyable>("IPluginFileMapper")
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName, &IPluginFileMapperWrapper::localizedName_Default)
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginFileMapperWrapper::master_Default, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default)
|
||||
.def("requirements", &MOBase::IPlugin::requirements, &IPluginFileMapperWrapper::requirements_Default)
|
||||
.def("mappings", bpy::pure_virtual(&MOBase::IPluginFileMapper::mappings))
|
||||
;
|
||||
|
||||
@@ -849,7 +912,7 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
|
||||
bpy::class_<IPluginGameWrapper, bpy::bases<IPlugin>, boost::noncopyable>("IPluginGame")
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName, &IPluginGameWrapper::localizedName_Default)
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginGameWrapper::master_Default, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default)
|
||||
|
||||
.def("detectGame", bpy::pure_virtual(&MOBase::IPluginGame::detectGame))
|
||||
.def("gameName", bpy::pure_virtual(&MOBase::IPluginGame::gameName))
|
||||
@@ -947,7 +1010,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("onInstallationStart", &IPluginInstaller::onInstallationStart, (bpy::arg("archive"), bpy::arg("reinstallation"), bpy::arg("current_mod")))
|
||||
.def("onInstallationEnd", &IPluginInstaller::onInstallationEnd, (bpy::arg("result"), bpy::arg("new_mod")))
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName, &IPluginInstallerSimpleWrapper::localizedName_Default)
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginInstallerSimpleWrapper::master_Default, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default)
|
||||
.def("requirements", &MOBase::IPlugin::requirements, &IPluginInstallerSimpleWrapper::requirements_Default)
|
||||
|
||||
// Note: Keeping the variant here even if we always return a tuple to be consistent with the wrapper and
|
||||
// have proper stubs generation.
|
||||
@@ -964,7 +1028,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("onInstallationStart", &IPluginInstaller::onInstallationStart, (bpy::arg("archive"), bpy::arg("reinstallation"), bpy::arg("current_mod")))
|
||||
.def("onInstallationEnd", &IPluginInstaller::onInstallationEnd, (bpy::arg("result"), bpy::arg("new_mod")))
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName, &IPluginInstallerCustomWrapper::localizedName_Default)
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginInstallerCustomWrapper::master_Default, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default)
|
||||
.def("requirements", &MOBase::IPlugin::requirements, &IPluginInstallerCustomWrapper::requirements_Default)
|
||||
|
||||
// Needs to add both otherwize boost does not understand:
|
||||
.def("isArchiveSupported", &IPluginInstaller::isArchiveSupported, bpy::arg("tree"))
|
||||
@@ -977,7 +1042,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
|
||||
bpy::class_<IPluginModPageWrapper, bpy::bases<IPlugin>, boost::noncopyable>("IPluginModPage")
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName, &IPluginModPageWrapper::localizedName_Default)
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginModPageWrapper::master_Default, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default)
|
||||
.def("requirements", &MOBase::IPlugin::requirements, &IPluginModPageWrapper::requirements_Default)
|
||||
|
||||
.def("displayName", bpy::pure_virtual(&IPluginModPage::displayName))
|
||||
.def("icon", bpy::pure_virtual(&IPluginModPage::icon))
|
||||
@@ -990,7 +1056,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
|
||||
bpy::class_<IPluginPreviewWrapper, bpy::bases<IPlugin>, boost::noncopyable>("IPluginPreview")
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName, &IPluginPreviewWrapper::localizedName_Default)
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginPreviewWrapper::master_Default, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default)
|
||||
.def("requirements", &MOBase::IPlugin::requirements, &IPluginPreviewWrapper::requirements_Default)
|
||||
|
||||
.def("supportedExtensions", bpy::pure_virtual(&IPluginPreview::supportedExtensions))
|
||||
.def("genFilePreview", bpy::pure_virtual(&IPluginPreview::genFilePreview), bpy::return_value_policy<bpy::return_by_value>(),
|
||||
@@ -999,7 +1066,8 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
|
||||
bpy::class_<IPluginToolWrapper, bpy::bases<IPlugin>, boost::noncopyable>("IPluginTool")
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName, &IPluginToolWrapper::localizedName_Default)
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default, bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("master", &MOBase::IPlugin::master, &IPluginToolWrapper::master_Default)
|
||||
.def("requirements", &MOBase::IPlugin::requirements, &IPluginToolWrapper::requirements_Default)
|
||||
|
||||
.def("displayName", bpy::pure_virtual(&IPluginTool::displayName))
|
||||
.def("tooltip", bpy::pure_virtual(&IPluginTool::tooltip))
|
||||
|
||||
+66
-11
@@ -91,19 +91,19 @@ namespace utils {
|
||||
using value_type = typename Container::value_type;
|
||||
|
||||
static void* convertible(PyObject* objPtr) {
|
||||
if (PySequence_Check(objPtr)) return objPtr;
|
||||
// Check that the object can be iterated or is a sequence. There is no "clean"
|
||||
// way checking that an object is iterable apparently (PyIter_Check checks that
|
||||
// an object is an iterator, which is very different).
|
||||
if (objPtr->ob_type->tp_iter != 0 || PySequence_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<Container>*)data)->storage.bytes;
|
||||
Container* result = new (storage) Container();
|
||||
bpy::list source(bpy::handle<>(bpy::borrowed(objPtr)));
|
||||
int length = bpy::len(source);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
result->push_back(bpy::extract<value_type>(source[i]));
|
||||
}
|
||||
|
||||
bpy::object source(bpy::handle<>(bpy::borrowed(objPtr)));
|
||||
bpy::stl_input_iterator<value_type> begin(source), end;
|
||||
std::copy(begin, end, std::back_inserter(*result));
|
||||
data->convertible = storage;
|
||||
}
|
||||
};
|
||||
@@ -132,7 +132,8 @@ namespace utils {
|
||||
using value_type = typename Container::value_type;
|
||||
|
||||
static void* convertible(PyObject* objPtr) {
|
||||
if (PySequence_Check(objPtr)) return objPtr;
|
||||
// See container_from_python.
|
||||
if (objPtr->ob_type->tp_iter != 0 && PySequence_Check(objPtr)) return objPtr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -140,15 +141,55 @@ namespace utils {
|
||||
void* storage = ((bpy::converter::rvalue_from_python_storage<Container>*)data)->storage.bytes;
|
||||
Container* result = new (storage) Container();
|
||||
bpy::list source(bpy::handle<>(bpy::borrowed(objPtr)));
|
||||
int length = bpy::len(source);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
result->insert(bpy::extract<value_type>(source[i]));
|
||||
bpy::stl_input_iterator<value_type> begin(source), end;
|
||||
std::copy(begin, end, std::inserter(*result, result->begin()));
|
||||
data->convertible = storage;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class Optional>
|
||||
struct optional_to_python {
|
||||
static PyObject* convert(const Optional& optional) {
|
||||
if (optional) {
|
||||
return bpy::incref(bpy::object(*optional).ptr());
|
||||
}
|
||||
else {
|
||||
return bpy::incref(Py_None);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class Optional>
|
||||
struct optional_from_python {
|
||||
|
||||
using value_type = typename Optional::value_type;
|
||||
|
||||
static void* convertible(PyObject* objPtr) {
|
||||
|
||||
if (objPtr == Py_None) {
|
||||
return objPtr;
|
||||
}
|
||||
|
||||
bpy::object source(bpy::handle<>(bpy::borrowed(objPtr)));
|
||||
return bpy::extract<value_type>(source).check() ? objPtr : nullptr;
|
||||
}
|
||||
|
||||
static void construct(PyObject* objPtr, bpy::converter::rvalue_from_python_stage1_data* data) {
|
||||
void* storage = ((bpy::converter::rvalue_from_python_storage<Optional>*)data)->storage.bytes;
|
||||
Optional* result = new (storage) Optional();
|
||||
|
||||
bpy::object source(bpy::handle<>(bpy::borrowed(objPtr)));
|
||||
if (!source.is_none()) {
|
||||
*result = bpy::extract<value_type>(source)();
|
||||
}
|
||||
|
||||
data->convertible = storage;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register from and to python converters for (at least) map, unordered_map and QMap.
|
||||
*
|
||||
@@ -197,6 +238,20 @@ namespace utils {
|
||||
, bpy::type_id<Container>());
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Register from and to python converters for optional.
|
||||
*
|
||||
* @tparam T The optional type (std::optional<X> or boost::optional<X>).
|
||||
*/
|
||||
template <class Optional>
|
||||
void register_optional() {
|
||||
bpy::to_python_converter<Optional, optional_to_python<Optional>>();
|
||||
bpy::converter::registry::push_back(
|
||||
&optional_from_python<Optional>::convertible
|
||||
, &optional_from_python<Optional>::construct
|
||||
, bpy::type_id<Optional>());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Show a deprecation warning.
|
||||
|
||||
@@ -143,4 +143,30 @@ ReturnType basicWrapperFunctionImplementationWithDefault(WrapperTypePtr wrapper,
|
||||
return details::wrapperFunctionImplementation<ReturnType>(wrapper, false, fn, nullptr, methodName, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the given method on the wrapper with the given arguments, with proper
|
||||
* exception handling, and store the intermediate result in the given python object,
|
||||
* falling back to the given function if the method does not exist.
|
||||
*
|
||||
* @param wrapper The wrapper object to use to retrieve the python method. Must have a publicly
|
||||
* available `className` attribute.
|
||||
* @param fn The function to call if the method does not exists.
|
||||
* @param ref Python object to which the result of `get_override()` should be stored.
|
||||
* @param methodName The name of the method.
|
||||
* @param args... Arguments for the method.
|
||||
*
|
||||
* Note: `fn` does not have to be a member-function of `wrapper` but `std::invoke(fn, wrapper, args...)` must be valid.
|
||||
*
|
||||
* @return the result of calling the given Python method on the wrapper.
|
||||
*
|
||||
* @throw pyexcept::PythonError if an error occurs while executing the python method.
|
||||
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
||||
*/
|
||||
template <class ReturnType, class WrapperType, class Fn, class... Args>
|
||||
ReturnType basicWrapperFunctionImplementationWithDefault(const WrapperType* wrapper, Fn fn, boost::python::object& ref, const char* methodName, Args... args)
|
||||
{
|
||||
return details::wrapperFunctionImplementation<ReturnType>(wrapper, false, fn, &ref, methodName, args...);
|
||||
}
|
||||
|
||||
|
||||
#endif // PYTHONWRAPPERUTILITIES_H
|
||||
|
||||
@@ -16,12 +16,25 @@
|
||||
#include <ipluginlist.h>
|
||||
#include <isavegame.h>
|
||||
#include <isavegameinfowidget.h>
|
||||
#include <pluginrequirements.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "gilock.h"
|
||||
#include "pythonwrapperutilities.h"
|
||||
|
||||
// This needs to be extendable in Python, so actually needs a wrapper (everything else probably doesn't):
|
||||
// This can be extended in C++, so why not in Python:
|
||||
class IPluginRequirementWrapper : public MOBase::IPluginRequirement, public boost::python::wrapper<MOBase::IPluginRequirement>
|
||||
{
|
||||
public:
|
||||
static constexpr const char* className = "IPluginRequirement";
|
||||
using boost::python::wrapper<MOBase::IPluginRequirement>::get_override;
|
||||
|
||||
virtual std::optional<Problem> check(MOBase::IOrganizer *o) const override {
|
||||
return basicWrapperFunctionImplementation<std::optional<Problem>>(this, "check", boost::python::ptr(o));
|
||||
};
|
||||
};
|
||||
|
||||
// This needs to be extendable in Python, so actually needs a wrapper:
|
||||
class ISaveGameWrapper : public MOBase::ISaveGame, public boost::python::wrapper<MOBase::ISaveGame>
|
||||
{
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user