PLplot  5.15.0
wxPLplotwindow.h
Go to the documentation of this file.
1 // Copyright (C) 2015 Phil Rosenberg
2 // Copyright (C) 2005 Werner Smekal
3 //
4 // This file is part of PLplot.
5 //
6 // PLplot is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU Library General Public License as published
8 // by the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // PLplot is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Library General Public License for more details.
15 //
16 // You should have received a copy of the GNU Library General Public License
17 // along with PLplot; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20 
21 #if !defined ( WXPLPLOTWINDOW_H__INCLUDED_ )
22 #define WXPLPLOTWINDOW_H__INCLUDED_
23 
24 #include "plplot.h"
25 #include "wxPLplotstream.h"
26 #include <wx/window.h>
27 #include <wx/dcmemory.h>
28 #include <wx/dcclient.h>
29 #include <wx/dcgraph.h>
30 #include <wx/dcbuffer.h>
31 
32 // A plplot wxWindow template. To create an actual plplot wxWindow use
33 // the type of wxWindow you wish to inherit from at the template parameter
34 // For example to create a plplot wxFrame create a wxPLplotwindow<wxFrame>
35 // then call the base wxWindow's Create method to initialise.
36 template <class WXWINDOW>
37 class wxPLplotwindow : public WXWINDOW
38 {
39 public:
40  wxPLplotwindow( bool useGraphicsContext = true, wxSize clientSize = wxDefaultSize,
41  int resizeRenderDelay_ms = 0 );
42  virtual ~wxPLplotwindow( void );
43 
44  void RenewPlot( void );
45  bool SavePlot( const wxString& driver, const wxString& filename );
46  wxPLplotstream* GetStream() { return m_created ? &m_stream : NULL; }
47  void setUseGraphicsContext( bool useGraphicsContext );
48  void setCanvasColour( const wxColour &colour );
49  bool IsReady() { return GetStream() != NULL; }
50 
51 protected:
52  virtual void OnPaint( wxPaintEvent& event );
53  virtual void OnSize( wxSizeEvent & event );
54  virtual void OnErase( wxEraseEvent &event );
55  virtual void OnCreate( wxWindowCreateEvent &event );
56  void OnRenderTimer( wxTimerEvent &event );
57  void OnMouse( wxMouseEvent &event );
59  bool m_created;
60 
61 private:
63  wxBitmap m_bitmap;
64  // The memory dc and wrapping gc dc for drawing. Note we
65  //use pointers and reallocate them whenever the bitmap is
66  //resized because reusing either of these causes problems
67  //for rendering on a wxGCDC - at least on Windows.
68  wxMemoryDC *m_memoryDc;
69  wxSize m_initialSize;
70 #ifdef wxUSE_GRAPHICS_CONTEXT
71  wxGCDC *m_gcDc;
72 #endif
73  wxColour m_canvasColour;
74  virtual void OnLocate( const PLGraphicsIn &graphicsIn ){}
75 
76  //these are to allow delayed repainting on resize. This causes
77  //jerky resizing for large plots
78  bool m_resizing;
81  wxTimer m_renderTimer;
82  static const int ID_RENDERTIMER;
83 };
84 
85 template<class WXWINDOW>
86 const int wxPLplotwindow<WXWINDOW>::ID_RENDERTIMER = ::wxNewId();
87 
92 
93 template<class WXWINDOW>
94 wxPLplotwindow<WXWINDOW>::wxPLplotwindow( bool useGraphicsContext, wxSize clientSize, int resizeRenderDelay_ms )
95  : m_created( false ), m_initialSize( clientSize ), m_resizing( false ), m_completedFirstRender( false ), m_renderTimer( this, ID_RENDERTIMER ), m_resizeRenderDelay( resizeRenderDelay_ms )
96 
97 {
98  PLPLOT_wxLogDebug( "wxPLplotwindow::wxPLplotwindow" );
99  m_memoryDc = NULL;
100 #ifdef wxUSE_GRAPHICS_CONTEXT
101  m_gcDc = NULL;
102  // Force initialization of m_useGraphicsContext and
103  // drawDc when setUseGraphicsContext is called below.
104  m_useGraphicsContext = !useGraphicsContext;
105 #endif
106  setUseGraphicsContext( useGraphicsContext );
107  m_canvasColour = *wxBLACK;
108 
109  //We use connect instead of Bind for compatibility with wxWidgets 2.8
110  //but should move to bind in the future.
111  WXWINDOW::Connect( wxEVT_SIZE, wxSizeEventHandler( wxPLplotwindow<WXWINDOW>::OnSize ) );
112  WXWINDOW::Connect( wxEVT_PAINT, wxPaintEventHandler( wxPLplotwindow<WXWINDOW>::OnPaint ) );
113  WXWINDOW::Connect( wxEVT_ERASE_BACKGROUND, wxEraseEventHandler( wxPLplotwindow<WXWINDOW>::OnErase ) );
114  WXWINDOW::Connect( wxEVT_CREATE, wxWindowCreateEventHandler( wxPLplotwindow<WXWINDOW>::OnCreate ) );
115  WXWINDOW::Connect( wxEVT_MOTION, wxMouseEventHandler( wxPLplotwindow<WXWINDOW>::OnMouse ) );
116  WXWINDOW::Connect( wxEVT_LEFT_UP, wxMouseEventHandler( wxPLplotwindow<WXWINDOW>::OnMouse ) );
117  WXWINDOW::Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( wxPLplotwindow<WXWINDOW>::OnMouse ) );
118  WXWINDOW::Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( wxPLplotwindow<WXWINDOW>::OnMouse ) );
119  WXWINDOW::Connect( ID_RENDERTIMER, wxEVT_TIMER, wxTimerEventHandler( wxPLplotwindow<WXWINDOW>::OnRenderTimer ) );
120 }
121 
122 
125 
126 template<class WXWINDOW>
128 {
129  if ( m_memoryDc )
130  delete m_memoryDc;
131  if ( m_gcDc )
132  delete m_gcDc;
133 }
134 
140 
141 template<class WXWINDOW>
142 void wxPLplotwindow<WXWINDOW>::OnPaint( wxPaintEvent &WXUNUSED( event ) )
143 {
144  //Really this should be in the constructor, but it caused a segfault
145  //on at least one system (CentOS with intel compiler and wxWidgets 2.8.12).
146  //Moving it here after WXWINDOW::Create has been called stops this and
147  //the call does nothing if the style is the same as previous calls so
148  //should be safe to call here.
149  //WXWINDOW::SetBackgroundStyle( wxBG_STYLE_CUSTOM );
150 
151  //wxAutoBufferedPaintDC dc( (WXWINDOW*)this );
152  int width = WXWINDOW::GetClientSize().GetWidth();
153  int height = WXWINDOW::GetClientSize().GetHeight();
154 
155  wxPaintDC paintDc( this );
156 
157  //if we are still resizing (i.e. the useris still messing
158  //with the size) then just fill the invalidated area with
159  //the background colour for now. A full rerender will
160  //happen once the size has stopped changing.
161  if ( m_resizing )
162  {
163  //fill the area with the background colour
164  paintDc.SetBackground( wxBrush( m_canvasColour ) );
165  paintDc.Clear();
166  //also blit on the previous image - it may have
167  //been invalidated, e.g. by shrinking then expanding
168  //the window.
169  paintDc.Blit( 0, 0, width, height, m_memoryDc, 0, 0 );
170 
171  return;
172  }
173 
174  //resize the plot if needed
175  bool needResize = width != m_bitmap.GetWidth() || height != m_bitmap.GetHeight();
176  if ( needResize )
177  {
178  m_bitmap.Create( width, height, 32 );
179  if ( m_memoryDc )
180  delete m_memoryDc;
181  m_memoryDc = new wxMemoryDC;
182  m_memoryDc->SelectObject( m_bitmap );
183  wxDC *drawDc = m_memoryDc;
184 #ifdef wxUSE_GRAPHICS_CONTEXT
185  if ( m_useGraphicsContext )
186  {
187  if ( m_gcDc )
188  delete m_gcDc;
189  m_gcDc = new wxGCDC( *m_memoryDc );
190  drawDc = m_gcDc;
191  }
192 #endif
193  if ( IsReady() )
194  m_stream.SetDC( drawDc );
195  drawDc->SetBackground( wxBrush( m_canvasColour ) );
196  drawDc->Clear();
197  if ( IsReady() )
198  m_stream.SetSize( width, height );
199  }
200 
201  paintDc.Blit( 0, 0, width, height, m_memoryDc, 0, 0 );
202 
203  if ( width > 0 && height > 0 )
204  m_completedFirstRender = true;
205 }
206 
209 
210 template<class WXWINDOW>
211 void wxPLplotwindow<WXWINDOW>::OnSize( wxSizeEvent& event )
212 {
213  //Once the window has been displayed properly for the first time we
214  //want to delay rendering on resize, this ensures that complex plots
215  //don't cause unresponsive or even nearly impossible resizing.
216 
217  //Don't delay the first render or if the size hasn't actually
218  //changed (this can be caused by a resize call from PlPlot but
219  //with the size the same).
220  int width = WXWINDOW::GetClientSize().GetWidth();
221  int height = WXWINDOW::GetClientSize().GetHeight();
222  int oldWidth = m_bitmap.IsOk() ? m_bitmap.GetWidth() : 0;
223  int oldHeight = m_bitmap.IsOk() ? m_bitmap.GetHeight() : 0;
224  if ( !m_completedFirstRender || ( m_resizeRenderDelay == 0 ) ||
225  ( width == oldWidth && height == oldHeight ) )
226  {
227  //++m_nResizes;
228  //Invalidate the whole window so it is all redrawn, otherwise only
229  //newly exposed parts of the window get redrawn
230  RenewPlot();
231  return;
232  }
233 
234  //If we wish to delay rerendering while the size settles down then
235  //invalidate the newly exposed area and flag that we are still resizing
236  //(this tells OnPaint to just fill the new area with the background
237  //colour), then set up a timer to trigger a proper rerender once the
238  //size has stopped changing.
239  m_resizing = true;
240  if ( width > oldWidth )
241  WXWINDOW::RefreshRect( wxRect( width, 0, width - oldWidth, height ) );
242  if ( height > oldHeight )
243  WXWINDOW::RefreshRect( wxRect( 0, oldHeight, oldWidth, height - oldHeight ) );
244 
245  //Start the timer, note that this resets the timer to 0 if it is still running
246  m_renderTimer.Start( m_resizeRenderDelay, true );
247 }
248 
251 
252 template<class WXWINDOW>
253 void wxPLplotwindow<WXWINDOW>::OnErase( wxEraseEvent& WXUNUSED( event ) )
254 {
255  //Do nothing. This stops screen flicker.
256 }
257 
263 
264 template<class WXWINDOW>
265 void wxPLplotwindow<WXWINDOW>::OnCreate( wxWindowCreateEvent &event )
266 {
267  PLPLOT_wxLogDebug( "wxPLplotwindow::OnCreate" );
268  if ( !m_created )
269  {
270  //set the client size if requested
271  if ( m_initialSize != wxDefaultSize )
272  WXWINDOW::SetClientSize( m_initialSize );
273  //create the stream
274  int width = WXWINDOW::GetClientSize().GetWidth();
275  int height = WXWINDOW::GetClientSize().GetHeight();
276  m_bitmap.Create( width, height );
277  if ( m_memoryDc )
278  delete m_memoryDc;
279  m_memoryDc = new wxMemoryDC;
280  m_memoryDc->SelectObject( m_bitmap );
281  wxDC * drawDc = m_memoryDc;
282 #ifdef wxUSE_GRAPHICS_CONTEXT
283  if ( m_useGraphicsContext )
284  {
285  if ( m_gcDc )
286  delete m_gcDc;
287  m_gcDc = new wxGCDC( *m_memoryDc );
288  drawDc = m_gcDc;
289  }
290 #endif
291  if ( !m_stream.IsValid() )
292  m_stream.Create( drawDc, width, height, wxPLPLOT_DRAW_TEXT );
293  else
294  m_stream.SetDC( drawDc );
295  drawDc->SetBackground( wxBrush( m_canvasColour ) );
296  drawDc->Clear();
297 
298  m_created = true;
299  RenewPlot();
300  }
301 }
302 
303 template<class WXWINDOW>
304 void wxPLplotwindow<WXWINDOW>::OnRenderTimer( wxTimerEvent &event )
305 {
306  if ( m_resizing )
307  {
308  m_resizing = false;
309  RenewPlot();
310  }
311 }
312 
313 //Capture Mouse events and pass the
314 template<class WXWINDOW>
315 void wxPLplotwindow<WXWINDOW>::OnMouse( wxMouseEvent &event )
316 {
317  PLGraphicsIn graphicsIn;
318  wxPoint cursorPosition = event.GetPosition();
319  wxSize clientSize = WXWINDOW::GetClientSize();
320 
321  graphicsIn.pX = cursorPosition.x;
322  graphicsIn.pY = cursorPosition.y;
323  graphicsIn.dX = PLFLT( cursorPosition.x + 0.5 ) / PLFLT( clientSize.GetWidth() );
324  graphicsIn.dY = 1.0 - PLFLT( cursorPosition.y + 0.5 ) / PLFLT( clientSize.GetHeight() );
325  graphicsIn.keysym = 0x20;
326  graphicsIn.state = 0;
327  graphicsIn.subwindow = -1;
328  graphicsIn.type = 0;
329  graphicsIn.string[0] = '\0';
330  if ( event.LeftUp() )
331  {
332  graphicsIn.button = 1;
333  graphicsIn.state |= PL_MASK_BUTTON1;
334  }
335  else if ( event.MiddleUp() )
336  {
337  graphicsIn.button = 2;
338  graphicsIn.state |= PL_MASK_BUTTON2;
339  }
340  else if ( event.RightUp() )
341  {
342  graphicsIn.button = 3;
343  graphicsIn.state |= PL_MASK_BUTTON3;
344  }
345  else if ( event.Aux1Up() )
346  {
347  graphicsIn.button = 4;
348  graphicsIn.state |= PL_MASK_BUTTON4;
349  }
350  else if ( event.Aux2Up() )
351  {
352  graphicsIn.button = 5;
353  graphicsIn.state |= PL_MASK_BUTTON5;
354  }
355  else
356  {
357  //If we get here we have just captured motion
358  //not a click
359  graphicsIn.button = 0;
360  graphicsIn.state = 0;
361  graphicsIn.keysym = 0;
362  }
363 
364  if ( wxGetKeyState( WXK_SHIFT ) )
365  graphicsIn.state |= PL_MASK_SHIFT;
366  if ( wxGetKeyState( WXK_CAPITAL ) )
367  graphicsIn.state |= PL_MASK_CAPS;
368  if ( wxGetKeyState( WXK_ALT ) && wxGetKeyState( WXK_CONTROL ) )
369  graphicsIn.state |= PL_MASK_ALTGR;
370  else if ( wxGetKeyState( WXK_CONTROL ) )
371  graphicsIn.state |= PL_MASK_CONTROL;
372  else if ( wxGetKeyState( WXK_ALT ) )
373  graphicsIn.state |= PL_MASK_ALT;
374  if ( wxGetKeyState( WXK_NUMLOCK ) )
375  graphicsIn.state |= PL_MASK_NUM;
376  if ( wxGetKeyState( WXK_SCROLL ) )
377  graphicsIn.state |= PL_MASK_SCROLL;
378  //Note I can't find a way to catch the windows key
379 
380  if ( IsReady() )
381  m_stream.translatecursor( &graphicsIn );
382  this->OnLocate( graphicsIn );
383 }
384 
387 
388 template<class WXWINDOW>
390 {
391  if ( m_created )
392  {
393  WXWINDOW::Refresh();
394  }
395 }
396 
397 
400 
401 template<class WXWINDOW>
402 bool wxPLplotwindow<WXWINDOW>::SavePlot( const wxString& devname, const wxString& filename )
403 {
404  int pls, pls_save;
405  FILE *sfile;
406 
407  if ( ( sfile = fopen( filename.mb_str(), "wb+" ) ) == NULL )
408  {
409  return false;
410  }
411 
412  plgstrm( &pls );
413  plmkstrm( &pls_save );
414  if ( pls_save < 0 )
415  {
416  fclose( sfile );
417  return false;
418  }
419  plsdev( devname.mb_str() );
420  plsfile( sfile );
421 
422  plspage( 0., 0., 800, 600, 0, 0 );
423  plcpstrm( pls, 0 );
424  pladv( 0 );
425  plreplot();
426  plend1();
427  plsstrm( pls );
428 
429  return true;
430 }
431 
434 
435 template<class WXWINDOW>
436 void wxPLplotwindow<WXWINDOW>::setUseGraphicsContext( bool useGraphicsContext )
437 {
438  wxDC *drawDc;
439 #ifdef wxUSE_GRAPHICS_CONTEXT
440  m_useGraphicsContext = useGraphicsContext;
441  drawDc = m_useGraphicsContext ? (wxDC *) m_gcDc : (wxDC *) m_memoryDc;
442 #else
443  drawDc = &m_memoryDc;
444  m_useGraphicsContext = false;
445 #endif
446  if ( IsReady() )
447  {
448  m_stream.SetDC( drawDc );
449  RenewPlot();
450  }
451 }
452 
453 template<class WXWINDOW>
454 void wxPLplotwindow<WXWINDOW>::setCanvasColour( const wxColour &colour )
455 {
456  m_canvasColour = colour;
457  RenewPlot();
458 }
459 
460 #endif // !defined( WXPLPLOTWINDOW_H__INCLUDED_ )
#define PL_MASK_BUTTON3
Definition: plplot.h:429
#define plsstrm
Definition: plplot.h:835
void Create(wxDC *dc, int width, int height, int style)
Called from the constructor or can be called by the user if the default constructor is used...
#define plspage
Definition: plplot.h:831
virtual void OnLocate(const PLGraphicsIn &graphicsIn)
void OnRenderTimer(wxTimerEvent &event)
Timer used in delayed rendering after resize.
#define plsdev
Definition: plplot.h:806
PLFLT dX
Definition: plplot.h:442
void setUseGraphicsContext(bool useGraphicsContext)
wxColour m_canvasColour
static const int ID_RENDERTIMER
wxPLplotstream is inherited from plstream, which is the C++ interface
size_t m_resizeRenderDelay
wxMemoryDC * m_memoryDc
void plsfile(FILE *file)
Definition: plcore.c:3802
#define PL_MASK_SHIFT
Definition: plplot.h:419
#define plend1
Definition: plplot.h:710
bool m_useGraphicsContext
Flag to indicate whether we should use a wxGCDC.
wxTimer m_renderTimer
#define plcpstrm
Definition: plplot.h:707
bool m_created
Flag to indicate the window has been Created.
virtual void OnCreate(wxWindowCreateEvent &event)
Window created event.
int type
Definition: plplot.h:435
#define PL_MASK_SCROLL
Definition: plplot.h:426
wxSize m_initialSize
void OnMouse(wxMouseEvent &event)
Mouse events.
void SetDC(wxDC *dc)
Set a new dc to write to.
wxPLplotstream m_stream
The wxPLplotstream which belongs to this plot widget.
unsigned int keysym
Definition: plplot.h:437
wxBitmap m_bitmap
static PLStream * pls[PL_NSTREAMS]
Definition: plcore.h:88
void SetSize(int width, int height)
Set new size of plot area.
#define PL_MASK_CAPS
Definition: plplot.h:420
wxPLplotstream * GetStream()
Get pointer to wxPLplotstream of this widget.
#define PL_MASK_NUM
Definition: plplot.h:423
PLINT subwindow
Definition: plplot.h:439
#define PL_MASK_BUTTON2
Definition: plplot.h:428
#define plmkstrm
Definition: plplot.h:772
float PLFLT
Definition: plplot.h:163
virtual void OnPaint(wxPaintEvent &event)
Paint event.
void RenewPlot(void)
Redo plot.
bool m_completedFirstRender
#define PL_MASK_BUTTON4
Definition: plplot.h:430
#define PL_MASK_ALTGR
Definition: plplot.h:424
virtual void OnErase(wxEraseEvent &event)
Background erase event.
PLINT translatecursor(PLGraphicsIn *gin)
Definition: plstream.cc:1382
#define PL_MASK_ALT
Definition: plplot.h:422
unsigned int state
Definition: plplot.h:436
#define PLPLOT_wxLogDebug(string)
#define PL_MASK_BUTTON1
Definition: plplot.h:427
#define plreplot
Definition: plplot.h:788
unsigned int button
Definition: plplot.h:438
#define PL_MASK_CONTROL
Definition: plplot.h:421
void setCanvasColour(const wxColour &colour)
PLFLT dY
Definition: plplot.h:442
wxPLplotwindow(bool useGraphicsContext=true, wxSize clientSize=wxDefaultSize, int resizeRenderDelay_ms=0)
Constructor.
virtual ~wxPLplotwindow(void)
Destructor.
#define pladv
Definition: plplot.h:692
#define plgstrm
Definition: plplot.h:744
char string[PL_MAXKEY]
Definition: plplot.h:440
virtual void OnSize(wxSizeEvent &event)
Size event.
bool SavePlot(const wxString &driver, const wxString &filename)
Save plot using a different driver.
#define PL_MASK_BUTTON5
Definition: plplot.h:431