summaryrefslogtreecommitdiff
path: root/grc/src/grc_gnuradio/wxgui
diff options
context:
space:
mode:
authorjcorgan2008-08-23 02:26:15 +0000
committerjcorgan2008-08-23 02:26:15 +0000
commitd52c462e5fd3eae7d00505a64a013e811d43234c (patch)
tree6b2a9e77c095ecc273e8b2b33a4bab37cfdf2fcd /grc/src/grc_gnuradio/wxgui
parent5c02ea03e1226ed706abeede426f0e1727f1ea25 (diff)
downloadgnuradio-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.am29
-rw-r--r--grc/src/grc_gnuradio/wxgui/__init__.py30
-rw-r--r--grc/src/grc_gnuradio/wxgui/callback_controls.py281
-rw-r--r--grc/src/grc_gnuradio/wxgui/top_block_gui.py99
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()
+