PLplot: wxwidgets_gc.cpp Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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