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