diff options
Diffstat (limited to 'gr-wxgui/src')
29 files changed, 814 insertions, 967 deletions
diff --git a/gr-wxgui/src/.gitignore b/gr-wxgui/src/.gitignore deleted file mode 100644 index f9c5da0db..000000000 --- a/gr-wxgui/src/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -/Makefile -/Makefile.in -/.deps -/.libs -/*.la -/*.lo -/*.pyc -/*.pyo diff --git a/gr-wxgui/src/Makefile.am b/gr-wxgui/src/Makefile.am deleted file mode 100644 index b6207ff05..000000000 --- a/gr-wxgui/src/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright 2004 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 $(top_srcdir)/Makefile.common - -SUBDIRS = python diff --git a/gr-wxgui/src/python/.gitignore b/gr-wxgui/src/python/.gitignore deleted file mode 100644 index f9c5da0db..000000000 --- a/gr-wxgui/src/python/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -/Makefile -/Makefile.in -/.deps -/.libs -/*.la -/*.lo -/*.pyc -/*.pyo diff --git a/gr-wxgui/src/python/Makefile.am b/gr-wxgui/src/python/Makefile.am deleted file mode 100644 index 2382d599c..000000000 --- a/gr-wxgui/src/python/Makefile.am +++ /dev/null @@ -1,69 +0,0 @@ -# -# Copyright 2004,2005,2008,2009 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 $(top_srcdir)/Makefile.common - -SUBDIRS = plotter - -# Install this stuff so that it ends up as the gnuradio.wxgui module -# This usually ends up at: -# ${prefix}/lib/python${python_version}/site-packages/gnuradio/wxgui - -ourpythondir = $(grpythondir)/wxgui -ourlibdir = $(grpyexecdir)/wxgui - -ourpython_PYTHON = \ - __init__.py \ - common.py \ - constants.py \ - constsink_gl.py \ - const_window.py \ - form.py \ - fftsink2.py \ - fftsink_nongl.py \ - fftsink_gl.py \ - fft_window.py \ - gui.py \ - histosink_gl.py \ - histo_window.py \ - numbersink2.py \ - number_window.py \ - plot.py \ - powermate.py \ - pubsub.py \ - scopesink2.py \ - scopesink_nongl.py \ - scopesink_gl.py \ - scope_window.py \ - termsink.py \ - waterfallsink2.py \ - waterfallsink_nongl.py \ - waterfallsink_gl.py \ - waterfall_window.py \ - slider.py \ - stdgui2.py - -formspythondir = $(grpythondir)/wxgui/forms - -formspython_PYTHON = \ - forms/__init__.py \ - forms/forms.py \ - forms/converters.py diff --git a/gr-wxgui/src/python/__init__.py b/gr-wxgui/src/python/__init__.py index a1cfeb223..68f8f4b5e 100644 --- a/gr-wxgui/src/python/__init__.py +++ b/gr-wxgui/src/python/__init__.py @@ -1,23 +1,23 @@ # # Copyright 2011 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. -# +# ''' This is the gr-wxgui package. This package provides a GUI interface diff --git a/gr-wxgui/src/python/common.py b/gr-wxgui/src/python/common.py index 3641ae644..1410d29df 100644 --- a/gr-wxgui/src/python/common.py +++ b/gr-wxgui/src/python/common.py @@ -121,7 +121,7 @@ def _register_access_method(destination, controller, key): def set(value): controller[key] = value setattr(destination, 'set_'+key, set) def get(): return controller[key] - setattr(destination, 'get_'+key, get) + setattr(destination, 'get_'+key, get) def register_access_methods(destination, controller): """ diff --git a/gr-wxgui/src/python/fft_window.py b/gr-wxgui/src/python/fft_window.py index f4f485f4b..99c1cf6e1 100644 --- a/gr-wxgui/src/python/fft_window.py +++ b/gr-wxgui/src/python/fft_window.py @@ -127,7 +127,7 @@ class control_panel(wx.Panel): parent.subscribe(USE_PERSISTENCE_KEY, widget.ShowItems) #allways show initially, so room is reserved for them widget.ShowItems(True) # (parent[USE_PERSISTENCE_KEY]) - + parent.subscribe(USE_PERSISTENCE_KEY, self._update_layout) #trace menu @@ -201,7 +201,7 @@ class control_panel(wx.Panel): # Just ignore the key value we get # we only need to now that the visability or size of something has changed self.parent.Layout() - #self.parent.Fit() + #self.parent.Fit() ################################################## # FFT window with plotter and control panel diff --git a/gr-wxgui/src/python/fftsink_gl.py b/gr-wxgui/src/python/fftsink_gl.py index 6cfaeff60..6b268f6cb 100644 --- a/gr-wxgui/src/python/fftsink_gl.py +++ b/gr-wxgui/src/python/fftsink_gl.py @@ -63,14 +63,14 @@ class _fft_sink_base(gr.hier_block2, common.wxgui_hb): #ensure avg alpha if avg_alpha is None: avg_alpha = 2.0/fft_rate #ensure analog alpha - if persist_alpha is None: + if persist_alpha is None: actual_fft_rate=float(sample_rate/fft_size)/float(max(1,int(float((sample_rate/fft_size)/fft_rate)))) #print "requested_fft_rate ",fft_rate #print "actual_fft_rate ",actual_fft_rate analog_cutoff_freq=0.5 # Hertz #calculate alpha from wanted cutoff freq persist_alpha = 1.0 - math.exp(-2.0*math.pi*analog_cutoff_freq/actual_fft_rate) - + #init gr.hier_block2.__init__( self, diff --git a/gr-wxgui/src/python/fftsink_nongl.py b/gr-wxgui/src/python/fftsink_nongl.py index 508b4e772..c756d8a3b 100644 --- a/gr-wxgui/src/python/fftsink_nongl.py +++ b/gr-wxgui/src/python/fftsink_nongl.py @@ -1,31 +1,31 @@ #!/usr/bin/env python # # Copyright 2003,2004,2005,2006,2007,2009,2010 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. -# +# from gnuradio import gr, gru, window from gnuradio.wxgui import stdgui2 import wx import plot import numpy -import math +import math DIV_LEVELS = (1, 2, 5, 10, 20) @@ -33,7 +33,7 @@ default_fftsink_size = (640,240) default_fft_rate = gr.prefs().get_long('wxgui', 'fft_rate', 15) class fft_sink_base(object): - def __init__(self, input_is_real=False, baseband_freq=0, y_per_div=10, + def __init__(self, input_is_real=False, baseband_freq=0, y_per_div=10, y_divs=8, ref_level=50, sample_rate=1, fft_size=512, fft_rate=default_fft_rate, @@ -73,7 +73,7 @@ class fft_sink_base(object): else: self.avg.set_taps(1.0) self.win.peak_vals = None - + def set_peak_hold(self, enable): self.peak_hold = enable self.win.set_peak_hold(enable) @@ -98,7 +98,7 @@ class fft_sink_base(object): def _set_n(self): self.one_in_n.set_n(max(1, int(self.sample_rate/self.fft_size/self.fft_rate))) - + class fft_sink_f(gr.hier_block2, fft_sink_base): def __init__(self, parent, baseband_freq=0, ref_scale=2.0, @@ -116,17 +116,17 @@ class fft_sink_f(gr.hier_block2, fft_sink_base): fft_rate=fft_rate, average=average, avg_alpha=avg_alpha, title=title, peak_hold=peak_hold,use_persistence=use_persistence,persist_alpha=persist_alpha) - + self.s2p = gr.stream_to_vector(gr.sizeof_float, self.fft_size) self.one_in_n = gr.keep_one_in_n(gr.sizeof_float * self.fft_size, max(1, int(self.sample_rate/self.fft_size/self.fft_rate))) - + mywindow = window.blackmanharris(self.fft_size) self.fft = gr.fft_vfc(self.fft_size, True, mywindow) power = 0 for tap in mywindow: power += tap*tap - + self.c2mag = gr.complex_to_mag(self.fft_size) self.avg = gr.single_pole_iir_filter_ff(1.0, self.fft_size) @@ -135,7 +135,7 @@ class fft_sink_f(gr.hier_block2, fft_sink_base): -10*math.log10(self.fft_size) # Adjust for number of bins -10*math.log10(power/self.fft_size) # Adjust for windowing loss -20*math.log10(ref_scale/2)) # Adjust for reference scale - + self.sink = gr.message_sink(gr.sizeof_float * self.fft_size, self.msgq, True) self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink) @@ -165,13 +165,13 @@ class fft_sink_c(gr.hier_block2, fft_sink_base): self.s2p = gr.stream_to_vector(gr.sizeof_gr_complex, self.fft_size) self.one_in_n = gr.keep_one_in_n(gr.sizeof_gr_complex * self.fft_size, max(1, int(self.sample_rate/self.fft_size/self.fft_rate))) - + mywindow = window.blackmanharris(self.fft_size) self.fft = gr.fft_vcc(self.fft_size, True, mywindow) power = 0 for tap in mywindow: power += tap*tap - + self.c2mag = gr.complex_to_mag(self.fft_size) self.avg = gr.single_pole_iir_filter_ff(1.0, self.fft_size) @@ -180,7 +180,7 @@ class fft_sink_c(gr.hier_block2, fft_sink_base): -10*math.log10(self.fft_size) # Adjust for number of bins -10*math.log10(power/self.fft_size) # Adjust for windowing loss -20*math.log10(ref_scale/2)) # Adjust for reference scale - + self.sink = gr.message_sink(gr.sizeof_float * self.fft_size, self.msgq, True) self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink) @@ -203,7 +203,7 @@ class DataEvent(wx.PyEvent): self.SetEventType (myDATA_EVENT) self.data = data - def Clone (self): + def Clone (self): self.__class__ (self.GetId()) @@ -231,20 +231,20 @@ class input_watcher (gru.msgq_runner): del de class control_panel(wx.Panel): - - class LabelText(wx.StaticText): + + class LabelText(wx.StaticText): def __init__(self, window, label): wx.StaticText.__init__(self, window, -1, label) font = self.GetFont() font.SetWeight(wx.FONTWEIGHT_BOLD) font.SetUnderlined(True) self.SetFont(font) - + def __init__(self, parent): self.parent = parent - wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER) + wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER) control_box = wx.BoxSizer(wx.VERTICAL) - + #checkboxes for average and peak hold control_box.AddStretchSpacer() control_box.Add(self.LabelText(self, 'Options'), 0, wx.ALIGN_CENTER) @@ -255,9 +255,9 @@ class control_panel(wx.Panel): self.use_persistence_check_box.Bind(wx.EVT_CHECKBOX, parent.on_use_persistence) control_box.Add(self.use_persistence_check_box, 0, wx.EXPAND) self.peak_hold_check_box = wx.CheckBox(parent=self, style=wx.CHK_2STATE, label="Peak Hold") - self.peak_hold_check_box.Bind(wx.EVT_CHECKBOX, parent.on_peak_hold) + self.peak_hold_check_box.Bind(wx.EVT_CHECKBOX, parent.on_peak_hold) control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND) - + #radio buttons for div size control_box.AddStretchSpacer() control_box.Add(self.LabelText(self, 'Set dB/div'), 0, wx.ALIGN_CENTER) @@ -269,12 +269,12 @@ class control_panel(wx.Panel): self.radio_buttons.append(radio_button) radio_box.Add(radio_button, 0, wx.ALIGN_LEFT) control_box.Add(radio_box, 0, wx.EXPAND) - + #ref lvl buttons control_box.AddStretchSpacer() control_box.Add(self.LabelText(self, 'Adj Ref Lvl'), 0, wx.ALIGN_CENTER) control_box.AddSpacer(2) - button_box = wx.BoxSizer(wx.HORIZONTAL) + button_box = wx.BoxSizer(wx.HORIZONTAL) self.ref_plus_button = wx.Button(self, -1, '+', style=wx.BU_EXACTFIT) self.ref_plus_button.Bind(wx.EVT_BUTTON, parent.on_incr_ref_level) button_box.Add(self.ref_plus_button, 0, wx.ALIGN_CENTER) @@ -287,7 +287,7 @@ class control_panel(wx.Panel): self.SetSizerAndFit(control_box) #update self.update() - + def update(self): """ Read the state of the fft plot settings and update the control panel. @@ -296,14 +296,14 @@ class control_panel(wx.Panel): self.average_check_box.SetValue(self.parent.fftsink.average) self.use_persistence_check_box.SetValue(self.parent.fftsink.use_persistence) self.peak_hold_check_box.SetValue(self.parent.fftsink.peak_hold) - #update radio buttons + #update radio buttons try: index = list(DIV_LEVELS).index(self.parent.fftsink.y_per_div) self.radio_buttons[index].SetValue(True) except: pass - + def on_radio_button_change(self, evt): - selected_radio_button = filter(lambda rb: rb.GetValue(), self.radio_buttons)[0] + selected_radio_button = filter(lambda rb: rb.GetValue(), self.radio_buttons)[0] index = self.radio_buttons.index(selected_radio_button) self.parent.fftsink.set_y_per_div(DIV_LEVELS[index]) @@ -311,41 +311,41 @@ class fft_window (wx.Panel): def __init__ (self, fftsink, parent, id = -1, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = ""): - + self.fftsink = fftsink - #init panel and plot - wx.Panel.__init__(self, parent, -1) - self.plot = plot.PlotCanvas(self, id, pos, size, style, name) + #init panel and plot + wx.Panel.__init__(self, parent, -1) + self.plot = plot.PlotCanvas(self, id, pos, size, style, name) #setup the box with plot and controls self.control_panel = control_panel(self) main_box = wx.BoxSizer (wx.HORIZONTAL) main_box.Add (self.plot, 1, wx.EXPAND) main_box.Add (self.control_panel, 0, wx.EXPAND) self.SetSizerAndFit(main_box) - + self.peak_hold = False self.peak_vals = None self.use_persistence=False self.persist_alpha=0.2 - + self.plot.SetEnableGrid (True) # self.SetEnableZoom (True) # self.SetBackgroundColour ('black') - + self.build_popup_menu() self.set_baseband_freq(self.fftsink.baseband_freq) - + EVT_DATA_EVENT (self, self.set_data) wx.EVT_CLOSE (self, self.on_close_window) self.plot.Bind(wx.EVT_RIGHT_UP, self.on_right_click) self.plot.Bind(wx.EVT_MOTION, self.evt_motion) - + self.input_watcher = input_watcher(fftsink.msgq, fftsink.fft_size, self) def set_scale(self, freq): - x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq)) + x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq)) if x >= 1e9: self._scale_factor = 1e-9 self._units = "GHz" @@ -364,7 +364,7 @@ class fft_window (wx.Panel): self.peak_vals = None self.set_scale(baseband_freq) self.fftsink.set_baseband_freq(baseband_freq) - + def on_close_window (self, event): print "fft_window:on_close_window" self.keep_running = False @@ -381,7 +381,7 @@ class fft_window (wx.Panel): self.peak_vals = numpy.maximum(dB, self.peak_vals) if self.fftsink.input_is_real: # only plot 1/2 the points - x_vals = ((numpy.arange (L/2) * (self.fftsink.sample_rate + x_vals = ((numpy.arange (L/2) * (self.fftsink.sample_rate * self._scale_factor / L)) + self.fftsink.baseband_freq * self._scale_factor) self._points = numpy.zeros((len(x_vals), 2), numpy.float64) @@ -415,7 +415,7 @@ class fft_window (wx.Panel): ymax = self.fftsink.ref_level ymin = self.fftsink.ref_level - self.fftsink.y_per_div * self.fftsink.y_divs y_range = ymin, ymax - self.plot.Draw (graphics, xAxis=x_range, yAxis=y_range, step=self.fftsink.y_per_div) + self.plot.Draw (graphics, xAxis=x_range, yAxis=y_range, step=self.fftsink.y_per_div) def set_use_persistence(self, enable): self.use_persistence = enable @@ -489,7 +489,7 @@ class fft_window (wx.Panel): def evt_motion(self, event): if not hasattr(self, "_points"): return # Got here before first window data update - + # Clip to plotted values (ux, uy) = self.plot.GetXY(event) # Scaled position x_vals = numpy.array(self._points[:,0]) @@ -510,7 +510,7 @@ class fft_window (wx.Panel): tip.Enable(True) tip.SetDelay(0) self.SetToolTip(tip) - + def build_popup_menu(self): self.id_incr_ref_level = wx.NewId() self.id_decr_ref_level = wx.NewId() @@ -524,7 +524,7 @@ class fft_window (wx.Panel): self.id_average = wx.NewId() self.id_use_persistence = wx.NewId() self.id_peak_hold = wx.NewId() - + self.plot.Bind(wx.EVT_MENU, self.on_average, id=self.id_average) self.plot.Bind(wx.EVT_MENU, self.on_use_persistence, id=self.id_use_persistence) self.plot.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold) @@ -537,7 +537,7 @@ class fft_window (wx.Panel): self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_5) self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_10) self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_20) - + # make a menu menu = wx.Menu() self.popup_menu = menu diff --git a/gr-wxgui/src/python/form.py b/gr-wxgui/src/python/form.py index b55b04d73..0442e49c8 100644 --- a/gr-wxgui/src/python/form.py +++ b/gr-wxgui/src/python/form.py @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2005 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. -# +# import wx from gnuradio import eng_notation @@ -32,7 +32,7 @@ def button_with_callback(parent, label, callback): btn = wx.Button(parent, new_id, label) wx.EVT_BUTTON(parent, new_id, lambda evt: callback()) return btn - + # ---------------------------------------------------------------- # Format converters @@ -128,7 +128,7 @@ class field(object): sizer.Add(label_widget, 0, wx.EXPAND) sizer.Add(widget, weight, wx.EXPAND) return widget - + def _error_msg(self): prefix = '' if self.label: @@ -223,7 +223,7 @@ class quantized_slider_field(field): self.max = range[1] self.step_size = float(range[2]) nsteps = int((self.max-self.min)/self.step_size) - + new_id = wx.NewId() w = wx.Slider(parent, new_id, 0, 0, nsteps, size=wx.Size(250, -1), style=wx.SL_HORIZONTAL) @@ -272,7 +272,7 @@ class radiobox_field(field): style=wx.RA_SPECIFY_ROWS | wx.RA_HORIZONTAL else: style=wx.RA_SPECIFY_COLS | wx.RA_HORIZONTAL - + w = wx.RadioBox(parent, new_id, label=label, style=style, majorDimension=major_dimension, choices=choices) self.f = self._pair_with_label(w, parent=parent, sizer=sizer, label=None, weight=weight) @@ -301,7 +301,7 @@ class form(dict): """ vals = [f.get_value_with_check() for f in self.values()] return [t[1] for t in vals if t[1] is not None] - + def get_key_vals(self): d = {} for (key, f) in self.items(): @@ -310,7 +310,7 @@ class form(dict): def _nop(*args): pass - + def check_input_and_call(self, callback, status_handler=_nop): """ Return a function that checks the form for errors, and then if it's OK, @@ -352,7 +352,7 @@ class demo_app_flow_graph (stdgui2.std_top_block): return True self.form = form() - + self.form['static1'] = \ static_text_field(parent=panel, sizer=vbox, label="Static Text", @@ -382,7 +382,7 @@ class demo_app_flow_graph (stdgui2.std_top_block): def _set_status_msg(self, msg): self.frame.GetStatusBar().SetStatusText(msg, 0) - + def main (): app = stdgui2.stdapp(demo_app_flow_graph, "wxgui form demo", nstatus=1) app.MainLoop () diff --git a/gr-wxgui/src/python/forms/.gitignore b/gr-wxgui/src/python/forms/.gitignore deleted file mode 100644 index a74b07aee..000000000 --- a/gr-wxgui/src/python/forms/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/*.pyc diff --git a/gr-wxgui/src/python/forms/__init__.py b/gr-wxgui/src/python/forms/__init__.py index 3f9f4c735..3068b18fe 100644 --- a/gr-wxgui/src/python/forms/__init__.py +++ b/gr-wxgui/src/python/forms/__init__.py @@ -21,7 +21,7 @@ """ The following classes will be available through gnuradio.wxgui.forms: -""" +""" ######################################################################## # External Converters diff --git a/gr-wxgui/src/python/forms/forms.py b/gr-wxgui/src/python/forms/forms.py index 19b30ffb0..f1d0038ab 100644 --- a/gr-wxgui/src/python/forms/forms.py +++ b/gr-wxgui/src/python/forms/forms.py @@ -29,7 +29,7 @@ The forms follow a layered model: * translation layer * translates the between the external and internal layers * handles parsing errors between layers - * external layer + * external layer * provided external access to the user * set_value, get_value, and optional callback * set and get through optional pubsub and key @@ -511,9 +511,9 @@ from gnuradio.wxgui import gui class app_gui (object): def __init__(self, frame, panel, vbox, top_block, options, args): - + def callback(v): print v - + radio_buttons( sizer=vbox, parent=panel, @@ -525,7 +525,7 @@ class app_gui (object): callback=callback, #major_dimension = 2, ) - + radio_buttons( sizer=vbox, parent=panel, @@ -537,7 +537,7 @@ class app_gui (object): callback=callback, #major_dimension = 2, ) - + radio_buttons( sizer=vbox, parent=panel, @@ -548,7 +548,7 @@ class app_gui (object): callback=callback, #major_dimension = 2, ) - + button( sizer=vbox, parent=panel, @@ -559,8 +559,8 @@ class app_gui (object): callback=callback, #width=100, ) - - + + drop_down( sizer=vbox, parent=panel, @@ -584,7 +584,7 @@ class app_gui (object): callback=callback, width=200, ) - + static_text( sizer=vbox, parent=panel, @@ -593,7 +593,7 @@ class app_gui (object): width=-1, bold=True, ) - + slider( sizer=vbox, parent=panel, @@ -601,7 +601,7 @@ class app_gui (object): label='slider', callback=callback, ) - + log_slider( sizer=vbox, parent=panel, @@ -609,7 +609,7 @@ class app_gui (object): label='slider', callback=callback, ) - + slider( sizer=vbox, parent=panel, @@ -619,7 +619,7 @@ class app_gui (object): style=wx.SL_VERTICAL, length=30, ) - + toggle_button( sizer=vbox, parent=panel, @@ -627,7 +627,7 @@ class app_gui (object): label='toggle it', callback=callback, ) - + single_button( sizer=vbox, parent=panel, diff --git a/gr-wxgui/src/python/gui.py b/gr-wxgui/src/python/gui.py index 2f59af593..ccc773eab 100644 --- a/gr-wxgui/src/python/gui.py +++ b/gr-wxgui/src/python/gui.py @@ -1,23 +1,23 @@ # # Copyright 2009 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. -# +# import wx from gnuradio import gr @@ -47,7 +47,7 @@ class top_panel(wx.Panel): p = wx.Panel(self) p.SetSize((640,480)) vbox.Add(p, 1, wx.EXPAND) - + self.SetSizer(vbox) self.SetAutoLayout(True) vbox.Fit(self) @@ -62,7 +62,7 @@ class top_panel(wx.Panel): # Top-level window frame with menu and status bars. # class top_frame(wx.Frame): - def __init__ (self, top_block, gui, options, args, + def __init__ (self, top_block, gui, options, args, title, nstatus, start, realtime): wx.Frame.__init__(self, None, -1, title) @@ -109,11 +109,11 @@ class top_frame(wx.Frame): # -# Top-level wxPython application object. User creates or subclasses this +# Top-level wxPython application object. User creates or subclasses this # in their GUI script. # class app(wx.App): - def __init__ (self, top_block=None, gui=None, options=None, args=None, + def __init__ (self, top_block=None, gui=None, options=None, args=None, title="GNU Radio", nstatus=1, start=False, realtime=False): self.top_block = top_block self.gui = gui diff --git a/gr-wxgui/src/python/plot.py b/gr-wxgui/src/python/plot.py index e0bc4ca60..041a2a7a5 100644 --- a/gr-wxgui/src/python/plot.py +++ b/gr-wxgui/src/python/plot.py @@ -27,13 +27,13 @@ # # Oct 15, 2004 Gordon Williams (g_will@cyberus.ca) # - Imported modules given leading underscore to name. -# - Added Cursor Line Tracking and User Point Labels. +# - Added Cursor Line Tracking and User Point Labels. # - Demo for Cursor Line Tracking and Point Labels. # - Size of plot preview frame adjusted to show page better. # - Added helper functions PositionUserToScreen and PositionScreenToUser in PlotCanvas. # - Added functions GetClosestPoints (all curves) and GetClosestPoint (only closest curve) # can be in either user coords or screen coords. -# +# # May 27, 2007 Johnathan Corgan (jcorgan@corganenterprises.com) # - Converted from numarray to numpy # @@ -45,8 +45,8 @@ This is a simple light weight plotting module that can be used with Boa or easily integrated into your own wxPython application. The emphasis is on small size and fast plotting for large data sets. It has a reasonable number of features to do line and scatter graphs -easily as well as simple bar graphs. It is not as sophisticated or -as powerful as SciPy Plt or Chaco. Both of these are great packages +easily as well as simple bar graphs. It is not as sophisticated or +as powerful as SciPy Plt or Chaco. Both of these are great packages but consume huge amounts of computer resources for simple plots. They can be found at http://scipy.com @@ -69,7 +69,7 @@ Major Additions Gordon Williams Feb. 2003 (g_will@cyberus.ca) -Doc strings and lots of comments -Optimizations for large number of points -Legends - + Did a lot of work here to speed markers up. Only a factor of 4 improvement though. Lines are much faster than markers, especially filled markers. Stay away from circles and triangles unless you @@ -128,11 +128,11 @@ class PolyPoints: self.scaled = self.points self.attributes = {} self.attributes.update(self._attributes) - for name, value in attr.items(): + for name, value in attr.items(): if name not in self._attributes.keys(): raise KeyError, "Style attribute incorrect. Should be one of %s" % self._attributes.keys() self.attributes[name] = value - + def boundingBox(self): if len(self.points) == 0: # no curves to draw @@ -154,7 +154,7 @@ class PolyPoints: self.currentScale= scale self.currentShift= shift # else unchanged use the current scaling - + def getLegend(self): return self.attributes['legend'] @@ -177,13 +177,13 @@ class PolyPoints: pntIndex = _numpy.argmin(d) dist = d[pntIndex] return [pntIndex, self.points[pntIndex], self.scaled[pntIndex], dist] - - + + class PolyLine(PolyPoints): """Class to define line type and style - All methods except __init__ are private. """ - + _attributes = {'colour': 'black', 'width': 1, 'style': wx.SOLID, @@ -224,7 +224,7 @@ class PolyMarker(PolyPoints): """Class to define marker type and style - All methods except __init__ are private. """ - + _attributes = {'colour': 'black', 'width': 1, 'size': 2, @@ -245,7 +245,7 @@ class PolyMarker(PolyPoints): 'fillstyle'= wx.SOLID, - wx.Brush fill style (use wx.TRANSPARENT for no fill) 'marker'= 'circle' - Marker shape 'legend'= '' - Marker Legend to display - + Marker Shapes: - 'circle' - 'dot' @@ -255,7 +255,7 @@ class PolyMarker(PolyPoints): - 'cross' - 'plus' """ - + PolyPoints.__init__(self, points, attr) def draw(self, dc, printerScale, coord= None): @@ -315,7 +315,7 @@ class PolyMarker(PolyPoints): poly.shape= (len(coords),3,2) poly += shape dc.DrawPolygonList(poly.astype(_numpy.int32)) - + def _cross(self, dc, coords, size=1): fact= 2.5*size for f in [[-fact,-fact,fact,fact],[-fact,fact,fact,-fact]]: @@ -370,7 +370,7 @@ class PlotGraphics: def setYLabel(self, yLabel= ''): """Set the Y axis label on the graph""" self.yLabel= yLabel - + def setTitle(self, title= ''): """Set the title at the top of graph""" self.title= title @@ -401,14 +401,14 @@ class PlotGraphics: oSymExt = o.getSymExtent(printerScale) symExt = _numpy.maximum(symExt, oSymExt) return symExt - + def getLegendNames(self): """Returns list of legend names""" lst = [None]*len(self) for i in range(len(self)): lst[i]= self.objects[i].getLegend() return lst - + def __len__(self): return len(self.objects) @@ -432,12 +432,12 @@ class PlotCanvas(wx.Window): self.decim_counter=0 """Constucts a window, which can be a child of a frame, dialog or any other non-control window""" - + wx.Window.__init__(self, parent, id, pos, size, style, name) self.border = (1,1) self.SetBackgroundColour("white") - + # Create some mouse events for zooming self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) @@ -466,7 +466,7 @@ class PlotCanvas(wx.Window): self._zoomCorner2= _numpy.array([0.0, 0.0]) # left mouse up corner self._zoomEnabled= False self._hasDragged= False - + # Drawing Variables self.last_draw = None self._pointScale= 1 @@ -476,7 +476,7 @@ class PlotCanvas(wx.Window): self._gridEnabled= False self._legendEnabled= False self._xUseScopeTicks= False - + # Fonts self._fontCache = {} self._fontSizeAxis= 10 @@ -504,13 +504,13 @@ class PlotCanvas(wx.Window): def set_persist_alpha(self, persist_alpha): self.alpha = persist_alpha - + # SaveFile def SaveFile(self, fileName= ''): """Saves the file to the type specified in the extension. If no file name is specified a dialog box is provided. Returns True if sucessful, otherwise False. - + .bmp Save a Windows bitmap file. .xbm Save an X bitmap file. .xpm Save an XPM bitmap file. @@ -519,7 +519,7 @@ class PlotCanvas(wx.Window): """ if _string.lower(fileName[-3:]) not in ['bmp','xbm','xpm','png','jpg']: dlg1 = wx.FileDialog( - self, + self, "Choose a file with extension bmp, gif, xbm, xpm, png, or jpg", ".", "", "BMP files (*.bmp)|*.bmp|XBM files (*.xbm)|*.xbm|XPM file (*.xpm)|*.xpm|PNG files (*.png)|*.png|JPG files (*.jpg)|*.jpg", wx.SAVE|wx.OVERWRITE_PROMPT @@ -576,7 +576,7 @@ class PlotCanvas(wx.Window): self.print_data=data.GetPrintData() # updates print_data finally: dlg.Destroy() - + def Printout(self, paper=None): """Print current plot.""" if paper != None: @@ -614,11 +614,11 @@ class PlotCanvas(wx.Window): def SetFontSizeAxis(self, point= 10): """Set the tick and axis label font size (default is 10 point)""" self._fontSizeAxis= point - + def GetFontSizeAxis(self): """Get current tick and axis label font size in points""" return self._fontSizeAxis - + def SetFontSizeTitle(self, point= 15): """Set Title font size (default is 15 point)""" self._fontSizeTitle= point @@ -626,11 +626,11 @@ class PlotCanvas(wx.Window): def GetFontSizeTitle(self): """Get current Title font size in points""" return self._fontSizeTitle - + def SetFontSizeLegend(self, point= 7): """Set Legend font size (default is 7 point)""" self._fontSizeLegend= point - + def GetFontSizeLegend(self): """Get current Legend font size in points""" return self._fontSizeLegend @@ -660,7 +660,7 @@ class PlotCanvas(wx.Window): """Set True to enable legend.""" if value not in [True,False]: raise TypeError, "Value should be True or False" - self._legendEnabled= value + self._legendEnabled= value self.Redraw() def GetEnableLegend(self): @@ -671,7 +671,7 @@ class PlotCanvas(wx.Window): """Set True to enable pointLabel.""" if value not in [True,False]: raise TypeError, "Value should be True or False" - self._pointLabelEnabled= value + self._pointLabelEnabled= value self.Redraw() #will erase existing pointLabel if present self.last_PointLabel = None @@ -694,8 +694,8 @@ class PlotCanvas(wx.Window): self.last_PointLabel = None #reset pointLabel if self.last_draw is not None: self.Draw(self.last_draw[0]) - - def ScrollRight(self, units): + + def ScrollRight(self, units): """Move view right number of axis units.""" self.last_PointLabel = None #reset pointLabel if self.last_draw is not None: @@ -710,7 +710,7 @@ class PlotCanvas(wx.Window): graphics, xAxis, yAxis= self.last_draw yAxis= (yAxis[0]+units, yAxis[1]+units) self.Draw(graphics,xAxis,yAxis) - + def GetXY(self,event): """Takes a mouse event and returns the XY user axis values.""" x,y= self.PositionScreenToUser(event.GetPosition()) @@ -721,13 +721,13 @@ class PlotCanvas(wx.Window): userPos= _numpy.array(pntXY) x,y= userPos * self._pointScale + self._pointShift return x,y - + def PositionScreenToUser(self, pntXY): """Converts Screen position to User Coordinates""" screenPos= _numpy.array(pntXY) x,y= (screenPos-self._pointShift)/self._pointScale return x,y - + def SetXSpec(self, type= 'auto'): """xSpec- defines x axis type. Can be 'none', 'min' or 'auto' where: @@ -736,7 +736,7 @@ class PlotCanvas(wx.Window): 'auto' - rounds axis range to sensible values """ self._xSpec= type - + def SetYSpec(self, type= 'auto'): """ySpec- defines x axis type. Can be 'none', 'min' or 'auto' where: @@ -749,11 +749,11 @@ class PlotCanvas(wx.Window): def GetXSpec(self): """Returns current XSpec for axis""" return self._xSpec - + def GetYSpec(self): """Returns current YSpec for axis""" return self._ySpec - + def GetXMaxRange(self): """Returns (minX, maxX) x-axis range for displayed graph""" graphics= self.last_draw[0] @@ -771,15 +771,15 @@ class PlotCanvas(wx.Window): def GetXCurrentRange(self): """Returns (minX, maxX) x-axis for currently displayed portion of graph""" return self.last_draw[1] - + def GetYCurrentRange(self): """Returns (minY, maxY) y-axis for currently displayed portion of graph""" return self.last_draw[2] - + def SetXUseScopeTicks(self, v=False): """Always 10 divisions, no labels""" self._xUseScopeTicks = v - + def GetXUseScopeTicks(self): return self._xUseScopeTicks @@ -788,7 +788,7 @@ class PlotCanvas(wx.Window): graphics- instance of PlotGraphics with list of PolyXXX objects xAxis - tuple with (min, max) axis range to view yAxis - same as xAxis - dc - drawing context - doesn't have to be specified. + dc - drawing context - doesn't have to be specified. If it's not, the offscreen buffer is used """ # check Axis is either tuple or none @@ -796,7 +796,7 @@ class PlotCanvas(wx.Window): raise TypeError, "xAxis should be None or (minX,maxX)" if type(yAxis) not in [type(None),tuple]: raise TypeError, "yAxis should be None or (minY,maxY)" - + # check case for axis = (a,b) where a==b caused by improper zooms if xAxis != None: if xAxis[0] == xAxis[1]: @@ -804,22 +804,22 @@ class PlotCanvas(wx.Window): if yAxis != None: if yAxis[0] == yAxis[1]: return - + if dc == None: - # sets new dc and clears it + # sets new dc and clears it if self.use_persistence: dc = wx.MemoryDC() dc.SelectObject(self._Buffer) dc.Clear() else: dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer) - dc.Clear() - + dc.Clear() + dc.BeginDrawing() # dc.Clear() - - + + # set font size for every thing but title and legend dc.SetFont(self._getFont(self._fontSizeAxis)) @@ -847,7 +847,7 @@ class PlotCanvas(wx.Window): dc.SetBrush(wx.Brush( wx.BLACK, wx.SOLID ) ) #wx.SOLID wx.TRANSPARENT ) ) #dc.SetLogicalFunction(wx.INVERT) #wx.XOR wx.INVERT dc.DrawRectangle( ptx,pty, rectWidth,rectHeight) - #dc.SetBrush(wx.Brush( wx.WHITE, wx.SOLID ) ) + #dc.SetBrush(wx.Brush( wx.WHITE, wx.SOLID ) ) #dc.SetLogicalFunction(wx.COPY) # Get ticks and textExtents for axis if required @@ -908,13 +908,13 @@ class PlotCanvas(wx.Window): self._pointScale= scale # make available for mouse events self._pointShift= shift - #dc.SetLogicalFunction(wx.INVERT) #wx.XOR wx.INVERT + #dc.SetLogicalFunction(wx.INVERT) #wx.XOR wx.INVERT self._drawAxes(dc, p1, p2, scale, shift, xticks, yticks) - #dc.SetLogicalFunction(wx.COPY) - + #dc.SetLogicalFunction(wx.COPY) + graphics.scaleAndShift(scale, shift) graphics.setPrinterScale(self.printerScale) # thicken up lines and markers if printing - + # set clipping area so drawing does not occur outside axis box ptx,pty,rectWidth,rectHeight= self._point2ClientCoord(p1, p2) dc.SetClippingRegion(ptx,pty,rectWidth,rectHeight) @@ -946,7 +946,7 @@ class PlotCanvas(wx.Window): self._Buffer2array +=self._Bufferarray.astype(_numpy.uint32)*alpha_int self._Buffer2array /=256 - ##copy back to image buffer + ##copy back to image buffer self._Buffer2.CopyFromBuffer(self._Buffer2array.astype(_numpy.uint8)) #, format=wx.BitmapBufferFormat_RGB, stride=-1) #draw to the screen @@ -958,7 +958,7 @@ class PlotCanvas(wx.Window): dc2.DrawBitmap(self._Buffer2, 0, 0, False) #dc2.DrawBitmap(self._Buffer, 0, 0, False) dc2.EndDrawing() - + def Redraw(self, dc= None): """Redraw the existing plot.""" if self.last_draw is not None: @@ -986,13 +986,13 @@ class PlotCanvas(wx.Window): xAxis = ( x - w/2, x + w/2 ) yAxis = ( y - h/2, y + h/2 ) self.Draw(graphics, xAxis, yAxis) - + def GetClosestPoints(self, pntXY, pointScaled= True): """Returns list with [curveNumber, legend, index of closest point, pointXY, scaledXY, distance] list for each curve. Returns [] if no curves are being plotted. - + x, y in user coords if pointScaled == True based on screen coords if pointScaled == False based on user coords @@ -1016,7 +1016,7 @@ class PlotCanvas(wx.Window): [curveNumber, legend, index of closest point, pointXY, scaledXY, distance] list for only the closest curve. Returns [] if no curves are being plotted. - + x, y in user coords if pointScaled == True based on screen coords if pointScaled == False based on user coords @@ -1042,7 +1042,7 @@ class PlotCanvas(wx.Window): you specify. This function can be called from parent window with onClick, - onMotion events etc. + onMotion events etc. """ if self.last_PointLabel != None: #compare pointXY @@ -1088,7 +1088,7 @@ class PlotCanvas(wx.Window): def OnMouseDoubleClick(self,event): if self._zoomEnabled: self.Reset() - + def OnMouseRightDown(self,event): if self._zoomEnabled: X,Y = self.GetXY(event) @@ -1113,13 +1113,13 @@ class PlotCanvas(wx.Window): # a file, or whatever. self._Buffer = wx.EmptyBitmap(Size[0],Size[1],24) - + if True: #self.use_persistence: #self._Bufferarray = _numpy.zeros((Size[0], Size[1],3), dtype=_numpy.uint8) self._Bufferarray = _numpy.zeros((Size[0]* Size[1]*3), dtype=_numpy.uint8) # Make new second offscreen bitmap: this bitmap will always have the - # last drawing in it, so it can be used to do display time dependent processing + # last drawing in it, so it can be used to do display time dependent processing # like averaging (IIR) or show differences between updates self._Buffer2 = wx.EmptyBitmap(Size[0],Size[1],24) # now the extra buffers for the IIR processing @@ -1144,24 +1144,24 @@ class PlotCanvas(wx.Window): self._drawPointLabel(self.last_PointLabel) #erase old self.last_PointLabel = None - + # Private Methods ************************************************** def _setSize(self, width=None, height=None): """DC width and height.""" if width == None: (self.width,self.height) = self.GetClientSize() else: - self.width, self.height= width,height + self.width, self.height= width,height self.plotbox_size = 0.97*_numpy.array([self.width, self.height]) xo = 0.5*(self.width-self.plotbox_size[0]) yo = self.height-0.5*(self.height-self.plotbox_size[1]) self.plotbox_origin = _numpy.array([xo, yo]) - + def _setPrinterScale(self, scale): """Used to thicken lines and increase marker size for print out.""" # line thickness on printer is very thin at 600 dot/in. Markers small self.printerScale= scale - + def _printDraw(self, printDC): """Used for printing.""" if self.last_draw != None: @@ -1183,7 +1183,7 @@ class PlotCanvas(wx.Window): dc = wx.ClientDC( self ) #this will erase if called twice dc.Blit(0, 0, width, height, dcs, 0, 0, wx.EQUIV) #(NOT src) XOR dst - + def _drawLegend(self,dc,graphics,rhsW,topH,legendBoxWH, legendSymExt, legendTextExt): """Draws legend symbols and text""" @@ -1222,7 +1222,7 @@ class PlotCanvas(wx.Window): xLabelWH= dc.GetTextExtent(xLabel) yLabelWH= dc.GetTextExtent(yLabel) return titleWH, xLabelWH, yLabelWH - + def _legendWH(self, dc, graphics): """Returns the size in screen units for legend box""" if self._legendEnabled != True: @@ -1236,7 +1236,7 @@ class PlotCanvas(wx.Window): txtExt= dc.GetTextExtent(txtList[0]) for txt in graphics.getLegendNames()[1:]: txtExt= _numpy.maximum(txtExt,dc.GetTextExtent(txt)) - maxW= symExt[0]+txtExt[0] + maxW= symExt[0]+txtExt[0] maxH= max(symExt[1],txtExt[1]) # padding .1 for lhs of legend box and space between lines maxW= maxW* 1.1 @@ -1250,7 +1250,7 @@ class PlotCanvas(wx.Window): ptx,pty,rectWidth,rectHeight= self._point2ClientCoord(corner1, corner2) # draw rectangle dc = wx.ClientDC( self ) - dc.BeginDrawing() + dc.BeginDrawing() dc.SetPen(wx.Pen(wx.BLACK)) dc.SetBrush(wx.Brush( wx.WHITE, wx.TRANSPARENT ) ) dc.SetLogicalFunction(wx.INVERT) @@ -1285,8 +1285,8 @@ class PlotCanvas(wx.Window): plr= _numpy.maximum(pt1,pt2) # Lower right corner rectWidth, rectHeight= plr-pul ptx,pty= pul - return ptx, pty, rectWidth, rectHeight - + return ptx, pty, rectWidth, rectHeight + def _axisInterval(self, spec, lower, upper): """Returns sensible axis range for given spec""" if spec == 'none' or spec == 'min': @@ -1320,10 +1320,10 @@ class PlotCanvas(wx.Window): raise ValueError, str(spec) + ': illegal axis specification' def _drawAxes(self, dc, p1, p2, scale, shift, xticks, yticks): - + penWidth= self.printerScale # increases thickness for printing only dc.SetPen(wx.Pen(wx.NamedColour('BLACK'), penWidth)) - + # set length of tick marks--long ones make grid if self._gridEnabled: x,y,width,height= self._point2ClientCoord(p1,p2) @@ -1332,7 +1332,7 @@ class PlotCanvas(wx.Window): else: yTickLength= 3 * self.printerScale # lengthens lines for printing xTickLength= 3 * self.printerScale - + if self._xSpec is not 'none': lower, upper = p1[0],p2[0] text = 1 @@ -1377,7 +1377,7 @@ class PlotCanvas(wx.Window): factor = f grid = factor * 10.**power if power > 4 or power < -4: - format = '%+7.1e' + format = '%+7.1e' elif power >= 0: digits = max(1, int(power)) format = '%' + `digits`+'.0f' @@ -1441,14 +1441,14 @@ class PlotPrintout(wx.Printout): dcSize= dc.GetSize() # DC size pageSize= self.GetPageSizePixels() # page size in terms of pixcels clientDcSize= self.graph.GetClientSize() - + # find what the margins are (mm) margLeftSize,margTopSize= self.graph.pageSetupData.GetMarginTopLeft() margRightSize, margBottomSize= self.graph.pageSetupData.GetMarginBottomRight() # calculate offset and scale for dc pixLeft= margLeftSize*PPIPrinter[0]/25.4 # mm*(dots/in)/(mm/in) - pixRight= margRightSize*PPIPrinter[0]/25.4 + pixRight= margRightSize*PPIPrinter[0]/25.4 pixTop= margTopSize*PPIPrinter[1]/25.4 pixBottom= margBottomSize*PPIPrinter[1]/25.4 @@ -1463,10 +1463,10 @@ class PlotPrintout(wx.Printout): pixTop *= ratioH plotAreaW *= ratioW plotAreaH *= ratioH - + # rescale plot to page or preview plot area self.graph._setSize(plotAreaW,plotAreaH) - + # Set offset and scale dc.SetDeviceOrigin(pixLeft,pixTop) @@ -1511,7 +1511,7 @@ def _draw1Objects(): markers2 = PolyMarker([(0., 0.), (pi/4., 1.), (pi/2, 0.), (3.*pi/4., -1)], legend='Cross Legend', colour='blue', marker='cross') - + return PlotGraphics([markers1, lines, markers2],"Graph Title", "X Axis", "Y Axis") def _draw2Objects(): @@ -1593,16 +1593,16 @@ class TestFrame(wx.Frame): menu = wx.Menu() menu.Append(200, 'Page Setup...', 'Setup the printer page') self.Bind(wx.EVT_MENU, self.OnFilePageSetup, id=200) - + menu.Append(201, 'Print Preview...', 'Show the current plot on page') self.Bind(wx.EVT_MENU, self.OnFilePrintPreview, id=201) - + menu.Append(202, 'Print...', 'Print the current plot') self.Bind(wx.EVT_MENU, self.OnFilePrint, id=202) - + menu.Append(203, 'Save Plot...', 'Save current plot') self.Bind(wx.EVT_MENU, self.OnSaveFile, id=203) - + menu.Append(205, 'E&xit', 'Enough of this already!') self.Bind(wx.EVT_MENU, self.OnFileExit, id=205) self.mainmenu.Append(menu, '&File') @@ -1620,25 +1620,25 @@ class TestFrame(wx.Frame): self.Bind(wx.EVT_MENU,self.OnPlotDraw5, id=210) menu.Append(260, 'Draw6', 'Draw plots6') self.Bind(wx.EVT_MENU,self.OnPlotDraw6, id=260) - + menu.Append(211, '&Redraw', 'Redraw plots') self.Bind(wx.EVT_MENU,self.OnPlotRedraw, id=211) menu.Append(212, '&Clear', 'Clear canvas') self.Bind(wx.EVT_MENU,self.OnPlotClear, id=212) menu.Append(213, '&Scale', 'Scale canvas') - self.Bind(wx.EVT_MENU,self.OnPlotScale, id=213) + self.Bind(wx.EVT_MENU,self.OnPlotScale, id=213) menu.Append(214, 'Enable &Zoom', 'Enable Mouse Zoom', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU,self.OnEnableZoom, id=214) + self.Bind(wx.EVT_MENU,self.OnEnableZoom, id=214) menu.Append(215, 'Enable &Grid', 'Turn on Grid', kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU,self.OnEnableGrid, id=215) menu.Append(220, 'Enable &Legend', 'Turn on Legend', kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU,self.OnEnableLegend, id=220) menu.Append(222, 'Enable &Point Label', 'Show Closest Point', kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU,self.OnEnablePointLabel, id=222) - + menu.Append(225, 'Scroll Up 1', 'Move View Up 1 Unit') - self.Bind(wx.EVT_MENU,self.OnScrUp, id=225) + self.Bind(wx.EVT_MENU,self.OnScrUp, id=225) menu.Append(230, 'Scroll Rt 2', 'Move View Right 2 Units') self.Bind(wx.EVT_MENU,self.OnScrRt, id=230) menu.Append(235, '&Plot Reset', 'Reset to original plot') @@ -1655,7 +1655,7 @@ class TestFrame(wx.Frame): # A status bar to tell people what's happening self.CreateStatusBar(1) - + self.client = PlotCanvas(self) #define the function for drawing pointLabels self.client.SetPointLabelFunc(self.DrawPointLabel) @@ -1678,7 +1678,7 @@ class TestFrame(wx.Frame): # ---------- dc.SetPen(wx.Pen(wx.BLACK)) dc.SetBrush(wx.Brush( wx.BLACK, wx.SOLID ) ) - + sx, sy = mDataDict["scaledXY"] #scaled x,y of closest point dc.DrawRectangle( sx-5,sy-5, 10, 10) #10by10 square centered on point px,py = mDataDict["pointXY"] @@ -1703,7 +1703,7 @@ class TestFrame(wx.Frame): dlst= self.client.GetClosetPoint( self.client.GetXY(event), pointScaled= True) if dlst != []: #returns [] if none curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst - #make up dictionary to pass to my user function (see DrawPointLabel) + #make up dictionary to pass to my user function (see DrawPointLabel) mDataDict= {"curveNum":curveNum, "legend":legend, "pIndex":pIndex,\ "pointXY":pointXY, "scaledXY":scaledXY} #pass dict to update the pointLabel @@ -1712,13 +1712,13 @@ class TestFrame(wx.Frame): def OnFilePageSetup(self, event): self.client.PageSetup() - + def OnFilePrintPreview(self, event): self.client.PrintPreview() - + def OnFilePrint(self, event): self.client.Printout() - + def OnSaveFile(self, event): self.client.SaveFile() @@ -1728,11 +1728,11 @@ class TestFrame(wx.Frame): def OnPlotDraw1(self, event): self.resetDefaults() self.client.Draw(_draw1Objects()) - + def OnPlotDraw2(self, event): self.resetDefaults() self.client.Draw(_draw2Objects()) - + def OnPlotDraw3(self, event): self.resetDefaults() self.client.SetFont(wx.Font(10,wx.SCRIPT,wx.NORMAL,wx.NORMAL)) @@ -1747,7 +1747,7 @@ class TestFrame(wx.Frame): drawObj= _draw4Objects() self.client.Draw(drawObj) ## # profile -## start = _time.clock() +## start = _time.clock() ## for x in range(10): ## self.client.Draw(drawObj) ## print "10 plots of Draw4 took: %f sec."%(_time.clock() - start) @@ -1775,7 +1775,7 @@ class TestFrame(wx.Frame): def OnPlotClear(self,event): self.client.Clear() - + def OnPlotScale(self, event): if self.client.last_draw != None: graphics, xAxis, yAxis= self.client.last_draw @@ -1783,10 +1783,10 @@ class TestFrame(wx.Frame): def OnEnableZoom(self, event): self.client.SetEnableZoom(event.IsChecked()) - + def OnEnableGrid(self, event): self.client.SetEnableGrid(event.IsChecked()) - + def OnEnableLegend(self, event): self.client.SetEnableLegend(event.IsChecked()) @@ -1795,7 +1795,7 @@ class TestFrame(wx.Frame): def OnScrUp(self, event): self.client.ScrollUp(1) - + def OnScrRt(self,event): self.client.ScrollRight(2) @@ -1814,7 +1814,7 @@ class TestFrame(wx.Frame): self.client.SetFontSizeLegend(7) self.client.SetXSpec('auto') self.client.SetYSpec('auto') - + def __test(): diff --git a/gr-wxgui/src/python/plotter/.gitignore b/gr-wxgui/src/python/plotter/.gitignore deleted file mode 100644 index b6950912c..000000000 --- a/gr-wxgui/src/python/plotter/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/Makefile -/Makefile.in -/*.pyc diff --git a/gr-wxgui/src/python/plotter/Makefile.am b/gr-wxgui/src/python/plotter/Makefile.am deleted file mode 100644 index d00f0a425..000000000 --- a/gr-wxgui/src/python/plotter/Makefile.am +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright 2004,2005,2008,2009 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 $(top_srcdir)/Makefile.common - -# Install this stuff so that it ends up as the gnuradio.wxgui module -# This usually ends up at: -# ${prefix}/lib/python${python_version}/site-packages/gnuradio/wxgui - -ourpythondir = $(grpythondir)/wxgui/plotter -ourlibdir = $(grpyexecdir)/wxgui/plotter - -ourpython_PYTHON = \ - __init__.py \ - bar_plotter.py \ - channel_plotter.py \ - common.py \ - gltext.py \ - grid_plotter_base.py \ - plotter_base.py \ - waterfall_plotter.py - diff --git a/gr-wxgui/src/python/plotter/common.py b/gr-wxgui/src/python/plotter/common.py index 4c50cd787..6775b7057 100644 --- a/gr-wxgui/src/python/plotter/common.py +++ b/gr-wxgui/src/python/plotter/common.py @@ -115,7 +115,7 @@ class point_label_thread(threading.Thread, mutex): def run(self): last_ts = time.time() last_coor = coor = None - try: + try: while True: time.sleep(1.0/30.0) self.lock() diff --git a/gr-wxgui/src/python/plotter/gltext.py b/gr-wxgui/src/python/plotter/gltext.py index 1b3c047dc..0b6e3f55b 100644 --- a/gr-wxgui/src/python/plotter/gltext.py +++ b/gr-wxgui/src/python/plotter/gltext.py @@ -1,503 +1,503 @@ -#!/usr/bin/env python
-# -*- coding: utf-8
-#
-# Provides some text display functions for wx + ogl
-# Copyright (C) 2007 Christian Brugger, Stefan Hacker
-#
-# This program 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 2 of the License, or
-# (at your option) any later version.
-#
-# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-import wx
-from OpenGL.GL import *
-
-"""
-Optimize with psyco if possible, this gains us about 50% speed when
-creating our textures in trade for about 4MBytes of additional memory usage for
-psyco. If you don't like loosing the memory you have to turn the lines following
-"enable psyco" into a comment while uncommenting the line after "Disable psyco".
-"""
-#Try to enable psyco
-try:
- import psyco
- psyco_optimized = False
-except ImportError:
- psyco = None
-
-#Disable psyco
-#psyco = None
-
-class TextElement(object):
- """
- A simple class for using system Fonts to display
- text in an OpenGL scene
- """
- def __init__(self,
- text = '',
- font = None,
- foreground = wx.BLACK,
- centered = False):
- """
- text (String) - Text
- font (wx.Font) - Font to draw with (None = System default)
- foreground (wx.Color) - Color of the text
- or (wx.Bitmap)- Bitmap to overlay the text with
- centered (bool) - Center the text
-
- Initializes the TextElement
- """
- # save given variables
- self._text = text
- self._lines = text.split('\n')
- self._font = font
- self._foreground = foreground
- self._centered = centered
-
- # init own variables
- self._owner_cnt = 0 #refcounter
- self._texture = None #OpenGL texture ID
- self._text_size = None #x/y size tuple of the text
- self._texture_size= None #x/y Texture size tuple
-
- # create Texture
- self.createTexture()
-
-
- #---Internal helpers
-
- def _getUpper2Base(self, value):
- """
- Returns the lowest value with the power of
- 2 greater than 'value' (2^n>value)
- """
- base2 = 1
- while base2 < value:
- base2 *= 2
- return base2
-
- #---Functions
-
- def draw_text(self, position = wx.Point(0,0), scale = 1.0, rotation = 0):
- """
- position (wx.Point) - x/y Position to draw in scene
- scale (float) - Scale
- rotation (int) - Rotation in degree
-
- Draws the text to the scene
- """
- #Enable necessary functions
- glColor(1,1,1,1)
- glEnable(GL_TEXTURE_2D)
- glEnable(GL_ALPHA_TEST) #Enable alpha test
- glAlphaFunc(GL_GREATER, 0)
- glEnable(GL_BLEND) #Enable blending
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
- #Bind texture
- glBindTexture(GL_TEXTURE_2D, self._texture)
-
- ow, oh = self._text_size
- w , h = self._texture_size
- #Perform transformations
- glPushMatrix()
- glTranslated(position.x, position.y, 0)
- glRotate(-rotation, 0, 0, 1)
- glScaled(scale, scale, scale)
- if self._centered:
- glTranslate(-w/2, -oh/2, 0)
- #Draw vertices
- glBegin(GL_QUADS)
- glTexCoord2f(0,0); glVertex2f(0,0)
- glTexCoord2f(0,1); glVertex2f(0,h)
- glTexCoord2f(1,1); glVertex2f(w,h)
- glTexCoord2f(1,0); glVertex2f(w,0)
- glEnd()
- glPopMatrix()
-
- #Disable features
- glDisable(GL_BLEND)
- glDisable(GL_ALPHA_TEST)
- glDisable(GL_TEXTURE_2D)
-
- def createTexture(self):
- """
- Creates a texture from the settings saved in TextElement, to be able to use normal
- system fonts conviently a wx.MemoryDC is used to draw on a wx.Bitmap. As wxwidgets
- device contexts don't support alpha at all it is necessary to apply a little hack
- to preserve antialiasing without sticking to a fixed background color:
-
- We draw the bmp in b/w mode so we can use its data as a alpha channel for a solid
- color bitmap which after GL_ALPHA_TEST and GL_BLEND will show a nicely antialiased
- text on any surface.
-
- To access the raw pixel data the bmp gets converted to a wx.Image. Now we just have
- to merge our foreground color with the alpha data we just created and push it all
- into a OpenGL texture and we are DONE *inhalesdelpy*
-
- DRAWBACK of the whole conversion thing is a really long time for creating the
- texture. If you see any optimizations that could save time PLEASE CREATE A PATCH!!!
- """
- # get a memory dc
- dc = wx.MemoryDC()
-
- # set our font
- dc.SetFont(self._font)
-
- # Approximate extend to next power of 2 and create our bitmap
- # REMARK: You wouldn't believe how much fucking speed this little
- # sucker gains compared to sizes not of the power of 2. It's like
- # 500ms --> 0.5ms (on my ATI-GPU powered Notebook). On Sams nvidia
- # machine there don't seem to occur any losses...bad drivers?
- ow, oh = dc.GetMultiLineTextExtent(self._text)[:2]
- w, h = self._getUpper2Base(ow), self._getUpper2Base(oh)
-
- self._text_size = wx.Size(ow,oh)
- self._texture_size = wx.Size(w,h)
- bmp = wx.EmptyBitmap(w,h)
-
-
- #Draw in b/w mode to bmp so we can use it as alpha channel
- dc.SelectObject(bmp)
- dc.SetBackground(wx.BLACK_BRUSH)
- dc.Clear()
- dc.SetTextForeground(wx.WHITE)
- x,y = 0,0
- centered = self.centered
- for line in self._lines:
- if not line: line = ' '
- tw, th = dc.GetTextExtent(line)
- if centered:
- x = int(round((w-tw)/2))
- dc.DrawText(line, x, y)
- x = 0
- y += th
- #Release the dc
- dc.SelectObject(wx.NullBitmap)
- del dc
-
- #Generate a correct RGBA data string from our bmp
- """
- NOTE: You could also use wx.AlphaPixelData to access the pixel data
- in 'bmp' directly, but the iterator given by it is much slower than
- first converting to an image and using wx.Image.GetData().
- """
- img = wx.ImageFromBitmap(bmp)
- alpha = img.GetData()
-
- if isinstance(self._foreground, wx.Colour):
- """
- If we have a static color...
- """
- r,g,b = self._foreground.Get()
- color = "%c%c%c" % (chr(r), chr(g), chr(b))
-
- data = ''
- for i in xrange(0, len(alpha)-1, 3):
- data += color + alpha[i]
-
- elif isinstance(self._foreground, wx.Bitmap):
- """
- If we have a bitmap...
- """
- bg_img = wx.ImageFromBitmap(self._foreground)
- bg = bg_img.GetData()
- bg_width = self._foreground.GetWidth()
- bg_height = self._foreground.GetHeight()
-
- data = ''
-
- for y in xrange(0, h):
- for x in xrange(0, w):
- if (y > (bg_height-1)) or (x > (bg_width-1)):
- color = "%c%c%c" % (chr(0),chr(0),chr(0))
- else:
- pos = (x+y*bg_width) * 3
- color = bg[pos:pos+3]
- data += color + alpha[(x+y*w)*3]
-
-
- # now convert it to ogl texture
- self._texture = glGenTextures(1)
- glBindTexture(GL_TEXTURE_2D, self._texture)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)
- glPixelStorei(GL_UNPACK_ALIGNMENT, 2)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
-
- def deleteTexture(self):
- """
- Deletes the OpenGL texture object
- """
- if self._texture:
- if glIsTexture(self._texture):
- glDeleteTextures(self._texture)
- else:
- self._texture = None
-
- def bind(self):
- """
- Increase refcount
- """
- self._owner_cnt += 1
-
- def release(self):
- """
- Decrease refcount
- """
- self._owner_cnt -= 1
-
- def isBound(self):
- """
- Return refcount
- """
- return self._owner_cnt
-
- def __del__(self):
- """
- Destructor
- """
- self.deleteTexture()
-
- #---Getters/Setters
-
- def getText(self): return self._text
- def getFont(self): return self._font
- def getForeground(self): return self._foreground
- def getCentered(self): return self._centered
- def getTexture(self): return self._texture
- def getTexture_size(self): return self._texture_size
-
- def getOwner_cnt(self): return self._owner_cnt
- def setOwner_cnt(self, value):
- self._owner_cnt = value
-
- #---Properties
-
- text = property(getText, None, None, "Text of the object")
- font = property(getFont, None, None, "Font of the object")
- foreground = property(getForeground, None, None, "Color of the text")
- centered = property(getCentered, None, None, "Is text centered")
- owner_cnt = property(getOwner_cnt, setOwner_cnt, None, "Owner count")
- texture = property(getTexture, None, None, "Used texture")
- texture_size = property(getTexture_size, None, None, "Size of the used texture")
-
-
-class Text(object):
- """
- A simple class for using System Fonts to display text in
- an OpenGL scene. The Text adds a global Cache of already
- created text elements to TextElement's base functionality
- so you can save some memory and increase speed
- """
- _texts = [] #Global cache for TextElements
-
- def __init__(self,
- text = 'Text',
- font = None,
- font_size = 8,
- foreground = wx.BLACK,
- centered = False,
- bold = False):
- """
- text (string) - displayed text
- font (wx.Font) - if None, system default font will be used with font_size
- font_size (int) - font size in points
- foreground (wx.Color) - Color of the text
- or (wx.Bitmap) - Bitmap to overlay the text with
- centered (bool) - should the text drawn centered towards position?
-
- Initializes the text object
- """
- #Init/save variables
- self._aloc_text = None
- self._text = text
- self._font_size = font_size
- self._foreground= foreground
- self._centered = centered
-
- #Check if we are offered a font
- if not font:
- #if not use the system default
- self._font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
- else:
- #save it
- self._font = font
-
- if bold: self._font.SetWeight(wx.FONTWEIGHT_BOLD)
-
- #Bind us to our texture
- self._initText()
-
- #---Internal helpers
-
- def _initText(self):
- """
- Initializes/Reinitializes the Text object by binding it
- to a TextElement suitable for its current settings
- """
- #Check if we already bound to a texture
- if self._aloc_text:
- #if so release it
- self._aloc_text.release()
- if not self._aloc_text.isBound():
- self._texts.remove(self._aloc_text)
- self._aloc_text = None
-
- #Adjust our font
- self._font.SetPointSize(self._font_size)
-
- #Search for existing element in our global buffer
- for element in self._texts:
- if element.text == self._text and\
- element.font == self._font and\
- element.foreground == self._foreground and\
- element.centered == self._centered:
- # We already exist in global buffer ;-)
- element.bind()
- self._aloc_text = element
- break
-
- if not self._aloc_text:
- # We are not in the global buffer, let's create ourselves
- aloc_text = self._aloc_text = TextElement(self._text,
- self._font,
- self._foreground,
- self._centered)
- aloc_text.bind()
- self._texts.append(aloc_text)
-
- def __del__(self):
- """
- Destructor
- """
- aloc_text = self._aloc_text
- aloc_text.release()
- if not aloc_text.isBound():
- self._texts.remove(aloc_text)
-
- #---Functions
-
- def draw_text(self, position = wx.Point(0,0), scale = 1.0, rotation = 0):
- """
- position (wx.Point) - x/y Position to draw in scene
- scale (float) - Scale
- rotation (int) - Rotation in degree
-
- Draws the text to the scene
- """
-
- self._aloc_text.draw_text(position, scale, rotation)
-
- #---Setter/Getter
-
- def getText(self): return self._text
- def setText(self, value, reinit = True):
- """
- value (bool) - New Text
- reinit (bool) - Create a new texture
-
- Sets a new text
- """
- self._text = value
- if reinit:
- self._initText()
-
- def getFont(self): return self._font
- def setFont(self, value, reinit = True):
- """
- value (bool) - New Font
- reinit (bool) - Create a new texture
-
- Sets a new font
- """
- self._font = value
- if reinit:
- self._initText()
-
- def getFont_size(self): return self._font_size
- def setFont_size(self, value, reinit = True):
- """
- value (bool) - New font size
- reinit (bool) - Create a new texture
-
- Sets a new font size
- """
- self._font_size = value
- if reinit:
- self._initText()
-
- def getForeground(self): return self._foreground
- def setForeground(self, value, reinit = True):
- """
- value (bool) - New centered value
- reinit (bool) - Create a new texture
-
- Sets a new value for 'centered'
- """
- self._foreground = value
- if reinit:
- self._initText()
-
- def getCentered(self): return self._centered
- def setCentered(self, value, reinit = True):
- """
- value (bool) - New centered value
- reinit (bool) - Create a new texture
-
- Sets a new value for 'centered'
- """
- self._centered = value
- if reinit:
- self._initText()
-
- def get_size(self):
- """
- Returns a text size tuple
- """
- return self._aloc_text._text_size
-
- def getTexture_size(self):
- """
- Returns a texture size tuple
- """
- return self._aloc_text.texture_size
-
- def getTextElement(self):
- """
- Returns the text element bound to the Text class
- """
- return self._aloc_text
-
- def getTexture(self):
- """
- Returns the texture of the bound TextElement
- """
- return self._aloc_text.texture
-
-
- #---Properties
-
- text = property(getText, setText, None, "Text of the object")
- font = property(getFont, setFont, None, "Font of the object")
- font_size = property(getFont_size, setFont_size, None, "Font size")
- foreground = property(getForeground, setForeground, None, "Color/Overlay bitmap of the text")
- centered = property(getCentered, setCentered, None, "Display the text centered")
- texture_size = property(getTexture_size, None, None, "Size of the used texture")
- texture = property(getTexture, None, None, "Texture of bound TextElement")
- text_element = property(getTextElement,None , None, "TextElement bound to this class")
-
-#Optimize critical functions
-if psyco and not psyco_optimized:
- psyco.bind(TextElement.createTexture)
- psyco_optimized = True
+#!/usr/bin/env python +# -*- coding: utf-8 +# +# Provides some text display functions for wx + ogl +# Copyright (C) 2007 Christian Brugger, Stefan Hacker +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import wx +from OpenGL.GL import * + +""" +Optimize with psyco if possible, this gains us about 50% speed when +creating our textures in trade for about 4MBytes of additional memory usage for +psyco. If you don't like loosing the memory you have to turn the lines following +"enable psyco" into a comment while uncommenting the line after "Disable psyco". +""" +#Try to enable psyco +try: + import psyco + psyco_optimized = False +except ImportError: + psyco = None + +#Disable psyco +#psyco = None + +class TextElement(object): + """ + A simple class for using system Fonts to display + text in an OpenGL scene + """ + def __init__(self, + text = '', + font = None, + foreground = wx.BLACK, + centered = False): + """ + text (String) - Text + font (wx.Font) - Font to draw with (None = System default) + foreground (wx.Color) - Color of the text + or (wx.Bitmap)- Bitmap to overlay the text with + centered (bool) - Center the text + + Initializes the TextElement + """ + # save given variables + self._text = text + self._lines = text.split('\n') + self._font = font + self._foreground = foreground + self._centered = centered + + # init own variables + self._owner_cnt = 0 #refcounter + self._texture = None #OpenGL texture ID + self._text_size = None #x/y size tuple of the text + self._texture_size= None #x/y Texture size tuple + + # create Texture + self.createTexture() + + + #---Internal helpers + + def _getUpper2Base(self, value): + """ + Returns the lowest value with the power of + 2 greater than 'value' (2^n>value) + """ + base2 = 1 + while base2 < value: + base2 *= 2 + return base2 + + #---Functions + + def draw_text(self, position = wx.Point(0,0), scale = 1.0, rotation = 0): + """ + position (wx.Point) - x/y Position to draw in scene + scale (float) - Scale + rotation (int) - Rotation in degree + + Draws the text to the scene + """ + #Enable necessary functions + glColor(1,1,1,1) + glEnable(GL_TEXTURE_2D) + glEnable(GL_ALPHA_TEST) #Enable alpha test + glAlphaFunc(GL_GREATER, 0) + glEnable(GL_BLEND) #Enable blending + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + #Bind texture + glBindTexture(GL_TEXTURE_2D, self._texture) + + ow, oh = self._text_size + w , h = self._texture_size + #Perform transformations + glPushMatrix() + glTranslated(position.x, position.y, 0) + glRotate(-rotation, 0, 0, 1) + glScaled(scale, scale, scale) + if self._centered: + glTranslate(-w/2, -oh/2, 0) + #Draw vertices + glBegin(GL_QUADS) + glTexCoord2f(0,0); glVertex2f(0,0) + glTexCoord2f(0,1); glVertex2f(0,h) + glTexCoord2f(1,1); glVertex2f(w,h) + glTexCoord2f(1,0); glVertex2f(w,0) + glEnd() + glPopMatrix() + + #Disable features + glDisable(GL_BLEND) + glDisable(GL_ALPHA_TEST) + glDisable(GL_TEXTURE_2D) + + def createTexture(self): + """ + Creates a texture from the settings saved in TextElement, to be able to use normal + system fonts conviently a wx.MemoryDC is used to draw on a wx.Bitmap. As wxwidgets + device contexts don't support alpha at all it is necessary to apply a little hack + to preserve antialiasing without sticking to a fixed background color: + + We draw the bmp in b/w mode so we can use its data as a alpha channel for a solid + color bitmap which after GL_ALPHA_TEST and GL_BLEND will show a nicely antialiased + text on any surface. + + To access the raw pixel data the bmp gets converted to a wx.Image. Now we just have + to merge our foreground color with the alpha data we just created and push it all + into a OpenGL texture and we are DONE *inhalesdelpy* + + DRAWBACK of the whole conversion thing is a really long time for creating the + texture. If you see any optimizations that could save time PLEASE CREATE A PATCH!!! + """ + # get a memory dc + dc = wx.MemoryDC() + + # set our font + dc.SetFont(self._font) + + # Approximate extend to next power of 2 and create our bitmap + # REMARK: You wouldn't believe how much fucking speed this little + # sucker gains compared to sizes not of the power of 2. It's like + # 500ms --> 0.5ms (on my ATI-GPU powered Notebook). On Sams nvidia + # machine there don't seem to occur any losses...bad drivers? + ow, oh = dc.GetMultiLineTextExtent(self._text)[:2] + w, h = self._getUpper2Base(ow), self._getUpper2Base(oh) + + self._text_size = wx.Size(ow,oh) + self._texture_size = wx.Size(w,h) + bmp = wx.EmptyBitmap(w,h) + + + #Draw in b/w mode to bmp so we can use it as alpha channel + dc.SelectObject(bmp) + dc.SetBackground(wx.BLACK_BRUSH) + dc.Clear() + dc.SetTextForeground(wx.WHITE) + x,y = 0,0 + centered = self.centered + for line in self._lines: + if not line: line = ' ' + tw, th = dc.GetTextExtent(line) + if centered: + x = int(round((w-tw)/2)) + dc.DrawText(line, x, y) + x = 0 + y += th + #Release the dc + dc.SelectObject(wx.NullBitmap) + del dc + + #Generate a correct RGBA data string from our bmp + """ + NOTE: You could also use wx.AlphaPixelData to access the pixel data + in 'bmp' directly, but the iterator given by it is much slower than + first converting to an image and using wx.Image.GetData(). + """ + img = wx.ImageFromBitmap(bmp) + alpha = img.GetData() + + if isinstance(self._foreground, wx.Colour): + """ + If we have a static color... + """ + r,g,b = self._foreground.Get() + color = "%c%c%c" % (chr(r), chr(g), chr(b)) + + data = '' + for i in xrange(0, len(alpha)-1, 3): + data += color + alpha[i] + + elif isinstance(self._foreground, wx.Bitmap): + """ + If we have a bitmap... + """ + bg_img = wx.ImageFromBitmap(self._foreground) + bg = bg_img.GetData() + bg_width = self._foreground.GetWidth() + bg_height = self._foreground.GetHeight() + + data = '' + + for y in xrange(0, h): + for x in xrange(0, w): + if (y > (bg_height-1)) or (x > (bg_width-1)): + color = "%c%c%c" % (chr(0),chr(0),chr(0)) + else: + pos = (x+y*bg_width) * 3 + color = bg[pos:pos+3] + data += color + alpha[(x+y*w)*3] + + + # now convert it to ogl texture + self._texture = glGenTextures(1) + glBindTexture(GL_TEXTURE_2D, self._texture) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0) + glPixelStorei(GL_UNPACK_ALIGNMENT, 2) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data) + + def deleteTexture(self): + """ + Deletes the OpenGL texture object + """ + if self._texture: + if glIsTexture(self._texture): + glDeleteTextures(self._texture) + else: + self._texture = None + + def bind(self): + """ + Increase refcount + """ + self._owner_cnt += 1 + + def release(self): + """ + Decrease refcount + """ + self._owner_cnt -= 1 + + def isBound(self): + """ + Return refcount + """ + return self._owner_cnt + + def __del__(self): + """ + Destructor + """ + self.deleteTexture() + + #---Getters/Setters + + def getText(self): return self._text + def getFont(self): return self._font + def getForeground(self): return self._foreground + def getCentered(self): return self._centered + def getTexture(self): return self._texture + def getTexture_size(self): return self._texture_size + + def getOwner_cnt(self): return self._owner_cnt + def setOwner_cnt(self, value): + self._owner_cnt = value + + #---Properties + + text = property(getText, None, None, "Text of the object") + font = property(getFont, None, None, "Font of the object") + foreground = property(getForeground, None, None, "Color of the text") + centered = property(getCentered, None, None, "Is text centered") + owner_cnt = property(getOwner_cnt, setOwner_cnt, None, "Owner count") + texture = property(getTexture, None, None, "Used texture") + texture_size = property(getTexture_size, None, None, "Size of the used texture") + + +class Text(object): + """ + A simple class for using System Fonts to display text in + an OpenGL scene. The Text adds a global Cache of already + created text elements to TextElement's base functionality + so you can save some memory and increase speed + """ + _texts = [] #Global cache for TextElements + + def __init__(self, + text = 'Text', + font = None, + font_size = 8, + foreground = wx.BLACK, + centered = False, + bold = False): + """ + text (string) - displayed text + font (wx.Font) - if None, system default font will be used with font_size + font_size (int) - font size in points + foreground (wx.Color) - Color of the text + or (wx.Bitmap) - Bitmap to overlay the text with + centered (bool) - should the text drawn centered towards position? + + Initializes the text object + """ + #Init/save variables + self._aloc_text = None + self._text = text + self._font_size = font_size + self._foreground= foreground + self._centered = centered + + #Check if we are offered a font + if not font: + #if not use the system default + self._font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + else: + #save it + self._font = font + + if bold: self._font.SetWeight(wx.FONTWEIGHT_BOLD) + + #Bind us to our texture + self._initText() + + #---Internal helpers + + def _initText(self): + """ + Initializes/Reinitializes the Text object by binding it + to a TextElement suitable for its current settings + """ + #Check if we already bound to a texture + if self._aloc_text: + #if so release it + self._aloc_text.release() + if not self._aloc_text.isBound(): + self._texts.remove(self._aloc_text) + self._aloc_text = None + + #Adjust our font + self._font.SetPointSize(self._font_size) + + #Search for existing element in our global buffer + for element in self._texts: + if element.text == self._text and\ + element.font == self._font and\ + element.foreground == self._foreground and\ + element.centered == self._centered: + # We already exist in global buffer ;-) + element.bind() + self._aloc_text = element + break + + if not self._aloc_text: + # We are not in the global buffer, let's create ourselves + aloc_text = self._aloc_text = TextElement(self._text, + self._font, + self._foreground, + self._centered) + aloc_text.bind() + self._texts.append(aloc_text) + + def __del__(self): + """ + Destructor + """ + aloc_text = self._aloc_text + aloc_text.release() + if not aloc_text.isBound(): + self._texts.remove(aloc_text) + + #---Functions + + def draw_text(self, position = wx.Point(0,0), scale = 1.0, rotation = 0): + """ + position (wx.Point) - x/y Position to draw in scene + scale (float) - Scale + rotation (int) - Rotation in degree + + Draws the text to the scene + """ + + self._aloc_text.draw_text(position, scale, rotation) + + #---Setter/Getter + + def getText(self): return self._text + def setText(self, value, reinit = True): + """ + value (bool) - New Text + reinit (bool) - Create a new texture + + Sets a new text + """ + self._text = value + if reinit: + self._initText() + + def getFont(self): return self._font + def setFont(self, value, reinit = True): + """ + value (bool) - New Font + reinit (bool) - Create a new texture + + Sets a new font + """ + self._font = value + if reinit: + self._initText() + + def getFont_size(self): return self._font_size + def setFont_size(self, value, reinit = True): + """ + value (bool) - New font size + reinit (bool) - Create a new texture + + Sets a new font size + """ + self._font_size = value + if reinit: + self._initText() + + def getForeground(self): return self._foreground + def setForeground(self, value, reinit = True): + """ + value (bool) - New centered value + reinit (bool) - Create a new texture + + Sets a new value for 'centered' + """ + self._foreground = value + if reinit: + self._initText() + + def getCentered(self): return self._centered + def setCentered(self, value, reinit = True): + """ + value (bool) - New centered value + reinit (bool) - Create a new texture + + Sets a new value for 'centered' + """ + self._centered = value + if reinit: + self._initText() + + def get_size(self): + """ + Returns a text size tuple + """ + return self._aloc_text._text_size + + def getTexture_size(self): + """ + Returns a texture size tuple + """ + return self._aloc_text.texture_size + + def getTextElement(self): + """ + Returns the text element bound to the Text class + """ + return self._aloc_text + + def getTexture(self): + """ + Returns the texture of the bound TextElement + """ + return self._aloc_text.texture + + + #---Properties + + text = property(getText, setText, None, "Text of the object") + font = property(getFont, setFont, None, "Font of the object") + font_size = property(getFont_size, setFont_size, None, "Font size") + foreground = property(getForeground, setForeground, None, "Color/Overlay bitmap of the text") + centered = property(getCentered, setCentered, None, "Display the text centered") + texture_size = property(getTexture_size, None, None, "Size of the used texture") + texture = property(getTexture, None, None, "Texture of bound TextElement") + text_element = property(getTextElement,None , None, "TextElement bound to this class") + +#Optimize critical functions +if psyco and not psyco_optimized: + psyco.bind(TextElement.createTexture) + psyco_optimized = True diff --git a/gr-wxgui/src/python/plotter/grid_plotter_base.py b/gr-wxgui/src/python/plotter/grid_plotter_base.py index a9bd02731..5eaa76bc0 100644 --- a/gr-wxgui/src/python/plotter/grid_plotter_base.py +++ b/gr-wxgui/src/python/plotter/grid_plotter_base.py @@ -78,7 +78,7 @@ class grid_plotter_base(plotter_base): def set_point_label_coordinate(self, coor): """ Set the point label coordinate. - @param coor the coordinate x, y tuple or None + @param coor the coordinate x, y tuple or None """ self.lock() self._point_label_coordinate = coor diff --git a/gr-wxgui/src/python/plotter/plotter_base.py b/gr-wxgui/src/python/plotter/plotter_base.py index b856215e9..5af580339 100644 --- a/gr-wxgui/src/python/plotter/plotter_base.py +++ b/gr-wxgui/src/python/plotter/plotter_base.py @@ -101,7 +101,7 @@ class plotter_base(wx.glcanvas.GLCanvas, common.mutex): self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None) def set_use_persistence(self,enable): - self.use_persistence=enable + self.use_persistence=enable self.clear_accum=True def set_persist_alpha(self,analog_alpha): diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index 0af64b826..f2456241c 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -204,7 +204,7 @@ class waterfall_plotter(grid_plotter_base): Create the texture to fit the fft_size X num_lines. @param flag the set/unset or update flag """ - if flag is not None: + if flag is not None: self._resize_texture_flag = flag return if not self._resize_texture_flag: return diff --git a/gr-wxgui/src/python/powermate.py b/gr-wxgui/src/python/powermate.py index 7f54dff33..7c324c5d9 100644 --- a/gr-wxgui/src/python/powermate.py +++ b/gr-wxgui/src/python/powermate.py @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2005 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. -# +# """ Handler for Griffin PowerMate, Contour ShuttlePro & ShuttleXpress USB knobs @@ -184,7 +184,7 @@ class powermate(threading.Thread): self.setDaemon (1) self.keep_running = True self.start () - + def __del__(self): self.keep_running = False if self.handle >= 0: @@ -227,7 +227,7 @@ class powermate(threading.Thread): except exceptions.OSError: return False - + def set_event_receiver(self, obj): self.event_receiver = obj @@ -239,7 +239,7 @@ class powermate(threading.Thread): """ if self.id != ID_POWERMATE: return False - + static_brightness &= 0xff; if pulse_speed < 0: pulse_speed = 0 @@ -269,14 +269,14 @@ class powermate(threading.Thread): raw_input_event = struct.unpack(input_event_struct,s) sec, usec, type, code, val = self.mapper(raw_input_event) - + if self.event_receiver is None: continue - + if type == IET_SYN: # ignore pass elif type == IET_MSC: # ignore (seems to be PowerMate reporting led brightness) - pass + pass elif type == IET_REL and code == IEC_REL_DIAL: #print "Dial: %d" % (val,) wx.PostEvent(self.event_receiver, PMRotateEvent(val)) @@ -346,13 +346,13 @@ class _contour_remapper(object): if type == IET_KEY: # remap keys so that all 3 gadgets have buttons 0 to 4 in common - return (sec, usec, type, + return (sec, usec, type, (IEC_BTN_5, IEC_BTN_6, IEC_BTN_7, IEC_BTN_8, IEC_BTN_0, IEC_BTN_1, IEC_BTN_2, IEC_BTN_3, IEC_BTN_4, IEC_BTN_9, IEC_BTN_10, IEC_BTN_11, IEC_BTN_12, IEC_BTN_13, IEC_BTN_14)[code - IEC_BTN_0], val) - + return event # ------------------------------------------------------------------------ @@ -374,9 +374,9 @@ class PMButtonEvent(wx.PyEvent): self.button = button self.value = value - def Clone (self): + def Clone (self): self.__class__(self.GetId()) - + class PMRotateEvent(wx.PyEvent): def __init__(self, delta): @@ -384,7 +384,7 @@ class PMRotateEvent(wx.PyEvent): self.SetEventType (grEVT_POWERMATE_ROTATE) self.delta = delta - def Clone (self): + def Clone (self): self.__class__(self.GetId()) @@ -394,9 +394,9 @@ class PMShuttleEvent(wx.PyEvent): self.SetEventType (grEVT_POWERMATE_SHUTTLE) self.position = position - def Clone (self): + def Clone (self): self.__class__(self.GetId()) - + # ------------------------------------------------------------------------ # Example usage # ------------------------------------------------------------------------ @@ -411,14 +411,14 @@ if __name__ == '__main__': EVT_POWERMATE_SHUTTLE(self, self.on_shuttle) self.brightness = 128 self.pulse_speed = 0 - + try: self.pm = powermate(self) except: sys.stderr.write("Unable to find PowerMate or Contour Shuttle\n") sys.exit(1) - self.pm.set_led_state(self.brightness, self.pulse_speed) + self.pm.set_led_state(self.brightness, self.pulse_speed) def on_button(self, evt): @@ -431,11 +431,11 @@ if __name__ == '__main__': new = max(0, min(255, self.brightness + evt.delta)) if new != self.brightness: self.brightness = new - self.pm.set_led_state(self.brightness, self.pulse_speed) - + self.pm.set_led_state(self.brightness, self.pulse_speed) + def on_shuttle(self, evt): print "Shuttle %d" % (evt.position,) - + class App(wx.App): def OnInit(self): title='PowerMate Demo' diff --git a/gr-wxgui/src/python/scope_window.py b/gr-wxgui/src/python/scope_window.py index 89a808cec..dc90a6045 100644 --- a/gr-wxgui/src/python/scope_window.py +++ b/gr-wxgui/src/python/scope_window.py @@ -120,7 +120,7 @@ class control_panel(wx.Panel): parent.subscribe(USE_PERSISTENCE_KEY, widget.ShowItems) #allways show initially, so room is reserved for them widget.ShowItems(True) # (parent[USE_PERSISTENCE_KEY]) - + parent.subscribe(USE_PERSISTENCE_KEY, self._update_layout) ################################################## @@ -406,7 +406,7 @@ class control_panel(wx.Panel): # Just ignore the key value we get # we only need to now that the visability or size of something has changed self.parent.Layout() - #self.parent.Fit() + #self.parent.Fit() ################################################## # Scope window with plotter and control panel @@ -477,12 +477,12 @@ class scope_window(wx.Panel, pubsub.pubsub): self[TRIGGER_LEVEL_KEY] = 0 self[TRIGGER_CHANNEL_KEY] = 0 self[TRIGGER_MODE_KEY] = trig_mode - + self[TRIGGER_SLOPE_KEY] = gr.gr_TRIG_SLOPE_POS self[T_FRAC_OFF_KEY] = 0.5 self[USE_PERSISTENCE_KEY] = use_persistence self[PERSIST_ALPHA_KEY] = persist_alpha - + if self[TRIGGER_MODE_KEY] == gr.gr_TRIG_MODE_STRIPCHART: self[T_FRAC_OFF_KEY] = 0.0 diff --git a/gr-wxgui/src/python/scopesink_gl.py b/gr-wxgui/src/python/scopesink_gl.py index 5ae897400..e6ff532e7 100644 --- a/gr-wxgui/src/python/scopesink_gl.py +++ b/gr-wxgui/src/python/scopesink_gl.py @@ -84,7 +84,7 @@ class _scope_sink_base(gr.hier_block2, common.wxgui_hb): **kwargs #do not end with a comma ): #ensure analog alpha - if persist_alpha is None: + if persist_alpha is None: actual_frame_rate=float(frame_rate) analog_cutoff_freq=0.5 # Hertz #calculate alpha from wanted cutoff freq @@ -157,11 +157,11 @@ class _scope_sink_base(gr.hier_block2, common.wxgui_hb): ) else: for i in range(num_inputs): - c2f = gr.complex_to_float() + c2f = gr.complex_to_float() self.wxgui_connect((self, i), c2f) for j in range(2): self.connect( - (c2f, j), + (c2f, j), ac_couple_block(self.controller, common.index_key(AC_COUPLE_KEY, 2*i+j), SAMPLE_RATE_KEY), (scope, 2*i+j), ) @@ -187,7 +187,7 @@ class test_top_block (stdgui2.std_top_block): default_input_rate = 1e6 if len(argv) > 1: - input_rate = int(argv[1]) + input_rate = int(argv[1]) else: input_rate = default_input_rate @@ -202,12 +202,12 @@ class test_top_block (stdgui2.std_top_block): t_scale = .00003*default_input_rate/input_rate # old behavior print "input rate %s v_scale %s t_scale %s" % (input_rate,v_scale,t_scale) - + # Generate a complex sinusoid ampl=1.0e3 self.src0 = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 25.1e3*input_rate/default_input_rate, ampl) - self.noise =gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 11.1*25.1e3*input_rate/default_input_rate, ampl/10) + self.noise =gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 11.1*25.1e3*input_rate/default_input_rate, ampl/10) #self.noise =gr.noise_source_c(gr.GR_GAUSSIAN, ampl/10) self.combine=gr.add_cc() @@ -223,7 +223,7 @@ class test_top_block (stdgui2.std_top_block): # self.connect("src0 throttle scope") self.connect(self.src0,(self.combine,0)) self.connect(self.noise,(self.combine,1)) - self.connect(self.combine, self.thr, scope) + self.connect(self.combine, self.thr, scope) def main (): app = stdgui2.stdapp (test_top_block, "O'Scope Test App") diff --git a/gr-wxgui/src/python/scopesink_nongl.py b/gr-wxgui/src/python/scopesink_nongl.py index bf2c50917..d45e79906 100644 --- a/gr-wxgui/src/python/scopesink_nongl.py +++ b/gr-wxgui/src/python/scopesink_nongl.py @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2003,2004,2006,2007 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. -# +# from gnuradio import gr, gru, eng_notation from gnuradio.wxgui import stdgui2 @@ -42,7 +42,7 @@ class scope_sink_f(gr.hier_block2): msgq = gr.msg_queue(2) # message queue that holds at most 2 messages self.guts = gr.oscope_sink_f(sample_rate, msgq) - for i in range(num_inputs): + for i in range(num_inputs): self.connect((self, i), (self.guts, i)) self.win = scope_window(win_info (msgq, sample_rate, frame_decim, @@ -63,16 +63,16 @@ class scope_sink_c(gr.hier_block2): msgq = gr.msg_queue(2) # message queue that holds at most 2 messages self.guts = gr.oscope_sink_f(sample_rate, msgq) - for i in range(num_inputs): - c2f = gr.complex_to_float() + for i in range(num_inputs): + c2f = gr.complex_to_float() self.connect((self, i), c2f) self.connect((c2f, 0), (self.guts, 2*i+0)) self.connect((c2f, 1), (self.guts, 2*i+1)) - + self.win = scope_window(win_info(msgq, sample_rate, frame_decim, v_scale, t_scale, self.guts, title), parent) self.win.info.xy = xy_mode - + def set_sample_rate(self, sample_rate): self.guts.set_sample_rate(sample_rate) self.win.info.set_sample_rate(sample_rate) @@ -132,7 +132,7 @@ v_scale_list = [ # counts / div, LARGER gains are SMALLER /div, appear EARLIER 1.0e+4 # 10000 /div, USRP full scale is -/+ 32767 ] - + wxDATA_EVENT = wx.NewEventType() def EVT_DATA_EVENT(win, func): @@ -144,12 +144,12 @@ class DataEvent(wx.PyEvent): self.SetEventType (wxDATA_EVENT) self.data = data - def Clone (self): + def Clone (self): self.__class__ (self.GetId()) class win_info (object): - __slots__ = ['msgq', 'sample_rate', 'frame_decim', 'v_scale', + __slots__ = ['msgq', 'sample_rate', 'frame_decim', 'v_scale', 'scopesink', 'title', 'time_scale_cursor', 'v_scale_cursor', 'marker', 'xy', 'autorange', 'running'] @@ -178,7 +178,7 @@ class win_info (object): def set_sample_rate(self, sample_rate): self.sample_rate = sample_rate - + def get_sample_rate (self): return self.sample_rate @@ -202,31 +202,31 @@ class input_watcher (gru.msgq_runner): def handle_msg(self, msg): if self.iscan == 0: # only display at frame_decim self.iscan = self.frame_decim - + nchan = int(msg.arg1()) # number of channels of data in msg nsamples = int(msg.arg2()) # number of samples in each channel - + s = msg.to_string() # get the body of the msg as a string - + bytes_per_chan = nsamples * gr.sizeof_float - + records = [] for ch in range (nchan): - + start = ch * bytes_per_chan chan_data = s[start:start+bytes_per_chan] rec = numpy.fromstring (chan_data, numpy.float32) records.append (rec) - + # print "nrecords = %d, reclen = %d" % (len (records),nsamples) - + de = DataEvent (records) wx.PostEvent (self.event_receiver, de) records = [] del de self.iscan -= 1 - + class scope_window (wx.Panel): @@ -248,7 +248,7 @@ class scope_window (wx.Panel): self.SetAutoLayout (True) self.sizer.Fit (self) self.set_autorange(self.info.autorange) - + # second row of control buttons etc. appears BELOW control_box def make_control2_box (self): @@ -339,14 +339,14 @@ class scope_window (wx.Panel): ctrlbox.Add (self.xy_choice, 0, wx.ALIGN_CENTER) return ctrlbox - + _marker_choices = ['line', 'plus', 'dot'] def update_timebase_label (self): time_per_div = self.info.get_time_per_div () s = ' ' + eng_notation.num_to_str (time_per_div) + 's/div' self.time_base_label.SetLabel (s) - + def decr_timebase (self, evt): self.info.time_scale_cursor.prev () self.update_timebase_label () @@ -359,7 +359,7 @@ class scope_window (wx.Panel): volts_per_div = self.info.get_volts_per_div () s = ' ' + eng_notation.num_to_str (volts_per_div) + '/div' # Not V/div self.v_scale_label.SetLabel (s) - + def decr_v_scale (self, evt): self.info.v_scale_cursor.prev () self.update_v_scale_label () @@ -367,7 +367,7 @@ class scope_window (wx.Panel): def incr_v_scale (self, evt): self.info.v_scale_cursor.next () self.update_v_scale_label () - + def marker_choice_event (self, evt): s = evt.GetString () self.set_marker (s) @@ -388,13 +388,13 @@ class scope_window (wx.Panel): self.autorange_checkbox.SetValue(False) self.inc_v_button.Enable(True) self.dec_v_button.Enable(True) - + def autorange_checkbox_event(self, evt): if evt.Checked(): self.set_autorange(True) else: self.set_autorange(False) - + def set_marker (self, s): self.info.set_marker (s) # set info for drawing routines i = self.marker_choice.FindString (s) @@ -409,7 +409,7 @@ class scope_window (wx.Panel): def set_format_plus (self): self.set_marker ('plus') - + def xy_choice_event (self, evt): s = evt.GetString () self.info.xy = s == 'X:Y' @@ -430,19 +430,19 @@ class scope_window (wx.Panel): sink.set_trigger_mode (gr.gr_TRIG_MODE_FREE) else: assert 0, "Bad trig_mode_choice string" - + def set_trig_level50 (self, evt): self.info.scopesink.set_trigger_level_auto () def run_stop (self, evt): self.info.running = not self.info.running - + class graph_window (plot.PlotCanvas): channel_colors = ['BLUE', 'RED', 'CYAN', 'MAGENTA', 'GREEN', 'YELLOW'] - + def __init__ (self, info, parent, id = -1, pos = wx.DefaultPosition, size = (640, 240), style = wx.DEFAULT_FRAME_STYLE, name = ""): @@ -453,7 +453,7 @@ class graph_window (plot.PlotCanvas): self.SetEnableZoom (True) self.SetEnableLegend(True) # self.SetBackgroundColour ('black') - + self.info = info; self.y_range = None self.x_range = None @@ -468,11 +468,11 @@ class graph_window (plot.PlotCanvas): def channel_color (self, ch): return self.channel_colors[ch % len(self.channel_colors)] - + def format_data (self, evt): if not self.info.running: return - + if self.info.xy: self.format_xy_data (evt) return @@ -545,7 +545,7 @@ class graph_window (plot.PlotCanvas): points = numpy.zeros ((len(records[0]), 2), numpy.float32) points[:,0] = records[0] points[:,1] = records[1] - + self.SetXUseScopeTicks (False) m = info.get_marker () @@ -607,7 +607,7 @@ class test_top_block (stdgui2.std_top_block): stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv) if len(argv) > 1: - frame_decim = int(argv[1]) + frame_decim = int(argv[1]) else: frame_decim = 1 @@ -622,7 +622,7 @@ class test_top_block (stdgui2.std_top_block): t_scale = None # old behavior print "frame decim %s v_scale %s t_scale %s" % (frame_decim,v_scale,t_scale) - + input_rate = 1e6 # Generate a complex sinusoid @@ -639,7 +639,7 @@ class test_top_block (stdgui2.std_top_block): # Ultimately this will be # self.connect("src0 throttle scope") - self.connect(self.src0, self.thr, scope) + self.connect(self.src0, self.thr, scope) def main (): app = stdgui2.stdapp (test_top_block, "O'Scope Test App") diff --git a/gr-wxgui/src/python/stdgui2.py b/gr-wxgui/src/python/stdgui2.py index f397fd01e..71436d72c 100644 --- a/gr-wxgui/src/python/stdgui2.py +++ b/gr-wxgui/src/python/stdgui2.py @@ -1,23 +1,23 @@ # # Copyright 2004 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. -# +# '''A simple wx gui for GNU Radio applications''' @@ -74,7 +74,7 @@ class stdframe (wx.Frame): def top_block (self): return self.panel.top_block - + class stdpanel (wx.Panel): def __init__ (self, parent, frame, top_block_maker, max_nouts=None): @@ -91,7 +91,7 @@ class stdpanel (wx.Panel): if(max_nouts is not None): self.top_block.start (max_nouts) else: - self.top_block.start () + self.top_block.start () class std_top_block (gr.top_block): def __init__ (self, parent, panel, vbox, argv): diff --git a/gr-wxgui/src/python/waterfall_window.py b/gr-wxgui/src/python/waterfall_window.py index 6536ada10..c78244f04 100644 --- a/gr-wxgui/src/python/waterfall_window.py +++ b/gr-wxgui/src/python/waterfall_window.py @@ -159,7 +159,7 @@ class control_panel(wx.Panel): self.parent[FRAME_RATE_KEY] *= 0.75 if self.parent[FRAME_RATE_KEY] < 1.0: self.parent[FRAME_RATE_KEY] = 1.0 - + if self.parent[FRAME_RATE_KEY] == old_rate: self.parent[DECIMATION_KEY] += 1 def _on_decr_time_scale(self, event): @@ -268,7 +268,7 @@ class waterfall_window(wx.Panel, pubsub.pubsub): #plot the fft self.plotter.set_samples( samples=samples, - minimum=self[REF_LEVEL_KEY] - self[DYNAMIC_RANGE_KEY], + minimum=self[REF_LEVEL_KEY] - self[DYNAMIC_RANGE_KEY], maximum=self[REF_LEVEL_KEY], ) #update the plotter diff --git a/gr-wxgui/src/python/waterfallsink_nongl.py b/gr-wxgui/src/python/waterfallsink_nongl.py index 3c25a9d9f..213415c82 100644 --- a/gr-wxgui/src/python/waterfallsink_nongl.py +++ b/gr-wxgui/src/python/waterfallsink_nongl.py @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2003,2004,2005,2007,2008 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. -# +# from gnuradio import gr, gru, window from gnuradio.wxgui import stdgui2 @@ -26,7 +26,7 @@ import wx import gnuradio.wxgui.plot as plot import numpy import os -import math +import math default_fftsink_size = (640,240) default_fft_rate = gr.prefs().get_long('wxgui', 'fft_rate', 15) @@ -70,7 +70,7 @@ class waterfall_sink_base(object): def _set_n(self): self.one_in_n.set_n(max(1, int(self.sample_rate/self.fft_size/self.fft_rate))) - + class waterfall_sink_f(gr.hier_block2, waterfall_sink_base): def __init__(self, parent, baseband_freq=0, y_per_div=10, ref_level=50, sample_rate=1, fft_size=512, @@ -85,11 +85,11 @@ class waterfall_sink_f(gr.hier_block2, waterfall_sink_base): sample_rate=sample_rate, fft_size=fft_size, fft_rate=fft_rate, average=average, avg_alpha=avg_alpha, title=title) - + self.s2p = gr.serial_to_parallel(gr.sizeof_float, self.fft_size) self.one_in_n = gr.keep_one_in_n(gr.sizeof_float * self.fft_size, max(1, int(self.sample_rate/self.fft_size/self.fft_rate))) - + mywindow = window.blackmanharris(self.fft_size) self.fft = gr.fft_vfc(self.fft_size, True, mywindow) self.c2mag = gr.complex_to_mag(self.fft_size) @@ -105,7 +105,7 @@ class waterfall_sink_f(gr.hier_block2, waterfall_sink_base): class waterfall_sink_c(gr.hier_block2, waterfall_sink_base): def __init__(self, parent, baseband_freq=0, y_per_div=10, ref_level=50, sample_rate=1, fft_size=512, - fft_rate=default_fft_rate, average=False, avg_alpha=None, + fft_rate=default_fft_rate, average=False, avg_alpha=None, title='', size=default_fftsink_size, **kwargs): gr.hier_block2.__init__(self, "waterfall_sink_f", @@ -120,7 +120,7 @@ class waterfall_sink_c(gr.hier_block2, waterfall_sink_base): self.s2p = gr.serial_to_parallel(gr.sizeof_gr_complex, self.fft_size) self.one_in_n = gr.keep_one_in_n(gr.sizeof_gr_complex * self.fft_size, max(1, int(self.sample_rate/self.fft_size/self.fft_rate))) - + mywindow = window.blackmanharris(self.fft_size) self.fft = gr.fft_vcc(self.fft_size, True, mywindow) self.c2mag = gr.complex_to_mag(self.fft_size) @@ -145,9 +145,9 @@ class DataEvent(wx.PyEvent): self.SetEventType (myDATA_EVENT) self.data = data - def Clone (self): + def Clone (self): self.__class__ (self.GetId()) - + class input_watcher (gru.msgq_runner): def __init__ (self, msgq, fft_size, event_receiver, **kwds): self.fft_size = fft_size @@ -181,7 +181,7 @@ class waterfall_window (wx.Panel): self.bm = wx.EmptyBitmap(self.fftsink.fft_size, 300, -1) self.scale_factor = 5.0 # FIXME should autoscale, or set this - + dc1 = wx.MemoryDC() dc1.SelectObject(self.bm) dc1.Clear() @@ -191,9 +191,9 @@ class waterfall_window (wx.Panel): wx.EVT_PAINT( self, self.OnPaint ) wx.EVT_CLOSE (self, self.on_close_window) EVT_DATA_EVENT (self, self.set_data) - + self.build_popup_menu() - + wx.EVT_CLOSE (self, self.on_close_window) self.Bind(wx.EVT_RIGHT_UP, self.on_right_click) @@ -213,14 +213,14 @@ class waterfall_window (wx.Panel): r.extend(range(0,255,4)) r.extend(self.const_list(255,64)) r.extend(range(255,128,-4)) - + g = [] g.extend(self.const_list(0,32)) g.extend(range(0,255,4)) g.extend(self.const_list(255,64)) g.extend(range(255,0,-4)) g.extend(self.const_list(0,32)) - + b = range(128,255,4) b.extend(self.const_list(255,64)) b.extend(range(255,0,-4)) @@ -234,7 +234,7 @@ class waterfall_window (wx.Panel): colour = wx.Colour(r[i], g[i], b[i]) pens.append( wx.Pen(colour, 2, wx.SOLID)) return pens - + def OnPaint(self, event): dc = wx.PaintDC(self) self.DoDrawing(dc) @@ -243,7 +243,7 @@ class waterfall_window (wx.Panel): if dc is None: dc = wx.ClientDC(self) dc.DrawBitmap(self.bm, 0, 0, False ) - + def const_list(self,const,len): a = [const] @@ -285,18 +285,18 @@ class waterfall_window (wx.Panel): value = int(dB[x_pos] * scale_factor) value = min(255, max(0, value)) dc1.SetPen(self.pens[value]) - dc1.DrawRectangle(x_pos*p_width, 0, p_width, 2) + dc1.DrawRectangle(x_pos*p_width, 0, p_width, 2) else: # complex fft for x_pos in range(0, d_max): # positive freqs value = int(dB[x_pos] * scale_factor) value = min(255, max(0, value)) dc1.SetPen(self.pens[value]) - dc1.DrawRectangle(x_pos*p_width + d_max, 0, p_width, 2) + dc1.DrawRectangle(x_pos*p_width + d_max, 0, p_width, 2) for x_pos in range(0 , d_max): # negative freqs value = int(dB[x_pos+d_max] * scale_factor) value = min(255, max(0, value)) dc1.SetPen(self.pens[value]) - dc1.DrawRectangle(x_pos*p_width, 0, p_width, 2) + dc1.DrawRectangle(x_pos*p_width, 0, p_width, 2) del dc1 self.DoDrawing (None) |