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