PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
wxwidgets_dc.cpp
Go to the documentation of this file.
1 // Copyright (C) 2005 Werner Smekal, Sjaak Verdoold
2 // Copyright (C) 2005 Germain Carrera Corraleche
3 // Copyright (C) 1999 Frank Huebner
4 //
5 // This file is part of PLplot.
6 //
7 // PLplot is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU Library General Public License as published
9 // by the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // PLplot is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with PLplot; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 
22 // TODO:
23 // - text clipping
24 // - implement AddToClipRegion for text correctly
25 //
26 
27 // wxwidgets headers
28 #include <wx/wx.h>
29 
30 #include "plDevs.h"
31 
32 // plplot headers
33 #include "plplotP.h"
34 
35 // std and driver headers
36 #include <cmath>
37 #include "wxwidgets.h"
38 
39 
40 //--------------------------------------------------------------------------
41 // wxPLDevDC::wxPLDevDC( void )
42 //
43 // Constructor of the standard wxWidgets device based on the wxPLDevBase
44 // class. Only some initialisations are done.
45 //--------------------------------------------------------------------------
47 {
48  m_dc = NULL;
49  m_bitmap = NULL;
50  m_font = NULL;
51  underlined = false;
52 }
53 
54 
55 //--------------------------------------------------------------------------
56 // wxPLDevDC::~wxPLDevDC( void )
57 //
58 // The deconstructor frees memory allocated by the device.
59 //--------------------------------------------------------------------------
61 {
62  if ( ownGUI )
63  {
64  if ( m_dc )
65  {
66  ( (wxMemoryDC *) m_dc )->SelectObject( wxNullBitmap );
67  delete m_dc;
68  }
69  if ( m_bitmap )
70  delete m_bitmap;
71  }
72 
73  if ( m_font )
74  delete m_font;
75 }
76 
77 
78 //--------------------------------------------------------------------------
79 // void wxPLDevDC::DrawLine( short x1a, short y1a, short x2a, short y2a )
80 //
81 // Draw a line from (x1a, y1a) to (x2a, y2a).
82 //--------------------------------------------------------------------------
83 void wxPLDevDC::DrawLine( short x1a, short y1a, short x2a, short y2a )
84 {
85  x1a = (short) ( x1a / scalex ); y1a = (short) ( height - y1a / scaley );
86  x2a = (short) ( x2a / scalex ); y2a = (short) ( height - y2a / scaley );
87 
88  m_dc->DrawLine( (wxCoord) x1a, (wxCoord) y1a, (wxCoord) x2a, (wxCoord) y2a );
89 
90  AddtoClipRegion( (int) x1a, (int) y1a, (int) x2a, (int) y2a );
91 }
92 
93 
94 //--------------------------------------------------------------------------
95 // void wxPLDevDC::DrawPolyline( short *xa, short *ya, PLINT npts )
96 //
97 // Draw a poly line - coordinates are in the xa and ya arrays.
98 //--------------------------------------------------------------------------
99 void wxPLDevDC::DrawPolyline( short *xa, short *ya, PLINT npts )
100 {
101  wxCoord x1a, y1a, x2a, y2a;
102 
103  x2a = (wxCoord) ( xa[0] / scalex );
104  y2a = (wxCoord) ( height - ya[0] / scaley );
105  for ( PLINT i = 1; i < npts; i++ )
106  {
107  x1a = x2a; y1a = y2a;
108  x2a = (wxCoord) ( xa[i] / scalex );
109  y2a = (wxCoord) ( height - ya[i] / scaley );
110 
111  m_dc->DrawLine( x1a, y1a, x2a, y2a );
112 
113  AddtoClipRegion( (int) x1a, (int) y1a, (int) x2a, (int) y2a );
114  }
115 }
116 
117 
118 //--------------------------------------------------------------------------
119 // void wxPLDevDC::ClearBackground( PLINT bgr, PLINT bgg, PLINT bgb,
120 // PLINT x1, PLINT y1, PLINT x2, PLINT y2 )
121 //
122 // Clear parts ((x1,y1) to (x2,y2)) of the background in color (bgr,bgg,bgb).
123 //--------------------------------------------------------------------------
125  PLINT x1, PLINT y1, PLINT x2, PLINT y2 )
126 {
127  if ( x1 < 0 )
128  x1 = 0;
129  else
130  x1 = (PLINT) ( x1 / scalex );
131  if ( y1 < 0 )
132  y1 = 0;
133  else
134  y1 = (PLINT) ( height - y1 / scaley );
135  if ( x2 < 0 )
136  x2 = width;
137  else
138  x2 = (PLINT) ( x2 / scalex );
139  if ( y2 < 0 )
140  y2 = height;
141  else
142  y2 = (PLINT) ( height - y2 / scaley );
143 
144  const wxPen oldPen = m_dc->GetPen();
145  const wxBrush oldBrush = m_dc->GetBrush();
146 
147  m_dc->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( bgr, bgg, bgb ), 1, wxSOLID ) ) );
148  m_dc->SetBrush( wxBrush( wxColour( bgr, bgg, bgb ) ) );
149  m_dc->DrawRectangle( x1, y1, x2 - x1, y2 - y1 );
150 
151  m_dc->SetPen( oldPen );
152  m_dc->SetBrush( oldBrush );
153 
154  AddtoClipRegion( x1, y1, x2, y2 );
155 }
156 
157 
158 //--------------------------------------------------------------------------
159 // void wxPLDevDC::FillPolygon( PLStream *pls )
160 //
161 // Draw a filled polygon.
162 //--------------------------------------------------------------------------
164 {
165  wxPoint *points = new wxPoint[pls->dev_npts];
166  wxCoord xoffset = 0;
167  wxCoord yoffset = 0;
168 
169  for ( int i = 0; i < pls->dev_npts; i++ )
170  {
171  points[i].x = (int) ( pls->dev_x[i] / scalex );
172  points[i].y = (int) ( height - pls->dev_y[i] / scaley );
173  if ( i > 0 )
174  AddtoClipRegion( points[i - 1].x, points[i - 1].y, points[i].x, points[i].y );
175  }
176 
177  if ( pls->dev_eofill )
178  {
179  m_dc->DrawPolygon( pls->dev_npts, points, xoffset, yoffset, wxODDEVEN_RULE );
180  }
181  else
182  {
183  m_dc->DrawPolygon( pls->dev_npts, points, xoffset, yoffset, wxWINDING_RULE );
184  }
185  delete[] points;
186 }
187 
188 
189 //--------------------------------------------------------------------------
190 // void wxPLDevDC::BlitRectangle( wxDC* dc, int vX, int vY,
191 // int vW, int vH )
192 //
193 // Copy/Blit a rectangle ((vX,vY) to (vX+vW,vY+vH)) into given dc.
194 //--------------------------------------------------------------------------
195 void wxPLDevDC::BlitRectangle( wxDC* dc, int vX, int vY, int vW, int vH )
196 {
197  if ( m_dc )
198  dc->Blit( vX, vY, vW, vH, m_dc, vX, vY );
199 }
200 
201 
202 //--------------------------------------------------------------------------
203 // void wxPLDevDC::CreateCanvas( void )
204 //
205 // Create canvas (bitmap and dc) if the driver provides the GUI.
206 //--------------------------------------------------------------------------
208 {
209  if ( ownGUI )
210  {
211  if ( !m_dc )
212  m_dc = new wxMemoryDC();
213 
214  ( (wxMemoryDC *) m_dc )->SelectObject( wxNullBitmap ); // deselect bitmap
215  if ( m_bitmap )
216  delete m_bitmap;
217  m_bitmap = new wxBitmap( bm_width, bm_height, 32 );
218  ( (wxMemoryDC *) m_dc )->SelectObject( *m_bitmap ); // select new bitmap
219  }
220 }
221 
222 
223 //--------------------------------------------------------------------------
224 // void wxPLDevDC::SetWidth( PLStream *pls )
225 //
226 // Set the width of the drawing pen.
227 //--------------------------------------------------------------------------
229 {
230  m_dc->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b ),
231  pls->width > 0 ? pls->width : 1, wxSOLID ) ) );
232 }
233 
234 
235 //--------------------------------------------------------------------------
236 // void wxPLDevDC::SetColor0( PLStream *pls )
237 //
238 // Set color from colormap 0.
239 //--------------------------------------------------------------------------
241 {
242  m_dc->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b, pls->curcolor.a ),
243  pls->width > 0 ? pls->width : 1, wxSOLID ) ) );
244  m_dc->SetBrush( wxBrush( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b, pls->curcolor.a ) ) );
245 }
246 
247 
248 //--------------------------------------------------------------------------
249 // void wxPLDevDC::SetColor1( PLStream *pls )
250 //
251 // Set color from colormap 1.
252 //--------------------------------------------------------------------------
254 {
255  m_dc->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b, pls->curcolor.a ),
256  pls->width > 0 ? pls->width : 1, wxSOLID ) ) );
257  m_dc->SetBrush( wxBrush( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b, pls->curcolor.a ) ) );
258 }
259 
260 
261 //--------------------------------------------------------------------------
262 // void wxPLDevDC::SetExternalBuffer( void* dc )
263 //
264 // Adds a dc to the device. In that case, the drivers doesn't provide
265 // a GUI.
266 //--------------------------------------------------------------------------
268 {
269  m_dc = (wxDC *) dc; // Add the dc to the device
270  ready = true;
271  ownGUI = false;
272 }
273 
274 
275 #ifdef PL_HAVE_FREETYPE
276 
277 //--------------------------------------------------------------------------
278 // void wxPLDevDC::PutPixel( short x, short y, PLINT color )
279 //
280 // Draw a pixel in color color @ (x,y).
281 //--------------------------------------------------------------------------
282 void wxPLDevDC::PutPixel( short x, short y, PLINT color )
283 {
284  const wxPen oldpen = m_dc->GetPen();
285  m_dc->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( GetRValue( color ), GetGValue( color ), GetBValue( color ) ),
286  1, wxSOLID ) ) );
287  m_dc->DrawPoint( x, y );
288  AddtoClipRegion( x, y, x, y );
289  m_dc->SetPen( oldpen );
290 }
291 
292 
293 //--------------------------------------------------------------------------
294 // void wxPLDevDC::PutPixel( short x, short y )
295 //
296 // Draw a pixel in current color @ (x,y).
297 //--------------------------------------------------------------------------
298 void wxPLDevDC::PutPixel( short x, short y )
299 {
300  m_dc->DrawPoint( x, y );
301  AddtoClipRegion( x, y, x, y );
302 }
303 
304 
305 //--------------------------------------------------------------------------
306 // PLINT wxPLDevDC::GetPixel( short x, short y )
307 //
308 // Get color information from pixel @ (x,y).
309 //--------------------------------------------------------------------------
310 PLINT wxPLDevDC::GetPixel( short x, short y )
311 {
312 #ifdef __WXGTK__
313  // The GetPixel method is incredible slow for wxGTK. Therefore we set the colour
314  // always to the background color, since this is the case anyway 99% of the time.
315  PLINT bgr, bgg, bgb; // red, green, blue
316  (void) x; (void) y; // Cast to void to silence compiler warnings about unused parameters
317  plgcolbg( &bgr, &bgg, &bgb ); // get background color information
318  return RGB( bgr, bgg, bgb );
319 #else
320  wxColour col;
321  m_dc->GetPixel( x, y, &col );
322  return RGB( col.Red(), col.Green(), col.Blue() );
323 #endif
324 }
325 
326 #endif // PL_HAVE_FREETYPE
327 
328 
329 //--------------------------------------------------------------------------
330 // void wxPLDevDC::PSDrawTextToDC( char* utf8_string, bool drawText )
331 //
332 // Draw utf8 text to screen if drawText==true. Otherwise determine
333 // width and height of text.
334 //--------------------------------------------------------------------------
335 void wxPLDevDC::PSDrawTextToDC( char* utf8_string, bool drawText )
336 {
337  wxCoord w, h, d, l;
338 
339  wxString str( wxConvUTF8.cMB2WC( utf8_string ), *wxConvCurrent );
340 
341  m_dc->GetTextExtent( str, &w, &h, &d, &l );
342 
343  if ( drawText )
344  {
345  m_dc->DrawRotatedText( str, (wxCoord) ( posX - yOffset / scaley * sin_rot ),
346  (wxCoord) ( height - (wxCoord) ( posY + yOffset * cos_rot / scaley ) ),
347  rotation * 180.0 / M_PI );
348  posX += (PLINT) ( w * cos_rot );
349  posY += (PLINT) ( w * sin_rot );
350  }
351 
352  textWidth += w;
353 
354  //keep track of the height of superscript text, the depth of subscript
355  //text and the height of regular text
356  if ( yOffset > 0.0001 )
357  {
358  //determine the height the text would have if it were full size
359  double currentOffset = yOffset;
360  double currentHeight = h;
361  while ( currentOffset > 0.0001 )
362  {
363  currentOffset -= scaley * fontSize * fontScale / 2.;
364  currentHeight *= 1.25;
365  }
366  textHeight = (wxCoord) textHeight > ( currentHeight )
367  ? textHeight
368  : currentHeight;
369  //work out the height including superscript
370  superscriptHeight = superscriptHeight > ( currentHeight + yOffset / scaley )
372  : static_cast<int>( ( currentHeight + yOffset / scaley ) );
373  }
374  else if ( yOffset < -0.0001 )
375  {
376  //determine the height the text would have if it were full size
377  double currentOffset = yOffset;
378  double currentHeight = h;
379  double currentDepth = d;
380  while ( currentOffset < -0.0001 )
381  {
382  currentOffset += scaley * fontSize * fontScale * 1.25 / 2.;
383  currentHeight *= 1.25;
384  currentDepth *= 1.25;
385  }
386  textHeight = (wxCoord) textHeight > currentHeight ? textHeight : currentHeight;
387  //work out the additional depth for subscript note an assumption has been made
388  //that the font size of (non-superscript and non-subscript) text is the same
389  //along a line. Currently there is no escape to change font size mid string
390  //so this should be fine
391  subscriptDepth = (wxCoord) subscriptDepth > ( ( -yOffset / scaley + h + d ) - ( currentDepth + textHeight ) )
393  : ( ( -yOffset / scaley + h + d ) - ( currentDepth + textHeight ) );
395  }
396  else
397  textHeight = (wxCoord) textHeight > ( h ) ? textHeight : h;
398 
399  memset( utf8_string, '\0', max_string_length );
400 }
401 
402 
403 //--------------------------------------------------------------------------
404 // void wxPLDevDC::PSSetFont( PLUNICODE fci )
405 //
406 // Set font defined by fci.
407 //--------------------------------------------------------------------------
409 {
410  unsigned char fontFamily, fontStyle, fontWeight;
411 
412  plP_fci2hex( fci, &fontFamily, PL_FCI_FAMILY );
413  plP_fci2hex( fci, &fontStyle, PL_FCI_STYLE );
414  plP_fci2hex( fci, &fontWeight, PL_FCI_WEIGHT );
415 
416  if ( m_font )
417  delete m_font;
418 
419  m_font = wxFont::New( (int) ( fontSize * fontScale < 4 ? 4 : fontSize * fontScale ),
420  fontFamilyLookup[fontFamily],
421  fontStyleLookup[fontStyle] | fontWeightLookup[fontWeight] );
422  m_font->SetUnderlined( underlined );
423  m_dc->SetFont( *m_font );
424 }
425 
426 
427 //--------------------------------------------------------------------------
428 // void wxPLDevDC::ProcessString( PLStream* pls, EscText* args )
429 //
430 // This is the main function which processes the unicode text strings.
431 // Font size, rotation and color are set, width and height of the
432 // text string is determined and then the string is drawn to the canvas.
433 //--------------------------------------------------------------------------
435 {
436  // Check that we got unicode, warning message and return if not
437  if ( args->unicode_array_len == 0 )
438  {
439  printf( "Non unicode string passed to the wxWidgets driver, ignoring\n" );
440  return;
441  }
442 
443  // Check that unicode string isn't longer then the max we allow
444  if ( args->unicode_array_len >= 500 )
445  {
446  printf( "Sorry, the wxWidgets drivers only handles strings of length < %d\n", 500 );
447  return;
448  }
449 
450  // Calculate the font size (in pixels)
451  fontSize = pls->chrht * VIRTUAL_PIXELS_PER_MM / scaley * 1.3;
452 
453  // Use PLplot core routine to get the corners of the clipping rectangle
454  PLINT rcx[4], rcy[4];
455  difilt_clip( rcx, rcy );
456 
457  wxPoint cpoints[4];
458  for ( int i = 0; i < 4; i++ )
459  {
460  cpoints[i].x = rcx[i] / scalex;
461  cpoints[i].y = height - rcy[i] / scaley;
462  }
463  wxDCClipper clip( *m_dc, wxRegion( 4, cpoints ) );
464 
465  // calculate rotation of text
466  plRotationShear( args->xform, &rotation, &shear, &stride );
467  rotation -= pls->diorot * M_PI / 2.0;
468  cos_rot = cos( rotation );
469  sin_rot = sin( rotation );
470 
471  // Set font color
472  m_dc->SetTextForeground( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b ) );
473  m_dc->SetTextBackground( wxColour( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b ) );
474 
475  PLUNICODE *lineStart = args->unicode_array;
476  int lineLen = 0;
477  bool lineFeed = false;
478  bool carriageReturn = false;
479  wxCoord paraHeight = 0;
480  // Get the curent font
481  fontScale = 1.0;
482  yOffset = 0.0;
483  plgfci( &fci );
484  PSSetFont( fci );
485  while ( lineStart != args->unicode_array + args->unicode_array_len )
486  {
487  while ( lineStart + lineLen != args->unicode_array + args->unicode_array_len
488  && *( lineStart + lineLen ) != (PLUNICODE) '\n' )
489  {
490  lineLen++;
491  }
492  //set line feed for the beginning of this line and
493  //carriage return for the end
494  lineFeed = carriageReturn;
495  carriageReturn = lineStart + lineLen != args->unicode_array + args->unicode_array_len
496  && *( lineStart + lineLen ) == (PLUNICODE) ( '\n' );
497  if ( lineFeed )
498  paraHeight += textHeight + subscriptDepth;
499 
500  //remember the text parameters so they can be restored
501  double startingFontScale = fontScale;
502  double startingYOffset = yOffset;
503  PLUNICODE startingFci = fci;
504 
505  // determine extent of text
506  posX = args->x / scalex;
507  posY = args->y / scaley;
508 
509  PSDrawText( lineStart, lineLen, false );
510 
511  if ( lineFeed && superscriptHeight > textHeight )
512  paraHeight += superscriptHeight - textHeight;
513 
514  // actually draw text, resetting the font first
515  fontScale = startingFontScale;
516  yOffset = startingYOffset;
517  fci = startingFci;
518  PSSetFont( fci );
519  posX = (PLINT) ( args->x / scalex - ( args->just * textWidth ) * cos_rot - ( 0.5 * textHeight - paraHeight * lineSpacing ) * sin_rot ); //move to set alignment
520  posY = (PLINT) ( args->y / scaley - ( args->just * textWidth ) * sin_rot + ( 0.5 * textHeight - paraHeight * lineSpacing ) * cos_rot );
521  PSDrawText( lineStart, lineLen, true ); //draw text
522 
523  lineStart += lineLen;
524  if ( carriageReturn )
525  lineStart++;
526  lineLen = 0;
527  }
528  //posX = args->x;
529  //posY = args->y;
530  //PSDrawText( args->unicode_array, args->unicode_array_len, false );
531 
532  //posX = (PLINT) ( args->x - ( ( args->just * textWidth ) * cos_rot + ( 0.5 * textHeight ) * sin_rot ) * scalex );
533  //posY = (PLINT) ( args->y - ( ( args->just * textWidth ) * sin_rot - ( 0.5 * textHeight ) * cos_rot ) * scaley );
534  //PSDrawText( args->unicode_array, args->unicode_array_len, true );
535 
536  AddtoClipRegion( 0, 0, width, height );
537 }
538 
539