PLplot
5.10.0
|
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"