1 /* -*- c++ -*- */
2 /*
3 * Copyright 2012 Free Software Foundation, Inc.
4 *
5 * This file is part of GNU Radio
6 *
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <gnuradio/qtgui/DisplayPlot.h>
24
25 #include <qwt_legend.h>
26 #include <qwt_scale_draw.h>
27 #include <QColor>
28 #include <QDebug>
29 #include <cmath>
30 #include <iostream>
31 #include <stdexcept>
32
DisplayPlot(int nplots,QWidget * parent)33 DisplayPlot::DisplayPlot(int nplots, QWidget* parent)
34 : QwtPlot(parent), d_nplots(nplots), d_stop(false)
35 {
36 qRegisterMetaType<QColorList>("QColorList");
37 resize(parent->width(), parent->height());
38
39 d_autoscale_state = false;
40
41 // Disable polygon clipping
42 #if QWT_VERSION < 0x060000
43 QwtPainter::setDeviceClipping(false);
44 #else
45 QwtPainter::setPolylineSplitting(false);
46 #endif
47
48 #if QWT_VERSION < 0x060000
49 // We don't need the cache here
50 canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
51 canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
52 #endif
53
54 QColor default_palette_color = QColor("white");
55 setPaletteColor(default_palette_color);
56
57 d_panner = new QwtPlotPanner(canvas());
58 d_panner->setAxisEnabled(QwtPlot::yRight, false);
59 d_panner->setMouseButton(Qt::MidButton, Qt::ControlModifier);
60
61 // emit the position of clicks on widget
62 d_picker = new QwtDblClickPlotPicker(canvas());
63
64 #if QWT_VERSION < 0x060000
65 connect(d_picker,
66 SIGNAL(selected(const QwtDoublePoint&)),
67 this,
68 SLOT(onPickerPointSelected(const QwtDoublePoint&)));
69 #else
70 d_picker->setStateMachine(new QwtPickerDblClickPointMachine());
71 connect(d_picker,
72 SIGNAL(selected(const QPointF&)),
73 this,
74 SLOT(onPickerPointSelected6(const QPointF&)));
75 #endif
76
77 // Configure magnify on mouse wheel
78 d_magnifier = new QwtPlotMagnifier(canvas());
79 d_magnifier->setAxisEnabled(QwtPlot::xBottom, false);
80
81 // Avoid jumping when labels with more/less digits
82 // appear/disappear when scrolling vertically
83
84 const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font());
85 QwtScaleDraw* sd = axisScaleDraw(QwtPlot::yLeft);
86 sd->setMinimumExtent(fm.width("100.00"));
87
88 QwtLegend* legendDisplay = new QwtLegend(this);
89
90 #if QWT_VERSION < 0x060100
91 legendDisplay->setItemMode(QwtLegend::CheckableItem);
92 insertLegend(legendDisplay);
93 connect(this,
94 SIGNAL(legendChecked(QwtPlotItem*, bool)),
95 this,
96 SLOT(legendEntryChecked(QwtPlotItem*, bool)));
97 #else /* QWT_VERSION < 0x060100 */
98 legendDisplay->setDefaultItemMode(QwtLegendData::Checkable);
99 insertLegend(legendDisplay);
100 connect(legendDisplay,
101 SIGNAL(checked(const QVariant&, bool, int)),
102 this,
103 SLOT(legendEntryChecked(const QVariant&, bool, int)));
104 #endif /* QWT_VERSION < 0x060100 */
105 }
106
~DisplayPlot()107 DisplayPlot::~DisplayPlot()
108 {
109 // d_zoomer and d_panner deleted when parent deleted
110 }
111
disableLegend()112 void DisplayPlot::disableLegend()
113 {
114 // Haven't found a good way to toggle it on/off
115 insertLegend(NULL);
116 }
117
setYaxis(double min,double max)118 void DisplayPlot::setYaxis(double min, double max)
119 {
120 setAxisScale(QwtPlot::yLeft, min, max);
121 if (!d_autoscale_state)
122 d_zoomer->setZoomBase();
123 }
124
setXaxis(double min,double max)125 void DisplayPlot::setXaxis(double min, double max)
126 {
127 setAxisScale(QwtPlot::xBottom, min, max);
128 d_zoomer->setZoomBase();
129 }
130
setLineLabel(unsigned int which,QString label)131 void DisplayPlot::setLineLabel(unsigned int which, QString label)
132 {
133 if (which >= d_plot_curve.size())
134 throw std::runtime_error("DisplayPlot::setLineLabel: index out of bounds");
135 d_plot_curve[which]->setTitle(label);
136 }
137
getLineLabel(unsigned int which)138 QString DisplayPlot::getLineLabel(unsigned int which)
139 {
140 if (which >= d_plot_curve.size())
141 throw std::runtime_error("DisplayPlot::getLineLabel: index out of bounds");
142 return d_plot_curve[which]->title().text();
143 }
144
setLineColor(unsigned int which,QColor color)145 void DisplayPlot::setLineColor(unsigned int which, QColor color)
146 {
147 if (which < d_nplots) {
148 // Set the color of the pen
149 QPen pen(d_plot_curve[which]->pen());
150 pen.setColor(color);
151 d_plot_curve[which]->setPen(pen);
152 // And set the color of the markers
153 #if QWT_VERSION < 0x060000
154 // d_plot_curve[which]->setBrush(QBrush(QColor(color)));
155 d_plot_curve[which]->setPen(pen);
156 QwtSymbol sym = (QwtSymbol)d_plot_curve[which]->symbol();
157 setLineMarker(which, sym.style());
158 #else
159 QwtSymbol* sym = (QwtSymbol*)d_plot_curve[which]->symbol();
160 if (sym) {
161 sym->setColor(color);
162 sym->setPen(pen);
163 d_plot_curve[which]->setSymbol(sym);
164 }
165 #endif
166 }
167 }
168
getLineColor(unsigned int which) const169 QColor DisplayPlot::getLineColor(unsigned int which) const
170 {
171 // If that plot doesn't exist then return black.
172 if (which < d_nplots)
173 return d_plot_curve[which]->pen().color();
174 return QColor("black");
175 }
176
177 // Use a preprocessor macro to create a bunch of hooks for Q_PROPERTY and hence the
178 // stylesheet.
179 #define SETUPLINE(i, im1) \
180 void DisplayPlot::setLineColor##i(QColor c) { setLineColor(im1, c); } \
181 const QColor DisplayPlot::getLineColor##i() const { return getLineColor(im1); } \
182 void DisplayPlot::setLineWidth##i(int width) { setLineWidth(im1, width); } \
183 int DisplayPlot::getLineWidth##i() const { return getLineWidth(im1); } \
184 void DisplayPlot::setLineStyle##i(Qt::PenStyle ps) { setLineStyle(im1, ps); } \
185 const Qt::PenStyle DisplayPlot::getLineStyle##i() const \
186 { \
187 return getLineStyle(im1); \
188 } \
189 void DisplayPlot::setLineMarker##i(QwtSymbol::Style ms) { setLineMarker(im1, ms); } \
190 const QwtSymbol::Style DisplayPlot::getLineMarker##i() const \
191 { \
192 return getLineMarker(im1); \
193 } \
194 void DisplayPlot::setMarkerAlpha##i(int alpha) { setMarkerAlpha(im1, alpha); } \
195 int DisplayPlot::getMarkerAlpha##i() const { return getMarkerAlpha(im1); }
196 SETUPLINE(1, 0)
197 SETUPLINE(2, 1)
198 SETUPLINE(3, 2)
199 SETUPLINE(4, 3)
200 SETUPLINE(5, 4)
201 SETUPLINE(6, 5)
202 SETUPLINE(7, 6)
203 SETUPLINE(8, 7)
204 SETUPLINE(9, 8)
205
setZoomerColor(QColor c)206 void DisplayPlot::setZoomerColor(QColor c)
207 {
208 d_zoomer->setRubberBandPen(c);
209 d_zoomer->setTrackerPen(c);
210 }
211
getZoomerColor() const212 QColor DisplayPlot::getZoomerColor() const { return d_zoomer->rubberBandPen().color(); }
213
setPaletteColor(QColor c)214 void DisplayPlot::setPaletteColor(QColor c)
215 {
216 QPalette palette;
217 palette.setColor(canvas()->backgroundRole(), c);
218 canvas()->setPalette(palette);
219 }
220
getPaletteColor() const221 QColor DisplayPlot::getPaletteColor() const
222 {
223 return canvas()->palette().color(canvas()->backgroundRole());
224 }
225
setAxisLabelFontSize(int axisId,int fs)226 void DisplayPlot::setAxisLabelFontSize(int axisId, int fs)
227 {
228 QwtText axis_title = QwtText(axisWidget(axisId)->title());
229 QFont font = QFont(axis_title.font());
230 font.setPointSize(fs);
231 axis_title.setFont(font);
232 axisWidget(axisId)->setTitle(axis_title);
233 }
234
getAxisLabelFontSize(int axisId) const235 int DisplayPlot::getAxisLabelFontSize(int axisId) const
236 {
237 return axisWidget(axisId)->title().font().pointSize();
238 }
239
setYaxisLabelFontSize(int fs)240 void DisplayPlot::setYaxisLabelFontSize(int fs)
241 {
242 setAxisLabelFontSize(QwtPlot::yLeft, fs);
243 }
244
getYaxisLabelFontSize() const245 int DisplayPlot::getYaxisLabelFontSize() const
246 {
247 int fs = getAxisLabelFontSize(QwtPlot::yLeft);
248 return fs;
249 }
250
setXaxisLabelFontSize(int fs)251 void DisplayPlot::setXaxisLabelFontSize(int fs)
252 {
253 setAxisLabelFontSize(QwtPlot::xBottom, fs);
254 }
255
getXaxisLabelFontSize() const256 int DisplayPlot::getXaxisLabelFontSize() const
257 {
258 int fs = getAxisLabelFontSize(QwtPlot::xBottom);
259 return fs;
260 }
261
setAxesLabelFontSize(int fs)262 void DisplayPlot::setAxesLabelFontSize(int fs)
263 {
264 setAxisLabelFontSize(QwtPlot::yLeft, fs);
265 setAxisLabelFontSize(QwtPlot::xBottom, fs);
266 }
267
getAxesLabelFontSize() const268 int DisplayPlot::getAxesLabelFontSize() const
269 {
270 // Returns 0 if all axes do not have the same font size.
271 int fs = getAxisLabelFontSize(QwtPlot::yLeft);
272 if (getAxisLabelFontSize(QwtPlot::xBottom) != fs)
273 return 0;
274 return fs;
275 }
276
setLineWidth(unsigned int which,int width)277 void DisplayPlot::setLineWidth(unsigned int which, int width)
278 {
279 if (which < d_nplots) {
280 // Set the new line width
281 QPen pen(d_plot_curve[which]->pen());
282 pen.setWidth(width);
283 d_plot_curve[which]->setPen(pen);
284
285 // Scale the marker size proportionally
286 #if QWT_VERSION < 0x060000
287 QwtSymbol sym = (QwtSymbol)d_plot_curve[which]->symbol();
288 sym.setSize(7 + 10 * log10(1.0 * width), 7 + 10 * log10(1.0 * width));
289 d_plot_curve[which]->setSymbol(sym);
290 #else
291 QwtSymbol* sym = (QwtSymbol*)d_plot_curve[which]->symbol();
292 if (sym) {
293 sym->setSize(7 + 10 * log10(1.0 * width), 7 + 10 * log10(1.0 * width));
294 d_plot_curve[which]->setSymbol(sym);
295 }
296 #endif
297 }
298 }
299
getLineWidth(unsigned int which) const300 int DisplayPlot::getLineWidth(unsigned int which) const
301 {
302 if (which < d_nplots) {
303 return d_plot_curve[which]->pen().width();
304 } else {
305 return 0;
306 }
307 }
308
setLineStyle(unsigned int which,Qt::PenStyle style)309 void DisplayPlot::setLineStyle(unsigned int which, Qt::PenStyle style)
310 {
311 if (which < d_nplots) {
312 QPen pen(d_plot_curve[which]->pen());
313 pen.setStyle(style);
314 d_plot_curve[which]->setPen(pen);
315 }
316 }
317
getLineStyle(unsigned int which) const318 const Qt::PenStyle DisplayPlot::getLineStyle(unsigned int which) const
319 {
320 if (which < d_nplots) {
321 return d_plot_curve[which]->pen().style();
322 } else {
323 return Qt::SolidLine;
324 }
325 }
326
setLineMarker(unsigned int which,QwtSymbol::Style marker)327 void DisplayPlot::setLineMarker(unsigned int which, QwtSymbol::Style marker)
328 {
329 if (which < d_nplots) {
330 #if QWT_VERSION < 0x060000
331 QwtSymbol sym = (QwtSymbol)d_plot_curve[which]->symbol();
332 QPen pen(d_plot_curve[which]->pen());
333 QBrush brush(pen.color());
334 sym.setStyle(marker);
335 sym.setPen(pen);
336 sym.setBrush(brush);
337 d_plot_curve[which]->setSymbol(sym);
338 #else
339 QwtSymbol* sym = (QwtSymbol*)d_plot_curve[which]->symbol();
340 if (sym) {
341 sym->setStyle(marker);
342 d_plot_curve[which]->setSymbol(sym);
343 }
344 #endif
345 }
346 }
347
getLineMarker(unsigned int which) const348 const QwtSymbol::Style DisplayPlot::getLineMarker(unsigned int which) const
349 {
350 if (which < d_nplots) {
351 #if QWT_VERSION < 0x060000
352 QwtSymbol sym = (QwtSymbol)d_plot_curve[which]->symbol();
353 return sym.style();
354 #else
355 QwtSymbol* sym = (QwtSymbol*)d_plot_curve[which]->symbol();
356 return sym->style();
357 #endif
358 } else {
359 return QwtSymbol::NoSymbol;
360 }
361 }
362
setMarkerAlpha(unsigned int which,int alpha)363 void DisplayPlot::setMarkerAlpha(unsigned int which, int alpha)
364 {
365 if (which < d_nplots) {
366 // Get the pen color
367 QPen pen(d_plot_curve[which]->pen());
368 QColor color = pen.color();
369
370 // Set new alpha and update pen
371 color.setAlpha(alpha);
372 pen.setColor(color);
373 d_plot_curve[which]->setPen(pen);
374
375 // And set the new color for the markers
376 #if QWT_VERSION < 0x060000
377 QwtSymbol sym = (QwtSymbol)d_plot_curve[which]->symbol();
378 setLineMarker(which, sym.style());
379 #else
380 QwtSymbol* sym = (QwtSymbol*)d_plot_curve[which]->symbol();
381 if (sym) {
382 sym->setColor(color);
383 sym->setPen(pen);
384 d_plot_curve[which]->setSymbol(sym);
385 }
386 #endif
387 }
388 }
389
getMarkerAlpha(unsigned int which) const390 int DisplayPlot::getMarkerAlpha(unsigned int which) const
391 {
392 if (which < d_nplots) {
393 return d_plot_curve[which]->pen().color().alpha();
394 } else {
395 return 0;
396 }
397 }
398
setStop(bool on)399 void DisplayPlot::setStop(bool on) { d_stop = on; }
400
resizeSlot(QSize * s)401 void DisplayPlot::resizeSlot(QSize* s)
402 {
403 // -10 is to spare some room for the legend and x-axis label
404 resize(s->width() - 10, s->height() - 10);
405 }
406
legendEntryChecked(QwtPlotItem * plotItem,bool on)407 void DisplayPlot::legendEntryChecked(QwtPlotItem* plotItem, bool on)
408 {
409 plotItem->setVisible(!on);
410 replot();
411 }
412
legendEntryChecked(const QVariant & plotItem,bool on,int index)413 void DisplayPlot::legendEntryChecked(const QVariant& plotItem, bool on, int index)
414 {
415 #if QWT_VERSION < 0x060100
416 std::runtime_error("DisplayPlot::legendEntryChecked with QVariant not enabled in "
417 "this version of QWT.\n");
418 #else
419 QwtPlotItem* p = infoToItem(plotItem);
420 legendEntryChecked(p, on);
421 #endif /* QWT_VERSION < 0x060100 */
422 }
423
onPickerPointSelected(const QwtDoublePoint & p)424 void DisplayPlot::onPickerPointSelected(const QwtDoublePoint& p)
425 {
426 QPointF point = p;
427 // fprintf(stderr,"onPickerPointSelected %f %f\n", point.x(), point.y());
428 emit plotPointSelected(point);
429 }
430
onPickerPointSelected6(const QPointF & p)431 void DisplayPlot::onPickerPointSelected6(const QPointF& p)
432 {
433 QPointF point = p;
434 // fprintf(stderr,"onPickerPointSelected %f %f\n", point.x(), point.y());
435 emit plotPointSelected(point);
436 }
437
setAxisLabels(bool en)438 void DisplayPlot::setAxisLabels(bool en)
439 {
440 enableAxis(0, en);
441 enableAxis(2, en);
442 }
443