1 /* Copyright (C) 2000  The PARI group.
2 
3 This file is part of the PARI/GP package.
4 
5 PARI/GP is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 2 of the License, or (at your option) any later
8 version. It is distributed in the hope that it will be useful, but WITHOUT
9 ANY WARRANTY WHATSOEVER.
10 
11 Check the License for details. You should have received a copy of it, along
12 with the package; see the file 'COPYING'. If not, write to the Free Software
13 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14 /////////////////////////////////////////////////////////////////////////////
15 //
16 //  High resolution plot using Trolltech's Qt library
17 //
18 //  You may possibly want to use this file with a "Qt Free Edition"
19 //  which is distributed under the terms of the Q PUBLIC LICENSE (QPL),
20 //  or with a "Qt/Embedded Free Edition" which is
21 //  distributed under the terms of the GNU General Public License (GPL).
22 //  Please check http://www.trolltech.com for details.
23 //
24 //                            ---Nils-Peter Skoruppa (www.countnumber.de)
25 /////////////////////////////////////////////////////////////////////////////
26 #include <Qt/qapplication.h>
27 #include <Qt/qwidget.h>
28 #include <Qt/qpainter.h>
29 #include <Qt/qcolor.h>
30 #include <Qt/qdesktopwidget.h>
31 #include <Qt/qevent.h>
32 #include <Qt/qpixmap.h>
33 #include <Qt/qsignalmapper.h>
34 #include <Qt/qimage.h>
35 #include <Qt/qimagewriter.h>
36 #include <Qt/qmainwindow.h>
37 #include <Qt/qmenubar.h>
38 #include <Qt/qtoolbar.h>
39 #include <Qt/qaction.h>
40 #include <Qt/qfiledialog.h>
41 #include <Qt/qmessagebox.h>
42 #include <Qt/qfile.h>
43 #include <Qt/qstatusbar.h>
44 #include <Qt/qimage.h>
45 #include <Qt/qlabel.h>
46 #include <Qt/qspinbox.h>
47 #include <Qt/qlayout.h>
48 
49 extern "C" {
50 #include "pari.h"
51 #include "rect.h"
52 #undef grem
53 }
54 
55 using namespace Qt;
56 
57 class Plotter: public QWidget {
58 
59   Q_OBJECT
60 
61 signals:
62   void clicked();
63 
64 protected:
65   void mouseReleaseEvent(QMouseEvent*);
66 
67 public:
68   Plotter(PARI_plot *T, GEN w, GEN x, GEN y, QWidget* parent = 0);
69   void save(const QString& s = *plotFile + ".xpm",
70             const QString& f = QString("XPM"));
71 
72 protected:
73   void paintEvent(QPaintEvent *);
74 
75 private:
76   PARI_plot *T;
77   GEN w, x, y;
78   QColor color0;
79   QFont font;
80   static QString *plotFile;
81   void draw(QPainter *p);
82 };
83 
84 QString *Plotter::plotFile = new QString("pariplot");
85 
86 static QColor
rgb_color(long c)87 rgb_color(long c)
88 {
89   int r, g, b; long_to_rgb(c, &r, &g, &b);
90   return QColor(r, g, b);
91 }
Plotter(PARI_plot * T,GEN w,GEN x,GEN y,QWidget * parent)92 Plotter::Plotter(PARI_plot *T, GEN w, GEN x, GEN y, QWidget* parent)
93     : QWidget(parent), font("lucida", 9) {
94   this->w = w;
95   this->x = x;
96   this->y = y;
97   this->T = T;
98   this->setFont(font);
99   {
100     int r, g, b;
101     color_to_rgb(gel(GP_DATA->colormap,1), &r, &g, &b);
102     color0 = QColor(r, g, b);
103   }
104   QPalette palette;
105   palette.setColor(backgroundRole(), color0);
106   setPalette(palette);
107 }
108 
109 static void
SetForeground(void * data,long col)110 SetForeground(void *data, long col)
111 {
112   QPainter *p = (QPainter *)data;
113   p->setPen(rgb_color(col));
114 }
115 
116 static void
DrawPoint(void * data,long x,long y)117 DrawPoint(void *data, long x, long y)
118 {
119   QPainter *p = (QPainter *)data;
120   p->drawPoint(x, y);
121 }
122 
123 static void
DrawLine(void * data,long x1,long y1,long x2,long y2)124 DrawLine(void *data, long x1, long y1, long x2, long y2)
125 {
126   QPainter *p = (QPainter *)data;
127   p->drawLine(x1, y1, x2, y2);
128 }
129 
130 static void
DrawRectangle(void * data,long x,long y,long w,long h)131 DrawRectangle(void *data, long x, long y, long w, long h)
132 {
133   QPainter *p = (QPainter *)data;
134   p->drawRect(x, y, w, h);
135 }
136 
137 static void
FillRectangle(void * data,long x,long y,long w,long h)138 FillRectangle(void *data, long x, long y, long w, long h)
139 {
140   QPainter *p = (QPainter *)data;
141   p->fillRect(x, y, w, h, p->pen().color());
142 }
143 
144 static void
DrawPoints(void * data,long nb,struct plot_points * pt)145 DrawPoints(void *data, long nb, struct plot_points *pt)
146 {
147   QPainter *p = (QPainter *)data;
148   QPolygon xp = QPolygon(nb);
149   long i;
150   for (i = 0;i < nb; i++) xp.setPoint(i,pt[i].x, pt[i].y);
151   p->drawPoints(xp);
152 }
153 
154 static void
DrawLines(void * data,long nb,struct plot_points * pt)155 DrawLines(void *data, long nb, struct plot_points *pt)
156 {
157   QPainter *p = (QPainter *)data;
158   QPolygon xp = QPolygon(nb);
159   long i;
160   for (i = 0;i < nb; i++) xp.setPoint(i, pt[i].x, pt[i].y);
161   p->drawPolyline(xp);
162 }
163 
164 static void
DrawString(void * data,long x,long y,char * text,long numtext)165 DrawString(void *data, long x, long y, char *text, long numtext)
166 {
167   QPainter *p = (QPainter *)data;
168   p->drawText(x, y, QString(text).left(numtext));
169 }
170 
171 void
draw(QPainter * p)172 Plotter::draw(QPainter *p)
173 {
174   struct plot_eng plotQt;
175   plotQt.sc=&SetForeground;
176   plotQt.pt=&DrawPoint;
177   plotQt.ln=&DrawLine;
178   plotQt.bx=&DrawRectangle;
179   plotQt.fb=&FillRectangle;
180   plotQt.mp=&DrawPoints;
181   plotQt.mp=&DrawPoints;
182   plotQt.ml=&DrawLines;
183   plotQt.st=&DrawString;
184   plotQt.pl=T;
185   plotQt.data=(void *)p;
186   double xs = double(this->width()) / T->width;
187   double ys = double(this->height()) / T->height;
188   gen_draw(&plotQt, this->w, this->x, this->y, xs, ys);
189 }
190 
191 void
save(const QString & s,const QString & f)192 Plotter::save(const QString& s, const QString& f)
193 {
194   QPixmap pm(this->width(), this->height());
195   QPainter p;
196   p.begin(&pm);
197   p.initFrom(this);
198   p.fillRect(0, 0, pm.width(), pm.height(), color0);
199   draw(&p);
200   p.end();
201   pm.save(s, f.toAscii().data());
202 }
203 
204 void
paintEvent(QPaintEvent *)205 Plotter::paintEvent(QPaintEvent *)
206 {
207   QPainter p;
208   p.begin(this);
209   this->draw(&p);
210   p.end();
211 }
212 
mouseReleaseEvent(QMouseEvent *)213 void Plotter::mouseReleaseEvent(QMouseEvent*) { emit clicked(); }
214 
215 /* XPM */
216 static const char * const fullscreen_xpm[] = {
217 "14 14 2 1",
218 "         c None",
219 ".        c #000000",
220 "..............",
221 ".     ..     .",
222 ".     ..     .",
223 ".    ....    .",
224 ".     ..     .",
225 ".  .  ..  .  .",
226 "..............",
227 "..............",
228 ".  .  ..  .  .",
229 ".     ..     .",
230 ".    ....    .",
231 ".     ..     .",
232 ".     ..     .",
233 ".............."};
234 
235 class PlotWindow: public QMainWindow
236 {
237   Q_OBJECT
238 
239 public:
240   PlotWindow(PARI_plot *T, GEN w, GEN x, GEN y, QWidget* parent = 0);
241   ~PlotWindow();
242 
243 protected:
244   void resizeEvent(QResizeEvent *);
245 
246 private slots:
247   void fullScreen();
248   void normalView();
249   void save();
250   void save(int);
251 
252 private:
253   static const QList<QByteArray> file_formats;
254   Plotter *plr;
255   QString saveFileName;
256   int saveFileFormat;
257   QLabel *res;
258   QMenu* menuFile;
259   QMenu* menuView;
260   QMenu* menuFormat;
261   QAction* quitAction;
262   QAction* saveAction;
263   QAction* fullScreenAction;
264   QSignalMapper* signalMapper;
265   QIcon* icon;
266 };
267 
268 const QList<QByteArray> PlotWindow::file_formats = QImageWriter::supportedImageFormats();
269 
PlotWindow(PARI_plot * T,GEN w,GEN x,GEN y,QWidget * parent)270 PlotWindow::PlotWindow(PARI_plot *T, GEN w, GEN x, GEN y, QWidget* parent)
271     : QMainWindow(parent), saveFileName("pariplot"), saveFileFormat(0)
272 {
273   setWindowTitle("Pari QtPlot");
274 
275   QPalette palette;
276   palette.setColor(this->backgroundRole(), white);
277   this->setPalette(palette);
278 
279   menuFile = menuBar()->addMenu("&File");
280 
281   saveAction = new QAction("&Save",this);
282   saveAction->setShortcut(QKeySequence(CTRL+Key_S));
283   connect (saveAction, SIGNAL(triggered()), this, SLOT(save()));
284   menuFile->addAction(saveAction);
285   menuFormat = menuFile->addMenu("Save &as");
286 
287   signalMapper = new QSignalMapper(this);
288 
289   for(int i = 0; i < file_formats.count(); i++)
290   {
291     QAction* tmpAction;
292     tmpAction = new QAction(QString(file_formats.at(i)),this);
293     connect (tmpAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
294     signalMapper->setMapping(tmpAction,i);
295     menuFormat->addAction(tmpAction);
296   }
297 
298   connect (signalMapper, SIGNAL(mapped(int)), this,SLOT(save(int)));
299 
300   quitAction = new QAction("&Quit",this);
301   quitAction->setShortcut(QKeySequence(CTRL+Key_Q));
302   connect (quitAction, SIGNAL(triggered()), this, SLOT(close()));
303   menuFile->addAction(quitAction);
304 
305   menuView = menuBar()->addMenu("&View");
306 
307   fullScreenAction = new QAction("Use &full screen", this);
308   fullScreenAction->setShortcut(QKeySequence(CTRL+Key_F));
309   icon = new QIcon();
310   icon->addPixmap(QPixmap((const char ** )fullscreen_xpm));
311   fullScreenAction->setIcon(*icon);
312   connect(fullScreenAction, SIGNAL(triggered()), this, SLOT(fullScreen()));
313   menuView->addAction(fullScreenAction);
314 
315   // Setting up an instance of plotter
316   plr = new Plotter(T, w, x, y, this);
317   connect(plr, SIGNAL(clicked()), this, SLOT(normalView()));
318   this->setCentralWidget(plr);
319 
320   this->resize(T->width, T->height + 24);
321   res = new QLabel();
322   statusBar()->addWidget(res);
323 }
324 
~PlotWindow()325 PlotWindow::~PlotWindow() {}
326 
327 void
resizeEvent(QResizeEvent * e)328 PlotWindow::resizeEvent(QResizeEvent *e)
329 {
330   QMainWindow::resizeEvent(e);
331   res->setText(QString("Resolution: ") +
332                 QString::number(plr->width()) + "x" +
333                 QString::number(plr->height()));
334   res->setFixedSize(res->sizeHint());
335 }
336 
337 void
fullScreen()338 PlotWindow::fullScreen()
339 {
340   plr->setParent(0);
341   plr->showMaximized();
342   plr->show();
343 }
344 
345 void
normalView()346 PlotWindow::normalView()
347 {
348   if (!plr->parentWidget())
349   {
350     plr->setParent(this);
351     this->setCentralWidget(plr);
352     plr->show();
353   }
354 }
355 
356 void
save()357 PlotWindow::save()
358 {
359   QString ff = QString(file_formats.at(saveFileFormat));
360   QString fn = saveFileName + "." + ff.toLower();
361   plr->save(fn, ff);
362   setWindowTitle(QString("Pari QtPlot:") + fn);
363 }
364 
365 void
save(int id)366 PlotWindow::save(int id)
367 {
368   QString ff(file_formats.at(id));
369   QString s(ff + " (*." + ff.toLower() +");;All (*)");
370   QString fn = QFileDialog::getSaveFileName(this, saveFileName + "." + ff,
371     saveFileName + "." + ff, s);
372   if (!fn.isEmpty())
373   {
374     saveFileName = fn;
375     int p;
376     if ((p = saveFileName.lastIndexOf("." + ff, -1)) >= 0)
377       saveFileName.truncate(p);
378     saveFileFormat = id;
379     save();
380   }
381 }
382 
383 #include "plotQt4.moc.cpp"
384 
385 static void
draw(PARI_plot * T,GEN w,GEN x,GEN y)386 draw(PARI_plot *T, GEN w, GEN x, GEN y)
387 {
388   if (pari_daemon()) return;  // parent process returns
389 
390   // launch Qt window
391   int argc = 1;                         // set argc = 2 for cross
392   const char * argv[] = { "gp", "-qws"}; // development using qvfb
393   QApplication a(argc, (char**) argv);
394   PlotWindow *win = new PlotWindow(T, w, x, y);
395   win->show();
396   a.exec();
397   pari_close(); exit(0);
398 }
399 
400 INLINE void
gp_get_display_sizes(long * dwidth,long * dheight,long * fwidth,long * fheight)401 gp_get_display_sizes(long *dwidth, long *dheight, long *fwidth, long *fheight)
402 {
403   /* There must be an easier way to get desktop size... */
404   int argc = 1;
405   const char * argv[] = { "gp", "-qws"};
406   QApplication a(argc, (char**) argv);
407   QDesktopWidget *qw = new QDesktopWidget();
408   if (qw)
409   {
410     QRect rec = qw->screenGeometry();
411     *dwidth  = rec.width();   // screen width
412     *dheight = rec.height();  //   and height
413   }
414   else
415   {
416     *dwidth  = 0;
417     *dheight = 0;
418   }
419   *fwidth  = 6; // font width
420   *fheight = 9; //   and height
421 }
422 
423 void
gp_get_plot(PARI_plot * T)424 gp_get_plot(PARI_plot *T)
425 {
426   gp_get_plot_generic(T,gp_get_display_sizes);
427   T->draw = &draw;
428 }
429