From bf31a2ce035100e23d3c4cea4ee12e448283396e Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 4 Oct 2023 14:43:13 +0200 Subject: [PATCH] Gui: Python support of workbench manipulation --- src/Gui/CMakeLists.txt | 2 + src/Gui/WorkbenchManipulator.cpp | 5 + src/Gui/WorkbenchManipulator.h | 3 + src/Gui/WorkbenchManipulatorPython.cpp | 124 +++++++++++++++++++++++++ src/Gui/WorkbenchManipulatorPython.h | 82 ++++++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 src/Gui/WorkbenchManipulatorPython.cpp create mode 100644 src/Gui/WorkbenchManipulatorPython.h diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index db6de80e6950..614a8d9fc89f 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1119,6 +1119,7 @@ SET(Workbench_CPP_SRCS WorkbenchFactory.cpp WorkbenchManager.cpp WorkbenchManipulator.cpp + WorkbenchManipulatorPython.cpp WorkbenchPyImp.cpp ) SET(Workbench_SRCS @@ -1133,6 +1134,7 @@ SET(Workbench_SRCS WorkbenchFactory.h WorkbenchManager.h WorkbenchManipulator.h + WorkbenchManipulatorPython.h ) SOURCE_GROUP("Workbench" FILES ${Workbench_SRCS}) diff --git a/src/Gui/WorkbenchManipulator.cpp b/src/Gui/WorkbenchManipulator.cpp index fdddbb878d05..b266dfce920c 100644 --- a/src/Gui/WorkbenchManipulator.cpp +++ b/src/Gui/WorkbenchManipulator.cpp @@ -42,6 +42,11 @@ void WorkbenchManipulator::removeManipulator(const WorkbenchManipulator::Ptr& pt } } +std::set WorkbenchManipulator::getManipulators() +{ + return manipulators; +} + void WorkbenchManipulator::changeMenuBar(MenuItem* menuBar) { for (auto& it : manipulators) { diff --git a/src/Gui/WorkbenchManipulator.h b/src/Gui/WorkbenchManipulator.h index b4901fba9824..97865d27015f 100644 --- a/src/Gui/WorkbenchManipulator.h +++ b/src/Gui/WorkbenchManipulator.h @@ -115,6 +115,9 @@ class GuiExport WorkbenchManipulator WorkbenchManipulator& operator = (const WorkbenchManipulator&) = delete; WorkbenchManipulator& operator = (WorkbenchManipulator&&) = delete; +protected: + static std::set getManipulators(); + private: static std::set manipulators; // NOLINT }; diff --git a/src/Gui/WorkbenchManipulatorPython.cpp b/src/Gui/WorkbenchManipulatorPython.cpp new file mode 100644 index 000000000000..dc5c61895e9b --- /dev/null +++ b/src/Gui/WorkbenchManipulatorPython.cpp @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2023 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + + +#include "PreCompiled.h" +#include "WorkbenchManipulatorPython.h" +#include + +using namespace Gui; + +void WorkbenchManipulatorPython::installManipulator(const Py::Object& obj) +{ + auto manip = std::make_shared(obj); + WorkbenchManipulator::installManipulator(manip); +} + +void WorkbenchManipulatorPython::removeManipulator(const Py::Object& obj) +{ + auto manip = getManipulators(); + for (const auto& it : manip) { + auto ptr = std::dynamic_pointer_cast(it); + if (ptr && ptr->object == obj) { + WorkbenchManipulator::removeManipulator(ptr); + break; + } + } +} + +WorkbenchManipulatorPython::WorkbenchManipulatorPython(const Py::Object& obj) + : object(obj) +{ +} + +WorkbenchManipulatorPython::~WorkbenchManipulatorPython() +{ + Base::PyGILStateLocker lock; + object = Py::None(); +} + +void WorkbenchManipulatorPython::modifyMenuBar([[maybe_unused]] MenuItem* menuBar) +{ + Base::PyGILStateLocker lock; + try { + if (object.hasAttr(std::string("modifyMenuBar"))) { + Py::Callable method(object.getAttr(std::string("modifyMenuBar"))); + Py::Tuple args(1); + method.apply(args); + } + } + catch (Py::Exception&) { + Base::PyException exc; // extract the Python error text + exc.ReportException(); + } +} + +void WorkbenchManipulatorPython::modifyContextMenu([[maybe_unused]] const char* recipient, + [[maybe_unused]] MenuItem* menuBar) +{ + Base::PyGILStateLocker lock; + try { + if (object.hasAttr(std::string("modifyContextMenu"))) { + Py::Callable method(object.getAttr(std::string("modifyContextMenu"))); + Py::Tuple args(2); + args.setItem(0, Py::String(recipient)); + method.apply(args); + } + } + catch (Py::Exception&) { + Base::PyException exc; // extract the Python error text + exc.ReportException(); + } +} + +void WorkbenchManipulatorPython::modifyToolBars([[maybe_unused]] ToolBarItem* toolBar) +{ + Base::PyGILStateLocker lock; + try { + if (object.hasAttr(std::string("modifyToolBars"))) { + Py::Callable method(object.getAttr(std::string("modifyToolBars"))); + Py::Tuple args(1); + method.apply(args); + } + } + catch (Py::Exception&) { + Base::PyException exc; // extract the Python error text + exc.ReportException(); + } +} + +void WorkbenchManipulatorPython::modifyDockWindows([[maybe_unused]] DockWindowItems* dockWindow) +{ + Base::PyGILStateLocker lock; + try { + if (object.hasAttr(std::string("modifyDockWindows"))) { + Py::Callable method(object.getAttr(std::string("modifyDockWindows"))); + Py::Tuple args(1); + method.apply(args); + } + } + catch (Py::Exception&) { + Base::PyException exc; // extract the Python error text + exc.ReportException(); + } +} diff --git a/src/Gui/WorkbenchManipulatorPython.h b/src/Gui/WorkbenchManipulatorPython.h new file mode 100644 index 000000000000..8b4d7b74057e --- /dev/null +++ b/src/Gui/WorkbenchManipulatorPython.h @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2023 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + + +#ifndef GUI_WORKBENCHMANIPULATOR_PYTHON_H +#define GUI_WORKBENCHMANIPULATOR_PYTHON_H + +#include +#include + +namespace Gui { + +/** + * The WorkbenchManipulatorPython class accepts an instance of a Python class + * that is supposed to implement any of the virtual functions. + * @author Werner Mayer + */ +class GuiExport WorkbenchManipulatorPython : public WorkbenchManipulator +{ +public: + static void installManipulator(const Py::Object& obj); + static void removeManipulator(const Py::Object& obj); + explicit WorkbenchManipulatorPython(const Py::Object& obj); + ~WorkbenchManipulatorPython() override; + +protected: + /*! + * \brief modifyMenuBar + * Method to manipulate the menu structure of a workbench. + */ + void modifyMenuBar([[maybe_unused]] MenuItem* menuBar) override; + /*! + * \brief modifyContextMenu + * Method to manipulate the contextmenu structure of a workbench. + */ + void modifyContextMenu([[maybe_unused]] const char* recipient, + [[maybe_unused]] MenuItem* menuBar) override; + /*! + * \brief modifyToolBars + * Method to manipulate the toolbar structure of a workbench + */ + void modifyToolBars([[maybe_unused]] ToolBarItem* toolBar) override; + /*! + * \brief modifyDockWindows + * Method to manipulate the dock window structure of a workbench + */ + void modifyDockWindows([[maybe_unused]] DockWindowItems* dockWindow) override; + +public: + WorkbenchManipulatorPython(const WorkbenchManipulatorPython&) = delete; + WorkbenchManipulatorPython(WorkbenchManipulatorPython&&) = delete; + WorkbenchManipulatorPython& operator = (const WorkbenchManipulatorPython&) = delete; + WorkbenchManipulatorPython& operator = (WorkbenchManipulatorPython&&) = delete; + +private: + Py::Object object; +}; + +} // namespace Gui + + +#endif // GUI_WORKBENCHMANIPULATOR_PYTHON_H