diff options
author | Johnathan Corgan | 2009-10-08 22:12:41 -0700 |
---|---|---|
committer | Johnathan Corgan | 2009-10-08 22:12:41 -0700 |
commit | 7ba8192e28713049324398f4b0c6d2eebdaa1fc7 (patch) | |
tree | e9b0d49e60cd6bf82c8d56f203a450f90d4f4337 /gr-wxgui/src/python | |
parent | 3a3cfaf293a46d83ffb905de04b43f3b1ff07d88 (diff) | |
parent | 38d5389f3054164a2f04d6e4e8fe381aa5ee03fc (diff) | |
download | gnuradio-7ba8192e28713049324398f4b0c6d2eebdaa1fc7.tar.gz gnuradio-7ba8192e28713049324398f4b0c6d2eebdaa1fc7.tar.bz2 gnuradio-7ba8192e28713049324398f4b0c6d2eebdaa1fc7.zip |
Merge branch 'wip/wxgui' of http://gnuradio.org/git/jblum
* 'wip/wxgui' of http://gnuradio.org/git/jblum:
using gr copy in the wxgui connect, added gr copy to grc xml
Added gr.copy(itemsize) block
point label transpareny, horizontal offset, and toggle on/off capability
simplify some params
moved the wxgui connect helper functions into the wrapper class
making use of update ui event
setup special wxgui connect on sinks, needs testing
working special connect for fftsink
work on a special connect function that registers a callback
added bind to visible event function to callback when visibility changes within tabs
Diffstat (limited to 'gr-wxgui/src/python')
-rw-r--r-- | gr-wxgui/src/python/common.py | 79 | ||||
-rw-r--r-- | gr-wxgui/src/python/constsink_gl.py | 6 | ||||
-rw-r--r-- | gr-wxgui/src/python/fftsink_gl.py | 6 | ||||
-rw-r--r-- | gr-wxgui/src/python/histosink_gl.py | 6 | ||||
-rw-r--r-- | gr-wxgui/src/python/numbersink2.py | 6 | ||||
-rw-r--r-- | gr-wxgui/src/python/plotter/common.py | 1 | ||||
-rw-r--r-- | gr-wxgui/src/python/plotter/grid_plotter_base.py | 11 | ||||
-rw-r--r-- | gr-wxgui/src/python/scopesink_gl.py | 49 | ||||
-rw-r--r-- | gr-wxgui/src/python/waterfallsink_gl.py | 6 |
9 files changed, 129 insertions, 41 deletions
diff --git a/gr-wxgui/src/python/common.py b/gr-wxgui/src/python/common.py index 9c97ce1ec..fa11b3152 100644 --- a/gr-wxgui/src/python/common.py +++ b/gr-wxgui/src/python/common.py @@ -19,6 +19,85 @@ # Boston, MA 02110-1301, USA. # +################################################## +# conditional disconnections of wx flow graph +################################################## +import wx +from gnuradio import gr + +class wxgui_hb(object): + """ + The wxgui hier block helper/wrapper class: + A hier block should inherit from this class to make use of the wxgui connect method. + To use, call wxgui_connect in place of regular connect; self.win must be defined. + The implementation will conditionally enable the copy block after the source (self). + This condition depends on weather or not the window is visible with the parent notebooks. + This condition will be re-checked on every ui update event. + """ + + def wxgui_connect(self, *points): + """ + Use wxgui connect when the first point is the self source of the hb. + The win property of this object should be set to the wx window. + When this method tries to connect self to the next point, + it will conditionally make this connection based on the visibility state. + All other points will be connected normally. + """ + try: + assert points[0] == self or points[0][0] == self + copy = gr.copy(self._hb.input_signature().sizeof_stream_item(0)) + handler = self._handler_factory(copy.set_enabled) + handler(False) #initially disable the copy block + self._bind_to_visible_event(win=self.win, handler=handler) + points = list(points) + points.insert(1, copy) #insert the copy block into the chain + except (AssertionError, IndexError): pass + self.connect(*points) #actually connect the blocks + + @staticmethod + def _handler_factory(handler): + """ + Create a function that will cache the visibility flag, + and only call the handler when that flag changes. + @param handler the function to call on a change + @return a function of 1 argument + """ + cache = [None] + def callback(visible): + if cache[0] == visible: return + cache[0] = visible + #print visible, handler + handler(visible) + return callback + + @staticmethod + def _bind_to_visible_event(win, handler): + """ + Bind a handler to a window when its visibility changes. + Specifically, call the handler when the window visibility changes. + This condition is checked on every update ui event. + @param win the wx window + @param handler a function of 1 param + """ + #is the window visible in the hierarchy + def is_wx_window_visible(my_win): + while True: + parent = my_win.GetParent() + if not parent: return True #reached the top of the hierarchy + #if we are hidden, then finish, otherwise keep traversing up + if isinstance(parent, wx.Notebook) and parent.GetCurrentPage() != my_win: return False + my_win = parent + #call the handler, the arg is shown or not + def handler_factory(my_win, my_handler): + return lambda *args: my_handler(is_wx_window_visible(my_win)) + handler = handler_factory(win, handler) + #bind the handler to all the parent notebooks + win.Bind(wx.EVT_UPDATE_UI, handler) + +################################################## +# Helpful Functions +################################################## + #A macro to apply an index to a key index_key = lambda key, i: "%s_%d"%(key, i+1) diff --git a/gr-wxgui/src/python/constsink_gl.py b/gr-wxgui/src/python/constsink_gl.py index b3a1625b0..91bc65d9f 100644 --- a/gr-wxgui/src/python/constsink_gl.py +++ b/gr-wxgui/src/python/constsink_gl.py @@ -31,7 +31,7 @@ from constants import * ################################################## # Constellation sink block (wrapper for old wxgui) ################################################## -class const_sink_c(gr.hier_block2): +class const_sink_c(gr.hier_block2, common.wxgui_hb): """ A constellation block with a gui window. """ @@ -94,8 +94,6 @@ class const_sink_c(gr.hier_block2): agc = gr.feedforward_agc_cc(16, 1) msgq = gr.msg_queue(2) sink = gr.message_sink(gr.sizeof_gr_complex*const_size, msgq, True) - #connect - self.connect(self, self._costas, self._retime, agc, sd, sink) #controller def setter(p, k, x): p[k] = x self.controller = pubsub() @@ -131,5 +129,7 @@ class const_sink_c(gr.hier_block2): sample_rate_key=SAMPLE_RATE_KEY, ) common.register_access_methods(self, self.win) + #connect + self.wxgui_connect(self, self._costas, self._retime, agc, sd, sink) diff --git a/gr-wxgui/src/python/fftsink_gl.py b/gr-wxgui/src/python/fftsink_gl.py index 3f0a93fc8..9d683d697 100644 --- a/gr-wxgui/src/python/fftsink_gl.py +++ b/gr-wxgui/src/python/fftsink_gl.py @@ -31,7 +31,7 @@ from constants import * ################################################## # FFT sink block (wrapper for old wxgui) ################################################## -class _fft_sink_base(gr.hier_block2): +class _fft_sink_base(gr.hier_block2, common.wxgui_hb): """ An fft block with real/complex inputs and a gui window. """ @@ -73,8 +73,6 @@ class _fft_sink_base(gr.hier_block2): ) msgq = gr.msg_queue(2) sink = gr.message_sink(gr.sizeof_float*fft_size, msgq, True) - #connect - self.connect(self, fft, sink) #controller self.controller = pubsub() self.controller.subscribe(AVERAGE_KEY, fft.set_average) @@ -106,6 +104,8 @@ class _fft_sink_base(gr.hier_block2): common.register_access_methods(self, self.win) setattr(self.win, 'set_baseband_freq', getattr(self, 'set_baseband_freq')) #BACKWARDS setattr(self.win, 'set_peak_hold', getattr(self, 'set_peak_hold')) #BACKWARDS + #connect + self.wxgui_connect(self, fft, sink) class fft_sink_f(_fft_sink_base): _fft_chain = blks2.logpwrfft_f diff --git a/gr-wxgui/src/python/histosink_gl.py b/gr-wxgui/src/python/histosink_gl.py index db6606e41..509f746be 100644 --- a/gr-wxgui/src/python/histosink_gl.py +++ b/gr-wxgui/src/python/histosink_gl.py @@ -31,7 +31,7 @@ from constants import * ################################################## # histo sink block (wrapper for old wxgui) ################################################## -class histo_sink_f(gr.hier_block2): +class histo_sink_f(gr.hier_block2, common.wxgui_hb): """ A histogram block and a gui window. """ @@ -56,8 +56,6 @@ class histo_sink_f(gr.hier_block2): histo = gr.histo_sink_f(msgq) histo.set_num_bins(num_bins) histo.set_frame_size(frame_size) - #connect - self.connect(self, histo) #controller self.controller = pubsub() self.controller.subscribe(NUM_BINS_KEY, histo.set_num_bins) @@ -79,6 +77,8 @@ class histo_sink_f(gr.hier_block2): msg_key=MSG_KEY, ) common.register_access_methods(self, self.win) + #connect + self.wxgui_connect(self, histo) # ---------------------------------------------------------------- # Standalone test app diff --git a/gr-wxgui/src/python/numbersink2.py b/gr-wxgui/src/python/numbersink2.py index 7f853e6a4..011acdfd5 100644 --- a/gr-wxgui/src/python/numbersink2.py +++ b/gr-wxgui/src/python/numbersink2.py @@ -31,7 +31,7 @@ from constants import * ################################################## # Number sink block (wrapper for old wxgui) ################################################## -class _number_sink_base(gr.hier_block2): +class _number_sink_base(gr.hier_block2, common.wxgui_hb): """ An decimator block with a number window display """ @@ -81,8 +81,6 @@ class _number_sink_base(gr.hier_block2): avg = gr.single_pole_iir_filter_cc(1.0) msgq = gr.msg_queue(2) sink = gr.message_sink(self._item_size, msgq, True) - #connect - self.connect(self, sd, mult, add, avg, sink) #controller self.controller = pubsub() self.controller.subscribe(SAMPLE_RATE_KEY, sd.set_sample_rate) @@ -118,6 +116,8 @@ class _number_sink_base(gr.hier_block2): common.register_access_methods(self, self.controller) #backwards compadibility self.set_show_gauge = self.win.show_gauges + #connect + self.wxgui_connect(self, sd, mult, add, avg, sink) class number_sink_f(_number_sink_base): _item_size = gr.sizeof_float diff --git a/gr-wxgui/src/python/plotter/common.py b/gr-wxgui/src/python/plotter/common.py index 7699986aa..4c50cd787 100644 --- a/gr-wxgui/src/python/plotter/common.py +++ b/gr-wxgui/src/python/plotter/common.py @@ -102,6 +102,7 @@ class point_label_thread(threading.Thread, mutex): #bind plotter mouse events self._plotter.Bind(wx.EVT_MOTION, lambda evt: self.enqueue(evt.GetPosition())) self._plotter.Bind(wx.EVT_LEAVE_WINDOW, lambda evt: self.enqueue(None)) + self._plotter.Bind(wx.EVT_RIGHT_DOWN, lambda evt: plotter.enable_point_label(not plotter.enable_point_label())) #start the thread threading.Thread.__init__(self) self.start() diff --git a/gr-wxgui/src/python/plotter/grid_plotter_base.py b/gr-wxgui/src/python/plotter/grid_plotter_base.py index 39bed1811..a9bd02731 100644 --- a/gr-wxgui/src/python/plotter/grid_plotter_base.py +++ b/gr-wxgui/src/python/plotter/grid_plotter_base.py @@ -36,8 +36,9 @@ AXIS_LABEL_PADDING = 5 TICK_LABEL_PADDING = 5 TITLE_LABEL_PADDING = 7 POINT_LABEL_FONT_SIZE = 8 -POINT_LABEL_COLOR_SPEC = (1, 1, .5) +POINT_LABEL_COLOR_SPEC = (1, 1, 0.5, 0.75) POINT_LABEL_PADDING = 3 +POINT_LABEL_OFFSET = 10 GRID_LINE_DASH_LEN = 4 ################################################## @@ -395,8 +396,12 @@ class grid_plotter_base(plotter_base): if not label_str: return txt = gltext.Text(label_str, font_size=POINT_LABEL_FONT_SIZE) w, h = txt.get_size() + #enable transparency + GL.glEnable(GL.GL_BLEND) + GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA) #draw rect + text - GL.glColor3f(*POINT_LABEL_COLOR_SPEC) - if x > self.width/2: x -= w+2*POINT_LABEL_PADDING + GL.glColor4f(*POINT_LABEL_COLOR_SPEC) + if x > self.width/2: x -= w+2*POINT_LABEL_PADDING + POINT_LABEL_OFFSET + else: x += POINT_LABEL_OFFSET self._draw_rect(x, y-h-2*POINT_LABEL_PADDING, w+2*POINT_LABEL_PADDING, h+2*POINT_LABEL_PADDING) txt.draw_text(wx.Point(x+POINT_LABEL_PADDING, y-h-POINT_LABEL_PADDING)) diff --git a/gr-wxgui/src/python/scopesink_gl.py b/gr-wxgui/src/python/scopesink_gl.py index a5e3ca3ce..2882488e3 100644 --- a/gr-wxgui/src/python/scopesink_gl.py +++ b/gr-wxgui/src/python/scopesink_gl.py @@ -34,7 +34,7 @@ class ac_couple_block(gr.hier_block2): Mute the low pass filter to disable ac coupling. """ - def __init__(self, controller, ac_couple_key, ac_couple, sample_rate_key): + def __init__(self, controller, ac_couple_key, sample_rate_key): gr.hier_block2.__init__( self, "ac_couple", @@ -52,13 +52,13 @@ class ac_couple_block(gr.hier_block2): controller.subscribe(ac_couple_key, lambda x: mute.set_mute(not x)) controller.subscribe(sample_rate_key, lambda x: lpf.set_taps(0.05)) #initialize - controller[ac_couple_key] = ac_couple + controller[ac_couple_key] = controller[ac_couple_key] controller[sample_rate_key] = controller[sample_rate_key] ################################################## # Scope sink block (wrapper for old wxgui) ################################################## -class _scope_sink_base(gr.hier_block2): +class _scope_sink_base(gr.hier_block2, common.wxgui_hb): """ A scope block with a gui window. """ @@ -102,25 +102,10 @@ class _scope_sink_base(gr.hier_block2): self.controller.publish(TRIGGER_SLOPE_KEY, scope.get_trigger_slope) self.controller.subscribe(TRIGGER_CHANNEL_KEY, scope.set_trigger_channel) self.controller.publish(TRIGGER_CHANNEL_KEY, scope.get_trigger_channel) - #connect - if self._real: - for i in range(num_inputs): - self.connect( - (self, i), - ac_couple_block(self.controller, common.index_key(AC_COUPLE_KEY, i), ac_couple, SAMPLE_RATE_KEY), - (scope, i), - ) - else: - for i in range(num_inputs): - c2f = gr.complex_to_float() - self.connect((self, i), c2f) - for j in range(2): - self.connect( - (c2f, j), - ac_couple_block(self.controller, common.index_key(AC_COUPLE_KEY, 2*i+j), ac_couple, SAMPLE_RATE_KEY), - (scope, 2*i+j), - ) - num_inputs *= 2 + actual_num_inputs = self._real and num_inputs or num_inputs*2 + #init ac couple + for i in range(actual_num_inputs): + self.controller[common.index_key(AC_COUPLE_KEY, i)] = ac_couple #start input watcher common.input_watcher(msgq, self.controller, MSG_KEY) #create window @@ -130,7 +115,7 @@ class _scope_sink_base(gr.hier_block2): size=size, title=title, frame_rate=frame_rate, - num_inputs=num_inputs, + num_inputs=actual_num_inputs, sample_rate_key=SAMPLE_RATE_KEY, t_scale=t_scale, v_scale=v_scale, @@ -144,6 +129,24 @@ class _scope_sink_base(gr.hier_block2): msg_key=MSG_KEY, ) common.register_access_methods(self, self.win) + #connect + if self._real: + for i in range(num_inputs): + self.wxgui_connect( + (self, i), + ac_couple_block(self.controller, common.index_key(AC_COUPLE_KEY, i), SAMPLE_RATE_KEY), + (scope, i), + ) + else: + for i in range(num_inputs): + c2f = gr.complex_to_float() + self.wxgui_connect((self, i), c2f) + for j in range(2): + self.connect( + (c2f, j), + ac_couple_block(self.controller, common.index_key(AC_COUPLE_KEY, 2*i+j), SAMPLE_RATE_KEY), + (scope, 2*i+j), + ) class scope_sink_f(_scope_sink_base): _item_size = gr.sizeof_float diff --git a/gr-wxgui/src/python/waterfallsink_gl.py b/gr-wxgui/src/python/waterfallsink_gl.py index 2d4c959f8..37844399e 100644 --- a/gr-wxgui/src/python/waterfallsink_gl.py +++ b/gr-wxgui/src/python/waterfallsink_gl.py @@ -31,7 +31,7 @@ from constants import * ################################################## # Waterfall sink block (wrapper for old wxgui) ################################################## -class _waterfall_sink_base(gr.hier_block2): +class _waterfall_sink_base(gr.hier_block2, common.wxgui_hb): """ An fft block with real/complex inputs and a gui window. """ @@ -73,8 +73,6 @@ class _waterfall_sink_base(gr.hier_block2): ) msgq = gr.msg_queue(2) sink = gr.message_sink(gr.sizeof_float*fft_size, msgq, True) - #connect - self.connect(self, fft, sink) #controller self.controller = pubsub() self.controller.subscribe(AVERAGE_KEY, fft.set_average) @@ -110,6 +108,8 @@ class _waterfall_sink_base(gr.hier_block2): ) common.register_access_methods(self, self.win) setattr(self.win, 'set_baseband_freq', getattr(self, 'set_baseband_freq')) #BACKWARDS + #connect + self.wxgui_connect(self, fft, sink) class waterfall_sink_f(_waterfall_sink_base): _fft_chain = blks2.logpwrfft_f |