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