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