PLplot  5.15.0
wxwidgets_dev.cpp
Go to the documentation of this file.
1 // Copyright (C) 2015-2017 Phil Rosenberg
2 // Copyright (C) 2017-2018 Alan W. Irwin
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 #define DEBUG
25 #define NEED_PLDEBUG
26 
27 // Set this to help when debugging wxPLViewer issues. It uses a memory
28 // map name without random characters and does not execute the viewer,
29 // allowing the user to execute the viewer 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 due to
35 // 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 #include <wx/ustring.h>
49 
50 // std and driver headers
51 #include <cmath>
52 #include <limits>
53 
54 // Needed for cerr, etc.
55 #if defined ( WXPLVIEWER_DEBUG ) || defined ( PLPLOT_WX_DEBUG_OUTPUT )
56 #include <iostream>
57 #endif
58 
59 //--------------------------------------------------------------------------
60 // PlDevice::PlDevice()
61 //
62 // Constructor for wxPLDevice
63 //--------------------------------------------------------------------------
65 {
66  m_prevSymbol = 0;
67  m_prevBaseFontSize = 0.;
68  m_prevLevel = 0;
69  m_prevFci = 0;
72 }
73 
74 //--------------------------------------------------------------------------
75 // void wxPLDevice::DrawText( PLStream* pls, EscText* args )
76 //
77 // This is the main function which processes the unicode text strings.
78 // Font size, rotation and color are set, width and height of the
79 // text string is determined and then the string is drawn to the canvas.
80 //--------------------------------------------------------------------------
82 {
83  // Split the text into lines separated by forced linebreak '\n' characters
84  // inserted by the user.
85  typedef std::pair< PLUNICODE *, PLUNICODE *> uniIterPair;
86  PLUNICODE *textEnd = args->unicode_array + args->unicode_array_len;
87  PLUNICODE lf = PLUNICODE( '\n' );
88  std::vector< uniIterPair > lines( 1, uniIterPair( args->unicode_array, textEnd ) );
89  for ( PLUNICODE * uni = args->unicode_array; uni != textEnd; ++uni )
90  {
91  if ( *uni == lf )
92  {
93  lines.back().second = uni;
94  lines.push_back( uniIterPair( uni + 1, textEnd ) );
95  }
96  }
97 
98  // Check that we got unicode, warning message and return if not
99  if ( args->unicode_array_len == 0 )
100  {
101  printf( "Non unicode string passed to the wxWidgets driver, ignoring\n" );
102  return;
103  }
104 
105  // Check that unicode string isn't longer then the max we allow
106  if ( args->unicode_array_len >= 500 )
107  {
108  printf( "Sorry, the wxWidgets drivers only handles strings of length < %d\n", 500 );
109  return;
110  }
111 
112  // Calculate the font size (in pt)
113  // PLplot saves it in mm (bizarre units!)
115 
116  //initialize the text state
117  PLUNICODE currentFci;
118  plgfci( &currentFci );
119  bool currentUnderlined = false;
120 
121  //Get the size of each line. Even for left aligned text
122  //we still need the text height to vertically align text
123  std::vector<wxCoord> lineWidths( lines.size() );
124  std::vector<wxCoord> lineHeights( lines.size() );
125  std::vector<wxCoord> lineDepths( lines.size() );
126  {
127  // Get the text length without drawing it. Also, determine
128  // lineWidths, lineHeights, and lineDepths arrays that are required
129  // for the actual draw.
130  wxCoord paraWidth = 0;
131  wxCoord paraHeight = 0;
132  PLUNICODE testFci = currentFci;
133  bool testUnderlined = currentUnderlined = false;
134  PLFLT identityMatrix[6];
135  plP_affine_identity( identityMatrix );
136  for ( size_t i = 0; i < lines.size(); ++i )
137  {
138  DrawTextLine( lines[i].first, lines[i].second - lines[i].first, 0, 0, 0, 0, identityMatrix, baseFontSize, false,
139  testUnderlined, testFci,
140  0, 0, 0, 0.0, lineWidths[i], lineHeights[i], lineDepths[i] );
141  paraWidth = MAX( paraWidth, lineWidths[i] );
142  paraHeight += lineHeights[i] + lineDepths[i];
143  }
144  pls->string_length = paraWidth / pls->xpmm;
145  }
146 
147  if ( !pls->get_string_length )
148  {
149  // Draw the text string if requested by PLplot. The needed lineWidths,
150  // lineHeights, and lineDepths arrays are determined above.
151  wxCoord cumSumHeight = 0;
152  // Plplot doesn't include plot orientation in args->xform, so we must
153  // rotate the text if needed;
154  PLFLT textTransform[6];
155  PLFLT diorot = pls->diorot - 4.0 * floor( pls->diorot / 4.0 ); //put diorot in range 0-4
156  textTransform[0] = args->xform[0];
157  textTransform[2] = args->xform[1];
158  textTransform[1] = args->xform[2];
159  textTransform[3] = args->xform[3];
160  textTransform[4] = 0.0;
161  textTransform[5] = 0.0;
162  PLFLT diorotTransform[6];
163  if ( diorot == 0.0 )
164  {
165  diorotTransform[0] = 1;
166  diorotTransform[1] = 0;
167  diorotTransform[2] = 0;
168  diorotTransform[3] = 1;
169  }
170  else if ( diorot == 1.0 )
171  {
172  diorotTransform[0] = 0;
173  diorotTransform[1] = -1;
174  diorotTransform[2] = 1;
175  diorotTransform[3] = 0;
176  }
177  else if ( diorot == 2.0 )
178  {
179  diorotTransform[0] = -1;
180  diorotTransform[1] = 0;
181  diorotTransform[2] = 0;
182  diorotTransform[3] = -1;
183  }
184  else if ( diorot == 3.0 )
185  {
186  diorotTransform[0] = 0;
187  diorotTransform[1] = 1;
188  diorotTransform[2] = -1;
189  diorotTransform[3] = 0;
190  }
191  else
192  {
193  PLFLT angle = diorot * M_PI / 2.0;
194  PLFLT cosAngle = cos( angle );
195  PLFLT sinAngle = sin( angle );
196  diorotTransform[0] = cosAngle;
197  diorotTransform[1] = -sinAngle;
198  diorotTransform[2] = sinAngle;
199  diorotTransform[3] = cosAngle;
200  }
201  diorotTransform[4] = 0;
202  diorotTransform[5] = 0;
203 
204  PLFLT finalTransform[6];
205  memcpy( finalTransform, textTransform, sizeof ( PLFLT ) * 6 );
206  plP_affine_multiply( finalTransform, textTransform, diorotTransform );
207 
208  std::vector<wxCoord> lineWidths_ignored( lines.size() );
209  std::vector<wxCoord> lineHeights_ignored( lines.size() );
210  std::vector<wxCoord> lineDepths_ignored( lines.size() );
211  for ( size_t i = 0; i < lines.size(); ++i )
212  {
213  DrawTextLine( lines[i].first, lines[i].second - lines[i].first,
214  args->x,
215  args->y,
216  -lineWidths[i] * args->just, 0.5 * ( lineHeights[i] ) - cumSumHeight,
217  finalTransform, baseFontSize, true,
218  currentUnderlined,
219  currentFci, pls->curcolor.r, pls->curcolor.g, pls->curcolor.b, pls->curcolor.a, lineWidths_ignored[i],
220  lineHeights_ignored[i], lineDepths_ignored[i] );
221 
222  // Ignore the ignored versions even though gdb tells me
223  // (AWI) they are the same as the unignored versions
224  // determined above for the DrawText false case (as
225  // expected from inspection of the DrawTextLine code).
226  cumSumHeight += lineHeights[i] + lineDepths[i];
227  }
228  }
229 }
230 
231 // This function will draw a line of text given by ucs4 with ucs4Len
232 // characters. The ucs4 argument must not contain any newline characters.
233 // basefontSize is the size of a full size character in points. Pass
234 // in underlined flag and fci for the beginning of the line. On
235 // return they will be filled with the values at the end of the line.
236 // On return textWidth, textHeigth and textDepth will be filled with
237 // the width, ascender height and descender depth of the text string.
238 // If drawText is true the text will actually be drawn. If it is
239 // false the size will be calculated but the text will not be
240 // rendered.
241 
242 void PlDevice::DrawTextLine( PLUNICODE* ucs4, int ucs4Len, wxCoord xOrigin, wxCoord yOrigin, wxCoord x, wxCoord y, PLFLT *transform, PLFLT baseFontSize, bool drawText, bool &underlined, PLUNICODE &fci, unsigned char red, unsigned char green, unsigned char blue, PLFLT alpha, wxCoord &textWidth, wxCoord &textHeight, wxCoord &textDepth )
243 {
244  PLINT level = 0;
245  PLFLT oldScale;
246  PLFLT Scale = 1.;
247  PLFLT scaledFontSize = baseFontSize;
248  PLFLT oldOffset;
249  PLFLT Offset = 0.;
250  PLFLT yScale;
251  PLFLT scaledOffset = 0.;
252 
253  // Factor of 1.2 is an empirical correction to work around a bug
254  // where the calculated symmetrical subscript and superscript
255  // offset arguments of DrawTextSection are rendered in that
256  // routine in an asymmetical way (with subscript levels having a
257  // differently rendered offset than the corresponding superscript
258  // level). Of course, fixing this DrawTextSection bug is far
259  // preferable to this workaround, but I have been unable to find
260  // that bug in DrawTextSection so I am leaving this ultimate fix
261  // until later.
262 
263  PLFLT empiricalSymmetricFactor = 1.2;
264 
265  wxCoord sectionWidth;
266  wxCoord sectionHeight;
267  wxCoord sectionDepth;
268 
269  // check if we have the same symbol as last time - only do this for single characters
270  // (e.g., typical plstring use).
271  if ( !drawText
272  && ucs4Len == 1
273  && ucs4[0] == m_prevSymbol
274  && baseFontSize == m_prevBaseFontSize
275  && level == m_prevLevel
276  && fci == m_prevFci )
277  {
278  textWidth = m_prevSymbolWidth;
279  textHeight = m_prevSymbolHeight;
280  textDepth = m_prevSymbolDepth;
281  return;
282  }
283 
284  wxString section;
285 
286  PLFLT sectionTransform[6];
287  memcpy( sectionTransform, transform, sizeof ( sectionTransform ) );
288 
289  // Get PLplot escape character
290  char plplotEsc;
291  plgesc( &plplotEsc );
292 
293  // Reset the size metrics
294  textWidth = 0;
295  textHeight = 0;
296  textDepth = 0;
297 
298  int i = 0;
299  while ( i < ucs4Len )
300  {
301  if ( ucs4[i] == (PLUNICODE) plplotEsc )
302  {
303  // We found an escape character. Move to the next character to see what we need to do next
304  ++i;
305  if ( ucs4[i] == (PLUNICODE) plplotEsc )
306  {
307  // Add the actual escape character to the string
308  section += wxUString( (wxChar32) ucs4[i] );
309  }
310  else
311  {
312  // We have a change of state. Output the string so far
313  DrawTextSection( section, xOrigin, yOrigin, x + textWidth, y + scaledOffset, transform,
314  scaledFontSize, drawText, underlined, fci, red, green, blue, alpha, yScale, sectionWidth, sectionHeight, sectionDepth );
315  textWidth += sectionWidth;
316  textHeight = MAX( textHeight, sectionHeight + scaledOffset );
317  textDepth = MAX( textDepth, sectionDepth - scaledOffset );
318  section = wxEmptyString;
319 
320  // Act on the escape character
321  if ( ucs4[i] == (PLUNICODE) 'u' )
322  {
323  // Superscript escape
324 
325  // y, textHeight, and textDepth are all scaled
326  // quantities so any offset-related variable that
327  // is linearly combined with them such as
328  // scaledOffset must be scaled as well. Offset is
329  // always positive so the last factor is to give
330  // scaledOffset the correct sign depending on
331  // level.
332  plP_script_scale( TRUE, &level, &oldScale, &Scale, &oldOffset, &Offset );
333  scaledFontSize = baseFontSize * Scale;
334  scaledOffset = yScale * Offset * baseFontSize * ( level > 0 ? 1.0 / empiricalSymmetricFactor : -1.0 * empiricalSymmetricFactor );
335  }
336  else if ( ucs4[i] == (PLUNICODE) 'd' )
337  {
338  // Subscript escape
339 
340  // y, textHeight, and textDepth are all scaled
341  // quantities so any offset-related variable that
342  // is linearly combined with them such as
343  // scaledOffset must be scaled as well. Offset is
344  // always positive so the last factor is to give
345  // scaledOffset the correct sign depending on
346  // level.
347  plP_script_scale( FALSE, &level, &oldScale, &Scale, &oldOffset, &Offset );
348  scaledFontSize = baseFontSize * Scale;
349  scaledOffset = yScale * Offset * baseFontSize * ( level > 0 ? 1.0 / empiricalSymmetricFactor : -1.0 * empiricalSymmetricFactor );
350  }
351  else if ( ucs4[i] == (PLUNICODE) '-' ) // underline
352  underlined = !underlined;
353  else if ( ucs4[i] == (PLUNICODE) '+' ) // overline
354  { // not implemented yet
355  }
356  }
357  }
358  else if ( ucs4[i] >= PL_FCI_MARK )
359  {
360  // A font change
361  // draw string so far
362  DrawTextSection( section, xOrigin, yOrigin, x + textWidth, y + scaledOffset, transform,
363  scaledFontSize, drawText, underlined, fci, red, green, blue, alpha, yScale, sectionWidth, sectionHeight, sectionDepth );
364  textWidth += sectionWidth;
365  textHeight = MAX( textHeight, sectionHeight + scaledOffset );
366  textDepth = MAX( textDepth, sectionDepth - scaledOffset );
367  section = wxEmptyString;
368 
369  // Get new fci
370  fci = ucs4[i];
371  }
372  else
373  {
374  // Just a regular character - add it to the string
375  section += wxUString( (wxChar32) ucs4[i] );
376  }
377 
378  ++i;
379  }
380 
381  // We have reached the end of the string. Draw the last section.
382  DrawTextSection( section, xOrigin, yOrigin, x + textWidth, y + scaledOffset, transform,
383  scaledFontSize, drawText, underlined, fci, red, green, blue, alpha, yScale, sectionWidth, sectionHeight, sectionDepth );
384  textWidth += sectionWidth;
385  textHeight = MAX( textHeight, sectionHeight + scaledOffset );
386  textDepth = MAX( textDepth, sectionDepth - scaledOffset );
387 
388  // If this was a single character remember its size as it is
389  // likely to be requested repeatedly (e.g., typical plstring use).
390  if ( ucs4Len == 1 )
391  {
392  m_prevSymbol = ucs4[0];
393  m_prevBaseFontSize = baseFontSize;
394  m_prevLevel = level;
395  m_prevFci = fci;
396  m_prevSymbolWidth = textWidth;
397  m_prevSymbolHeight = textHeight;
398  m_prevSymbolDepth = textDepth;
399  }
400 }
401 
402 //--------------------------------------------------------------------------
403 // Scaler class
404 // This class changes the logical scale of a dc on construction and resets
405 // it to its original value on destruction. It is ideal for making temporary
406 // changes to the scale and guaranteeing that the scale gets set back.
407 //--------------------------------------------------------------------------
408 class Scaler
409 {
410 public:
411  Scaler( wxDC * dc, double xScale, double yScale )
412  {
413  m_dc = dc;
414  if ( m_dc )
415  {
416  dc->GetUserScale( &m_xScaleOld, &m_yScaleOld );
417  dc->SetUserScale( xScale, yScale );
418  }
419  }
421  {
422  if ( m_dc )
423  m_dc->SetUserScale( m_xScaleOld, m_yScaleOld );
424  }
425 private:
426  wxDC *m_dc;
427  double m_xScaleOld;
428  double m_yScaleOld;
429  Scaler & operator=( const Scaler & );
430  Scaler ( const Scaler & );
431 };
432 
433 //--------------------------------------------------------------------------
434 // OriginChanger class
435 // This class changes the logical origin of a dc on construction and resets
436 // it to its original value on destruction. It is ideal for making temporary
437 // changes to the origin and guaranteeing that the scale gets set back.
438 //--------------------------------------------------------------------------
440 {
441 public:
442  OriginChanger( wxDC * dc, wxCoord xOrigin, wxCoord yOrigin )
443  {
444  m_dc = dc;
445  if ( m_dc )
446  {
447  dc->GetLogicalOrigin( &m_xOriginOld, &m_yOriginOld );
448  dc->SetLogicalOrigin( xOrigin, yOrigin );
449  }
450  }
452  {
453  if ( m_dc )
454  m_dc->SetLogicalOrigin( m_xOriginOld, m_yOriginOld );
455  }
456 private:
457  wxDC *m_dc;
458  wxCoord m_xOriginOld;
459  wxCoord m_yOriginOld;
462 };
463 
464 //--------------------------------------------------------------------------
465 // DrawingObjectsChanger class
466 // This class changes the pen and brush of a dc on construction and resets
467 // them to their original values on destruction. It is ideal for making temporary
468 // changes to the pen and brush and guaranteeing that they get set back.
469 //--------------------------------------------------------------------------
471 {
472 public:
473  DrawingObjectsChanger( wxDC *dc, const wxPen &pen, const wxBrush &brush )
474  {
475  m_dc = dc;
476  if ( m_dc )
477  {
478  m_pen = dc->GetPen();
479  m_brush = dc->GetBrush();
480  dc->SetPen( pen );
481  dc->SetBrush( brush );
482  }
483  }
485  {
486  if ( m_dc )
487  {
488  m_dc->SetPen( m_pen );
489  m_dc->SetBrush( m_brush );
490  }
491  }
492 private:
493  wxDC *m_dc;
494  wxPen m_pen;
495  wxBrush m_brush;
498 };
499 
500 //--------------------------------------------------------------------------
501 //TextObjectsSaver class
502 //This class saves the text rendering details of a dc on construction and
503 //resets them to their original values on destruction. It can be used to
504 //ensure the restoration of state when a scope is exited
505 //--------------------------------------------------------------------------
507 {
508 public:
509  TextObjectsSaver( wxDC *dc )
510  {
511  m_dc = dc;
512  if ( m_dc )
513  {
514  m_font = dc->GetFont();
515  m_textForeground = dc->GetTextForeground();
516  m_textBackground = dc->GetTextBackground();
517  }
518  }
520  {
521  if ( m_dc )
522  {
523  m_dc->SetTextForeground( m_textForeground );
524  m_dc->SetTextBackground( m_textBackground );
525  m_dc->SetFont( m_font );
526  }
527  }
528 private:
529  wxDC *m_dc;
530  wxFont m_font;
535 };
536 
537 //--------------------------------------------------------------------------
538 // TextObjectsChanger class
539 // This class changes the font and text colours of a dc on construction and resets
540 // them to their original values on destruction. It is ideal for making temporary
541 // changes to the text and guaranteeing that they get set back.
542 //--------------------------------------------------------------------------
544 {
545 public:
546  TextObjectsChanger( wxDC *dc, const wxFont &font, const wxColour &textForeground, const wxColour &textBackground )
547  : m_saver( dc )
548  {
549  if ( dc )
550  {
551  dc->SetTextForeground( textForeground );
552  dc->SetTextBackground( textBackground );
553  dc->SetFont( font );
554  }
555  }
556  TextObjectsChanger( wxDC *dc, const wxFont &font )
557  : m_saver( dc )
558  {
559  if ( dc )
560  dc->SetFont( font );
561  }
562  TextObjectsChanger( wxDC *dc, FontGrabber &fontGrabber, PLUNICODE fci, PLFLT size, bool underlined, const wxColour &textForeground, const wxColour &textBackground )
563  : m_saver( dc )
564  {
565  if ( dc )
566  {
567  wxFont font = fontGrabber.GetFont( fci, size, underlined ).getWxFont();
568  dc->SetTextForeground( textForeground );
569  dc->SetTextBackground( textBackground );
570  dc->SetFont( font );
571  }
572  }
573 private:
577 };
578 
579 //--------------------------------------------------------------------------
580 // Clipper class
581 // This class changes the clipping region of a dc on construction and restores
582 // it to its previous region on destruction. It is ideal for making temporary
583 // changes to the clip region and guaranteeing that the scale gets set back.
584 //
585 // It turns out that clipping is mostly broken for wxGCDC - see
586 // http://trac.wxwidgets.org/ticket/17013. So there are a lot of things in
587 // this class to work around those bugs. In particular you should check
588 // isEveryThingClipped before drawing as I'm not sure if non-overlapping
589 //clip regions behave properly.
590 //--------------------------------------------------------------------------
591 class Clipper
592 {
593 public:
594  Clipper( wxDC * dc, const wxRect &rect )
595  {
596  m_dc = dc;
597  m_clipEverything = true;
598  if ( m_dc )
599  {
600  dc->GetClippingBox( m_boxOld );
601  wxRect newRect = rect;
602  m_clipEverything = !( newRect.Intersects( m_boxOld )
603  || ( m_boxOld.width == 0 && m_boxOld.height == 0 ) );
604  if ( m_clipEverything )
605  dc->SetClippingRegion( wxRect( -1, -1, 1, 1 ) ); //not sure if this works
606  else
607  dc->SetClippingRegion( rect );
608  }
609  }
611  {
612  if ( m_dc )
613  {
614  m_dc->DestroyClippingRegion();
615  m_dc->SetClippingRegion( wxRect( 0, 0, 0, 0 ) );
616  m_dc->DestroyClippingRegion();
617  if ( m_boxOld.width != 0 && m_boxOld.height != 0 )
618  m_dc->SetClippingRegion( m_boxOld );
619  }
620  }
622  {
623  return m_clipEverything;
624  }
625 private:
626  wxDC *m_dc;
627  wxRect m_boxOld;
629  Clipper & operator=( const Clipper & );
630  Clipper ( const Clipper & );
631 };
632 
633 //--------------------------------------------------------------------------
634 // class Rand
635 // This is a simple random number generator class, created solely so that
636 // random numbers can be generated in this file without "contaminating" the
637 // global series of random numbers with a new seed.
638 // It uses an algorithm that apparently used to be used in gcc rand()
639 // provided under GNU LGPL v2.1.
640 //--------------------------------------------------------------------------
641 class Rand
642 {
643 public:
645  {
646 #ifdef _WIN32
647  rand_s( &m_seed );
648 #else
649  std::fstream fin( "/dev/urandom", std::ios::in );
650  if ( fin.is_open() )
651  fin.read( (char *) ( &m_seed ), sizeof ( m_seed ) );
652  else
653  {
654  fin.clear();
655  fin.open( "/dev/random", std::ios::in );
656  if ( fin.is_open() )
657  fin.read( (char *) ( &m_seed ), sizeof ( m_seed ) );
658  else
659  m_seed = 0;
660  }
661  fin.close();
662 #endif
663  }
664  Rand( unsigned int seed )
665  {
666  m_seed = seed;
667  }
668  unsigned int operator()()
669  {
670  unsigned int next = m_seed;
671  int result;
672 
673  next *= 1103515245;
674  next += 12345;
675  result = (unsigned int) ( next / max ) % 2048;
676 
677  next *= 1103515245;
678  next += 12345;
679  result <<= 10;
680  result ^= (unsigned int) ( next / max ) % 1024;
681 
682  next *= 1103515245;
683  next += 12345;
684  result <<= 10;
685  result ^= (unsigned int) ( next / max ) % 1024;
686 
687  m_seed = next;
688 
689  return result;
690  }
691  static const unsigned int max = 65536;
692 private:
693  unsigned int m_seed;
694 };
695 
696 void plFontToWxFontParameters( PLUNICODE fci, PLFLT scaledFontSize, wxFontFamily &family, int &style, int &weight, int &pt )
697 {
698  unsigned char plFontFamily, plFontStyle, plFontWeight;
699 
700  plP_fci2hex( fci, &plFontFamily, PL_FCI_FAMILY );
701  plP_fci2hex( fci, &plFontStyle, PL_FCI_STYLE );
702  plP_fci2hex( fci, &plFontWeight, PL_FCI_WEIGHT );
703 
704  family = fontFamilyLookup[plFontFamily];
705  style = fontStyleLookup[plFontStyle];
706  weight = fontWeightLookup[plFontWeight];
707  pt = ROUND( scaledFontSize );
708 }
709 
711 {
712  m_fci = 0;
713  m_size = std::numeric_limits<PLFLT>::quiet_NaN();
714  m_underlined = false;
715  m_hasFont = false;
716 }
717 
718 Font::Font( PLUNICODE fci, PLFLT size, bool underlined, bool createFontOnConstruction )
719 {
720  m_fci = fci;
721  m_size = size;
722  m_underlined = underlined;
723  m_hasFont = false;
724  if ( createFontOnConstruction )
725  createFont();
726 }
727 
729 {
730  wxFontFamily family;
731  int style;
732  int weight;
733  int pt;
734  plFontToWxFontParameters( m_fci, m_size, family, style, weight, pt );
735 
736  m_font = wxFont( pt, family, style, weight, m_underlined, wxEmptyString, wxFONTENCODING_DEFAULT );
737  //wxWidgets has a feature where wxDEFAULT can be passed in as the size in the constructor
738  //which gives the default size for the system. Annoyingly wxDEFAULT is 70 which can get used
739  //as an actual size. The workaround as per http://trac.wxwidgets.org/ticket/12315 is to call
740  //wxFont::SetPointSize after construction.
741  if ( pt == wxDEFAULT )
742  m_font.SetPointSize( pt );
743  m_hasFont = true;
744 }
745 
747 {
748  if ( !m_hasFont )
749  createFont();
750  return m_font;
751 }
752 
753 bool operator ==( const Font &lhs, const Font &rhs )
754 {
755  return lhs.getFci() == rhs.getFci()
756  && lhs.getSize() == rhs.getSize()
757  && lhs.getUnderlined() == rhs.getUnderlined();
758 }
759 
760 //--------------------------------------------------------------------------
761 // FontGrabber::FontGrabber( )
762 //
763 // Default constructor
764 //--------------------------------------------------------------------------
766 {
767  m_lastWasCached = false;
768 }
769 
770 //--------------------------------------------------------------------------
771 // Font FontGrabber::GetFont( PLUNICODE fci )
772 //
773 // Get the requested font either fresh or from the cache.
774 //--------------------------------------------------------------------------
775 Font FontGrabber::GetFont( PLUNICODE fci, PLFLT scaledFontSize, bool underlined )
776 {
777  Font newFont( fci, scaledFontSize, underlined );
778  if ( m_prevFont == newFont )
779  {
780  m_lastWasCached = true;
781  return m_prevFont;
782  }
783 
784  m_lastWasCached = false;
785 
786  return m_prevFont = newFont;
787 }
788 
789 //--------------------------------------------------------------------------
790 // wxPLDevice::wxPLDevice( void )
791 //
792 // Constructor of the standard wxWidgets device based on the wxPLDevBase
793 // class. Only some initialisations are done.
794 //--------------------------------------------------------------------------
796  : m_plplotEdgeLength( PLFLT( SHRT_MAX ) ), m_interactiveTextImage( 1, 1 )
797 {
798  PLPLOT_wxLogDebug( "wxPLDevice(): enter" );
799  m_fixedAspect = false;
800 
801  m_lineSpacing = 1.0;
802 
803  m_dc = NULL;
804 
805  wxGraphicsContext *gc = wxGraphicsContext::Create( m_interactiveTextImage );
806  PLPLOT_wxLogDebug( "wxPLDevice(): gc done" );
807  try
808  {
809  m_interactiveTextGcdc = new wxGCDC( gc );
810  }
811  catch ( ... )
812  {
813  delete gc;
814  throw( "wxPLDevice::wxPLDevice: unknown failure in new wxGCDC( gc )" );
815  }
816  PLPLOT_wxLogDebug( "wxPLDevice(): m_interactiveTextGcdc done" );
817 
818  if ( mfo )
819  strcpy( m_mfo, mfo );
820  else
821  //assume we will be outputting to the default
822  //memory map until we are given a dc to draw to
823 #ifdef WXPLVIEWER_DEBUG
824  strcpy( m_mfo, "plplotMemoryMap" );
825 #else
826  strcpy( m_mfo, "plplotMemoryMap??????????" );
827 #endif
828 
829  // be verbose and write out debug messages
830 #ifdef _DEBUG
831  pls->verbose = 1;
832  pls->debug = 1;
833 #endif
834 
835  pls->color = 1; // Is a color device
836  pls->dev_flush = 1; // Handles flushes
837  pls->dev_fill0 = 1; // Can handle solid fills
838  pls->dev_fill1 = 0; // Can't handle pattern fills
839  pls->dev_dash = 0;
840  pls->dev_clear = 1; // driver supports clear
841  pls->plbuf_write = 1; // use the plot buffer!
842  pls->termin = ( strlen( m_mfo ) ) > 0 ? 0 : 1; // interactive device unless we are writing to memory - pretty sure this is an unused option though
843  pls->graphx = GRAPHICS_MODE; // This indicates this is a graphics driver. PLplot will therefore call pltext() before outputting text, however we currently have not implemented catching that text.
844 
845  if ( text )
846  {
847  pls->dev_text = 1; // want to draw text
848  pls->dev_unicode = 1; // want unicode
849  if ( hrshsym )
850  pls->dev_hrshsym = 1;
851  }
852 
853 
854  // Set up physical limits of plotting device in plplot internal units
855  // we just tell plplot we are the maximum plint in both dimensions
856  //which gives us the best resolution
857  plP_setphy( (PLINT) 0, (PLINT) SHRT_MAX,
858  (PLINT) 0, (PLINT) SHRT_MAX );
859 
860  // set dpi and page size defaults if the user has not already set
861  // these with -dpi or -geometry command line options or with
862  // plspage.
863 
864  if ( pls->xdpi <= 0. || pls->ydpi <= 0. )
865  {
866  // Use recommended default pixels per inch.
868  }
869 
870  if ( pls->xlength == 0 || pls->ylength == 0 )
871  {
872  // Use recommended default pixel width and height.
874  }
876 
877  SetSize( pls, plsc->xlength, plsc->ylength );
878 
879  if ( pls->dev_data )
880  {
881  SetDC( pls, (wxDC *) pls->dev_data );
882  PLPLOT_wxLogDebug( "wxPLDevice(): SetDC done" );
883  }
884  else
885  {
886  SetupMemoryMap();
887  }
888 
889  PLPLOT_wxLogDebug( "wxPLDevice(): leave" );
890  //this must be the absolute last thing that is done
891  //so that if an exception is thrown pls->dev remains as NULL
892  pls->dev = (void *) this;
893 }
894 
895 //--------------------------------------------------------------------------
896 // wxPLDevice::~wxPLDevice( void )
897 //
898 // The destructor frees memory allocated by the device.
899 //--------------------------------------------------------------------------
901 {
902  if ( m_outputMemoryMap.isValid() )
903  {
904 #ifdef PL_WXWIDGETS_IPC3
905  m_header.completeFlag = 1;
907 #else
909  header->completeFlag = 1;
910 #endif
911  }
912 
913  delete m_interactiveTextGcdc;
914 }
915 
916 //--------------------------------------------------------------------------
917 // void wxPLDevice::PreDestructorTidy( PLStream *pls )
918 //
919 // This function performs any tidying up that requires a PLStream. should
920 // be called before the destructor obviously
921 //--------------------------------------------------------------------------
923 {
924  if ( !m_dc && pls->nopause )
926 }
927 
928 //--------------------------------------------------------------------------
929 // void wxPLDevice::DrawLine( short x1a, short y1a, short x2a, short y2a )
930 //
931 // Draw a line from (x1a, y1a) to (x2a, y2a).
932 //--------------------------------------------------------------------------
933 void wxPLDevice::DrawLine( short x1a, short y1a, short x2a, short y2a )
934 {
935  if ( !m_dc )
936  return;
937 
938  Clipper clipper( m_dc, GetClipRegion().GetBox() );
939  Scaler scaler( m_dc, 1.0 / m_scale, 1.0 / m_scale );
940  DrawingObjectsChanger drawingObjectsChanger( m_dc, m_pen, m_brush );
941  m_dc->DrawLine( (wxCoord) ( m_xAspect * x1a ), (wxCoord) ( m_yAspect * ( m_plplotEdgeLength - y1a ) ),
942  (wxCoord) ( m_xAspect * x2a ), (wxCoord) ( m_yAspect * ( m_plplotEdgeLength - y2a ) ) );
943 }
944 
945 
946 //--------------------------------------------------------------------------
947 // void wxPLDevice::DrawPolyline( short *xa, short *ya, PLINT npts )
948 //
949 // Draw a poly line - coordinates are in the xa and ya arrays.
950 //--------------------------------------------------------------------------
951 void wxPLDevice::DrawPolyline( short *xa, short *ya, PLINT npts )
952 {
953  if ( !m_dc )
954  return;
955  Clipper clipper( m_dc, GetClipRegion().GetBox() );
956  Scaler scaler( m_dc, 1.0 / m_scale, 1.0 / m_scale );
957  DrawingObjectsChanger drawingObjectsChanger( m_dc, m_pen, m_brush );
958  for ( PLINT i = 1; i < npts; i++ )
959  m_dc->DrawLine( m_xAspect * xa[i - 1], m_yAspect * ( m_plplotEdgeLength - ya[i - 1] ),
960  m_xAspect * xa[i], m_yAspect * ( m_plplotEdgeLength - ya[i] ) );
961 }
962 
963 
964 //--------------------------------------------------------------------------
965 // void wxPLDevice::ClearBackground( PLStream* pls, PLINT bgr, PLINT bgg, PLINT bgb,
966 // PLINT x1, PLINT y1, PLINT x2, PLINT y2 )
967 //
968 // Clear parts ((x1,y1) to (x2,y2)) of the background in color (bgr,bgg,bgb).
969 //--------------------------------------------------------------------------
971 {
972  if ( !m_dc )
973  return;
974 
975  x1 = x1 < 0 ? 0 : x1;
976  x2 = x2 < 0 ? m_plplotEdgeLength : x2;
977  y1 = y1 < 0 ? 0 : y1;
978  y2 = y2 < 0 ? m_plplotEdgeLength : y2;
979 
980  PLINT x = MIN( x1, x2 ) * m_xAspect;
981  PLINT y = ( m_plplotEdgeLength - MAX( y1, y2 ) ) * m_yAspect;
982  PLINT width = abs( x1 - x2 ) * m_xAspect;
983  PLINT height = abs( y1 - y2 ) * m_yAspect;
984 
985  if ( width > 0 && height > 0 )
986  {
987  PLINT r, g, b;
988  PLFLT a;
989  plgcolbga( &r, &g, &b, &a );
990  wxColour bgColour( r, g, b, a * 255 );
991  DrawingObjectsChanger changer( m_dc, wxPen( bgColour, 0 ), wxBrush( bgColour ) );
992  Scaler scaler( m_dc, 1.0 / m_scale, 1.0 / m_scale );
993  m_dc->DrawRectangle( x, y, width, height );
994  }
995 }
996 
997 
998 //--------------------------------------------------------------------------
999 // void wxPLDevice::FillPolygon( PLStream *pls )
1000 //
1001 // Draw a filled polygon.
1002 //--------------------------------------------------------------------------
1004 {
1005  if ( !m_dc )
1006  return;
1007 
1008  //edge the polygon with a 0.5 pixel line to avoid seams. This is a
1009  //bit of a bodge really but this is a difficult problem
1010  wxPen edgePen( m_brush.GetColour(), m_scale, wxSOLID );
1011  DrawingObjectsChanger changer( m_dc, edgePen, m_brush );
1012  //DrawingObjectsChanger changer(m_dc, wxNullPen, m_brush );
1013  Clipper clipper( m_dc, GetClipRegion().GetBox() );
1014  Scaler scaler( m_dc, 1.0 / m_scale, 1.0 / m_scale );
1015  wxPoint *points = new wxPoint[pls->dev_npts];
1016  wxCoord xoffset = 0;
1017  wxCoord yoffset = 0;
1018 
1019  for ( int i = 0; i < pls->dev_npts; i++ )
1020  {
1021  points[i].x = (int) ( m_xAspect * pls->dev_x[i] );
1022  points[i].y = (int) ( m_yAspect * ( m_plplotEdgeLength - pls->dev_y[i] ) );
1023  }
1024 
1025  if ( pls->dev_eofill )
1026  {
1027  m_dc->DrawPolygon( pls->dev_npts, points, xoffset, yoffset, wxODDEVEN_RULE );
1028  }
1029  else
1030  {
1031  m_dc->DrawPolygon( pls->dev_npts, points, xoffset, yoffset, wxWINDING_RULE );
1032  }
1033  delete[] points;
1034 }
1035 
1036 
1037 //--------------------------------------------------------------------------
1038 // void wxPLDevice::SetWidth( PLStream *pls )
1039 //
1040 // Set the width of the drawing pen.
1041 //--------------------------------------------------------------------------
1043 {
1044  PLFLT width = ( pls->width > 0.0 ? pls->width : 1.0 ) * m_scale;
1045  m_pen = wxPen( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b,
1046  pls->curcolor.a * 255 ), width, wxSOLID );
1047 }
1048 
1049 
1050 //--------------------------------------------------------------------------
1051 // void wxPLDevice::SetColor( PLStream *pls )
1052 //
1053 // Set color from PLStream.
1054 //--------------------------------------------------------------------------
1056 {
1057  PLFLT width = ( pls->width > 0.0 ? pls->width : 1.0 ) * m_scale;
1058  m_pen = wxPen( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b,
1059  pls->curcolor.a * 255 ), width, wxSOLID );
1060  m_brush = wxBrush( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b,
1061  pls->curcolor.a * 255 ) );
1062 }
1063 
1064 //--------------------------------------------------------------------------
1065 // void wxPLDevice::SetXorMode( bool on )
1066 //
1067 // Set whether we want XOR mode on or off.
1068 //--------------------------------------------------------------------------
1069 void wxPLDevice::SetXorMode( bool on )
1070 {
1071  if ( m_dc )
1072  m_dc->SetLogicalFunction( on ? wxXOR : wxCOPY );
1073 }
1074 
1075 //--------------------------------------------------------------------------
1076 // void wxPLDevice::SetDC( PLStream *pls, void* dc )
1077 //
1078 // Adds a dc to the device. In that case, the drivers doesn't provide
1079 // a GUI.
1080 //--------------------------------------------------------------------------
1081 void wxPLDevice::SetDC( PLStream *pls, wxDC* dc )
1082 {
1083  if ( m_outputMemoryMap.isValid() )
1084  throw( "wxPLDevice::SetDC The DC must be set before initialisation. The device is outputting to a separate viewer" );
1085  m_dc = dc; // Add the dc to the device
1086  m_useDcTextTransform = false;
1087  m_gc = NULL;
1088  if ( m_dc )
1089  {
1090 #if wxVERSION_NUMBER >= 2902
1091  m_useDcTextTransform = m_dc->CanUseTransformMatrix();
1092 #endif
1093  //Prior to some point in wxWidgets 3.1 development wxGCDC didn't
1094  //support transformation matrices, but the underlying
1095  //wxGraphicsContext had its own transformation matrix ability.
1096  //So check if we are using a wxGCDC using RTTI and if so we can
1097  //use this.
1098  wxGCDC *gcdc = NULL;
1099  try
1100  {
1101  //put this in a try block as I'm not sure if it will throw if
1102  //RTTI is switched off
1103  gcdc = dynamic_cast< wxGCDC* >( m_dc );
1104  }
1105  catch ( ... )
1106  {
1107  throw( "unknown failure in dynamic_cast< wxGCDC* >( m_dc )" );
1108  }
1109  if ( gcdc )
1110  m_gc = gcdc->GetGraphicsContext();
1111 
1112  strcpy( m_mfo, "" );
1113  SetSize( pls, m_width, m_height ); //call with our current size to set the scaling
1114  pls->has_string_length = 1; // Driver supports string length calculations, if we have a dc to draw on
1115  }
1116  else
1117  {
1118  pls->has_string_length = 0; //if we have no device to draw on we cannot check string size
1119  }
1120 }
1121 
1122 // This function will draw a section of text given by section at location
1123 // x, y relative to the origin xOrigin, yOrigin. The text must not
1124 // contain any newline characters or PLplot escapes.
1125 // transform is a transformation to be applied to the device context AFTER
1126 // the origin of the device context has been moved to xOrigin, yOrigin. The
1127 // purpose of having this origin is to allow the units used by wxWidgets to
1128 // be different to those passed in and for the scaling factors to be
1129 // different in each direction.
1130 // scaledFontSize is the font size in pt after any scaling for super/sub script.
1131 // The underlined flag, overlined flag, fci and text colours are inputs defining
1132 // the text style.
1133 // On return yScale, textWidth, textHeigth and textDepth will be
1134 // filled with the scaling value used for the Y dimension and the
1135 // (positive) width, (positive) ascender height and (positive)
1136 // descender depth of the text string.
1137 // If drawText is true the text will actually be rendered. If it is false the size
1138 // will be calculated but the text will not be rendered.
1139 //--------------------------------------------------------------------------
1140 void wxPLDevice::DrawTextSection( wxString section, wxCoord xOrigin, wxCoord yOrigin, wxCoord x, wxCoord y, PLFLT *transform, PLFLT scaledFontSize, bool drawText, bool underlined, PLUNICODE fci, unsigned char red, unsigned char green, unsigned char blue, PLFLT alpha, PLFLT &yScale, wxCoord &sectionWidth, wxCoord &sectionHeight, wxCoord &sectionDepth )
1141 {
1142  //for text, work in native coordinates, because it is significantly easier when
1143  //dealing with superscripts and text chunks.
1144  //The scaler object sets the scale to the new value until it is destroyed
1145  //when this function exits.
1146  Scaler scaler( m_dc, 1.0, 1.0 );
1147  //Also move the origin back to the top left, rather than the bottom
1148  OriginChanger originChanger( m_dc, 0, wxCoord( m_height - m_plplotEdgeLength / m_yScale ) );
1149  //save the text state for automatic restoration on scope exit
1150  TextObjectsSaver textObjectsSaver( m_dc );
1151 
1152  wxCoord leading;
1153  Font font = m_fontGrabber.GetFont( fci, scaledFontSize, underlined );
1154 
1155  // Adjusted so that utf8 "heavy multiplication x", "number sign",
1156  // "four teardrop-spoked asterisk", and "8-spoked asterisk" are
1157  // aligned properly when running
1158  //
1159  // python (or python3 as appropriate) examples/python/test_circle.py -dev wxwidgets
1160  //
1161  PLFLT empiricalYOffset = -0.020 * scaledFontSize * m_yScale;
1162  wxCoord empiricalY = y + empiricalYOffset;
1163  // Return via the yScale argument the value used for scaling in the Y direction.
1164  yScale = m_yScale;
1165  if ( m_dc )
1166  {
1167  wxFont theFont = font.getWxFont();
1168 
1169  // gdb sessions typically show something like the following:
1170  // 4: sectionWidth = (wxCoord &) @0x7fffffffd6ec: 7
1171  // 3: sectionHeight = (wxCoord &) @0x7fffffffd6e8: 13
1172  // 2: sectionDepth = (wxCoord &) @0x7fffffffd6e4: 3
1173  // 1: leading = 0
1174  // That is, sectionWidth, sectionHeight, and sectionDepth
1175  // returned by GetTextExtent are all normally small positive integers while leading
1176  // returned by the same call is typically zero.
1177  m_dc->GetTextExtent( section, &sectionWidth, &sectionHeight,
1178  &sectionDepth, &leading, &theFont );
1179  }
1180  else
1181  {
1182  wxFont theFont = font.getWxFont();
1183  // See comments above concerning interpretation of GetTextExtent results.
1184  m_interactiveTextGcdc->GetTextExtent( section, &sectionWidth, &sectionHeight,
1185  &sectionDepth, &leading, &theFont );
1186  }
1187 
1188  // The leading value that is returned is a vertical offset used by
1189  // some font designers, but I (AWI) can find no documentation
1190  // concerning the sign convention for leading so I simply follow
1191  // here the convention previously used by this code.
1192  // Note, that all fonts I have tried have zero leading so (a) this
1193  // adopted sign convention does not matter for them, and (b) if it
1194  // is wrong here, there is no chance to debug it by looking at the
1195  // vertical offset of rendered strings.
1196  sectionHeight -= leading;
1197  sectionDepth += leading;
1198  sectionWidth *= m_xScale;
1199  sectionHeight *= m_yScale;
1200  sectionDepth *= m_yScale;
1201 
1202  // Draw the text if requested
1203  if ( drawText && m_dc )
1204  {
1205  //set the text colour
1206  m_dc->SetTextBackground( wxColour( red, green, blue, alpha * 255 ) );
1207  m_dc->SetTextForeground( wxColour( red, green, blue, alpha * 255 ) );
1208 
1209  // Set the clipping limits
1210  PLINT rcx[4], rcy[4];
1211  difilt_clip( rcx, rcy );
1212  wxPoint cpoints[4];
1213  for ( int i = 0; i < 4; i++ )
1214  {
1215  cpoints[i].x = rcx[i] / m_xScale;
1216  cpoints[i].y = m_height - rcy[i] / m_yScale;
1217  }
1218  Clipper clipper( m_dc, wxRegion( 4, cpoints ).GetBox() );
1219 
1220  Font font = m_fontGrabber.GetFont( fci, scaledFontSize, underlined );
1221  m_dc->SetFont( font.getWxFont() );
1222 
1223  if ( m_useDcTextTransform )
1224  {
1225 #if wxVERSION_NUMBER >= 2902
1226  wxAffineMatrix2D originalDcMatrix = m_dc->GetTransformMatrix();
1227 
1228  wxAffineMatrix2D newMatrix = originalDcMatrix;
1229  newMatrix.Translate( xOrigin / m_xScale, m_height - yOrigin / m_yScale );
1230  wxAffineMatrix2D textMatrix;
1231  // For some reason we don't do the mirroring like in the
1232  // wxGraphicsContext when we use a wxDC.
1233  PLFLT xTransform = transform[4] / m_xScale;
1234  PLFLT yTransform = transform[5] / m_yScale;
1235  textMatrix.Set(
1236  wxMatrix2D(
1237  transform[0], transform[2],
1238  transform[1], transform[3] ),
1239  wxPoint2DDouble(
1240  xTransform, yTransform ) );
1241  newMatrix.Concat( textMatrix );
1242  m_dc->SetTransformMatrix( newMatrix );
1243 
1244  m_dc->DrawText( section, x / m_xScale, -empiricalY / m_yScale );
1245 
1246  m_dc->SetTransformMatrix( originalDcMatrix );
1247 #endif
1248  }
1249  else if ( m_gc )
1250  {
1251  wxGraphicsMatrix originalGcMatrix = m_gc->GetTransform();
1252 
1253  m_gc->Translate( xOrigin / m_xScale, m_height - yOrigin / m_yScale ); //move to text starting position
1254  //Create a wxGraphicsMatrix from our plplot transformation matrix.
1255  //Note the different conventions
1256  //1) plplot transforms use notation x' = Mx, where x and x' are column vectors,
1257  // wxGraphicsContext uses xM = x' where x and x' are row vectors. This means
1258  // we must transpose the matrix.
1259  //2) plplot Affine matrices a represented by 6 values which start at the top left
1260  // and work down each column. The 3rd row is implied as 0 0 1. wxWidget matrices
1261  // are represented by 6 values which start at the top left and work along each
1262  // row. The 3rd column is implied as 0 0 1. This means we must transpose the
1263  // matrix.
1264  //3) Items 1 and 2 cancel out so we don't actually need to do anything about them.
1265  //4) The wxGraphicsContext has positive y in the downward direction, but plplot
1266  // has positive y in the upwards direction. This means we must do a reflection
1267  // in the y direction before and after applying the transform. Also we must scale
1268  // the translation parts to match the pixel scale.
1269  //The overall transform is
1270  //
1271  // |1 0 0| |transform[0] transform[2] transform[4]/m_xScale| |1 0 0|
1272  // |0 -1 0| |transform[1] transform[3] transform[5]/m_yScale| |0 -1 0|
1273  // |0 0 1| | 0 0 1 | |0 0 1|
1274  //
1275  //which results in
1276  //
1277  // | transform[0] -transform[2] 0|
1278  // |-transform[1] transform[3] 0|
1279  // | transform[4]/m_xScale -transform[5]/m_yScale 1|
1280  //
1281  PLFLT xTransform = transform[4] / m_xScale;
1282  PLFLT yTransform = transform[5] / m_yScale;
1283  wxGraphicsMatrix matrix = m_gc->CreateMatrix(
1284  transform[0], -transform[1],
1285  -transform[2], transform[3],
1286  xTransform, -yTransform );
1287  wxGraphicsMatrix reflectMatrix = m_gc->CreateMatrix();
1288  m_gc->ConcatTransform( matrix );
1289  m_gc->DrawText( section, x / m_xScale, -empiricalY / m_yScale );
1290  m_gc->SetTransform( originalGcMatrix );
1291  }
1292  else
1293  {
1294  // If we are stuck with a wxDC that has no transformation
1295  // abilities then all we can really do is rotate the text
1296  // - this is a bit of a poor state really, but to be
1297  // honest it is better than defaulting to Hershey for all
1298  // text
1299  PLFLT xTransformed = x / m_xScale * transform[0] + empiricalY / m_yScale * transform[2] + transform[4] / m_xScale;
1300  PLFLT yTransformed = x / m_xScale * transform[1] + empiricalY / m_yScale * transform[3] + transform[4] / m_xScale;
1301  // This angle calculation comes from transforming the
1302  // point (0,0) and any other point on the empiricalY = 0 line and
1303  // getting the angle from the horizontal of that line.
1304  PLFLT angle = atan2( transform[1], transform[0] ) * 180.0 / M_PI;
1305  m_dc->DrawRotatedText( section, xOrigin / m_xScale + xTransformed, m_height - yOrigin / m_yScale - yTransformed, angle );
1306  }
1307  }
1308 }
1309 
1310 //--------------------------------------------------------------------------
1311 // void wxPLDevice::EndPage( PLStream* pls )
1312 // End the page. This is the point that we write the buffer to the memory
1313 // mapped file if needed
1314 //--------------------------------------------------------------------------
1316 {
1317  if ( !m_dc )
1318  {
1319  if ( pls->nopause )
1321  else
1323  return;
1324  }
1325 }
1326 
1327 //--------------------------------------------------------------------------
1328 // void wxPLDevice::BeginPage( PLStream* pls )
1329 // Sets up for transfer in case it is needed and sets the current state
1330 //--------------------------------------------------------------------------
1332 {
1333  if ( !m_dc )
1334  {
1337  }
1338 
1339  // Get the starting colour, width and font from the stream
1340  SetWidth( pls );
1341  SetColor( pls );
1342 
1343  //clear the page
1344  ClearBackground( pls );
1345 }
1346 
1347 //--------------------------------------------------------------------------
1348 // void wxPLDevice::SetSize( PLStream* pls )
1349 // Set the size of the page, scale parameters and the dpi
1350 //--------------------------------------------------------------------------
1351 void wxPLDevice::SetSize( PLStream* pls, int width, int height )
1352 {
1353  //we call BeginPage, before we fiddle with fixed aspect so that the
1354  //whole background gets filled
1355  // get boundary coordinates in plplot units
1356  PLINT xmin;
1357  PLINT xmax;
1358  PLINT ymin;
1359  PLINT ymax;
1360  plP_gphy( &xmin, &xmax, &ymin, &ymax );
1361  //split the scaling into an overall scale, the same in both dimensions
1362  //and an aspect part which differs in both directions.
1363  //We will apply the aspect ratio part, and let the DC do the overall
1364  //scaling. This gives us subpixel accuracy, but ensures line thickness
1365  //remains consistent in both directions
1366  m_xScale = width > 0 ? (PLFLT) ( xmax - xmin ) / (PLFLT) width : 0.0;
1367  m_yScale = height > 0 ? (PLFLT) ( ymax - ymin ) / (PLFLT) height : 0.0;
1368  m_scale = MIN( m_xScale, m_yScale );
1369 
1370  if ( !m_fixedAspect )
1371  {
1374  }
1375  else
1376  {
1377  //now sort out the fixed aspect and reset the logical scale if needed
1378  if ( PLFLT( height ) / PLFLT( width ) > m_yAspect / m_xAspect )
1379  {
1382  }
1383  else
1384  {
1387  }
1388  }
1389 
1390  m_width = ( xmax - xmin ) / m_xScale;
1391  pls->xlength = PLINT( m_width + 0.5 );
1392  m_height = ( ymax - ymin ) / m_yScale;
1393  pls->ylength = PLINT( m_height + 0.5 );
1394 
1395  // Set the number of plplot pixels per mm
1397  //
1398  //The line above is technically correct, however, 3d text only looks at device dimensions (32767x32767 square)
1399  //but 2d rotated text uses the mm size derived above. The only way to consistently deal with them is
1400  //by having an equal device units per mm in both directions and do a correction in DrawText().
1401  //Usefully this also allows us to change text rotation as aspect ratios change
1402  //PLFLT size = m_xAspect > m_yAspect ? m_width : m_height;
1403  //plP_setpxl( m_plplotEdgeLength / size * pls->xdpi / PLPLOT_MM_PER_INCH, m_plplotEdgeLength / size * pls->ydpi / PLPLOT_MM_PER_INCH );
1404 
1405 
1406  // redraw the plot
1407  if ( m_dc && pls->plbuf_buffer )
1408  plreplot();
1409 }
1410 
1411 
1413 {
1414  m_fixedAspect = fix;
1415 }
1416 
1418 {
1419  if ( !m_dc )
1420 #ifdef PL_WXWIDGETS_IPC3
1421  TransmitBuffer( pls, transmissionFlush );
1422 #else
1424 #endif
1425 }
1426 
1427 // This function transmits data to the gui program via a memory map.
1428 // This function can be called with pls set to NULL for transmission
1429 // of just a flag for e.g. page end or begin.
1430 void wxPLDevice::TransmitBuffer( PLStream* pls, unsigned char transmissionType )
1431 {
1432  if ( !m_outputMemoryMap.isValid() )
1433  return;
1434 #ifdef PL_WXWIDGETS_IPC3
1435  // New much cleaner variant of this code which makes use of two
1436  // additional members of the MemoryMapHeader called transmissionType
1437  // and plbufAmountToTransmit which contain what their names imply.
1438 
1439  try
1440  {
1441  m_header.transmissionType = transmissionType;
1442  // This value may be zeroed below for those transmissionTypes which require
1443  // that no part of plbuf should be transmitted.
1444  m_header.plbufAmountToTransmit = pls ? pls->plbuf_top - m_localBufferPosition : 0;
1445 
1446  switch ( transmissionType )
1447  {
1448  // Special valid cases.
1449  case transmissionLocate:
1450  m_header.locateModeFlag = 1;
1451  break;
1452  // N.B. These transmissionTypes require
1453  // that no part of plbuf should be transmitted.
1455  case transmissionClose:
1456  m_header.plbufAmountToTransmit = 0;
1457  break;
1458  // Generic valid cases where nothing special has to be done
1459  case transmissionBeginPage:
1460  case transmissionEndOfPage:
1462  case transmissionComplete:
1463  case transmissionFlush:
1464  break;
1465 
1466  // Invalid cases.
1467  default:
1468  throw( "wxPLDevice::TransmitBuffer: called with invalid value of transmissionType" );
1469  break;
1470  }
1471 
1472 #ifdef PLPLOT_WX_DEBUG_OUTPUT
1473  std::cerr << "Before transmitBytes" << std::endl;
1474  std::cerr << "transmissionType = " << static_cast<unsigned int>( m_header.transmissionType ) << std::endl;
1475  std::cerr << "plbufAmountToTransmit = " << m_header.plbufAmountToTransmit << std::endl;
1476  std::cerr << "viewerOpenFlag = " << m_header.viewerOpenFlag << std::endl;
1477  std::cerr << "locateModeFlag = " << m_header.locateModeFlag << std::endl;
1478  std::cerr << "completeFlag = " << m_header.completeFlag << std::endl;
1479 #endif // #ifdef PLPLOT_WX_DEBUG_OUTPUT
1480  m_outputMemoryMap.transmitBytes( true, &m_header, sizeof ( MemoryMapHeader ) );
1481  if ( m_header.plbufAmountToTransmit > 0 )
1482  {
1483  // N.B. the above condition implies pls is non-NULL.
1484  // Transmit m_header.plbufAmountToTransmit bytes of plbuf to the reader process.
1485  m_outputMemoryMap.transmitBytes( false, (char *) pls->plbuf_buffer + m_localBufferPosition, m_header.plbufAmountToTransmit );
1486  m_localBufferPosition += m_header.plbufAmountToTransmit;
1487  }
1488  } // End of try block
1489 
1490 
1491  catch ( const char *message )
1492  {
1493  plwarn( message );
1494  plwarn( "wxPLDevice::TransmitBuffer: error" );
1495  }
1496 
1497  catch ( ... )
1498  {
1499  plwarn( "wxPLDevice::TransmitBuffer: Unknown error" );
1500  }
1501 
1502 #else // #ifdef PL_WXWIDGETS_IPC3
1503  // Amount of plbuf buffer to copy.
1504  size_t amountToCopy = pls ? pls->plbuf_top - m_localBufferPosition : 0;
1505  const size_t headerSize = sizeof ( transmissionType ) + sizeof ( size_t );
1506  bool first = true;
1507  size_t counter = 0;
1508  const size_t counterLimit = 10000;
1509  bool completed = false;
1510  while ( !completed && counter < counterLimit )
1511  {
1512  //if we are doing multiple loops then pause briefly before we
1513  //lock to give the reading application a chance to spot the
1514  //change.
1515  if ( !first )
1516  wxMilliSleep( 10 );
1517  first = false;
1518 
1519  size_t copyAmount = 0;
1520  size_t freeSpace = 0;
1521  //lock the mutex so reading and writing don't overlap
1522  try
1523  {
1524  //PLNamedMutexLocker lock( &m_mutex );
1526 
1527  //check how much free space we have before the end of the buffer
1528  //or if we have looped round how much free space we have before
1529  //we reach the read point
1530  freeSpace = m_outputMemoryMap.getSize() - mapHeader.writeLocation;
1531  // if readLocation is at the beginning then don't quite fill up the buffer
1532  if ( mapHeader.readLocation == plMemoryMapReservedSpace )
1533  --freeSpace;
1534 
1535  //if the free space left in the file is less than that needed for the header then
1536  //just tell the GUI to skip the rest of the file so it can start again at the
1537  //beginning of the file.
1538  if ( freeSpace <= headerSize )
1539  {
1540  if ( mapHeader.readLocation > mapHeader.writeLocation ) //don't overtake the read buffer
1541  freeSpace = 0;
1542  else if ( mapHeader.readLocation == plMemoryMapReservedSpace ) // don't catch up exactly with the read buffer
1543  freeSpace = 0;
1544  else
1545  {
1546  //send a skip end of file command and move back to the beginning of the file
1547  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1548  (void *) ( &transmissionSkipFileEnd ), sizeof ( transmissionSkipFileEnd ) );
1550  counter = 0;
1551  plwarn( "wxWidgets wrapping buffer" );
1552  continue;
1553  }
1554  }
1555 
1556  //if this is a beginning of page, then send a beginning of page flag first
1557  if ( transmissionType == transmissionBeginPage )
1558  {
1559  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1560  (void *) ( &transmissionBeginPage ), sizeof ( transmissionBeginPage ) );
1561  mapHeader.writeLocation += sizeof ( transmissionBeginPage );
1562  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1564  counter = 0;
1565  if ( amountToCopy == 0 )
1566  completed = true;
1567  transmissionType = transmissionRegular;
1568  continue;
1569  }
1570 
1571  //if this is a end of page and we have completed
1572  //the buffer then send a end of page flag first
1573  if ( ( transmissionType == transmissionEndOfPage || transmissionType == transmissionEndOfPageNoPause )
1574  && amountToCopy == 0 )
1575  {
1576  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1577  (void *) ( &transmissionType ), sizeof ( transmissionType ) );
1578  mapHeader.writeLocation += sizeof ( transmissionType );
1579  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1581  counter = 0;
1582  completed = true;
1583  continue;
1584  }
1585 
1586  if ( transmissionType == transmissionLocate && amountToCopy == 0 )
1587  {
1588  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1589  (void *) ( &transmissionLocate ), sizeof ( transmissionLocate ) );
1590  mapHeader.writeLocation += sizeof ( transmissionLocate );
1591  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1593  mapHeader.locateModeFlag = 1;
1594  counter = 0;
1595  completed = true;
1596  continue;
1597  }
1598 
1599  if ( transmissionType == transmissionRequestTextSize )
1600  {
1601  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1602  (void *) ( &transmissionRequestTextSize ), sizeof ( transmissionRequestTextSize ) );
1603  mapHeader.writeLocation += sizeof ( transmissionRequestTextSize );
1604  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1606  counter = 0;
1607  completed = true;
1608  continue;
1609  }
1610  if ( transmissionType == transmissionClose )
1611  {
1612  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1613  (void *) ( &transmissionType ), sizeof ( transmissionType ) );
1614  mapHeader.writeLocation += sizeof ( transmissionType );
1615  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1617  counter = 0;
1618  completed = true;
1619  continue;
1620  }
1621 
1622  //if we have looped round stay 1 character behind the read buffer - it makes it
1623  //easier to test whether the reading has caught up with the writing or vice versa
1624  if ( mapHeader.writeLocation < mapHeader.readLocation && mapHeader.readLocation > 0 )
1625  freeSpace = mapHeader.readLocation - mapHeader.writeLocation - 1;
1626 
1627  if ( freeSpace > headerSize )
1628  {
1629  //decide exactly how much to copy
1630  copyAmount = MIN( amountToCopy, freeSpace - headerSize );
1631 
1632  //copy the header and the amount we can to the buffer
1633  if ( copyAmount != amountToCopy )
1634  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1635  (char *) ( &transmissionPartial ), sizeof ( transmissionPartial ) );
1636  else
1637  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation,
1638  (char *) ( &transmissionComplete ), sizeof ( transmissionComplete ) );
1639  if ( pls )
1640  {
1641  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation + sizeof ( transmissionComplete ),
1642  (char *) ( &copyAmount ), sizeof ( copyAmount ) );
1643  memcpy( m_outputMemoryMap.getBuffer() + mapHeader.writeLocation + headerSize,
1644  (char *) pls->plbuf_buffer + m_localBufferPosition, copyAmount );
1645  m_localBufferPosition += copyAmount;
1646  mapHeader.writeLocation += copyAmount + headerSize;
1647  if ( mapHeader.writeLocation == m_outputMemoryMap.getSize() )
1649  amountToCopy -= copyAmount;
1650  counter = 0;
1651  }
1652  if ( amountToCopy == 0 && transmissionType != transmissionEndOfPage
1653  && transmissionType != transmissionLocate
1654  && transmissionType != transmissionEndOfPageNoPause )
1655  completed = true;
1656  }
1657  else
1658  {
1659  ++counter;
1660  }
1661  }
1662 #ifdef _WIN32
1663  catch ( DWORD )
1664  {
1665  plwarn( "Locking mutex failed when trying to communicate with " NAME_wxPLViewer "." );
1666  break;
1667  }
1668 #endif
1669  catch ( ... )
1670  {
1671  plwarn( "Unknown error when trying to communicate with " NAME_wxPLViewer "." );
1672  break;
1673  }
1674  }
1675  if ( counter == counterLimit )
1676  {
1677  plwarn( "Communication timeout with " NAME_wxPLViewer " - disconnecting" );
1679  }
1680 #endif // #ifdef PL_WXWIDGETS_IPC3
1681 }
1682 
1684 {
1685  PLPLOT_wxLogDebug( "SetupMemoryMap(): enter" );
1686  if ( strlen( m_mfo ) > 0 )
1687  {
1688 #ifdef PL_WXWIDGETS_IPC3
1689  const size_t mapSize = sizeof ( shmbuf );
1690 #else
1691  const size_t mapSize = 1024 * 1024;
1692  char mutexName[PLPLOT_MAX_PATH];
1693 #endif
1694  //create a memory map to hold the data and add it to the array of maps
1695  int nTries = 0;
1696  char mapName[PLPLOT_MAX_PATH];
1697  static Rand randomGenerator; // make this static so that rapid repeat calls don't use the same seed
1698  while ( nTries < 10 )
1699  {
1700  PLPLOT_wxLogDebug( "SetupMemoryMap(): mapName start" );
1701  for ( int i = 0; i < strlen( m_mfo ); ++i )
1702  {
1703  if ( m_mfo[i] == '?' )
1704  mapName[i] = 'A' + (char) ( randomGenerator() % 26 );
1705  else
1706  mapName[i] = m_mfo[i];
1707  }
1708  PLPLOT_wxLogDebug( "SetupMemoryMap(): mapName done" );
1709  mapName[strlen( m_mfo )] = '\0';
1710  //truncate it earlier if needed
1711  if ( strlen( m_mfo ) > PLPLOT_MAX_PATH - 4 )
1712  mapName[PLPLOT_MAX_PATH - 4] = '\0';
1713  pldebug( "wxPLDevice::SetupMemoryMap", "nTries = %d, mapName = %s\n", nTries, mapName );
1714  PLPLOT_wxLogDebug( "SetupMemoryMap(): m_outputMemoryMap.create call" );
1715  m_outputMemoryMap.create( mapName, mapSize, false, true );
1716  PLPLOT_wxLogDebug( "SetupMemoryMap(): m_outputMemoryMap.create done" );
1717  if ( m_outputMemoryMap.isValid() )
1718  {
1719 #ifndef PL_WXWIDGETS_IPC3
1720  strcpy( mutexName, mapName );
1721  strcat( mutexName, "mut" );
1722  pldebug( "wxPLDevice::SetupMemoryMap", "nTries = %d, mutexName = %s\n", nTries, mutexName );
1723  m_mutex.create( mutexName );
1724  if ( !m_mutex.isValid() )
1726 #endif // #ifndef PL_WXWIDGETS_IPC3
1727  }
1728  if ( m_outputMemoryMap.isValid() )
1729  break;
1730  ++nTries;
1731  }
1732  //m_outputMemoryMap.create( m_mfo, pls->plbuf_top, false, true );
1733  //check the memory map is valid
1734  if ( !m_outputMemoryMap.isValid() )
1735  {
1736  plwarn( "Error creating memory map for wxWidget instruction transmission. The plots will not be displayed" );
1737  return;
1738  }
1739 
1740 #ifdef PL_WXWIDGETS_IPC3
1741  // Should only be executed once per valid Memory map before wxPLViewer is launched.
1742  m_outputMemoryMap.initializeSemaphoresToValid( mapName );
1743  //zero out the reserved area
1744  m_header.viewerOpenFlag = 0;
1745  m_header.locateModeFlag = 0;
1746  m_header.completeFlag = 0;
1747 #else // #ifdef PL_WXWIDGETS_IPC3
1749  header->readLocation = plMemoryMapReservedSpace;
1750  header->writeLocation = plMemoryMapReservedSpace;
1751  header->viewerOpenFlag = 0;
1752  header->locateModeFlag = 0;
1753  header->completeFlag = 0;
1754 #endif // #ifdef PL_WXWIDGETS_IPC3
1755 
1756  //try to find the wxPLViewer executable, in the first instance just assume it
1757  //is in the path.
1758  //wxString exeName = wxT( "/nfs/see-fs-02_users/earpros/usr/src/plplot-plplot/build/utils/" NAME_wxPLViewer );
1759  wxString exeName = wxT( NAME_wxPLViewer );
1760  if ( plInBuildTree() )
1761  {
1762  //if we are in the build tree check for the needed exe in there
1763  wxArrayString files;
1764  wxString utilsDir = wxString( wxT( BUILD_DIR ) ) + wxString( wxT( "/utils" ) );
1765  wxDir::GetAllFiles( utilsDir, &files, exeName, wxDIR_FILES | wxDIR_DIRS );
1766  if ( files.size() == 0 )
1767  wxDir::GetAllFiles( utilsDir, &files, exeName + wxT( ".exe" ), wxDIR_FILES | wxDIR_DIRS );
1768  if ( files.size() > 0 )
1769  exeName = files[0];
1770  }
1771  else
1772  {
1773  //check the plplot bin install directory
1774  wxArrayString files;
1775  wxDir::GetAllFiles( wxT( BIN_DIR ), &files, exeName, wxDIR_FILES | wxDIR_DIRS );
1776  if ( files.size() == 0 )
1777  wxDir::GetAllFiles( wxT( BIN_DIR ), &files, exeName + wxT( ".exe" ), wxDIR_FILES | wxDIR_DIRS );
1778  if ( files.size() > 0 )
1779  exeName = files[0];
1780  }
1781  //Run the wxPlViewer with command line parameters telling it the location and size of the buffer
1782  wxString command;
1783  command << wxT( "\"" ) << exeName << wxT( "\" " ) << wxString( mapName, wxConvUTF8 ) << wxT( " " ) <<
1784  mapSize << wxT( " " ) << m_width << wxT( " " ) << m_height;
1785 #ifndef WXPLVIEWER_DEBUG
1786 #ifdef _WIN32
1787 
1788  if ( wxExecute( command, wxEXEC_ASYNC ) == 0 )
1789  plwarn( "Failed to run " NAME_wxPLViewer " - no plots will be shown" );
1790 #else //_WIN32
1791  //Linux doesn't like using wxExecute without a wxApp, so use system instead
1792  command << wxT( " &" );
1793  system( command.mb_str() );
1794 #endif //_WIN32
1795 #else // ifndef WXPLVIEWER_DEBUG
1796  wxString runMessage;
1797  runMessage << "Begin Running " NAME_wxPLViewer " in the debugger now to continue. Use the parameters: plplotMemoryMap " <<
1798  mapSize << " " << m_width << " " << m_height;
1799  // fprintf( stdout, runMessage );
1800  // FIXME: The above fprintf does not output runMessage (because of buffered output?)
1801  // So output instead with cerr
1802  std::cerr << runMessage << std::endl;
1803 #endif // ifndef WXPLVIEWER_DEBUG
1804 
1805 #ifdef PL_WXWIDGETS_IPC3
1806  size_t nbytes;
1807  try
1808  {
1809  // Update the header from the read (i.e.,
1810  // wxPLViewer) side. Warning, this will block indefinitely
1811  // until the read side sends the required data. So
1812  // theoretically you could wait until the next day to launch
1813  // wxPLViewer using gdb and -dev wxwidgets would happily
1814  // wake up and start communicating with it. N.B. we could
1815  // change this infinite timeout later (by changing all
1816  // sem_wait calls in PLThreeSemaphores to sem_timedwait with a
1817  // generic timeout of say 2 minutes before it throws an
1818  // exception). But regardless of the ultimate resolution of
1819  // that issue, the following will not require any
1820  // wxMilliSleep loops.
1821  m_outputMemoryMap.receiveBytes( true, &m_header, sizeof ( MemoryMapHeader ) );
1822 #ifdef PLPLOT_WX_DEBUG_OUTPUT
1823  std::cerr << "After receiveBytes" << std::endl;
1824  std::cerr << "transmissionType = " << static_cast<unsigned int>( m_header.transmissionType ) << std::endl;
1825  std::cerr << "plbufAmountToTransmit = " << m_header.plbufAmountToTransmit << std::endl;
1826  std::cerr << "viewerOpenFlag = " << m_header.viewerOpenFlag << std::endl;
1827  std::cerr << "locateModeFlag = " << m_header.locateModeFlag << std::endl;
1828  std::cerr << "completeFlag = " << m_header.completeFlag << std::endl;
1829 #endif // #ifdef PLPLOT_WX_DEBUG_OUTPUT
1830  }
1831  catch ( const char *message )
1832  {
1833  plwarn( message );
1834  plwarn( "wxPLDevice::SetupMemoryMap: error" );
1835  }
1836  catch ( ... )
1837  {
1838  plwarn( "wxPLDevice::SetupMemoryMap: Unknown error" );
1839  }
1840  // This value is generated by the read side.
1841  size_t &viewerSignal = m_header.viewerOpenFlag;
1842 #else // #ifdef PL_WXWIDGETS_IPC3
1843 
1844 #ifndef WXPLVIEWER_DEBUG
1845  size_t maxTries = 1000;
1846 #else // ifndef WXPLVIEWER_DEBUG
1847  size_t maxTries = 100000;
1848 #endif // ifndef WXPLVIEWER_DEBUG
1849  //wait until the viewer signals it has opened the map file
1850  size_t counter = 0;
1851  size_t &viewerSignal = header->viewerOpenFlag;
1852  while ( counter < maxTries && viewerSignal == 0 )
1853  {
1854  wxMilliSleep( 10 );
1855  ++counter;
1856  }
1857 #endif // #ifdef PL_WXWIDGETS_IPC3
1858  if ( viewerSignal == 0 )
1859  plwarn( NAME_wxPLViewer " failed to signal it has found the shared memory." );
1860  }
1861  PLPLOT_wxLogDebug( "SetupMemoryMap(): leave" );
1862 }
1863 
1865 {
1866  if ( !m_dc && m_outputMemoryMap.isValid() )
1867  {
1868 #ifdef PL_WXWIDGETS_IPC3
1870  m_outputMemoryMap.receiveBytes( true, &m_header, sizeof ( MemoryMapHeader ) );
1871  *graphicsIn = m_header.graphicsIn;
1872 #else // #ifdef PL_WXWIDGETS_IPC3
1875  bool gotResponse = false;
1876  while ( !gotResponse )
1877  {
1878  wxMilliSleep( 100 );
1879  PLNamedMutexLocker lock( &m_mutex );
1880  gotResponse = header->locateModeFlag == 0;
1881  }
1882 
1883  PLNamedMutexLocker lock( &m_mutex );
1884  *graphicsIn = header->graphicsIn;
1885 #endif //ifdef PL_WXWIDGETS_IPC3
1886  }
1887  else
1888  {
1889  plwarn( "plGetCursor cannot be used when the user supplies a wxDC or until " NAME_wxPLViewer " is initialised" );
1890  graphicsIn->dX = -1;
1891  graphicsIn->dY = -1;
1892  graphicsIn->pX = -1;
1893  graphicsIn->pY = -1;
1894  }
1895 }
1896 
1897 //--------------------------------------------------------------------------
1898 // wxRegion wxPLDevice::GetClipRegion()
1899 // Gets the current clip region from plplot as a wxRegion
1900 //--------------------------------------------------------------------------
1901 
1903 {
1904  PLINT rcx[4], rcy[4];
1905  difilt_clip( rcx, rcy );
1906 
1907  wxPoint cpoints[4];
1908  for ( int i = 0; i < 4; i++ )
1909  {
1910  cpoints[i].x = rcx[i] / m_xScale;
1911  cpoints[i].y = m_height - rcy[i] / m_yScale;
1912  }
1913  return wxRegion( 4, cpoints );
1914 }
bool m_clipEverything
bool isEverythingClipped()
Clipper(const Clipper &)
Clipper & operator=(const Clipper &)
wxDC * m_dc
Clipper(wxDC *dc, const wxRect &rect)
wxRect m_boxOld
DrawingObjectsChanger(const DrawingObjectsChanger &)
DrawingObjectsChanger(wxDC *dc, const wxPen &pen, const wxBrush &brush)
DrawingObjectsChanger & operator=(const DrawingObjectsChanger &)
bool m_lastWasCached
Definition: wxwidgets.h:78
Font m_prevFont
Definition: wxwidgets.h:77
Font GetFont(PLUNICODE fci, PLFLT scaledFontSize, bool underlined)
Definition: wxwidgets.h:48
PLUNICODE getFci() const
Definition: wxwidgets.h:53
wxFont m_font
Definition: wxwidgets.h:58
bool m_hasFont
Definition: wxwidgets.h:62
wxFont getWxFont()
void createFont()
bool m_underlined
Definition: wxwidgets.h:61
PLFLT m_size
Definition: wxwidgets.h:60
PLFLT getSize() const
Definition: wxwidgets.h:54
PLUNICODE m_fci
Definition: wxwidgets.h:59
bool getUnderlined() const
Definition: wxwidgets.h:55
wxCoord m_xOriginOld
wxCoord m_yOriginOld
OriginChanger(const OriginChanger &)
OriginChanger & operator=(const OriginChanger &)
OriginChanger(wxDC *dc, wxCoord xOrigin, wxCoord yOrigin)
size_t getSize()
void create(const char *name, PLINT size, bool mustExist, bool mustNotExist)
char * getBuffer()
void create(const char *name, bool aquireOnCreate=false)
virtual void DrawTextSection(wxString section, wxCoord xOrigin, wxCoord yOrigin, wxCoord x, wxCoord y, PLFLT *transform, PLFLT scaledFontSize, bool drawText, bool underlined, PLUNICODE fci, unsigned char red, unsigned char green, unsigned char blue, PLFLT alpha, PLFLT &yScale, wxCoord &sectionWidth, wxCoord &sectionHeight, wxCoord &sectionDepth)
Definition: wxwidgets.h:105
PLFLT m_prevBaseFontSize
Definition: wxwidgets.h:108
PLUNICODE m_prevSymbol
Definition: wxwidgets.h:107
void drawText(PLStream *pls, EscText *args)
wxCoord m_prevSymbolDepth
Definition: wxwidgets.h:113
void DrawTextLine(PLUNICODE *ucs4, int ucs4Len, wxCoord xOrigin, wxCoord yOrigin, wxCoord x, wxCoord y, PLFLT *transform, PLFLT baseFontSize, bool drawText, bool &underlined, PLUNICODE &fci, unsigned char red, unsigned char green, unsigned char blue, PLFLT alpha, wxCoord &textWidth, wxCoord &textHeight, wxCoord &textDepth)
wxCoord m_prevSymbolHeight
Definition: wxwidgets.h:112
PLUNICODE m_prevFci
Definition: wxwidgets.h:110
PLINT m_prevLevel
Definition: wxwidgets.h:109
wxCoord m_prevSymbolWidth
Definition: wxwidgets.h:111
Rand(unsigned int seed)
static const unsigned int max
unsigned int m_seed
unsigned int operator()()
Scaler & operator=(const Scaler &)
double m_xScaleOld
double m_yScaleOld
Scaler(const Scaler &)
wxDC * m_dc
Scaler(wxDC *dc, double xScale, double yScale)
TextObjectsChanger(wxDC *dc, FontGrabber &fontGrabber, PLUNICODE fci, PLFLT size, bool underlined, const wxColour &textForeground, const wxColour &textBackground)
TextObjectsChanger(const TextObjectsChanger &)
TextObjectsChanger(wxDC *dc, const wxFont &font, const wxColour &textForeground, const wxColour &textBackground)
TextObjectsSaver m_saver
TextObjectsChanger & operator=(const TextObjectsChanger &)
TextObjectsChanger(wxDC *dc, const wxFont &font)
TextObjectsSaver & operator=(const TextObjectsSaver &)
TextObjectsSaver(const TextObjectsSaver &)
wxColour m_textForeground
TextObjectsSaver(wxDC *dc)
wxColour m_textBackground
wxPen m_pen
Definition: wxwidgets.h:151
void DrawPolyline(short *xa, short *ya, PLINT npts)
void DrawLine(short x1a, short y1a, short x2a, short y2a)
PLFLT m_yScale
Definition: wxwidgets.h:166
bool m_useDcTextTransform
Definition: wxwidgets.h:147
wxImage m_interactiveTextImage
Definition: wxwidgets.h:156
char m_mfo[PLPLOT_MAX_PATH]
Definition: wxwidgets.h:190
bool m_fixedAspect
Definition: wxwidgets.h:170
void EndPage(PLStream *pls)
wxRegion GetClipRegion()
virtual ~wxPLDevice(void)
void SetDC(PLStream *pls, wxDC *dc)
FontGrabber m_fontGrabber
Definition: wxwidgets.h:175
PLFLT m_width
Definition: wxwidgets.h:163
void FixAspectRatio(bool fix)
wxBrush m_brush
Definition: wxwidgets.h:152
void PreDestructorTidy(PLStream *pls)
PLFLT m_scale
Definition: wxwidgets.h:169
void DrawTextSection(wxString section, wxCoord xOrigin, wxCoord yOrigin, wxCoord x, wxCoord y, PLFLT *transform, PLFLT scaledFontSize, bool drawText, bool underlined, PLUNICODE fci, unsigned char red, unsigned char green, unsigned char blue, PLFLT alpha, PLFLT &yScale, wxCoord &sectionWidth, wxCoord &sectionHeight, wxCoord &sectionDepth)
PLMemoryMap m_outputMemoryMap
Definition: wxwidgets.h:198
void TransmitBuffer(PLStream *pls, unsigned char transmissionType)
PLFLT m_lineSpacing
Definition: wxwidgets.h:182
void Locate(PLStream *pls, PLGraphicsIn *graphicsIn)
void SetXorMode(bool on)
void SetSize(PLStream *pls, int width, int height)
void SetColor(PLStream *pls)
size_t m_localBufferPosition
Definition: wxwidgets.h:197
void BeginPage(PLStream *pls)
PLFLT m_xAspect
Definition: wxwidgets.h:167
wxGraphicsContext * m_gc
Definition: wxwidgets.h:150
void SetWidth(PLStream *pls)
PLFLT m_xScale
Definition: wxwidgets.h:165
const PLFLT m_plplotEdgeLength
Definition: wxwidgets.h:162
PLFLT m_yAspect
Definition: wxwidgets.h:168
void SetupMemoryMap()
void Flush(PLStream *pls)
void ClearBackground(PLStream *pls, PLINT x1=-1, PLINT y1=-1, PLINT x2=-1, PLINT y2=-1)
wxGCDC * m_interactiveTextGcdc
Definition: wxwidgets.h:157
PLNamedMutex m_mutex
Definition: wxwidgets.h:195
PLFLT m_height
Definition: wxwidgets.h:164
wxPLDevice(PLStream *pls, char *mfo, PLINT text, PLINT hrshsym)
wxDC * m_dc
Definition: wxwidgets.h:146
void FillPolygon(PLStream *pls)
const char header[]
Definition: deltaT-gen.c:41
#define MIN(a, b)
Definition: dsplint.c:29
#define MAX(a, b)
Definition: dsplint.c:28
void plP_affine_identity(PLFLT *affine_vector)
Definition: plaffine.c:56
void plP_affine_multiply(PLFLT *affine_vectorA, PLFLT_VECTOR affine_vectorB, PLFLT_VECTOR affine_vectorC)
Definition: plaffine.c:184
void plP_fci2hex(PLUNICODE fci, unsigned char *phexdigit, unsigned char hexpower)
Definition: plcore.c:3958
void difilt_clip(PLINT *x_coords, PLINT *y_coords)
Definition: plcore.c:1603
int plInBuildTree()
Definition: plcore.c:2888
void plP_setpxl(PLFLT xpmm, PLFLT ypmm)
Definition: plcore.c:4238
void plP_gphy(PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax)
Definition: plcore.c:4198
void plgesc(char *p_esc)
Definition: plcore.c:3914
void plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
Definition: plcore.c:4249
static PLStream * pls[PL_NSTREAMS]
Definition: plcore.h:88
void plwarn(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1863
#define PLPLOT_MAX_PATH
Definition: plplotP.h:446
#define PLPLOT_MM_PER_INCH
Definition: plplotP.h:313
#define GRAPHICS_MODE
Definition: plplotP.h:288
#define PLPLOT_POINTS_PER_INCH
Definition: plplotP.h:314
#define PLPLOT_DEFAULT_WIDTH_PIXELS
Definition: plplotP.h:329
#define PLPLOT_DEFAULT_HEIGHT_PIXELS
Definition: plplotP.h:330
#define TRUE
Definition: plplotP.h:176
#define FALSE
Definition: plplotP.h:177
#define PLPLOT_DEFAULT_PIXELS_PER_INCH
Definition: plplotP.h:326
#define M_PI
Definition: plplotP.h:119
#define ROUND(a)
Definition: plplotP.h:202
#define plgfci
Definition: plplot.h:735
PLUINT PLUNICODE
Definition: plplot.h:201
float PLFLT
Definition: plplot.h:163
#define PL_FCI_WEIGHT
Definition: plplot.h:378
#define plspage
Definition: plplot.h:831
#define PL_FCI_STYLE
Definition: plplot.h:377
#define PL_FCI_FAMILY
Definition: plplot.h:376
#define plgcolbga
Definition: plplot.h:727
int PLINT
Definition: plplot.h:181
#define plreplot
Definition: plplot.h:788
#define PL_FCI_MARK
Definition: plplot.h:370
#define BUILD_DIR
Definition: plplot_config.h:24
#define NAME_wxPLViewer
#define BIN_DIR
Definition: plplot_config.h:21
void plP_script_scale(PLBOOL ifupper, PLINT *level, PLFLT *old_scale, PLFLT *scale, PLFLT *old_offset, PLFLT *offset)
Definition: plsym.c:1302
static int hrshsym
Definition: ps.c:79
static int text
Definition: ps.c:77
unsigned short unicode_array_len
Definition: plplotP.h:736
PLFLT just
Definition: plplotP.h:708
PLINT x
Definition: plplotP.h:712
PLUNICODE * unicode_array
Definition: plplotP.h:735
PLINT y
Definition: plplotP.h:713
PLFLT * xform
Definition: plplotP.h:709
PLFLT a
Definition: plplot.h:551
unsigned char r
Definition: plplot.h:548
unsigned char g
Definition: plplot.h:549
unsigned char b
Definition: plplot.h:550
PLFLT dY
Definition: plplot.h:442
PLFLT dX
Definition: plplot.h:442
PLINT verbose
Definition: plstrm.h:527
PLINT ylength
Definition: plstrm.h:617
PLFLT xdpi
Definition: plstrm.h:616
size_t plbuf_top
Definition: plstrm.h:650
PLINT dev_fill0
Definition: plstrm.h:571
PLINT dev_hrshsym
Definition: plstrm.h:753
void * plbuf_buffer
Definition: plstrm.h:649
PLINT dev_npts
Definition: plstrm.h:581
PLINT debug
Definition: plstrm.h:527
PLINT color
Definition: plstrm.h:569
PLINT dev_dash
Definition: plstrm.h:571
short * dev_y
Definition: plstrm.h:582
PLINT plbuf_write
Definition: plstrm.h:567
PLFLT width
Definition: plstrm.h:552
PLINT dev_clear
Definition: plstrm.h:572
void * dev_data
Definition: plstrm.h:596
short * dev_x
Definition: plstrm.h:582
PLFLT chrht
Definition: plstrm.h:686
PLINT dev_unicode
Definition: plstrm.h:747
PLColor curcolor
Definition: plstrm.h:543
PLINT get_string_length
Definition: plstrm.h:787
PLINT dev_text
Definition: plstrm.h:572
PLINT termin
Definition: plstrm.h:568
PLINT has_string_length
Definition: plstrm.h:785
PLFLT string_length
Definition: plstrm.h:786
void * dev
Definition: plstrm.h:594
PLINT xlength
Definition: plstrm.h:617
PLINT graphx
Definition: plstrm.h:568
PLINT dev_fill1
Definition: plstrm.h:571
PLINT nopause
Definition: plstrm.h:568
PLFLT ydpi
Definition: plstrm.h:616
PLINT dev_flush
Definition: plstrm.h:571
PLINT dev_eofill
Definition: plstrm.h:788
PLFLT xpmm
Definition: plstrm.h:707
PLFLT diorot
Definition: plstrm.h:661
Definition: plgridd.c:86
static Tcl_DString command
Definition: tkMain.c:121
#define PLPLOT_wxLogDebug(string)
const int fontStyleLookup[3]
Definition: wxwidgets.h:251
const wxFontFamily fontFamilyLookup[5]
Definition: wxwidgets.h:243
const int fontWeightLookup[2]
Definition: wxwidgets.h:257
const unsigned char transmissionEndOfPageNoPause
const unsigned char transmissionRegular
const unsigned char transmissionPartial
const unsigned char transmissionSkipFileEnd
const unsigned char transmissionEndOfPage
const unsigned char transmissionClose
const unsigned char transmissionComplete
const unsigned char transmissionRequestTextSize
const PLINT plMemoryMapReservedSpace
const unsigned char transmissionBeginPage
const unsigned char transmissionLocate
bool operator==(const Font &lhs, const Font &rhs)
void plFontToWxFontParameters(PLUNICODE fci, PLFLT scaledFontSize, wxFontFamily &family, int &style, int &weight, int &pt)