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