diff options
author | Tom Rondeau <trondeau@vt.edu> | 2013-02-27 17:22:17 -0500 |
---|---|---|
committer | Tom Rondeau <trondeau@vt.edu> | 2013-02-27 17:29:14 -0500 |
commit | eaedba3fa9969e6579afe986200b128285b3b9c9 (patch) | |
tree | 7a2c5bd4e6697d4200215e2251b6078b146ea85a /gnuradio-core/src/python | |
parent | fc911a81fce33ad7127806a8cbe44fa151cea188 (diff) |
ctrlport: Allows drag-and-drop from table list to a plotter to add a new curve to the plot.
Diffstat (limited to 'gnuradio-core/src/python')
-rw-r--r-- | gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py | 672 | ||||
-rwxr-xr-x | gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor | 50 |
2 files changed, 298 insertions, 424 deletions
diff --git a/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py b/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py index 091f0642c6..1bcf6bf807 100644 --- a/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py +++ b/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2012 Free Software Foundation, Inc. +# Copyright 2012,2013 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -32,34 +32,68 @@ except ImportError: print "Error: Program requires PyQt4 and gr-qtgui." sys.exit(1) -class GrDataPlotterC(gr.top_block): - def __init__(self, name, rate, pmin=None, pmax=None, stripchart=False): +class GrDataPlotParent(gr.top_block, QtGui.QWidget): + # Setup signals + plotupdated = QtCore.pyqtSignal(QtGui.QWidget) + + def __init__(self, name, rate, pmin=None, pmax=None): gr.top_block.__init__(self) + QtGui.QWidget.__init__(self, None) - self._stripchart = stripchart self._name = name self._npts = 500 - samp_rate = 1.0 + self._rate = rate + self.knobnames = [name,] + + self.layout = QtGui.QVBoxLayout() + self.setLayout(self.layout) + + self.setAcceptDrops(True) - self._last_data = self._npts*[0,] - self._data_len = 0 + def _setup(self, nconnections): + self.stop() + self.wait() - self.src = gr.vector_source_c([]) - self.thr = blocks.throttle(gr.sizeof_gr_complex, rate) - self.snk = qtgui.time_sink_c(self._npts, samp_rate, - self._name, 1) - self.snk.enable_autoscale(True) + if(self.layout.count() > 0): + # Remove and disconnect. Making sure no references to snk + # remain so that the plot gets deleted. + self.layout.removeWidget(self.py_window) + self.disconnect(self.thr, (self.snk, 0)) + self.disconnect(self.src[0], self.thr) + for n in xrange(1, self._ncons): + self.disconnect(self.src[n], (self.snk,n)) - self.connect(self.src, self.thr, (self.snk, 0)) + self._ncons = nconnections + self._data_len = self._ncons*[0,] - self.snk.set_line_label(0, "Real") - self.snk.set_line_label(1, "Imag") + self.thr = blocks.throttle(self._datasize, self._rate) + self.snk = self.get_qtsink() + + self.connect(self.thr, (self.snk, 0)) + + self._last_data = [] + self.src = [] + for n in xrange(self._ncons): + self.set_line_label(n, self.knobnames[n]) + + self._last_data.append(int(self._npts)*[0,]) + self.src.append(self.get_vecsource()) + + if(n == 0): + self.connect(self.src[n], self.thr) + else: + self.connect(self.src[n], (self.snk,n)) self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + self.layout.addWidget(self.py_window) + def __del__(self): pass + def close(self): + self.snk.close() + def qwidget(self): return self.py_window @@ -69,162 +103,162 @@ class GrDataPlotterC(gr.top_block): def semilogy(self, en=True): self.snk.enable_semilogy(en) - def stem(self, en=True): - self.snk.enable_stem_plot(en) + def dragEnterEvent(self, e): + e.acceptProposedAction() + + def dropEvent(self, e): + self.knobnames.append(str(e.mimeData().text())) + + # create a new qwidget plot with the new data stream. + self._setup(len(self.knobnames)) + + # emit that this plot has been updated with a new qwidget. + self.plotupdated.emit(self) + + e.acceptProposedAction() + + def data_to_complex(self, data): + if(self._iscomplex): + data_r = data[0::2] + data_i = data[1::2] + data = [complex(r,i) for r,i in zip(data_r, data_i)] + return data def update(self, data): # Ask GUI if there has been a change in nsamps - npts = self.snk.nsamps() + npts = self.get_npts() if(self._npts != npts): # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] + for n in xrange(self._ncons): + if(npts < self._npts): + if(self._data_len[n] < npts): + self._last_data[n] = self._last_data[n][0:npts] + else: + self._last_data[n] = self._last_data[n][self._data_len[n]-npts:self._data_len[n]] + self._data_len[n] = npts else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] + self._last_data[n] += (npts - self._npts)*[0,] self._npts = npts self.snk.reset() - + if(self._stripchart): # Update the plot data depending on type - if(type(data) == list): - data_r = data[0::2] - data_i = data[1::2] - data = [complex(r,i) for r,i in zip(data_r, data_i)] - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) + for n in xrange(self._ncons): + if(type(data[n]) == list): + data[n] = self.data_to_complex(data[n]) + if(len(data[n]) > self._npts): + self.src[n].set_data(data[n]) + self._last_data[n] = data[n][-self._npts:] + else: + newdata = self._last_data[n][-(self._npts-len(data)):] + newdata += data[n] + self.src[n].set_data(newdata) + self._last_data[n] = newdata + + else: # single value update + if(self._iscomplex): + data[n] = complex(data[n][0], data[n][1]) + if(self._data_len[n] < self._npts): + self._last_data[n][self._data_len[n]] = data[n] + self._data_len[n] += 1 + else: + self._last_data[n] = self._last_data[n][1:] + self._last_data[n].append(data[n]) + self.src[n].set_data(self._last_data[n]) else: - if(type(data) != list): - data = [data,] - self.src.set_data(data) + for n in xrange(self._ncons): + if(type(data[n]) != list): + data[n] = [data[n],] + data[n] = self.data_to_complex(data[n]) + self.src[n].set_data(data[n]) + + -class GrDataPlotterF(gr.top_block): +class GrDataPlotterC(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None, stripchart=False): - gr.top_block.__init__(self) + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) self._stripchart = stripchart - self._name = name - self._npts = 500 - samp_rate = 1.0 + self._datasize = gr.sizeof_gr_complex + self._iscomplex = True - self._last_data = self._npts*[0,] - self._data_len = 0 + self._setup(1) - self.src = gr.vector_source_f([]) - self.thr = blocks.throttle(gr.sizeof_float, rate) - self.snk = qtgui.time_sink_f(self._npts, samp_rate, - self._name, 1) - self.snk.enable_autoscale(True) + def stem(self, en=True): + self.snk.enable_stem_plot(en) - self.connect(self.src, self.thr, (self.snk, 0)) + def get_qtsink(self): + snk = qtgui.time_sink_c(self._npts, 1.0, + self._name, self._ncons) + snk.enable_autoscale(True) + return snk - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + def get_vecsource(self): + return gr.vector_source_c([]) - def __del__(self): - pass + def get_npts(self): + self._npts = self.snk.nsamps() + return self._npts - def qwidget(self): - return self.py_window + def set_line_label(self, n, name): + self.snk.set_line_label(2*n+0, "Re{" + self.knobnames[n] + "}") + self.snk.set_line_label(2*n+1, "Im{" + self.knobnames[n] + "}") - def name(self): - return self._name - def semilogy(self, en=True): - self.snk.enable_semilogy(en) +class GrDataPlotterF(GrDataPlotParent): + def __init__(self, name, rate, pmin=None, pmax=None, stripchart=False): + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - def stem(self, en=True): - self.snk.enable_stem_plot(en) + self._stripchart = stripchart + self._datasize = gr.sizeof_float + self._iscomplex = False - def update(self, data): - # Ask GUI if there has been a change in nsamps - npts = self.snk.nsamps() - if(self._npts != npts): + self._setup(1) - # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] - else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] - self._npts = npts - self.snk.reset() + def stem(self, en=True): + self.snk.enable_stem_plot(en) - if(self._stripchart): - # Update the plot data depending on type - if(type(data) == list): - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) - else: - if(type(data) != list): - data = [data,] - self.src.set_data(data) + def get_qtsink(self): + snk = qtgui.time_sink_f(self._npts, 1.0, + self._name, self._ncons) + snk.enable_autoscale(True) + return snk + + def get_vecsource(self): + return gr.vector_source_f([]) + + def get_npts(self): + self._npts = self.snk.nsamps() + return self._npts + + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) -class GrDataPlotterConst(gr.top_block): + +class GrDataPlotterConst(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self._name = name - self._npts = 500 - samp_rate = 1.0 + self._datasize = gr.sizeof_gr_complex + self._stripchart = False + self._iscomplex = True - self._last_data = self._npts*[0,] - self._data_len = 0 + self._setup(1) - self.src = gr.vector_source_c([]) - self.thr = blocks.throttle(gr.sizeof_gr_complex, rate) - self.snk = qtgui.const_sink_c(self._npts, - self._name, 1) - self.snk.enable_autoscale(True) + def get_qtsink(self): + snk = qtgui.const_sink_c(self._npts, + self._name, + self._ncons) + snk.enable_autoscale(True) + return snk - self.connect(self.src, self.thr, (self.snk, 0)) + def get_vecsource(self): + return gr.vector_source_c([]) - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) - - def __del__(self): - pass - - def qwidget(self): - return self.py_window - - def name(self): - return self._name + def get_npts(self): + self._npts = self.snk.nsamps() + return self._npts def scatter(self, en=True): if(en): @@ -232,327 +266,133 @@ class GrDataPlotterConst(gr.top_block): else: self.snk.set_line_style(0, 1) - def update(self, data): - # Ask GUI if there has been a change in nsamps - npts = self.snk.nsamps() - if(self._npts != npts): - - # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] - else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] - self._npts = npts - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - data_r = data[0::2] - data_i = data[1::2] - data = [complex(r,i) for r,i in zip(data_r, data_i)] - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) -class GrDataPlotterPsdC(gr.top_block): +class GrDataPlotterPsdC(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self._name = name - self._samp_rate = 1.0 - self._fftsize = 2048 + self._datasize = gr.sizeof_gr_complex + self._stripchart = True + self._iscomplex = True + + self._npts = 2048 self._wintype = gr.firdes.WIN_BLACKMAN_hARRIS self._fc = 0 - - self._last_data = self._fftsize*[0,] - self._data_len = 0 - - self.src = gr.vector_source_c([]) - self.thr = blocks.throttle(gr.sizeof_gr_complex, rate) - self.snk = qtgui.freq_sink_c(self._fftsize, self._wintype, - self._fc, self._samp_rate, - self._name, 1) - self.snk.enable_autoscale(True) - self.connect(self.src, self.thr, (self.snk, 0)) + self._setup(1) - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + def get_qtsink(self): + snk = qtgui.freq_sink_c(self._npts, self._wintype, + self._fc, 1.0, + self._name, + self._ncons) + snk.enable_autoscale(True) + return snk - def __del__(self): - pass + def get_vecsource(self): + return gr.vector_source_c([]) - def qwidget(self): - return self.py_window + def get_npts(self): + self._npts = self.snk.fft_size() + return self._npts - def name(self): - return self._name + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) - def update(self, data): - # Ask GUI if there has been a change in nsamps - fftsize = self.snk.fft_size() - if(self._fftsize != fftsize): - # Adjust buffers to accomodate new settings - if(fftsize < self._fftsize): - if(self._data_len < fftsize): - self._last_data = self._last_data[0:fftsize] - else: - self._last_data = self._last_data[self._data_len-fftsize:self._data_len] - self._data_len = fftsize - else: - self._last_data += (fftsize - self._fftsize)*[0,] - self._fftsize = fftsize - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - data_r = data[0::2] - data_i = data[1::2] - data = [complex(r,i) for r,i in zip(data_r, data_i)] - if(len(data) > self._fftsize): - self.src.set_data(data) - self._last_data = data[-self._fftsize:] - else: - newdata = self._last_data[-(self._fftsize-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._fftsize): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) - -class GrDataPlotterPsdF(gr.top_block): +class GrDataPlotterPsdF(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self._name = name - self._samp_rate = 1.0 - self._fftsize = 2048 + self._datasize = gr.sizeof_float + self._stripchart = True + self._iscomplex = False + + self._npts = 2048 self._wintype = gr.firdes.WIN_BLACKMAN_hARRIS self._fc = 0 - - self._last_data = self._fftsize*[0,] - self._data_len = 0 - - self.src = gr.vector_source_f([]) - self.thr = blocks.throttle(gr.sizeof_float, rate) - self.snk = qtgui.freq_sink_f(self._fftsize, self._wintype, - self._fc, self._samp_rate, - self._name, 1) - self.snk.enable_autoscale(True) - self.connect(self.src, self.thr, (self.snk, 0)) + self._setup(1) - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + def get_qtsink(self): + snk = qtgui.freq_sink_f(self._npts, self._wintype, + self._fc, 1.0, + self._name, + self._ncons) + snk.enable_autoscale(True) + return snk - def __del__(self): - pass - - def qwidget(self): - return self.py_window - - def name(self): - return self._name + def get_vecsource(self): + return gr.vector_source_f([]) - def update(self, data): - # Ask GUI if there has been a change in nsamps - fftsize = self.snk.fft_size() - if(self._fftsize != fftsize): + def get_npts(self): + self._npts = self.snk.fft_size() + return self._npts - # Adjust buffers to accomodate new settings - if(fftsize < self._fftsize): - if(self._data_len < fftsize): - self._last_data = self._last_data[0:fftsize] - else: - self._last_data = self._last_data[self._data_len-fftsize:self._data_len] - self._data_len = fftsize - else: - self._last_data += (fftsize - self._fftsize)*[0,] - self._fftsize = fftsize - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - data_r = data[0::2] - data_i = data[1::2] - data = [complex(r,i) for r,i in zip(data_r, data_i)] - if(len(data) > self._fftsize): - self.src.set_data(data) - self._last_data = data[-self._fftsize:] - else: - newdata = self._last_data[-(self._fftsize-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._fftsize): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) -class GrTimeRasterF(gr.top_block): +class GrTimeRasterF(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) - - self._name = name - self._npts = 100 - self._rows = 100 - samp_rate = 1.0 - - self._last_data = self._npts*[0,] - self._data_len = 0 + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self.src = gr.vector_source_f([]) - self.thr = blocks.throttle(gr.sizeof_float, rate) - self.snk = qtgui.time_raster_sink_f(samp_rate, self._npts, self._rows, - [], [], self._name, 1) + self._npts = 10 + self._rows = 40 - self.connect(self.src, self.thr, (self.snk, 0)) + self._datasize = gr.sizeof_float + self._stripchart = False + self._iscomplex = False - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + self._setup(1) - def __del__(self): - pass + def get_qtsink(self): + snk = qtgui.time_raster_sink_f(1.0, self._npts, self._rows, + [], [], self._name, + self._ncons) + return snk - def qwidget(self): - return self.py_window + def get_vecsource(self): + return gr.vector_source_f([]) - def name(self): - return self._name + def get_npts(self): + self._npts = self.snk.num_cols() + return self._npts - def update(self, data): - # Ask GUI if there has been a change in nsamps - npts = int(self.snk.num_cols()) - if(self._npts != npts): - - # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] - else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] - self._npts = npts - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) -class GrTimeRasterB(gr.top_block): +class GrTimeRasterB(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) - - self._name = name - self._npts = 100 - self._rows = 100 - samp_rate = 1.0 + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self._last_data = self._npts*[0,] - self._data_len = 0 + self._npts = 10 + self._rows = 40 - self.src = gr.vector_source_b([]) - self.thr = blocks.throttle(gr.sizeof_char, rate) - self.snk = qtgui.time_raster_sink_b(samp_rate, self._npts, self._rows, - [], [], self._name, 1) + self._datasize = gr.sizeof_char + self._stripchart = False + self._iscomplex = False - self.connect(self.src, self.thr, (self.snk, 0)) + self._setup(1) - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + def get_qtsink(self): + snk = qtgui.time_raster_sink_b(1.0, self._npts, self._rows, + [], [], self._name, + self._ncons) + return snk - def __del__(self): - pass - - def qwidget(self): - return self.py_window - - def name(self): - return self._name + def get_vecsource(self): + return gr.vector_source_b([]) - def update(self, data): - # Ask GUI if there has been a change in nsamps - npts = self.snk.num_cols() - if(self._npts != npts): + def get_npts(self): + self._npts = self.snk.num_cols() + return self._npts - # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] - else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] - self._npts = npts - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) class GrDataPlotterValueTable: diff --git a/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor b/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor index 3f717da5ca..d5d349a38a 100755 --- a/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor +++ b/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor @@ -55,7 +55,7 @@ class MAINWindow(QtGui.QMainWindow): def __init__(self, radio, port, interface): super(MAINWindow, self).__init__() - self.updateRate = 2000; + self.updateRate = 1000; self.conns = [] self.plots = [] self.knobprops = [] @@ -83,7 +83,7 @@ class MAINWindow(QtGui.QMainWindow): icon = QtGui.QIcon(ctrlport.__path__[0] + "/icon.png" ) self.setWindowIcon(icon) - # Locally turn off ControlPort export from GR. This prevents + # Locally turn off ControlPort export from GR. This prevents # our GR-based plotters from launching their own ControlPort # instance (and possibly causing a port collision if one has # been specified). @@ -222,17 +222,44 @@ class MAINWindow(QtGui.QMainWindow): else: self.newPlotPsdC(tag, uid, title) + def startDrag(self, e): + drag = QtGui.QDrag(self) + mime_data = QtCore.QMimeData() + + mime_data.setText(e.text(0)) + drag.setMimeData(mime_data) + + drop = drag.start() + def createPlot(self, plot, uid, title): plot.start() self.plots[uid].append(plot) - self.mdiArea.addSubWindow(plot.qwidget()) - plot.qwidget().setWindowTitle("{0}: {1}".format(title, plot.name())) + self.mdiArea.addSubWindow(plot) + plot.setWindowTitle("{0}: {1}".format(title, plot.name())) self.connect(plot.qwidget(), QtCore.SIGNAL('destroyed(QObject*)'), self.destroyPlot) - plot.qwidget().show() + # when the plot is updated via drag-and-drop, we need to be + # notified of the new qwidget that's created so we can + # properly destroy it. + plot.plotupdated.connect(self.plotUpdated) + + plot.show() + + def plotUpdated(self, q): + # the plot has been updated with a new qwidget; make sure this + # gets dies to the destroyPlot function. + for i, plots in enumerate(self.plots): + for p in plots: + if(p == q): + #plots.remove(p) + #plots.append(q) + self.connect(q.qwidget(), + QtCore.SIGNAL('destroyed(QObject*)'), + self.destroyPlot) + break def destroyPlot(self, obj): for plots in self.plots: @@ -280,7 +307,9 @@ class MAINWindow(QtGui.QMainWindow): def update(self, knobs, uid): #sys.stderr.write("KNOB KEYS: {0}\n".format(knobs.keys())) for plot in self.plots[uid]: - data = knobs[plot.name()].value + data = [] + for n in plot.knobnames: + data.append(knobs[n].value) plot.update(data) plot.stop() plot.wait() @@ -636,7 +665,7 @@ class MForm(QtGui.QWidget): self.constupdatediv = 0 self.tableupdatediv = 0 plotsize=250 - + # make table self.table = GrDataPlotterValueTable(uid, self, 0, 0, 400, 200) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) @@ -644,7 +673,7 @@ class MForm(QtGui.QWidget): self.table.treeWidget.setEditTriggers(QtGui.QAbstractItemView.EditKeyPressed) self.table.treeWidget.setSortingEnabled(True) self.table.treeWidget.setDragEnabled(True) - + # add things to layouts self.horizontalLayout.addWidget(self.table.treeWidget) @@ -662,6 +691,11 @@ class MForm(QtGui.QWidget): QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), self.parent.newSub); + # Allow drag/drop event from table item to plotter + self.connect(self.table.treeWidget, + QtCore.SIGNAL('itemPressed(QTreeWidgetItem*, int)'), + self.parent.startDrag) + def openMenu(self, pos): index = self.table.treeWidget.selectedIndexes() item = self.table.treeWidget.itemFromIndex(index[0]) |