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