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