Main MRPT website > C++ reference
MRPT logo
WxSubsystem.h
Go to the documentation of this file.
1 /* +---------------------------------------------------------------------------+
2  | The Mobile Robot Programming Toolkit (MRPT) C++ library |
3  | |
4  | http://www.mrpt.org/ |
5  | |
6  | Copyright (C) 2005-2012 University of Malaga |
7  | |
8  | This software was written by the Machine Perception and Intelligent |
9  | Robotics Lab, University of Malaga (Spain). |
10  | Contact: Jose-Luis Blanco <jlblanco@ctima.uma.es> |
11  | |
12  | This file is part of the MRPT project. |
13  | |
14  | MRPT is free software: you can redistribute it and/or modify |
15  | it under the terms of the GNU General Public License as published by |
16  | the Free Software Foundation, either version 3 of the License, or |
17  | (at your option) any later version. |
18  | |
19  | MRPT is distributed in the hope that it will be useful, |
20  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
21  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22  | GNU General Public License for more details. |
23  | |
24  | You should have received a copy of the GNU General Public License |
25  | along with MRPT. If not, see <http://www.gnu.org/licenses/>. |
26  | |
27  +---------------------------------------------------------------------------+ */
28 #ifndef MRPT_WX_SUBSYSTEM_H
29 #define MRPT_WX_SUBSYSTEM_H
30 
32 #include <mrpt/utils/utils_defs.h>
33 #include <mrpt/system/threads.h>
34 #include <mrpt/config.h>
35 #include <mrpt/synch.h>
37 
38 #include <mrpt/gui/link_pragmas.h>
39 
40 #include <queue>
41 
42 #if MRPT_HAS_WXWIDGETS
43 
44 // This is to prevent wxWidgets to include winsock.h, and
45 // later the user to include winsock2.h, what leads to conflicts:
46 //#ifdef HAVE_WINSOCK2_H
47 //# include <winsock2.h>
48 //#endif
49 
50 #include <wx/sizer.h>
51 #include <wx/statbmp.h>
52 #include <wx/menu.h>
53 #include <wx/toolbar.h>
54 #include <wx/frame.h>
55 #include <wx/timer.h>
56 #include <wx/statusbr.h>
57 #include <wx/msgdlg.h>
58 #include <wx/artprov.h>
59 #include <wx/bitmap.h>
60 #include <wx/intl.h>
61 #include <wx/image.h>
62 #include <wx/string.h>
63 #include <wx/msgdlg.h>
64 #include <wx/filedlg.h>
65 #include <wx/progdlg.h>
66 #include <wx/imaglist.h>
67 #include <wx/busyinfo.h>
68 #include <wx/log.h>
69 #include <wx/textdlg.h>
70 #include <wx/dirdlg.h>
71 #include <wx/colordlg.h>
72 #include <wx/dcmemory.h>
73 #include <wx/app.h>
74 #include <wx/pen.h>
75 
76 // The wxMathPlot library
78 
79 #if 0
80 // The wxFreeChart library
81 #include <wx/chartpanel.h>
82 #include <wx/bars/barplot.h>
83 
84 #include <wx/axis/numberaxis.h>
85 #include <wx/axis/categoryaxis.h>
86 #include <wx/axis/dateaxis.h>
87 
88 #include <wx/xy/xyhistorenderer.h>
89 #include <wx/xy/xydataset.h>
90 #include <wx/xy/xylinerenderer.h>
91 #include <wx/xy/xyplot.h>
92 #include <wx/xy/xysimpledataset.h>
93 
94 #include <wx/xyz/xyzdataset.h>
95 #include <wx/xyz/bubbleplot.h>
96 
97 #include <wx/category/categorydataset.h>
98 #include <wx/category/categorysimpledataset.h>
99 #endif
100 
101 #endif
102 
103 namespace mrpt
104 {
105  namespace gui
106  {
107  using namespace mrpt::system;
108 
109  class CDisplayWindow;
110  class CDisplayWindow3D;
111  class CDisplayWindowPlots;
112  class CMyGLCanvas_DisplayWindow3D;
113 
114  /** This class implements the GUI thread required for the wxWidgets-based GUI.
115  * This system is employed internally by gui::CDisplayWindow and gui::CDisplayWindow3D, and must be not used in any way directly by the MRPT user.
116  *
117  * The system works by creating a invisible wxFrame that process timer events where it checks a queue of requests sent from the main MRPT thread. The
118  * requests include the creation, deletion,... of windows (2D/3D). In that way, just one thread is required for all the GUI windows, and the wxWidgets
119  * is initialized and clean-up correctly.
120  *
121  * This header should be included just from the implementation files of CDisplayWindow and CDisplayWindow3D, since it uses wxWidgets classes.
122  *
123  * \sa gui::CDisplayWindow, gui::CDisplayWindow3D
124  * \ingroup mrpt_gui_grp
125  */
127  {
128  #if MRPT_HAS_WXWIDGETS
129 
130  public:
131 
132  /** 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.
133  */
134  static void waitWxShutdownsIfNoWindows();
135 
136  /** Will be set to true at runtime if it's not detected a running wxApp instance.
137  * For console apps, we'll create a new thread and run wxEntry from there.
138  * For GUI apps (MRPT-based Windows are a part of a user wxWidget apps), we must leave the control of
139  * message dispatching to the current main loop, so we cannot create a different threads, making things a little different (hence this variable).
140  */
141  static volatile bool isConsoleApp;
142 
143  /** An auxiliary global object used just to launch a final request to the wxSubsystem for shutdown:
144  */
145  class CAuxWxSubsystemShutdowner
146  {
147  public:
148  CAuxWxSubsystemShutdowner();
149  ~CAuxWxSubsystemShutdowner();
150  };
151 
152  static CAuxWxSubsystemShutdowner global_wxsubsystem_shutdown;
153 
154 
155  /** The main frame of the wxWidgets application
156  */
157  class CWXMainFrame: public wxFrame
158  {
159  friend void WxSubsystem::waitWxShutdownsIfNoWindows();
160 
161  public:
162  CWXMainFrame(wxWindow* parent,wxWindowID id = -1);
163  virtual ~CWXMainFrame();
164 
165  /** Atomically increments the number of windows created with the main frame as parent.
166  * \return The updated number of windows.
167  */
168  static int notifyWindowCreation();
169 
170  /** Atomically decrements the number of windows created with the main frame as parent.
171  * \return The updated number of windows (0 if the calling was the last one).
172  */
173  static int notifyWindowDestruction();
174 
175  static volatile CWXMainFrame* oneInstance;
176 
177 
178  private:
179 
180  static synch::CCriticalSection cs_windowCount;
181  static int m_windowCount;
182 
183  wxTimer *m_theTimer;
184 
185  void OnTimerProcessRequests(wxTimerEvent& event);
186 
187  DECLARE_EVENT_TABLE()
188 
189  }; // end class CWXMainFrame
190 
191  struct TWxMainThreadData
192  {
193  TWxMainThreadData();
194 
195  /** The thread ID of wxMainThread, or 0 if it is not running.
196  */
197  TThreadHandle m_wxMainThreadId;
198 
199  /** This is signaled when wxMainThread is ready.
200  */
201  synch::CSemaphore m_semWxMainThreadReady;
202 
203  /** The critical section for accessing "m_wxMainThreadId"
204  */
205  synch::CCriticalSection m_csWxMainThreadId;
206  };
207 
208  static TWxMainThreadData& GetWxMainThreadInstance();
209 
210 
211  /** This will be the "MAIN" of wxWidgets: It starts an application object and does not end until all the windows are closed.
212  * Only one instance of this thread can be running at a given instant, no matter how many windows are open.
213  */
214  static void wxMainThread();
215 
216  /** The data structure for each inter-thread request:
217  */
218  struct GUI_IMPEXP TRequestToWxMainThread
219  {
220  TRequestToWxMainThread() :
221  source2D ( NULL ),
222  source3D ( NULL ),
223  sourcePlots ( NULL ),
224  sourceCameraSelectDialog(false),
225  voidPtr (NULL),
226  voidPtr2 (NULL),
227  x (400),
228  y (400),
229  boolVal (false)
230  { }
231 
232  /** Only one of source* can be non-NULL, indicating the class that generated the request. */
233  gui::CDisplayWindow *source2D;
234 
235  /** Only one of source* can be non-NULL, indicating the class that generated the request. */
236  gui::CDisplayWindow3D *source3D;
237 
238  /** Only one of source* can be non-NULL, indicating the class that generated the request. */
239  gui::CDisplayWindowPlots *sourcePlots;
240 
241  /** Only one of source* can be non-NULL, indicating the class that generated the request. */
242  bool sourceCameraSelectDialog;
243 
244  /** Parameters, depending on OPCODE.
245  */
246  std::string str;
247 
248  /** Parameters, depending on OPCODE.
249  */
250  void *voidPtr, *voidPtr2;
251  int x,y;
252  bool boolVal;
253  vector_float vector_x,vector_y;
254  std::string plotName;
255 
256  /** Valid codes are:
257  * For CDisplayWindow:
258  * - 200: Create a new 2D window, with caption "str" and initial size "x" & "y", and save the "wxFrame*" in the "void**" passed in voidPtr.
259  * - 201: Updates the image shown in the window, from a "wxImage*" passed in voidPtr2. The wxImage object will be freed with delete after that. voidPtr must be a "wxFrame*", a "CWindowDialog*" actually.
260  * - 202: Set position to x,y
261  * - 203: Change size to x,y
262  * - 204: Change title to "str"
263  * - 299: Delete the window associated with this source object.
264  *
265  * For CDisplayWindow3D:
266  * - 300: Create a new 3D window, with caption "str" and initial size "x" & "y", and save the "wxFrame*" in the "void**" passed in voidPtr.
267  * - 302: Set position to x,y
268  * - 303: Change size to x,y
269  * - 304: Change title to "str"
270  * - 350: Force refresh
271  * - 360: Add a 2D text message: vector_x: [0]:x, [1]:y, [2,3,4]:R G B, "x": enum of desired font. "y": unique index, "str": String.
272  * - 361: Clear all 2D text messages.
273  * - 362: Add a 2D text message (vectorized fonts)
274  * - 370: Change min/max range: min=vector_x[0], max=vector_x[1]
275  * - 399: Delete the window associated with this source object.
276  *
277  * For CDisplayWindowPlots:
278  * - 400: Create a new Plots window, with caption "str" and initial size "x" & "y",and save the "wxFrame*" in the "void**" passed in voidPtr.
279  * - 402: Set position to x,y
280  * - 403: Change size to x,y
281  * - 404: Change title to "str"
282  * - 499: Delete the window associated with this source object.
283  * - 410: Depending on "boolVal", enable/disable the mouse-zoom & pan
284  * - 411: Depending on "boolVal", enable/disable the aspect ratio fix
285  * - 412: Zoom over a rectangle vectorx[0-1] & vectory[0-1]
286  * - 413: Axis fit, with aspect ratio fix to boolVal.
287  * - 414: Clear all plot objects.
288  * - 420: Add/update a 2D line/points plot: x/y data= vector_x/vector_y, format string=str, plot name =plotName.
289  * - 421: Add/update a 2D ellipse: format string=str, plot name =plotName, vector_x[0,1]:X/Y center, vector_x[2]:quantiles, vector_y[0,1,2]: Covariance matrix entries 00,11,01, boolVal=showName?
290  * - 422: Add/update a bitmap: plot name =plotName, vector_x[0,1]:X/Y corner, vector_x[2,3]: X/Y widths, voidPtr2: pointer to a newly created wxImage with the bitmap.
291  * - 440: Insert submenu in the popup menu. plotName=menu label, x=user-defined ID.
292  * - 700: Shows a camera-pick-dialog and wait for user selection. "voidPtr" must point to a CSemaphore, which will be signaled twice (1st upon construction, 2nd upon dialog close); voidPtr2 must point to a "mrpt::gui::CPanelCameraSelection*" which will be filled with the selection (the panel must be deleted by the caller)
293  *
294  */
295  int OPCODE;
296 
297  };
298 
299  /** Thread-safe method to return the next pending request, or NULL if there is none (After usage, FREE the memory!)
300  */
301  static TRequestToWxMainThread * popPendingWxRequest();
302 
303  /** Thread-safe method to insert a new pending request (The memory must be dinamically allocated with "new T[1]", will be freed by receiver.)
304  */
305  static void pushPendingWxRequest( TRequestToWxMainThread *data );
306 
307  /** Thread-safe method to create one single instance of the main wxWidgets thread: it will create the thread only if it is not running yet.
308  */
309  static bool createOneInstanceMainThread();
310 
311 
312  static wxBitmap getMRPTDefaultIcon();
313  private:
314  /** Do not access directly to this, use the thread-safe functions
315  */
316  static std::queue<TRequestToWxMainThread*> *listPendingWxRequests;
317  static synch::CCriticalSection *cs_listPendingWxRequests;
318  #endif
319  }; // End of class def.
320 
321 
322  #if MRPT_HAS_WXWIDGETS
323 
324  /** The wx dialog for gui::CDisplayWindow
325  */
326  class CWindowDialog: public wxFrame
327  {
328  public:
329  /** A custom control to display the bitmap and avoid flicker
330  */
331  class wxMRPTImageControl : public wxPanel
332  {
333  protected:
334  wxBitmap *m_img;
336  CDisplayWindow *m_win2D;
337 
338  public:
339  wxMRPTImageControl( wxWindow *parent,wxWindowID winID,int x, int y, int width, int height);
340  virtual ~wxMRPTImageControl();
341 
342  wxPoint m_last_mouse_point, m_last_mouse_click;
343  //mrpt::synch::CCriticalSection m_mouse_cs;
344 
345  void AssignImage(wxBitmap *img); //!< Assigns this image. This object has the ownship of the image and will delete it when appropriate.
346  void GetBitmap(wxBitmap &bmp);
347 
348  void OnPaint(wxPaintEvent &ev);
349  void OnMouseMove(wxMouseEvent& ev);
350  void OnMouseClick(wxMouseEvent& ev);
351  void OnChar(wxKeyEvent& ev);
352 
353  void OnEraseBackground(wxEraseEvent &ev) { /* Do nothing */ }
354  };
355 
356 
357 
358  public:
359  CWindowDialog( CDisplayWindow *win2D, WxSubsystem::CWXMainFrame* parent,wxWindowID id = -1, const std::string &caption = std::string("[MRPT-CDisplayWindow]"), wxSize initialSize = wxDefaultSize );
360  virtual ~CWindowDialog();
361 
362  CDisplayWindow *m_win2D;
363  WxSubsystem::CWXMainFrame *m_mainFrame;
364 
365  //wxStaticBitmap *m_image;
366  wxMRPTImageControl *m_image;
367 
368  static const long ID_IMAGE_BITMAP;
369 
370  private:
371 
372  void OnClose (wxCloseEvent& event);
373  void OnMenuClose(wxCommandEvent& event);
374  void OnMenuAbout(wxCommandEvent& event);
375  void OnMenuSave(wxCommandEvent& event);
376  void OnChar(wxKeyEvent& event);
377  void OnKeyDown(wxKeyEvent& event);
378  void OnResize(wxSizeEvent& event);
379  void OnMouseDown(wxMouseEvent& event);
380 
381  DECLARE_EVENT_TABLE()
382  }; // end class CWindowDialog
383 
384  class C3DWindowDialog: public wxFrame
385  {
386  friend class gui::CMyGLCanvas_DisplayWindow3D;
387 
388  public:
389 
390  C3DWindowDialog(CDisplayWindow3D *win3D, WxSubsystem::CWXMainFrame* parent,wxWindowID id = -1, const std::string &caption = std::string("[MRPT-CDisplayWindow3D]"), wxSize initialSize = wxDefaultSize );
391  virtual ~C3DWindowDialog();
392 
393  CDisplayWindow3D *m_win3D;
394  WxSubsystem::CWXMainFrame *m_mainFrame;
395 
396  CMyGLCanvas_DisplayWindow3D *m_canvas;
397 
398  void clearTextMessages();
399  void addTextMessage(
400  const double x_frac,
401  const double y_frac,
402  const std::string &text,
403  const mrpt::utils::TColorf &color,
404  const size_t unique_index,
405  const mrpt::opengl::TOpenGLFont font
406  );
407  void addTextMessage(
408  const double x_frac,
409  const double y_frac,
410  const std::string &text,
411  const mrpt::utils::TColorf &color,
412  const std::string &font_name,
413  const double font_size,
414  const mrpt::opengl::TOpenGLFontStyle font_style,
415  const size_t unique_index,
416  const double font_spacing,
417  const double font_kerning
418  );
419 
420  private:
421 
422  void OnClose (wxCloseEvent& event);
423  void OnMenuClose(wxCommandEvent& event);
424  void OnMenuAbout(wxCommandEvent& event);
425  void OnChar(wxKeyEvent& event);
426  void OnResize(wxSizeEvent& event);
427 
428  static const long ID_MENUITEM1;
429  static const long ID_MENUITEM2;
430 
431  DECLARE_EVENT_TABLE()
432  };
433 
434  /** The wx dialog for gui::CDisplayWindowPlots
435  */
436  class CWindowDialogPlots: public wxFrame
437  {
438  public:
439  CWindowDialogPlots( CDisplayWindowPlots *winPlots, WxSubsystem::CWXMainFrame* parent,wxWindowID id = -1, const std::string &caption = std::string("[MRPT-CDisplayWindowPlots]"), wxSize initialSize = wxDefaultSize );
440  virtual ~CWindowDialogPlots();
441 
442  CDisplayWindowPlots *m_winPlots;
443  WxSubsystem::CWXMainFrame *m_mainFrame;
444 
445  mpWindow *m_plot;
446  // wxChartPanel *m_chartPanel;
447  static const long ID_PLOT;
448  static const long ID_MENU_PRINT;
449  bool m_firstSubmenu; //!< to know whether to insert a separator the first time.
450  std::map<long,long> m_ID2ID; //!< wxIDs to user IDs for submenus.
451  mrpt::math::TPoint2D m_curCursorPos; //!< In graph coords
452  wxPoint m_last_mouse_point; //!< In pixels
453 
454  void OnMenuSelected(wxCommandEvent& ev);
455  void OnMouseMove(wxMouseEvent& event);
456 
457 
458  /** Redirected from CDisplayWindowPlots::plot
459  */
460  void plot(
461  const vector_float &x,
462  const vector_float &y,
463  const std::string &lineFormat,
464  const std::string &plotName);
465 
466  /** Redirected from CDisplayWindowPlots::plotEllipse
467  */
468  void plotEllipse(
469  const vector_float &x,
470  const vector_float &y,
471  const std::string &lineFormat,
472  const std::string &plotName,
473  bool showName = false);
474 
475  /** Redirected from CDisplayWindowPlots::image
476  */
477  void image(
478  void *theWxImage,
479  const float &x0,
480  const float &y0,
481  const float &w,
482  const float &h,
483  const std::string &plotName);
484 
485  private:
486 
487  void OnClose (wxCloseEvent& event);
488  void OnMenuPrint(wxCommandEvent& event);
489  void OnMenuClose(wxCommandEvent& event);
490  void OnMenuAbout(wxCommandEvent& event);
491  void OnChar(wxKeyEvent& event);
492  void OnResize(wxSizeEvent& event);
493  void OnMouseDown(wxMouseEvent& event);
494 
495  DECLARE_EVENT_TABLE()
496  }; // end class CWindowDialog
497 
498  #ifndef _U
499  #ifdef wxUSE_UNICODE
500  #define _U(x) wxString((x),wxConvUTF8)
501  #define _UU(x,y) wxString((x),y)
502  #else
503  #define _U(x) (x)
504  #define _UU(x,y) (x)
505  #endif
506  #endif
507 
508  #endif
509 
510  } // End of namespace
511 } // End of namespace
512 
513 #endif



Page generated by Doxygen 1.8.3 for MRPT 0.9.6 SVN: at Fri Feb 15 22:05:02 EST 2013