PLplot: plqt.cpp Source File

PLplot 5.15.0

plqt.cpp
Go to the documentation of this file.
1 // This software was donated under the LGPL to the PLplot project in
2 // March 2009 by the
3 // Cluster Science Centre
4 // QSAS team,
5 // Imperial College, London
6 //
7 // Copyright (C) 2009 Imperial College, London
8 // Copyright (C) 2009-2019 Alan W. Irwin
9 //
10 // This is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Lesser Public License as published
12 // by the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // This software is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // To received a copy of the GNU Library General Public License
21 // write to the Free Software Foundation, Inc.,
22 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24
25 #include "qt.h"
26
27 // Global variables for Qt driver.
28 PLDLLIMPEXP_QT_DATA( int ) vectorize = 0;
29 PLDLLIMPEXP_QT_DATA( int ) lines_aa = 1;
30 PLDLLIMPEXP_QT_DATA( MasterHandler ) handler;
31
32 // Master Device Handler for multiple streams
33 // Only handles multiple Qt devices
34 MasterHandler::MasterHandler() : QObject()
35 {
36 masterDevice = NULL;
37 }
38
39 bool MasterHandler::isMasterDevice( QtPLDriver* d )
40 {
41 return d == masterDevice;
42 }
43
44 void MasterHandler::setMasterDevice( QtPLDriver* d )
45 {
46 masterDevice = d;
47 }
48
49 void MasterHandler::DeviceChangedPage( QtPLDriver* d )
50 {
51 if ( d == masterDevice )
52 {
53 emit MasterChangedPage();
54 }
55 }
56
57 void MasterHandler::DeviceClosed( QtPLDriver* d )
58 {
59 if ( d == masterDevice )
60 {
61 emit MasterClosed();
62 masterDevice = NULL;
63 }
64 }
65
67 QMutex QtPLDriver::mutex;
68
69 QtPLDriver::QtPLDriver( PLINT i_iWidth, PLINT i_iHeight )
70 {
71 m_dWidth = i_iWidth;
72 m_dHeight = i_iHeight;
73 }
74
75 QtPLDriver::~QtPLDriver()
76 {
77 }
78
79 void QtPLDriver::setPLStream( PLStream *p )
80 {
81 pls = p;
82 }
83
84 void QtPLDriver::drawArc( short x, short y, short a, short b, PLFLT angle1, PLFLT angle2, PLFLT rotate, bool fill )
85 {
86 if ( !m_painterP->isActive() )
87 return;
88 QRectF rect( (PLFLT) ( x - a ) * downscale,
89 m_dHeight - (PLFLT) ( y + b ) * downscale,
90 (PLFLT) a * downscale * 2,
91 (PLFLT) b * downscale * 2
92 );
93 if ( rotate != 0.0 )
94 {
95 m_painterP->save();
96 m_painterP->translate( (PLFLT) x * downscale, m_dHeight - (PLFLT) y * downscale );
97 m_painterP->rotate( -rotate );
98 m_painterP->translate( -(PLFLT) x * downscale, -m_dHeight + (PLFLT) y * downscale );
99 }
100
101 if ( fill )
102 m_painterP->drawPie( rect, (int) ( angle1 * 16 ), (int) ( ( angle2 - angle1 ) * 16 ) );
103 else
104 m_painterP->drawArc( rect, (int) ( angle1 * 16 ), (int) ( ( angle2 - angle1 ) * 16 ) );
105
106 if ( rotate != 0.0 )
107 {
108 m_painterP->restore();
109 }
110 }
111
112 void QtPLDriver::drawLine( short x1, short y1, short x2, short y2 )
113 {
114 if ( !m_painterP->isActive() )
115 return;
116 QLineF line( (PLFLT) x1 * downscale,
117 m_dHeight - (PLFLT) y1 * downscale,
118 (PLFLT) x2 * downscale,
119 m_dHeight - (PLFLT) y2 * downscale
120 );
121
122 m_painterP->drawLine( line );
123 }
124
125 void QtPLDriver::drawPolyline( short * x, short * y, PLINT npts )
126 {
127 if ( !m_painterP->isActive() )
128 return;
129 QPointF * polyline = new QPointF[npts];
130 for ( int i = 0; i < npts; ++i )
131 {
132 polyline[i].setX( (PLFLT) x[i] * downscale );
133 polyline[i].setY( m_dHeight - (PLFLT) y[i] * downscale );
134 }
135 m_painterP->drawPolyline( polyline, npts );
136 delete[] polyline;
137 }
138
139 void QtPLDriver::drawPolygon( short * x, short * y, PLINT npts )
140 {
141 if ( !m_painterP->isActive() )
142 return;
143 QPointF * polygon = new QPointF[npts];
144 for ( int i = 0; i < npts; ++i )
145 {
146 polygon[i].setX( (PLFLT) x[i] * downscale );
147 polygon[i].setY( m_dHeight - (PLFLT) y[i] * downscale );
148 }
149 if ( plsc->dev_eofill )
150 m_painterP->drawPolygon( polygon, npts, Qt::OddEvenFill );
151 else
152 m_painterP->drawPolygon( polygon, npts, Qt::WindingFill );
153 delete[] polygon;
154 }
155
156
157 QFont QtPLDriver::getFont( PLUNICODE unicode )
158 {
159 // Get new font parameters
160 unsigned char fontFamily, fontStyle, fontWeight;
161
162 plP_fci2hex( unicode, &fontFamily, PL_FCI_FAMILY );
163 plP_fci2hex( unicode, &fontStyle, PL_FCI_STYLE );
164 plP_fci2hex( unicode, &fontWeight, PL_FCI_WEIGHT );
165
166 QFont f;
167
168 f.setPointSizeF( currentFontSize * currentFontScale < 4 ? 4 : currentFontSize * currentFontScale );
169
170 switch ( fontFamily )
171 {
172 case 1:
173 f.setStyleHint( QFont::Serif );
174 break;
175 case 2:
176 f.setStyleHint( QFont::TypeWriter );
177 break;
178 case 0: case 3: case 4: default:
179 f.setStyleHint( QFont::SansSerif );
180 break;
181 }
182
183 // Use a bogus family name here to force Qt to find fonts using setStyleHint instead.
184 // N.B. specifying an empty string which you would think would do this same job,
185 // does not work as well as a non-empty string pointing to a bogus family name
186 // for both the opensuse Qt5 version as well as the Debian Testing version of
187 // that library.
188 f.setFamily( "bogusxxxxxxxxxxxxxxxxxxxxbogus" );
189
190 if ( fontStyle )
191 f.setItalic( true );
192 if ( fontWeight )
193 f.setWeight( QFont::Bold );
194 else
195 f.setWeight( QFont::Normal );
196
197 f.setUnderline( underlined );
198 f.setOverline( overlined );
199
200 return f;
201 }
202
203 void QtPLDriver::drawTextInPicture( QPainter* p, const QString& text )
204 {
205 QRectF rect( 0., 0., 0., 0. );
206 QRectF bounding;
207 QPicture tempPic;
208 QPainter tempPainter( &tempPic );
209 tempPainter.setFont( p->font() );
210
211 if ( vectorize )
212 {
213 bounding = tempPainter.boundingRect( rect, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextDontClip, text );
214
215 tempPainter.save();
216 // QPen savePen=tempPainter.pen();
217 QPen pen = QPen( Qt::NoPen );
218 tempPainter.setPen( pen );
219
220 double offset = QFontMetrics( tempPainter.font(), &tempPic ).boundingRect( text ).top(); // Distance between the baseline and the top of the bounding box
221
222 QPainterPath path;
223 path.addText( QPointF( bounding.left(), bounding.top() - offset ), tempPainter.font(), text );
224 tempPainter.drawPath( path );
225 tempPainter.restore();
226 }
227 else
228 {
229 tempPainter.drawText( rect, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextDontClip, text, &bounding );
230 }
231
232 tempPainter.end();
233
234 p->drawPicture( (int) ( xOffset + bounding.width() / 2. ), (int) -yOffset, tempPic );
235
236 xOffset += bounding.width();
237 }
238
239 // 0.8 mimics the offset of first superscript/subscript level implemented
240 // in plstr (plsym.c) for Hershey fonts. Indeed when comparing with
241 // -dev xwin results this factor appears to offset the centers of the
242 // letters appropriately (but not their edges since different font sizes
243 // are involved).
244 # define RISE_FACTOR 0.8
245
246 QPicture QtPLDriver::getTextPicture( PLUNICODE fci, PLUNICODE* text, int len, PLFLT chrht )
247 {
248 char plplotEsc;
249 plgesc( &plplotEsc );
250
251 QPicture res;
252 QPainter p( &res );
253
254 QString currentString;
255 PLFLT old_sscale, sscale, old_soffset, soffset;
256 PLINT level = 0;
257 PLFLT dyOffset = 0.;
258 #ifdef PLPLOT_USE_QT5
259 // Empirical Y offset of text (needed for Qt5 for some reason).
260 // Note this was derived using the test_circle.py python script
261 // with the vertical alignment of the light diagonal cross
262 // optimized. That example shows that other glyphs (except for
263 // the well-known asterisk case which is vertically misaligned by
264 // font design) do not have the best vertical alignment. This is
265 // contrary to the results for cairo and qt with Qt4 which need no
266 // special empirical Y offset to get good vertical alignment for
267 // most glyphs of that example (other than the asterisk). An
268 // additional issue which confuses the decision concerning the
269 // best vertical alignment for qt with Qt5 is the font selection
270 // for qt with Qt5 is quite different than that for qt with Qt4 or
271 // cairo. I assume all these issues are due to Qt5 version 5.2.1
272 // font selection and font alignment bugs which will be addressed
273 // for future Qt5 versions.
274 // PLFLT empirical_yOffset = -0.63 * chrht * POINTS_PER_INCH / 25.4;
275 // With Debian Jessie Qt5 version 5.3.2, that font alignment bug
276 // finally appears to be fixed.
277 PLFLT empirical_yOffset = 0.;
278 #else
279 PLFLT empirical_yOffset = 0.;
280 #endif
281 yOffset = empirical_yOffset;
282 xOffset = 0.;
283
284 // Scaling factor of 1.45 determined empirically to make all qt results
285 // have the same character size as cairo results (taking into account
286 // the slightly different actual glyph sizes for the different
287 // default fonts found by cairo and qt).
288 currentFontSize = chrht * POINTS_PER_INCH / 25.4 * 1.45;
289 currentFontScale = 1.;
290 underlined = false;
291 overlined = false;
292
293 p.setFont( getFont( fci ) );
294
295 int i = 0;
296 while ( i < len )
297 {
298 if ( text[i] < PL_FCI_MARK ) // Not a font change
299 {
300 if ( text[i] != (PLUNICODE) plplotEsc )
301 {
302 currentString.append( QString( QChar( text[i] ) ) );
303 ++i;
304 continue;
305 }
306 ++i; // Now analyse the escaped character
307 switch ( text[i] )
308 {
309 case 'd': //subscript
310 drawTextInPicture( &p, currentString );
311 currentString.clear();
312 plP_script_scale( FALSE, &level,
313 &old_sscale, &sscale, &old_soffset, &soffset );
314 currentFontScale = sscale;
315
316 // The correction for the difference in magnitude
317 // between the baseline and middle coordinate systems
318 // for subscripts should be
319 // -0.5*(fontSize - superscript/subscript fontSize).
320 // dyOffset = -0.5 * currentFontSize * ( 1.0 - sscale );
321 // But empirically this change in offset should not be applied
322 // so leave it at its initial value of zero.
323 yOffset = empirical_yOffset - ( currentFontSize * RISE_FACTOR * soffset + dyOffset );
324
325 p.setFont( getFont( fci ) );
326 break;
327
328 case 'u': //superscript
329 drawTextInPicture( &p, currentString );
330
331 currentString.clear();
332 plP_script_scale( TRUE, &level,
333 &old_sscale, &sscale, &old_soffset, &soffset );
334 currentFontScale = sscale;
335
336 // The correction for the difference in magnitude
337 // between the baseline and middle coordinate systems
338 // for superscripts should be
339 // 0.5*(fontSize - superscript/subscript fontSize).
340 // dyOffset = 0.5 * currentFontSize * ( 1.0 - sscale );
341 // But empirically this change in offset should not be applied
342 // so leave it at its initial value of zero.
343 yOffset = empirical_yOffset + currentFontSize * RISE_FACTOR * soffset + dyOffset;
344
345 p.setFont( getFont( fci ) );
346 break;
347
348 case '-':
349 drawTextInPicture( &p, currentString );
350
351 currentString.clear();
352 underlined = !underlined;
353 p.setFont( getFont( fci ) );
354 break;
355
356 case '+':
357 drawTextInPicture( &p, currentString );
358
359 currentString.clear();
360 overlined = !overlined;
361 p.setFont( getFont( fci ) );
362 break;
363
364
365 case '#':
366 currentString.append( QString( (QChar *) &( text[i] ), 1 ) );
367 break;
368
369 default:
370 std::cout << "unknown escape char " << ( (QChar) text[i] ).toLatin1() << std::endl;
371 break;
372 }
373 }
374 else // Font change
375 {
376 drawTextInPicture( &p, currentString );
377
378 currentString.clear();
379 fci = text[i];
380 p.setFont( getFont( fci ) );
381 }
382 ++i;
383 }
384 drawTextInPicture( &p, currentString );
385
386 p.end();
387
388 return res;
389 }
390
391 void QtPLDriver::drawText( EscText* txt )
392 {
393 if ( !m_painterP->isActive() )
394 return;
395
396 // Check that we got unicode, warning message and return if not
397 if ( txt->unicode_array_len == 0 )
398 {
399 printf( "Non unicode string passed to a Qt driver, ignoring\n" );
400 return;
401 }
402
403 // Check that unicode string isn't longer then the max we allow
404 if ( txt->unicode_array_len >= 500 )
405 {
406 printf( "Sorry, the Qt drivers only handle strings of length < %d\n", 500 );
407 return;
408 }
409
410 PLFLT rotation, shear, stride;
411 plRotationShear( txt->xform, &rotation, &shear, &stride );
412
413 double picDpi;
414 PLUNICODE fci;
415 plgfci( &fci );
416 QPicture picText = getTextPicture( fci, txt->unicode_array, txt->unicode_array_len, pls->chrht );
417 picDpi = picText.logicalDpiY();
418
419 if ( pls->get_string_length )
420 {
421 pls->string_length = ( (PLFLT) xOffset / picDpi ) * 25.4;
422 return;
423 }
424
425 m_painterP->setClipping( true );
426 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 );
427
428 rotation -= pls->diorot * M_PI / 2.0;
429 m_painterP->translate( txt->x * downscale, m_dHeight - txt->y * downscale );
430 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. );
431
432 m_painterP->setWorldMatrix( rotShearMatrix, true );
433
434 m_painterP->translate( -txt->just * xOffset * m_painterP->device()->logicalDpiY() / picDpi, 0. );
435
436 m_painterP->drawPicture( 0, 0, picText );
437
438 m_painterP->resetTransform();;
439 m_painterP->setClipping( false );
440 }
441
442 void QtPLDriver::setColor( int r, int g, int b, double alpha )
443 {
444 if ( !m_painterP->isActive() )
445 return;
446
447 QPen p = m_painterP->pen();
448 p.setColor( QColor( r, g, b, (int) ( alpha * 255 ) ) );
449 m_painterP->setPen( p );
450
451 QBrush B = m_painterP->brush();
452 B.setColor( QColor( r, g, b, (int) ( alpha * 255 ) ) );
453 B.setStyle( Qt::SolidPattern );
454 m_painterP->setBrush( B );
455 }
456
457 void QtPLDriver::setGradient( int x1, int x2, int y1, int y2,
458 unsigned char *r, unsigned char *g,
459 unsigned char *b, PLFLT *alpha, PLINT ncol1 )
460 {
461 if ( !m_painterP->isActive() || ncol1 < 2 )
462 return;
463
464 int i;
465 qreal stop_arg;
466 QLinearGradient linear_gradient;
467 QGradientStops stops;
468
469 linear_gradient = QLinearGradient(
470 QPointF( (qreal) ( x1 * downscale ), (qreal) ( m_dHeight - y1 * downscale ) ),
471 QPointF( (qreal) ( x2 * downscale ), (qreal) ( m_dHeight - y2 * downscale ) ) );
472
473 for ( i = 0; i < ncol1; i++ )
474 {
475 stop_arg = (qreal) i / (qreal) ( ncol1 - 1 );
476 stops << QGradientStop( stop_arg, QColor( r[i], g[i],
477 b[i], (int) ( alpha[i] * 255 ) ) );
478 }
479 linear_gradient.setStops( stops );
480 m_painterP->setBrush( linear_gradient );
481 }
482
483 void QtPLDriver::setWidthF( PLFLT w )
484 {
485 if ( !m_painterP->isActive() )
486 return;
487
488 QPen p = m_painterP->pen();
489 p.setWidthF( w );
490 m_painterP->setPen( p );
491 }
492
493 // void QtPLDriver::setDashed(PLINT nms, PLINT* mark, PLINT* space)
494 // {
495 // if(!m_painterP->isActive()) return;
496 //
497 // QVector<qreal> vect;
498 // for(int i=0; i<nms; ++i)
499 // {
500 // vect << (PLFLT)mark[i]*m_painterP->device()->logicalDpiX()/25400.;
501 // vect << (PLFLT)space[i]*m_painterP->device()->logicalDpiX()/25400.;
502 // }
503 // QPen p=m_painterP->pen();
504 // p.setDashPattern(vect);
505 // m_painterP->setPen(p);
506 // }
507
508 void QtPLDriver::setSolid()
509 {
510 if ( !m_painterP->isActive() )
511 return;
512
513 QPen p = m_painterP->pen();
514 p.setStyle( Qt::SolidLine );
515 m_painterP->setPen( p );
516 }
517
519 #if defined ( PLD_bmpqt ) || defined ( PLD_jpgqt ) || defined ( PLD_pngqt ) || defined ( PLD_ppmqt ) || defined ( PLD_tiffqt ) || defined ( PLD_memqt )
520 QtRasterDevice::QtRasterDevice( int i_iWidth, int i_iHeight ) :
521 QtPLDriver( i_iWidth, i_iHeight ),
522 QImage( i_iWidth, i_iHeight, QImage::Format_ARGB32 )
523 {
524 // Painter initialised in the constructor contrary
525 // to buffered drivers, which paint only in doPlot().
526 m_painterP = new QPainter( this );
527 fill( Qt::transparent );
528
529 QBrush b = m_painterP->brush();
530 b.setStyle( Qt::SolidPattern );
531 m_painterP->setBrush( b );
532 m_painterP->setRenderHint( QPainter::Antialiasing, (bool) lines_aa );
533 }
534
535 QtRasterDevice::~QtRasterDevice()
536 {
537 delete m_painterP;
538 }
539
540 void QtRasterDevice::definePlotName( const char* fileName, const char* format )
541 {
542 // Avoid buffer overflows
543 strncpy( this->format, format, 4 );
544 this->format[4] = '\0';
545
546 this->fileName = QString( fileName );
547 }
548
549 void QtRasterDevice::savePlot()
550 {
551 m_painterP->end();
552 if ( save( fileName, format, 85 ) )
553 {
554 m_painterP->begin( this );
555 m_painterP->setRenderHint( QPainter::Antialiasing, (bool) lines_aa );
556 QBrush b = m_painterP->brush();
557 b.setStyle( Qt::SolidPattern );
558 m_painterP->setBrush( b );
559 }
560 else
561 {
562 printf( "WARNING: %s raster format currently not supported by your Qt installation\n", format );
563 }
564 }
565
566 void QtRasterDevice::setBackgroundColor( int r, int g, int b, double alpha )
567 {
568 if ( !m_painterP->isActive() )
569 return;
570
571
572 QBrush brush( QColor( r, g, b, (int) ( alpha * 255 ) ) );
573 m_painterP->fillRect( 0, 0, width(), height(), brush );
574 }
575 #endif
576
577 #if defined ( PLD_svgqt ) && QT_VERSION >= 0x040300
578 QtSVGDevice::QtSVGDevice( int i_iWidth, int i_iHeight ) :
579 QtPLDriver( i_iWidth, i_iHeight )
580 {
581 m_painterP = NULL;
582 }
583
584 QtSVGDevice::~QtSVGDevice()
585 {
586 delete m_painterP;
587 }
588
589 void QtSVGDevice::definePlotName( const char* fileName )
590 {
591 setFileName( QString( fileName ) );
592 setResolution( POINTS_PER_INCH );
593 setSize( QSize( (int) m_dWidth, (int) m_dHeight ) );
594 #if QT_VERSION >= 0x040500
595 setViewBox( QRect( 0, 0, (int) m_dWidth, (int) m_dHeight ) );
596 #endif
597
598 m_painterP = new QPainter( this );
599 }
600
601 void QtSVGDevice::savePlot()
602 {
603 m_painterP->end();
604 }
605
606 void QtSVGDevice::setBackgroundColor( int r, int g, int b, double alpha )
607 {
608 if ( !m_painterP->isActive() )
609 return;
610
611 QBrush brush( QColor( r, g, b, (int) ( alpha * 255 ) ) );
612 m_painterP->fillRect( 0, 0, width(), height(), brush );
613 }
614 #endif
615
616 #if defined ( PLD_epsqt ) || defined ( PLD_pdfqt )
617 QtEPSDevice::QtEPSDevice( int i_iWidth, int i_iHeight )
618 {
619 #if QT_VERSION < 0x040400
620 setPageSize( QPrinter::A4 );
621 #else
622 setFullPage( true );
623 setPaperSize( QSizeF( i_iHeight, i_iWidth ), QPrinter::Point );
624 #endif
625 setResolution( POINTS_PER_INCH );
626 setColorMode( QPrinter::Color );
627 setOrientation( QPrinter::Landscape );
628 setPrintProgram( QString( "lpr" ) );
629
630 if ( i_iWidth <= 0 || i_iHeight <= 0 )
631 {
632 m_dWidth = pageRect().width();
633 m_dHeight = pageRect().height();
634 }
635 else
636 {
637 m_dWidth = i_iWidth;
638 m_dHeight = i_iHeight;
639 }
640 m_painterP = NULL;
641 }
642
643 QtEPSDevice::~QtEPSDevice()
644 {
645 delete m_painterP;
646 }
647
648 void QtEPSDevice::definePlotName( const char* fileName, int ifeps )
649 {
650 setOutputFileName( QString( fileName ) );
651 if ( ifeps )
652 {
653 #ifndef PLPLOT_USE_QT5
654 setOutputFormat( QPrinter::PostScriptFormat );
655 #endif
656 }
657 else
658 {
659 setOutputFormat( QPrinter::PdfFormat );
660 }
661
662 m_painterP = new QPainter( this );
663 }
664
665 void QtEPSDevice::savePlot()
666 {
667 m_painterP->end();
668 }
669
670 void QtEPSDevice::setBackgroundColor( int r, int g, int b, double alpha )
671 {
672 if ( !m_painterP->isActive() )
673 return;
674
675 QBrush brush( QColor( r, g, b, (int) ( alpha * 255 ) ) );
676 m_painterP->fillRect( 0, 0, width(), height(), brush );
677 }
678 #endif
679
680 #if defined ( PLD_qtwidget ) || defined ( PLD_extqt )
681 QtPLWidget::QtPLWidget( int i_iWidth, int i_iHeight, QWidget* parent ) :
682 QWidget( parent ), QtPLDriver( i_iWidth, i_iHeight )
683 {
684 m_painterP = new QPainter;
685
686 m_dAspectRatio = m_dWidth / m_dHeight;
687
688 m_pixPixmap = NULL;
689 // m_iOldSize=0;
690 pageNumber = 0;
691 resize( i_iWidth, i_iHeight );
692 lastColour.r = -1;
693 setVisible( true );
694 // Dropping this appears to give more reliable results
695 // (QColor::setRgb: RGB parameters out of range warnings go away)
696 // according to Jonathan Woithe <jwoithe@just42.net> and according
697 // to my own tests does not affect results from the
698 // test_interactive target.
699 // QApplication::processEvents();
700 redrawFromLastFlush = false;
701 redrawAll = true;
702
703 NoPen = QPen( Qt::NoPen );
704 NoPen.setWidthF( 0. );
705
706 locate_mode = 0;
707 }
708
709 QtPLWidget::~QtPLWidget()
710 {
711 clearBuffer();
712 delete m_pixPixmap;
713 }
714
715 void QtPLWidget::clearWidget()
716 {
717 clearBuffer();
718 setBackgroundColor( bgColour.r, bgColour.g, bgColour.b, bgColour.alpha );
719 redrawAll = true;
720 // m_bAwaitingRedraw=true;
721 update();
722 }
723
724 void QtPLWidget::flush()
725 {
726 repaint();
727 QApplication::processEvents();
728 }
729
730 void QtPLWidget::clearBuffer()
731 {
732 lastColour.r = -1;
733 for ( QLinkedList<BufferElement>::iterator i = m_listBuffer.begin(); i != m_listBuffer.end(); ++i )
734 {
735 switch ( i->Element )
736 {
737 case LINE:
738 delete i->Data.Line;
739 break;
740 case RECTANGLE:
741 delete i->Data.Rect;
742 break;
743
744 case POLYLINE:
745 case POLYGON:
746 delete i->Data.Polyline;
747 break;
748
749 case TEXT:
750 delete[] i->Data.TextStruct->text;
751 delete i->Data.TextStruct;
752 break;
753
754 case SET_COLOUR:
755 case SET_BG_COLOUR:
756 delete i->Data.ColourStruct;
757 break;
758
759 case SET_GRADIENT:
760 delete i->Data.LinearGradient;
761 break;
762
763 case ARC:
764 delete i->Data.ArcStruct->rect;
765 delete i->Data.ArcStruct->dx;
766 delete i->Data.ArcStruct;
767
768 default:
769 break;
770 }
771 }
772
773 m_listBuffer.clear();
774 start_iterator = m_listBuffer.constBegin();
775 redrawAll = true;
776 }
777
778
779 void QtPLWidget::drawArc( short x, short y, short a, short b, PLFLT angle1, PLFLT angle2, PLFLT rotate, bool fill )
780 {
781 BufferElement el;
782 el.Element = ARC;
783 el.Data.ArcStruct = new struct ArcStruct_;
784 el.Data.ArcStruct->rect = new QRectF( (PLFLT) ( x - a ) * downscale,
785 m_dHeight - (PLFLT) ( y + b ) * downscale,
786 (PLFLT) a * downscale * 2,
787 (PLFLT) b * downscale * 2
788 );
789 el.Data.ArcStruct->startAngle = (int) ( angle1 * 16 );
790 el.Data.ArcStruct->spanAngle = (int) ( ( angle2 - angle1 ) * 16 );
791 el.Data.ArcStruct->rotate = rotate;
792 el.Data.ArcStruct->dx = new QPointF( (PLFLT) x * downscale, m_dHeight - (PLFLT) y * downscale );
793 el.Data.ArcStruct->fill = fill;
794
795 m_listBuffer.append( el );
796 redrawFromLastFlush = true;
797 }
798
799
800 void QtPLWidget::drawLine( short x1, short y1, short x2, short y2 )
801 {
802 BufferElement el;
803 el.Element = LINE;
804 el.Data.Line = new QLineF( QPointF( (PLFLT) x1 * downscale, (PLFLT) ( m_dHeight - y1 * downscale ) ), QPointF( (PLFLT) x2 * downscale, (PLFLT) ( m_dHeight - y2 * downscale ) ) );
805
806 m_listBuffer.append( el );
807 redrawFromLastFlush = true;
808 }
809
810 void QtPLWidget::drawPolyline( short * x, short * y, PLINT npts )
811 {
812 BufferElement el;
813 el.Element = POLYLINE;
814 el.Data.Polyline = new QPolygonF;
815 for ( int i = 0; i < npts; ++i )
816 {
817 ( *el.Data.Polyline ) << QPointF( (PLFLT) ( x[i] ) * downscale, (PLFLT) ( m_dHeight - ( y[i] ) * downscale ) );
818 }
819
820 m_listBuffer.append( el );
821 redrawFromLastFlush = true;
822 }
823
824 void QtPLWidget::drawPolygon( short * x, short * y, PLINT npts )
825 {
826 BufferElement el;
827
828 bool isRect = false;
829 if ( npts == 4 ) // Check if it's a rectangle. If so, it can be made faster to display
830 {
831 if ( x[0] == x[1] && x[2] == x[3] && y[0] == y[3] && y[1] == y[2] )
832 {
833 isRect = true;
834 }
835 else if ( x[0] == x[3] && x[1] == x[2] && y[0] == y[1] && y[2] == y[3] )
836 {
837 isRect = true;
838 }
839 }
840 if ( npts == 5 )
841 {
842 if ( x[0] == x[4] && y[0] == y[4] )
843 {
844 if ( x[0] == x[1] && x[2] == x[3] && y[0] == y[3] && y[1] == y[2] )
845 {
846 isRect = true;
847 }
848 else if ( x[0] == x[3] && x[1] == x[2] && y[0] == y[1] && y[2] == y[3] )
849 {
850 isRect = true;
851 }
852 }
853 }
854
855 if ( isRect )
856 {
857 el.Element = RECTANGLE;
858
859 double x1, y1, x2, y2, x0, y0, width, height;
860 x1 = (PLFLT) ( x[0] ) * downscale;
861 x2 = (PLFLT) ( x[2] ) * downscale;
862 y1 = (PLFLT) ( m_dHeight - ( y[0] ) * downscale );
863 y2 = (PLFLT) ( m_dHeight - ( y[2] ) * downscale );
864 if ( x1 < x2 )
865 {
866 x0 = x1;
867 width = x2 - x1;
868 }
869 else
870 {
871 x0 = x2;
872 width = x1 - x2;
873 }
874 if ( y1 < y2 )
875 {
876 y0 = y1;
877 height = y2 - y1;
878 }
879 else
880 {
881 y0 = y2;
882 height = y1 - y2;
883 }
884 el.Data.Rect = new QRectF( x0, y0, width, height );
885 }
886 else
887 {
888 el.Element = POLYGON;
889 el.Data.Polyline = new QPolygonF;
890 for ( int i = 0; i < npts; ++i )
891 {
892 ( *el.Data.Polyline ) << QPointF( (PLFLT) ( x[i] ) * downscale, (PLFLT) ( m_dHeight - ( y[i] ) * downscale ) );
893 }
894 }
895
896 m_listBuffer.append( el );
897 redrawFromLastFlush = true;
898 }
899
900 void QtPLWidget::setColor( int r, int g, int b, double alpha )
901 {
902 if ( lastColour.r != r || lastColour.g != g || lastColour.b != b || lastColour.alpha != alpha )
903 {
904 BufferElement el;
905 el.Element = SET_COLOUR;
906 el.Data.ColourStruct = new struct ColourStruct_;
907 el.Data.ColourStruct->R = r;
908 el.Data.ColourStruct->G = g;
909 el.Data.ColourStruct->B = b;
910 el.Data.ColourStruct->A = (PLINT) ( alpha * 255. );
911
912 m_listBuffer.append( el );
913
914 lastColour.r = r;
915 lastColour.g = g;
916 lastColour.b = b;
917 lastColour.alpha = alpha;
918 }
919 // No need to ask for a redraw at this point. The color only affects subsequent items
920 // redrawFromLastFlush=true;
921 }
922
923 void QtPLWidget::setGradient( int x1, int x2, int y1, int y2,
924 unsigned char *r, unsigned char *g,
925 unsigned char *b, PLFLT *alpha, PLINT ncol1 )
926 {
927 int i;
928 BufferElement el;
929 qreal stop_arg;
930 QGradientStops stops;
931
932 el.Element = SET_GRADIENT;
933
934 el.Data.LinearGradient = new QLinearGradient;
935 *el.Data.LinearGradient = QLinearGradient(
936 QPointF( (qreal) ( x1 * downscale ), (qreal) ( m_dHeight - y1 * downscale ) ),
937 QPointF( (qreal) ( x2 * downscale ), (qreal) ( m_dHeight - y2 * downscale ) ) );
938 for ( i = 0; i < ncol1; i++ )
939 {
940 stop_arg = (qreal) i / (qreal) ( ncol1 - 1 );
941 stops << QGradientStop( stop_arg, QColor( r[i], g[i],
942 b[i], (int) ( alpha[i] * 255 ) ) );
943 }
944 ( *el.Data.LinearGradient ).setStops( stops );
945 m_listBuffer.append( el );
946
947 // No need to ask for a redraw at this point. The gradient only
948 // affects subsequent items.
949 //redrawFromLastFlush=true;
950 }
951
952 void QtPLWidget::setBackgroundColor( int r, int g, int b, double alpha )
953 {
954 BufferElement el;
955 el.Element = SET_BG_COLOUR;
956 el.Data.ColourStruct = new struct ColourStruct_;
957 el.Data.ColourStruct->R = r;
958 el.Data.ColourStruct->G = g;
959 el.Data.ColourStruct->B = b;
960 el.Data.ColourStruct->A = (PLINT) ( alpha * 255. );
961
962 bgColour.r = r;
963 bgColour.g = g;
964 bgColour.b = b;
965 bgColour.alpha = alpha;
966 if ( alpha >= 0.999 )
967 {
968 clearBuffer();
969 }
970 m_listBuffer.append( el );
971 redrawFromLastFlush = true;
972 }
973
974 void QtPLWidget::setWidthF( PLFLT w )
975 {
976 BufferElement el;
977 el.Element = SET_WIDTH;
978 el.Data.fltParam = w;
979 m_listBuffer.append( el );
980 // redrawFromLastFlush=true;
981 }
982
983 void QtPLWidget::drawText( EscText* txt )
984 {
985 if ( pls->get_string_length )
986 {
987 PLUNICODE fci;
988 QPicture picText;
989 double picDpi;
990 PLUNICODE *text;
991
992 plgfci( &fci );
993 text = new PLUNICODE[txt->unicode_array_len];
994 memcpy( text, txt->unicode_array, txt->unicode_array_len * sizeof ( PLUNICODE ) );
995 picText = getTextPicture( fci,
996 text,
997 txt->unicode_array_len,
998 pls->chrht );
999 //
1000 // I'm assuming that y_fact is 1.0 here, as it is impossible
1001 // to know in advance (or so I believe). When the text is
1002 // rendered "for real" it will be: pls->chrht * y_fact.
1003 //
1004 // Hazen 6/2011
1005 //
1006 picDpi = picText.logicalDpiY();
1007 pls->string_length = ( (PLFLT) xOffset / picDpi ) * 25.4;
1008 delete[] text;
1009 return;
1010 }
1011
1012 BufferElement el;
1013
1014 el.Element = TEXT;
1015 el.Data.TextStruct = new struct TextStruct_;
1016 el.Data.TextStruct->x = txt->x * downscale;
1017 el.Data.TextStruct->y = m_dHeight - txt->y * downscale;
1018 el.Data.TextStruct->clipxmin = pls->clpxmi * downscale;
1019 el.Data.TextStruct->clipymin = m_dHeight - pls->clpymi * downscale;
1020 el.Data.TextStruct->clipxmax = pls->clpxma * downscale;
1021 el.Data.TextStruct->clipymax = m_dHeight - pls->clpyma * downscale;
1022 PLUNICODE fci;
1023 plgfci( &fci );
1024 el.Data.TextStruct->fci = fci;
1025 PLFLT rotation, shear, stride;
1026 plRotationShear( txt->xform, &rotation, &shear, &stride );
1027 rotation -= pls->diorot * M_PI / 2.0;
1028 el.Data.TextStruct->rotation = rotation;
1029 el.Data.TextStruct->shear = shear;
1030 el.Data.TextStruct->stride = stride;
1031 el.Data.TextStruct->just = txt->just;
1032 el.Data.TextStruct->text = new PLUNICODE[txt->unicode_array_len];
1033 memcpy( el.Data.TextStruct->text, txt->unicode_array, txt->unicode_array_len * sizeof ( PLUNICODE ) );
1034 el.Data.TextStruct->len = txt->unicode_array_len;
1035 el.Data.TextStruct->chrht = pls->chrht;
1036
1037 m_listBuffer.append( el );
1038 redrawFromLastFlush = true;
1039 }
1040
1041 void QtPLWidget::renderText( QPainter* p, struct TextStruct_* s, double x_fact, double x_offset, double y_fact, double y_offset )
1042 {
1043 if ( s->len <= 0 || s->len >= 500 )
1044 return;
1045 QPicture picText = getTextPicture( s->fci, s->text, s->len, s->chrht * y_fact );
1046
1047 double picDpi = picText.logicalDpiY();
1048
1049 p->setClipping( true );
1050 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 );
1051 p->translate( s->x * x_fact + x_offset, s->y * y_fact + y_offset );
1052 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. );
1053 p->setWorldMatrix( rotShearMatrix, true );
1054
1055 p->translate( -s->just * xOffset * p->device()->logicalDpiY() / picDpi, 0. );
1056
1057 p->drawPicture( 0, 0, picText );
1058
1059 p->resetTransform();
1060
1061 p->setClipping( false );
1062 }
1063
1064 void QtPLWidget::resetPensAndBrushes( QPainter* painter )
1065 {
1066 SolidPen = QPen();
1067 hasPen = true;
1068 painter->setPen( SolidPen );
1069 SolidBrush = QBrush( Qt::SolidPattern );
1070 }
1071
1072 void QtPLWidget::lookupButtonEvent( QMouseEvent * event )
1073 {
1074 Qt::MouseButtons buttons = event->buttons();
1075 Qt::KeyboardModifiers modifiers = event->modifiers();
1076 gin.pX = event->x();
1077 gin.pY = height() - event->y();
1078 gin.dX = (PLFLT) event->x() / width();
1079 gin.dY = (PLFLT) ( height() - event->y() ) / height();
1080
1081 switch ( event->button() )
1082 {
1083 case Qt::LeftButton:
1084 gin.button = 1;
1085 break;
1086 case Qt::MidButton:
1087 gin.button = 2;
1088 break;
1089 case Qt::RightButton:
1090 gin.button = 3;
1091 break;
1092 default:
1093 break;
1094 }
1095
1096 // Map Qt button and key states to the (X windows) values used
1097 // by plplot.
1098 gin.state = 0;
1099 if ( buttons & Qt::LeftButton )
1100 gin.state |= 1 << 8;
1101 if ( buttons & Qt::MidButton )
1102 gin.state |= 1 << 9;
1103 if ( buttons & Qt::RightButton )
1104 gin.state |= 1 << 10;
1105 if ( modifiers & Qt::ShiftModifier )
1106 gin.state |= 1 << 0;
1107 if ( modifiers & Qt::ControlModifier )
1108 gin.state |= 1 << 2;
1109 if ( modifiers & Qt::AltModifier )
1110 gin.state |= 1 << 3;
1111 if ( modifiers & Qt::MetaModifier )
1112 gin.state |= 1 << 3;
1113
1114 gin.keysym = 0x20;
1115 }
1116
1117 void QtPLWidget::locate()
1118 {
1119 if ( plTranslateCursor( &gin ) )
1120 {
1121 if ( locate_mode == 2 )
1122 {
1123 pltext();
1124 if ( gin.keysym < 0xFF && isprint( gin.keysym ) )
1125 std::cout << gin.wX << " " << gin.wY << " " << (char) gin.keysym << std::endl;
1126 else
1127 std::cout << gin.wX << " " << gin.wY << " " << std::hex << gin.keysym << std::endl;
1128
1129 plgra();
1130 }
1131 }
1132 else
1133 {
1134 locate_mode = 0;
1135 QApplication::restoreOverrideCursor();
1136 }
1137 }
1138
1139 void QtPLWidget::mouseEvent( QMouseEvent * event )
1140 {
1141 lookupButtonEvent( event );
1142
1143 if ( locate_mode )
1144 {
1145 if ( event->button() == Qt::LeftButton )
1146 {
1147 locate();
1148 }
1149 }
1150 else
1151 {
1152 if ( event->button() == Qt::RightButton )
1153 {
1154 handler.DeviceChangedPage( this );
1155 }
1156 }
1157 }
1158
1159 void QtPLWidget::mousePressEvent( QMouseEvent * event )
1160 {
1161 mouseEvent( event );
1162 }
1163
1164 void QtPLWidget::mouseReleaseEvent( QMouseEvent * PL_UNUSED( event ) )
1165 {
1166 //mouseEvent( event );
1167 }
1168
1169 void QtPLWidget::mouseMoveEvent( QMouseEvent * PL_UNUSED( event ) )
1170 {
1171 //mouseEvent( event );
1172 }
1173
1174 void QtPLWidget::keyPressEvent( QKeyEvent* event )
1175 {
1176 if ( locate_mode )
1177 {
1178 QPoint p = QCursor::pos();
1179 gin.pX = p.x();
1180 gin.pY = height() - p.y();
1181 gin.dX = (PLFLT) p.x() / width();
1182 gin.dY = (PLFLT) ( height() - p.y() ) / height();
1183
1184 switch ( event->key() )
1185 {
1186 case Qt::Key_Escape:
1187 locate_mode = 0;
1188 QApplication::restoreOverrideCursor();
1189 plGinInit( &gin );
1190 break;
1191 case Qt::Key_Shift:
1192 case Qt::Key_Control:
1193 case Qt::Key_Alt:
1194 case Qt::Key_Meta:
1195 case Qt::Key_AltGr:
1196 plGinInit( &gin );
1197 case Qt::Key_Left:
1198 case Qt::Key_Right:
1199 case Qt::Key_Up:
1200 case Qt::Key_Down:
1201 {
1202 int x1, y1, dx = 0, dy = 0;
1203 int xmin = 0, xmax = width() - 1, ymin = 0, ymax = height() - 1;
1204 switch ( event->key() )
1205 {
1206 case Qt::Key_Left:
1207 dx = -1;
1208 break;
1209 case Qt::Key_Right:
1210 dx = 1;
1211 break;
1212 case Qt::Key_Up:
1213 dy = -1;
1214 break;
1215 case Qt::Key_Down:
1216 dy = 1;
1217 break;
1218 }
1219 if ( event->modifiers() & Qt::ShiftModifier )
1220 {
1221 dx *= 5;
1222 dy *= 5;
1223 }
1224 if ( event->modifiers() & Qt::ControlModifier )
1225 {
1226 dx *= 5;
1227 dy *= 5;
1228 }
1229 if ( event->modifiers() & Qt::AltModifier )
1230 {
1231 dx *= 5;
1232 dy *= 5;
1233 }
1234 x1 = gin.pX + dx;
1235 y1 = gin.pY + dy;
1236
1237 if ( x1 < xmin )
1238 dx = xmin - gin.pX;
1239 if ( y1 < ymin )
1240 dy = ymin - gin.pY;
1241 if ( x1 > xmax )
1242 dx = xmax - gin.pX;
1243 if ( y1 > ymax )
1244 dy = ymax - gin.pY;
1245
1246 QCursor::setPos( p.x() + dx, p.y() + dy );
1247 plGinInit( &gin );
1248 break;
1249 }
1250 default:
1251 locate();
1252 break;
1253 }
1254 }
1255 else
1256 {
1257 if ( event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return )
1258 {
1259 handler.DeviceChangedPage( this );
1260 }
1261 if ( event->text() == "Q" )
1262 {
1263 // Terminate on a 'Q' (not 'q', since it's too easy to hit by mistake)
1264 pls->nopause = TRUE;
1265 plexit( "" );
1266 }
1267 else if ( event->text() == "L" )
1268 // Begin locate mode
1269 {
1270 locate_mode = 2;
1271 QApplication::setOverrideCursor( Qt::CrossCursor );
1272 }
1273 }
1274 }
1275
1276 void QtPLWidget::closeEvent( QCloseEvent* event )
1277 {
1278 handler.DeviceClosed( this );
1279 event->ignore();
1280 }
1281
1282 void QtPLWidget::nextPage()
1283 {
1284 clearWidget();
1285 pageNumber++;
1286 }
1287
1288 void QtPLWidget::resizeEvent( QResizeEvent * )
1289 {
1290 // m_bAwaitingRedraw=true;
1291 redrawAll = true;
1292 delete m_pixPixmap;
1293 m_pixPixmap = NULL;
1294 }
1295
1296 void QtPLWidget::paintEvent( QPaintEvent * )
1297 {
1298 double x_fact, y_fact, x_offset( 0. ), y_offset( 0. ); //Parameters to scale and center the plot on the widget
1299
1300 getPlotParameters( x_fact, y_fact, x_offset, y_offset );
1301
1302 if ( redrawAll || m_pixPixmap == NULL )
1303 {
1304 if ( m_pixPixmap != NULL )
1305 {
1306 delete m_pixPixmap;
1307 }
1308 m_pixPixmap = new QPixmap( width(), height() );
1309 QPainter* painter = new QPainter;
1310 painter->begin( m_pixPixmap );
1311
1312 // Draw the margins and the background
1313 painter->fillRect( 0, 0, width(), height(), QColor( bgColour.r, bgColour.g, bgColour.b ) );
1314
1315 // Re-initialise pens etc.
1316 resetPensAndBrushes( painter );
1317
1318 start_iterator = m_listBuffer.constBegin();
1319
1320 // Draw the plot
1321 doPlot( painter, x_fact, y_fact, x_offset, y_offset );
1322 painter->end();
1323
1324 // m_iOldSize=m_listBuffer.size();
1325
1326 delete painter;
1327 }
1328 else
1329 {
1330 QPainter* painter = new QPainter;
1331 painter->begin( m_pixPixmap );
1332 if ( hasPen )
1333 painter->setPen( SolidPen );
1334 else
1335 painter->setPen( NoPen );
1336
1337 // Draw the plot
1338 doPlot( painter, x_fact, y_fact, x_offset, y_offset );
1339 painter->end();
1340 }
1341
1342 // draw the current pixmap
1343 m_painterP->begin( this );
1344
1345 m_painterP->drawPixmap( 0, 0, *m_pixPixmap );
1346
1347 m_painterP->end();
1348 }
1349
1350 void QtPLWidget::doPlot( QPainter* p, double x_fact, double y_fact, double x_offset, double y_offset )
1351 {
1352 QLineF line;
1353 QVector<qreal> vect;
1354 QRectF rect;
1355
1356
1357 // QPen SolidPen;
1358 //
1359 // QPen NoPen(Qt::NoPen);
1360 // NoPen.setWidthF(0.); // Cosmetic pen
1361 // p->setPen(SolidPen);
1362 // bool hasPen=true;
1363
1364 p->setRenderHints( QPainter::Antialiasing, (bool) lines_aa );
1365
1366 // QBrush SolidBrush(Qt::SolidPattern);
1367 p->setBrush( SolidBrush );
1368
1369 QTransform trans;
1370 trans = trans.translate( x_offset, y_offset );
1371 trans = trans.scale( x_fact, y_fact );
1372
1373 p->setTransform( trans );
1374
1375 if ( m_listBuffer.empty() )
1376 {
1377 p->fillRect( 0, 0, 1, 1, QBrush() );
1378 return;
1379 }
1380
1381 // unrolls the buffer and draws each element accordingly
1382 for ( QLinkedList<BufferElement>::const_iterator i = start_iterator; i != m_listBuffer.constEnd(); ++i )
1383 {
1384 switch ( i->Element )
1385 {
1386 case SET_COLOUR:
1387 SolidPen.setColor( QColor( i->Data.ColourStruct->R, i->Data.ColourStruct->G, i->Data.ColourStruct->B, i->Data.ColourStruct->A ) );
1388 if ( hasPen )
1389 {
1390 p->setPen( SolidPen );
1391 }
1392 SolidBrush.setColor( QColor( i->Data.ColourStruct->R, i->Data.ColourStruct->G, i->Data.ColourStruct->B, i->Data.ColourStruct->A ) );
1393 p->setBrush( SolidBrush );
1394 break;
1395
1396 case SET_GRADIENT:
1397 p->setBrush( *( i->Data.LinearGradient ) );
1398 break;
1399
1400 case LINE:
1401 if ( !hasPen )
1402 {
1403 p->setPen( SolidPen );
1404 hasPen = true;
1405 }
1406 p->drawLine( *( i->Data.Line ) );
1407
1408 break;
1409
1410 case POLYLINE:
1411 if ( !hasPen )
1412 {
1413 p->setPen( SolidPen );
1414 hasPen = true;
1415 }
1416 p->drawPolyline( *( i->Data.Polyline ) );
1417 break;
1418
1419 case RECTANGLE:
1420 p->setRenderHints( QPainter::Antialiasing, false );
1421 if ( hasPen )
1422 {
1423 p->setPen( NoPen );
1424 hasPen = false;
1425 }
1426 p->drawRect( *( i->Data.Rect ) );
1427 p->setRenderHints( QPainter::Antialiasing, (bool) lines_aa );
1428 break;
1429
1430 case POLYGON:
1431 p->setRenderHints( QPainter::Antialiasing, false );
1432 if ( hasPen )
1433 {
1434 p->setPen( NoPen );
1435 hasPen = false;
1436 }
1437 if ( plsc->dev_eofill )
1438 p->drawPolygon( *( i->Data.Polyline ), Qt::OddEvenFill );
1439 else
1440 p->drawPolygon( *( i->Data.Polyline ), Qt::WindingFill );
1441 p->setRenderHints( QPainter::Antialiasing, (bool) lines_aa );
1442 break;
1443
1444 case TEXT:
1445 if ( !hasPen )
1446 {
1447 p->setPen( SolidPen );
1448 hasPen = true;
1449 }
1450 p->save();
1451 p->resetTransform();
1452
1453 renderText( p, i->Data.TextStruct, x_fact, x_offset, y_fact, y_offset );
1454 p->restore();
1455 break;
1456
1457 case SET_WIDTH:
1458 SolidPen.setWidthF( i->Data.fltParam );
1459 if ( hasPen )
1460 {
1461 p->setPen( SolidPen );
1462 }
1463 break;
1464
1465 case SET_BG_COLOUR:
1466 SolidBrush.setColor( QColor( i->Data.ColourStruct->R, i->Data.ColourStruct->G, i->Data.ColourStruct->B, i->Data.ColourStruct->A ) );
1467 p->fillRect( 0, 0, (int) m_dWidth, (int) m_dHeight, SolidBrush );
1468 break;
1469
1470 case ARC:
1471 if ( !hasPen )
1472 {
1473 p->setPen( SolidPen );
1474 hasPen = true;
1475 }
1476 if ( i->Data.ArcStruct->rotate != 0.0 )
1477 {
1478 p->save();
1479 p->translate( *( i->Data.ArcStruct->dx ) );
1480 p->rotate( -i->Data.ArcStruct->rotate );
1481 p->translate( -*( i->Data.ArcStruct->dx ) );
1482 }
1483
1484 if ( i->Data.ArcStruct->fill )
1485 p->drawPie( *( i->Data.ArcStruct->rect ), i->Data.ArcStruct->startAngle, i->Data.ArcStruct->spanAngle );
1486 else
1487 p->drawArc( *( i->Data.ArcStruct->rect ), i->Data.ArcStruct->startAngle, i->Data.ArcStruct->spanAngle );
1488
1489 if ( i->Data.ArcStruct->rotate != 0.0 )
1490 {
1491 p->restore();
1492 }
1493
1494 break;
1495 default:
1496 break;
1497 }
1498 }
1499
1500 start_iterator = m_listBuffer.constEnd();
1501 --start_iterator;
1502 redrawFromLastFlush = false;
1503 redrawAll = false;
1504 }
1505
1506 void QtPLWidget::getPlotParameters( double & io_dXFact, double & io_dYFact, double & io_dXOffset, double & io_dYOffset )
1507 {
1508 double w = (double) width();
1509 double h = (double) height();
1510 if ( w / h > m_dAspectRatio ) //Too wide, h is the limitating factor
1511 {
1512 io_dYFact = h / m_dHeight;
1513 io_dXFact = h * m_dAspectRatio / m_dWidth;
1514 io_dYOffset = 0.;
1515 io_dXOffset = ( w - io_dXFact * m_dWidth ) / 2.;
1516 }
1517 else
1518 {
1519 io_dXFact = w / m_dWidth;
1520 io_dYFact = w / m_dAspectRatio / m_dHeight;
1521 io_dXOffset = 0.;
1522 io_dYOffset = ( h - io_dYFact * m_dHeight ) / 2.;
1523 }
1524 }
1525
1526 void QtPLWidget::getCursorCmd( PLGraphicsIn *ptr )
1527 {
1528 plGinInit( &gin );
1529
1530 locate_mode = 1;
1531 QApplication::setOverrideCursor( Qt::CrossCursor );
1532
1533 while ( gin.pX < 0 && locate_mode )
1534 QCoreApplication::processEvents( QEventLoop::AllEvents, 10 );
1535
1536 QApplication::restoreOverrideCursor();
1537 *ptr = gin;
1538 }
1539
1540 #endif
1541
1542 #if defined ( PLD_extqt )
1543 QtExtWidget::QtExtWidget( int i_iWidth, int i_iHeight, QWidget* parent ) :
1544 QtPLWidget( i_iWidth, i_iHeight, parent )
1545 {
1546 cursorParameters.isTracking = false;
1547 cursorParameters.cursor_x = -1.0;
1548 cursorParameters.cursor_y = -1.0;
1549 killed = false;
1550 }
1551
1552 QtExtWidget::~QtExtWidget()
1553 {
1554 killed = true;
1555 QCoreApplication::processEvents( QEventLoop::AllEvents, 10 );
1556 delete m_pixPixmap;
1557 delete m_painterP;
1558 m_pixPixmap = NULL;
1559 m_painterP = NULL;
1560 }
1561
1562 void QtExtWidget::captureMousePlotCoords( PLFLT* x, PLFLT* y )
1563 {
1564 setMouseTracking( true );
1565 cursorParameters.isTracking = true;
1566 cursorParameters.cursor_x =
1567 cursorParameters.cursor_y = -1.;
1568 do
1569 {
1570 QCoreApplication::processEvents( QEventLoop::AllEvents, 10 );
1571 } while ( cursorParameters.isTracking && !killed );
1572
1573 *x = cursorParameters.cursor_x;
1574 *y = cursorParameters.cursor_y;
1575 }
1576
1577 void QtExtWidget::mouseMoveEvent( QMouseEvent* event )
1578 {
1579 if ( !cursorParameters.isTracking )
1580 return;
1581
1582 double x_fact, y_fact, x_offset, y_offset; //Parameters to scale and center the plot on the widget
1583
1584 getPlotParameters( x_fact, y_fact, x_offset, y_offset );
1585
1586 cursorParameters.cursor_x = (PLFLT) event->x();
1587 cursorParameters.cursor_y = (PLFLT) event->y();
1588
1589 double ratio_x;
1590 double ratio_y;
1591 ratio_x = ( cursorParameters.cursor_x - x_offset ) / ( width() - 2. * x_offset );
1592 ratio_y = ( cursorParameters.cursor_y - y_offset ) / ( height() - 2. * y_offset );
1593
1594 PLFLT a, b;
1595 PLINT c;
1596 plcalc_world( ratio_x, 1. - ratio_y, &a, &b, &c );
1597
1598 if ( c < 0 )
1599 {
1600 cursorParameters.cursor_x = -1.;
1601 cursorParameters.cursor_y = -1.;
1602 }
1603
1604 update();
1605 }
1606
1607 void QtExtWidget::mousePressEvent( QMouseEvent* /* event */ )
1608 {
1609 }
1610
1611 void QtExtWidget::mouseReleaseEvent( QMouseEvent* event )
1612 {
1613 if ( !cursorParameters.isTracking )
1614 return;
1615
1616 double x_fact, y_fact, x_offset, y_offset; //Parameters to scale and center the plot on the widget
1617
1618 getPlotParameters( x_fact, y_fact, x_offset, y_offset );
1619
1620 cursorParameters.cursor_x = (PLFLT) event->x();
1621 cursorParameters.cursor_y = (PLFLT) event->y();
1622 cursorParameters.isTracking = false;
1623 setMouseTracking( false );
1624
1625 double ratio_x;
1626 double ratio_y;
1627 ratio_x = ( cursorParameters.cursor_x - x_offset ) / ( width() - 2. * x_offset );
1628 ratio_y = ( cursorParameters.cursor_y - y_offset ) / ( height() - 2. * y_offset );
1629
1630 PLFLT a, b;
1631 PLINT c;
1632 plcalc_world( ratio_x, 1. - ratio_y, &a, &b, &c );
1633
1634 if ( c < 0 )
1635 {
1636 cursorParameters.cursor_x = -1.;
1637 cursorParameters.cursor_y = -1.;
1638 }
1639 else
1640 {
1641 cursorParameters.cursor_x = a;
1642 cursorParameters.cursor_y = b;
1643 }
1644
1645 update();
1646 }
1647
1648 void QtExtWidget::paintEvent( QPaintEvent* event )
1649 {
1650 QtPLWidget::paintEvent( event );
1651
1652 if ( !cursorParameters.isTracking || cursorParameters.cursor_x < 0 )
1653 return;
1654
1655 QPainter p( this );
1656
1657 p.setPen( QPen( Qt::white ) );
1658
1659 p.drawLine( (int) cursorParameters.cursor_x, 0, (int) cursorParameters.cursor_x, height() );
1660 p.drawLine( 0, (int) cursorParameters.cursor_y, width(), (int) cursorParameters.cursor_y );
1661
1662 p.end();
1663 }
1664
1665 void plsetqtdev( QtExtWidget* widget )
1666 {
1667 plsc->dev = (void *) widget;
1668 widget->setPLStream( plsc );
1669 }
1670
1671 void plsetqtdev( QtExtWidget* widget, int argc, char** argv )
1672 {
1673 plparseopts( &argc, argv, PL_PARSE_FULL );
1674 plsc->dev = (void *) widget;
1675 widget->setPLStream( plsc );
1676 }
1677
1678 void plfreeqtdev()
1679 {
1680 delete ( (QtExtWidget *) plsc->dev );
1681 plsc->dev = NULL;
1682 }
1683 #endif
QtPLDriver::drawPolygon
virtual void drawPolygon(short *x, short *y, PLINT npts)
Definition: plqt.cpp:139
plP_script_scale
void plP_script_scale(PLBOOL ifupper, PLINT *level, PLFLT *old_scale, PLFLT *scale, PLFLT *old_offset, PLFLT *offset)
Definition: plsym.c:1302
argv
static char ** argv
Definition: qt.cpp:49
plgesc
void plgesc(char *p_esc)
Definition: plcore.c:3914
plexit
void plexit(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1958
MasterHandler::MasterHandler
MasterHandler()
Definition: plqt.cpp:34
MasterHandler::MasterClosed
void MasterClosed()
Definition: moc_qt.cpp:142
EscText::just
PLFLT just
Definition: plplotP.h:708
plP_fci2hex
void plP_fci2hex(PLUNICODE fci, unsigned char *phexdigit, unsigned char hexpower)
Definition: plcore.c:3958
QtPLDriver::setColor
virtual void setColor(int r, int g, int b, double alpha)
Definition: plqt.cpp:442
QtPLDriver::getTextPicture
QPicture getTextPicture(PLUNICODE fci, PLUNICODE *text, int len, PLFLT chrht)
Definition: plqt.cpp:246
PLUNICODE
PLUINT PLUNICODE
Definition: plplot.h:201
argc
static int argc
Definition: qt.cpp:48
plGinInit
void plGinInit(PLGraphicsIn *gin)
Definition: plctrl.c:2887
plTranslateCursor
PLINT plTranslateCursor(PLGraphicsIn *plg)
Definition: plpage.c:259
PLStream::diorot
PLFLT diorot
Definition: plstrm.h:661
plparseopts
#define plparseopts
Definition: plplot.h:778
QtPLDriver::~QtPLDriver
virtual ~QtPLDriver()
Definition: plqt.cpp:75
MasterHandler
Definition: qt.h:96
QtPLDriver::drawPolyline
virtual void drawPolyline(short *x, short *y, PLINT npts)
Definition: plqt.cpp:125
PLINT
int PLINT
Definition: plplot.h:181
QtPLDriver::drawArc
virtual void drawArc(short x, short y, short width, short height, PLFLT angle1, PLFLT angle2, PLFLT rotate, bool fill)
Definition: plqt.cpp:84
MasterHandler::DeviceClosed
void DeviceClosed(QtPLDriver *d)
Definition: plqt.cpp:57
plcalc_world
#define plcalc_world
Definition: plplot.h:700
QtPLDriver::mutex
static QMutex mutex
Definition: qt.h:144
MasterHandler::masterDevice
QtPLDriver * masterDevice
Definition: qt.h:113
EscText
Definition: plplotP.h:699
PLStream::clpymi
PLINT clpymi
Definition: plstrm.h:704
fileName
static const char * fileName
Definition: tkMain.c:134
line
static struct line line[]
TRUE
#define TRUE
Definition: plplotP.h:176
FALSE
#define FALSE
Definition: plplotP.h:177
QtPLDriver::drawText
virtual void drawText(EscText *txt)
Definition: plqt.cpp:391
RISE_FACTOR
#define RISE_FACTOR
Definition: plqt.cpp:244
PL_FCI_STYLE
#define PL_FCI_STYLE
Definition: plplot.h:377
MasterHandler::DeviceChangedPage
void DeviceChangedPage(QtPLDriver *d)
Definition: plqt.cpp:49
PLStream::get_string_length
PLINT get_string_length
Definition: plstrm.h:787
MasterHandler::MasterChangedPage
void MasterChangedPage()
Definition: moc_qt.cpp:136
pltext
#define pltext
Definition: plplot.h:855
MasterHandler::setMasterDevice
void setMasterDevice(QtPLDriver *d)
Definition: plqt.cpp:44
PLStream::clpxmi
PLINT clpxmi
Definition: plstrm.h:704
pls
static PLStream * pls[PL_NSTREAMS]
Definition: plcore.h:88
QtPLDriver::QtPLDriver
QtPLDriver(PLINT i_iWidth=QT_DEFAULT_X, PLINT i_iHeight=QT_DEFAULT_Y)
Definition: plqt.cpp:69
plgfci
#define plgfci
Definition: plplot.h:735
plRotationShear
void plRotationShear(PLFLT *xFormMatrix, PLFLT *rotation, PLFLT *shear, PLFLT *stride)
Definition: plot3d.c:2767
LINE
#define LINE
Definition: metadefs.h:61
qt.h
QtPLDriver::setWidthF
virtual void setWidthF(PLFLT w)
Definition: plqt.cpp:483
QtPLDriver
Definition: qt.h:117
EscText::unicode_array_len
unsigned short unicode_array_len
Definition: plplotP.h:736
PLStream
Definition: plstrm.h:523
text
static int text
Definition: ps.c:77
QtPLDriver::setGradient
virtual void setGradient(int x1, int x2, int y1, int y2, unsigned char *r, unsigned char *g, unsigned char *b, PLFLT *alpha, PLINT ncol1)
Definition: plqt.cpp:457
QtPLDriver::drawLine
virtual void drawLine(short x1, short y1, short x2, short y2)
Definition: plqt.cpp:112
PL_UNUSED
#define PL_UNUSED(x)
Definition: plplot.h:138
PLFLT
float PLFLT
Definition: plplot.h:163
PL_PARSE_FULL
#define PL_PARSE_FULL
Definition: plplot.h:359
POINTS_PER_INCH
#define POINTS_PER_INCH
Definition: svg.c:42
PL_FCI_FAMILY
#define PL_FCI_FAMILY
Definition: plplot.h:376
PLStream::chrht
PLFLT chrht
Definition: plstrm.h:686
PL_FCI_WEIGHT
#define PL_FCI_WEIGHT
Definition: plplot.h:378
QtPLDriver::drawTextInPicture
void drawTextInPicture(QPainter *, const QString &)
Definition: plqt.cpp:203
QtPLDriver::setSolid
virtual void setSolid()
Definition: plqt.cpp:508
PLDLLIMPEXP_QT_DATA
PLDLLIMPEXP_QT_DATA(int) vectorize=0
PLStream::nopause
PLINT nopause
Definition: plstrm.h:568
EscText::y
PLINT y
Definition: plplotP.h:713
PLStream::clpxma
PLINT clpxma
Definition: plstrm.h:704
POLYLINE
#define POLYLINE
Definition: metadefs.h:65
EscText::x
PLINT x
Definition: plplotP.h:712
PLStream::string_length
PLFLT string_length
Definition: plstrm.h:786
QtPLDriver::getFont
QFont getFont(PLUNICODE code)
Definition: plqt.cpp:157
EscText::unicode_array
PLUNICODE * unicode_array
Definition: plplotP.h:735
M_PI
#define M_PI
Definition: plplotP.h:119
QtPLDriver::setPLStream
void setPLStream(PLStream *pls)
Definition: plqt.cpp:79
plgra
#define plgra
Definition: plplot.h:740
EscText::xform
PLFLT * xform
Definition: plplotP.h:709
plcallback::fill
PLDLLIMPEXP_CXX void fill(PLINT n, const PLFLT *x, const PLFLT *y)
Definition: plstream.cc:246
MasterHandler::isMasterDevice
bool isMasterDevice(QtPLDriver *d)
Definition: plqt.cpp:39
PLStream::clpyma
PLINT clpyma
Definition: plstrm.h:704
PL_FCI_MARK
#define PL_FCI_MARK
Definition: plplot.h:370
PLGraphicsIn
Definition: plplot.h:433