PLplot  5.10.0
wxwidgets_gc.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines