summaryrefslogtreecommitdiff
path: root/gr-wxgui/src/python
diff options
context:
space:
mode:
authorJosh Blum2009-10-12 12:16:12 -0700
committerJosh Blum2009-10-12 12:16:12 -0700
commit5b74bb4d34f381fa8a8af1e1d96ea2d673a8be71 (patch)
treead6a9f64e3b610d008b0fb612772efd4162a82aa /gr-wxgui/src/python
parent57e810d3f07909947a9fb2daeb507b439d5f4f50 (diff)
parent38d5389f3054164a2f04d6e4e8fe381aa5ee03fc (diff)
downloadgnuradio-5b74bb4d34f381fa8a8af1e1d96ea2d673a8be71.tar.gz
gnuradio-5b74bb4d34f381fa8a8af1e1d96ea2d673a8be71.tar.bz2
gnuradio-5b74bb4d34f381fa8a8af1e1d96ea2d673a8be71.zip
Merge commit '38d5389f3054164a2f04d6e4e8fe381aa5ee03fc' into vrt
Diffstat (limited to 'gr-wxgui/src/python')
-rw-r--r--gr-wxgui/src/python/common.py79
-rw-r--r--gr-wxgui/src/python/constsink_gl.py6
-rw-r--r--gr-wxgui/src/python/fftsink_gl.py6
-rw-r--r--gr-wxgui/src/python/histosink_gl.py6
-rw-r--r--gr-wxgui/src/python/numbersink2.py6
-rw-r--r--gr-wxgui/src/python/plotter/common.py1
-rw-r--r--gr-wxgui/src/python/plotter/grid_plotter_base.py11
-rw-r--r--gr-wxgui/src/python/scopesink_gl.py49
-rw-r--r--gr-wxgui/src/python/waterfallsink_gl.py6
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