PLplot  5.11.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
wxwidgets_dev.cpp
Go to the documentation of this file.
1 // Copyright (C) 2015 Phil Rosenberg
2 // Copyright (C) 2005 Werner Smekal, Sjaak Verdoold
3 // Copyright (C) 2005 Germain Carrera Corraleche
4 // Copyright (C) 1999 Frank Huebner
5 //
6 // This file is part of PLplot.
7 //
8 // PLplot is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU Library General Public License as published
10 // by the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // PLplot is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public License
19 // along with PLplot; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 
23 #define DEBUG
24 #define NEED_PLDEBUG
25 
26 //set this to help when debugging wxPLViewer issues
27 //it uses a memory map name without random characters
28 //and does not execute the viewer, allowing the user to do
29 //it in a debugger
30 //#define WXPLVIEWER_DEBUG
31 
32 //headers needed for Rand
33 #ifdef WIN32
34 //this include must occur before any other include of stdlib.h
35 //due to the #define _CRT_RAND_S
36 #define _CRT_RAND_S
37 #include <stdlib.h>
38 #else
39 #include <fstream>
40 #endif
41 
42 //plplot headers
43 #include "plDevs.h"
44 #include "wxwidgets.h" // includes wx/wx.h
45 
46 // wxwidgets headers
47 #include <wx/dir.h>
48 
49 
50 
51 // std and driver headers
52 #include <cmath>
53 
54 
55 //--------------------------------------------------------------------------
56 // Scaler class
57 // This class changes the logical scale of a dc on construction and resets
58 // it to its original value on destruction. It is ideal for making temporary
59 // changes to the scale and guarenteeing that the scale gets set back.
60 //--------------------------------------------------------------------------
61 class Scaler
62 {
63 public:
64  Scaler( wxDC * dc, double xScale, double yScale )
65  {
66  m_dc = dc;
67  dc->GetLogicalScale( &m_xScaleOld, &m_yScaleOld );
68  dc->SetLogicalScale( xScale, yScale );
69  }
71  {
72  m_dc->SetLogicalScale( m_xScaleOld, m_yScaleOld );
73  }
74 private:
75  wxDC *m_dc;
76  double m_xScaleOld;
77  double m_yScaleOld;
78 };
79 
80 //--------------------------------------------------------------------------
81 // OriginChanger class
82 // This class changes the logical origin of a dc on construction and resets
83 // it to its original value on destruction. It is ideal for making temporary
84 // changes to the origin and guarenteeing that the scale gets set back.
85 //--------------------------------------------------------------------------
87 {
88 public:
89  OriginChanger( wxDC * dc, long xOrigin, long yOrigin )
90  {
91  m_dc = dc;
92  dc->GetLogicalOrigin( &m_xOriginOld, &m_yOriginOld );
93  dc->SetLogicalOrigin( xOrigin, yOrigin );
94  }
96  {
97  m_dc->SetLogicalOrigin( m_xOriginOld, m_yOriginOld );
98  }
99 private:
100  wxDC *m_dc;
103 };
104 
105 //--------------------------------------------------------------------------
106 // DrawingObjectsChanger class
107 // This class changes the pen and brush of a dc on construction and resets
108 // them to their original values on destruction. It is ideal for making temporary
109 // changes to the pen and brush and guarenteeing that they get set back.
110 //--------------------------------------------------------------------------
112 {
113 public:
114  DrawingObjectsChanger( wxDC *dc, const wxPen &pen, const wxBrush &brush )
115  {
116  m_dc = dc;
117  m_pen = dc->GetPen();
118  m_brush = dc->GetBrush();
119  dc->SetPen( pen );
120  dc->SetBrush( brush );
121  }
123  {
124  m_dc->SetPen( m_pen );
125  m_dc->SetBrush( m_brush );
126  }
127 private:
128  wxDC *m_dc;
129  wxPen m_pen;
130  wxBrush m_brush;
131 };
132 
133 //--------------------------------------------------------------------------
134 // TextObjectsChanger class
135 // This class changes the font and text colours of a dc on construction and resets
136 // them to their original values on destruction. It is ideal for making temporary
137 // changes to the text and guarenteeing that they get set back.
138 //--------------------------------------------------------------------------
140 {
141 public:
142  TextObjectsChanger( wxDC *dc, const wxFont &font, const wxColour &textForeground, const wxColour &textBackground )
143  {
144  m_dc = dc;
145  m_font = dc->GetFont();
146  m_textForeground = dc->GetTextForeground();
147  m_textBackground = dc->GetTextBackground();
148  dc->SetTextForeground( textForeground );
149  dc->SetTextBackground( textBackground );
150  dc->SetFont( font );
151  }
152  TextObjectsChanger( wxDC *dc, const wxFont &font )
153  {
154  m_dc = dc;
155  m_font = dc->GetFont();
156  m_textForeground = dc->GetTextForeground();
157  m_textBackground = dc->GetTextBackground();
158  dc->SetFont( font );
159  }
161  {
162  m_dc->SetTextForeground( m_textForeground );
163  m_dc->SetTextBackground( m_textBackground );
164  m_dc->SetFont( m_font );
165  }
166 private:
167  wxDC *m_dc;
168  wxFont m_font;
171 };
172 
173 //--------------------------------------------------------------------------
174 // class Rand
175 // This is a simple random number generator class, created soley so that
176 // random numbers can be generated in this file without "contaminating" the
177 // global series of random numbers with a new seed.
178 // It uses an algorithm that apparently used to be used in gcc rand()
179 // provided under GNU LGPL v2.1.
180 //--------------------------------------------------------------------------
181 class Rand
182 {
183 public:
185  {
186 #ifdef WIN32
187  rand_s( &m_seed );
188 #else
189  std::fstream fin( "/dev/random", std::ios::in );
190  fin.read( (char *) ( &m_seed ), sizeof ( m_seed ) );
191  fin.close();
192 #endif
193  }
194  Rand( unsigned int seed )
195  {
196  m_seed = seed;
197  }
198  unsigned int operator()()
199  {
200  unsigned int next = m_seed;
201  int result;
202 
203  next *= 1103515245;
204  next += 12345;
205  result = (unsigned int) ( next / max ) % 2048;
206 
207  next *= 1103515245;
208  next += 12345;
209  result <<= 10;
210  result ^= (unsigned int) ( next / max ) % 1024;
211 
212  next *= 1103515245;
213  next += 12345;
214  result <<= 10;
215  result ^= (unsigned int) ( next / max ) % 1024;
216 
217  m_seed = next;
218 
219  return result;
220  }
221  static const unsigned int max = 65536;
222 private:
223  unsigned int m_seed;
224 };
225 
226 //--------------------------------------------------------------------------
227 // wxPLDevice::wxPLDevice( void )
228 //
229 // Constructor of the standard wxWidgets device based on the wxPLDevBase
230 // class. Only some initialisations are done.
231 //--------------------------------------------------------------------------
233  : m_plplotEdgeLength( PLFLT( SHRT_MAX ) )
234 {
235  m_fixedAspect = false;
236 
237  m_lineSpacing = 1.0;
238  m_underlined = false;
239 
240  m_dc = NULL;
241 
242  if ( mfo )
243  strcpy( m_mfo, mfo );
244  else
245  //assume we will be outputting to the default
246  //memory map until we are given a dc to draw to
247 #ifdef WXPLVIEWER_DEBUG
248  strcpy( m_mfo, "plplotMemoryMap" );
249 #else
250  strcpy( m_mfo, "plplotMemoryMap??????????" );
251 #endif
252 
253  // be verbose and write out debug messages
254 #ifdef _DEBUG
255  pls->verbose = 1;
256  pls->debug = 1;
257 #endif
258 
259  pls->color = 1; // Is a color device
260  pls->dev_flush = 1; // Handles flushes
261  pls->dev_fill0 = 1; // Can handle solid fills
262  pls->dev_fill1 = 0; // Can't handle pattern fills
263  pls->dev_dash = 0;
264  pls->dev_clear = 1; // driver supports clear
265  pls->plbuf_write = 1; // use the plot buffer!
266  pls->termin = ( strlen( m_mfo ) ) > 0 ? 0 : 1; // interactive device unless we are writing to memory - pretty sure this is an unused option though
267  pls->graphx = GRAPHICS_MODE; // This indicates this is a graphics driver. PLPlot with therefore cal pltext() before outputting text, however we currently have not implemented catching that text.
268 
269  if ( text )
270  {
271  pls->dev_text = 1; // want to draw text
272  pls->dev_unicode = 1; // want unicode
273  if ( hrshsym )
274  pls->dev_hrshsym = 1;
275  }
276 
277 
278  // Set up physical limits of plotting device in plplot internal units
279  // we just tell plplot we are the maximum plint in both dimensions
280  //which gives us the best resolution
281  plP_setphy( (PLINT) 0, (PLINT) SHRT_MAX,
282  (PLINT) 0, (PLINT) SHRT_MAX );
283 
284  // set dpi and page size defaults
285  // the user might have already set this with plspage
286  // so check first
287  if ( !plsc->pageset )
288  c_plspage( 90, 90, 900, 675, 0, 0 );
289 
290  //check dpi is non-zero otherwise we get infinities in some calcualtions
291  //and ridiculous numbers in others
292  if ( pls->xdpi == 0.0 || pls->ydpi == 0 )
293  {
294  if ( pls->xdpi == 0.0 && pls->ydpi == 0 )
295  c_plspage( 90, 90, 0, 0, 0, 0 );
296  else
297  {
298  PLFLT dpi = MAX( pls->xdpi, pls->ydpi );
299  pls->xdpi = dpi;
300  pls->ydpi = dpi;
301  }
302  }
303 
305 
306  SetSize( pls, plsc->xlength, plsc->ylength );
307 
308  if ( pls->dev_data )
309  SetDC( pls, (wxDC *) pls->dev_data );
310  else
311  SetupMemoryMap();
312 
313  //this must be the absolute last thing that is done
314  //so that if an exception is thrown pls->dev remains as NULL
315  pls->dev = (void *) this;
316 }
317 
318 
319 //--------------------------------------------------------------------------
320 // wxPLDevice::~wxPLDevice( void )
321 //
322 // The deconstructor frees memory allocated by the device.
323 //--------------------------------------------------------------------------
325 {
326  if ( m_outputMemoryMap.isValid() )
327  {
329  header->completeFlag = 1;
330  }
331 }
332 
333 
334 //--------------------------------------------------------------------------
335 // void wxPLDevice::DrawLine( short x1a, short y1a, short x2a, short y2a )
336 //
337 // Draw a line from (x1a, y1a) to (x2a, y2a).
338 //--------------------------------------------------------------------------
339 void wxPLDevice::DrawLine( short x1a, short y1a, short x2a, short y2a )
340 {
341  if ( !m_dc )
342  return;
343 
344  Scaler scaler( m_dc, 1.0 / m_scale, 1.0 / m_scale );
345  DrawingObjectsChanger drawingObjectsChanger( m_dc, m_pen, m_brush );
346  m_dc->DrawLine( (wxCoord) ( m_xAspect * x1a ), (wxCoord) ( m_yAspect * ( m_plplotEdgeLength - y1a ) ),
347  (wxCoord) ( m_xAspect * x2a ), (wxCoord) ( m_yAspect * ( m_plplotEdgeLength - y2a ) ) );
348 }
349 
350 
351 //--------------------------------------------------------------------------
352 // void wxPLDevice::DrawPolyline( short *xa, short *ya, PLINT npts )
353 //
354 // Draw a poly line - coordinates are in the xa and ya arrays.
355 //--------------------------------------------------------------------------
356 void wxPLDevice::DrawPolyline( short *xa, short *ya, PLINT npts )
357 {
358  if ( !m_dc )
359  return;
360 
361  Scaler scaler( m_dc, 1.0 / m_scale, 1.0 / m_scale );
362  DrawingObjectsChanger drawingObjectsChanger( m_dc, m_pen, m_brush );
363  for ( PLINT i = 1; i < npts; i++ )
364  m_dc->DrawLine( m_xAspect * xa[i - 1], m_yAspect * ( m_plplotEdgeLength - ya[i - 1] ),
365  m_xAspect * xa[i], m_yAspect * ( m_plplotEdgeLength - ya[i] ) );
366 }
367 
368 
369 //--------------------------------------------------------------------------
370 // void wxPLDevice::ClearBackground( PLStream* pls, PLINT bgr, PLINT bgg, PLINT bgb,
371 // PLINT x1, PLINT y1, PLINT x2, PLINT y2 )
372 //
373 // Clear parts ((x1,y1) to (x2,y2)) of the background in color (bgr,bgg,bgb).
374 //--------------------------------------------------------------------------
376 {
377  if ( !m_dc )
378  return;
379 
380  x1 = x1 < 0 ? 0 : x1;
381  x2 = x2 < 0 ? m_plplotEdgeLength : x2;
382  y1 = y1 < 0 ? 0 : y1;
383  y2 = y2 < 0 ? m_plplotEdgeLength : y2;
384 
385  PLINT x = MIN( x1, x2 );
386  PLINT y = MIN( y1, y2 );
387  PLINT width = abs( x1 - x2 );
388  PLINT height = abs( y1 - y2 );
389 
390  if ( width > 0 && height > 0 )
391  {
392  PLINT r, g, b;
393  PLFLT a;
394  plgcolbga( &r, &g, &b, &a );
395  wxColour bgColour( r, g, b, a * 255 );
396  DrawingObjectsChanger changer( m_dc, wxPen( bgColour, 0 ), wxBrush( bgColour ) );
397  m_dc->DrawRectangle( x, y, width, height );
398  }
399 }
400 
401 
402 //--------------------------------------------------------------------------
403 // void wxPLDevice::FillPolygon( PLStream *pls )
404 //
405 // Draw a filled polygon.
406 //--------------------------------------------------------------------------
408 {
409  if ( !m_dc )
410  return;
411 
412  //edge the polygon with a 0.5 pixel line to avoid seams. This is a
413  //bit of a bodge really but this is a difficult problem
414  wxPen edgePen( m_brush.GetColour(), m_scale, wxSOLID );
415  DrawingObjectsChanger changer( m_dc, edgePen, m_brush );
416  //DrawingObjectsChanger changer(m_dc, wxNullPen, m_brush );
417  Scaler scaler( m_dc, 1.0 / m_scale, 1.0 / m_scale );
418  wxPoint *points = new wxPoint[pls->dev_npts];
419  wxCoord xoffset = 0;
420  wxCoord yoffset = 0;
421 
422  for ( int i = 0; i < pls->dev_npts; i++ )
423  {
424  points[i].x = (int) ( m_xAspect * pls->dev_x[i] );
425  points[i].y = (int) ( m_yAspect * ( m_plplotEdgeLength - pls->dev_y[i] ) );
426  }
427 
428  if ( pls->dev_eofill )
429  {
430  m_dc->DrawPolygon( pls->dev_npts, points, xoffset, yoffset, wxODDEVEN_RULE );
431  }
432  else
433  {
434  m_dc->DrawPolygon( pls->dev_npts, points, xoffset, yoffset, wxWINDING_RULE );
435  }
436  delete[] points;
437 }
438 
439 
440 //--------------------------------------------------------------------------
441 // void wxPLDevice::SetWidth( PLStream *pls )
442 //
443 // Set the width of the drawing pen.
444 //--------------------------------------------------------------------------
446 {
447  PLFLT width = ( pls->width > 0.0 ? pls->width : 1.0 ) * m_scale;
448  m_pen = wxPen( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b,
449  pls->curcolor.a * 255 ), width, wxSOLID );
450 }
451 
452 
453 //--------------------------------------------------------------------------
454 // void wxPLDevice::SetColor( PLStream *pls )
455 //
456 // Set color from PLStream.
457 //--------------------------------------------------------------------------
459 {
460  PLFLT width = ( pls->width > 0.0 ? pls->width : 1.0 ) * m_scale;
461  m_pen = wxPen( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b,
462  pls->curcolor.a * 255 ), width, wxSOLID );
463  m_brush = wxBrush( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b,
464  pls->curcolor.a * 255 ) );
465 }
466 
467 
468 //--------------------------------------------------------------------------
469 // void wxPLDevice::SetDC( PLStream *pls, void* dc )
470 //
471 // Adds a dc to the device. In that case, the drivers doesn't provide
472 // a GUI.
473 //--------------------------------------------------------------------------
474 void wxPLDevice::SetDC( PLStream *pls, wxDC* dc )
475 {
476  if ( m_outputMemoryMap.isValid() )
477  throw( "wxPLDevice::SetDC The DC must be set before initialisation. The device is outputting to a separate viewer" );
478  m_dc = dc; // Add the dc to the device
479  m_useDcTextTransform = false;
480  m_gc = NULL;
481  if ( m_dc )
482  {
483 #if wxVERSION_NUMBER >= 2902
484  m_useDcTextTransform = m_dc->CanUseTransformMatrix();
485 #endif
486  //If we don't have wxDC tranforms we can use the
487  //underlying wxGCDC if this is a wxGCDC
488  if ( !m_useDcTextTransform )
489  {
490  //check to see if m_dc is a wxGCDC by using RTTI
491  wxGCDC *gcdc = NULL;
492  try
493  {
494  //put this in a try block as I'm not sure if it will throw if
495  //RTTI is switched off
496  gcdc = dynamic_cast< wxGCDC* >( m_dc );
497  }
498  catch ( ... )
499  {
500  }
501  if ( gcdc )
502  m_gc = gcdc->GetGraphicsContext();
503  }
504 
505  strcpy( m_mfo, "" );
506  SetSize( pls, m_width, m_height ); //call with our current size to set the scaling
507  pls->has_string_length = 1; // Driver supports string length calculations, if we have a dc to draw on
508  }
509  else
510  {
511  pls->has_string_length = 0; //if we have no device to draw on we cannot check string size
512  }
513 }
514 
515 PLFLT getTextOffset( PLINT superscriptLevel, PLFLT baseFontSize )
516 {
517  if ( superscriptLevel == 0 )
518  return 0;
519  else
520  {
521  PLFLT fontScale = pow( 0.8, abs( superscriptLevel ) );
522  if ( superscriptLevel > 0 )
523  return getTextOffset( superscriptLevel - 1, baseFontSize ) + baseFontSize * fontScale / 2.;
524  else
525  return getTextOffset( superscriptLevel + 1, baseFontSize ) - baseFontSize * fontScale * 0.8 / 2.;
526  }
527 }
528 
529 //--------------------------------------------------------------------------
530 // void wxPLDevice::DrawText( PLUNICODE* ucs4, int ucs4Len, bool drawText )
531 //
532 // This is the function to draw text. Pass in a unicde string and its
533 // length and set drawText to true to actually draw the text or false to
534 // just get text metrics. This function will process the string for inline
535 // style change escapes and newlines.
536 //--------------------------------------------------------------------------
537 void wxPLDevice::DrawTextLine( PLUNICODE* ucs4, int ucs4Len, PLFLT baseFontSize, bool drawText, PLINT &superscriptLevel )
538 {
539  if ( !m_dc )
540  return;
541 
542  char utf8_string[m_max_string_length];
543  char utf8[5];
544  memset( utf8_string, '\0', m_max_string_length );
545 
546  // Get PLplot escape character
547  char plplotEsc;
548  plgesc( &plplotEsc );
549 
550  //Reset the size metrics
551  m_textWidth = 0;
552  m_textHeight = 0;
554  m_subscriptDepth = 0;
555 
556  int i = 0;
557  while ( i < ucs4Len )
558  {
559  if ( ucs4[i] < PL_FCI_MARK ) // not a font change
560  {
561  if ( ucs4[i] != (PLUNICODE) plplotEsc ) // a character to display
562  {
563  ucs4_to_utf8( ucs4[i], utf8 );
564  strncat( utf8_string, utf8,
565  sizeof ( utf8_string ) - strlen( utf8_string ) - 1 );
566  i++;
567  continue;
568  }
569  i++;
570  if ( ucs4[i] == (PLUNICODE) plplotEsc ) // a escape character to display
571  {
572  ucs4_to_utf8( ucs4[i], utf8 );
573  strncat( utf8_string, utf8,
574  sizeof ( utf8_string ) - strlen( utf8_string ) - 1 );
575  i++;
576  continue;
577  }
578  else
579  {
580  if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
581  { // draw string so far
582  PLFLT fontScale = pow( 0.8, abs( superscriptLevel ) );
583  PLFLT yOffset = getTextOffset( superscriptLevel, baseFontSize ) * m_yScale;
584  DrawTextSection( utf8_string, baseFontSize * fontScale, yOffset, drawText );
585 
586  ++superscriptLevel;
587  fontScale = pow( 0.8, abs( superscriptLevel ) );
588  m_dc->SetFont( GetFont( m_fci, baseFontSize * fontScale ) );
589  }
590  if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
591  { // draw string so far
592  PLFLT fontScale = pow( 0.8, abs( superscriptLevel ) );
593  PLFLT yOffset = getTextOffset( superscriptLevel, baseFontSize ) * m_yScale;
594  DrawTextSection( utf8_string, baseFontSize * fontScale, yOffset, drawText );
595 
596  --superscriptLevel;
597  fontScale = pow( 0.8, abs( superscriptLevel ) );
598  m_dc->SetFont( GetFont( m_fci, baseFontSize * fontScale ) );
599  }
600  if ( ucs4[i] == (PLUNICODE) '-' ) // underline
601  { // draw string so far
602  PLFLT fontScale = pow( 0.8, abs( superscriptLevel ) );
603  PLFLT yOffset = getTextOffset( superscriptLevel, baseFontSize ) * m_yScale;
604  DrawTextSection( utf8_string, baseFontSize * fontScale, yOffset, drawText );
605 
607  m_dc->SetFont( GetFont( m_fci, baseFontSize * fontScale ) );
608  }
609  if ( ucs4[i] == (PLUNICODE) '+' ) // overline
610  { // not implemented yet
611  }
612  i++;
613  }
614  }
615  else // a font change
616  {
617  // draw string so far
618  PLFLT fontScale = pow( 0.8, abs( superscriptLevel ) );
619  PLFLT yOffset = getTextOffset( superscriptLevel, baseFontSize ) * m_yScale;
620  DrawTextSection( utf8_string, baseFontSize * fontScale, yOffset, drawText );
621 
622  // get new font
623  m_fci = ucs4[i];
624  m_dc->SetFont( GetFont( m_fci, baseFontSize * fontScale ) );
625  i++;
626  }
627  }
628 
629  //we have reached the end of the string. Draw the remainder.
630  PLFLT fontScale = pow( 0.8, abs( superscriptLevel ) );
631  PLFLT yOffset = getTextOffset( superscriptLevel, baseFontSize ) * m_yScale;
632  DrawTextSection( utf8_string, baseFontSize * fontScale, yOffset, drawText );
633 }
634 
635 
636 //--------------------------------------------------------------------------
637 // void wxPLDevice::DrawTextSection( char* utf8_string, bool drawText )
638 //
639 // Draw a section of text. This should already have been processed and
640 // split into sections so that the text passed in has no style changes or
641 // newines.
642 //--------------------------------------------------------------------------
643 void wxPLDevice::DrawTextSection( char* utf8_string, PLFLT scaledFontSize, PLFLT yOffset, bool drawText )
644 {
645  if ( !m_dc )
646  return;
647 
648  wxCoord w, h, d, l;
649 
650  wxString str = wxString::FromUTF8( utf8_string );
651  //wxString str( wxConvUTF8.cMB2WC( utf8_string ), *wxConvCurrent );
652 
653  m_dc->GetTextExtent( str, &w, &h, &d, &l );
654 
655  if ( drawText )
656  {
657  //if we are using wxDC transforms or the wxGC, then the transformations
658  //have already been applied
659  if ( m_gc )
660  m_gc->DrawText( str, m_textWidth, -yOffset / m_yScale );
661  else if ( m_useDcTextTransform )
662  m_dc->DrawText( str, m_textWidth, -yOffset / m_yScale );
663  else
664  {
665  //If we are stuck with a wxDC that has no transformation abilities then
666  // all we can really do is rotate the text - this is a bit of a poor state
667  // really, but to be honest it is better than defaulting to hershey for all
668  // text
669  if ( m_rotation == 0 )
670  m_dc->DrawRotatedText( str, (wxCoord) ( m_posX + m_textWidth ),
671  (wxCoord) ( m_height - (wxCoord) ( m_posY + yOffset / m_yScale ) ),
672  m_rotation * 180.0 / M_PI );
673  else
674  m_dc->DrawRotatedText( str,
675  (wxCoord) ( m_posX - yOffset / m_yScale * sin( m_rotation ) + m_textWidth * cos( m_rotation ) ),
676  (wxCoord) ( m_height - (wxCoord) ( m_posY + yOffset * cos( m_rotation ) / m_yScale ) - m_textWidth * sin( m_rotation ) ),
677  m_rotation * 180.0 / M_PI );
678  }
679  }
680 
681  m_textWidth += w;
682 
683  //keep track of the height of superscript text, the depth of subscript
684  //text and the height of regular text
685  if ( yOffset > 0.0001 )
686  {
687  //determine the height the text would have if it were full size
688  double currentOffset = yOffset;
689  double currentHeight = h;
690  while ( currentOffset > 0.0001 )
691  {
692  currentOffset -= m_yScale * scaledFontSize / 2.;
693  currentHeight *= 1.25;
694  }
695  m_textHeight = (wxCoord) m_textHeight > ( currentHeight )
696  ? m_textHeight
697  : currentHeight;
698  //work out the height including superscript
699  m_superscriptHeight = m_superscriptHeight > ( currentHeight + yOffset / m_yScale )
701  : static_cast<int>( ( currentHeight + yOffset / m_yScale ) );
702  }
703  else if ( yOffset < -0.0001 )
704  {
705  //determine the height the text would have if it were full size
706  double currentOffset = yOffset;
707  double currentHeight = h;
708  double currentDepth = d;
709  while ( currentOffset < -0.0001 )
710  {
711  currentOffset += m_yScale * scaledFontSize * 1.25 / 2.;
712  currentHeight *= 1.25;
713  currentDepth *= 1.25;
714  }
715  m_textHeight = (wxCoord) m_textHeight > currentHeight ? m_textHeight : currentHeight;
716  //work out the additional depth for subscript note an assumption has been made
717  //that the font size of (non-superscript and non-subscript) text is the same
718  //along a line. Currently there is no escape to change font size mid string
719  //so this should be fine
720  m_subscriptDepth = (wxCoord) m_subscriptDepth > ( ( -yOffset / m_yScale + h + d ) - ( currentDepth + m_textHeight ) )
722  : ( ( -yOffset / m_yScale + h + d ) - ( currentDepth + m_textHeight ) );
724  }
725  else
726  m_textHeight = (wxCoord) m_textHeight > ( h ) ? m_textHeight : h;
727 
728  memset( utf8_string, '\0', m_max_string_length );
729 }
730 
731 
732 //--------------------------------------------------------------------------
733 // void wxPLDevice::SetFont( PLUNICODE fci )
734 //
735 // Set font defined by fci.
736 //--------------------------------------------------------------------------
737 wxFont wxPLDevice::GetFont( PLUNICODE fci, PLFLT scaledFontSize )
738 {
739  unsigned char fontFamily, fontStyle, fontWeight;
740 
741  plP_fci2hex( fci, &fontFamily, PL_FCI_FAMILY );
742  plP_fci2hex( fci, &fontStyle, PL_FCI_STYLE );
743  plP_fci2hex( fci, &fontWeight, PL_FCI_WEIGHT );
744 
745  //create the font based on point size ( with 1 point = 1/72 inch )
746  return wxFont( (int) ( scaledFontSize < 4 ? 4 : scaledFontSize ),
747  fontFamilyLookup[fontFamily],
748  fontStyleLookup[fontStyle],
749  fontWeightLookup[fontWeight],
750  m_underlined,
751  wxEmptyString,
752  wxFONTENCODING_DEFAULT
753  );
754 }
755 
756 
757 //--------------------------------------------------------------------------
758 // void wxPLDevice::ProcessString( PLStream* pls, EscText* args )
759 //
760 // This is the main function which processes the unicode text strings.
761 // Font size, rotation and color are set, width and height of the
762 // text string is determined and then the string is drawn to the canvas.
763 //--------------------------------------------------------------------------
765 {
766  if ( !m_dc )
767  return;
768 
769  //for text, work in native coordinates, partly to avoid rewriting existing code
770  //but also because we should get better text hinting for screen display I think.
771  //The scaler object sets the scale to the new value until it is destroyed
772  //when this function exits.
773  Scaler scaler( m_dc, 1.0, 1.0 );
774 
775  //Also move the origin so the text region buts up to the dc top, not the bottom
776  OriginChanger originChanger( m_dc, 0, m_height - m_plplotEdgeLength / m_yScale );
777 
778  // Check that we got unicode, warning message and return if not
779  if ( args->unicode_array_len == 0 )
780  {
781  printf( "Non unicode string passed to the wxWidgets driver, ignoring\n" );
782  return;
783  }
784 
785  // Check that unicode string isn't longer then the max we allow
786  if ( args->unicode_array_len >= 500 )
787  {
788  printf( "Sorry, the wxWidgets drivers only handles strings of length < %d\n", 500 );
789  return;
790  }
791 
792  // Calculate the font size (in pt)
793  // Plplot saves it in mm (bizarre units!)
794  PLFLT baseFontSize = pls->chrht * 72.0 / 25.4;
795 
796  // Use PLplot core routine to get the corners of the clipping rectangle
797  PLINT rcx[4], rcy[4];
798  difilt_clip( rcx, rcy );
799 
800  wxPoint cpoints[4];
801  for ( int i = 0; i < 4; i++ )
802  {
803  cpoints[i].x = rcx[i] / m_xScale;
804  cpoints[i].y = m_height - rcy[i] / m_yScale;
805  }
806  wxDCClipper clip( *m_dc, wxRegion( 4, cpoints ) );
807 
808  PLUNICODE *lineStart = args->unicode_array;
809  int lineLen = 0;
810  bool lineFeed = false;
811  bool carriageReturn = false;
812  wxCoord paraHeight = 0;
813  // Get the curent font
814  PLINT superscriptLevel = 0;
815  plgfci( &m_fci );
816  //set the font up, we use a textObjectChanger here so that the font returns
817  //to its original value on exit
818  TextObjectsChanger textObjectsChanger( m_dc, GetFont( m_fci, baseFontSize ),
819  wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b, pls->curcolor.a * 255 ),
820  wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b, pls->curcolor.a * 255 ) );
821 
822  //draw each line of text individually and record the width of the paragraph
823  wxCoord paragraphWidth = 0;
824  while ( lineStart != args->unicode_array + args->unicode_array_len )
825  {
826  //get the length of the line
827  while ( lineStart + lineLen != args->unicode_array + args->unicode_array_len
828  && *( lineStart + lineLen ) != (PLUNICODE) '\n' )
829  {
830  lineLen++;
831  }
832 
833  //set line feed for the beginning of this line and
834  //carriage return for the end
835  lineFeed = carriageReturn;
836  carriageReturn = lineStart + lineLen != args->unicode_array + args->unicode_array_len
837  && *( lineStart + lineLen ) == (PLUNICODE) ( '\n' );
838  if ( lineFeed )
839  paraHeight += m_textHeight + m_subscriptDepth;
840 
841  //remember the text parameters so they can be restored
842  double lineStartSuperscriptLevel = superscriptLevel;
843  PLUNICODE lineStartFci = m_fci;
844 
845  // determine extent of text
846  m_posX = args->x / m_xScale;
847  m_posY = args->y / m_yScale;
848  DrawTextLine( lineStart, lineLen, baseFontSize, false, superscriptLevel );
849  paragraphWidth = MAX( paragraphWidth, m_textWidth );
850 
851  if ( lineFeed && m_superscriptHeight > m_textHeight )
852  paraHeight += m_superscriptHeight - m_textHeight;
853 
854  // actually draw text, resetting the font first
855  if ( !pls->get_string_length )
856  {
857  superscriptLevel = lineStartSuperscriptLevel;
858  m_fci = lineStartFci;
859  m_dc->SetFont( GetFont( m_fci, pow( 0.8, abs( superscriptLevel ) ) * baseFontSize ) );
860 
861 
862  // calculate rotation of text
863  PLFLT shear;
864  PLFLT stride;
865  plRotationShear( args->xform, &m_rotation, &shear, &stride );
866  m_rotation -= pls->diorot * M_PI / 2.0;
867  PLFLT cos_rot = cos( m_rotation );
868  PLFLT sin_rot = sin( m_rotation );
869  PLFLT cos_shear = cos( shear );
870  PLFLT sin_shear = sin( shear );
871 
872  //Set the transform if possible and draw the text
873  if ( m_gc )
874  {
875  wxGraphicsMatrix originalMatrix = m_gc->GetTransform();
876 
877  m_gc->Translate( args->x / m_xScale, m_height - args->y / m_yScale ); //move to text starting position
878  wxGraphicsMatrix matrix = m_gc->CreateMatrix(
879  cos_rot * stride, -sin_rot * stride,
880  cos_rot * sin_shear + sin_rot * cos_shear,
881  -sin_rot * sin_shear + cos_rot * cos_shear,
882  0.0, 0.0 ); //create rotation transformation matrix
883  m_gc->ConcatTransform( matrix ); //rotate
884  m_gc->Translate( -args->just * m_textWidth, -0.5 * m_textHeight + paraHeight * m_lineSpacing ); //move to set alignment
885 
886  DrawTextLine( lineStart, lineLen, baseFontSize, true, superscriptLevel );
887  m_gc->SetTransform( originalMatrix );
888  }
889 #if wxVERSION_NUMBER >= 2902
890  else if ( m_useDcTextTransform )
891  {
892  wxAffineMatrix2D originalMatrix = m_dc->GetTransformMatrix();
893 
894  wxAffineMatrix2D newMatrix = originalMatrix;
895  newMatrix.Translate( args->x / m_xScale, m_height - args->y / m_yScale );
896  wxAffineMatrix2D textMatrix;
897  textMatrix.Set( wxMatrix2D( cos_rot * stride, -sin_rot * stride,
898  cos_rot * sin_shear + sin_rot * cos_shear,
899  -sin_rot * sin_shear + cos_rot * cos_shear ),
900  wxPoint2DDouble( 0.0, 0.0 ) );
901  newMatrix.Concat( textMatrix );
902  newMatrix.Translate( -args->just * m_textWidth, -0.5 * m_textHeight + paraHeight * m_lineSpacing );
903 
904  m_dc->SetTransformMatrix( newMatrix );
905  DrawTextLine( lineStart, lineLen, baseFontSize, true, superscriptLevel );
906  m_dc->SetTransformMatrix( originalMatrix );
907  }
908 #endif
909  else
910  {
911  m_posX = (PLINT) ( args->x / m_xScale - ( args->just * m_textWidth ) * cos_rot - ( 0.5 * m_textHeight - paraHeight * m_lineSpacing ) * sin_rot ); //move to set alignment
912  m_posY = (PLINT) ( args->y / m_yScale - ( args->just * m_textWidth ) * sin_rot + ( 0.5 * m_textHeight - paraHeight * m_lineSpacing ) * cos_rot );
913  DrawTextLine( lineStart, lineLen, baseFontSize, true, superscriptLevel );
914  }
915  }
916 
917  lineStart += lineLen;
918  if ( carriageReturn )
919  lineStart++;
920  lineLen = 0;
921  }
922 
923  //set the size of the string in mm
924  if ( pls->get_string_length )
925  pls->string_length = paragraphWidth * m_xScale / pls->xpmm;
926 }
927 
928 //--------------------------------------------------------------------------
929 // void wxPLDevice::EndPage( PLStream* pls )
930 // End the page. This is the point that we write the buffer to the memory
931 // mapped file if needed
932 //--------------------------------------------------------------------------
934 {
935  if ( !m_dc )
936  {
938  return;
939  }
940 }
941 
942 //--------------------------------------------------------------------------
943 // void wxPLDevice::BeginPage( PLStream* pls )
944 // Sets up for transfer in case it is needed and sets the current state
945 //--------------------------------------------------------------------------
947 {
948  if ( !m_dc )
949  {
952  }
953 
954  // Get the starting colour, width and font from the stream
955  SetWidth( pls );
956  SetColor( pls );
957 
958  //clear the page
959  ClearBackground( pls );
960 }
961 
962 //--------------------------------------------------------------------------
963 // void wxPLDevice::SetSize( PLStream* pls )
964 // Set the size of the page, scale parameters and the dpi
965 //--------------------------------------------------------------------------
966 void wxPLDevice::SetSize( PLStream* pls, int width, int height )
967 {
968  //we call BeginPage, before we fiddle with fixed aspect so that the
969  //whole background gets filled
970  // get boundary coordinates in plplot units
971  PLINT xmin;
972  PLINT xmax;
973  PLINT ymin;
974  PLINT ymax;
975  plP_gphy( &xmin, &xmax, &ymin, &ymax );
976  //split the scaling into an overall scale, the same in both dimensions
977  //and an aspect part which differs in both directions.
978  //We will apply the aspect ratio part, and let the DC do the overall
979  //scaling. This gives us subpixel accuray, but ensures line thickness
980  //remains consistent in both directions
981  m_xScale = width > 0 ? (PLFLT) ( xmax - xmin ) / (PLFLT) width : 0.0;
982  m_yScale = height > 0 ? (PLFLT) ( ymax - ymin ) / (PLFLT) height : 0.0;
984 
985  if ( !m_fixedAspect )
986  {
989  }
990  else
991  {
992  //now sort out the fixed aspect and reset the logical scale if needed
993  if ( PLFLT( height ) / PLFLT( width ) > m_yAspect / m_xAspect )
994  {
997  }
998  else
999  {
1002  }
1003  }
1004 
1005  m_width = ( xmax - xmin ) / m_xScale;
1006  pls->xlength = PLINT( m_width + 0.5 );
1007  m_height = ( ymax - ymin ) / m_yScale;
1008  pls->ylength = PLINT( m_height + 0.5 );
1009 
1010  // Set the number of plplot pixels per mm
1011  plP_setpxl( m_plplotEdgeLength / m_width * pls->xdpi / 25.4, m_plplotEdgeLength / m_height * pls->ydpi / 25.4 );
1012 
1013  pls->aspect = m_xAspect / m_yAspect;
1014 
1015  // redraw the plot
1016  if ( m_dc && pls->plbuf_buffer )
1017  plreplot();
1018 }
1019 
1020 
1022 {
1023  m_fixedAspect = fix;
1024 }
1025 
1027 {
1028  if ( !m_dc )
1030 }
1031 
1032 //This function transmits the remaining buffer to the gui program via a memory map
1033 //If the buffer is too big for the memory map then it will loop round waiting for
1034 //the gui to catch up each time
1035 // note that this function can be called with pls set to NULL for transmissions
1036 //of jsut a flag for e.g. page end or begin
1037 void wxPLDevice::TransmitBuffer( PLStream* pls, unsigned char transmissionType )
1038 {
1039  if ( !m_outputMemoryMap.isValid() )
1040  return;
1041  size_t amountToCopy = pls ? pls->plbuf_top - m_localBufferPosition : 0;
1042  bool first = true;
1043  size_t counter = 0;
1044  const size_t counterLimit = 10000;
1045  const size_t headerSize = sizeof ( transmissionType ) + sizeof ( size_t );
1046  bool completed = false;
1047  while ( !completed && counter < counterLimit )
1048  {
1049  //if we are doing multiple loops then pause briefly before we
1050  //lock to give the reading application a chance to spot the
1051  //change.
1052  if ( !first )
1053  wxMilliSleep( 10 );
1054  first = false;
1055 
1056 
1057  size_t copyAmount = 0;
1058  size_t freeSpace = 0;
1059  //lock the mutex so reading and writing don't overlap
1060  try
1061  {
1062  PLNamedMutexLocker lock( &m_mutex );
1064 
1065  //check how much free space we have before the end of the buffer
1066  //or if we have looped round how much free space we have before
1067  //we reach the read point
1068  freeSpace = m_outputMemoryMap.getSize() - mapHeader.writeLocation;
1069  // if readLocation is at the beginning then don't quite fill up the buffer
1070  if ( mapHeader.readLocation == plMemoryMapReservedSpace )
1071  --freeSpace;
1072 
1073  //if the free space left in the file is less than that needed for the header then
1074  //just tell the GUI to skip the rest of the file so it can start again at the
1075  //beginning of the file.
1076  if ( freeSpace <= headerSize )
1077  {
1078  if ( mapHeader.readLocation > mapHeader.writeLocation ) //don't overtake the read buffer
1079  freeSpace = 0;
1080  else if ( mapHeader.readLocation == plMemoryMapReservedSpace ) // don't catch up exactly with the read buffer
1081  freeSpace = 0;
1082  else
1083  {
1084  //send a skip end of file command and move back to the beginning of the file
1085  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1086  (void *) ( &transmissionSkipFileEnd ), sizeof ( transmissionSkipFileEnd ) );
1088  counter = 0;
1089  continue;
1090  }
1091  }
1092 
1093  //if this is a beginning of page then send a beginning of page flag first
1094  if ( transmissionType == transmissionBeginPage )
1095  {
1096  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1097  (void *) ( &transmissionBeginPage ), sizeof ( transmissionBeginPage ) );
1098  mapHeader.writeLocation += sizeof ( transmissionBeginPage );
1099  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1101  counter = 0;
1102  if ( amountToCopy == 0 )
1103  completed = true;
1104  transmissionType = transmissionRegular;
1105  continue;
1106  }
1107 
1108  //if this is a end of page and we have completed
1109  //the buffer then send a end of page flag first
1110  if ( transmissionType == transmissionEndOfPage && amountToCopy == 0 )
1111  {
1112  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1113  (void *) ( &transmissionEndOfPage ), sizeof ( transmissionEndOfPage ) );
1114  mapHeader.writeLocation += sizeof ( transmissionEndOfPage );
1115  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1117  counter = 0;
1118  completed = true;
1119  continue;
1120  }
1121 
1122  if ( transmissionType == transmissionLocate && amountToCopy == 0 )
1123  {
1124  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1125  (void *) ( &transmissionLocate ), sizeof ( transmissionLocate ) );
1126  mapHeader.writeLocation += sizeof ( transmissionEndOfPage );
1127  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1129  mapHeader.locateModeFlag = 1;
1130  counter = 0;
1131  completed = true;
1132  continue;
1133  }
1134 
1135  //if we have looped round stay 1 character behind the read buffer - it makes it
1136  //easier to test whether the reading has caught up with the writing or vica versa
1137  if ( mapHeader.writeLocation < mapHeader.readLocation && mapHeader.readLocation > 0 )
1138  freeSpace = mapHeader.readLocation - mapHeader.writeLocation - 1;
1139 
1140  if ( freeSpace > headerSize )
1141  {
1142  //decide exactly how much to copy
1143  copyAmount = MIN( amountToCopy, freeSpace - headerSize );
1144 
1145  //copy the header and the amount we can to the buffer
1146  if ( copyAmount != amountToCopy )
1147  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1148  (char *) ( &transmissionPartial ), sizeof ( transmissionPartial ) );
1149  else
1150  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1151  (char *) ( &transmissionComplete ), sizeof ( transmissionComplete ) );
1152  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation + sizeof ( transmissionComplete ),
1153  (char *) ( &copyAmount ), sizeof ( copyAmount ) );
1154  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation + headerSize,
1155  (char *) pls->plbuf_buffer + m_localBufferPosition, copyAmount );
1156  m_localBufferPosition += copyAmount;
1157  mapHeader.writeLocation += copyAmount + headerSize;
1158  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1160  amountToCopy -= copyAmount;
1161  counter = 0;
1162  if ( amountToCopy == 0 && transmissionType != transmissionEndOfPage
1163  && transmissionType != transmissionLocate )
1164  completed = true;
1165  }
1166  else
1167  {
1168  ++counter;
1169  }
1170  }
1171 #ifdef WIN32
1172  catch ( DWORD )
1173  {
1174  plwarn( "Locking mutex failed when trying to communicate with wxPLViewer." );
1175  break;
1176  }
1177 #endif
1178  catch ( ... )
1179  {
1180  plwarn( "Unknown error when trying to communicate with wxPLViewer." );
1181  break;
1182  }
1183  }
1184  if ( counter == counterLimit )
1185  {
1186  plwarn( "Communication timeout with wxPLViewer - disconnecting" );
1188  }
1189 }
1190 
1192 {
1193  if ( strlen( m_mfo ) > 0 )
1194  {
1195  const size_t mapSize = 1024 * 1024;
1196  //create a memory map to hold the data and add it to the array of maps
1197  int nTries = 0;
1198  char mapName[PLPLOT_MAX_PATH];
1199  char mutexName[PLPLOT_MAX_PATH];
1200  static Rand randomGenerator; // make this static so that rapid repeat calls don't use the same seed
1201  while ( nTries < 10 )
1202  {
1203  for ( int i = 0; i < strlen( m_mfo ); ++i )
1204  {
1205  if ( m_mfo[i] == '?' )
1206  mapName[i] = 'A' + (char) ( randomGenerator() % 26 );
1207  else
1208  mapName[i] = m_mfo[i];
1209  }
1210  mapName[strlen( m_mfo )] = '\0';
1211  //truncate it earlier if needed
1212  if ( strlen( m_mfo ) > PLPLOT_MAX_PATH - 4 )
1213  mapName[PLPLOT_MAX_PATH - 4] = '\0';
1214  pldebug( "wxPLDevice::SetupMemoryMap", "nTries = %d, mapName = %s\n", nTries, mapName );
1215  strcpy( mutexName, mapName );
1216  strcat( mutexName, "mut" );
1217  pldebug( "wxPLDevice::SetupMemoryMap", "nTries = %d, mutexName = %s\n", nTries, mutexName );
1218  m_outputMemoryMap.create( mapName, mapSize, false, true );
1219  if ( m_outputMemoryMap.isValid() )
1220  m_mutex.create( mutexName );
1221  if ( !m_mutex.isValid() )
1223  if ( m_outputMemoryMap.isValid() )
1224  break;
1225  ++nTries;
1226  }
1227  //m_outputMemoryMap.create( m_mfo, pls->plbuf_top, false, true );
1228  //check the memory map is valid
1229  if ( !m_outputMemoryMap.isValid() )
1230  {
1231  plwarn( "Error creating memory map for wxWidget instruction transmission. The plots will not be displayed" );
1232  return;
1233  }
1234 
1235  //zero out the reserved area
1239  header->viewerOpenFlag = 0;
1240  header->locateModeFlag = 0;
1241  header->completeFlag = 0;
1242 
1243  //try to find the wxPLViewer executable, in the first instance just assume it
1244  //is in the path.
1245  wxString exeName = wxT( "wxPLViewer" );
1246  if ( plInBuildTree() )
1247  {
1248  //if we are in the build tree check for the needed exe in there
1249  wxArrayString files;
1250  wxDir::GetAllFiles( wxT( BUILD_DIR ), &files, exeName, wxDIR_FILES | wxDIR_DIRS );
1251  if ( files.size() == 0 )
1252  wxDir::GetAllFiles( wxT( BUILD_DIR ), &files, exeName + wxT( ".exe" ), wxDIR_FILES | wxDIR_DIRS );
1253  if ( files.size() > 0 )
1254  exeName = files[0];
1255  }
1256  else
1257  {
1258  //check the plplot bin install directory
1259  wxArrayString files;
1260  wxDir::GetAllFiles( wxT( BIN_DIR ), &files, exeName, wxDIR_FILES | wxDIR_DIRS );
1261  if ( files.size() == 0 )
1262  wxDir::GetAllFiles( wxT( BIN_DIR ), &files, exeName + wxT( ".exe" ), wxDIR_FILES | wxDIR_DIRS );
1263  if ( files.size() > 0 )
1264  exeName = files[0];
1265  }
1266  //Run the wxPlViewer with command line parameters telling it the location and size of the buffer
1267  wxString command;
1268  command << wxT( "\"" ) << exeName << wxT( "\" " ) << wxString( mapName, wxConvUTF8 ) << wxT( " " ) <<
1269  mapSize << wxT( " " ) << m_width << wxT( " " ) << m_height;
1270 #ifndef WXPLVIEWER_DEBUG
1271 #ifdef WIN32
1272 
1273  if ( wxExecute( command, wxEXEC_ASYNC ) == 0 )
1274  plwarn( "Failed to run wxPLViewer - no plots will be shown" );
1275 #else //WIN32
1276  //Linux doesn't like using wxExecute without a wxApp, so use system instead
1277  command << wxT( " &" );
1278  system( command.mb_str() );
1279 #endif //WIN32
1280  size_t maxTries = 1000;
1281 #else //WXPLVIEWER_DEBUG
1282  fprintf( stdout, "Begin Running wxPLViewer in the debugger now to continue." );
1283  size_t maxTries = 100000;
1284 #endif //WXPLVIEWER_DEBUG
1285  //wait until the viewer signals it has opened the map file
1286  size_t counter = 0;
1287  size_t &viewerSignal = header->viewerOpenFlag;
1288  while ( counter < maxTries && viewerSignal == 0 )
1289  {
1290  wxMilliSleep( 10 );
1291  }
1292  if ( viewerSignal == 0 )
1293  plwarn( "wxPLViewer failed to signal it has found the shared memory." );
1294  }
1295 }
1296 
1297 void wxPLDevice::Locate( PLStream* pls, PLGraphicsIn *graphicsIn )
1298 {
1299  if ( !m_dc && m_outputMemoryMap.isValid() )
1300  {
1303  bool gotResponse = false;
1304  while ( !gotResponse )
1305  {
1306  wxMilliSleep( 100 );
1307  PLNamedMutexLocker lock( &m_mutex );
1308  gotResponse = header->locateModeFlag == 0;
1309  }
1310 
1311  PLNamedMutexLocker lock( &m_mutex );
1312  *graphicsIn = header->graphicsIn;
1313  }
1314  else
1315  {
1316  plwarn( "plGetCursor cannot be used when the user supplies a wxDC or until wxPLViewer is initialised" );
1317  graphicsIn->dX = -1;
1318  graphicsIn->dY = -1;
1319  graphicsIn->pX = -1;
1320  graphicsIn->pY = -1;
1321  }
1322 }