diff options
Diffstat (limited to 'grc/src/grc_gnuradio/wxgui/callback_controls.py')
-rw-r--r-- | grc/src/grc_gnuradio/wxgui/callback_controls.py | 281 |
1 files changed, 281 insertions, 0 deletions
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 |