diff options
Diffstat (limited to 'grc/src/grc_gnuradio')
-rw-r--r-- | grc/src/grc_gnuradio/wxgui/Makefile.am | 6 | ||||
-rw-r--r-- | grc/src/grc_gnuradio/wxgui/forms/__init__.py | 54 | ||||
-rw-r--r-- | grc/src/grc_gnuradio/wxgui/forms/converters.py | 143 | ||||
-rw-r--r-- | grc/src/grc_gnuradio/wxgui/forms/forms.py | 473 |
4 files changed, 0 insertions, 676 deletions
diff --git a/grc/src/grc_gnuradio/wxgui/Makefile.am b/grc/src/grc_gnuradio/wxgui/Makefile.am index b82ca4c90..2e5e7ebd0 100644 --- a/grc/src/grc_gnuradio/wxgui/Makefile.am +++ b/grc/src/grc_gnuradio/wxgui/Makefile.am @@ -25,9 +25,3 @@ ourpythondir = $(grc_gnuradio_prefix)/wxgui ourpython_PYTHON = \ __init__.py \ top_block_gui.py - -oursubpythondir = $(grc_gnuradio_prefix)/wxgui/forms -oursubpython_PYTHON = \ - forms/__init__.py \ - forms/converters.py \ - forms/forms.py diff --git a/grc/src/grc_gnuradio/wxgui/forms/__init__.py b/grc/src/grc_gnuradio/wxgui/forms/__init__.py deleted file mode 100644 index 07226668b..000000000 --- a/grc/src/grc_gnuradio/wxgui/forms/__init__.py +++ /dev/null @@ -1,54 +0,0 @@ -# -# 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. -# - -""" -The following classes will be available through gnuradio.wxgui.forms: -""" - -######################################################################## -# External Converters -######################################################################## -from converters import \ - eval_converter, str_converter, \ - float_converter, int_converter - -######################################################################## -# External Forms -######################################################################## -from forms import \ - radio_buttons, drop_down, notebook, \ - button, toggle_button, single_button, \ - check_box, text_box, static_text, \ - slider, log_slider - -######################################################################## -# Helpful widgets -######################################################################## -import wx - -class static_box_sizer(wx.StaticBoxSizer): - def __init__(self, parent, label='', bold=False, orient=wx.VERTICAL): - box = wx.StaticBox(parent=parent, label=label) - if bold: - font = box.GetFont() - font.SetWeight(wx.FONTWEIGHT_BOLD) - box.SetFont(font) - wx.StaticBoxSizer.__init__(self, box=box, orient=orient) diff --git a/grc/src/grc_gnuradio/wxgui/forms/converters.py b/grc/src/grc_gnuradio/wxgui/forms/converters.py deleted file mode 100644 index 5971cfc09..000000000 --- a/grc/src/grc_gnuradio/wxgui/forms/converters.py +++ /dev/null @@ -1,143 +0,0 @@ -# -# 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. -# - -from gnuradio import eng_notation -import math - -class abstract_converter(object): - def external_to_internal(self, v): - """ - Convert from user specified value to value acceptable to underlying primitive. - The underlying primitive usually expects strings. - """ - raise NotImplementedError - def internal_to_external(self, s): - """ - Convert from underlying primitive value to user specified value. - The underlying primitive usually expects strings. - """ - raise NotImplementedError - def help(self): - return "Any string is acceptable" - -class identity_converter(abstract_converter): - def external_to_internal(self,v): - return v - def internal_to_external(self, s): - return s - -######################################################################## -# Commonly used converters -######################################################################## -class chooser_converter(abstract_converter): - """ - Convert between a set of possible choices and an index. - Used in the chooser base and all sub-classes. - """ - def __init__(self, choices): - self._choices = choices - def external_to_internal(self, choice): - return self._choices.index(choice) - def internal_to_external(self, index): - return self._choices[index] - def help(self): - return 'Enter a possible value in choices: "%s"'%str(self._choices) - -class bool_converter(abstract_converter): - """ - The internal representation is boolean. - The external representation is specified. - Used in the check box form. - """ - def __init__(self, true, false): - self._true = true - self._false = false - def external_to_internal(self, v): - return bool(v) - def internal_to_external(self, v): - if v: return self._true - else: return self._false - def help(self): - return "Value must be cast-able to type bool." - -class eval_converter(abstract_converter): - """ - A catchall converter when int and float are not enough. - Evaluate the internal representation with python's eval(). - Possible uses, set a complex number, constellation points. - Used in text box. - """ - def external_to_internal(self, s): - return str(s) - def internal_to_external(self, s): - return eval(s) - def help(self): - return "Value must be evaluatable by python's eval." - -class str_converter(abstract_converter): - def external_to_internal(self, v): - return str(v) - def internal_to_external(self, s): - return str(s) - -class int_converter(abstract_converter): - def external_to_internal(self, v): - return str(int(round(v))) - def internal_to_external(self, s): - return int(s, 0) - def help(self): - return "Enter an integer. Leading 0x indicates hex" - -class float_converter(abstract_converter): - def external_to_internal(self, v): - return eng_notation.num_to_str(v) - def internal_to_external(self, s): - return eng_notation.str_to_num(s) - def help(self): - return "Enter a float with optional scale suffix. E.g., 100.1M" - -class slider_converter(abstract_converter): - """ - Scale values to and from the slider. - """ - def __init__(self, minimum, maximum, num_steps, cast): - assert minimum < maximum - assert num_steps > 0 - self._offset = minimum - self._scaler = float(maximum - minimum)/num_steps - self._cast = cast - def external_to_internal(self, v): - return (v - self._offset)/self._scaler - def internal_to_external(self, v): - return self._cast(v*self._scaler + self._offset) - def help(self): - return "Value should be within slider range" - -class log_slider_converter(slider_converter): - def __init__(self, min_exp, max_exp, num_steps, base): - assert min_exp < max_exp - assert num_steps > 0 - self._base = base - slider_converter.__init__(self, minimum=min_exp, maximum=max_exp, num_steps=num_steps, cast=float) - def external_to_internal(self, v): - return slider_converter.external_to_internal(self, math.log(v, self._base)) - def internal_to_external(self, v): - return self._base**slider_converter.internal_to_external(self, v) diff --git a/grc/src/grc_gnuradio/wxgui/forms/forms.py b/grc/src/grc_gnuradio/wxgui/forms/forms.py deleted file mode 100644 index 5c5b6bad5..000000000 --- a/grc/src/grc_gnuradio/wxgui/forms/forms.py +++ /dev/null @@ -1,473 +0,0 @@ -# -# 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. -# - -""" -The forms module contains general purpose wx-gui forms for gnuradio apps. - -The forms follow a layered model: - * internal layer - * deals with the wxgui objects directly - * implemented in event handler and update methods - * translation layer - * translates the between the external and internal layers - * handles parsing errors between layers - * external layer - * provided external access to the user - * set_value, get_value, and optional callback - * set and get through optional pubsub and key -""" - -EXT_KEY = 'external' -INT_KEY = 'internal' - -import wx -import sys -from gnuradio.gr.pubsub import pubsub -import converters - -EVT_DATA = wx.PyEventBinder(wx.NewEventType()) -class DataEvent(wx.PyEvent): - def __init__(self, data): - wx.PyEvent.__init__(self, wx.NewId(), EVT_DATA.typeId) - self.data = data - -######################################################################## -# Base Class Form -######################################################################## -class _form_base(pubsub, wx.BoxSizer): - def __init__(self, parent=None, sizer=None, proportion=0, flag=wx.EXPAND, ps=None, key='', value=None, callback=None, converter=converters.identity_converter()): - pubsub.__init__(self) - wx.BoxSizer.__init__(self, wx.HORIZONTAL) - self._parent = parent - self._converter = converter - self._callback = callback - self._widgets = list() - #add to the sizer if provided - if sizer: sizer.Add(self, proportion, flag) - #proxy the pubsub and key into this form - if ps is not None: - assert key - self.proxy(EXT_KEY, ps, key) - #no pubsub passed, must set initial value - else: self.set_value(value) - - def _add_widget(self, widget, label='', flag=0): - """ - Add the main widget to this object sizer. - If label is passed, add a label as well. - Register the widget and the label in the widgets list (for enable/disable). - Bind the update handler to the widget for data events. - This ensures that the gui thread handles updating widgets. - Setup the pusub triggers for external and internal. - @param widget the main widget - @param label the optional label - @param flag additional flags for widget - """ - #setup data event - widget.Bind(EVT_DATA, lambda x: self._update(x.data)) - update = lambda x: wx.PostEvent(widget, DataEvent(x)) - #register widget - self._widgets.append(widget) - #create optional label - if not label: self.Add(widget, 1, wx.ALIGN_CENTER_VERTICAL | flag) - else: - label_text = wx.StaticText(self._parent, label='%s: '%label) - self._widgets.append(label_text) - self.Add(label_text, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT) - self.Add(widget, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | flag) - #initialize without triggering pubsubs - self._translate_external_to_internal(self[EXT_KEY]) - update(self[INT_KEY]) - #subscribe all the functions - self.subscribe(INT_KEY, update) - self.subscribe(INT_KEY, self._translate_internal_to_external) - self.subscribe(EXT_KEY, self._translate_external_to_internal) - if self._callback: self.subscribe(EXT_KEY, self._callback) - - def _translate_external_to_internal(self, external): - try: - internal = self._converter.external_to_internal(external) - #prevent infinite loop between internal and external pubsub keys by only setting if changed - if self[INT_KEY] != internal: self[INT_KEY] = internal - except Exception, e: - self._err_msg(external, e) - self[INT_KEY] = self[INT_KEY] #reset to last good setting - - def _translate_internal_to_external(self, internal): - try: - external = self._converter.internal_to_external(internal) - #prevent infinite loop between internal and external pubsub keys by only setting if changed - if self[EXT_KEY] != external: self[EXT_KEY] = external - except Exception, e: - self._err_msg(internal, e) - self[EXT_KEY] = self[EXT_KEY] #reset to last good setting - - def _err_msg(self, value, e): - print >> sys.stderr, 'Error translating value: "%s"\n\t%s\n\t%s'%(value, e, self._converter.help()) - - #override in subclasses to handle the wxgui object - def _update(self, value): raise NotImplementedError - def _handle(self, event): raise NotImplementedError - - #provide a set/get interface for this form - def get_value(self): return self[EXT_KEY] - def set_value(self, value): self[EXT_KEY] = value - - def Disable(self, disable=True): self.Enable(not disable) - def Enable(self, enable=True): - if enable: - for widget in self._widgets: widget.Enable() - else: - for widget in self._widgets: widget.Disable() - -######################################################################## -# Static Text Form -######################################################################## -class static_text(_form_base): - def __init__(self, label='', width=-1, bold=False, converter=converters.str_converter(), **kwargs): - _form_base.__init__(self, converter=converter, **kwargs) - self._static_text = wx.StaticText(self._parent, size=wx.Size(width, -1)) - if bold: - font = self._static_text.GetFont() - font.SetWeight(wx.FONTWEIGHT_BOLD) - self._static_text.SetFont(font) - self._add_widget(self._static_text, label) - - def _update(self, label): self._static_text.SetLabel(label) - -######################################################################## -# Text Box Form -######################################################################## -class text_box(_form_base): - def __init__(self, label='', width=-1, converter=converters.eval_converter(), **kwargs): - _form_base.__init__(self, converter=converter, **kwargs) - self._text_box = wx.TextCtrl(self._parent, size=wx.Size(width, -1), style=wx.TE_PROCESS_ENTER) - self._text_box.Bind(wx.EVT_TEXT_ENTER, self._handle) - self._add_widget(self._text_box, label) - - def _handle(self, event): self[INT_KEY] = self._text_box.GetValue() - def _update(self, value): self._text_box.SetValue(value) - -######################################################################## -# Slider Form -######################################################################## -class _slider_base(_form_base): - """ - Base class for linear and log slider. - @param length the length of the slider in px - @param style wx.SL_HORIZONTAL or wx.SL_VERTICAL - """ - def __init__(self, label='', length=-1, converter=None, num_steps=100, style=wx.SL_HORIZONTAL, **kwargs): - _form_base.__init__(self, converter=converter, **kwargs) - if style & wx.SL_HORIZONTAL: slider_size = wx.Size(length, -1) - elif style & wx.SL_VERTICAL: slider_size = wx.Size(-1, length) - else: raise NotImplementedError - self._slider = wx.Slider(self._parent, minValue=0, maxValue=num_steps, size=slider_size, style=style) - self._slider.Bind(wx.EVT_SCROLL, self._handle) - self._add_widget(self._slider, label, flag=wx.EXPAND) - - def _handle(self, event): self[INT_KEY] = self._slider.GetValue() - def _update(self, value): self._slider.SetValue(value) - -class slider(_slider_base): - """ - A generic linear slider. - @param cast a cast function, int, or float (default=float) - """ - def __init__(self, minimum=-100, maximum=100, num_steps=100, step_size=None, cast=float, **kwargs): - assert step_size or num_steps - if step_size is not None: num_steps = (maximum - minimum)/step_size - converter = converters.slider_converter(minimum=minimum, maximum=maximum, num_steps=num_steps, cast=cast) - _slider_base.__init__(self, converter=converter, num_steps=num_steps, **kwargs) - -class log_slider(_slider_base): - """ - A generic log slider. - """ - def __init__(self, min_exp=0, max_exp=1, base=10, num_steps=100, step_size=None, **kwargs): - assert step_size or num_steps - if step_size is not None: num_steps = (max_exp - min_exp)/step_size - converter = converters.log_slider_converter(min_exp=min_exp, max_exp=max_exp, num_steps=num_steps, base=base) - _slider_base.__init__(self, converter=converter, num_steps=num_steps, **kwargs) - -######################################################################## -# Check Box Form -######################################################################## -class check_box(_form_base): - def __init__(self, label='', true=True, false=False, **kwargs): - _form_base.__init__(self, converter=converters.bool_converter(true=true, false=false), **kwargs) - self._check_box = wx.CheckBox(self._parent, style=wx.CHK_2STATE, label=label) - self._check_box.Bind(wx.EVT_CHECKBOX, self._handle) - self._add_widget(self._check_box) - - def _handle(self, event): self[INT_KEY] = self._check_box.IsChecked() - def _update(self, checked): self._check_box.SetValue(checked) - -######################################################################## -# Base Class Chooser Form -######################################################################## -class _chooser_base(_form_base): - def __init__(self, choices=[], labels=None, **kwargs): - _form_base.__init__(self, converter=converters.chooser_converter(choices), **kwargs) - self._choices = choices - self._labels = map(str, labels or choices) - -######################################################################## -# Drop Down Chooser Form -######################################################################## -class drop_down(_chooser_base): - def __init__(self, label='', **kwargs): - _chooser_base.__init__(self, **kwargs) - self._drop_down = wx.Choice(self._parent, choices=self._labels) - self._drop_down.Bind(wx.EVT_CHOICE, self._handle) - self._add_widget(self._drop_down, label) - - def _handle(self, event): self[INT_KEY] = self._drop_down.GetSelection() - def _update(self, i): self._drop_down.SetSelection(i) - -######################################################################## -# Button Chooser Form -# Circularly move through the choices with each click. -# Can be a single-click button with one choice. -# Can be a 2-state button with two choices. -######################################################################## -class button(_chooser_base): - def __init__(self, label='', style=0, width=-1, **kwargs): - _chooser_base.__init__(self, **kwargs) - self._button = wx.Button(self._parent, size=wx.Size(width, -1), style=style) - self._button.Bind(wx.EVT_BUTTON, self._handle) - self._add_widget(self._button, label) - - def _handle(self, event): self[INT_KEY] = (self[INT_KEY] + 1)%len(self._choices) #circularly increment index - def _update(self, i): self._button.SetLabel(self._labels[i]); self.Layout() - -class toggle_button(button): - """ - Create a dual state button. - This button will alternate between True and False when clicked. - """ - def __init__(self, true_label='On (click to stop)', false_label='Off (click to start)', **kwargs): - button.__init__(self, choices=[True, False], labels=[true_label, false_label], **kwargs) - -class single_button(toggle_button): - """ - Create a single state button. - This button will callback() when clicked. - For use when state holding is not important. - """ - def __init__(self, label='click for callback', **kwargs): - toggle_button.__init__(self, true_label=label, false_label=label, value=True, **kwargs) - -######################################################################## -# Radio Buttons Chooser Form -######################################################################## -class radio_buttons(_chooser_base): - """ - Create a radio button form. - @param parent the parent widget - @param sizer add this widget to sizer if provided (optional) - @param proportion the proportion when added to the sizer (default=0) - @param ps the pubsub object (optional) - @param key the pubsub key (optional) - @param value the default value (optional) - @param choices list of possible values - @param labels list of labels for each choice (default=choices) - @param major_dimension the number of rows/cols (default=auto) - @param label title label for this widget (optional) - @param style useful style args: wx.RA_HORIZONTAL, wx.RA_VERTICAL, wx.NO_BORDER (default=wx.RA_HORIZONTAL) - """ - def __init__(self, style=wx.RA_HORIZONTAL, label='', major_dimension=0, **kwargs): - _chooser_base.__init__(self, **kwargs) - #create radio buttons - self._radio_buttons = wx.RadioBox(self._parent, choices=self._labels, style=style, label=label, majorDimension=major_dimension) - self._radio_buttons.Bind(wx.EVT_RADIOBOX, self._handle) - self._add_widget(self._radio_buttons) - - def _handle(self, event): self[INT_KEY] = self._radio_buttons.GetSelection() - def _update(self, i): self._radio_buttons.SetSelection(i) - -######################################################################## -# Notebook Chooser Form -# The notebook pages/tabs are for selecting between choices. -# A page must be added to the notebook for each choice. -######################################################################## -class notebook(_chooser_base): - def __init__(self, pages, notebook, **kwargs): - _chooser_base.__init__(self, **kwargs) - assert len(pages) == len(self._choices) - self._notebook = notebook - self._notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self._handle) - #add pages, setting the label on each tab - for i, page in enumerate(pages): - self._notebook.AddPage(page, self._labels[i]) - self._add_widget(self._notebook) - - def _handle(self, event): self[INT_KEY] = self._notebook.GetSelection() - def _update(self, i): self._notebook.SetSelection(i) - -# ---------------------------------------------------------------- -# Stand-alone test application -# ---------------------------------------------------------------- - -import wx -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, - choices=[2, 4, 8, 16], - labels=['two', 'four', 'eight', 'sixteen'], - value=4, - style=wx.RA_HORIZONTAL, - label='test radio long string', - callback=callback, - #major_dimension = 2, - ) - - radio_buttons( - sizer=vbox, - parent=panel, - choices=[2, 4, 8, 16], - labels=['two', 'four', 'eight', 'sixteen'], - value=4, - style=wx.RA_VERTICAL, - label='test radio long string', - callback=callback, - #major_dimension = 2, - ) - - radio_buttons( - sizer=vbox, - parent=panel, - choices=[2, 4, 8, 16], - labels=['two', 'four', 'eight', 'sixteen'], - value=4, - style=wx.RA_VERTICAL | wx.NO_BORDER, - callback=callback, - #major_dimension = 2, - ) - - button( - sizer=vbox, - parent=panel, - choices=[2, 4, 8, 16], - labels=['two', 'four', 'eight', 'sixteen'], - value=2, - label='button value', - callback=callback, - #width=100, - ) - - - drop_down( - sizer=vbox, - parent=panel, - choices=[2, 4, 8, 16], - value=2, - label='Choose One', - callback=callback, - ) - check_box( - sizer=vbox, - parent=panel, - value=False, - label='check me', - callback=callback, - ) - text_box( - sizer=vbox, - parent=panel, - value=3, - label='text box', - callback=callback, - width=200, - ) - - static_text( - sizer=vbox, - parent=panel, - value='bob', - label='static text', - width=-1, - bold=True, - ) - - slider( - sizer=vbox, - parent=panel, - value=12, - label='slider', - callback=callback, - ) - - log_slider( - sizer=vbox, - parent=panel, - value=12, - label='slider', - callback=callback, - ) - - slider( - sizer=vbox, - parent=panel, - value=12, - label='slider', - callback=callback, - style=wx.SL_VERTICAL, - length=30, - ) - - toggle_button( - sizer=vbox, - parent=panel, - value=True, - label='toggle it', - callback=callback, - ) - - single_button( - sizer=vbox, - parent=panel, - label='sig test', - callback=callback, - ) - -if __name__ == "__main__": - try: - - # Create the GUI application - app = gui.app( - gui=app_gui, # User interface class - title="Test Forms", # Top window title - ) - - # And run it - app.MainLoop() - - except RuntimeError, e: - print e - sys.exit(1) |