PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
wxwidgets.cpp
Go to the documentation of this file.
1 // Copyright (C) 2005 Werner Smekal, Sjaak Verdoold
2 // Copyright (C) 2005 Germain Carrera Corraleche
3 // Copyright (C) 1999 Frank Huebner
4 //
5 // This file is part of PLplot.
6 //
7 // PLplot is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU Library General Public License as published
9 // by the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // PLplot is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with PLplot; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 
22 // TODO:
23 // - NA
24 //
25 
26 // wxwidgets headers
27 #include <wx/wx.h>
28 #include <wx/wfstream.h>
29 #include <wx/except.h>
30 
31 #include "plDevs.h"
32 
33 // plplot headers
34 #include "plplotP.h"
35 #include "drivers.h"
36 
37 // C/C++ headers
38 #include <cstdio>
39 
40 #include "wxwidgets.h"
41 
42 // Static function prototypes
43 #ifdef PL_HAVE_FREETYPE
44 static void plD_pixel_wxwidgets( PLStream *pls, short x, short y );
45 static PLINT plD_read_pixel_wxwidgets( PLStream *pls, short x, short y );
46 static void plD_set_pixel_wxwidgets( PLStream *pls, short x, short y, PLINT colour );
47 static void init_freetype_lv1( PLStream *pls );
48 static void init_freetype_lv2( PLStream *pls );
49 #endif
50 
51 // private functions needed by the wxwidgets Driver
52 static void install_buffer( PLStream *pls );
53 static void wxRunApp( PLStream *pls, bool runonce = false );
54 static void GetCursorCmd( PLStream *pls, PLGraphicsIn *ptr );
55 static void fill_polygon( PLStream *pls );
56 
57 #ifdef __WXMAC__
58  #include <Carbon/Carbon.h>
59 extern "C" { void CPSEnableForegroundOperation( ProcessSerialNumber* psn ); }
60 #endif
61 
63 
64 //--------------------------------------------------------------------------
65 // void Log_Verbose( const char *fmt, ... )
66 //
67 // Print verbose debug message to stderr (printf style).
68 //--------------------------------------------------------------------------
69 void Log_Verbose( const char *fmt, ... )
70 {
71 #ifdef _DEBUG_VERBOSE
72  va_list args;
73  va_start( args, fmt );
74  fprintf( stderr, "Verbose: " );
75  vfprintf( stderr, fmt, args );
76  fprintf( stderr, "\n" );
77  va_end( args );
78  fflush( stderr );
79 #else
80  (void) fmt; // Cast to void to silence compiler warnings about unused paraemeter
81 #endif
82 }
83 
84 
85 //--------------------------------------------------------------------------
86 // void Log_Debug( const char *fmt, ... )
87 //
88 // Print debug message to stderr (printf style).
89 //--------------------------------------------------------------------------
90 void Log_Debug( const char *fmt, ... )
91 {
92 #ifdef _DEBUG
93  va_list args;
94  va_start( args, fmt );
95  fprintf( stderr, "Debug: " );
96  vfprintf( stderr, fmt, args );
97  fprintf( stderr, "\n" );
98  va_end( args );
99  fflush( stderr );
100 #else
101  (void) fmt; // Cast to void to silence compiler warnings about unused paraemeter
102 #endif
103 }
104 
105 
106 //--------------------------------------------------------------------------
107 // In the following you'll find the driver functions which are
108 // are needed by the plplot core.
109 //--------------------------------------------------------------------------
110 
111 // Device info
112 #ifdef __cplusplus
113 extern "C" {
114 #endif
115 
117 #ifdef PLD_wxwidgets
118  "wxwidgets:wxWidgets Driver:1:wxwidgets:51:wxwidgets\n"
119 #endif
120 #ifdef PLD_wxpng
121  "wxpng:wxWidgets PNG Driver:0:wxwidgets:52:wxpng\n"
122 #endif
123 ;
124 
125 #ifdef __cplusplus
126 }
127 #endif
128 
129 
130 //--------------------------------------------------------------------------
131 // wxPLDevBase::wxPLDevBase( void )
132 //
133 // Contructor of base class of wxPLDev classes.
134 //--------------------------------------------------------------------------
135 wxPLDevBase::wxPLDevBase( int bcknd ) : backend( bcknd )
136 {
137  // Log_Verbose( "wxPLDevBase::wxPLDevBase()" );
138 
139  ready = false;
140  ownGUI = false;
141  waiting = false;
142  resizing = false;
143  exit = false;
144 
145  comcount = 0;
146 
147  m_frame = NULL;
148  xpos = 0;
149  ypos = 0;
150  // width, height are set in plD_init_wxwidgets
151  // bm_width, bm_height are set in install_buffer
152 
153  // xmin, xmax, ymin, ymax are set in plD_init_wxwidgets
154  // scalex, scaley are set in plD_init_wxwidgets
155 
156  plstate_width = false;
157  plstate_color0 = false;
158  plstate_color1 = false;
159 
160  locate_mode = 0;
161  draw_xhair = false;
162 
163  newclipregion = true;
164  clipminx = 1024;
165  clipmaxx = 0;
166  clipminy = 800;
167  clipmaxy = 0;
168 
169  freetype = 0;
170  smooth_text = 0;
171 
172  devName = (const char **) malloc( NDEV * sizeof ( char** ) );
173  memset( devName, '\0', NDEV * sizeof ( char** ) );
174  devDesc = (const char **) malloc( NDEV * sizeof ( char** ) );
175  memset( devDesc, '\0', NDEV * sizeof ( char** ) );
176  ndev = NDEV;
177 
178  lineSpacing = 1.0;
179 }
180 
181 
183 {
184  if ( devDesc )
185  free( devDesc );
186  if ( devName )
187  free( devName );
188 }
189 
190 
191 void wxPLDevBase::AddtoClipRegion( int x1, int y1, int x2, int y2 )
192 {
193  newclipregion = false;
194  if ( x1 < x2 )
195  {
196  if ( x1 < clipminx )
197  clipminx = x1;
198  if ( x2 > clipmaxx )
199  clipmaxx = x2;
200  }
201  else
202  {
203  if ( x2 < clipminx )
204  clipminx = x2;
205  if ( x1 > clipmaxx )
206  clipmaxx = x1;
207  }
208  if ( y1 < y2 )
209  {
210  if ( y1 < clipminy )
211  clipminy = y1;
212  if ( y2 > clipmaxy )
213  clipmaxy = y2;
214  }
215  else
216  {
217  if ( y2 < clipminy )
218  clipminy = y2;
219  if ( y1 > clipmaxy )
220  clipmaxy = y1;
221  }
222 }
223 
224 
225 void wxPLDevBase::PSDrawText( PLUNICODE* ucs4, int ucs4Len, bool drawText )
226 {
227  int i = 0;
228 
229  char utf8_string[max_string_length];
230  char utf8[5];
231  memset( utf8_string, '\0', max_string_length );
232 
233  // Get PLplot escape character
234  char plplotEsc;
235  plgesc( &plplotEsc );
236 
237  //Reset the size metrics
238  textWidth = 0;
239  textHeight = 0;
240  superscriptHeight = 0;
241  subscriptDepth = 0;
242 
243  while ( i < ucs4Len )
244  {
245  if ( ucs4[i] < PL_FCI_MARK ) // not a font change
246  {
247  if ( ucs4[i] != (PLUNICODE) plplotEsc ) // a character to display
248  {
249  ucs4_to_utf8( ucs4[i], utf8 );
250  strncat( utf8_string, utf8,
251  sizeof ( utf8_string ) - strlen( utf8_string ) - 1 );
252  i++;
253  continue;
254  }
255  i++;
256  if ( ucs4[i] == (PLUNICODE) plplotEsc ) // a escape character to display
257  {
258  ucs4_to_utf8( ucs4[i], utf8 );
259  strncat( utf8_string, utf8,
260  sizeof ( utf8_string ) - strlen( utf8_string ) - 1 );
261  i++;
262  continue;
263  }
264  else
265  {
266  if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
267  { // draw string so far
268  PSDrawTextToDC( utf8_string, drawText );
269 
270  // change font scale
271  if ( yOffset < -0.0001 )
272  fontScale *= 1.25; // Subscript scaling parameter
273  else
274  fontScale *= 0.8; // Subscript scaling parameter
275  PSSetFont( fci );
276 
277  yOffset += scaley * fontSize * fontScale / 2.;
278  }
279  if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
280  { // draw string so far
281  PSDrawTextToDC( utf8_string, drawText );
282 
283  // change font scale
284  double old_fontScale = fontScale;
285  if ( yOffset > 0.0001 )
286  fontScale *= 1.25; // Subscript scaling parameter
287  else
288  fontScale *= 0.8; // Subscript scaling parameter
289  PSSetFont( fci );
290 
291  yOffset -= scaley * fontSize * old_fontScale / 2.;
292  }
293  if ( ucs4[i] == (PLUNICODE) '-' ) // underline
294  { // draw string so far
295  PSDrawTextToDC( utf8_string, drawText );
296 
298  PSSetFont( fci );
299  }
300  if ( ucs4[i] == (PLUNICODE) '+' ) // overline
301  { // not implemented yet
302  }
303  i++;
304  }
305  }
306  else // a font change
307  {
308  // draw string so far
309  PSDrawTextToDC( utf8_string, drawText );
310 
311  // get new font
312  fci = ucs4[i];
313  PSSetFont( fci );
314  i++;
315  }
316  }
317 
318  PSDrawTextToDC( utf8_string, drawText );
319 }
320 
321 
322 //--------------------------------------------------------------------------
323 // void common_init( PLStream *pls )
324 //
325 // Basic initialization for all devices.
326 //--------------------------------------------------------------------------
328 {
329  // Log_Verbose( "common_init()" );
330 
331  wxPLDevBase* dev;
332  PLFLT downscale, downscale2;
333 
334  // default options
335  static PLINT freetype = -1;
336  static PLINT smooth_text = 1;
337  static PLINT text = -1;
338  static PLINT hrshsym = 0;
339 
340  // default backend uses wxGraphicsContext, if not available
341  // the agg library will be used, if not available the basic
342  // backend will be used.
343  static PLINT backend = wxBACKEND_DC;
344  #if wxUSE_GRAPHICS_CONTEXT
345  backend = wxBACKEND_GC;
346  #else
347  #ifdef HAVE_AGG
348  backend = wxBACKEND_AGG;
349  #endif
350  #endif
351 
352  DrvOpt wx_options[] = {
353 #ifdef PL_HAVE_FREETYPE
354  { "freetype", DRV_INT, &freetype, "Use FreeType library" },
355  { "smooth", DRV_INT, &smooth_text, "Turn text smoothing on (1) or off (0)" },
356 #endif
357  { "hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)" },
358  { "backend", DRV_INT, &backend, "Choose backend: (0) standard, (1) using AGG library, (2) using wxGraphicsContext" },
359  { "text", DRV_INT, &text, "Use own text routines (text=0|1)" },
360  { NULL, DRV_INT, NULL, NULL }
361  };
362 
363  // Check for and set up driver options
364  plParseDrvOpts( wx_options );
365 
366  // allocate memory for the device storage
367  switch ( backend )
368  {
369  case wxBACKEND_GC:
370  // in case wxGraphicsContext isn't available, the next backend (agg
371  // if available) in this list will be used
372 #if wxUSE_GRAPHICS_CONTEXT
373  dev = new wxPLDevGC;
374  // by default the own text routines are used for wxGC
375  if ( text == -1 )
376  text = 1;
377  freetype = 0; // this backend is vector oriented and doesn't know pixels
378  break;
379 #endif
380  case wxBACKEND_AGG:
381  // in case the agg library isn't available, the standard backend
382  // will be used
383 #ifdef HAVE_AGG
384  dev = new wxPLDevAGG;
385  // by default the freetype text routines are used for wxAGG
386  text = 0; // text processing doesn't work yet for the AGG backend
387  if ( freetype == -1 )
388  freetype = 1;
389  break;
390 #endif
391  default:
392  dev = new wxPLDevDC;
393  // by default the own text routines are used for wxDC
394  if ( text == -1 )
395  {
396  if ( freetype != 1 )
397  text = 1;
398  else
399  text = 0;
400  }
401  if ( freetype == -1 )
402  freetype = 0;
403  break;
404  }
405  if ( dev == NULL )
406  {
407  plexit( "Insufficient memory" );
408  }
409  pls->dev = (void *) dev;
410 
411 // be verbose and write out debug messages
412 #ifdef _DEBUG
413  pls->verbose = 1;
414  pls->debug = 1;
415 #endif
416 
417  pls->color = 1; // Is a color device
418  pls->dev_flush = 1; // Handles flushes
419  pls->dev_fill0 = 1; // Can handle solid fills
420  pls->dev_fill1 = 0; // Can't handle pattern fills
421  pls->dev_dash = 0;
422  pls->dev_clear = 1; // driver supports clear
423 
424  if ( text )
425  {
426  pls->dev_text = 1; // want to draw text
427  pls->dev_unicode = 1; // want unicode
428  if ( hrshsym )
429  pls->dev_hrshsym = 1;
430  }
431 
432 #ifdef PL_HAVE_FREETYPE
433  // own text routines have higher priority over freetype
434  // if text and freetype option are set to 1
435  if ( !text )
436  {
437  dev->smooth_text = smooth_text;
438  dev->freetype = freetype;
439  }
440 
441  if ( dev->freetype )
442  {
443  pls->dev_text = 1; // want to draw text
444  pls->dev_unicode = 1; // want unicode
445  if ( hrshsym )
446  pls->dev_hrshsym = 1;
447 
448  init_freetype_lv1( pls );
449  FT_Data* FT = (FT_Data *) pls->FT;
450  FT->want_smooth_text = smooth_text;
451  }
452 #endif
453 
454  // initialize frame size and position
455  if ( pls->xlength <= 0 || pls->ylength <= 0 )
456  plspage( 0.0, 0.0, (PLINT) ( CANVAS_WIDTH * DEVICE_PIXELS_PER_IN ),
457  (PLINT) ( CANVAS_HEIGHT * DEVICE_PIXELS_PER_IN ), 0, 0 );
458 
459  dev->width = pls->xlength;
460  dev->height = pls->ylength;
461  dev->clipminx = pls->xlength;
462  dev->clipminy = pls->ylength;
463 
464  if ( pls->xoffset != 0 || pls->yoffset != 0 )
465  {
466  dev->xpos = (int) ( pls->xoffset );
467  dev->ypos = (int) ( pls->yoffset );
468  }
469 
470 
471  // If portrait mode, apply a rotation and set freeaspect
472  if ( pls->portrait )
473  {
474  plsdiori( (PLFLT) ( 4 - ORIENTATION ) );
475  pls->freeaspect = 1;
476  }
477 
478  // Set the number of pixels per mm
479  plP_setpxl( (PLFLT) VIRTUAL_PIXELS_PER_MM, (PLFLT) VIRTUAL_PIXELS_PER_MM );
480 
481  // Set up physical limits of plotting device (in drawing units)
482  downscale = (double) dev->width / (double) ( PIXELS_X - 1 );
483  downscale2 = (double) dev->height / (double) PIXELS_Y;
484  if ( downscale < downscale2 )
485  downscale = downscale2;
486  plP_setphy( (PLINT) 0, (PLINT) ( dev->width / downscale ),
487  (PLINT) 0, (PLINT) ( dev->height / downscale ) );
488 
489  // get physical device limits coordinates
490  plP_gphy( &dev->xmin, &dev->xmax, &dev->ymin, &dev->ymax );
491 
492  // setting scale factors
493  dev->scalex = (PLFLT) ( dev->xmax - dev->xmin ) / ( dev->width );
494  dev->scaley = (PLFLT) ( dev->ymax - dev->ymin ) / ( dev->height );
495 
496  // set dpi
497  plspage( VIRTUAL_PIXELS_PER_IN / dev->scalex, VIRTUAL_PIXELS_PER_IN / dev->scaley, 0, 0, 0, 0 );
498 
499 #ifdef PL_HAVE_FREETYPE
500  if ( dev->freetype )
501  init_freetype_lv2( pls );
502 #endif
503 
504  // find out what file drivers are available
505  plgFileDevs( &dev->devDesc, &dev->devName, &dev->ndev );
506 
507  return dev;
508 }
509 
510 
511 #ifdef PLD_wxwidgets
512 
513 //--------------------------------------------------------------------------
514 // void plD_dispatch_init_wxwidgets( PLDispatchTable *pdt )
515 //
516 // Make wxwidgets driver functions known to plplot.
517 //--------------------------------------------------------------------------
519 {
520 #ifndef ENABLE_DYNDRIVERS
521  pdt->pl_MenuStr = "wxWidgets DC";
522  pdt->pl_DevName = "wxwidgets";
523 #endif
525  pdt->pl_seq = 51;
534 }
535 
536 //--------------------------------------------------------------------------
537 // plD_init_wxwidgets( PLStream* pls )
538 //
539 // Initialize wxWidgets device.
540 //--------------------------------------------------------------------------
541 void plD_init_wxwidgets( PLStream* pls )
542 {
543  // Log_Verbose( "plD_init_wxwidgets()" );
544 
545  wxPLDevBase* dev;
546  dev = common_init( pls );
547 
548  pls->plbuf_write = 1; // use the plot buffer!
549  pls->termin = 1; // interactive device
550  pls->graphx = GRAPHICS_MODE; // No text mode for this driver (at least for now, might add a console window if I ever figure it out and have the inclination)
551 
552  dev->showGUI = true;
553  dev->bitmapType = (wxBitmapType) 0;
554 }
555 
556 #endif // PLD_wxwidgets
557 
558 
559 #ifdef PLD_wxpng
560 
561 //--------------------------------------------------------------------------
562 // void plD_dispatch_init_wxpng( PLDispatchTable *pdt )
563 //
564 // Make wxpng driver functions known to plplot.
565 //--------------------------------------------------------------------------
567 {
568 #ifndef ENABLE_DYNDRIVERS
569  pdt->pl_MenuStr = "wxWidgets PNG driver";
570  pdt->pl_DevName = "wxpng";
571 #endif
573  pdt->pl_seq = 52;
582 }
583 
584 //--------------------------------------------------------------------------
585 // void plD_init_wxpng( PLStream *pls )
586 //
587 // Initialize wxpng device.
588 //--------------------------------------------------------------------------
589 void plD_init_wxpng( PLStream *pls )
590 {
591  // Log_Verbose( "plD_init_wxwidgets()" );
592 
593  wxPLDevBase* dev;
594  dev = common_init( pls );
595 
596  // Initialize family file info
597  plFamInit( pls );
598 
599  // Prompt for a file name if not already set.
600  plOpenFile( pls );
601 
602  pls->plbuf_write = 1; // use the plot buffer!
603  pls->dev_flush = 0; // No need for flushes
604  pls->termin = 0; // file oriented device
605  pls->graphx = GRAPHICS_MODE; // No text mode for this driver (at least for now, might add a console window if I ever figure it out and have the inclination)
606  pls->page = 0;
607 
608  dev->showGUI = false;
609  dev->bitmapType = wxBITMAP_TYPE_PNG;
610 }
611 
612 #endif // PLD_wxpng
613 
614 
615 //--------------------------------------------------------------------------
616 // void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a,
617 // short x2a, short y2a )
618 //
619 // Draws a line from (x1a, y1a) to (x2a, y2a).
620 //--------------------------------------------------------------------------
621 void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
622 {
623  // Log_Verbose( "plD_line_wxwidgets(x1a=%d, y1a=%d, x2a=%d, y2a=%d)", x1a, y1a, x2a, y2a );
624 
625  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
626 
627  if ( !( dev->ready ) )
628  install_buffer( pls );
629 
630  dev->DrawLine( x1a, y1a, x2a, y2a );
631 
632  if ( !( dev->resizing ) && dev->ownGUI )
633  {
634  dev->comcount++;
635  if ( dev->comcount > MAX_COMCOUNT )
636  {
637  wxRunApp( pls, true );
638  dev->comcount = 0;
639  }
640  }
641 }
642 
643 
644 //--------------------------------------------------------------------------
645 // void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya,
646 // PLINT npts )
647 //
648 // Draw a poly line - points are in xa and ya arrays.
649 //--------------------------------------------------------------------------
650 void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya, PLINT npts )
651 {
652  // Log_Verbose( "plD_polyline_wxwidgets()" );
653 
654  // should be changed to use the wxDC::DrawLines function?
655  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
656 
657  if ( !( dev->ready ) )
658  install_buffer( pls );
659 
660  dev->DrawPolyline( xa, ya, npts );
661 
662  if ( !( dev->resizing ) && dev->ownGUI )
663  {
664  dev->comcount++;
665  if ( dev->comcount > MAX_COMCOUNT )
666  {
667  wxRunApp( pls, true );
668  dev->comcount = 0;
669  }
670  }
671 }
672 
673 
674 //--------------------------------------------------------------------------
675 // void plD_eop_wxwidgets( PLStream *pls )
676 //
677 // End of Page. This function is called if a "end of page" is send by the
678 // user. This command is ignored if we have the plot embedded in a
679 // wxWidgets application, otherwise the application created by the device
680 // takes over.
681 //--------------------------------------------------------------------------
683 {
684  // Log_Verbose( "plD_eop_wxwidgets()" );
685 
686  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
687 
688  if ( dev->bitmapType )
689  {
690  wxMemoryDC memDC;
691  wxBitmap bitmap( dev->width, dev->height, -1 );
692  memDC.SelectObject( bitmap );
693 
694  dev->BlitRectangle( &memDC, 0, 0, dev->width, dev->height );
695  wxImage buffer = bitmap.ConvertToImage();
696  wxFFileOutputStream fstream( pls->OutFile );
697  if ( !( buffer.SaveFile( fstream, dev->bitmapType ) ) )
698  puts( "Troubles saving file!" );
699  memDC.SelectObject( wxNullBitmap );
700  }
701 
702  if ( dev->ownGUI )
703  {
704  if ( pls->nopause || !dev->showGUI )
705  wxRunApp( pls, true );
706  else
707  wxRunApp( pls );
708  }
709 }
710 
711 
712 //--------------------------------------------------------------------------
713 // void plD_bop_wxwidgets( PLStream *pls )
714 //
715 // Begin of page. Before any plot command, this function is called, If we
716 // have already a dc the background is cleared in background color and some
717 // state calls are resent - this is because at the first call of this
718 // function, a dc does most likely not exist, but state calls are recorded
719 // and when a new dc is created this function is called again.
720 //--------------------------------------------------------------------------
722 {
723  // Log_Verbose( "plD_bop_wxwidgets()" );
724 
725  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
726 
727  if ( dev->ready )
728  {
729  //if( pls->termin==0 ) {
730  // plGetFam( pls );
731  // force new file if pls->family set for all subsequent calls to plGetFam
732  // n.b. putting this after plGetFam call is important since plinit calls
733  // bop, and you don't want the familying sequence started until after
734  // that first call to bop.
735 
736  // n.b. pls->dev can change because of an indirect call to plD_init_png
737  // from plGetFam if familying is enabled. Thus, wait to define dev until
738  // now.
739  //dev = (wxPLDevBase*)pls->dev;
740  //
741  // pls->famadv = 1;
742  // pls->page++;
743  // }
744 
745  // clear background
746  PLINT bgr, bgg, bgb; // red, green, blue
747  plgcolbg( &bgr, &bgg, &bgb ); // get background color information
748  dev->ClearBackground( bgr, bgg, bgb );
749 
750  // Replay escape calls that come in before PLESC_DEVINIT. All of them
751  // required a DC that didn't exist yet.
752  //
753  if ( dev->plstate_width )
755  dev->plstate_width = false;
756 
757  if ( dev->plstate_color0 )
759  dev->plstate_color0 = false;
760 
761  if ( dev->plstate_color1 )
763  dev->plstate_color1 = false;
764 
765  // why this? xwin driver has this
766  // pls->page++;
767  }
768 }
769 
770 
771 //--------------------------------------------------------------------------
772 // void plD_tidy_wxwidgets( PLStream *pls )
773 //
774 // This function is called, if all plots are done.
775 //--------------------------------------------------------------------------
777 {
778  // Log_Verbose( "plD_tidy_wxwidgets()" );
779 
780  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
781 
782 #ifdef PL_HAVE_FREETYPE
783  if ( dev->freetype )
784  {
785  FT_Data *FT = (FT_Data *) pls->FT;
786  plscmap0n( FT->ncol0_org );
787  plD_FreeType_Destroy( pls );
788  }
789 #endif
790 
791  if ( dev->ownGUI )
792  {
793  wxPLGetApp().RemoveFrame( dev->m_frame );
794  if ( !wxPLGetApp().FrameCount() )
795  wxUninitialize();
796  }
797 
798  delete dev;
799  pls->dev = NULL; // since in plcore.c pls->dev is free_mem'd
800 }
801 
802 
803 //--------------------------------------------------------------------------
804 // void plD_state_wxwidgets( PLStream *pls, PLINT op )
805 //
806 // Handler for several state codes. Here we take care of setting the width
807 // and color of the pen.
808 //--------------------------------------------------------------------------
810 {
811  // Log_Verbose( "plD_state_wxwidgets(op=%d)", op );
812 
813  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
814 
815  switch ( op )
816  {
817  case PLSTATE_WIDTH: // 1
818  if ( dev->ready )
819  dev->SetWidth( pls );
820  else
821  dev->plstate_width = true;
822  break;
823 
824  case PLSTATE_COLOR0: // 2
825  if ( dev->ready )
826  dev->SetColor0( pls );
827  else
828  dev->plstate_color0 = true;
829  break;
830 
831  case PLSTATE_COLOR1: // 3
832  if ( dev->ready )
833  dev->SetColor1( pls );
834  else
835  dev->plstate_color1 = true;
836  break;
837 
838  default:
839  if ( !( dev->ready ) )
840  install_buffer( pls );
841  }
842 }
843 
844 
845 //--------------------------------------------------------------------------
846 // void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
847 //
848 // Handler for several escape codes. Here we take care of filled polygons,
849 // XOR or copy mode, initialize device (install dc from outside), and if
850 // there is freetype support, rerendering of text.
851 //--------------------------------------------------------------------------
852 void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
853 {
854  // Log_Verbose( "plD_esc_wxwidgets(op=%d, ptr=%x)", op, ptr );
855 
856  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
857 
858  switch ( op )
859  {
860  case PLESC_FILL:
861  fill_polygon( pls );
862  break;
863 
864  case PLESC_XORMOD:
865  // switch between wxXOR and wxCOPY
866  // if( dev->ready ) {
867  // if( dev->m_dc->GetLogicalFunction() == wxCOPY )
868  // dev->m_dc->SetLogicalFunction( wxXOR );
869  // else if( dev->m_dc->GetLogicalFunction() == wxXOR )
870  // dev->m_dc->SetLogicalFunction( wxCOPY );
871  // }
872  break;
873 
874  case PLESC_DEVINIT:
875  dev->SetExternalBuffer( ptr );
876 
877  // replay begin of page call and state settings
878  plD_bop_wxwidgets( pls );
879  break;
880 
881  case PLESC_HAS_TEXT:
882  if ( !( dev->ready ) )
883  install_buffer( pls );
884 
885  if ( dev->freetype )
886  {
887 #ifdef PL_HAVE_FREETYPE
888  plD_render_freetype_text( pls, (EscText *) ptr );
889 #endif
890  }
891  else
892  dev->ProcessString( pls, (EscText *) ptr );
893  break;
894 
895  case PLESC_RESIZE:
896  {
897  wxSize* size = (wxSize *) ptr;
898  wx_set_size( pls, size->GetWidth(), size->GetHeight() );
899  }
900  break;
901 
902  case PLESC_CLEAR:
903  if ( !( dev->ready ) )
904  install_buffer( pls );
905  // Since the plot is updated only every MAX_COMCOUNT commands (usually 5000)
906  // before we clear the screen we need to show the plot at least once :)
907  if ( !( dev->resizing ) && dev->ownGUI )
908  {
909  wxRunApp( pls, true );
910  dev->comcount = 0;
911  }
912  dev->ClearBackground( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b,
913  pls->sppxmi, pls->sppymi, pls->sppxma, pls->sppyma );
914  break;
915 
916  case PLESC_FLUSH: // forced update of the window
917  if ( !( dev->resizing ) && dev->ownGUI )
918  {
919  wxRunApp( pls, true );
920  dev->comcount = 0;
921  }
922  break;
923 
924  case PLESC_GETC:
925  if ( dev->ownGUI )
926  GetCursorCmd( pls, (PLGraphicsIn *) ptr );
927  break;
928 
929  case PLESC_GETBACKEND:
930  *( (int *) ptr ) = dev->backend;
931  break;
932 
933  default:
934  break;
935  }
936 }
937 
938 
939 //--------------------------------------------------------------------------
940 // static void fill_polygon( PLStream *pls )
941 //
942 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
943 //--------------------------------------------------------------------------
944 static void fill_polygon( PLStream *pls )
945 {
946  // Log_Verbose( "fill_polygon(), npts=%d, x[0]=%d, y[0]=%d", pls->dev_npts, pls->dev_y[0], pls->dev_y[0] );
947 
948  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
949 
950  if ( !( dev->ready ) )
951  install_buffer( pls );
952 
953  dev->FillPolygon( pls );
954 
955  if ( !( dev->resizing ) && dev->ownGUI )
956  {
957  dev->comcount += 10;
958  if ( dev->comcount > MAX_COMCOUNT )
959  {
960  wxRunApp( pls, true );
961  dev->comcount = 0;
962  }
963  }
964 }
965 
966 
967 //--------------------------------------------------------------------------
968 // void wx_set_size( PLStream* pls, int width, int height )
969 //
970 // Adds a dc to the stream. The associated device is attached to the canvas
971 // as the property "dev".
972 //--------------------------------------------------------------------------
973 void wx_set_size( PLStream* pls, int width, int height )
974 {
975  // TODO: buffer must be resized here or in wxplotstream
976  // Log_Verbose( "wx_set_size()" );
977 
978  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
979 
980  // set new size and scale parameters
981  dev->width = width;
982  dev->height = height;
983  dev->scalex = (PLFLT) ( dev->xmax - dev->xmin ) / dev->width;
984  dev->scaley = (PLFLT) ( dev->ymax - dev->ymin ) / dev->height;
985 
986  // recalculate the dpi used in calculation of fontsize
987  pls->xdpi = VIRTUAL_PIXELS_PER_IN / dev->scalex;
988  pls->ydpi = VIRTUAL_PIXELS_PER_IN / dev->scaley;
989 
990  // clear background if we have a dc, since it's invalid (TODO: why, since in bop
991  // it must be cleared anyway?)
992  if ( dev->ready )
993  {
994  PLINT bgr, bgg, bgb; // red, green, blue
995  plgcolbg( &bgr, &bgg, &bgb ); // get background color information
996 
997  dev->CreateCanvas();
998  dev->ClearBackground( bgr, bgg, bgb );
999  }
1000 
1001  // freetype parameters must also be changed
1002 #ifdef PL_HAVE_FREETYPE
1003  if ( dev->freetype )
1004  {
1005  FT_Data *FT = (FT_Data *) pls->FT;
1006  FT->scalex = dev->scalex;
1007  FT->scaley = dev->scaley;
1008  FT->ymax = dev->height;
1009  }
1010 #endif
1011 }
1012 
1013 
1014 //--------------------------------------------------------------------------
1015 // int plD_errorexithandler_wxwidgets( const char *errormessage )
1016 //
1017 // If an PLplot error occurs, this function shows a dialog regarding
1018 // this error and than exits.
1019 //--------------------------------------------------------------------------
1020 int plD_errorexithandler_wxwidgets( const char *errormessage )
1021 {
1022  if ( errormessage[0] )
1023  {
1024  wxMessageDialog dialog( 0, wxString( errormessage, *wxConvCurrent ), wxString( "wxWidgets PLplot App error", *wxConvCurrent ), wxOK | wxICON_ERROR );
1025  dialog.ShowModal();
1026  }
1027 
1028  return 0;
1029 }
1030 
1031 
1032 //--------------------------------------------------------------------------
1033 // void plD_erroraborthandler_wxwidgets( const char *errormessage )
1034 //
1035 // If PLplot aborts, this function shows a dialog regarding
1036 // this error.
1037 //--------------------------------------------------------------------------
1038 void plD_erroraborthandler_wxwidgets( const char *errormessage )
1039 {
1040  if ( errormessage[0] )
1041  {
1042  wxMessageDialog dialog( 0, ( wxString( errormessage, *wxConvCurrent ) + wxString( " aborting operation...", *wxConvCurrent ) ), wxString( "wxWidgets PLplot App abort", *wxConvCurrent ), wxOK | wxICON_ERROR );
1043  dialog.ShowModal();
1044  }
1045 }
1046 
1047 
1048 
1049 
1050 #ifdef PL_HAVE_FREETYPE
1051 
1052 //--------------------------------------------------------------------------
1053 // static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
1054 //
1055 // callback function, of type "plD_pixel_fp", which specifies how a single
1056 // pixel is set in the current colour.
1057 //--------------------------------------------------------------------------
1058 static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
1059 {
1060  // Log_Verbose( "plD_pixel_wxwidgets" );
1061 
1062  wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
1063 
1064  if ( !( dev->ready ) )
1065  install_buffer( pls );
1066 
1067  dev->PutPixel( x, y );
1068 
1069  if ( !( dev->resizing ) && dev->ownGUI )
1070  {
1071  dev->comcount++;
1072  if ( dev->comcount > MAX_COMCOUNT )
1073  {
1074  wxRunApp( pls, true );
1075  dev->comcount = 0;
1076  }
1077  }
1078 }
1079 
1080 
1081 //--------------------------------------------------------------------------
1082 // static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
1083 //
1084 // callback function, of type "plD_pixel_fp", which specifies how a single
1085 // pixel is set in the current colour.
1086 //--------------------------------------------------------------------------
1087 static void plD_set_pixel_wxwidgets( PLStream *pls, short x, short y, PLINT colour )
1088 {
1089  // Log_Verbose( "plD_set_pixel_wxwidgets" );
1090 
1091  wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
1092 
1093  if ( !( dev->ready ) )
1094  install_buffer( pls );
1095 
1096  dev->PutPixel( x, y, colour );
1097 
1098  if ( !( dev->resizing ) && dev->ownGUI )
1099  {
1100  dev->comcount++;
1101  if ( dev->comcount > MAX_COMCOUNT )
1102  {
1103  wxRunApp( pls, true );
1104  dev->comcount = 0;
1105  }
1106  }
1107 }
1108 
1109 
1110 //--------------------------------------------------------------------------
1111 // void plD_read_pixel_wxwidgets (PLStream *pls, short x, short y)
1112 //
1113 // callback function, of type "plD_pixel_fp", which specifies how a single
1114 // pixel is read.
1115 //--------------------------------------------------------------------------
1116 static PLINT plD_read_pixel_wxwidgets( PLStream *pls, short x, short y )
1117 {
1118  // Log_Verbose( "plD_read_pixel_wxwidgets" );
1119 
1120  wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
1121 
1122  if ( !( dev->ready ) )
1123  install_buffer( pls );
1124 
1125  return dev->GetPixel( x, y );
1126 }
1127 
1128 
1129 //--------------------------------------------------------------------------
1130 // void init_freetype_lv1 (PLStream *pls)
1131 //
1132 // "level 1" initialisation of the freetype library.
1133 // "Level 1" initialisation calls plD_FreeType_init(pls) which allocates
1134 // memory to the pls->FT structure, then sets up the pixel callback
1135 // function.
1136 //--------------------------------------------------------------------------
1137 static void init_freetype_lv1( PLStream *pls )
1138 {
1139  // Log_Verbose( "init_freetype_lv1" );
1140 
1141  plD_FreeType_init( pls );
1142 
1143  FT_Data *FT = (FT_Data *) pls->FT;
1144  FT->pixel = (plD_pixel_fp) plD_pixel_wxwidgets;
1145 
1146  //
1147  // See if we have a 24 bit device (or better), in which case
1148  // we can use the better antialising.
1149  //
1150  // the bitmap we are using in the antialized case has always
1151  // 32 bit depth
1152  FT->BLENDED_ANTIALIASING = 1;
1153  FT->read_pixel = (plD_read_pixel_fp) plD_read_pixel_wxwidgets;
1154  FT->set_pixel = (plD_set_pixel_fp) plD_set_pixel_wxwidgets;
1155 }
1156 
1157 
1158 //--------------------------------------------------------------------------
1159 // void init_freetype_lv2 (PLStream *pls)
1160 //
1161 // "Level 2" initialisation of the freetype library.
1162 // "Level 2" fills in a few setting that aren't public until after the
1163 // graphics sub-syetm has been initialised.
1164 // The "level 2" initialisation fills in a few things that are defined
1165 // later in the initialisation process for the GD driver.
1166 //
1167 // FT->scale is a scaling factor to convert co-ordinates. This is used by
1168 // the GD and other drivers to scale back a larger virtual page and this
1169 // eliminate the "hidden line removal bug". Set it to 1 if your device
1170 // doesn't have scaling.
1171 //
1172 // Some coordinate systems have zero on the bottom, others have zero on
1173 // the top. Freetype does it one way, and most everything else does it the
1174 // other. To make sure everything is working ok, we have to "flip" the
1175 // coordinates, and to do this we need to know how big in the Y dimension
1176 // the page is, and whether we have to invert the page or leave it alone.
1177 //
1178 // FT->ymax specifies the size of the page FT->invert_y=1 tells us to
1179 // invert the y-coordinates, FT->invert_y=0 will not invert the
1180 // coordinates.
1181 //--------------------------------------------------------------------------
1182 
1183 static void init_freetype_lv2( PLStream *pls )
1184 {
1185  // Log_Verbose( "init_freetype_lv2" );
1186 
1187  wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
1188  FT_Data *FT = (FT_Data *) pls->FT;
1189 
1190  FT->scalex = dev->scalex;
1191  FT->scaley = dev->scaley;
1192  FT->ymax = dev->height;
1193  FT->invert_y = 1;
1194  FT->smooth_text = 0;
1195 
1196  if ( ( FT->want_smooth_text == 1 ) && ( FT->BLENDED_ANTIALIASING == 0 ) ) // do we want to at least *try* for smoothing ?
1197  {
1198  FT->ncol0_org = pls->ncol0; // save a copy of the original size of ncol0
1199  FT->ncol0_xtra = 16777216 - ( pls->ncol1 + pls->ncol0 ); // work out how many free slots we have
1200  FT->ncol0_width = FT->ncol0_xtra / ( pls->ncol0 - 1 ); // find out how many different shades of anti-aliasing we can do
1201  if ( FT->ncol0_width > 4 ) // are there enough colour slots free for text smoothing ?
1202  {
1203  if ( FT->ncol0_width > max_number_of_grey_levels_used_in_text_smoothing )
1204  FT->ncol0_width = max_number_of_grey_levels_used_in_text_smoothing; // set a maximum number of shades
1205  plscmap0n( FT->ncol0_org + ( FT->ncol0_width * pls->ncol0 ) ); // redefine the size of cmap0
1206  // the level manipulations are to turn off the plP_state(PLSTATE_CMAP0)
1207  // call in plscmap0 which (a) leads to segfaults since the GD image is
1208  // not defined at this point and (b) would be inefficient in any case since
1209  // setcmap is always called later (see plD_bop_png) to update the driver
1210  // color palette to be consistent with cmap0.
1211  {
1212  PLINT level_save;
1213  level_save = pls->level;
1214  pls->level = 0;
1215  pl_set_extended_cmap0( pls, FT->ncol0_width, FT->ncol0_org ); // call the function to add the extra cmap0 entries and calculate stuff
1216  pls->level = level_save;
1217  }
1218  FT->smooth_text = 1; // Yippee ! We had success setting up the extended cmap0
1219  }
1220  else
1221  plwarn( "Insufficient colour slots available in CMAP0 to do text smoothing." );
1222  }
1223  else if ( ( FT->want_smooth_text == 1 ) && ( FT->BLENDED_ANTIALIASING == 1 ) ) // If we have a truecolour device, we wont even bother trying to change the palette
1224  {
1225  FT->smooth_text = 1;
1226  }
1227 }
1228 
1229 #endif
1230 
1231 
1232 //--------------------------------------------------------------------------
1233 // GetCursorCmd()
1234 //
1235 // Waits for a graphics input event and returns coordinates.
1236 //--------------------------------------------------------------------------
1237 static void GetCursorCmd( PLStream* pls, PLGraphicsIn* ptr )
1238 {
1239  // Log_Verbose( "GetCursorCmd" );
1240 
1241  wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
1242  PLGraphicsIn *gin = &( dev->gin );
1243 
1244  // Initialize
1245  plGinInit( gin );
1247  dev->draw_xhair = true;
1248 
1249  // Run event loop until a point is selected
1250  wxRunApp( pls, false );
1251 
1252  *ptr = *gin;
1253  if ( dev->locate_mode )
1254  {
1255  dev->locate_mode = 0;
1256  dev->draw_xhair = false;
1257  }
1258 }
1259 
1260 
1261 
1262 
1263 //--------------------------------------------------------------------------
1264 // This part includes wxWidgets specific functions, which allow to
1265 // open a window from the command line, if needed.
1266 //--------------------------------------------------------------------------
1267 
1268 
1269 //--------------------------------------------------------------------------
1270 // void install_buffer( PLStream *pls )
1271 //
1272 // If this driver is called from a command line executable (and not
1273 // from within a wxWidgets program), this function prepares a DC and a
1274 // bitmap to plot into.
1275 //--------------------------------------------------------------------------
1276 static void install_buffer( PLStream *pls )
1277 {
1278  // Log_Verbose( "install_buffer" );
1279 
1280  wxPLDevBase * dev = (wxPLDevBase *) pls->dev;
1281  static bool initApp = false;
1282 
1283  if ( !initApp )
1284  {
1285  // this hack enables to have a GUI on Mac OSX even if the
1286  // program was called from the command line (and isn't a bundle)
1287 #ifdef __WXMAC__
1288  ProcessSerialNumber psn;
1289 
1290  GetCurrentProcess( &psn );
1291  CPSEnableForegroundOperation( &psn );
1292  SetFrontProcess( &psn );
1293 #endif
1294 
1295  // initialize wxWidgets
1296  wxInitialize();
1297  wxLog::GetActiveTarget();
1298  wxTRY {
1299  wxPLGetApp().CallOnInit();
1300  }
1301  wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); plexit( "Can't init wxWidgets!" ); )
1302  initApp = true;
1303  }
1304 
1305 
1306  wxString title( pls->plwindow, *wxConvCurrent );
1307  switch ( dev->backend )
1308  {
1309  case wxBACKEND_DC:
1310  title += wxT( " - wxWidgets (basic)" );
1311  break;
1312  case wxBACKEND_GC:
1313  title += wxT( " - wxWidgets (wxGC)" );
1314  break;
1315  case wxBACKEND_AGG:
1316  title += wxT( " - wxWidgets (AGG)" );
1317  break;
1318  default:
1319  break;
1320  }
1321  dev->m_frame = new wxPLplotFrame( title, pls );
1322  wxPLGetApp().AddFrame( dev->m_frame );
1323 
1324  // set size and position of window
1325  dev->m_frame->SetClientSize( dev->width, dev->height );
1326  if ( dev->xpos != 0 || dev->ypos != 0 )
1327  dev->m_frame->SetSize( dev->xpos, dev->ypos,
1328  wxDefaultCoord, wxDefaultCoord,
1329  wxSIZE_USE_EXISTING );
1330 
1331  if ( dev->showGUI )
1332  {
1333  dev->m_frame->Show( true );
1334  dev->m_frame->Raise();
1335  }
1336  else
1337  dev->m_frame->Show( false );
1338 
1339  // get a DC and a bitmap or an imagebuffer
1340  dev->ownGUI = true;
1341  dev->bm_width = dev->width;
1342  dev->bm_height = dev->height;
1343  dev->CreateCanvas();
1344  dev->ready = true;
1345 
1346  // Set wx error handler for various errors in plplot
1349 
1350  // replay command we may have missed
1351  plD_bop_wxwidgets( pls );
1352 }
1353 
1354 
1355 //--------------------------------------------------------------------------
1356 // void wxRunApp( PLStream *pls, bool runonce )
1357 //
1358 // This is a hacked wxEntry-function, so that wxUninitialize is not
1359 // called twice. Here we actually start the wxApplication.
1360 //--------------------------------------------------------------------------
1361 static void wxRunApp( PLStream *pls, bool runonce )
1362 {
1363  // Log_Verbose( "wxRunApp" );
1364 
1365  wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
1366 
1367  dev->waiting = true;
1368  wxTRY
1369  {
1370  class CallOnExit
1371  {
1372 public:
1373  // only call OnExit if exit is true (i.e. due an exception)
1374  ~CallOnExit() { if ( exit ) wxPLGetApp().OnExit();}
1375  bool exit;
1376  } callOnExit;
1377 
1378  callOnExit.exit = true;
1379  wxPLGetApp().SetAdvanceFlag( runonce );
1380  wxPLGetApp().SetRefreshFlag();
1381 
1382  // add an idle event is necessary for Linux (wxGTK2)
1383  // but not for Windows, but it doesn't harm
1384  wxIdleEvent event;
1385  wxPLGetApp().AddPendingEvent( event );
1386  wxPLGetApp().OnRun(); // start wxWidgets application
1387  callOnExit.exit = false;
1388  }
1389  wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); plexit( "Problem running wxWidgets!" ); )
1390 
1391  if ( dev->exit )
1392  {
1393  wxPLGetApp().OnExit();
1394  plexit( "" );
1395  }
1396 
1397  dev->waiting = false;
1398 }