MRPT  2.0.4
WxSubsystem.h
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 #pragma once
10 
11 #include <mrpt/config.h>
12 #include <mrpt/gui/gui_frwds.h>
14 #include <mrpt/math/TPoint2D.h>
16 #include <future>
17 #include <map>
18 #include <mutex>
19 #include <queue>
20 #include <thread>
21 
22 #if MRPT_HAS_WXWIDGETS
23 
24 #include <wx/app.h>
25 #include <wx/artprov.h>
26 #include <wx/bitmap.h>
27 #include <wx/busyinfo.h>
28 #include <wx/colordlg.h>
29 #include <wx/dcmemory.h>
30 #include <wx/dirdlg.h>
31 #include <wx/filedlg.h>
32 #include <wx/frame.h>
33 #include <wx/image.h>
34 #include <wx/imaglist.h>
35 #include <wx/intl.h>
36 #include <wx/log.h>
37 #include <wx/menu.h>
38 #include <wx/msgdlg.h>
39 #include <wx/pen.h>
40 #include <wx/progdlg.h>
41 #include <wx/sizer.h>
42 #include <wx/statbmp.h>
43 #include <wx/statusbr.h>
44 #include <wx/string.h>
45 #include <wx/textdlg.h>
46 #include <wx/timer.h>
47 #include <wx/toolbar.h>
48 
49 // The wxMathPlot library
50 #include <mrpt/3rdparty/mathplot/mathplot.h>
51 
52 #if 0
53 // The wxFreeChart library
54 #include <wx/bars/barplot.h>
55 #include <wx/chartpanel.h>
56 
57 #include <wx/axis/categoryaxis.h>
58 #include <wx/axis/dateaxis.h>
59 #include <wx/axis/numberaxis.h>
60 
61 #include <wx/xy/xydataset.h>
62 #include <wx/xy/xyhistorenderer.h>
63 #include <wx/xy/xylinerenderer.h>
64 #include <wx/xy/xyplot.h>
65 #include <wx/xy/xysimpledataset.h>
66 
67 #include <wx/xyz/bubbleplot.h>
68 #include <wx/xyz/xyzdataset.h>
69 
70 #include <wx/category/categorydataset.h>
71 #include <wx/category/categorysimpledataset.h>
72 #endif
73 
74 #endif
75 #include <mrpt/gui/gui_frwds.h>
76 
77 namespace mrpt::gui
78 {
79 /** This class implements the GUI thread required for the wxWidgets-based GUI.
80  * This system is employed internally by gui::CDisplayWindow and
81  * gui::CDisplayWindow3D, and must be not used in any way directly by the MRPT
82  * user.
83  *
84  * The system works by creating a invisible wxFrame that process timer events
85  * where it checks a queue of requests sent from the main MRPT thread. The
86  * requests include the creation, deletion,... of windows (2D/3D). In that
87  * way, just one thread is required for all the GUI windows, and the wxWidgets
88  * is initialized and clean-up correctly.
89  *
90  * This header should be included just from the implementation files of
91  * CDisplayWindow and CDisplayWindow3D, since it uses wxWidgets classes.
92  *
93  * \sa gui::CDisplayWindow, gui::CDisplayWindow3D
94  * \ingroup mrpt_gui_grp
95  */
97 {
98 #if MRPT_HAS_WXWIDGETS
99 
100  public:
101  /** This method must be called in the destructor of the user class FROM THE
102  * MAIN THREAD, in order to wait for the shutdown of the wx thread if this
103  * was the last open window.
104  */
105  static void waitWxShutdownsIfNoWindows();
106 
107  /** Will be set to true at runtime if it's not detected a running wxApp
108  * instance.
109  * For console apps, we'll create a new thread and run wxEntry from there.
110  * For GUI apps (MRPT-based Windows are a part of a user wxWidget apps),
111  * we must leave the control of
112  * message dispatching to the current main loop, so we cannot create a
113  * different threads, making things a little different (hence this
114  * variable).
115  */
116  static bool isConsoleApp();
117 
118  /** An auxiliary global object used just to launch a final request to the
119  * wxSubsystem for shutdown:
120  */
122  {
123  public:
126  };
127 
129 
130  /** The main frame of the wxWidgets application
131  */
132  class CWXMainFrame : public wxFrame
133  {
135 
136  public:
137  CWXMainFrame(wxWindow* parent, wxWindowID id = -1);
138  ~CWXMainFrame() override;
139 
140  /** Atomically increments the number of windows created with the main
141  * frame as parent.
142  * \return The updated number of windows.
143  */
144  static int notifyWindowCreation();
145 
146  /** Atomically decrements the number of windows created with the main
147  * frame as parent.
148  * \return The updated number of windows (0 if the calling was the last
149  * one).
150  */
151  static int notifyWindowDestruction();
152 
153  static volatile CWXMainFrame* oneInstance;
154 
155  private:
156  static std::mutex cs_windowCount;
157  static int m_windowCount;
158 
159  wxTimer* m_theTimer;
160 
161  void OnTimerProcessRequests(wxTimerEvent& event);
162 
163  DECLARE_EVENT_TABLE()
164 
165  }; // end class CWXMainFrame
166 
168  {
169  /** The thread ID of wxMainThread, or 0 if it is not running. */
170  std::thread m_wxMainThreadId;
171  /** This is signaled when wxMainThread is ready. */
172  std::promise<void> m_semWxMainThreadReady;
173  std::promise<void> m_done;
174  /** The critical section for accessing "m_wxMainThreadId" */
175  std::mutex m_csWxMainThreadId;
176  };
177 
179 
180  /** This will be the "MAIN" of wxWidgets: It starts an application object
181  * and does not end until all the windows are closed.
182  * Only one instance of this thread can be running at a given instant, no
183  * matter how many windows are open.
184  */
185  static void wxMainThread();
186 
187  /** The data structure for each inter-thread request:
188  */
190  {
191  TRequestToWxMainThread() = default;
192 
193  /** Only one of source* can be non-nullptr, indicating the class that
194  * generated the request. */
196 
197  /** Only one of source* can be non-nullptr, indicating the class that
198  * generated the request. */
200 
201  /** Only one of source* can be non-nullptr, indicating the class that
202  * generated the request. */
204 
205  /** Only one of source* can be non-nullptr, indicating the class that
206  * generated the request. */
208 
209  /** Parameters, depending on OPCODE.
210  */
211  std::string str;
212 
213  /** Parameters, depending on OPCODE.
214  */
215  void *voidPtr{nullptr}, *voidPtr2{nullptr};
216  int x{400}, y{400};
217  bool boolVal{false};
219  std::string plotName;
220 
221  /** Valid codes are:
222  * For CDisplayWindow:
223  * - 200: Create a new 2D window, with caption "str" and initial
224  *size "x" & "y", and save the "wxFrame*" in the "void**" passed in
225  *voidPtr.
226  * - 201: Updates the image shown in the window, from a "wxImage*"
227  *passed in voidPtr2. The wxImage object will be freed with delete
228  *after that. voidPtr must be a "wxFrame*", a "CWindowDialog*"
229  *actually.
230  * - 202: Set position to x,y
231  * - 203: Change size to x,y
232  * - 204: Change title to "str"
233  * - 299: Delete the window associated with this source object.
234  *
235  * For CDisplayWindow3D:
236  * - 300: Create a new 3D window, with caption "str" and initial
237  *size "x" & "y", and save the "wxFrame*" in the "void**" passed in
238  *voidPtr.
239  * - 302: Set position to x,y
240  * - 303: Change size to x,y
241  * - 304: Change title to "str"
242  * - 350: Force refresh
243  * - [Removed in MRPT2] 360: Add a 2D text message:
244  * - [Removed in MRPT2] 361: Clear all 2D text messages.
245  * - [Removed in MRPT2] 362: Add a 2D text message (vector font)
246  * - 370: Change min/max range: min=vector_x[0], max=vector_x[1]
247  * - 399: Delete the window associated with this source object.
248  *
249  * For CDisplayWindowPlots:
250  * - 400: Create a new Plots window, with caption "str" and initial
251  *size "x" & "y",and save the "wxFrame*" in the "void**" passed in
252  *voidPtr.
253  * - 402: Set position to x,y
254  * - 403: Change size to x,y
255  * - 404: Change title to "str"
256  * - 499: Delete the window associated with this source object.
257  * - 410: Depending on "boolVal", enable/disable the mouse-zoom &
258  *pan
259  * - 411: Depending on "boolVal", enable/disable the aspect ratio
260  *fix
261  * - 412: Zoom over a rectangle vectorx[0-1] & vectory[0-1]
262  * - 413: Axis fit, with aspect ratio fix to boolVal.
263  * - 414: Clear all plot objects.
264  * - 420: Add/update a 2D line/points plot: x/y data=
265  *vector_x/vector_y, format string=str, plot name =plotName.
266  * - 421: Add/update a 2D ellipse: format string=str, plot name
267  *=plotName, vector_x[0,1]:X/Y center, vector_x[2]:quantiles,
268  *vector_y[0,1,2]: Covariance matrix entries 00,11,01,
269  *boolVal=showName?
270  * - 422: Add/update a bitmap: plot name =plotName,
271  *vector_x[0,1]:X/Y
272  *corner, vector_x[2,3]: X/Y widths, voidPtr2: pointer to a newly
273  *created wxImage with the bitmap.
274  * - 440: Insert submenu in the popup menu. plotName=menu label,
275  *x=user-defined ID.
276  * - 700: Shows a camera-pick-dialog and wait for user selection.
277  *"voidPtr" must point to a CSemaphore, which will be signaled twice
278  *(1st upon construction, 2nd upon dialog close); voidPtr2 must point
279  *to a "mrpt::gui::CPanelCameraSelection*" which will be filled with
280  *the selection (the panel must be deleted by the caller)
281  *
282  */
283  int OPCODE;
284  };
285 
286  /** Thread-safe method to return the next pending request, or nullptr if
287  * there is none (After usage, FREE the memory!)
288  */
290 
291  /** Thread-safe method to insert a new pending request (The memory must be
292  * dinamically allocated with "new T[1]", will be freed by receiver.)
293  */
295 
296  /** Thread-safe method to create one single instance of the main wxWidgets
297  * thread: it will create the thread only if it is not running yet.
298  */
299  static bool createOneInstanceMainThread();
300 
301  static wxBitmap getMRPTDefaultIcon();
302 
303  private:
304  /** Do not access directly to this, use the thread-safe functions
305  */
306  static std::queue<TRequestToWxMainThread*>* listPendingWxRequests;
307  static std::mutex* cs_listPendingWxRequests;
308 #endif
309 }; // End of class def.
310 
311 #if MRPT_HAS_WXWIDGETS
312 
313 /** The wx dialog for gui::CDisplayWindow
314  */
315 class CWindowDialog : public wxFrame
316 {
317  public:
318  /** A custom control to display the bitmap and avoid flicker
319  */
320  class wxMRPTImageControl : public wxPanel
321  {
322  protected:
323  std::unique_ptr<wxBitmap> m_img;
324  std::mutex m_img_cs;
326 
327  public:
329  wxWindow* parent, wxWindowID winID, int x, int y, int width,
330  int height);
331  ~wxMRPTImageControl() override;
332 
334  // std::mutex m_mouse_cs;
335 
336  /** Assigns this image. This object has the ownship of the image and
337  * will delete it when appropriate. */
338  void AssignImage(wxBitmap* img);
339  void GetBitmap(wxBitmap& bmp);
340 
341  void OnPaint(wxPaintEvent& ev);
342  void OnMouseMove(wxMouseEvent& ev);
343  void OnMouseClick(wxMouseEvent& ev);
344  void OnChar(wxKeyEvent& ev);
345 
346  void OnEraseBackground(wxEraseEvent& ev)
347  { /* Do nothing */
348  }
349  };
350 
351  public:
354  wxWindowID id = -1,
355  const std::string& caption = std::string("[MRPT-CDisplayWindow]"),
356  wxSize initialSize = wxDefaultSize);
357  ~CWindowDialog() override;
358 
361 
362  // wxStaticBitmap *m_image;
364 
365  static const long ID_IMAGE_BITMAP;
366 
367  private:
368  void OnClose(wxCloseEvent& event);
369  void OnMenuClose(wxCommandEvent& event);
370  void OnMenuAbout(wxCommandEvent& event);
371  void OnMenuSave(wxCommandEvent& event);
372  void OnChar(wxKeyEvent& event);
373  void OnKeyDown(wxKeyEvent& event);
374  void OnResize(wxSizeEvent& event);
375  void OnMouseDown(wxMouseEvent& event);
376  void OnMouseMove(wxMouseEvent& event);
377 
378  DECLARE_EVENT_TABLE()
379 }; // end class CWindowDialog
380 
381 class C3DWindowDialog : public wxFrame
382 {
384 
385  public:
388  wxWindowID id = -1,
389  const std::string& caption = std::string("[MRPT-CDisplayWindow3D]"),
390  wxSize initialSize = wxDefaultSize);
391  ~C3DWindowDialog() override;
392 
395 
396  CMyGLCanvas_DisplayWindow3D* m_canvas;
397 
398  private:
399  void OnClose(wxCloseEvent& event);
400  void OnMenuClose(wxCommandEvent& event);
401  void OnMenuAbout(wxCommandEvent& event);
402  void OnChar(wxKeyEvent& event);
403  void OnResize(wxSizeEvent& event);
404 
405  static const long ID_MENUITEM1;
406  static const long ID_MENUITEM2;
407 
408  DECLARE_EVENT_TABLE()
409 };
410 
411 /** The wx dialog for gui::CDisplayWindowPlots
412  */
413 class CWindowDialogPlots : public wxFrame
414 {
415  public:
418  wxWindowID id = -1,
419  const std::string& caption = std::string("[MRPT-CDisplayWindowPlots]"),
420  wxSize initialSize = wxDefaultSize);
421  ~CWindowDialogPlots() override;
422 
425 
426  mpWindow* m_plot;
427  // wxChartPanel *m_chartPanel;
428  static const long ID_PLOT;
429  static const long ID_MENU_PRINT;
430  /** to know whether to insert a separator the first time. */
432  /** wxIDs to user IDs for submenus. */
433  std::map<long, long> m_ID2ID;
434  /** In graph coords */
436  /** In pixels */
438 
439  void OnMenuSelected(wxCommandEvent& ev);
440  void OnMouseMove(wxMouseEvent& event);
441 
442  /** Redirected from CDisplayWindowPlots::plot
443  */
444  void plot(
446  const std::string& lineFormat, const std::string& plotName);
447 
448  /** Redirected from CDisplayWindowPlots::plotEllipse
449  */
450  void plotEllipse(
452  const std::string& lineFormat, const std::string& plotName,
453  bool showName = false);
454 
455  /** Redirected from CDisplayWindowPlots::image
456  */
457  void image(
458  void* theWxImage, float x0, float y0, float w, float h,
459  const std::string& plotName);
460 
461  private:
462  void OnClose(wxCloseEvent& event);
463  void OnMenuPrint(wxCommandEvent& event);
464  void OnMenuClose(wxCommandEvent& event);
465  void OnMenuAbout(wxCommandEvent& event);
466  void OnChar(wxKeyEvent& event);
467  void OnResize(wxSizeEvent& event);
468  void OnMouseDown(wxMouseEvent& event);
469 
470  DECLARE_EVENT_TABLE()
471 }; // end class CWindowDialog
472 
473 #endif
474 
475 } // namespace mrpt::gui
An auxiliary global object used just to launch a final request to the wxSubsystem for shutdown: ...
Definition: WxSubsystem.h:121
std::map< long, long > m_ID2ID
wxIDs to user IDs for submenus.
Definition: WxSubsystem.h:433
static void pushPendingWxRequest(TRequestToWxMainThread *data)
Thread-safe method to insert a new pending request (The memory must be dinamically allocated with "ne...
void * voidPtr
Parameters, depending on OPCODE.
Definition: WxSubsystem.h:215
void OnMenuAbout(wxCommandEvent &event)
static TRequestToWxMainThread * popPendingWxRequest()
Thread-safe method to return the next pending request, or nullptr if there is none (After usage...
void OnClose(wxCloseEvent &event)
mrpt::gui::CDisplayWindow3D * source3D
Only one of source* can be non-nullptr, indicating the class that generated the request.
Definition: WxSubsystem.h:199
void OnMenuSave(wxCommandEvent &event)
friend class gui::CMyGLCanvas_DisplayWindow3D
Definition: WxSubsystem.h:383
void OnResize(wxSizeEvent &event)
The data structure for each inter-thread request:
Definition: WxSubsystem.h:189
Template for column vectors of dynamic size, compatible with Eigen.
Create a GUI window and display plots with MATLAB-like interfaces and commands.
static int notifyWindowCreation()
Atomically increments the number of windows created with the main frame as parent.
void AssignImage(wxBitmap *img)
Assigns this image.
void OnTimerProcessRequests(wxTimerEvent &event)
This method processes the pending requests from the main MRPT application thread. ...
static std::mutex * cs_listPendingWxRequests
Definition: WxSubsystem.h:307
std::thread m_wxMainThreadId
The thread ID of wxMainThread, or 0 if it is not running.
Definition: WxSubsystem.h:170
void OnMenuClose(wxCommandEvent &event)
The wx dialog for gui::CDisplayWindowPlots.
Definition: WxSubsystem.h:413
void OnMenuClose(wxCommandEvent &event)
wxPoint m_last_mouse_point
In pixels.
Definition: WxSubsystem.h:437
static wxBitmap getMRPTDefaultIcon()
CDisplayWindow3D * m_win3D
Definition: WxSubsystem.h:393
static volatile CWXMainFrame * oneInstance
Definition: WxSubsystem.h:153
C3DWindowDialog(CDisplayWindow3D *win3D, WxSubsystem::CWXMainFrame *parent, wxWindowID id=-1, const std::string &caption=std::string("[MRPT-CDisplayWindow3D]"), wxSize initialSize=wxDefaultSize)
std::mutex m_csWxMainThreadId
The critical section for accessing "m_wxMainThreadId".
Definition: WxSubsystem.h:175
static TWxMainThreadData & GetWxMainThreadInstance()
wxMRPTImageControl(wxWindow *parent, wxWindowID winID, int x, int y, int width, int height)
void OnResize(wxSizeEvent &event)
WxSubsystem::CWXMainFrame * m_mainFrame
Definition: WxSubsystem.h:424
int OPCODE
Valid codes are: For CDisplayWindow:
Definition: WxSubsystem.h:283
void OnChar(wxKeyEvent &event)
static std::queue< TRequestToWxMainThread * > * listPendingWxRequests
Do not access directly to this, use the thread-safe functions.
Definition: WxSubsystem.h:306
static const long ID_MENUITEM1
Definition: WxSubsystem.h:405
CWindowDialogPlots(CDisplayWindowPlots *winPlots, WxSubsystem::CWXMainFrame *parent, wxWindowID id=-1, const std::string &caption=std::string("[MRPT-CDisplayWindowPlots]"), wxSize initialSize=wxDefaultSize)
wxMRPTImageControl * m_image
Definition: WxSubsystem.h:363
CDisplayWindowPlots * m_winPlots
Definition: WxSubsystem.h:423
static const long ID_PLOT
Definition: WxSubsystem.h:428
void OnKeyDown(wxKeyEvent &event)
void OnMouseDown(wxMouseEvent &event)
void OnMenuClose(wxCommandEvent &event)
void OnMenuSelected(wxCommandEvent &ev)
CWXMainFrame(wxWindow *parent, wxWindowID id=-1)
A custom control to display the bitmap and avoid flicker.
Definition: WxSubsystem.h:320
mrpt::math::TPoint2D m_curCursorPos
In graph coords.
Definition: WxSubsystem.h:435
std::promise< void > m_semWxMainThreadReady
This is signaled when wxMainThread is ready.
Definition: WxSubsystem.h:172
This class creates a window as a graphical user interface (GUI) for displaying images to the user...
void plot(const mrpt::math::CVectorFloat &x, const mrpt::math::CVectorFloat &y, const std::string &lineFormat, const std::string &plotName)
Redirected from CDisplayWindowPlots::plot.
The main frame of the wxWidgets application.
Definition: WxSubsystem.h:132
CDisplayWindow * m_win2D
Definition: WxSubsystem.h:359
The wx dialog for gui::CDisplayWindow.
Definition: WxSubsystem.h:315
bool sourceCameraSelectDialog
Only one of source* can be non-nullptr, indicating the class that generated the request.
Definition: WxSubsystem.h:207
void OnMouseMove(wxMouseEvent &event)
static void wxMainThread()
This will be the "MAIN" of wxWidgets: It starts an application object and does not end until all the ...
void OnChar(wxKeyEvent &event)
void OnMouseMove(wxMouseEvent &event)
static void waitWxShutdownsIfNoWindows()
This method must be called in the destructor of the user class FROM THE MAIN THREAD, in order to wait for the shutdown of the wx thread if this was the last open window.
static const long ID_MENU_PRINT
Definition: WxSubsystem.h:429
WxSubsystem::CWXMainFrame * m_mainFrame
Definition: WxSubsystem.h:360
void OnResize(wxSizeEvent &event)
This class implements the GUI thread required for the wxWidgets-based GUI.
Definition: WxSubsystem.h:96
void OnClose(wxCloseEvent &event)
void OnMenuAbout(wxCommandEvent &event)
void plotEllipse(const mrpt::math::CVectorFloat &x, const mrpt::math::CVectorFloat &y, const std::string &lineFormat, const std::string &plotName, bool showName=false)
Redirected from CDisplayWindowPlots::plotEllipse.
static const long ID_IMAGE_BITMAP
Definition: WxSubsystem.h:365
void OnMouseDown(wxMouseEvent &event)
CWindowDialog(CDisplayWindow *win2D, WxSubsystem::CWXMainFrame *parent, wxWindowID id=-1, const std::string &caption=std::string("[MRPT-CDisplayWindow]"), wxSize initialSize=wxDefaultSize)
static CAuxWxSubsystemShutdowner global_wxsubsystem_shutdown
Definition: WxSubsystem.h:128
mrpt::gui::CDisplayWindowPlots * sourcePlots
Only one of source* can be non-nullptr, indicating the class that generated the request.
Definition: WxSubsystem.h:203
static bool isConsoleApp()
Will be set to true at runtime if it&#39;s not detected a running wxApp instance.
Definition: WxSubsystem.cpp:53
void OnClose(wxCloseEvent &event)
void image(void *theWxImage, float x0, float y0, float w, float h, const std::string &plotName)
Redirected from CDisplayWindowPlots::image.
Classes for creating GUI windows for 2D and 3D visualization.
Definition: about_box.h:14
void OnMenuPrint(wxCommandEvent &event)
mrpt::gui::CDisplayWindow * source2D
Only one of source* can be non-nullptr, indicating the class that generated the request.
Definition: WxSubsystem.h:195
void OnMenuAbout(wxCommandEvent &event)
std::string str
Parameters, depending on OPCODE.
Definition: WxSubsystem.h:211
WxSubsystem::CWXMainFrame * m_mainFrame
Definition: WxSubsystem.h:394
static const long ID_MENUITEM2
Definition: WxSubsystem.h:406
static bool createOneInstanceMainThread()
Thread-safe method to create one single instance of the main wxWidgets thread: it will create the thr...
static int notifyWindowDestruction()
Atomically decrements the number of windows created with the main frame as parent.
CMyGLCanvas_DisplayWindow3D * m_canvas
Definition: WxSubsystem.h:396
A graphical user interface (GUI) for efficiently rendering 3D scenes in real-time.
static struct FontData data
Definition: gltext.cpp:144
bool m_firstSubmenu
to know whether to insert a separator the first time.
Definition: WxSubsystem.h:431



Page generated by Doxygen 1.8.14 for MRPT 2.0.4 Git: 7b5ddf9de Fri May 29 14:02:56 2020 +0200 at vie may 29 14:15:09 CEST 2020