diff options
author | jcorgan | 2008-08-23 02:26:15 +0000 |
---|---|---|
committer | jcorgan | 2008-08-23 02:26:15 +0000 |
commit | d52c462e5fd3eae7d00505a64a013e811d43234c (patch) | |
tree | 6b2a9e77c095ecc273e8b2b33a4bab37cfdf2fcd /grc/src/grc_gnuradio/wxgui | |
parent | 5c02ea03e1226ed706abeede426f0e1727f1ea25 (diff) | |
download | gnuradio-d52c462e5fd3eae7d00505a64a013e811d43234c.tar.gz gnuradio-d52c462e5fd3eae7d00505a64a013e811d43234c.tar.bz2 gnuradio-d52c462e5fd3eae7d00505a64a013e811d43234c.zip |
Merged changeset r9285:9377 from jblum/grc into trunk, with distcheck fixes
and local modifications.
Integrates previously separate GNU Radio Companion into top-level component
'grc'. (Josh Blum)
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9378 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'grc/src/grc_gnuradio/wxgui')
-rw-r--r-- | grc/src/grc_gnuradio/wxgui/Makefile.am | 29 | ||||
-rw-r--r-- | grc/src/grc_gnuradio/wxgui/__init__.py | 30 | ||||
-rw-r--r-- | grc/src/grc_gnuradio/wxgui/callback_controls.py | 281 | ||||
-rw-r--r-- | grc/src/grc_gnuradio/wxgui/top_block_gui.py | 99 |
4 files changed, 439 insertions, 0 deletions
diff --git a/grc/src/grc_gnuradio/wxgui/Makefile.am b/grc/src/grc_gnuradio/wxgui/Makefile.am new file mode 100644 index 000000000..2e7072eae --- /dev/null +++ b/grc/src/grc_gnuradio/wxgui/Makefile.am @@ -0,0 +1,29 @@ +# +# 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. +# + +include $(top_srcdir)/Makefile.common + +ourpythondir = $(pythondir)/grc_gnuradio/wxgui + +ourpython_PYTHON = \ + __init__.py \ + callback_controls.py \ + top_block_gui.py diff --git a/grc/src/grc_gnuradio/wxgui/__init__.py b/grc/src/grc_gnuradio/wxgui/__init__.py new file mode 100644 index 000000000..c0fdca52c --- /dev/null +++ b/grc/src/grc_gnuradio/wxgui/__init__.py @@ -0,0 +1,30 @@ +# 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. +# + +from callback_controls import \ + button_control, \ + drop_down_control, \ + radio_buttons_horizontal_control, \ + radio_buttons_vertical_control, \ + slider_horizontal_control, \ + slider_vertical_control, \ + text_box_control +from top_block_gui import top_block_gui + diff --git a/grc/src/grc_gnuradio/wxgui/callback_controls.py b/grc/src/grc_gnuradio/wxgui/callback_controls.py new file mode 100644 index 000000000..c1ba784eb --- /dev/null +++ b/grc/src/grc_gnuradio/wxgui/callback_controls.py @@ -0,0 +1,281 @@ +# 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. +# + +import wx +import sys + +class LabelText(wx.StaticText): + """Label text class for uniform labels among all controls.""" + + def __init__(self, window, label): + wx.StaticText.__init__(self, window, -1, str(label)) + font = self.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + self.SetFont(font) + +class _control_base(wx.BoxSizer): + """Control base class""" + + def __init__(self, window, callback): + self.window = window + self.callback = callback + wx.BoxSizer.__init__(self, wx.VERTICAL) + + def get_window(self): return self.window + + def call(self): return self.callback(self.get_value()) + + def get_value(self): raise NotImplementedError + +class _chooser_control_base(_control_base): + """House a drop down or radio buttons for variable control.""" + + def __init__(self, window, callback, label='Label', index=0, choices=[0], labels=[]): + """! + Chooser contructor. + Create the slider, text box, and label. + @param window the wx parent window + @param callback call the callback on changes + @param label the label title + @param index the default choice index + @param choices a list of choices + @param labels the choice labels or empty list + """ + #initialize + _control_base.__init__(self, window, callback) + label_text = LabelText(self.get_window(), label) + self.Add(label_text, 0, wx.ALIGN_CENTER) + self.index = index + self.choices = choices + self.labels = map(str, labels or choices) + self._init() + + def _handle_changed(self, event=None): + """! + A change is detected. Call the callback. + """ + try: self.call() + except Exception, e: print >> sys.stderr, 'Error in exec callback from handle changed.\n', e + + def get_value(self): + """! + Update the chooser. + @return one of the possible choices + """ + self._update() + return self.choices[self.index] + +############################################################################################## +# Button Control +############################################################################################## +class button_control(_chooser_control_base): + """House a button for variable control.""" + + def _init(self): + self.button = wx.Button(self.get_window(), -1, self.labels[self.index]) + self.button.Bind(wx.EVT_BUTTON, self._handle_changed) + self.Add(self.button, 0, wx.ALIGN_CENTER) + + def _update(self): + self.index = (self.index + 1)%len(self.choices) #circularly increment index + self.button.SetLabel(self.labels[self.index]) + +############################################################################################## +# Drop Down Control +############################################################################################## +class drop_down_control(_chooser_control_base): + """House a drop down for variable control.""" + + def _init(self): + self.drop_down = wx.Choice(self.get_window(), -1, choices=self.labels) + self.Add(self.drop_down, 0, wx.ALIGN_CENTER) + self.drop_down.Bind(wx.EVT_CHOICE, self._handle_changed) + self.drop_down.SetSelection(self.index) + + def _update(self): + self.index = self.drop_down.GetSelection() + +############################################################################################## +# Radio Buttons Control +############################################################################################## +class _radio_buttons_control_base(_chooser_control_base): + """House radio buttons for variable control.""" + + def _init(self): + #create box for radio buttons + radio_box = wx.BoxSizer(self.radio_box_orientation) + panel = wx.Panel(self.get_window(), -1) + panel.SetSizer(radio_box) + self.Add(panel, 0, wx.ALIGN_CENTER) + #create radio buttons + self.radio_buttons = list() + for label in self.labels: + radio_button = wx.RadioButton(panel, -1, label) + radio_button.SetValue(False) + self.radio_buttons.append(radio_button) + radio_box.Add(radio_button, 0, self.radio_button_align) + radio_button.Bind(wx.EVT_RADIOBUTTON, self._handle_changed) + #set one radio button active + self.radio_buttons[self.index].SetValue(True) + + def _update(self): + selected_radio_button = filter(lambda rb: rb.GetValue(), self.radio_buttons)[0] + self.index = self.radio_buttons.index(selected_radio_button) + +class radio_buttons_horizontal_control(_radio_buttons_control_base): + radio_box_orientation = wx.HORIZONTAL + radio_button_align = wx.ALIGN_CENTER +class radio_buttons_vertical_control(_radio_buttons_control_base): + radio_box_orientation = wx.VERTICAL + radio_button_align = wx.ALIGN_LEFT + +############################################################################################## +# Slider Control +############################################################################################## +class _slider_control_base(_control_base): + """House a Slider and a Text Box for variable control.""" + + def __init__(self, window, callback, label='Label', value=50, min=0, max=100, num_steps=100): + """! + Slider contructor. + Create the slider, text box, and label. + @param window the wx parent window + @param callback call the callback on changes + @param label the label title + @param value the default value + @param min the min + @param max the max + @param num_steps the number of steps + """ + #initialize + _control_base.__init__(self, window, callback) + self.min = float(min) + self.max = float(max) + self.num_steps = int(num_steps) + #create gui elements + label_text_sizer = wx.BoxSizer(self.label_text_orientation) #label and text box container + label_text = LabelText(self.get_window(), '%s: '%str(label)) + self.text_box = text_box = wx.TextCtrl(self.get_window(), -1, str(value), style=wx.TE_PROCESS_ENTER) + text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this special enter hotkey event + for obj in (label_text, text_box): #fill the container with label and text entry box + label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL) + self.Add(label_text_sizer, 0, wx.ALIGN_CENTER) + #make the slider + self.slider = slider = wx.Slider(self.get_window(), -1, size=wx.Size(*self.slider_size), style=self.slider_style) + try: slider.SetRange(0, num_steps) + except Exception, e: + print >> sys.stderr, 'Error in set slider range: "%s".'%e + sys.exit(-1) + slider.Bind(wx.EVT_SCROLL, self._handle_scroll) #bind the scrolling event + self.Add(slider, 0, wx.ALIGN_CENTER) + #init slider and text box + self._value = value + self._set_slider_value(self._value) #sets the slider's value + self.text_box.SetValue(str(self._value)) + + def get_value(self): + """! + Get the current set value. + @return the value (float) + """ + return self._value + + def _set_slider_value(self, real_value): + """! + Translate the real numerical value into a slider value and, + write the value to the slider. + @param real_value the numeric value the slider should represent + """ + slider_value = (float(real_value) - self.min)*self.num_steps/(self.max - self.min) + self.slider.SetValue(slider_value) + + def _handle_scroll(self, event=None): + """! + A scroll event is detected. Read the slider, call the callback. + """ + slider_value = self.slider.GetValue() + new_value = slider_value*(self.max - self.min)/self.num_steps + self.min + self.text_box.SetValue(str(new_value)) + self._value = new_value + try: self.call() + except Exception, e: print >> sys.stderr, 'Error in exec callback from handle scroll.\n', e + + def _handle_enter(self, event=None): + """! + An enter key was pressed. Read the text box, call the callback. + """ + new_value = float(self.text_box.GetValue()) + self._set_slider_value(new_value) + self._value = new_value + try: self.call() + except Exception, e: print >> sys.stderr, 'Error in exec callback from handle enter.\n', e + +class slider_horizontal_control(_slider_control_base): + label_text_orientation = wx.HORIZONTAL + slider_style = wx.SL_HORIZONTAL + slider_size = 200, 20 +class slider_vertical_control(_slider_control_base): + label_text_orientation = wx.VERTICAL + slider_style = wx.SL_VERTICAL + slider_size = 20, 200 + +############################################################################################## +# Text Box Control +############################################################################################## +class text_box_control(_control_base): + """House a Text Box for variable control.""" + + def __init__(self, window, callback, label='Label', value=50): + """! + Text box contructor. + Create the text box, and label. + @param window the wx parent window + @param callback call the callback on changes + @param label the label title + @param value the default value + """ + #initialize + _control_base.__init__(self, window, callback) + #create gui elements + label_text_sizer = wx.BoxSizer(wx.HORIZONTAL) #label and text box container + label_text = LabelText(self.get_window(), '%s: '%str(label)) + self.text_box = text_box = wx.TextCtrl(self.get_window(), -1, str(value), style=wx.TE_PROCESS_ENTER) + text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this special enter hotkey event + for obj in (label_text, text_box): #fill the container with label and text entry box + label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL) + self.Add(label_text_sizer, 0, wx.ALIGN_CENTER) + self.text_box.SetValue(str(value)) + + def get_value(self): + """! + Get the current set value. + @return the value (float) + """ + return self._value + + def _handle_enter(self, event=None): + """! + An enter key was pressed. Read the text box, call the callback. + If the text cannot be evaluated, do not try callback. + """ + try: self._value = eval(self.text_box.GetValue()) + except: return + try: self.call() + except Exception, e: print >> sys.stderr, 'Error in exec callback from handle enter.\n', e diff --git a/grc/src/grc_gnuradio/wxgui/top_block_gui.py b/grc/src/grc_gnuradio/wxgui/top_block_gui.py new file mode 100644 index 000000000..d56d20056 --- /dev/null +++ b/grc/src/grc_gnuradio/wxgui/top_block_gui.py @@ -0,0 +1,99 @@ +# 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. +# + +import wx +import sys, os +from gnuradio import gr + +default_gui_size = (200, 100) + +class top_block_gui(gr.top_block): + """gr top block with wx gui app and grid sizer.""" + + def __init__(self, title='', size=default_gui_size, icon=None): + """! + Initialize the gr top block. + Create the wx gui elements. + @param title the main window title + @param size the main window size tuple in pixels + @param icon the file path to an icon or None + """ + #initialize + gr.top_block.__init__(self) + self._size = size + #set the icon + if icon and os.path.isfile(icon): self._icon = icon + else: self._icon = None + #create gui elements + self._wx_app = wx.App() + self._wx_frame = wx.Frame(None , -1, title) + self._wx_grid = wx.GridBagSizer(5, 5) + self._wx_vbox = wx.BoxSizer(wx.VERTICAL) + + def GetWin(self): + """! + Get the window for wx elements to fit within. + @return the wx frame + """ + return self._wx_frame + + def Add(self, win): + """! + Add a window to the wx vbox. + @param win the wx window + """ + self._wx_vbox.Add(win, 0, wx.EXPAND) + + def GridAdd(self, win, row, col, row_span=1, col_span=1): + """! + Add a window to the wx grid at the given position. + @param win the wx window + @param row the row specification (integer >= 0) + @param col the column specification (integer >= 0) + @param row_span the row span specification (integer >= 1) + @param col_span the column span specification (integer >= 1) + """ + self._wx_grid.Add(win, wx.GBPosition(row, col), wx.GBSpan(row_span, col_span), wx.EXPAND) + + def Run(self): + """! + Setup the wx gui elements. + Start the gr top block. + Block with the wx main loop. + """ + #set wx app icon + if self._icon: self._wx_frame.SetIcon(wx.Icon(self._icon, wx.BITMAP_TYPE_ANY)) + #set minimal window size + self._wx_frame.SetSizeHints(*self._size) + #create callback for quit + def _quit(event): + gr.top_block.stop(self) + self._wx_frame.Destroy() + #setup app + self._wx_vbox.Add(self._wx_grid, 0, wx.EXPAND) + self._wx_frame.Bind(wx.EVT_CLOSE, _quit) + self._wx_frame.SetSizerAndFit(self._wx_vbox) + self._wx_frame.Show() + self._wx_app.SetTopWindow(self._wx_frame) + #start flow graph + gr.top_block.start(self) + #blocking main loop + self._wx_app.MainLoop() + |