Merged changeset r9241:9289 from jblum/glwxgui into trunk. Adds OpenGL versions...
[debian/gnuradio] / gr-wxgui / src / python / number_window.py
diff --git a/gr-wxgui/src/python/number_window.py b/gr-wxgui/src/python/number_window.py
new file mode 100644 (file)
index 0000000..8572b7c
--- /dev/null
@@ -0,0 +1,184 @@
+#
+# Copyright 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.
+#
+
+##################################################
+# Imports
+##################################################
+import common
+import numpy
+import wx
+import pubsub
+from constants import *
+
+##################################################
+# Constants
+##################################################
+NEG_INF = float('-inf')
+SLIDER_STEPS = 100
+AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP = -3, 0
+DEFAULT_NUMBER_RATE = 5
+DEFAULT_WIN_SIZE = (300, 300)
+DEFAULT_GAUGE_RANGE = 1000
+
+##################################################
+# Number window control panel
+##################################################
+class control_panel(wx.Panel):
+       """!
+       A control panel with wx widgits to control the averaging.
+       """
+
+       def __init__(self, parent):
+               """!
+               Create a new control panel.
+               @param parent the wx parent window
+               """
+               self.parent = parent
+               wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
+               control_box = wx.BoxSizer(wx.VERTICAL)
+               #checkboxes for average and peak hold
+               control_box.AddStretchSpacer()
+               control_box.Add(common.LabelText(self, 'Options'), 0, wx.ALIGN_CENTER)
+               self.average_check_box = common.CheckBoxController(self, 'Average', parent.ext_controller, parent.average_key)
+               control_box.Add(self.average_check_box, 0, wx.EXPAND)
+               self.peak_hold_check_box = common.CheckBoxController(self, 'Peak Hold', parent, PEAK_HOLD_KEY)
+               control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
+               control_box.AddSpacer(2)
+               self.avg_alpha_slider = common.LogSliderController(
+                       self, 'Avg Alpha',
+                       AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP, SLIDER_STEPS,
+                       parent.ext_controller, parent.avg_alpha_key,
+                       formatter=lambda x: ': %.4f'%x,
+               )
+               parent.ext_controller.subscribe(parent.average_key, self.avg_alpha_slider.Enable)
+               control_box.Add(self.avg_alpha_slider, 0, wx.EXPAND)
+               #run/stop
+               control_box.AddStretchSpacer()
+               self.run_button = common.ToggleButtonController(self, parent, RUNNING_KEY, 'Stop', 'Run')
+               control_box.Add(self.run_button, 0, wx.EXPAND)
+               #set sizer
+               self.SetSizerAndFit(control_box)
+
+##################################################
+# Numbersink window with label and gauges
+##################################################
+class number_window(wx.Panel, pubsub.pubsub, common.prop_setter):
+       def __init__(
+               self,
+               parent,
+               controller,
+               size,
+               title,
+               units,
+               show_gauge,
+               real,
+               minval,
+               maxval,
+               decimal_places,
+               average_key,
+               avg_alpha_key,
+               peak_hold,
+               msg_key,
+       ):
+               pubsub.pubsub.__init__(self)
+               wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
+               #setup
+               self.peak_val_real = NEG_INF
+               self.peak_val_imag = NEG_INF
+               self.ext_controller = controller
+               self.real = real
+               self.units = units
+               self.minval = minval
+               self.maxval = maxval
+               self.decimal_places = decimal_places
+               self.average_key = average_key
+               self.avg_alpha_key = avg_alpha_key
+               #setup the box with display and controls
+               self.control_panel = control_panel(self)
+               main_box = wx.BoxSizer(wx.HORIZONTAL)
+               sizer = wx.BoxSizer(wx.VERTICAL)
+               main_box.Add(sizer, 1, wx.EXPAND)
+               main_box.Add(self.control_panel, 0, wx.EXPAND)
+               sizer.Add(common.LabelText(self, title), 1, wx.ALIGN_CENTER)
+               self.text = wx.StaticText(self, size=(size[0], -1))
+               sizer.Add(self.text, 1, wx.EXPAND)
+               self.gauge_real = wx.Gauge(self, range=DEFAULT_GAUGE_RANGE, style=wx.GA_HORIZONTAL)
+               self.gauge_imag = wx.Gauge(self, range=DEFAULT_GAUGE_RANGE, style=wx.GA_HORIZONTAL)
+               #hide/show gauges
+               self.show_gauges(show_gauge)
+               sizer.Add(self.gauge_real, 1, wx.EXPAND)
+               sizer.Add(self.gauge_imag, 1, wx.EXPAND)
+               self.SetSizerAndFit(main_box)
+               #initial setup
+               self.ext_controller[self.average_key] = self.ext_controller[self.average_key]
+               self.ext_controller[self.avg_alpha_key] = self.ext_controller[self.avg_alpha_key]
+               self._register_set_prop(self, PEAK_HOLD_KEY, peak_hold)
+               self._register_set_prop(self, RUNNING_KEY, True)
+               #register events
+               self.ext_controller.subscribe(msg_key, self.handle_msg)
+
+       def show_gauges(self, show_gauge):
+               """!
+               Show or hide the gauges.
+               If this is real, never show the imaginary gauge.
+               @param show_gauge true to show
+               """
+               if show_gauge: self.gauge_real.Show()
+               else: self.gauge_real.Hide()
+               if show_gauge and not self.real: self.gauge_imag.Show()
+               else: self.gauge_imag.Hide()
+
+       def handle_msg(self, msg):
+               """!
+               Handle a message from the message queue.
+               Convert the string based message into a float or complex.
+               If more than one number was read, only take the last number.
+               Perform peak hold operations, set the gauges and display.
+               @param msg the number sample as a character array
+               """
+               if not self[RUNNING_KEY]: return
+               #set gauge
+               def set_gauge_value(gauge, value):
+                       gauge_val = DEFAULT_GAUGE_RANGE*(value-self.minval)/(self.maxval-self.minval)
+                       gauge_val = max(0, gauge_val) #clip
+                       gauge_val = min(DEFAULT_GAUGE_RANGE, gauge_val) #clip
+                       gauge.SetValue(gauge_val)
+               format_string = "%%.%df"%self.decimal_places
+               if self.real:
+                       sample = numpy.fromstring(msg, numpy.float32)[-1]
+                       if self[PEAK_HOLD_KEY]: sample = self.peak_val_real = max(self.peak_val_real, sample)
+                       label_text = "%s %s"%(format_string%sample, self.units)
+                       set_gauge_value(self.gauge_real, sample)
+               else:
+                       sample = numpy.fromstring(msg, numpy.complex64)[-1]
+                       if self[PEAK_HOLD_KEY]:
+                               self.peak_val_real = max(self.peak_val_real, sample.real)
+                               self.peak_val_imag = max(self.peak_val_imag, sample.imag)
+                               sample = self.peak_val_real + self.peak_val_imag*1j
+                       label_text = "%s + %sj %s"%(format_string%sample.real, format_string%sample.imag, self.units)
+                       set_gauge_value(self.gauge_real, sample.real)
+                       set_gauge_value(self.gauge_imag, sample.imag)
+               #set label text
+               self.text.SetLabel(label_text)
+               #clear peak hold
+               if not self[PEAK_HOLD_KEY]:
+                       self.peak_val_real = NEG_INF
+                       self.peak_val_imag = NEG_INF