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;
31 
32 // Master Device Handler for multiple streams
33 // Only handles multiple Qt devices
35 {
36  masterDevice = NULL;
37 }
38 
40 {
41  return d == masterDevice;
42 }
43 
45 {
46  masterDevice = d;
47 }
48 
50 {
51  if ( d == masterDevice )
52  {
53  emit MasterChangedPage();
54  }
55 }
56 
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 
76 {
77 }
78 
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 
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 
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 
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 
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
virtual void drawPolygon(short *x, short *y, PLINT npts)
Definition: plqt.cpp:139
void plP_script_scale(PLBOOL ifupper, PLINT *level, PLFLT *old_scale, PLFLT *scale, PLFLT *old_offset, PLFLT *offset)
Definition: plsym.c:1302
static char ** argv
Definition: qt.cpp:49
void plgesc(char *p_esc)
Definition: plcore.c:3914
void plexit(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1958
MasterHandler()
Definition: plqt.cpp:34
void MasterClosed()
Definition: moc_qt.cpp:142
PLFLT just
Definition: plplotP.h:708
void plP_fci2hex(PLUNICODE fci, unsigned char *phexdigit, unsigned char hexpower)
Definition: plcore.c:3958
virtual void setColor(int r, int g, int b, double alpha)
Definition: plqt.cpp:442
QPicture getTextPicture(PLUNICODE fci, PLUNICODE *text, int len, PLFLT chrht)
Definition: plqt.cpp:246
PLUINT PLUNICODE
Definition: plplot.h:201
static int argc
Definition: qt.cpp:48
void plGinInit(PLGraphicsIn *gin)
Definition: plctrl.c:2887
PLINT plTranslateCursor(PLGraphicsIn *plg)
Definition: plpage.c:259
PLFLT diorot
Definition: plstrm.h:661
#define plparseopts
Definition: plplot.h:778
virtual ~QtPLDriver()
Definition: plqt.cpp:75
virtual void drawPolyline(short *x, short *y, PLINT npts)
Definition: plqt.cpp:125
int PLINT
Definition: plplot.h:181
virtual void drawArc(short x, short y, short width, short height, PLFLT angle1, PLFLT angle2, PLFLT rotate, bool fill)
Definition: plqt.cpp:84
void DeviceClosed(QtPLDriver *d)
Definition: plqt.cpp:57
#define plcalc_world
Definition: plplot.h:700
static QMutex mutex
Definition: qt.h:144
QtPLDriver * masterDevice
Definition: qt.h:113
PLINT clpymi
Definition: plstrm.h:704
static const char * fileName
Definition: tkMain.c:134
static struct line line[]
#define TRUE
Definition: plplotP.h:176
#define FALSE
Definition: plplotP.h:177
virtual void drawText(EscText *txt)
Definition: plqt.cpp:391
#define RISE_FACTOR
Definition: plqt.cpp:244
#define PL_FCI_STYLE
Definition: plplot.h:377
void DeviceChangedPage(QtPLDriver *d)
Definition: plqt.cpp:49
PLINT get_string_length
Definition: plstrm.h:787
void MasterChangedPage()
Definition: moc_qt.cpp:136
#define pltext
Definition: plplot.h:855
void setMasterDevice(QtPLDriver *d)
Definition: plqt.cpp:44
PLINT clpxmi
Definition: plstrm.h:704
static PLStream * pls[PL_NSTREAMS]
Definition: plcore.h:88
QtPLDriver(PLINT i_iWidth=QT_DEFAULT_X, PLINT i_iHeight=QT_DEFAULT_Y)
Definition: plqt.cpp:69
#define plgfci
Definition: plplot.h:735
void plRotationShear(PLFLT *xFormMatrix, PLFLT *rotation, PLFLT *shear, PLFLT *stride)
Definition: plot3d.c:2767
#define LINE
Definition: metadefs.h:61
virtual void setWidthF(PLFLT w)
Definition: plqt.cpp:483
Definition: qt.h:117
unsigned short unicode_array_len
Definition: plplotP.h:736
static int text
Definition: ps.c:77
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
virtual void drawLine(short x1, short y1, short x2, short y2)
Definition: plqt.cpp:112
#define PL_UNUSED(x)
Definition: plplot.h:138
float PLFLT
Definition: plplot.h:163
#define PL_PARSE_FULL
Definition: plplot.h:359
#define POINTS_PER_INCH
Definition: svg.c:42
#define PL_FCI_FAMILY
Definition: plplot.h:376
PLFLT chrht
Definition: plstrm.h:686
#define PL_FCI_WEIGHT
Definition: plplot.h:378
void drawTextInPicture(QPainter *, const QString &)
Definition: plqt.cpp:203
virtual void setSolid()
Definition: plqt.cpp:508
PLDLLIMPEXP_QT_DATA(int) vectorize=0
PLINT nopause
Definition: plstrm.h:568
PLINT y
Definition: plplotP.h:713
PLINT clpxma
Definition: plstrm.h:704
#define POLYLINE
Definition: metadefs.h:65
PLINT x
Definition: plplotP.h:712
PLFLT string_length
Definition: plstrm.h:786
QFont getFont(PLUNICODE code)
Definition: plqt.cpp:157
PLUNICODE * unicode_array
Definition: plplotP.h:735
#define M_PI
Definition: plplotP.h:119
void setPLStream(PLStream *pls)
Definition: plqt.cpp:79
#define plgra
Definition: plplot.h:740
PLFLT * xform
Definition: plplotP.h:709
PLDLLIMPEXP_CXX void fill(PLINT n, const PLFLT *x, const PLFLT *y)
Definition: plstream.cc:246
bool isMasterDevice(QtPLDriver *d)
Definition: plqt.cpp:39
PLINT clpyma
Definition: plstrm.h:704
#define PL_FCI_MARK
Definition: plplot.h:370