1 // 2 // 3 // This software is provided under the LGPL in March 2009 by the 4 // Cluster Science Centre 5 // QSAS team, 6 // Imperial College, London 7 // 8 // Copyright (C) 2009 Imperial College, London 9 // Copyright (C) 2009-2016 Alan W. Irwin 10 // 11 // This is free software; you can redistribute it and/or modify 12 // it under the terms of the GNU General Lesser Public License as published 13 // by the Free Software Foundation; either version 2 of the License, or 14 // (at your option) any later version. 15 // 16 // This software is distributed in the hope that it will be useful, 17 // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 // GNU Lesser General Public License for more details. 20 // 21 // To received a copy of the GNU Library General Public License 22 // write to the Free Software Foundation, Inc., 23 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 24 // 25 // History: 26 // 27 // 28 // March 2009: v1.00 29 // Initial release. 30 // 31 // 32 33 // 34 // Interpretation of the -geometry XSIZExYSIZE option (or the third and fourth 35 // parameters of plspage if those are specified by the user instead) for 36 // the various devices: 37 // - the raster devices (bmpqt, jpgqt, pngqt, ppmqt, tiffqt): 38 // XSIZE and YSIZE define the x and y size in pixels 39 // - qtwidget: 40 // XSIZE and YSIZE define the default x and y size of the widget in 41 // pixels, as well as its aspect ratio, which is kept when the widget is 42 // resized. 43 // - svgqt, epsqt, pdfqt: 44 // XSIZE and YSIZE define the x and y size in points (1/72 of inches). 45 // EPS and PDF files will be drawn in A4 pages for Qt versions before 4.4 46 // 47 // Interpretation of the -dpi DPI option (or the first parameter of 48 // plspage if that is specified by the user instead). 49 // DPI is ignored for all but the raster devices. For those devices 50 // DPI should be set to the DPI value of the monitor being used to view 51 // the results if exact character sizes are desired. Otherwise, DEFAULT_DPI 52 // (set to an average value for modern monitors) is used instead. 53 // 54 55 #ifndef QT_H 56 #define QT_H 57 58 #include <iostream> 59 #include <QImage> 60 #include <QPainter> 61 #include <QLinkedList> 62 #include <QPrinter> 63 #include <QApplication> 64 #include <QWidget> 65 #include <QMouseEvent> 66 #include <QTabWidget> 67 #include <QMainWindow> 68 #include <QPicture> 69 #include <QMutex> 70 71 #include "plDevs.h" 72 #include "plplotP.h" 73 #include "drivers.h" 74 75 // Used for devices (epsqt, pdfqt, svgqt) with known physical size in points. 76 #define POINTS_PER_INCH 72 77 78 // Average value of dots per inch assumed for modern monitors if the user 79 // does not specify a value appropriate to their monitor with plspage or 80 // the -dpi option. Used only for devices with size specified in pixels 81 // but not qtwidget since it has independent access to information (e.g., 82 // delivered by X) about the DPI of the monitor. So this value is only 83 // used for the raster devices (bmpqt, jpgqt, pngqt, ppmqt, tiffqt). 84 #define DEFAULT_DPI 72 85 86 // These values are in units of pixels (the raster devices and qtwidget) 87 // or points (epsqt, pdfqt, svgqt). In the points case, this corresponds 88 // to the A4 paper size. 89 #define QT_DEFAULT_X 842 90 #define QT_DEFAULT_Y 595 91 92 class QtPLDriver; 93 94 // Master Device Handler for multiple streams 95 // Only handles multiple Qt devices 96 class PLDLLIMPEXP_QT MasterHandler : public QObject 97 { 98 Q_OBJECT 99 100 public: 101 MasterHandler(); 102 103 bool isMasterDevice( QtPLDriver* d ); 104 void setMasterDevice( QtPLDriver* d ); 105 void DeviceChangedPage( QtPLDriver* d ); 106 void DeviceClosed( QtPLDriver* d ); 107 108 signals: 109 void MasterChangedPage(); 110 void MasterClosed(); 111 112 protected: 113 QtPLDriver* masterDevice; 114 }; 115 116 // Basic class, offering the common interface to all Qt plplot devices 117 class PLDLLIMPEXP_QT QtPLDriver 118 { 119 public: 120 // Constructor, taking the device size as arguments 121 QtPLDriver( PLINT i_iWidth = QT_DEFAULT_X, PLINT i_iHeight = QT_DEFAULT_Y ); 122 123 virtual ~QtPLDriver(); // does not delete emitter! 124 125 void setPLStream( PLStream *pls ); // store the related stream 126 127 virtual void drawArc( short x, short y, short width, short height, PLFLT angle1, PLFLT angle2, PLFLT rotate, bool fill ); 128 // Draws a line from (x1, y1) to (x2, y2) in internal plplot coordinates 129 virtual void drawLine( short x1, short y1, short x2, short y2 ); 130 virtual void drawPolyline( short * x, short * y, PLINT npts ); 131 virtual void drawPolygon( short * x, short * y, PLINT npts ); 132 virtual void drawText( EscText* txt ); 133 virtual void setColor( int r, int g, int b, double alpha ); setBackgroundColor(int,int,int,double)134 virtual void setBackgroundColor( int /* r */, int /* g */, int /* b */, double /* alpha */ ){} 135 virtual void setGradient( int x1, int x2, int y1, int y2, 136 unsigned char *r, unsigned char *g, 137 unsigned char *b, PLFLT *alpha, PLINT ncol1 ); 138 virtual void setWidthF( PLFLT w ); 139 // Set pen to draw solid strokes (called after drawing dashed strokes) 140 virtual void setSolid(); 141 // Conversion factor from internal plplot coordinates to device coordinates 142 double downscale; 143 double m_dWidth, m_dHeight; 144 static QMutex mutex; // All-purpose mutex 145 146 protected: 147 // Returns font with the good size for a QPicture's resolution 148 QFont getFont( PLUNICODE code ); 149 // Draws text in a QPicture using a sub-QPicture (!), updates the current xOffset 150 void drawTextInPicture( QPainter*, const QString& ); 151 // Gets the QPicture displaying text, with the base chrht char height 152 QPicture getTextPicture( PLUNICODE fci, PLUNICODE* text, int len, PLFLT chrht ); 153 154 // Text-related variables 155 bool underlined; 156 bool overlined; 157 double currentFontScale; 158 double currentFontSize; 159 double yOffset; 160 double xOffset; 161 162 PLStream *pls; 163 164 QPainter * m_painterP; 165 }; 166 167 #if defined ( PLD_bmpqt ) || defined ( PLD_jpgqt ) || defined ( PLD_pngqt ) || defined ( PLD_ppmqt ) || defined ( PLD_tiffqt ) || defined ( PLD_memqt ) 168 // Driver painting whatever raster format Qt can save 169 class PLDLLIMPEXP_QT QtRasterDevice : public QtPLDriver, public QImage 170 { 171 public: 172 QtRasterDevice( int i_iWidth = QT_DEFAULT_X, 173 int i_iHeight = QT_DEFAULT_Y ); 174 virtual ~QtRasterDevice(); 175 176 virtual void setBackgroundColor( int r, int g, int b, double alpha ); 177 void definePlotName( const char* fileName, const char* format ); 178 void savePlot(); setResolution(double dotsPerInch)179 virtual void setResolution( double dotsPerInch ) 180 { 181 setDotsPerMeterX( (int) ( ( dotsPerInch / 25.4 ) * 1000. ) ); 182 setDotsPerMeterY( (int) ( ( dotsPerInch / 25.4 ) * 1000. ) ); 183 } 184 // used by the memqt driver 185 unsigned char *memory; 186 187 protected: 188 char format[5]; 189 QString fileName; 190 }; 191 #endif 192 193 #if defined ( PLD_svgqt ) && QT_VERSION >= 0x040300 194 #include <QSvgGenerator> 195 // Driver painting on an SVG device 196 class PLDLLIMPEXP_QT QtSVGDevice : public QtPLDriver, public QSvgGenerator 197 { 198 public: 199 QtSVGDevice( int i_iWidth = QT_DEFAULT_X, 200 int i_iHeight = QT_DEFAULT_Y ); 201 202 virtual ~QtSVGDevice(); 203 204 virtual void setBackgroundColor( int r, int g, int b, double alpha ); 205 void definePlotName( const char* fileName ); 206 void savePlot(); 207 208 protected: 209 }; 210 #endif 211 212 #if defined ( PLD_epsqt ) || defined ( PLD_pdfqt ) 213 // Driver painting on an EPS or PDF device, uses QPrinter 214 // A (possibly dummy) QApplication must be declared before use 215 class PLDLLIMPEXP_QT QtEPSDevice : public QtPLDriver, public QPrinter 216 { 217 public: 218 #if QT_VERSION < 0x040400 219 QtEPSDevice( int i_iWidth = -1, int i_iHeight = -1 ); 220 #else 221 QtEPSDevice( int i_iWidth = QT_DEFAULT_X, int i_iHeight = QT_DEFAULT_Y ); 222 #endif 223 224 virtual ~QtEPSDevice(); 225 226 virtual void setBackgroundColor( int r, int g, int b, double alpha ); 227 void definePlotName( const char* fileName, int ifeps ); 228 void savePlot(); 229 230 protected: 231 }; 232 #endif 233 234 #if defined ( PLD_qtwidget ) || defined ( PLD_extqt ) 235 236 typedef enum ElementType_ 237 { 238 LINE, 239 POLYLINE, 240 POLYGON, 241 RECTANGLE, 242 SET_WIDTH, 243 SET_COLOUR, 244 SET_GRADIENT, 245 SET_SMOOTH, 246 TEXT, 247 SET_BG_COLOUR, 248 ARC 249 } ElementType; // Identifiers for elements of the buffer 250 251 struct ColourStruct_ 252 { 253 PLINT R, G, B, A; 254 }; 255 256 struct TextStruct_ 257 { 258 PLFLT x; 259 PLFLT y; 260 PLFLT clipxmin; 261 PLFLT clipymin; 262 PLFLT clipxmax; 263 PLFLT clipymax; 264 PLFLT rotation; 265 PLFLT shear; 266 PLFLT stride; 267 PLFLT just; 268 PLUNICODE * text; 269 PLUNICODE fci; 270 PLINT len; 271 PLFLT chrht; 272 }; 273 274 struct ArcStruct_ 275 { 276 QRectF *rect; 277 QPointF *dx; 278 int startAngle; 279 int spanAngle; 280 PLFLT rotate; 281 bool fill; 282 }; 283 284 class BufferElement 285 { 286 public: 287 ElementType Element; 288 289 union DataType 290 { 291 QLineF * Line; 292 QPolygonF * Polyline; 293 QRectF * Rect; 294 QLinearGradient * LinearGradient; 295 struct ColourStruct_* ColourStruct; 296 struct TextStruct_ * TextStruct; 297 struct ArcStruct_ * ArcStruct; 298 PLINT intParam; 299 PLFLT fltParam; 300 } Data; 301 }; 302 303 // This widget allows to use plplot as a plotting engine in a Qt 304 // Application. The aspect ratio of the plotted data is constant, so 305 // gray strips are used to delimit the page when the widget aspect 306 // ratio is not the one of the plotted page. 307 308 // N.B. The moc application assumes that the first inherited class and 309 // only that inherited class is a subclass of QObject. Therefore, 310 // Qwidget (a subclass of QObject) must be first. 311 class PLDLLIMPEXP_QT QtPLWidget : public QWidget, public QtPLDriver 312 { 313 Q_OBJECT 314 315 public: 316 // Parameters are the actual size of the page, NOT the size of the widget 317 // Call QWidget::resize for that 318 QtPLWidget( int i_iWidth = QT_DEFAULT_X, int i_iHeight = QT_DEFAULT_Y, QWidget * parent = 0 ); 319 320 virtual ~QtPLWidget(); 321 322 void clearWidget(); 323 void clearBuffer(); 324 325 int pageNumber; 326 327 void drawArc( short x, short y, short width, short height, PLFLT angle1, PLFLT angle2, PLFLT rotate, bool fill ); 328 void drawLine( short x1, short y1, short x2, short y2 ); 329 void drawPolyline( short * x, short * y, PLINT npts ); 330 void drawPolygon( short * x, short * y, PLINT npts ); 331 void setColor( int r, int g, int b, double alpha ); 332 void setBackgroundColor( int r, int g, int b, double alpha ); 333 void setGradient( int x1, int x2, int y1, int y2, 334 unsigned char *r, unsigned char *g, 335 unsigned char *b, PLFLT *alpha, PLINT ncol1 ); 336 void setWidthF( PLFLT r ); 337 void drawText( EscText* txt ); 338 void flush(); 339 void getCursorCmd( PLGraphicsIn *ptr ); 340 341 protected: 342 343 void resizeEvent( QResizeEvent* ); 344 void paintEvent( QPaintEvent* ); 345 void mouseEvent( QMouseEvent * event ); 346 347 void getPlotParameters( double & io_dXFact, double & io_dYFact, double & io_dXOffset, double & io_dYOffset ); // gives the parameters to scale and center the plot on the page 348 void doPlot( QPainter* p, double x_fact, double y_fact, double x_offset, double y_offset ); // Actually draws the plot. Deported in a function for readability 349 void renderText( QPainter* p, struct TextStruct_* s, double x_fact, double x_offset, double y_fact, double y_offset ); 350 void lookupButtonEvent( QMouseEvent * event ); 351 void locate(); 352 353 void resetPensAndBrushes( QPainter* ); 354 355 double m_dAspectRatio; // Is kept constant during resizes 356 QPixmap * m_pixPixmap; // stores the drawn image as long as it does not have to be regenerated 357 358 QLinkedList<BufferElement> m_listBuffer; // Buffer holding the draw instructions 359 // bool m_bAwaitingRedraw; 360 // int m_iOldSize; // Holds the size of the buffer. Modified => image has to be redrawn 361 bool redrawFromLastFlush; 362 bool redrawAll; 363 364 // Pens and brushes required to maintain the status between 2 flushes 365 QPen SolidPen; 366 QPen NoPen; 367 bool hasPen; 368 QBrush SolidBrush; 369 // end parameters 370 371 QLinkedList<BufferElement>::const_iterator start_iterator; 372 373 struct 374 { 375 int r; 376 int g; 377 int b; 378 double alpha; 379 } lastColour; 380 381 struct 382 { 383 int r; 384 int g; 385 int b; 386 double alpha; 387 } bgColour; 388 389 PLGraphicsIn gin; // Graphics Input Structure 390 int locate_mode; // Set while in locate mode 391 392 protected slots: 393 void mousePressEvent( QMouseEvent * event ); 394 void mouseReleaseEvent( QMouseEvent * event ); 395 void mouseMoveEvent( QMouseEvent * event ); 396 void keyPressEvent( QKeyEvent* event ); 397 void closeEvent( QCloseEvent* event ); 398 void nextPage(); 399 }; 400 401 #endif 402 403 #if defined ( PLD_extqt ) 404 class PLDLLIMPEXP_QT QtExtWidget : public QtPLWidget 405 { 406 Q_OBJECT 407 408 public: 409 QtExtWidget( int i_iWidth = QT_DEFAULT_X, int i_iHeight = QT_DEFAULT_Y, QWidget * parent = 0 ); 410 411 virtual ~QtExtWidget(); 412 413 void captureMousePlotCoords( PLFLT* x, PLFLT* y ); 414 415 public slots: 416 417 void mouseMoveEvent( QMouseEvent* event ); 418 void mouseReleaseEvent( QMouseEvent* event ); 419 void mousePressEvent( QMouseEvent* event ); 420 421 protected: 422 void paintEvent( QPaintEvent* ); 423 424 struct 425 { 426 bool isTracking; 427 double cursor_x, cursor_y; 428 } cursorParameters; 429 430 bool killed; 431 }; 432 433 PLDLLIMPEXP_QT void plsetqtdev( QtExtWidget* widget ); // Registers the widget as plot device, as the widget has to be created in the Qt application GUI, prior to any plplot call. Must be called before plinit(). 434 435 PLDLLIMPEXP_QT void plsetqtdev( QtExtWidget* widget, int argc, char** argv ); // Registers the widget as plot device, as the widget has to be created in the Qt application GUI, prior to any plplot call. Must be called before plinit(). 436 437 PLDLLIMPEXP_QT void plfreeqtdev(); // Deletes and unregisters the device. 438 439 #endif 440 441 // These variables are declared in plqt.cpp but also needed 442 // by the qt driver. 443 extern PLDLLIMPEXP_QT_DATA( int ) vectorize; 444 extern PLDLLIMPEXP_QT_DATA( int ) lines_aa; 445 extern PLDLLIMPEXP_QT_DATA( MasterHandler ) handler; 446 447 #if defined ( plplot_pyqt4_EXPORTS ) 448 #define initplplot_pyqt4 PLDLLIMPEXP_PYQT4 initplplot_pyqt4 449 #endif 450 451 #if defined ( plplot_pyqt5_EXPORTS ) 452 #define initplplot_pyqt5 PLDLLIMPEXP_PYQT5 initplplot_pyqt5 453 #endif 454 455 #endif 456