Add bindings for TaskDialog.

This commit is contained in:
Mikaël Capelle
2020-12-08 19:44:10 +01:00
parent 2ed4b901c0
commit 87c91b8259
5 changed files with 133 additions and 0 deletions
+1
View File
@@ -35,6 +35,7 @@ add_filter(NAME src/converters GROUPS
add_filter(NAME src/runner GROUPS
pythonrunner
pylogger
widgets
)
add_filter(NAME src/utils GROUPS
+41
View File
@@ -66,6 +66,37 @@ namespace utils {
}
namespace Enum_converter {
/**
*
*/
template <typename Enum>
struct Enum_to_int
{
static PyObject* convert(const Enum& flags) {
return bpy::incref(bpy::object(static_cast<int>(flags)).ptr());
}
};
template <typename Enum>
struct Enum_from_python_obj
{
static void* convertible(PyObject* objPtr) {
return SIPLong_Check(objPtr) ? objPtr : nullptr;
}
static void construct(PyObject* objPtr, bpy::converter::rvalue_from_python_stage1_data* data) {
int intVersion = (int)SIPLong_AsLong(objPtr);
void* storage = ((bpy::converter::rvalue_from_python_storage<Enum>*)data)->storage.bytes;
new (storage) Enum(static_cast<Enum>(intVersion));
data->convertible = storage;
}
};
}
namespace QFlags_converter {
/**
@@ -508,6 +539,16 @@ namespace utils {
bpy::type_id<Flags>());
}
template <class Enum>
inline void register_enum_converter() {
using namespace Enum_converter;
bpy::to_python_converter<Enum, Enum_to_int<Enum>>();
bpy::converter::registry::push_back(
&Enum_from_python_obj<Enum>::convertible,
&Enum_from_python_obj<Enum>::construct,
bpy::type_id<Enum>());
}
template <class QClass>
inline void register_qclass_converter() {
using Converter = QClass_converter::QClass_converters<QClass>;
+16
View File
@@ -15,6 +15,7 @@
#include <iplugintool.h>
#include <iprofile.h>
#include <log.h>
#include <report.h>
#include "uibasewrappers.h"
#include "proxypluginwrappers.h"
@@ -41,6 +42,7 @@
#include "converters.h"
#include "shared_ptr_converter.h"
#include "pylogger.h"
#include "widgets.h"
using namespace MOBase;
@@ -86,6 +88,10 @@ BOOST_PYTHON_MODULE(mobase)
utils::register_qflags_converter<IPluginGame::ProfileSettings>();
utils::register_qflags_converter<IModList::ModStates>();
// Enums:
utils::register_enum_converter<QMessageBox::StandardButton>();
utils::register_enum_converter<QMessageBox::Icon>();
// Pointers:
bpy::register_ptr_to_python<std::shared_ptr<FileTreeEntry>>();
bpy::register_ptr_to_python<std::shared_ptr<const FileTreeEntry>>();
@@ -116,6 +122,7 @@ BOOST_PYTHON_MODULE(mobase)
utils::register_sequence_container<std::vector<std::shared_ptr<const IPluginRequirement>>>();
utils::register_sequence_container<std::vector<ModDataContent::Content>>();
utils::register_sequence_container<std::vector<Mapping>>();
utils::register_sequence_container<std::vector<TaskDialogButton>>();
utils::register_set_container<std::set<QString>>();
@@ -132,6 +139,7 @@ BOOST_PYTHON_MODULE(mobase)
bpy::register_tuple<std::tuple<bool, DWORD>>(); // IOrganizer::waitForApplication
bpy::register_tuple<std::tuple<bool, bool>>(); // IProfile::invalidationActive
bpy::register_tuple<std::tuple<IPluginInstaller::EInstallResult, std::shared_ptr<IFileTree>, QString, int>>();
bpy::register_tuple<std::tuple<QString, QString>>();
// Variants:
bpy::register_variant<std::variant<
@@ -140,6 +148,7 @@ BOOST_PYTHON_MODULE(mobase)
std::tuple<IPluginInstaller::EInstallResult, std::shared_ptr<IFileTree>, QString, int>>>();
bpy::register_variant<std::variant<IFileTree::OverwritesType, std::size_t>>();
bpy::register_variant<std::variant<QString, bool>>();
bpy::register_variant<std::variant<QString, std::tuple<QString, QString>>>();
// Functions:
utils::register_functor_converter<void()>(); // converter for the onRefreshed-callback
@@ -1088,6 +1097,13 @@ BOOST_PYTHON_MODULE(mobase)
bpy::def("getProductVersion", &MOBase::getProductVersion, bpy::arg("executable"));
bpy::def("getIconForExecutable", &MOBase::iconForExecutable, bpy::arg("executable"));
bpy::object widgets(bpy::borrowed(PyImport_AddModule("mobase.widgets")));
bpy::scope().attr("widgets") = widgets;
{
bpy::scope w_ = widgets;
register_widgets();
}
// Expose MoVariant: MoVariant is a fake object whose only purpose is to be used as a type-hint
// on the python side (e.g., def foo(x: mobase.MoVariant)). The real MoVariant is defined in the
// generated stubs, since it's only relevant when doing type-checking, but this needs to be defined,
+66
View File
@@ -0,0 +1,66 @@
#include "widgets.h"
#include <variant>
#include <boost/python.hpp>
#include "report.h"
#include "variant_helper.h"
namespace bpy = boost::python;
using namespace MOBase;
void register_widgets() {
// TaskDialog is also in Windows System.
using TaskDialog = MOBase::TaskDialog;
// TaskDialog
bpy::class_<TaskDialogButton>("TaskDialogButton", bpy::no_init)
.def(bpy::init<QString, QString, QMessageBox::StandardButton>((bpy::arg("text"), bpy::arg("description"), bpy::arg("button"))))
.def(bpy::init<QString, QMessageBox::StandardButton>((bpy::arg("text"), bpy::arg("button"))));
bpy::class_<TaskDialog, TaskDialog*, boost::noncopyable>("TaskDialog", bpy::no_init)
.def("__init__", bpy::make_constructor(+[](
QWidget* parent, QString const& title, QString const& main,
QString const& content, QString const& details, QMessageBox::Icon icon,
std::vector<TaskDialogButton> const& buttons,
std::variant<QString, std::tuple<QString, QString>> const& remember) {
auto* dialog = new TaskDialog(parent, title);
dialog->main(main).content(content).details(details).icon(icon);
for (auto& button : buttons) {
dialog->button(button);
}
std::visit([dialog](auto const& item) {
QString action, file;
if constexpr (std::is_same_v<std::decay_t<decltype(item)>, QString>) {
action = item;
}
else {
action = std::get<0>(item);
file = std::get<1>(item);
}
dialog->remember(action, file);
}, remember);
return dialog;
}, bpy::default_call_policies(),
(bpy::arg("parent") = (QWidget*)nullptr, bpy::arg("title") = "", bpy::arg("main") = "", bpy::arg("content") = "",
bpy::arg("details") = "", bpy::arg("icon") = QMessageBox::NoIcon, bpy::arg("buttons") = std::vector<TaskDialogButton>{},
bpy::arg("remember") = "")))
.def("setTitle", &TaskDialog::title, bpy::return_self<>(), bpy::arg("title"))
.def("setMain", &TaskDialog::main, bpy::return_self<>(), bpy::arg("main"))
.def("setContent", &TaskDialog::content, bpy::return_self<>(), bpy::arg("content"))
.def("setDetails", &TaskDialog::details, bpy::return_self<>(), bpy::arg("details"))
.def("setIcon", &TaskDialog::icon, bpy::return_self<>(), bpy::arg("icon"))
.def("addButton", &TaskDialog::button, bpy::return_self<>(), bpy::arg("button"))
.def("setRemember", &TaskDialog::remember, bpy::return_self<>(), (bpy::arg("action"), bpy::arg("file") = ""))
.def("setWidth", &TaskDialog::setWidth, bpy::arg("widget"))
.def("addContent", &TaskDialog::addContent, bpy::arg("widget"))
.def("exec", &TaskDialog::exec)
;
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef PYTHON_WIDGETS_HPP
#define PYTHON_WIDGETS_HPP
/**
* @brief Register uibase widgets in the current scope.
*/
void register_widgets();
#endif