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