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