ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
Runtime.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #undef slots
9 
10 #include <pybind11/embed.h>
11 #include <pybind11/pybind11.h>
12 
13 #include <QCoreApplication>
14 #include <QEventLoop>
15 #include <QtConcurrent>
16 
18 #include <ecvMainAppInterface.h>
19 
20 #include "Consoles.h"
21 #include "Runtime.h"
22 #include "Threading.h"
23 #include "ccGuiPythonInstance.h"
24 
25 namespace py = pybind11;
26 using namespace pybind11::literals;
27 
28 namespace Runtime
29 {
30 
33 {
34  public:
35  virtual ~PythonPluginInterface() = default;
36 
37  virtual py::object getIcon()
38  {
39  return py::none();
40  }
41 
45  virtual std::vector<Runtime::RegisteredPlugin::Action> getActions() = 0;
46 };
47 
48 // Trampoline to allow Python classes to inherit our interface
50 {
51  public:
53 
54  std::vector<Runtime::RegisteredPlugin::Action> getActions() override
55  {
56  PYBIND11_OVERLOAD_PURE(std::vector<Runtime::RegisteredPlugin::Action>,
57  PythonPluginInterface /* Parent class */,
58  getActions /* function name */);
59  }
60 
61  py::object getIcon() override
62  {
63  PYBIND11_OVERRIDE(
64  py::object, PythonPluginInterface /* Parent class */, getIcon /* function name */);
65  }
66 };
67 
69 
71 
73 {
74  return s_pythonInstance;
75 }
76 
78 {
79  return s_cmdLineInstance;
80 }
81 
82 void setMainAppInterfaceInstance(ecvMainAppInterface *appInterface) noexcept(false)
83 {
84  if (s_pythonInstance == nullptr)
85  {
86  s_pythonInstance = new ccGuiPythonInstance(appInterface);
87  }
88 }
89 
91 {
92  if (s_pythonInstance != nullptr)
93  {
94  delete s_pythonInstance;
95  s_pythonInstance = nullptr;
96  }
97 }
98 
100 {
101  if (s_cmdLineInstance == nullptr)
102  {
103  s_cmdLineInstance = cmdLine;
104  }
105 }
106 
108 {
109  if (s_cmdLineInstance != nullptr)
110  {
111  s_cmdLineInstance = nullptr;
112  }
113 }
114 
115 } // namespace Runtime
116 
118 {
119  py::enum_<Qt::GlobalColor>(m, "GlobalColor");
120 
121  py::class_<QColor>(m, "QColor");
122 
123  py::class_<QListWidget, std::unique_ptr<QListWidget, py::nodelete>>(m, "QListWidget");
124 
125  py::class_<ccConsoleOutput>(m, "ccConsoleOutput")
126  .def(py::init<>())
127  .def(py::init<const char *>(), "prefix"_a)
128  .def("write", &ccConsoleOutput::write)
129  .def("isatty", &ccConsoleOutput::isatty)
130  .def("flush", &ccConsoleOutput::flush);
131 
132  py::class_<ListWidgetConsole>(m, "ListWidgetConsole")
133  .def(py::init<QListWidget *, Qt::GlobalColor>())
134  .def(py::init<QListWidget *, QColor>())
135  .def(py::init<QListWidget *>())
136  .def("write", &ListWidgetConsole::write)
137  .def("isatty", &ListWidgetConsole::isatty)
138  .def("flush", &ListWidgetConsole::flush);
139 }
140 
141 void define_ccGUIPythonInstance(py::module &);
142 void define_ccCommandLine(py::module &);
143 
144 PYBIND11_EMBEDDED_MODULE(pycc_runtime, m)
145 {
146  py::class_<ecvMainAppInterface>(m, "ecvMainAppInterface");
147 
150 
151  py::class_<Runtime::PythonPluginInterface, Runtime::PythonPluginTrampoline>(
152  m, "PythonPluginInterface", R"doc(
153  The base class for Python plugins.
154 
155  Every plugin must inherit from this.
156 
157  .. code:: Python
158 
159  import pycc
160 
161  class MyPlugin(pycc.PythonPluginInterface):
162  def __init__(self):
163  super().__init__()
164  )doc")
165  .def(py::init<>())
166  .def("getActions", &Runtime::PythonPluginInterface::getActions, R"doc(
167 
168  .. important::
169  This method. must be implemented
170 
171  The method shall return the list of actions the plugin can perform.
172  Actions will get added to the context menu of the plugin.
173 
174  The returned actions must be of type :class:`pycc.Action`.
175 )doc")
176  .def("getIcon", &Runtime::PythonPluginInterface::getIcon, R"doc(
177  It is not mandatory to implement this method.
178 
179  When implemented, it shall return the icon that shall be used for the
180  plugin sub menu.
181 
182  see :class:`pycc.Action`.
183 )doc");
184 
185  py::class_<Runtime::RegisteredPlugin::Action>(m, "Action", R"doc(
186  Represent an action of a plugin.
187 
188  Parameters
189  ----------
190  name: str
191  The name of the action
192  target:
193  method of the plugin that performs the action
194  icon: optional, either bytes, or tuple[bytes, str] or str default to None
195  Icon of the action.
196  - If the type is bytes, then they shall the bytes of the icon itself.
197  - If the types is Tuple[bytes, str], then bytes shall be the bytes of the icon
198  itself and str the format, e.g. (some_bytes, "PNG")
199  - If str then it shall be the path to a file.
200 )doc")
201  .def(py::init<QString, py::object, py::object>(),
202  "name"_a,
203  "target"_a,
204  "icon"_a = py::none());
205 
206  m.def("ProcessEvents", []() { QCoreApplication::processEvents(); });
207 
208  m.def(
209  "RunInThread",
210  [](py::object callable, py::args args, py::kwargs kwargs)
211  {
212  PyThreadStateReleaser stateReleaser{};
213  QEventLoop loop;
214  QFutureWatcher<py::object> watcher;
215  QObject::connect(&watcher, &decltype(watcher)::finished, &loop, &decltype(loop)::quit);
216  QFuture<py::object> future =
217  QtConcurrent::run(call_fn, stateReleaser.state, callable, args, kwargs);
218  watcher.setFuture(future);
219  loop.exec();
220 
221  return future.result();
222  },
223  "callable"_a);
224 
225  m.def("RunThread",
226  [](py::object thread)
227  {
228  py::object isAliveMethod = thread.attr("is_alive");
229  thread.attr("start")();
230  while (isAliveMethod())
231  {
232  QCoreApplication::processEvents();
233  }
234  });
235 
236  // Use leading __ to give hints that user should not import this in their scripts
237  m.def("GetGUIInstance", &Runtime::GetInstance, py::return_value_policy::reference);
238  m.def("GetCmdLineInstance", &Runtime::GetCmdLineInstance, py::return_value_policy::reference);
239  m.def(
240  "GetInstance",
241  []() -> py::object
242  {
243  auto guiInstance = Runtime::GetInstance();
244  if (guiInstance)
245  {
246  return py::cast(guiInstance);
247  }
248  else
249  {
250  return py::cast(Runtime::GetCmdLineInstance());
251  }
252  },
253  py::return_value_policy::reference);
254 }
void define_ccGUIPythonInstance(py::module &)
void define_ccCommandLine(py::module &)
PYBIND11_EMBEDDED_MODULE(ccinternals, m)
Definition: Runtime.cpp:117
py::object call_fn(PyThreadState *main_state, py::object callable, py::args args, py::kwargs kwargs)
Definition: Threading.h:79
bool isatty() const
Definition: Consoles.h:140
void flush() const
Definition: Consoles.h:145
void write(const char *messagePart)
Definition: Consoles.h:129
Interface that 'class-style' PythonPlugin must implement to be loaded.
Definition: Runtime.cpp:33
virtual py::object getIcon()
Definition: Runtime.cpp:37
virtual ~PythonPluginInterface()=default
virtual std::vector< Runtime::RegisteredPlugin::Action > getActions()=0
std::vector< Runtime::RegisteredPlugin::Action > getActions() override
Definition: Runtime.cpp:54
py::object getIcon() override
Definition: Runtime.cpp:61
Command line interface.
bool isatty() const
Definition: Consoles.h:94
void write(const char *messagePart)
Definition: Consoles.h:82
void flush() const
Definition: Consoles.h:99
Main application interface (for plugins)
void setMainAppInterfaceInstance(ecvMainAppInterface *appInterface) noexcept(false)
Definition: Runtime.cpp:82
void unsetMainAppInterfaceInstance() noexcept
Unsets the app interface pointer.
Definition: Runtime.cpp:90
void setCmdLineInterfaceInstance(ccCommandLineInterface *cmdLine) noexcept
Definition: Runtime.cpp:99
ccGuiPythonInstance * GetInstance() noexcept
Definition: Runtime.cpp:72
ccCommandLineInterface * GetCmdLineInstance() noexcept
Definition: Runtime.cpp:77
void unsetCmdLineInterfaceInstance() noexcept
Unsets the pointer to the cmdline app interface.
Definition: Runtime.cpp:107
static ccGuiPythonInstance * s_pythonInstance
Definition: Runtime.cpp:68
static ccCommandLineInterface * s_cmdLineInstance
Definition: Runtime.cpp:70