PLplot: plqt.cpp Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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