From c8fcb9405e77caffaf8918d25d62c0afea04c37a Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 19 Nov 2021 15:45:56 +0100 Subject: [PATCH] Gui: extend PySide2 wrapper of MainWindow with extra functions --- src/Gui/Application.cpp | 2 + src/Gui/ApplicationPy.cpp | 14 +--- src/Gui/CMakeLists.txt | 2 + src/Gui/MainWindowPy.cpp | 151 ++++++++++++++++++++++++++++++++++++++ src/Gui/MainWindowPy.h | 61 +++++++++++++++ 5 files changed, 220 insertions(+), 10 deletions(-) create mode 100644 src/Gui/MainWindowPy.cpp create mode 100644 src/Gui/MainWindowPy.h diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 94e2cb47e4..ca1b8d7967 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -87,6 +87,7 @@ #include "SoFCDB.h" #include "PythonConsolePy.h" #include "PythonDebugger.h" +#include "MainWindowPy.h" #include "MDIViewPy.h" #include "View3DPy.h" #include "DlgOnlineHelpImp.h" @@ -458,6 +459,7 @@ Application::Application(bool GUIenabled) OutputStdout ::init_type(); OutputStderr ::init_type(); PythonStdin ::init_type(); + MainWindowPy ::init_type(); MDIViewPy ::init_type(); View3DInventorPy ::init_type(); View3DInventorViewerPy ::init_type(); diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index 82a883cb1f..7f149f6960 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -44,6 +44,7 @@ #include "Command.h" #include "Document.h" #include "MainWindow.h" +#include "MainWindowPy.h" #include "Macro.h" #include "EditorView.h" #include "PythonEditor.h" @@ -705,20 +706,13 @@ PyObject* Application::sSendFocusView(PyObject * /*self*/, PyObject *args) PyObject* Application::sGetMainWindow(PyObject * /*self*/, PyObject *args) { if (!PyArg_ParseTuple(args, "")) - return NULL; + return nullptr; - PythonWrapper wrap; - if (!wrap.loadCoreModule() || - !wrap.loadGuiModule() || - !wrap.loadWidgetsModule()) { - PyErr_SetString(PyExc_RuntimeError, "Failed to load Python wrapper for Qt"); - return 0; - } try { - return Py::new_reference_to(wrap.fromQWidget(Gui::getMainWindow(), "QMainWindow")); + return Py::new_reference_to(MainWindowPy::createWrapper(Gui::getMainWindow())); } catch (const Py::Exception&) { - return 0; + return nullptr; } } diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 50a596949b..c492e461ec 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1037,6 +1037,7 @@ SOURCE_GROUP("View3D\\Inventor" FILES ${Inventor_SRCS}) SET(Widget_CPP_SRCS FileDialog.cpp MainWindow.cpp + MainWindowPy.cpp PrefWidgets.cpp InputField.cpp ProgressBar.cpp @@ -1054,6 +1055,7 @@ SET(Widget_CPP_SRCS SET(Widget_HPP_SRCS FileDialog.h MainWindow.h + MainWindowPy.h PrefWidgets.h InputField.h ProgressBar.h diff --git a/src/Gui/MainWindowPy.cpp b/src/Gui/MainWindowPy.cpp new file mode 100644 index 0000000000..2b9576437c --- /dev/null +++ b/src/Gui/MainWindowPy.cpp @@ -0,0 +1,151 @@ +/*************************************************************************** + * Copyright (c) 2021 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +#endif + +#include "MainWindowPy.h" +#include "MainWindow.h" +#include "MDIView.h" +#include "MDIViewPy.h" +#include "PythonWrapper.h" + + +using namespace Gui; + + +void MainWindowPy::init_type() +{ + behaviors().name("MainWindowPy"); + behaviors().doc("Python binding class for the MainWindow class"); + // you must have overwritten the virtual functions + behaviors().supportRepr(); + behaviors().supportGetattr(); + behaviors().supportSetattr(); + behaviors().set_tp_new(extension_object_new); + + add_varargs_method("getWindows",&MainWindowPy::getWindows,"getWindows()"); + add_varargs_method("getWindowsOfType",&MainWindowPy::getWindowsOfType,"getWindowsOfType(typeid)"); + add_varargs_method("setActiveWindow", &MainWindowPy::setActiveWindow, "setActiveWindow(MDIView)"); + add_varargs_method("getActiveWindow", &MainWindowPy::getActiveWindow, "getActiveWindow()"); +} + +PyObject *MainWindowPy::extension_object_new(struct _typeobject * /*type*/, PyObject * /*args*/, PyObject * /*kwds*/) +{ + return new MainWindowPy(nullptr); +} + +Py::Object MainWindowPy::type() +{ + return Py::Object( reinterpret_cast( behaviors().type_object() ) ); +} + +Py::ExtensionObject MainWindowPy::create(MainWindow *mw) +{ + Py::Callable class_type(type()); + Py::Tuple arg; + auto inst = Py::ExtensionObject(class_type.apply(arg, Py::Dict())); + inst.extensionObject()->_mw = mw; + return inst; +} + +Py::Object MainWindowPy::createWrapper(MainWindow *mw) +{ + PythonWrapper wrap; + if (!wrap.loadCoreModule() || + !wrap.loadGuiModule() || + !wrap.loadWidgetsModule()) { + throw Py::RuntimeError("Failed to load Python wrapper for Qt"); + } + + // copy attributes + std::list attr = {"getWindows", "getWindowsOfType", "setActiveWindow", "getActiveWindow"}; + + Py::Object py = wrap.fromQWidget(mw, "QMainWindow"); + Py::ExtensionObject inst(create(mw)); + for (const auto& it : attr) { + py.setAttr(it, inst.getAttr(it)); + } + return py; +} + +MainWindowPy::MainWindowPy(MainWindow *mw) + : _mw(mw) +{ +} + +MainWindowPy::~MainWindowPy() +{ + // in case the class is instantiated on the stack + ob_refcnt = 0; +} + +Py::Object MainWindowPy::repr() +{ + std::string s; + std::ostringstream s_out; + if (!_mw) + throw Py::RuntimeError("Cannot print representation of deleted object"); + s_out << "MainWindow"; + return Py::String(s_out.str()); +} + +Py::Object MainWindowPy::getWindows(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + return Py::None(); +} + +Py::Object MainWindowPy::getWindowsOfType(const Py::Tuple& args) +{ + return Py::None(); +} + +Py::Object MainWindowPy::setActiveWindow(const Py::Tuple& args) +{ + Py::ExtensionObject mdi(args[0].callMemberFunction("cast_to_base")); + if (_mw) { + _mw->setActiveWindow(mdi.extensionObject()->getMDIViewPtr()); + } + + return Py::None(); +} + +Py::Object MainWindowPy::getActiveWindow(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + if (_mw) { + MDIView* mdi = _mw->activeWindow(); + if (mdi) { + return Py::asObject(mdi->getPyObject()); + } + } + return Py::None(); +} diff --git a/src/Gui/MainWindowPy.h b/src/Gui/MainWindowPy.h new file mode 100644 index 0000000000..abc03bb013 --- /dev/null +++ b/src/Gui/MainWindowPy.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (c) 2021 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_MAINWINDOWPY_H +#define GUI_MAINWINDOWPY_H + +#include +#include +#include +#include + +namespace Gui { +class MainWindow; + +class GuiExport MainWindowPy : public Py::PythonExtension +{ +public: + static void init_type(); + static PyObject *extension_object_new( PyTypeObject *subtype, PyObject * /*args*/, PyObject * /*kwds*/ ); + + static Py::Object createWrapper(MainWindow *mw); + static Py::Object type(); + static Py::ExtensionObject create(MainWindow *mw); + + MainWindowPy(MainWindow *mw); + ~MainWindowPy(); + + Py::Object repr(); + + Py::Object getWindows(const Py::Tuple&); + Py::Object getWindowsOfType(const Py::Tuple&); + Py::Object setActiveWindow(const Py::Tuple&); + Py::Object getActiveWindow(const Py::Tuple&); + +private: + QPointer _mw; +}; + +} // namespace Gui + +#endif //GUI_MAINWINDOWPY_H