PLplot  5.10.0
plqt.cpp
Go to the documentation of this file.
00001 // This software was donated under the LGPL to the PLplot project in
00002 // March 2009 by the
00003 // Cluster Science Centre
00004 // QSAS team,
00005 // Imperial College, London
00006 //
00007 // Copyright (C) 2009  Imperial College, London
00008 // Copyright (C) 2009-2011  Alan W. Irwin
00009 //
00010 // This is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU General Lesser Public License as published
00012 // by the Free Software Foundation; either version 2 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // This software is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // To received a copy of the GNU Library General Public License
00021 // write to the Free Software Foundation, Inc.,
00022 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00023 //
00024 
00025 #include "qt.h"
00026 
00027 // Global variables for Qt driver.
00028 PLDLLIMPEXP_QT_DATA( int ) vectorize = 0;
00029 PLDLLIMPEXP_QT_DATA( int ) lines_aa  = 1;
00030 PLDLLIMPEXP_QT_DATA( MasterHandler ) handler;
00031 
00032 // Master Device Handler for multiple streams
00033 // Only handles multiple Qt devices
00034 MasterHandler::MasterHandler() : QObject()
00035 {
00036     masterDevice = NULL;
00037 }
00038 
00039 bool MasterHandler::isMasterDevice( QtPLDriver* d )
00040 {
00041     return d == masterDevice;
00042 }
00043 
00044 void MasterHandler::setMasterDevice( QtPLDriver* d )
00045 {
00046     masterDevice = d;
00047 }
00048 
00049 void MasterHandler::DeviceChangedPage( QtPLDriver* d )
00050 {
00051     if ( d == masterDevice )
00052     {
00053         emit MasterChangedPage();
00054     }
00055 }
00056 
00057 void MasterHandler::DeviceClosed( QtPLDriver* d )
00058 {
00059     if ( d == masterDevice )
00060     {
00061         emit MasterClosed();
00062         masterDevice = NULL;
00063     }
00064 }
00065 
00067 QMutex QtPLDriver::mutex;
00068 
00069 QtPLDriver::QtPLDriver( PLINT i_iWidth, PLINT i_iHeight )
00070 {
00071     m_dWidth  = i_iWidth;
00072     m_dHeight = i_iHeight;
00073 }
00074 
00075 QtPLDriver::~QtPLDriver()
00076 {
00077 }
00078 
00079 void QtPLDriver::setPLStream( PLStream *p )
00080 {
00081     pls = p;
00082 }
00083 
00084 void QtPLDriver::drawArc( short x, short y, short a, short b, PLFLT angle1, PLFLT angle2, PLFLT rotate, bool fill )
00085 {
00086     if ( !m_painterP->isActive() )
00087         return;
00088     QRectF rect( (PLFLT) ( x - a ) * downscale,
00089                  m_dHeight - (PLFLT) ( y + b ) * downscale,
00090                  (PLFLT) a * downscale * 2,
00091                  (PLFLT) b * downscale * 2
00092                  );
00093     if ( rotate != 0.0 )
00094     {
00095         m_painterP->save();
00096         m_painterP->translate( (PLFLT) x * downscale, m_dHeight - (PLFLT) y * downscale );
00097         m_painterP->rotate( -rotate );
00098         m_painterP->translate( -(PLFLT) x * downscale, -m_dHeight + (PLFLT) y * downscale );
00099     }
00100 
00101     if ( fill )
00102         m_painterP->drawPie( rect, (int) ( angle1 * 16 ), (int) ( ( angle2 - angle1 ) * 16 ) );
00103     else
00104         m_painterP->drawArc( rect, (int) ( angle1 * 16 ), (int) ( ( angle2 - angle1 ) * 16 ) );
00105 
00106     if ( rotate != 0.0 )
00107     {
00108         m_painterP->restore();
00109     }
00110 }
00111 
00112 void QtPLDriver::drawLine( short x1, short y1, short x2, short y2 )
00113 {
00114     if ( !m_painterP->isActive() )
00115         return;
00116     QLineF line( (PLFLT) x1 * downscale,
00117                  m_dHeight - (PLFLT) y1 * downscale,
00118                  (PLFLT) x2 * downscale,
00119                  m_dHeight - (PLFLT) y2 * downscale
00120                  );
00121 
00122     m_painterP->drawLine( line );
00123 }
00124 
00125 void QtPLDriver::drawPolyline( short * x, short * y, PLINT npts )
00126 {
00127     if ( !m_painterP->isActive() )
00128         return;
00129     QPointF * polyline = new QPointF[npts];
00130     for ( int i = 0; i < npts; ++i )
00131     {
00132         polyline[i].setX( (PLFLT) x[i] * downscale );
00133         polyline[i].setY( m_dHeight - (PLFLT) y[i] * downscale );
00134     }
00135     m_painterP->drawPolyline( polyline, npts );
00136     delete[] polyline;
00137 }
00138 
00139 void QtPLDriver::drawPolygon( short * x, short * y, PLINT npts )
00140 {
00141     if ( !m_painterP->isActive() )
00142         return;
00143     QPointF * polygon = new QPointF[npts];
00144     for ( int i = 0; i < npts; ++i )
00145     {
00146         polygon[i].setX( (PLFLT) x[i] * downscale );
00147         polygon[i].setY( m_dHeight - (PLFLT) y[i] * downscale );
00148     }
00149     if ( plsc->dev_eofill )
00150         m_painterP->drawPolygon( polygon, npts, Qt::OddEvenFill );
00151     else
00152         m_painterP->drawPolygon( polygon, npts, Qt::WindingFill );
00153     delete[] polygon;
00154 }
00155 
00156 
00157 QFont QtPLDriver::getFont( PLUNICODE unicode )
00158 {
00159     // Get new font parameters
00160     unsigned char fontFamily, fontStyle, fontWeight;
00161 
00162     plP_fci2hex( unicode, &fontFamily, PL_FCI_FAMILY );
00163     plP_fci2hex( unicode, &fontStyle, PL_FCI_STYLE );
00164     plP_fci2hex( unicode, &fontWeight, PL_FCI_WEIGHT );
00165 
00166     QFont f;
00167 
00168     f.setPointSizeF( currentFontSize * currentFontScale < 4 ? 4 : currentFontSize * currentFontScale );
00169 
00170     switch ( fontFamily )
00171     {
00172     case 1:
00173         f.setStyleHint( QFont::Serif );
00174         break;
00175     case 2:
00176         f.setStyleHint( QFont::TypeWriter );
00177         break;
00178     case 0: case 3: case 4: default:
00179         f.setStyleHint( QFont::SansSerif );
00180         break;
00181     }
00182     f.setFamily( "" ); // no family name, forcing Qt to find an appropriate font by itself
00183 
00184     if ( fontStyle )
00185         f.setItalic( true );
00186     if ( fontWeight )
00187         f.setWeight( QFont::Bold );
00188     else
00189         f.setWeight( QFont::Normal );
00190 
00191     f.setUnderline( underlined );
00192     f.setOverline( overlined );
00193 
00194     return f;
00195 }
00196 
00197 void QtPLDriver::drawTextInPicture( QPainter* p, const QString& text )
00198 {
00199     QRectF   rect( 0., 0., 0., 0. );
00200     QRectF   bounding;
00201     QPicture tempPic;
00202     QPainter tempPainter( &tempPic );
00203     tempPainter.setFont( p->font() );
00204 
00205     if ( vectorize )
00206     {
00207         bounding = tempPainter.boundingRect( rect, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextDontClip, text );
00208 
00209         tempPainter.save();
00210 //         QPen savePen=tempPainter.pen();
00211         QPen pen = QPen( Qt::NoPen );
00212         tempPainter.setPen( pen );
00213 
00214         double       offset = QFontMetrics( tempPainter.font(), &tempPic ).boundingRect( text ).top(); // Distance between the baseline and the top of the bounding box
00215 
00216         QPainterPath path;
00217         path.addText( QPointF( bounding.left(), bounding.top() - offset ), tempPainter.font(), text );
00218         tempPainter.drawPath( path );
00219         tempPainter.restore();
00220     }
00221     else
00222     {
00223         tempPainter.drawText( rect, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextDontClip, text, &bounding );
00224     }
00225 
00226     tempPainter.end();
00227 
00228     p->drawPicture( (int) ( xOffset + bounding.width() / 2. ), (int) -yOffset, tempPic );
00229 
00230     xOffset += bounding.width();
00231 }
00232 
00233 // 0.8 mimics the offset of first superscript/subscript level implemented
00234 // in plstr (plsym.c) for Hershey fonts.  Indeed when comparing with
00235 // -dev xwin results this factor appears to offset the centers of the
00236 // letters appropriately (but not their edges since different font sizes
00237 // are involved).
00238 # define RISE_FACTOR    0.8
00239 
00240 QPicture QtPLDriver::getTextPicture( PLUNICODE fci, PLUNICODE* text, int len, PLFLT chrht )
00241 {
00242     char plplotEsc;
00243     plgesc( &plplotEsc );
00244 
00245     QPicture res;
00246     QPainter p( &res );
00247 
00248     QString  currentString;
00249     PLFLT    old_sscale, sscale, old_soffset, soffset;
00250     PLINT    level    = 0;
00251     PLFLT    dyOffset = 0.;
00252 #ifdef PLPLOT_USE_QT5
00253     // Empirical Y offset of text (needed for Qt5 for some reason).
00254     // Note this was derived using the test_circle.py python script
00255     // with the vertical alignment of the light diagonal cross
00256     // optimized.  That example shows that other glyphs (except for
00257     // the well-known asterisk case which is vertically misaligned by
00258     // font design) do not have the best vertical alignment.  This is
00259     // contrary to the results for cairo and qt with Qt4 which need no
00260     // special empirical Y offset to get good vertical alignment for
00261     // most glyphs of that example (other than the asterisk).  An
00262     // additional issue which confuses the decision concerning the
00263     // best vertical alignment for qt with Qt5 is the font selection
00264     // for qt with Qt5 is quite different than that for qt with Qt4 or
00265     // cairo.  I assume all these issues are due to Qt5 version 5.2.1
00266     // font selection and font alignment bugs which will be addressed
00267     // for future Qt5 versions.
00268     PLFLT empirical_yOffset = -0.63 * chrht * POINTS_PER_INCH / 25.4;
00269 #else
00270     PLFLT empirical_yOffset = 0.;
00271 #endif
00272     yOffset = empirical_yOffset;
00273     xOffset = 0.;
00274 
00275     // Scaling factor of 1.45 determined empirically to make all qt results
00276     // have the same character size as cairo results (taking into account
00277     // the slightly different actual glyph sizes for the different
00278     // default fonts found by cairo and qt).
00279     currentFontSize  = chrht * POINTS_PER_INCH / 25.4 * 1.45;
00280     currentFontScale = 1.;
00281     underlined       = false;
00282     overlined        = false;
00283 
00284     p.setFont( getFont( fci ) );
00285 
00286     int i = 0;
00287     while ( i < len )
00288     {
00289         if ( text[i] < PL_FCI_MARK ) // Not a font change
00290         {
00291             if ( text[i] != (PLUNICODE) plplotEsc )
00292             {
00293                 currentString.append( QString( QChar( text[i] ) ) );
00294                 ++i;
00295                 continue;
00296             }
00297             ++i; // Now analyse the escaped character
00298             switch ( text[i] )
00299             {
00300             case 'd': //subscript
00301                 drawTextInPicture( &p, currentString );
00302                 currentString.clear();
00303                 plP_script_scale( FALSE, &level,
00304                     &old_sscale, &sscale, &old_soffset, &soffset );
00305                 currentFontScale = sscale;
00306 
00307                 // The correction for the difference in magnitude
00308                 // between the baseline and middle coordinate systems
00309                 // for subscripts should be
00310                 // -0.5*(fontSize - superscript/subscript fontSize).
00311                 // dyOffset = -0.5 * currentFontSize * ( 1.0 - sscale );
00312                 // But empirically this change in offset should not be applied
00313                 // so leave it at its initial value of zero.
00314                 yOffset = empirical_yOffset - ( currentFontSize * RISE_FACTOR * soffset + dyOffset );
00315 
00316                 p.setFont( getFont( fci ) );
00317                 break;
00318 
00319             case 'u':  //superscript
00320                 drawTextInPicture( &p, currentString );
00321 
00322                 currentString.clear();
00323                 plP_script_scale( TRUE, &level,
00324                     &old_sscale, &sscale, &old_soffset, &soffset );
00325                 currentFontScale = sscale;
00326 
00327                 // The correction for the difference in magnitude
00328                 // between the baseline and middle coordinate systems
00329                 // for superscripts should be
00330                 // 0.5*(fontSize - superscript/subscript fontSize).
00331                 // dyOffset = 0.5 * currentFontSize * ( 1.0 - sscale );
00332                 // But empirically this change in offset should not be applied
00333                 // so leave it at its initial value of zero.
00334                 yOffset = empirical_yOffset + currentFontSize * RISE_FACTOR * soffset + dyOffset;
00335 
00336                 p.setFont( getFont( fci ) );
00337                 break;
00338 
00339             case '-':
00340                 drawTextInPicture( &p, currentString );
00341 
00342                 currentString.clear();
00343                 underlined = !underlined;
00344                 p.setFont( getFont( fci ) );
00345                 break;
00346 
00347             case '+':
00348                 drawTextInPicture( &p, currentString );
00349 
00350                 currentString.clear();
00351                 overlined = !overlined;
00352                 p.setFont( getFont( fci ) );
00353                 break;
00354 
00355 
00356             case '#':
00357                 currentString.append( QString( (QChar *) &( text[i] ), 1 ) );
00358                 break;
00359 
00360             default:
00361                 std::cout << "unknown escape char " << ( (QChar) text[i] ).toLatin1() << std::endl;
00362                 break;
00363             }
00364         }
00365         else // Font change
00366         {
00367             drawTextInPicture( &p, currentString );
00368 
00369             currentString.clear();
00370             fci = text[i];
00371             p.setFont( getFont( fci ) );
00372         }
00373         ++i;
00374     }
00375     drawTextInPicture( &p, currentString );
00376 
00377     p.end();
00378 
00379     return res;
00380 }
00381 
00382 void QtPLDriver::drawText( EscText* txt )
00383 {
00384     if ( !m_painterP->isActive() )
00385         return;
00386 
00387     // Check that we got unicode, warning message and return if not
00388     if ( txt->unicode_array_len == 0 )
00389     {
00390         printf( "Non unicode string passed to a Qt driver, ignoring\n" );
00391         return;
00392     }
00393 
00394     // Check that unicode string isn't longer then the max we allow
00395     if ( txt->unicode_array_len >= 500 )
00396     {
00397         printf( "Sorry, the Qt drivers only handle strings of length < %d\n", 500 );
00398         return;
00399     }
00400 
00401     PLFLT rotation, shear, stride;
00402     plRotationShear( txt->xform, &rotation, &shear, &stride );
00403 
00404     double    picDpi;
00405     PLUNICODE fci;
00406     plgfci( &fci );
00407     QPicture  picText = getTextPicture( fci, txt->unicode_array, txt->unicode_array_len, pls->chrht );
00408     picDpi = picText.logicalDpiY();
00409 
00410     if ( pls->get_string_length )
00411     {
00412         pls->string_length = ( (PLFLT) xOffset / picDpi ) * 25.4;
00413         return;
00414     }
00415 
00416     m_painterP->setClipping( true );
00417     m_painterP->setClipRect( QRect( (int) ( pls->clpxmi * downscale ), (int) ( m_dHeight - pls->clpyma * downscale ), (int) ( ( pls->clpxma - pls->clpxmi ) * downscale ), (int) ( ( pls->clpyma - pls->clpymi ) * downscale ) ), Qt::ReplaceClip );
00418 
00419     rotation -= pls->diorot * M_PI / 2.0;
00420     m_painterP->translate( txt->x * downscale, m_dHeight - txt->y * downscale );
00421     QMatrix rotShearMatrix( cos( rotation ) * stride, -sin( rotation ) * stride, cos( rotation ) * sin( shear ) + sin( rotation ) * cos( shear ), -sin( rotation ) * sin( shear ) + cos( rotation ) * cos( shear ), 0., 0. );
00422 
00423     m_painterP->setWorldMatrix( rotShearMatrix, true );
00424 
00425     m_painterP->translate( -txt->just * xOffset * m_painterP->device()->logicalDpiY() / picDpi, 0. );
00426 
00427     m_painterP->drawPicture( 0, 0, picText );
00428 
00429     m_painterP->resetTransform();;
00430     m_painterP->setClipping( false );
00431 }
00432 
00433 void QtPLDriver::setColor( int r, int g, int b, double alpha )
00434 {
00435     if ( !m_painterP->isActive() )
00436         return;
00437 
00438     QPen p = m_painterP->pen();
00439     p.setColor( QColor( r, g, b, (int) ( alpha * 255 ) ) );
00440     m_painterP->setPen( p );
00441 
00442     QBrush B = m_painterP->brush();
00443     B.setColor( QColor( r, g, b, (int) ( alpha * 255 ) ) );
00444     B.setStyle( Qt::SolidPattern );
00445     m_painterP->setBrush( B );
00446 }
00447 
00448 void QtPLDriver::setGradient( int x1, int x2, int y1, int y2,
00449                               unsigned char *r, unsigned char *g,
00450                               unsigned char *b, PLFLT *alpha, PLINT ncol1 )
00451 {
00452     if ( !m_painterP->isActive() || ncol1 < 2 )
00453         return;
00454 
00455     int             i;
00456     qreal           stop_arg;
00457     QLinearGradient linear_gradient;
00458     QGradientStops  stops;
00459 
00460     linear_gradient = QLinearGradient(
00461         QPointF( (qreal) ( x1 * downscale ), (qreal) ( m_dHeight - y1 * downscale ) ),
00462         QPointF( (qreal) ( x2 * downscale ), (qreal) ( m_dHeight - y2 * downscale ) ) );
00463 
00464     for ( i = 0; i < ncol1; i++ )
00465     {
00466         stop_arg = (qreal) i / (qreal) ( ncol1 - 1 );
00467         stops << QGradientStop( stop_arg, QColor( r[i], g[i],
00468                 b[i], (int) ( alpha[i] * 255 ) ) );
00469     }
00470     linear_gradient.setStops( stops );
00471     m_painterP->setBrush( linear_gradient );
00472 }
00473 
00474 void QtPLDriver::setWidthF( PLFLT w )
00475 {
00476     if ( !m_painterP->isActive() )
00477         return;
00478 
00479     QPen p = m_painterP->pen();
00480     p.setWidthF( w );
00481     m_painterP->setPen( p );
00482 }
00483 
00484 // void QtPLDriver::setDashed(PLINT nms, PLINT* mark, PLINT* space)
00485 // {
00486 //     if(!m_painterP->isActive()) return;
00487 //
00488 //     QVector<qreal> vect;
00489 //     for(int i=0; i<nms; ++i)
00490 //     {
00491 //         vect << (PLFLT)mark[i]*m_painterP->device()->logicalDpiX()/25400.;
00492 //         vect << (PLFLT)space[i]*m_painterP->device()->logicalDpiX()/25400.;
00493 //     }
00494 //     QPen p=m_painterP->pen();
00495 //     p.setDashPattern(vect);
00496 //     m_painterP->setPen(p);
00497 // }
00498 
00499 void QtPLDriver::setSolid()
00500 {
00501     if ( !m_painterP->isActive() )
00502         return;
00503 
00504     QPen p = m_painterP->pen();
00505     p.setStyle( Qt::SolidLine );
00506     m_painterP->setPen( p );
00507 }
00508 
00510 #if defined ( PLD_bmpqt ) || defined ( PLD_jpgqt ) || defined ( PLD_pngqt ) || defined ( PLD_ppmqt ) || defined ( PLD_tiffqt )
00511 QtRasterDevice::QtRasterDevice( int i_iWidth, int i_iHeight ) :
00512     QtPLDriver( i_iWidth, i_iHeight ),
00513     QImage( i_iWidth, i_iHeight, QImage::Format_RGB32 )
00514 {
00515     // Painter initialised in the constructor contrary
00516     // to buffered drivers, which paint only in doPlot().
00517     m_painterP = new QPainter( this );
00518     QBrush b = m_painterP->brush();
00519     b.setStyle( Qt::SolidPattern );
00520     m_painterP->setBrush( b );
00521     m_painterP->setRenderHint( QPainter::Antialiasing, (bool) lines_aa );
00522 }
00523 
00524 QtRasterDevice::~QtRasterDevice()
00525 {
00526     delete m_painterP;
00527 }
00528 
00529 void QtRasterDevice::definePlotName( const char* fileName, const char* format )
00530 {
00531     // Avoid buffer overflows
00532     strncpy( this->format, format, 4 );
00533     this->format[4] = '\0';
00534 
00535     this->fileName = QString( fileName );
00536 }
00537 
00538 void QtRasterDevice::savePlot()
00539 {
00540     m_painterP->end();
00541     save( fileName, format, 85 );
00542 
00543     m_painterP->begin( this );
00544     m_painterP->setRenderHint( QPainter::Antialiasing, (bool) lines_aa );
00545     QBrush b = m_painterP->brush();
00546     b.setStyle( Qt::SolidPattern );
00547     m_painterP->setBrush( b );
00548 }
00549 
00550 void QtRasterDevice::setBackgroundColor( int r, int g, int b, double alpha )
00551 {
00552     if ( !m_painterP->isActive() )
00553         return;
00554 
00555     QBrush brush( QColor( r, g, b, (int) ( alpha * 255 ) ) );
00556     m_painterP->fillRect( 0, 0, width(), height(), brush );
00557 }
00558 #endif
00559 
00560 #if defined ( PLD_svgqt ) && QT_VERSION >= 0x040300
00561 QtSVGDevice::QtSVGDevice( int i_iWidth, int i_iHeight ) :
00562     QtPLDriver( i_iWidth, i_iHeight )
00563 {
00564     m_painterP = NULL;
00565 }
00566 
00567 QtSVGDevice::~QtSVGDevice()
00568 {
00569     delete m_painterP;
00570 }
00571 
00572 void QtSVGDevice::definePlotName( const char* fileName )
00573 {
00574     setFileName( QString( fileName ) );
00575     setResolution( POINTS_PER_INCH );
00576     setSize( QSize( (int) m_dWidth, (int) m_dHeight ) );
00577 #if QT_VERSION >= 0x040500
00578     setViewBox( QRect( 0, 0, (int) m_dWidth, (int) m_dHeight ) );
00579 #endif
00580 
00581     m_painterP = new QPainter( this );
00582 }
00583 
00584 void QtSVGDevice::savePlot()
00585 {
00586     m_painterP->end();
00587 }
00588 
00589 void QtSVGDevice::setBackgroundColor( int r, int g, int b, double alpha )
00590 {
00591     if ( !m_painterP->isActive() )
00592         return;
00593 
00594     QBrush brush( QColor( r, g, b, (int) ( alpha * 255 ) ) );
00595     m_painterP->fillRect( 0, 0, width(), height(), brush );
00596 }
00597 #endif
00598 
00599 #if defined ( PLD_epsqt ) || defined ( PLD_pdfqt )
00600 QtEPSDevice::QtEPSDevice( int i_iWidth, int i_iHeight )
00601 {
00602 #if QT_VERSION < 0x040400
00603     setPageSize( QPrinter::A4 );
00604 #else
00605     setFullPage( true );
00606     setPaperSize( QSizeF( i_iHeight, i_iWidth ), QPrinter::Point );
00607 #endif
00608     setResolution( POINTS_PER_INCH );
00609     setColorMode( QPrinter::Color );
00610     setOrientation( QPrinter::Landscape );
00611     setPrintProgram( QString( "lpr" ) );
00612 
00613     if ( i_iWidth <= 0 || i_iHeight <= 0 )
00614     {
00615         m_dWidth  = pageRect().width();
00616         m_dHeight = pageRect().height();
00617     }
00618     else
00619     {
00620         m_dWidth  = i_iWidth;
00621         m_dHeight = i_iHeight;
00622     }
00623     m_painterP = NULL;
00624 }
00625 
00626 QtEPSDevice::~QtEPSDevice()
00627 {
00628     delete m_painterP;
00629 }
00630 
00631 void QtEPSDevice::definePlotName( const char* fileName, int ifeps )
00632 {
00633     setOutputFileName( QString( fileName ) );
00634     if ( ifeps )
00635     {
00636 #ifndef PLPLOT_USE_QT5
00637         setOutputFormat( QPrinter::PostScriptFormat );
00638 #endif
00639     }
00640     else
00641     {
00642         setOutputFormat( QPrinter::PdfFormat );
00643     }
00644 
00645     m_painterP = new QPainter( this );
00646 }
00647 
00648 void QtEPSDevice::savePlot()
00649 {
00650     m_painterP->end();
00651 }
00652 
00653 void QtEPSDevice::setBackgroundColor( int r, int g, int b, double alpha )
00654 {
00655     if ( !m_painterP->isActive() )
00656         return;
00657 
00658     QBrush brush( QColor( r, g, b, (int) ( alpha * 255 ) ) );
00659     m_painterP->fillRect( 0, 0, width(), height(), brush );
00660 }
00661 #endif
00662 
00663 #if defined ( PLD_qtwidget ) || defined ( PLD_extqt )
00664 QtPLWidget::QtPLWidget( int i_iWidth, int i_iHeight, QWidget* parent ) :
00665     QWidget( parent ), QtPLDriver( i_iWidth, i_iHeight )
00666 {
00667     m_painterP = new QPainter;
00668 
00669     m_dAspectRatio = m_dWidth / m_dHeight;
00670 
00671     m_pixPixmap = NULL;
00672 //     m_iOldSize=0;
00673     pageNumber = 0;
00674     resize( i_iWidth, i_iHeight );
00675     lastColour.r = -1;
00676     setVisible( true );
00677     // Dropping this appears to give more reliable results
00678     // (QColor::setRgb: RGB parameters out of range warnings go away)
00679     // according to Jonathan Woithe <jwoithe@just42.net> and according
00680     // to my own tests does not affect results from the
00681     // test_interactive target.
00682     // QApplication::processEvents();
00683     redrawFromLastFlush = false;
00684     redrawAll           = true;
00685 
00686     NoPen = QPen( Qt::NoPen );
00687     NoPen.setWidthF( 0. );
00688 
00689     locate_mode = 0;
00690 }
00691 
00692 QtPLWidget::~QtPLWidget()
00693 {
00694     clearBuffer();
00695     delete m_pixPixmap;
00696 }
00697 
00698 void QtPLWidget::clearWidget()
00699 {
00700     clearBuffer();
00701     setBackgroundColor( bgColour.r, bgColour.g, bgColour.b, bgColour.alpha );
00702     redrawAll = true;
00703 //     m_bAwaitingRedraw=true;
00704     update();
00705 }
00706 
00707 void QtPLWidget::flush()
00708 {
00709     repaint();
00710     QApplication::processEvents();
00711 }
00712 
00713 void QtPLWidget::clearBuffer()
00714 {
00715     lastColour.r = -1;
00716     for ( QLinkedList<BufferElement>::iterator i = m_listBuffer.begin(); i != m_listBuffer.end(); ++i )
00717     {
00718         switch ( i->Element )
00719         {
00720         case LINE:
00721             delete i->Data.Line;
00722             break;
00723         case RECTANGLE:
00724             delete i->Data.Rect;
00725             break;
00726 
00727         case POLYLINE:
00728         case POLYGON:
00729             delete i->Data.Polyline;
00730             break;
00731 
00732         case TEXT:
00733             delete[] i->Data.TextStruct->text;
00734             delete i->Data.TextStruct;
00735             break;
00736 
00737         case SET_COLOUR:
00738         case SET_BG_COLOUR:
00739             delete i->Data.ColourStruct;
00740             break;
00741 
00742         case SET_GRADIENT:
00743             delete i->Data.LinearGradient;
00744             break;
00745 
00746         case ARC:
00747             delete i->Data.ArcStruct->rect;
00748             delete i->Data.ArcStruct->dx;
00749             delete i->Data.ArcStruct;
00750 
00751         default:
00752             break;
00753         }
00754     }
00755 
00756     m_listBuffer.clear();
00757     start_iterator = m_listBuffer.constBegin();
00758     redrawAll      = true;
00759 }
00760 
00761 
00762 void QtPLWidget::drawArc( short x, short y, short a, short b, PLFLT angle1, PLFLT angle2, PLFLT rotate, bool fill )
00763 {
00764     BufferElement el;
00765     el.Element              = ARC;
00766     el.Data.ArcStruct       = new struct ArcStruct_;
00767     el.Data.ArcStruct->rect = new QRectF( (PLFLT) ( x - a ) * downscale,
00768         m_dHeight - (PLFLT) ( y + b ) * downscale,
00769         (PLFLT) a * downscale * 2,
00770         (PLFLT) b * downscale * 2
00771         );
00772     el.Data.ArcStruct->startAngle = (int) ( angle1 * 16 );
00773     el.Data.ArcStruct->spanAngle  = (int) ( ( angle2 - angle1 ) * 16 );
00774     el.Data.ArcStruct->rotate     = rotate;
00775     el.Data.ArcStruct->dx         = new QPointF( (PLFLT) x * downscale, m_dHeight - (PLFLT) y * downscale );
00776     el.Data.ArcStruct->fill       = fill;
00777 
00778     m_listBuffer.append( el );
00779     redrawFromLastFlush = true;
00780 }
00781 
00782 
00783 void QtPLWidget::drawLine( short x1, short y1, short x2, short y2 )
00784 {
00785     BufferElement el;
00786     el.Element   = LINE;
00787     el.Data.Line = new QLineF( QPointF( (PLFLT) x1 * downscale, (PLFLT) ( m_dHeight - y1 * downscale ) ), QPointF( (PLFLT) x2 * downscale, (PLFLT) ( m_dHeight - y2 * downscale ) ) );
00788 
00789     m_listBuffer.append( el );
00790     redrawFromLastFlush = true;
00791 }
00792 
00793 void QtPLWidget::drawPolyline( short * x, short * y, PLINT npts )
00794 {
00795     BufferElement el;
00796     el.Element       = POLYLINE;
00797     el.Data.Polyline = new QPolygonF;
00798     for ( int i = 0; i < npts; ++i )
00799     {
00800         ( *el.Data.Polyline ) << QPointF( (PLFLT) ( x[i] ) * downscale, (PLFLT) ( m_dHeight - ( y[i] ) * downscale ) );
00801     }
00802 
00803     m_listBuffer.append( el );
00804     redrawFromLastFlush = true;
00805 }
00806 
00807 void QtPLWidget::drawPolygon( short * x, short * y, PLINT npts )
00808 {
00809     BufferElement el;
00810 
00811     bool          isRect = false;
00812     if ( npts == 4 ) // Check if it's a rectangle. If so, it can be made faster to display
00813     {
00814         if ( x[0] == x[1] && x[2] == x[3] && y[0] == y[3] && y[1] == y[2] )
00815         {
00816             isRect = true;
00817         }
00818         else if ( x[0] == x[3] && x[1] == x[2] && y[0] == y[1] && y[2] == y[3] )
00819         {
00820             isRect = true;
00821         }
00822     }
00823     if ( npts == 5 )
00824     {
00825         if ( x[0] == x[4] && y[0] == y[4] )
00826         {
00827             if ( x[0] == x[1] && x[2] == x[3] && y[0] == y[3] && y[1] == y[2] )
00828             {
00829                 isRect = true;
00830             }
00831             else if ( x[0] == x[3] && x[1] == x[2] && y[0] == y[1] && y[2] == y[3] )
00832             {
00833                 isRect = true;
00834             }
00835         }
00836     }
00837 
00838     if ( isRect )
00839     {
00840         el.Element = RECTANGLE;
00841 
00842         double x1, y1, x2, y2, x0, y0, width, height;
00843         x1 = (PLFLT) ( x[0] ) * downscale;
00844         x2 = (PLFLT) ( x[2] ) * downscale;
00845         y1 = (PLFLT) ( m_dHeight - ( y[0] ) * downscale );
00846         y2 = (PLFLT) ( m_dHeight - ( y[2] ) * downscale );
00847         if ( x1 < x2 )
00848         {
00849             x0    = x1;
00850             width = x2 - x1;
00851         }
00852         else
00853         {
00854             x0    = x2;
00855             width = x1 - x2;
00856         }
00857         if ( y1 < y2 )
00858         {
00859             y0     = y1;
00860             height = y2 - y1;
00861         }
00862         else
00863         {
00864             y0     = y2;
00865             height = y1 - y2;
00866         }
00867         el.Data.Rect = new QRectF( x0, y0, width, height );
00868     }
00869     else
00870     {
00871         el.Element       = POLYGON;
00872         el.Data.Polyline = new QPolygonF;
00873         for ( int i = 0; i < npts; ++i )
00874         {
00875             ( *el.Data.Polyline ) << QPointF( (PLFLT) ( x[i] ) * downscale, (PLFLT) ( m_dHeight - ( y[i] ) * downscale ) );
00876         }
00877     }
00878 
00879     m_listBuffer.append( el );
00880     redrawFromLastFlush = true;
00881 }
00882 
00883 void QtPLWidget::setColor( int r, int g, int b, double alpha )
00884 {
00885     if ( lastColour.r != r || lastColour.g != g || lastColour.b != b || lastColour.alpha != alpha )
00886     {
00887         BufferElement el;
00888         el.Element              = SET_COLOUR;
00889         el.Data.ColourStruct    = new struct ColourStruct_;
00890         el.Data.ColourStruct->R = r;
00891         el.Data.ColourStruct->G = g;
00892         el.Data.ColourStruct->B = b;
00893         el.Data.ColourStruct->A = (PLINT) ( alpha * 255. );
00894 
00895         m_listBuffer.append( el );
00896 
00897         lastColour.r     = r;
00898         lastColour.g     = g;
00899         lastColour.b     = b;
00900         lastColour.alpha = alpha;
00901     }
00902     // No need to ask for a redraw at this point. The color only affects subsequent items
00903 //     redrawFromLastFlush=true;
00904 }
00905 
00906 void QtPLWidget::setGradient( int x1, int x2, int y1, int y2,
00907                               unsigned char *r, unsigned char *g,
00908                               unsigned char *b, PLFLT *alpha, PLINT ncol1 )
00909 {
00910     int            i;
00911     BufferElement  el;
00912     qreal          stop_arg;
00913     QGradientStops stops;
00914 
00915     el.Element = SET_GRADIENT;
00916 
00917     el.Data.LinearGradient  = new QLinearGradient;
00918     *el.Data.LinearGradient = QLinearGradient(
00919         QPointF( (qreal) ( x1 * downscale ), (qreal) ( m_dHeight - y1 * downscale ) ),
00920         QPointF( (qreal) ( x2 * downscale ), (qreal) ( m_dHeight - y2 * downscale ) ) );
00921     for ( i = 0; i < ncol1; i++ )
00922     {
00923         stop_arg = (qreal) i / (qreal) ( ncol1 - 1 );
00924         stops << QGradientStop( stop_arg, QColor( r[i], g[i],
00925                 b[i], (int) ( alpha[i] * 255 ) ) );
00926     }
00927     ( *el.Data.LinearGradient ).setStops( stops );
00928     m_listBuffer.append( el );
00929 
00930     // No need to ask for a redraw at this point. The gradient only
00931     // affects subsequent items.
00932     //redrawFromLastFlush=true;
00933 }
00934 
00935 void QtPLWidget::setBackgroundColor( int r, int g, int b, double alpha )
00936 {
00937     BufferElement el;
00938     el.Element              = SET_BG_COLOUR;
00939     el.Data.ColourStruct    = new struct ColourStruct_;
00940     el.Data.ColourStruct->R = r;
00941     el.Data.ColourStruct->G = g;
00942     el.Data.ColourStruct->B = b;
00943     el.Data.ColourStruct->A = (PLINT) ( alpha * 255. );
00944 
00945     bgColour.r     = r;
00946     bgColour.g     = g;
00947     bgColour.b     = b;
00948     bgColour.alpha = alpha;
00949     if ( alpha >= 0.999 )
00950     {
00951         clearBuffer();
00952     }
00953     m_listBuffer.append( el );
00954     redrawFromLastFlush = true;
00955 }
00956 
00957 void QtPLWidget::setWidthF( PLFLT w )
00958 {
00959     BufferElement el;
00960     el.Element       = SET_WIDTH;
00961     el.Data.fltParam = w;
00962     m_listBuffer.append( el );
00963 //     redrawFromLastFlush=true;
00964 }
00965 
00966 void QtPLWidget::drawText( EscText* txt )
00967 {
00968     if ( pls->get_string_length )
00969     {
00970         PLUNICODE fci;
00971         QPicture  picText;
00972         double    picDpi;
00973         PLUNICODE *text;
00974 
00975         plgfci( &fci );
00976         text = new PLUNICODE[txt->unicode_array_len];
00977         memcpy( text, txt->unicode_array, txt->unicode_array_len * sizeof ( PLUNICODE ) );
00978         picText = getTextPicture( fci,
00979             text,
00980             txt->unicode_array_len,
00981             pls->chrht );
00982         //
00983         // I'm assuming that y_fact is 1.0 here, as it is impossible
00984         // to know in advance (or so I believe). When the text is
00985         // rendered "for real" it will be: pls->chrht * y_fact.
00986         //
00987         // Hazen 6/2011
00988         //
00989         picDpi             = picText.logicalDpiY();
00990         pls->string_length = ( (PLFLT) xOffset / picDpi ) * 25.4;
00991         delete[] text;
00992         return;
00993     }
00994 
00995     BufferElement el;
00996 
00997     el.Element                   = TEXT;
00998     el.Data.TextStruct           = new struct TextStruct_;
00999     el.Data.TextStruct->x        = txt->x * downscale;
01000     el.Data.TextStruct->y        = m_dHeight - txt->y * downscale;
01001     el.Data.TextStruct->clipxmin = pls->clpxmi * downscale;
01002     el.Data.TextStruct->clipymin = m_dHeight - pls->clpymi * downscale;
01003     el.Data.TextStruct->clipxmax = pls->clpxma * downscale;
01004     el.Data.TextStruct->clipymax = m_dHeight - pls->clpyma * downscale;
01005     PLUNICODE fci;
01006     plgfci( &fci );
01007     el.Data.TextStruct->fci = fci;
01008     PLFLT rotation, shear, stride;
01009     plRotationShear( txt->xform, &rotation, &shear, &stride );
01010     rotation -= pls->diorot * M_PI / 2.0;
01011     el.Data.TextStruct->rotation = rotation;
01012     el.Data.TextStruct->shear    = shear;
01013     el.Data.TextStruct->stride   = stride;
01014     el.Data.TextStruct->just     = txt->just;
01015     el.Data.TextStruct->text     = new PLUNICODE[txt->unicode_array_len];
01016     memcpy( el.Data.TextStruct->text, txt->unicode_array, txt->unicode_array_len * sizeof ( PLUNICODE ) );
01017     el.Data.TextStruct->len   = txt->unicode_array_len;
01018     el.Data.TextStruct->chrht = pls->chrht;
01019 
01020     m_listBuffer.append( el );
01021     redrawFromLastFlush = true;
01022 }
01023 
01024 void QtPLWidget::renderText( QPainter* p, struct TextStruct_* s, double x_fact, double x_offset, double y_fact, double y_offset )
01025 {
01026     if ( s->len <= 0 || s->len >= 500 )
01027         return;
01028     QPicture picText = getTextPicture( s->fci, s->text, s->len, s->chrht * y_fact );
01029 
01030     double   picDpi = picText.logicalDpiY();
01031 
01032     p->setClipping( true );
01033     p->setClipRect( QRectF( s->clipxmin * x_fact + x_offset, s->clipymax * y_fact + y_offset, ( s->clipxmax - s->clipxmin ) * x_fact, ( -s->clipymax + s->clipymin ) * y_fact ), Qt::ReplaceClip );
01034     p->translate( s->x * x_fact + x_offset, s->y * y_fact + y_offset );
01035     QMatrix rotShearMatrix( cos( s->rotation ) * s->stride, -sin( s->rotation ) * s->stride, cos( s->rotation ) * sin( s->shear ) + sin( s->rotation ) * cos( s->shear ), -sin( s->rotation ) * sin( s->shear ) + cos( s->rotation ) * cos( s->shear ), 0., 0. );
01036     p->setWorldMatrix( rotShearMatrix, true );
01037 
01038     p->translate( -s->just * xOffset * p->device()->logicalDpiY() / picDpi, 0. );
01039 
01040     p->drawPicture( 0, 0, picText );
01041 
01042     p->resetTransform();
01043 
01044     p->setClipping( false );
01045 }
01046 
01047 void QtPLWidget::resetPensAndBrushes( QPainter* painter )
01048 {
01049     SolidPen = QPen();
01050     hasPen   = true;
01051     painter->setPen( SolidPen );
01052     SolidBrush = QBrush( Qt::SolidPattern );
01053 }
01054 
01055 void QtPLWidget::lookupButtonEvent( QMouseEvent * event )
01056 {
01057     Qt::MouseButtons      buttons   = event->buttons();
01058     Qt::KeyboardModifiers modifiers = event->modifiers();
01059     gin.pX = event->x();
01060     gin.pY = height() - event->y();
01061     gin.dX = (PLFLT) event->x() / width();
01062     gin.dY = (PLFLT) ( height() - event->y() ) / height();
01063 
01064     switch ( event->button() )
01065     {
01066     case Qt::LeftButton:
01067         gin.button = 1;
01068         break;
01069     case Qt::MidButton:
01070         gin.button = 2;
01071         break;
01072     case Qt::RightButton:
01073         gin.button = 3;
01074         break;
01075     default:
01076         break;
01077     }
01078 
01079     // Map Qt button and key states to the (X windows) values used
01080     // by plplot.
01081     gin.state = 0;
01082     if ( buttons & Qt::LeftButton )
01083         gin.state |= 1 << 8;
01084     if ( buttons & Qt::MidButton )
01085         gin.state |= 1 << 9;
01086     if ( buttons & Qt::RightButton )
01087         gin.state |= 1 << 10;
01088     if ( modifiers & Qt::ShiftModifier )
01089         gin.state |= 1 << 0;
01090     if ( modifiers & Qt::ControlModifier )
01091         gin.state |= 1 << 2;
01092     if ( modifiers & Qt::AltModifier )
01093         gin.state |= 1 << 3;
01094     if ( modifiers & Qt::MetaModifier )
01095         gin.state |= 1 << 3;
01096 
01097     gin.keysym = 0x20;
01098 }
01099 
01100 void QtPLWidget::locate()
01101 {
01102     if ( plTranslateCursor( &gin ) )
01103     {
01104         if ( locate_mode == 2 )
01105         {
01106             pltext();
01107             if ( gin.keysym < 0xFF && isprint( gin.keysym ) )
01108                 std::cout << gin.wX << " " << gin.wY << " " << (char) gin.keysym << std::endl;
01109             else
01110                 std::cout << gin.wX << " " << gin.wY << " " << std::hex << gin.keysym << std::endl;
01111 
01112             plgra();
01113         }
01114     }
01115     else
01116     {
01117         locate_mode = 0;
01118         QApplication::restoreOverrideCursor();
01119     }
01120 }
01121 
01122 void QtPLWidget::mouseEvent( QMouseEvent * event )
01123 {
01124     lookupButtonEvent( event );
01125 
01126     if ( locate_mode )
01127     {
01128         if ( event->button() == Qt::LeftButton )
01129         {
01130             locate();
01131         }
01132     }
01133     else
01134     {
01135         if ( event->button() == Qt::RightButton )
01136         {
01137             handler.DeviceChangedPage( this );
01138         }
01139     }
01140 }
01141 
01142 void QtPLWidget::mousePressEvent( QMouseEvent * event )
01143 {
01144     mouseEvent( event );
01145 }
01146 
01147 void QtPLWidget::mouseReleaseEvent( QMouseEvent * PL_UNUSED( event ) )
01148 {
01149     //mouseEvent( event );
01150 }
01151 
01152 void QtPLWidget::mouseMoveEvent( QMouseEvent * PL_UNUSED( event ) )
01153 {
01154     //mouseEvent( event );
01155 }
01156 
01157 void QtPLWidget::keyPressEvent( QKeyEvent* event )
01158 {
01159     if ( locate_mode )
01160     {
01161         QPoint p = QCursor::pos();
01162         gin.pX = p.x();
01163         gin.pY = height() - p.y();
01164         gin.dX = (PLFLT) p.x() / width();
01165         gin.dY = (PLFLT) ( height() - p.y() ) / height();
01166 
01167         switch ( event->key() )
01168         {
01169         case Qt::Key_Escape:
01170             locate_mode = 0;
01171             QApplication::restoreOverrideCursor();
01172             plGinInit( &gin );
01173             break;
01174         case Qt::Key_Shift:
01175         case Qt::Key_Control:
01176         case Qt::Key_Alt:
01177         case Qt::Key_Meta:
01178         case Qt::Key_AltGr:
01179             plGinInit( &gin );
01180         case Qt::Key_Left:
01181         case Qt::Key_Right:
01182         case Qt::Key_Up:
01183         case Qt::Key_Down:
01184         {
01185             int x1, y1, dx = 0, dy = 0;
01186             int xmin = 0, xmax = width() - 1, ymin = 0, ymax = height() - 1;
01187             switch ( event->key() )
01188             {
01189             case Qt::Key_Left:
01190                 dx = -1;
01191                 break;
01192             case Qt::Key_Right:
01193                 dx = 1;
01194                 break;
01195             case Qt::Key_Up:
01196                 dy = -1;
01197                 break;
01198             case Qt::Key_Down:
01199                 dy = 1;
01200                 break;
01201             }
01202             if ( event->modifiers() & Qt::ShiftModifier )
01203             {
01204                 dx *= 5;
01205                 dy *= 5;
01206             }
01207             if ( event->modifiers() & Qt::ControlModifier )
01208             {
01209                 dx *= 5;
01210                 dy *= 5;
01211             }
01212             if ( event->modifiers() & Qt::AltModifier )
01213             {
01214                 dx *= 5;
01215                 dy *= 5;
01216             }
01217             x1 = gin.pX + dx;
01218             y1 = gin.pY + dy;
01219 
01220             if ( x1 < xmin )
01221                 dx = xmin - gin.pX;
01222             if ( y1 < ymin )
01223                 dy = ymin - gin.pY;
01224             if ( x1 > xmax )
01225                 dx = xmax - gin.pX;
01226             if ( y1 > ymax )
01227                 dy = ymax - gin.pY;
01228 
01229             QCursor::setPos( p.x() + dx, p.y() + dy );
01230             plGinInit( &gin );
01231             break;
01232         }
01233         default:
01234             locate();
01235             break;
01236         }
01237     }
01238     else
01239     {
01240         if ( event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return )
01241         {
01242             handler.DeviceChangedPage( this );
01243         }
01244         if ( event->text() == "Q" )
01245         {
01246             // Terminate on a 'Q' (not 'q', since it's too easy to hit by mistake)
01247             pls->nopause = TRUE;
01248             plexit( "" );
01249         }
01250         else if ( event->text() == "L" )
01251         // Begin locate mode
01252         {
01253             locate_mode = 2;
01254             QApplication::setOverrideCursor( Qt::CrossCursor );
01255         }
01256     }
01257 }
01258 
01259 void QtPLWidget::closeEvent( QCloseEvent* event )
01260 {
01261     handler.DeviceClosed( this );
01262     event->ignore();
01263 }
01264 
01265 void QtPLWidget::nextPage()
01266 {
01267     clearWidget();
01268     pageNumber++;
01269 }
01270 
01271 void QtPLWidget::resizeEvent( QResizeEvent * )
01272 {
01273 //     m_bAwaitingRedraw=true;
01274     redrawAll = true;
01275     delete m_pixPixmap;
01276     m_pixPixmap = NULL;
01277 }
01278 
01279 void QtPLWidget::paintEvent( QPaintEvent * )
01280 {
01281     double x_fact, y_fact, x_offset( 0. ), y_offset( 0. ); //Parameters to scale and center the plot on the widget
01282 
01283     getPlotParameters( x_fact, y_fact, x_offset, y_offset );
01284 
01285     if ( redrawAll || m_pixPixmap == NULL )
01286     {
01287         if ( m_pixPixmap != NULL )
01288         {
01289             delete m_pixPixmap;
01290         }
01291         m_pixPixmap = new QPixmap( width(), height() );
01292         QPainter* painter = new QPainter;
01293         painter->begin( m_pixPixmap );
01294 
01295         // Draw the margins and the background
01296         painter->fillRect( 0, 0, width(), height(), QColor( bgColour.r, bgColour.g, bgColour.b ) );
01297 
01298         // Re-initialise pens etc.
01299         resetPensAndBrushes( painter );
01300 
01301         start_iterator = m_listBuffer.constBegin();
01302 
01303         // Draw the plot
01304         doPlot( painter, x_fact, y_fact, x_offset, y_offset );
01305         painter->end();
01306 
01307 //             m_iOldSize=m_listBuffer.size();
01308 
01309         delete painter;
01310     }
01311     else
01312     {
01313         QPainter* painter = new QPainter;
01314         painter->begin( m_pixPixmap );
01315         if ( hasPen )
01316             painter->setPen( SolidPen );
01317         else
01318             painter->setPen( NoPen );
01319 
01320         // Draw the plot
01321         doPlot( painter, x_fact, y_fact, x_offset, y_offset );
01322         painter->end();
01323     }
01324 
01325     // draw the current pixmap
01326     m_painterP->begin( this );
01327 
01328     m_painterP->drawPixmap( 0, 0, *m_pixPixmap );
01329 
01330     m_painterP->end();
01331 }
01332 
01333 void QtPLWidget::doPlot( QPainter* p, double x_fact, double y_fact, double x_offset, double y_offset )
01334 {
01335     QLineF         line;
01336     QVector<qreal> vect;
01337     QRectF         rect;
01338 
01339 
01340 //     QPen SolidPen;
01341 //
01342 //     QPen NoPen(Qt::NoPen);
01343 //     NoPen.setWidthF(0.); // Cosmetic pen
01344 //     p->setPen(SolidPen);
01345 //     bool hasPen=true;
01346 
01347     p->setRenderHints( QPainter::Antialiasing, (bool) lines_aa );
01348 
01349 //     QBrush SolidBrush(Qt::SolidPattern);
01350     p->setBrush( SolidBrush );
01351 
01352     QTransform trans;
01353     trans = trans.translate( x_offset, y_offset );
01354     trans = trans.scale( x_fact, y_fact );
01355 
01356     p->setTransform( trans );
01357 
01358     if ( m_listBuffer.empty() )
01359     {
01360         p->fillRect( 0, 0, 1, 1, QBrush() );
01361         return;
01362     }
01363 
01364     // unrolls the buffer and draws each element accordingly
01365     for ( QLinkedList<BufferElement>::const_iterator i = start_iterator; i != m_listBuffer.constEnd(); ++i )
01366     {
01367         switch ( i->Element )
01368         {
01369         case SET_COLOUR:
01370             SolidPen.setColor( QColor( i->Data.ColourStruct->R, i->Data.ColourStruct->G, i->Data.ColourStruct->B, i->Data.ColourStruct->A ) );
01371             if ( hasPen )
01372             {
01373                 p->setPen( SolidPen );
01374             }
01375             SolidBrush.setColor( QColor( i->Data.ColourStruct->R, i->Data.ColourStruct->G, i->Data.ColourStruct->B, i->Data.ColourStruct->A ) );
01376             p->setBrush( SolidBrush );
01377             break;
01378 
01379         case SET_GRADIENT:
01380             p->setBrush( *( i->Data.LinearGradient ) );
01381             break;
01382 
01383         case LINE:
01384             if ( !hasPen )
01385             {
01386                 p->setPen( SolidPen );
01387                 hasPen = true;
01388             }
01389             p->drawLine( *( i->Data.Line ) );
01390 
01391             break;
01392 
01393         case POLYLINE:
01394             if ( !hasPen )
01395             {
01396                 p->setPen( SolidPen );
01397                 hasPen = true;
01398             }
01399             p->drawPolyline( *( i->Data.Polyline ) );
01400             break;
01401 
01402         case RECTANGLE:
01403             p->setRenderHints( QPainter::Antialiasing, false );
01404             if ( hasPen )
01405             {
01406                 p->setPen( NoPen );
01407                 hasPen = false;
01408             }
01409             p->drawRect( *( i->Data.Rect ) );
01410             p->setRenderHints( QPainter::Antialiasing, (bool) lines_aa );
01411             break;
01412 
01413         case POLYGON:
01414             p->setRenderHints( QPainter::Antialiasing, false );
01415             if ( hasPen )
01416             {
01417                 p->setPen( NoPen );
01418                 hasPen = false;
01419             }
01420             if ( plsc->dev_eofill )
01421                 p->drawPolygon( *( i->Data.Polyline ), Qt::OddEvenFill );
01422             else
01423                 p->drawPolygon( *( i->Data.Polyline ), Qt::WindingFill );
01424             p->setRenderHints( QPainter::Antialiasing, (bool) lines_aa );
01425             break;
01426 
01427         case TEXT:
01428             if ( !hasPen )
01429             {
01430                 p->setPen( SolidPen );
01431                 hasPen = true;
01432             }
01433             p->save();
01434             p->resetTransform();
01435 
01436             renderText( p, i->Data.TextStruct, x_fact, x_offset, y_fact, y_offset );
01437             p->restore();
01438             break;
01439 
01440         case SET_WIDTH:
01441             SolidPen.setWidthF( i->Data.fltParam );
01442             if ( hasPen )
01443             {
01444                 p->setPen( SolidPen );
01445             }
01446             break;
01447 
01448         case SET_BG_COLOUR:
01449             SolidBrush.setColor( QColor( i->Data.ColourStruct->R, i->Data.ColourStruct->G, i->Data.ColourStruct->B, i->Data.ColourStruct->A ) );
01450             p->fillRect( 0, 0, (int) m_dWidth, (int) m_dHeight, SolidBrush );
01451             break;
01452 
01453         case ARC:
01454             if ( !hasPen )
01455             {
01456                 p->setPen( SolidPen );
01457                 hasPen = true;
01458             }
01459             if ( i->Data.ArcStruct->rotate != 0.0 )
01460             {
01461                 p->save();
01462                 p->translate( *( i->Data.ArcStruct->dx ) );
01463                 p->rotate( -i->Data.ArcStruct->rotate );
01464                 p->translate( -*( i->Data.ArcStruct->dx ) );
01465             }
01466 
01467             if ( i->Data.ArcStruct->fill )
01468                 p->drawPie( *( i->Data.ArcStruct->rect ), i->Data.ArcStruct->startAngle, i->Data.ArcStruct->spanAngle );
01469             else
01470                 p->drawArc( *( i->Data.ArcStruct->rect ), i->Data.ArcStruct->startAngle, i->Data.ArcStruct->spanAngle );
01471 
01472             if ( i->Data.ArcStruct->rotate != 0.0 )
01473             {
01474                 p->restore();
01475             }
01476 
01477             break;
01478         default:
01479             break;
01480         }
01481     }
01482 
01483     start_iterator = m_listBuffer.constEnd();
01484     --start_iterator;
01485     redrawFromLastFlush = false;
01486     redrawAll           = false;
01487 }
01488 
01489 void QtPLWidget::getPlotParameters( double & io_dXFact, double & io_dYFact, double & io_dXOffset, double & io_dYOffset )
01490 {
01491     double w = (double) width();
01492     double h = (double) height();
01493     if ( w / h > m_dAspectRatio ) //Too wide, h is the limitating factor
01494     {
01495         io_dYFact   = h / m_dHeight;
01496         io_dXFact   = h * m_dAspectRatio / m_dWidth;
01497         io_dYOffset = 0.;
01498         io_dXOffset = ( w - io_dXFact * m_dWidth ) / 2.;
01499     }
01500     else
01501     {
01502         io_dXFact   = w / m_dWidth;
01503         io_dYFact   = w / m_dAspectRatio / m_dHeight;
01504         io_dXOffset = 0.;
01505         io_dYOffset = ( h - io_dYFact * m_dHeight ) / 2.;
01506     }
01507 }
01508 
01509 void QtPLWidget::getCursorCmd( PLGraphicsIn *ptr )
01510 {
01511     plGinInit( &gin );
01512 
01513     locate_mode = 1;
01514     QApplication::setOverrideCursor( Qt::CrossCursor );
01515 
01516     while ( gin.pX < 0 && locate_mode )
01517         QCoreApplication::processEvents( QEventLoop::AllEvents, 10 );
01518 
01519     QApplication::restoreOverrideCursor();
01520     *ptr = gin;
01521 }
01522 
01523 #endif
01524 
01525 #if defined ( PLD_extqt )
01526 QtExtWidget::QtExtWidget( int i_iWidth, int i_iHeight, QWidget* parent ) :
01527     QtPLWidget( i_iWidth, i_iHeight, parent )
01528 {
01529     cursorParameters.isTracking = false;
01530     cursorParameters.cursor_x   = -1.0;
01531     cursorParameters.cursor_y   = -1.0;
01532     killed = false;
01533 }
01534 
01535 QtExtWidget::~QtExtWidget()
01536 {
01537     killed = true;
01538     QCoreApplication::processEvents( QEventLoop::AllEvents, 10 );
01539     delete m_pixPixmap;
01540     delete m_painterP;
01541     m_pixPixmap = NULL;
01542     m_painterP  = NULL;
01543 }
01544 
01545 void QtExtWidget::captureMousePlotCoords( PLFLT* x, PLFLT* y )
01546 {
01547     setMouseTracking( true );
01548     cursorParameters.isTracking   = true;
01549     cursorParameters.cursor_x     =
01550         cursorParameters.cursor_y = -1.;
01551     do
01552     {
01553         QCoreApplication::processEvents( QEventLoop::AllEvents, 10 );
01554     } while ( cursorParameters.isTracking && !killed );
01555 
01556     *x = cursorParameters.cursor_x;
01557     *y = cursorParameters.cursor_y;
01558 }
01559 
01560 void QtExtWidget::mouseMoveEvent( QMouseEvent* event )
01561 {
01562     if ( !cursorParameters.isTracking )
01563         return;
01564 
01565     double x_fact, y_fact, x_offset, y_offset; //Parameters to scale and center the plot on the widget
01566 
01567     getPlotParameters( x_fact, y_fact, x_offset, y_offset );
01568 
01569     cursorParameters.cursor_x = (PLFLT) event->x();
01570     cursorParameters.cursor_y = (PLFLT) event->y();
01571 
01572     double ratio_x;
01573     double ratio_y;
01574     ratio_x = ( cursorParameters.cursor_x - x_offset ) / ( width() - 2. * x_offset );
01575     ratio_y = ( cursorParameters.cursor_y - y_offset ) / ( height() - 2. * y_offset );
01576 
01577     PLFLT a, b;
01578     PLINT c;
01579     plcalc_world( ratio_x, 1. - ratio_y, &a, &b, &c );
01580 
01581     if ( c < 0 )
01582     {
01583         cursorParameters.cursor_x = -1.;
01584         cursorParameters.cursor_y = -1.;
01585     }
01586 
01587     update();
01588 }
01589 
01590 void QtExtWidget::mousePressEvent( QMouseEvent*  /* event */ )
01591 {
01592 }
01593 
01594 void QtExtWidget::mouseReleaseEvent( QMouseEvent* event )
01595 {
01596     if ( !cursorParameters.isTracking )
01597         return;
01598 
01599     double x_fact, y_fact, x_offset, y_offset; //Parameters to scale and center the plot on the widget
01600 
01601     getPlotParameters( x_fact, y_fact, x_offset, y_offset );
01602 
01603     cursorParameters.cursor_x   = (PLFLT) event->x();
01604     cursorParameters.cursor_y   = (PLFLT) event->y();
01605     cursorParameters.isTracking = false;
01606     setMouseTracking( false );
01607 
01608     double ratio_x;
01609     double ratio_y;
01610     ratio_x = ( cursorParameters.cursor_x - x_offset ) / ( width() - 2. * x_offset );
01611     ratio_y = ( cursorParameters.cursor_y - y_offset ) / ( height() - 2. * y_offset );
01612 
01613     PLFLT a, b;
01614     PLINT c;
01615     plcalc_world( ratio_x, 1. - ratio_y, &a, &b, &c );
01616 
01617     if ( c < 0 )
01618     {
01619         cursorParameters.cursor_x = -1.;
01620         cursorParameters.cursor_y = -1.;
01621     }
01622     else
01623     {
01624         cursorParameters.cursor_x = a;
01625         cursorParameters.cursor_y = b;
01626     }
01627 
01628     update();
01629 }
01630 
01631 void QtExtWidget::paintEvent( QPaintEvent* event )
01632 {
01633     QtPLWidget::paintEvent( event );
01634 
01635     if ( !cursorParameters.isTracking || cursorParameters.cursor_x < 0 )
01636         return;
01637 
01638     QPainter p( this );
01639 
01640     p.setPen( QPen( Qt::white ) );
01641 
01642     p.drawLine( (int) cursorParameters.cursor_x, 0, (int) cursorParameters.cursor_x, height() );
01643     p.drawLine( 0, (int) cursorParameters.cursor_y, width(), (int) cursorParameters.cursor_y );
01644 
01645     p.end();
01646 }
01647 
01648 void plsetqtdev( QtExtWidget* widget )
01649 {
01650     plsc->dev = (void *) widget;
01651     widget->setPLStream( plsc );
01652 }
01653 
01654 void plsetqtdev( QtExtWidget* widget, int argc, char** argv )
01655 {
01656     plparseopts( &argc, (const char **) argv, PL_PARSE_FULL );
01657     plsc->dev = (void *) widget;
01658     widget->setPLStream( plsc );
01659 }
01660 
01661 void plfreeqtdev()
01662 {
01663     delete ( (QtExtWidget *) plsc->dev );
01664     plsc->dev = NULL;
01665 }
01666 #endif
01667 
01668 #include "moc_files.h"
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines