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