PLplot 5.15.0
Loading...
Searching...
No Matches
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//--------------------------------------------------------------------------
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!)
114 PLFLT baseFontSize = pls->chrht * PLPLOT_POINTS_PER_INCH / PLPLOT_MM_PER_INCH;
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
242void 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//--------------------------------------------------------------------------
409{
410public:
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 }
425private:
426 wxDC *m_dc;
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{
441public:
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 }
456private:
457 wxDC *m_dc;
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{
472public:
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 }
492private:
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{
508public:
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 }
528private:
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{
545public:
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 }
573private:
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//--------------------------------------------------------------------------
592{
593public:
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 }
625private:
626 wxDC *m_dc;
627 wxRect m_boxOld;
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//--------------------------------------------------------------------------
641class Rand
642{
643public:
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;
692private:
693 unsigned int m_seed;
694};
695
696void 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
718Font::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
753bool 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//--------------------------------------------------------------------------
769
770//--------------------------------------------------------------------------
771// Font FontGrabber::GetFont( PLUNICODE fci )
772//
773// Get the requested font either fresh or from the cache.
774//--------------------------------------------------------------------------
775Font 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 {
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
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//--------------------------------------------------------------------------
933void 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//--------------------------------------------------------------------------
951void 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//--------------------------------------------------------------------------
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//--------------------------------------------------------------------------
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//--------------------------------------------------------------------------
1140void 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
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
1345}
1346
1347//--------------------------------------------------------------------------
1348// void wxPLDevice::SetSize( PLStream* pls )
1349// Set the size of the page, scale parameters and the dpi
1350//--------------------------------------------------------------------------
1351void 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;
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.
1430void 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
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 );
1525 MemoryMapHeader & mapHeader = *(MemoryMapHeader *) m_outputMemoryMap.getBuffer();
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" );
1678 m_outputMemoryMap.close();
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() )
1725 m_outputMemoryMap.close();
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 &)
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)
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
OriginChanger(const OriginChanger &)
OriginChanger(wxDC *dc, wxCoord xOrigin, wxCoord yOrigin)
OriginChanger & operator=(const OriginChanger &)
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()()
double m_xScaleOld
double m_yScaleOld
Scaler(const Scaler &)
wxDC * m_dc
Scaler & operator=(const Scaler &)
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(const TextObjectsSaver &)
TextObjectsSaver(wxDC *dc)
TextObjectsSaver & operator=(const TextObjectsSaver &)
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
#define NAME_wxPLViewer
#define BIN_DIR
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 dY
Definition plplot.h:442
PLFLT dX
Definition plplot.h:442
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)