PLplot
5.10.0
|
00001 // Copyright (C) 2008 Werner Smekal 00002 // 00003 // This file is part of PLplot. 00004 // 00005 // PLplot is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU Library General Public License as published 00007 // by the Free Software Foundation; either version 2 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // PLplot is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU Library General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU Library General Public License 00016 // along with PLplot; if not, write to the Free Software 00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00018 // 00019 00020 00021 // TODO: 00022 // - text clipping 00023 // - implement AddToClipRegion for text correctly 00024 // 00025 00026 // wxwidgets headers 00027 #include <wx/wx.h> 00028 00029 #include "plDevs.h" 00030 00031 // plplot headers 00032 #include "plplotP.h" 00033 00034 // std and driver headers 00035 #include "wxwidgets.h" 00036 00037 #include <wx/string.h> 00038 #include <string> 00039 00040 // only compile code if wxGraphicsContext available 00041 #if wxUSE_GRAPHICS_CONTEXT 00042 00043 wxPLDevGC::wxPLDevGC( void ) : wxPLDevBase( wxBACKEND_GC ) 00044 { 00045 // Log_Verbose( "%s", __FUNCTION__ ); 00046 00047 m_dc = NULL; 00048 m_bitmap = NULL; 00049 m_context = NULL; 00050 m_font = NULL; 00051 underlined = false; 00052 } 00053 00054 00055 wxPLDevGC::~wxPLDevGC() 00056 { 00057 // Log_Verbose( "%s", __FUNCTION__ ); 00058 00059 if ( ownGUI ) 00060 { 00061 if ( m_dc ) 00062 { 00063 ( (wxMemoryDC *) m_dc )->SelectObject( wxNullBitmap ); 00064 delete m_dc; 00065 } 00066 if ( m_bitmap ) 00067 delete m_bitmap; 00068 } 00069 00070 delete m_font; 00071 delete m_context; 00072 } 00073 00074 00075 void wxPLDevGC::DrawLine( short x1a, short y1a, short x2a, short y2a ) 00076 { 00077 // Log_Verbose( "%s", __FUNCTION__ ); 00078 00079 wxDouble x1 = x1a / scalex; 00080 wxDouble y1 = height - y1a / scaley; 00081 wxDouble x2 = x2a / scalex; 00082 wxDouble y2 = height - y2a / scaley; 00083 00084 wxGraphicsPath path = m_context->CreatePath(); 00085 path.MoveToPoint( x1, y1 ); 00086 path.AddLineToPoint( x2, y2 ); 00087 m_context->StrokePath( path ); 00088 00089 AddtoClipRegion( (int) x1, (int) y1, (int) x2, (int) y2 ); 00090 } 00091 00092 00093 void wxPLDevGC::DrawPolyline( short *xa, short *ya, PLINT npts ) 00094 { 00095 // Log_Verbose( "%s", __FUNCTION__ ); 00096 00097 wxGraphicsPath path = m_context->CreatePath(); 00098 path.MoveToPoint( xa[0] / scalex, height - ya[0] / scaley ); 00099 for ( PLINT i = 1; i < npts; i++ ) 00100 path.AddLineToPoint( xa[i] / scalex, height - ya[i] / scaley ); 00101 m_context->StrokePath( path ); 00102 00103 wxDouble x, y, w, h; 00104 path.GetBox( &x, &y, &w, &h ); 00105 AddtoClipRegion( (int) x, (int) y, (int) ( x + w ), (int) ( y + h ) ); 00106 } 00107 00108 00109 void wxPLDevGC::ClearBackground( PLINT bgr, PLINT bgg, PLINT bgb, PLINT x1, PLINT y1, PLINT x2, PLINT y2 ) 00110 { 00111 // Log_Verbose( "%s", __FUNCTION__ ); 00112 00113 wxDouble x1a, y1a, x2a, y2a; 00114 00115 if ( x1 < 0 ) 00116 x1a = 0; 00117 else 00118 x1a = x1 / scalex; 00119 if ( y1 < 0 ) 00120 y1a = 0; 00121 else 00122 y1a = height - y1 / scaley; 00123 if ( x2 < 0 ) 00124 x2a = width; 00125 else 00126 x2a = x2 / scalex; 00127 if ( y2 < 0 ) 00128 y2a = height; 00129 else 00130 y2a = height - y2 / scaley; 00131 00132 m_context->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( bgr, bgg, bgb ), 1, wxSOLID ) ) ); 00133 m_context->SetBrush( wxBrush( wxColour( bgr, bgg, bgb ) ) ); 00134 m_context->DrawRectangle( x1a, y1a, x2a - x1a, y2a - y1a ); 00135 00136 m_context->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( mColorRedStroke, mColorGreenStroke, 00137 mColorBlueStroke, mStrokeOpacity ), 00138 1, wxSOLID ) ) ); 00139 m_context->SetBrush( wxBrush( wxColour( mColorRedFill, mColorGreenFill, mColorBlueFill, mStrokeOpacity ) ) ); 00140 00141 AddtoClipRegion( (int) x1a, (int) y1a, (int) x2a, (int) y2a ); 00142 } 00143 00144 00145 void wxPLDevGC::FillPolygon( PLStream *pls ) 00146 { 00147 // Log_Verbose( "%s", __FUNCTION__ ); 00148 00149 bool isRect = false; 00150 short* x = pls->dev_x; 00151 short* y = pls->dev_y; 00152 00153 if ( pls->dev_npts == 4 ) // Check if it's a rectangle. If so, it can be made faster to display 00154 { 00155 if ( x[0] == x[1] && x[2] == x[3] && y[0] == y[3] && y[1] == y[2] ) 00156 isRect = true; 00157 else if ( x[0] == x[3] && x[1] == x[2] && y[0] == y[1] && y[2] == y[3] ) 00158 isRect = true; 00159 } 00160 if ( pls->dev_npts == 5 ) 00161 { 00162 if ( x[0] == x[4] && y[0] == y[4] ) 00163 { 00164 if ( x[0] == x[1] && x[2] == x[3] && y[0] == y[3] && y[1] == y[2] ) 00165 isRect = true; 00166 else if ( x[0] == x[3] && x[1] == x[2] && y[0] == y[1] && y[2] == y[3] ) 00167 isRect = true; 00168 } 00169 } 00170 00171 if ( isRect ) //isRect) { 00172 { 00173 double x1, y1, x2, y2, x0, y0, w, h; 00174 00175 x1 = x[0] / scalex; 00176 x2 = x[2] / scalex; 00177 y1 = height - y[0] / scaley; 00178 y2 = height - y[2] / scaley; 00179 00180 if ( x1 < x2 ) 00181 { 00182 x0 = x1; 00183 w = x2 - x1; 00184 } 00185 else 00186 { 00187 x0 = x2; 00188 w = x1 - x2; 00189 } 00190 if ( y1 < y2 ) 00191 { 00192 y0 = y1; 00193 h = y2 - y1; 00194 } 00195 else 00196 { 00197 y0 = y2; 00198 h = y1 - y2; 00199 } 00200 m_context->DrawRectangle( x0, y0, w, h ); 00201 AddtoClipRegion( (int) x0, (int) y0, (int) w, (int) h ); 00202 } 00203 else 00204 { 00205 wxGraphicsPath path = m_context->CreatePath(); 00206 path.MoveToPoint( x[0] / scalex, height - y[0] / scaley ); 00207 for ( int i = 1; i < pls->dev_npts; i++ ) 00208 path.AddLineToPoint( x[i] / scalex, height - y[i] / scaley ); 00209 path.CloseSubpath(); 00210 00211 if ( pls->dev_eofill ) 00212 m_context->DrawPath( path, wxODDEVEN_RULE ); 00213 else 00214 m_context->DrawPath( path, wxWINDING_RULE ); 00215 00216 wxDouble x, y, w, h; 00217 path.GetBox( &x, &y, &w, &h ); 00218 00219 AddtoClipRegion( (int) x, (int) y, (int) ( x + w ), (int) ( y + h ) ); 00220 } 00221 } 00222 00223 00224 void wxPLDevGC::BlitRectangle( wxDC* dc, int vX, int vY, int vW, int vH ) 00225 { 00226 // Log_Verbose( "%s", __FUNCTION__ ); 00227 00228 if ( m_dc ) 00229 dc->Blit( vX, vY, vW, vH, m_dc, vX, vY ); 00230 } 00231 00232 00233 void wxPLDevGC::CreateCanvas() 00234 { 00235 // Log_Verbose( "%s", __FUNCTION__ ); 00236 00237 if ( ownGUI ) 00238 { 00239 if ( !m_dc ) 00240 m_dc = new wxMemoryDC(); 00241 00242 ( (wxMemoryDC *) m_dc )->SelectObject( wxNullBitmap ); // deselect bitmap 00243 if ( m_bitmap ) 00244 delete m_bitmap; 00245 m_bitmap = new wxBitmap( bm_width, bm_height, 32 ); 00246 ( (wxMemoryDC *) m_dc )->SelectObject( *m_bitmap ); // select new bitmap 00247 } 00248 00249 if ( m_dc ) 00250 { 00251 delete m_context; 00252 m_context = wxGraphicsContext::Create( *( (wxMemoryDC *) m_dc ) ); 00253 } 00254 } 00255 00256 00257 void wxPLDevGC::SetWidth( PLStream *pls ) 00258 { 00259 // Log_Verbose( "%s", __FUNCTION__ ); 00260 00261 m_context->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( mColorRedStroke, mColorGreenStroke, 00262 mColorBlueStroke, mStrokeOpacity ), 00263 pls->width > 0 ? pls->width : 1, wxSOLID ) ) ); 00264 } 00265 00266 00267 void wxPLDevGC::SetColor0( PLStream *pls ) 00268 { 00269 // Log_Verbose( "%s", __FUNCTION__ ); 00270 00271 mColorRedStroke = pls->curcolor.r; 00272 mColorGreenStroke = pls->curcolor.g; 00273 mColorBlueStroke = pls->curcolor.b; 00274 mColorRedFill = pls->curcolor.r; 00275 mColorGreenFill = pls->curcolor.g; 00276 mColorBlueFill = pls->curcolor.b; 00277 mStrokeOpacity = (unsigned char) ( pls->curcolor.a * 255 ); 00278 00279 m_context->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( mColorRedStroke, mColorGreenStroke, 00280 mColorBlueStroke, mStrokeOpacity ), 00281 pls->width > 0 ? pls->width : 1, wxSOLID ) ) ); 00282 m_context->SetBrush( wxBrush( wxColour( mColorRedFill, mColorGreenFill, mColorBlueFill, mStrokeOpacity ) ) ); 00283 } 00284 00285 00286 void wxPLDevGC::SetColor1( PLStream *pls ) 00287 { 00288 // Log_Verbose( "%s", __FUNCTION__ ); 00289 00290 mColorRedStroke = pls->curcolor.r; 00291 mColorGreenStroke = pls->curcolor.g; 00292 mColorBlueStroke = pls->curcolor.b; 00293 mColorRedFill = pls->curcolor.r; 00294 mColorGreenFill = pls->curcolor.g; 00295 mColorBlueFill = pls->curcolor.b; 00296 mStrokeOpacity = (unsigned char) ( pls->curcolor.a * 255 ); 00297 00298 m_context->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( mColorRedStroke, mColorGreenStroke, 00299 mColorBlueStroke, mStrokeOpacity ), 00300 pls->width > 0 ? pls->width : 1, wxSOLID ) ) ); 00301 m_context->SetBrush( wxBrush( wxColour( mColorRedFill, mColorGreenFill, mColorBlueFill, mStrokeOpacity ) ) ); 00302 } 00303 00304 00305 //-------------------------------------------------------------------------- 00306 // void wx_set_dc( PLStream* pls, wxDC* dc ) 00307 // 00308 // Adds a dc to the stream. The associated device is attached to the canvas 00309 // as the property "dev". 00310 //-------------------------------------------------------------------------- 00311 void wxPLDevGC::SetExternalBuffer( void* dc ) 00312 { 00313 // Log_Verbose( "%s", __FUNCTION__ ); 00314 00315 m_dc = (wxDC *) dc; // Add the dc to the device 00316 m_context = wxGraphicsContext::Create( *( (wxMemoryDC *) m_dc ) ); 00317 ready = true; 00318 ownGUI = false; 00319 } 00320 00321 00322 #ifdef PL_HAVE_FREETYPE 00323 00324 void wxPLDevGC::PutPixel( short x, short y, PLINT color ) 00325 { 00326 // Log_Verbose( "%s", __FUNCTION__ ); 00327 00328 const wxPen oldpen = m_dc->GetPen(); 00329 m_context->SetPen( *( wxThePenList->FindOrCreatePen( wxColour( GetRValue( color ), GetGValue( color ), GetBValue( color ) ), 00330 1, wxSOLID ) ) ); 00331 //m_context->DrawPoint( x, y ); 00332 AddtoClipRegion( x, y, x, y ); 00333 m_context->SetPen( oldpen ); 00334 } 00335 00336 void wxPLDevGC::PutPixel( short x, short y ) 00337 { 00338 // Log_Verbose( "%s", __FUNCTION__ ); 00339 00340 //m_dc->DrawPoint( x, y ); 00341 AddtoClipRegion( x, y, x, y ); 00342 } 00343 00344 PLINT wxPLDevGC::GetPixel( short x, short y ) 00345 { 00346 // Log_Verbose( "%s", __FUNCTION__ ); 00347 00348 #ifdef __WXGTK__ 00349 // Cast function parameters to (void) to silence compiler warnings about unused parameters 00350 (void) x; 00351 (void) y; 00352 // The GetPixel method is incredible slow for wxGTK. Therefore we set the colour 00353 // always to the background color, since this is the case anyway 99% of the time. 00354 PLINT bgr, bgg, bgb; // red, green, blue 00355 plgcolbg( &bgr, &bgg, &bgb ); // get background color information 00356 return RGB( bgr, bgg, bgb ); 00357 #else 00358 wxColour col; 00359 m_dc->GetPixel( x, y, &col ); 00360 return RGB( col.Red(), col.Green(), col.Blue() ); 00361 #endif 00362 } 00363 00364 #endif // PL_HAVE_FREETYPE 00365 00366 00367 void wxPLDevGC::PSDrawTextToDC( char* utf8_string, bool drawText ) 00368 { 00369 // Log_Verbose( "%s", __FUNCTION__ ); 00370 00371 wxDouble w, h, d, l; 00372 00373 wxString str( wxConvUTF8.cMB2WC( utf8_string ), *wxConvCurrent ); 00374 00375 w = 0; 00376 m_context->GetTextExtent( str, &w, &h, &d, &l ); 00377 00378 if ( drawText ) 00379 { 00380 m_context->DrawText( str, 0, -yOffset / scaley ); 00381 m_context->Translate( w, 0 ); 00382 } 00383 00384 textWidth += static_cast<int>( w ); 00385 00386 //keep track of the height of superscript text, the depth of subscript 00387 //text and the height of regular text 00388 if ( yOffset > 0.0001 ) 00389 { 00390 //determine the height the text would have if it were full size 00391 double currentOffset = yOffset; 00392 double currentHeight = h; 00393 while ( currentOffset > 0.0001 ) 00394 { 00395 currentOffset -= scaley * fontSize * fontScale / 2.; 00396 currentHeight *= 1.25; 00397 } 00398 textHeight = textHeight > ( currentHeight ) 00399 ? textHeight 00400 : static_cast<int>( ( currentHeight ) ); 00401 //work out the height including superscript 00402 superscriptHeight = superscriptHeight > ( currentHeight + yOffset / scaley ) 00403 ? superscriptHeight 00404 : static_cast<int>( ( currentHeight + yOffset / scaley ) ); 00405 } 00406 else if ( yOffset < -0.0001 ) 00407 { 00408 //determine the height the text would have if it were full size 00409 double currentOffset = yOffset; 00410 double currentHeight = h; 00411 double currentDepth = d; 00412 while ( currentOffset < -0.0001 ) 00413 { 00414 currentOffset += scaley * fontSize * fontScale * 1.25 / 2.; 00415 currentHeight *= 1.25; 00416 currentDepth *= 1.25; 00417 } 00418 textHeight = textHeight > currentHeight ? textHeight : static_cast<int>( ( currentHeight ) ); 00419 //work out the additional depth for subscript note an assumption has been made 00420 //that the font size of (non-superscript and non-subscript) text is the same 00421 //along a line. Currently there is no escape to change font size mid string 00422 //so this should be fine 00423 subscriptDepth = subscriptDepth > ( ( -yOffset / scaley + h + d ) - ( currentDepth + textHeight ) ) 00424 ? subscriptDepth 00425 : static_cast<int>( ( -yOffset / scaley + h + d ) - ( currentDepth + textHeight ) ); 00426 subscriptDepth = subscriptDepth > 0 ? subscriptDepth : 0; 00427 } 00428 else 00429 textHeight = textHeight > h ? textHeight : static_cast<int>( h ); 00430 00431 memset( utf8_string, '\0', max_string_length ); 00432 } 00433 00434 00435 void wxPLDevGC::PSSetFont( PLUNICODE fci ) 00436 { 00437 // Log_Verbose( "%s", __FUNCTION__ ); 00438 00439 unsigned char fontFamily, fontStyle, fontWeight; 00440 00441 plP_fci2hex( fci, &fontFamily, PL_FCI_FAMILY ); 00442 plP_fci2hex( fci, &fontStyle, PL_FCI_STYLE ); 00443 plP_fci2hex( fci, &fontWeight, PL_FCI_WEIGHT ); 00444 if ( m_font ) 00445 delete m_font; 00446 m_font = wxFont::New( static_cast<int>( fontSize * fontScale ), 00447 fontFamilyLookup[fontFamily], 00448 fontStyleLookup[fontStyle] | fontWeightLookup[fontWeight] ); 00449 m_font->SetUnderlined( underlined ); 00450 m_context->SetFont( *m_font, wxColour( textRed, textGreen, textBlue ) ); 00451 } 00452 00453 00454 void wxPLDevGC::ProcessString( PLStream* pls, EscText* args ) 00455 { 00456 // Log_Verbose( "%s", __FUNCTION__ ); 00457 00458 // Check that we got unicode, warning message and return if not 00459 if ( args->unicode_array_len == 0 ) 00460 { 00461 printf( "Non unicode string passed to a cairo driver, ignoring\n" ); 00462 return; 00463 } 00464 00465 // Check that unicode string isn't longer then the max we allow 00466 if ( args->unicode_array_len >= max_string_length ) 00467 { 00468 printf( "Sorry, the wxWidgets drivers only handles strings of length < %d\n", max_string_length ); 00469 return; 00470 } 00471 00472 // Calculate the font size (in pixels) 00473 fontSize = pls->chrht * VIRTUAL_PIXELS_PER_MM / scaley * 1.3; 00474 00475 // Use PLplot core routine to get the corners of the clipping rectangle 00476 PLINT rcx[4], rcy[4]; 00477 difilt_clip( rcx, rcy ); 00478 00479 #ifdef __WXOSX_COCOA__ 00480 wxPoint topLeft( width, height ), bottomRight( -1, -1 ); 00481 for ( int i = 0; i < 4; i++ ) 00482 { 00483 topLeft.x = topLeft.x > ( rcx[i] / scalex ) ? ( rcx[i] / scalex ) : topLeft.x; 00484 topLeft.y = topLeft.y > ( height - rcy[i] / scaley ) ? ( height - rcy[i] / scaley ) : topLeft.y; 00485 bottomRight.x = bottomRight.x < ( rcx[i] / scalex ) ? ( rcx[i] / scalex ) : bottomRight.x; 00486 bottomRight.y = bottomRight.y < ( height - rcy[i] / scaley ) ? ( height - rcy[i] / scaley ) : bottomRight.y; 00487 } 00488 00489 m_context->Clip( wxRegion( topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y ) ); 00490 // m_context->Clip( wxRegion( topLeft, bottomRight) ); // this wxRegion constructor doesn't work in wxWidgets 2.9.2/Cocoa 00491 #else 00492 wxPoint cpoints[4]; 00493 for ( int i = 0; i < 4; i++ ) 00494 { 00495 cpoints[i].x = rcx[i] / scalex; 00496 cpoints[i].y = height - rcy[i] / scaley; 00497 } 00498 m_context->Clip( wxRegion( 4, cpoints ) ); 00499 #endif 00500 00501 // text color 00502 textRed = pls->curcolor.r; 00503 textGreen = pls->curcolor.g; 00504 textBlue = pls->curcolor.b; 00505 00506 // calculate rotation of text 00507 plRotationShear( args->xform, &rotation, &shear, &stride ); 00508 rotation -= pls->diorot * M_PI / 2.0; 00509 cos_rot = cos( rotation ); 00510 sin_rot = sin( rotation ); 00511 cos_shear = cos( shear ); 00512 sin_shear = sin( shear ); 00513 00514 00515 PLUNICODE *lineStart = args->unicode_array; 00516 int lineLen = 0; 00517 bool lineFeed = false; 00518 bool carriageReturn = false; 00519 wxCoord paraHeight = 0; 00520 // Get the curent font 00521 fontScale = 1.0; 00522 yOffset = 0.0; 00523 plgfci( &fci ); 00524 PSSetFont( fci ); 00525 while ( lineStart != args->unicode_array + args->unicode_array_len ) 00526 { 00527 while ( lineStart + lineLen != args->unicode_array + args->unicode_array_len 00528 && *( lineStart + lineLen ) != (PLUNICODE) '\n' ) 00529 { 00530 lineLen++; 00531 } 00532 //set line feed for the beginning of this line and 00533 //carriage return for the end 00534 lineFeed = carriageReturn; 00535 carriageReturn = lineStart + lineLen != args->unicode_array + args->unicode_array_len 00536 && *( lineStart + lineLen ) == (PLUNICODE) ( '\n' ); 00537 if ( lineFeed ) 00538 paraHeight += textHeight + subscriptDepth; 00539 00540 //remember the text parameters so they can be restored 00541 double startingFontScale = fontScale; 00542 double startingYOffset = yOffset; 00543 PLUNICODE startingFci = fci; 00544 00545 // determine extent of text 00546 PSDrawText( lineStart, lineLen, false ); 00547 00548 if ( lineFeed && superscriptHeight > textHeight ) 00549 paraHeight += superscriptHeight - textHeight; 00550 00551 // actually draw text, resetting the font first 00552 fontScale = startingFontScale; 00553 yOffset = startingYOffset; 00554 fci = startingFci; 00555 PSSetFont( fci ); 00556 m_context->PushState(); //save current position 00557 m_context->Translate( args->x / scalex, height - args->y / scaley ); //move to text starting position 00558 wxGraphicsMatrix matrix = m_context->CreateMatrix( 00559 cos_rot * stride, -sin_rot * stride, 00560 cos_rot * sin_shear + sin_rot * cos_shear, 00561 -sin_rot * sin_shear + cos_rot * cos_shear, 00562 0.0, 0.0 ); //create rotation transformation matrix 00563 m_context->ConcatTransform( matrix ); //rotate 00564 m_context->Translate( -args->just * textWidth, -0.5 * textHeight + paraHeight * lineSpacing ); //move to set alignment 00565 PSDrawText( lineStart, lineLen, true ); //draw text 00566 m_context->PopState(); //return to original position 00567 00568 lineStart += lineLen; 00569 if ( carriageReturn ) 00570 lineStart++; 00571 lineLen = 0; 00572 } 00573 00574 00575 AddtoClipRegion( 0, 0, width, height ); 00576 00577 m_context->ResetClip(); 00578 } 00579 00580 #endif