diff options
author | Tom Rondeau <tom@trondeau.com> | 2015-04-04 16:57:29 -0400 |
---|---|---|
committer | Tom Rondeau <tom@trondeau.com> | 2015-04-04 16:57:29 -0400 |
commit | 8cdc041e1aaf8771de0fd9e7327720dc5b383464 (patch) | |
tree | e3da9f53206a52bffe85cde4da8ca08094171553 | |
parent | 6afc40e80f05a6cc2dbdebcc037ed40c5f5921f1 (diff) |
qtgui: adds control panel to frequency sinks.
Also adds ability to disable the legend. Currently, only exposed in
GRC for the freq sinks.
-rw-r--r-- | gr-qtgui/grc/qtgui_freq_sink_x.xml | 38 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h | 12 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h | 9 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/displayform.h | 2 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h | 4 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h | 4 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h | 94 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h | 30 | ||||
-rw-r--r-- | gr-qtgui/lib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | gr-qtgui/lib/DisplayPlot.cc | 6 | ||||
-rw-r--r-- | gr-qtgui/lib/FrequencyDisplayPlot.cc | 34 | ||||
-rw-r--r-- | gr-qtgui/lib/displayform.cc | 6 | ||||
-rw-r--r-- | gr-qtgui/lib/freq_sink_c_impl.cc | 27 | ||||
-rw-r--r-- | gr-qtgui/lib/freq_sink_c_impl.h | 4 | ||||
-rw-r--r-- | gr-qtgui/lib/freq_sink_f_impl.cc | 27 | ||||
-rw-r--r-- | gr-qtgui/lib/freq_sink_f_impl.h | 4 | ||||
-rw-r--r-- | gr-qtgui/lib/freqcontrolpanel.cc | 219 | ||||
-rw-r--r-- | gr-qtgui/lib/freqdisplayform.cc | 256 |
19 files changed, 751 insertions, 28 deletions
diff --git a/gr-qtgui/grc/qtgui_freq_sink_x.xml b/gr-qtgui/grc/qtgui_freq_sink_x.xml index aea46ab4e3..96a9fd053d 100644 --- a/gr-qtgui/grc/qtgui_freq_sink_x.xml +++ b/gr-qtgui/grc/qtgui_freq_sink_x.xml @@ -26,6 +26,10 @@ self.$(id).set_trigger_mode($tr_mode, $tr_level, $tr_chan, $tr_tag) self.$(id).enable_autoscale($autoscale) self.$(id).enable_grid($grid) self.$(id).set_fft_average($average) +self.$(id).enable_control_panel($ctrlpanel) + +if not $legend: + self.$(id).disable_legend() if $type == type(float()): self.$(id).set_plot_pos_half(not $freqhalf) @@ -319,6 +323,40 @@ $(gui_hint()($win))</make> <!-- Begin Config Tab items --> <param> + <name>Control Panel</name> + <key>ctrlpanel</key> + <value>False</value> + <type>enum</type> + <hide>part</hide> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + <tab>Config</tab> + </param> + + <param> + <name>Legend</name> + <key>legend</key> + <value>True</value> + <type>enum</type> + <hide>part</hide> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + <tab>Config</tab> + </param> + + <param> <name>Line 1 Label</name> <key>label1</key> <type>string</type> diff --git a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt index 6ba992363d..1e0c9f35f2 100644 --- a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt +++ b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt @@ -31,6 +31,7 @@ install(FILES DisplayPlot.h form_menus.h freqdisplayform.h + freqcontrolpanel.h freq_sink_c.h freq_sink_f.h FrequencyDisplayPlot.h diff --git a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h index 73c744063b..19b118223c 100644 --- a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h +++ b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h @@ -37,6 +37,7 @@ #include <qwt_plot_magnifier.h> #include <qwt_plot_marker.h> #include <qwt_symbol.h> +#include <qwt_legend.h> #include <gnuradio/qtgui/utils.h> #if QWT_VERSION >= 0x060000 @@ -46,6 +47,13 @@ typedef QList<QColor> QColorList; Q_DECLARE_METATYPE ( QColorList ) +#if QWT_VERSION < 0x060100 +#include <qwt_legend_item.h> +#else /* QWT_VERSION < 0x060100 */ +#include <qwt_legend_data.h> +#include <qwt_legend_label.h> +#endif /* QWT_VERSION < 0x060100 */ + /*! * \brief QWidget base plot to build QTGUI plotting tools. * \ingroup qtgui_blk @@ -117,6 +125,8 @@ public: DisplayPlot(int nplots, QWidget*); virtual ~DisplayPlot(); + void disableLegend(); + virtual void replot() = 0; const QColor getLineColor1 () const; @@ -289,6 +299,8 @@ protected: QList<QColor> d_trace_colors; bool d_autoscale_state; + + QwtLegend d_legend; }; #endif /* DOMAIN_DISPLAY_PLOT_H */ diff --git a/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h index cb44fbe510..3a8f1f33c3 100644 --- a/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h +++ b/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h @@ -70,9 +70,6 @@ public: const double noiseFloorAmplitude, const double peakFrequency, const double peakAmplitude, const double timeInterval); - void clearMaxData(); - void clearMinData(); - void replot(); void setYaxis(double min, double max); @@ -117,9 +114,13 @@ public slots: void onPickerPointSelected6(const QPointF & p); void setAutoScale(bool state); + void setAutoScaleShot(); void setPlotPosHalf(bool half); + void clearMaxData(); + void clearMinData(); + private: void _resetXAxisPoints(); void _autoScale(double bottom, double top); @@ -164,6 +165,8 @@ private: double d_peak_amplitude; double d_noise_floor_amplitude; + + bool d_autoscale_shot; }; #endif /* FREQUENCY_DISPLAY_PLOT_HPP */ diff --git a/gr-qtgui/include/gnuradio/qtgui/displayform.h b/gr-qtgui/include/gnuradio/qtgui/displayform.h index 02d2cf8cd4..2ef4b801cf 100644 --- a/gr-qtgui/include/gnuradio/qtgui/displayform.h +++ b/gr-qtgui/include/gnuradio/qtgui/displayform.h @@ -86,6 +86,8 @@ public slots: void saveFigure(); + void disableLegend(); + private slots: virtual void newData(const QEvent*) = 0; virtual void autoScale(bool) = 0; diff --git a/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h b/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h index f49e7b062f..8869afcc0d 100644 --- a/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h +++ b/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h @@ -159,8 +159,12 @@ namespace gr { virtual void enable_menu(bool en=true) = 0; virtual void enable_grid(bool en=true) = 0; virtual void enable_autoscale(bool en=true) = 0; + virtual void enable_control_panel(bool en=true) = 0; + virtual void enable_max_hold(bool en) = 0; + virtual void enable_min_hold(bool en) = 0; virtual void clear_max_hold() = 0; virtual void clear_min_hold() = 0; + virtual void disable_legend() = 0; virtual void reset() = 0; QApplication *d_qApplication; diff --git a/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h index ed65d3136c..552e1e4301 100644 --- a/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h +++ b/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h @@ -165,8 +165,12 @@ namespace gr { virtual void enable_menu(bool en=true) = 0; virtual void enable_grid(bool en=true) = 0; virtual void enable_autoscale(bool en=true) = 0; + virtual void enable_control_panel(bool en=true) = 0; + virtual void enable_max_hold(bool en) = 0; + virtual void enable_min_hold(bool en) = 0; virtual void clear_max_hold() = 0; virtual void clear_min_hold() = 0; + virtual void disable_legend() = 0; virtual void reset() = 0; QApplication *d_qApplication; diff --git a/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h b/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h new file mode 100644 index 0000000000..fe7636f0ad --- /dev/null +++ b/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h @@ -0,0 +1,94 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FREQ_CONTROL_PANEL_H +#define FREQ_CONTROL_PANEL_H + +#include <QtGui/QtGui> +#include <vector> +#include <QSlider> +#include <QComboBox> +#include <QCheckBox> +#include <QPushButton> +#include <QLabel> +#include <QHBoxLayout> +#include <gnuradio/qtgui/displayform.h> +#include <gnuradio/qtgui/freqdisplayform.h> + +class FreqControlPanel : public QVBoxLayout +{ + Q_OBJECT + +public: + FreqControlPanel(FreqDisplayForm *form); + ~FreqControlPanel(); + +public slots: + void notifyAvgSlider(int val); + void toggleGrid(bool en); + void toggleMaxHold(bool en); + void toggleMinHold(bool en); + + void toggleFFTSize(int val); + void toggleFFTWindow(const gr::filter::firdes::win_type win); + +signals: + void signalAvgSlider(float val); + void signalAvg(bool en); + +private: + FreqDisplayForm *d_parent; + + QGroupBox *d_trace_box; + QVBoxLayout *d_trace_layout; + QCheckBox *d_maxhold_check; + QCheckBox *d_minhold_check; + + QHBoxLayout *d_avg_layout; + QLabel *d_avg_label; + QSlider *d_avg_slider; + + QGroupBox *d_axes_box; + QVBoxLayout *d_axes_layout; + + QCheckBox *d_grid_check; + QHBoxLayout *d_yrange_layout; + QLabel *d_yrange_label; + QPushButton *d_yrange_plus; + QPushButton *d_yrange_minus; + + QHBoxLayout *d_ymin_layout; + QLabel *d_ymin_label; + QPushButton *d_ymin_plus; + QPushButton *d_ymin_minus; + + QPushButton *d_autoscale_button; + + QGroupBox *d_fft_box; + QVBoxLayout *d_fft_layout; + QComboBox *d_fft_size_combo; + QComboBox *d_fft_win_combo; + + int d_slider_max, d_slider_min, d_slider_step; +}; + +#endif /* FREQ_CONTROL_PANEL_H */ diff --git a/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h b/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h index 744ac3ee90..1f866ba560 100644 --- a/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h +++ b/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h @@ -31,6 +31,8 @@ #include <gnuradio/qtgui/displayform.h> +class FreqControlPanel; + /*! * \brief DisplayForm child for managing frequency (PSD) plots. * \ingroup qtgui_blk @@ -76,6 +78,7 @@ public slots: void setYMax(const QString &m); void setYMin(const QString &m); void autoScale(bool en); + void autoScaleShot(); void setPlotPosHalf(bool half); void clearMaxHold(); void clearMinHold(); @@ -89,6 +92,28 @@ public slots: void setTriggerTagKey(QString s); void setTriggerTagKey(const std::string &s); + void setupControlPanel(bool en); + void setupControlPanel(); + void teardownControlPanel(); + + void notifyYAxisPlus(); + void notifyYAxisMinus(); + void notifyYRangePlus(); + void notifyYRangeMinus(); + void notifyFFTSize(const QString &s); + void notifyFFTWindow(const QString &s); + void notifyMaxHold(bool en); + void notifyMinHold(bool en); + +signals: + void signalFFTSize(int size); + void signalFFTWindow(gr::filter::firdes::win_type win); + void signalReplot(); + void signalClearMaxData(); + void signalClearMinData(); + void signalSetMaxFFTVisible(bool en); + void signalSetMinFFTVisible(bool en); + private slots: void newData(const QEvent *updateEvent); void onPlotPointSelected(const QPointF p); @@ -109,7 +134,7 @@ private: FFTSizeMenu *d_sizemenu; FFTAverageMenu *d_avgmenu; FFTWindowMenu *d_winmenu; - QAction *d_clearmin_act, *d_clearmax_act; + QAction *d_minhold_act, *d_maxhold_act; QMenu *d_triggermenu; TriggerModeMenu *d_tr_mode_menu; @@ -121,6 +146,9 @@ private: float d_trig_level; int d_trig_channel; std::string d_trig_tag_key; + + QAction *d_controlpanelmenu; + FreqControlPanel *d_controlpanel; }; #endif /* FREQ_DISPLAY_FORM_H */ diff --git a/gr-qtgui/lib/CMakeLists.txt b/gr-qtgui/lib/CMakeLists.txt index 64e47f4d60..a0af95bbbb 100644 --- a/gr-qtgui/lib/CMakeLists.txt +++ b/gr-qtgui/lib/CMakeLists.txt @@ -28,6 +28,7 @@ set(qtgui_moc_hdrs ${qtgui_mod_includedir}/timecontrolpanel.h ${qtgui_mod_includedir}/timerasterdisplayform.h ${qtgui_mod_includedir}/freqdisplayform.h + ${qtgui_mod_includedir}/freqcontrolpanel.h ${qtgui_mod_includedir}/constellationdisplayform.h ${qtgui_mod_includedir}/waterfalldisplayform.h ${qtgui_mod_includedir}/histogramdisplayform.h @@ -72,6 +73,7 @@ set(qtgui_sources timecontrolpanel.cc timerasterdisplayform.cc freqdisplayform.cc + freqcontrolpanel.cc constellationdisplayform.cc histogramdisplayform.cc numberdisplayform.cc diff --git a/gr-qtgui/lib/DisplayPlot.cc b/gr-qtgui/lib/DisplayPlot.cc index dcf5461d25..30fd837772 100644 --- a/gr-qtgui/lib/DisplayPlot.cc +++ b/gr-qtgui/lib/DisplayPlot.cc @@ -102,6 +102,12 @@ DisplayPlot::~DisplayPlot() // d_zoomer and d_panner deleted when parent deleted } +void +DisplayPlot::disableLegend() +{ + // Haven't found a good way to toggle it on/off + insertLegend(NULL); +} void DisplayPlot::setYaxis(double min, double max) diff --git a/gr-qtgui/lib/FrequencyDisplayPlot.cc b/gr-qtgui/lib/FrequencyDisplayPlot.cc index 8005be191b..2c7f3eff2e 100644 --- a/gr-qtgui/lib/FrequencyDisplayPlot.cc +++ b/gr-qtgui/lib/FrequencyDisplayPlot.cc @@ -27,16 +27,9 @@ #include <gnuradio/qtgui/qtgui_types.h> #include <qwt_scale_draw.h> -#include <qwt_legend.h> #include <QColor> #include <iostream> -#if QWT_VERSION < 0x060100 -#include <qwt_legend_item.h> -#else /* QWT_VERSION < 0x060100 */ -#include <qwt_legend_data.h> -#include <qwt_legend_label.h> -#endif /* QWT_VERSION < 0x060100 */ /*********************************************************************** * Widget to provide mouse pointer coordinate text @@ -95,6 +88,7 @@ FrequencyDisplayPlot::FrequencyDisplayPlot(int nplots, QWidget* parent) d_max_fft_data = new double[d_numPoints]; d_xdata = new double[d_numPoints]; d_half_freq = false; + d_autoscale_shot = false; setAxisTitle(QwtPlot::xBottom, "Frequency (Hz)"); setAxisScaleDraw(QwtPlot::xBottom, new FreqDisplayScaleDraw(0)); @@ -222,19 +216,25 @@ FrequencyDisplayPlot::FrequencyDisplayPlot(int nplots, QWidget* parent) // Turn off min/max hold plots in legend #if QWT_VERSION < 0x060100 QWidget *w; - QwtLegend* legendDisplay = legend(); - w = legendDisplay->find(d_min_fft_plot_curve); + d_legend = legend(); + w = legend()->find(d_min_fft_plot_curve); ((QwtLegendItem*)w)->setChecked(true); - w = legendDisplay->find(d_max_fft_plot_curve); + w = legend()->find(d_max_fft_plot_curve); ((QwtLegendItem*)w)->setChecked(true); + legend()->setVisible(false); #else /* QWT_VERSION < 0x060100 */ QWidget *w; w = ((QwtLegend*)legend())->legendWidget(itemToInfo(d_min_fft_plot_curve)); ((QwtLegendLabel*)w)->setChecked(true); + ((QwtLegendLabel*)w)->setVisible(false); + w = ((QwtLegend*)legend())->legendWidget(itemToInfo(d_max_fft_plot_curve)); ((QwtLegendLabel*)w)->setChecked(true); + ((QwtLegendLabel*)w)->setVisible(false); + #endif /* QWT_VERSION < 0x060100 */ + replot(); } @@ -412,8 +412,13 @@ FrequencyDisplayPlot::plotNewData(const std::vector<double*> dataPoints, } } - if(d_autoscale_state) + if(d_autoscale_state) { _autoScale(bottom, top); + if(d_autoscale_shot) { + d_autoscale_state = false; + d_autoscale_shot = false; + } + } d_noise_floor_amplitude = noiseFloorAmplitude; d_peak_frequency = peakFrequency; @@ -470,6 +475,13 @@ FrequencyDisplayPlot::setAutoScale(bool state) } void +FrequencyDisplayPlot::setAutoScaleShot() +{ + d_autoscale_state = true; + d_autoscale_shot = true; +} + +void FrequencyDisplayPlot::setPlotPosHalf(bool half) { d_half_freq = half; diff --git a/gr-qtgui/lib/displayform.cc b/gr-qtgui/lib/displayform.cc index 326b96c1d6..27a09512fc 100644 --- a/gr-qtgui/lib/displayform.cc +++ b/gr-qtgui/lib/displayform.cc @@ -374,3 +374,9 @@ DisplayForm::saveFigure() delete filebox; } + +void +DisplayForm::disableLegend() +{ + d_display_plot->disableLegend(); +} diff --git a/gr-qtgui/lib/freq_sink_c_impl.cc b/gr-qtgui/lib/freq_sink_c_impl.cc index adc1f76857..ee2fc52c1a 100644 --- a/gr-qtgui/lib/freq_sink_c_impl.cc +++ b/gr-qtgui/lib/freq_sink_c_impl.cc @@ -391,6 +391,27 @@ namespace gr { } void + freq_sink_c_impl::enable_control_panel(bool en) + { + if(en) + d_main_gui->setupControlPanel(); + else + d_main_gui->teardownControlPanel(); + } + + void + freq_sink_c_impl::enable_max_hold(bool en) + { + d_main_gui->notifyMaxHold(en); + } + + void + freq_sink_c_impl::enable_min_hold(bool en) + { + d_main_gui->notifyMinHold(en); + } + + void freq_sink_c_impl::clear_max_hold() { d_main_gui->clearMaxHold(); @@ -403,6 +424,12 @@ namespace gr { } void + freq_sink_c_impl::disable_legend() + { + d_main_gui->disableLegend(); + } + + void freq_sink_c_impl::reset() { gr::thread::scoped_lock lock(d_setlock); diff --git a/gr-qtgui/lib/freq_sink_c_impl.h b/gr-qtgui/lib/freq_sink_c_impl.h index b5f9cd3d4d..908ce0b563 100644 --- a/gr-qtgui/lib/freq_sink_c_impl.h +++ b/gr-qtgui/lib/freq_sink_c_impl.h @@ -142,8 +142,12 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); void enable_autoscale(bool en); + void enable_control_panel(bool en); + void enable_max_hold(bool en); + void enable_min_hold(bool en); void clear_max_hold(); void clear_min_hold(); + void disable_legend(); void reset(); int work(int noutput_items, diff --git a/gr-qtgui/lib/freq_sink_f_impl.cc b/gr-qtgui/lib/freq_sink_f_impl.cc index 1e01208b27..05a2ff7c39 100644 --- a/gr-qtgui/lib/freq_sink_f_impl.cc +++ b/gr-qtgui/lib/freq_sink_f_impl.cc @@ -396,6 +396,27 @@ namespace gr { } void + freq_sink_f_impl::enable_control_panel(bool en) + { + if(en) + d_main_gui->setupControlPanel(); + else + d_main_gui->teardownControlPanel(); + } + + void + freq_sink_f_impl::enable_max_hold(bool en) + { + d_main_gui->notifyMaxHold(en); + } + + void + freq_sink_f_impl::enable_min_hold(bool en) + { + d_main_gui->notifyMinHold(en); + } + + void freq_sink_f_impl::clear_max_hold() { d_main_gui->clearMaxHold(); @@ -408,6 +429,12 @@ namespace gr { } void + freq_sink_f_impl::disable_legend() + { + d_main_gui->disableLegend(); + } + + void freq_sink_f_impl::reset() { gr::thread::scoped_lock lock(d_setlock); diff --git a/gr-qtgui/lib/freq_sink_f_impl.h b/gr-qtgui/lib/freq_sink_f_impl.h index 1463699319..e1ae0e95eb 100644 --- a/gr-qtgui/lib/freq_sink_f_impl.h +++ b/gr-qtgui/lib/freq_sink_f_impl.h @@ -142,8 +142,12 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); void enable_autoscale(bool en); + void enable_control_panel(bool en); + void enable_max_hold(bool en); + void enable_min_hold(bool en); void clear_max_hold(); void clear_min_hold(); + void disable_legend(); void reset(); int work(int noutput_items, diff --git a/gr-qtgui/lib/freqcontrolpanel.cc b/gr-qtgui/lib/freqcontrolpanel.cc new file mode 100644 index 0000000000..d33e0105ed --- /dev/null +++ b/gr-qtgui/lib/freqcontrolpanel.cc @@ -0,0 +1,219 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include <gnuradio/qtgui/freqcontrolpanel.h> + +FreqControlPanel::FreqControlPanel(FreqDisplayForm *form) + : QVBoxLayout(), + d_parent(form) +{ + // Set up the box for trace items + d_trace_box = new QGroupBox("Trace Options"); + d_trace_layout = new QVBoxLayout; + d_maxhold_check = new QCheckBox("Max Hold"); + d_minhold_check = new QCheckBox("Min Hold"); + + d_avg_layout = new QHBoxLayout; + d_avg_label = new QLabel("Avg:"); + d_slider_max = 100; + d_slider_min = 1; + d_slider_step = 1; + d_avg_slider = new QSlider(Qt::Horizontal); + d_avg_slider->setRange(d_slider_min, d_slider_max); + d_avg_slider->setTickInterval(d_slider_step); + d_avg_slider->setValue(d_slider_max); + d_avg_layout->addWidget(d_avg_label); + d_avg_layout->addWidget(d_avg_slider); + + // Set up the box for axis items + d_axes_box = new QGroupBox("Axis Options"); + d_axes_layout = new QVBoxLayout; + + d_grid_check = new QCheckBox("Grid"); + d_yrange_layout = new QHBoxLayout; + d_yrange_label = new QLabel("Y Range:"); + d_yrange_plus = new QPushButton("+"); + d_yrange_minus = new QPushButton("-"); + d_yrange_plus->setMaximumWidth(30); + d_yrange_plus->setMinimumWidth(30); + d_yrange_minus->setMaximumWidth(30); + d_yrange_minus->setMinimumWidth(30); + d_yrange_layout->addWidget(d_yrange_label); + d_yrange_layout->addWidget(d_yrange_plus); + d_yrange_layout->addWidget(d_yrange_minus); + + d_ymin_layout = new QHBoxLayout; + d_ymin_label = new QLabel("Ref Level:"); + d_ymin_plus = new QPushButton("+"); + d_ymin_minus = new QPushButton("-"); + d_ymin_plus->setMaximumWidth(30); + d_ymin_plus->setMinimumWidth(30); + d_ymin_minus->setMaximumWidth(30); + d_ymin_minus->setMinimumWidth(30); + d_ymin_layout->addWidget(d_ymin_label); + d_ymin_layout->addWidget(d_ymin_plus); + d_ymin_layout->addWidget(d_ymin_minus); + + d_autoscale_button = new QPushButton("Autoscale"); + + + // Set up the box for FFT settings + d_fft_box = new QGroupBox("FFT"); + d_fft_layout = new QVBoxLayout; + d_fft_size_combo = new QComboBox(); + d_fft_size_combo->addItem("32"); + d_fft_size_combo->addItem("64"); + d_fft_size_combo->addItem("128"); + d_fft_size_combo->addItem("256"); + d_fft_size_combo->addItem("512"); + d_fft_size_combo->addItem("1024"); + d_fft_size_combo->addItem("2048"); + d_fft_size_combo->addItem("4096"); + + d_fft_win_combo = new QComboBox(); + d_fft_win_combo->addItem("None"); + d_fft_win_combo->addItem("Hamming"); + d_fft_win_combo->addItem("Hann"); + d_fft_win_combo->addItem("Blackman"); + d_fft_win_combo->addItem("Blackman-harris"); + d_fft_win_combo->addItem("Rectangular"); + d_fft_win_combo->addItem("Kaiser"); + d_fft_win_combo->addItem("Flat-top"); + + + // Set up the boxes into the layout + d_trace_layout->addWidget(d_maxhold_check); + d_trace_layout->addWidget(d_minhold_check); + d_trace_layout->addLayout(d_avg_layout); + d_trace_box->setLayout(d_trace_layout); + + d_axes_layout->addWidget(d_grid_check); + d_axes_layout->addLayout(d_yrange_layout); + d_axes_layout->addLayout(d_ymin_layout); + d_axes_layout->addWidget(d_autoscale_button); + d_axes_box->setLayout(d_axes_layout); + + d_fft_layout->addWidget(d_fft_size_combo); + d_fft_layout->addWidget(d_fft_win_combo); + d_fft_box->setLayout(d_fft_layout); + + addWidget(d_trace_box); + addWidget(d_axes_box); + addWidget(d_fft_box); + + addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, + QSizePolicy::Expanding)); + + connect(d_maxhold_check, SIGNAL(clicked(bool)), + d_parent, SLOT(notifyMaxHold(bool))); + connect(d_minhold_check, SIGNAL(clicked(bool)), + d_parent, SLOT(notifyMinHold(bool))); + + connect(d_avg_slider, SIGNAL(valueChanged(int)), + this, SLOT(notifyAvgSlider(int))); + connect(this, SIGNAL(signalAvgSlider(float)), + d_parent, SLOT(setFFTAverage(float))); + + connect(d_grid_check, SIGNAL(clicked(bool)), + d_parent, SLOT(setGrid(bool))); + + connect(d_ymin_plus, SIGNAL(pressed(void)), + d_parent, SLOT(notifyYAxisPlus(void))); + connect(d_ymin_minus, SIGNAL(pressed(void)), + d_parent, SLOT(notifyYAxisMinus(void))); + connect(d_yrange_plus, SIGNAL(pressed(void)), + d_parent, SLOT(notifyYRangePlus(void))); + connect(d_yrange_minus, SIGNAL(pressed(void)), + d_parent, SLOT(notifyYRangeMinus(void))); + + connect(d_autoscale_button, SIGNAL(pressed(void)), + d_parent, SLOT(autoScaleShot(void))); + + connect(d_fft_size_combo, SIGNAL(currentIndexChanged(const QString&)), + d_parent, SLOT(notifyFFTSize(const QString&))); + connect(d_fft_win_combo, SIGNAL(currentIndexChanged(const QString&)), + d_parent, SLOT(notifyFFTWindow(const QString&))); +} + +FreqControlPanel::~FreqControlPanel() +{ + removeWidget(d_axes_box); + removeWidget(d_trace_box); + delete d_axes_box; + delete d_trace_box; + + // All other children of the boxes are automatically deleted. +} + +void +FreqControlPanel::toggleGrid(bool en) +{ + d_grid_check->setChecked(en); +} + +void +FreqControlPanel::toggleMaxHold(bool en) +{ + d_maxhold_check->setChecked(en); +} + +void +FreqControlPanel::toggleMinHold(bool en) +{ + d_minhold_check->setChecked(en); +} + +void +FreqControlPanel::notifyAvgSlider(int val) +{ + float fval = static_cast<float>(val) / (d_slider_max - d_slider_min); + emit signalAvgSlider(fval); + emit signalAvg(true); +} + +void +FreqControlPanel::toggleFFTSize(int val) +{ + int index = static_cast<int>(logf(static_cast<float>(val))/logf(2.0f)) - 5; + d_fft_size_combo->setCurrentIndex(index); +} + +void +FreqControlPanel::toggleFFTWindow(const gr::filter::firdes::win_type win) +{ + if(win == -1) + d_fft_win_combo->setCurrentIndex(0); + if(win == gr::filter::firdes::WIN_HAMMING) + d_fft_win_combo->setCurrentIndex(1); + else if(win == gr::filter::firdes::WIN_HANN) + d_fft_win_combo->setCurrentIndex(2); + else if(win == gr::filter::firdes::WIN_BLACKMAN) + d_fft_win_combo->setCurrentIndex(3); + else if(win == gr::filter::firdes::WIN_BLACKMAN_hARRIS) + d_fft_win_combo->setCurrentIndex(4); + else if(win == gr::filter::firdes::WIN_RECTANGULAR) + d_fft_win_combo->setCurrentIndex(5); + else if(win == gr::filter::firdes::WIN_KAISER) + d_fft_win_combo->setCurrentIndex(6); + else if(win == gr::filter::firdes::WIN_FLATTOP) + d_fft_win_combo->setCurrentIndex(7); +} diff --git a/gr-qtgui/lib/freqdisplayform.cc b/gr-qtgui/lib/freqdisplayform.cc index d7fa1563fa..bdd3a0dac0 100644 --- a/gr-qtgui/lib/freqdisplayform.cc +++ b/gr-qtgui/lib/freqdisplayform.cc @@ -22,7 +22,9 @@ #include <cmath> #include <QMessageBox> +#include <QSpacerItem> #include <gnuradio/qtgui/freqdisplayform.h> +#include <gnuradio/qtgui/freqcontrolpanel.h> #include <iostream> FreqDisplayForm::FreqDisplayForm(int nplots, QWidget* parent) @@ -34,8 +36,12 @@ FreqDisplayForm::FreqDisplayForm(int nplots, QWidget* parent) d_layout = new QGridLayout(this); d_display_plot = new FrequencyDisplayPlot(nplots, this); d_layout->addWidget(d_display_plot, 0, 0); + + d_layout->setColumnStretch(0, 1); setLayout(d_layout); + d_controlpanel = NULL; + d_num_real_data_points = 1024; d_fftsize = 1024; d_fftavg = 1.0; @@ -65,14 +71,16 @@ FreqDisplayForm::FreqDisplayForm(int nplots, QWidget* parent) connect(minymenu, SIGNAL(whichTrigger(QString)), this, SLOT(setYMin(QString))); - d_clearmax_act = new QAction("Clear Max", this); - d_menu->addAction(d_clearmax_act); - connect(d_clearmax_act, SIGNAL(triggered()), - this, SLOT(clearMaxHold())); - d_clearmin_act = new QAction("Clear Min", this); - d_menu->addAction(d_clearmin_act); - connect(d_clearmin_act, SIGNAL(triggered()), - this, SLOT(clearMinHold())); + d_maxhold_act = new QAction("Max Hold", this); + d_maxhold_act->setCheckable(true); + d_menu->addAction(d_maxhold_act); + connect(d_maxhold_act, SIGNAL(triggered(bool)), + this, SLOT(notifyMaxHold(bool))); + d_minhold_act = new QAction("Min Hold", this); + d_minhold_act->setCheckable(true); + d_menu->addAction(d_minhold_act); + connect(d_minhold_act, SIGNAL(triggered(bool)), + this, SLOT(notifyMinHold(bool))); // Set up the trigger menu d_triggermenu = new QMenu("Trigger", this); @@ -86,6 +94,12 @@ FreqDisplayForm::FreqDisplayForm(int nplots, QWidget* parent) d_triggermenu->addAction(d_tr_tag_key_act); d_menu->addMenu(d_triggermenu); + d_controlpanelmenu = new QAction("Control Panel", this); + d_controlpanelmenu->setCheckable(true); + d_menu->addAction(d_controlpanelmenu); + connect(d_controlpanelmenu, SIGNAL(triggered(bool)), + this, SLOT(setupControlPanel(bool))); + setTriggerMode(gr::qtgui::TRIG_MODE_FREE); connect(d_tr_mode_menu, SIGNAL(whichTrigger(gr::qtgui::trigger_mode)), this, SLOT(setTriggerMode(gr::qtgui::trigger_mode))); @@ -105,10 +119,22 @@ FreqDisplayForm::FreqDisplayForm(int nplots, QWidget* parent) connect(d_tr_tag_key_act, SIGNAL(whichTrigger(QString)), this, SLOT(setTriggerTagKey(QString))); + connect(this, SIGNAL(signalClearMaxData()), + getPlot(), SLOT(clearMaxData())); + connect(this, SIGNAL(signalClearMinData()), + getPlot(), SLOT(clearMinData())); + connect(this, SIGNAL(signalSetMaxFFTVisible(bool)), + getPlot(), SLOT(setMaxFFTVisible(bool))); + connect(this, SIGNAL(signalSetMinFFTVisible(bool)), + getPlot(), SLOT(setMinFFTVisible(bool))); + Reset(); connect(d_display_plot, SIGNAL(plotPointSelected(const QPointF)), this, SLOT(onPlotPointSelected(const QPointF))); + + connect(this, SIGNAL(signalReplot()), + getPlot(), SLOT(replot())); } FreqDisplayForm::~FreqDisplayForm() @@ -117,6 +143,64 @@ FreqDisplayForm::~FreqDisplayForm() // Don't worry about deleting Display Plots - they are deleted when parents are deleted delete d_int_validator; + + teardownControlPanel(); +} + +void +FreqDisplayForm::setupControlPanel(bool en) +{ + if(en) { + setupControlPanel(); + } + else { + teardownControlPanel(); + } +} + +void +FreqDisplayForm::setupControlPanel() +{ + if(d_controlpanel) + delete d_controlpanel; + + // Create the control panel layout + d_controlpanel = new FreqControlPanel(this); + + // Connect action items in menu to controlpanel widgets + connect(d_grid_act, SIGNAL(triggered(bool)), + d_controlpanel, SLOT(toggleGrid(bool))); + connect(d_sizemenu, SIGNAL(whichTrigger(int)), + d_controlpanel, SLOT(toggleFFTSize(int))); + connect(d_winmenu, SIGNAL(whichTrigger(gr::filter::firdes::win_type)), + d_controlpanel, SLOT(toggleFFTWindow(gr::filter::firdes::win_type))); + connect(this, SIGNAL(signalFFTSize(int)), + d_controlpanel, SLOT(toggleFFTSize(int))); + connect(this, SIGNAL(signalFFTWindow(gr::filter::firdes::win_type)), + d_controlpanel, SLOT(toggleFFTWindow(gr::filter::firdes::win_type))); + connect(d_maxhold_act, SIGNAL(triggered(bool)), + d_controlpanel, SLOT(toggleMaxHold(bool))); + connect(d_minhold_act, SIGNAL(triggered(bool)), + d_controlpanel, SLOT(toggleMinHold(bool))); + + d_layout->addLayout(d_controlpanel, 0, 1); + + d_controlpanel->toggleGrid(d_grid_act->isChecked()); + d_controlpanelmenu->setChecked(true); + + emit signalFFTSize(getFFTSize()); + emit signalFFTWindow(getFFTWindowType()); +} + +void +FreqDisplayForm::teardownControlPanel() +{ + if(d_controlpanel) { + d_layout->removeItem(d_controlpanel); + delete d_controlpanel; + d_controlpanel = NULL; + } + d_controlpanelmenu->setChecked(false); } FrequencyDisplayPlot* @@ -177,7 +261,9 @@ FreqDisplayForm::setFFTSize(const int newsize) { d_fftsize = newsize; d_sizemenu->getActionFromSize(newsize)->setChecked(true); - getPlot()->replot(); + + emit signalReplot(); + emit signalFFTSize(newsize); } void @@ -185,7 +271,8 @@ FreqDisplayForm::setFFTAverage(const float newavg) { d_fftavg = newavg; d_avgmenu->getActionFromAvg(newavg)->setChecked(true); - getPlot()->replot(); + emit signalReplot(); + //emit signalFFTAverage(newavg); } void @@ -193,7 +280,8 @@ FreqDisplayForm::setFFTWindowType(const gr::filter::firdes::win_type newwin) { d_fftwintype = newwin; d_winmenu->getActionFromWindow(newwin)->setChecked(true); - getPlot()->replot(); + emit signalReplot(); + emit signalFFTWindow(newwin); } void @@ -249,14 +337,21 @@ FreqDisplayForm::autoScale(bool en) d_autoscale_act->setChecked(en); getPlot()->setAutoScale(d_autoscale_state); - getPlot()->replot(); + emit signalReplot(); +} + +void +FreqDisplayForm::autoScaleShot() +{ + getPlot()->setAutoScaleShot(); + emit signalReplot(); } void FreqDisplayForm::setPlotPosHalf(bool half) { getPlot()->setPlotPosHalf(half); - getPlot()->replot(); + emit signalReplot(); } void @@ -376,3 +471,138 @@ FreqDisplayForm::getTriggerTagKey() const { return d_trig_tag_key; } + + + +/******************************************************************** + * Notifcation messages from the control panel + *******************************************************************/ + + +void +FreqDisplayForm::notifyYAxisPlus() +{ +#if QWT_VERSION < 0x060100 + QwtScaleDiv *ax = getPlot()->axisScaleDiv(QwtPlot::yLeft); + double range = ax->upperBound() - ax->lowerBound(); + double step = range/20.0; + getPlot()->setYaxis(ax->lowerBound()+step, ax->upperBound()+step); + +#else + + QwtScaleDiv ax = getPlot()->axisScaleDiv(QwtPlot::yLeft); + double range = ax.upperBound() - ax.lowerBound(); + double step = range/20.0; + getPlot()->setYaxis(ax.lowerBound()+step, ax.upperBound()+step); +#endif +} + +void +FreqDisplayForm::notifyYAxisMinus() +{ +#if QWT_VERSION < 0x060100 + QwtScaleDiv *ax = getPlot()->axisScaleDiv(QwtPlot::yLeft); + double range = ax->upperBound() - ax->lowerBound(); + double step = range/20.0; + getPlot()->setYaxis(ax->lowerBound()-step, ax->upperBound()-step); + +#else + + QwtScaleDiv ax = getPlot()->axisScaleDiv(QwtPlot::yLeft); + double range = ax.upperBound() - ax.lowerBound(); + double step = range/20.0; + getPlot()->setYaxis(ax.lowerBound()-step, ax.upperBound()-step); +#endif +} + +void +FreqDisplayForm::notifyYRangePlus() +{ +#if QWT_VERSION < 0x060100 + QwtScaleDiv *ax = getPlot()->axisScaleDiv(QwtPlot::yLeft); + double range = ax->upperBound() - ax->lowerBound(); + double step = range/20.0; + getPlot()->setYaxis(ax->lowerBound()-step, ax->upperBound()+step); + +#else + + QwtScaleDiv ax = getPlot()->axisScaleDiv(QwtPlot::yLeft); + double range = ax.upperBound() - ax.lowerBound(); + double step = range/20.0; + getPlot()->setYaxis(ax.lowerBound()-step, ax.upperBound()+step); +#endif +} + +void +FreqDisplayForm::notifyYRangeMinus() +{ +#if QWT_VERSION < 0x060100 + QwtScaleDiv *ax = getPlot()->axisScaleDiv(QwtPlot::yLeft); + double range = ax->upperBound() - ax->lowerBound(); + double step = range/20.0; + getPlot()->setYaxis(ax->lowerBound()+step, ax->upperBound()-step); + +#else + + QwtScaleDiv ax = getPlot()->axisScaleDiv(QwtPlot::yLeft); + double range = ax.upperBound() - ax.lowerBound(); + double step = range/20.0; + getPlot()->setYaxis(ax.lowerBound()+step, ax.upperBound()-step); +#endif +} + + +void +FreqDisplayForm::notifyFFTSize(const QString &s) +{ + setFFTSize(s.toInt()); +} + +void +FreqDisplayForm::notifyFFTWindow(const QString &s) +{ + if(s == "None") { + d_fftwintype = gr::filter::firdes::WIN_NONE; + } + else if(s == "Hamming") { + d_fftwintype = gr::filter::firdes::WIN_HAMMING; + } + else if(s == "Hann") { + d_fftwintype = gr::filter::firdes::WIN_HANN; + } + else if(s == "Blackman") { + d_fftwintype = gr::filter::firdes::WIN_BLACKMAN; + } + else if(s == "Blackman-harris") { + d_fftwintype = gr::filter::firdes::WIN_BLACKMAN_hARRIS; + } + else if(s == "Rectangular") { + d_fftwintype = gr::filter::firdes::WIN_RECTANGULAR; + } + else if(s == "Kaiser") { + d_fftwintype = gr::filter::firdes::WIN_KAISER; + } + else if(s == "Flat-top") { + d_fftwintype = gr::filter::firdes::WIN_FLATTOP; + } + + d_winmenu->getActionFromWindow(d_fftwintype)->setChecked(true); + emit signalReplot(); +} + + +void +FreqDisplayForm::notifyMaxHold(bool en) +{ + d_maxhold_act->setChecked(en); + emit signalClearMaxData(); + emit signalSetMaxFFTVisible(en); +} + +void +FreqDisplayForm::notifyMinHold(bool en) +{ + d_minhold_act->setChecked(en); + emit signalClearMinData(); + emit signalSetMinFFTVisible(en); +} |