1 # Copyright 2008 Free Software Foundation, Inc.
3 # This file is part of GNU Radio
5 # GNU Radio is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3, or (at your option)
10 # GNU Radio is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with GNU Radio; see the file COPYING. If not, write to
17 # the Free Software Foundation, Inc., 51 Franklin Street,
18 # Boston, MA 02110-1301, USA.
23 from gnuradio import eng_notation
25 class LabelText(wx.StaticText):
26 """Label text class for uniform labels among all controls."""
28 def __init__(self, window, label):
29 wx.StaticText.__init__(self, window, label=str(label))
31 font.SetWeight(wx.FONTWEIGHT_BOLD)
34 class _control_base(wx.BoxSizer):
35 """Control base class"""
37 def __init__(self, window, callback):
39 self.callback = callback
40 wx.BoxSizer.__init__(self, wx.VERTICAL)
42 def get_window(self): return self.window
44 def call(self): return self.callback(self.get_value())
46 def get_value(self): raise NotImplementedError
48 def set_value(self): raise NotImplementedError
50 class _chooser_control_base(_control_base):
51 """House a drop down or radio buttons for variable control."""
53 def __init__(self, window, callback, label='Label', index=0, choices=[0], labels=[]):
56 Create the slider, text box, and label.
57 @param window the wx parent window
58 @param callback call the callback on changes
59 @param label the label title
60 @param index the default choice index
61 @param choices a list of choices
62 @param labels the choice labels or empty list
65 _control_base.__init__(self, window, callback)
66 label_text = LabelText(self.get_window(), label)
67 self.Add(label_text, 0, wx.ALIGN_CENTER)
69 self.choices = choices
70 self.labels = map(str, labels or choices)
73 def _handle_changed(self, event=None):
75 A change is detected. Call the callback.
78 except Exception, e: print >> sys.stderr, 'Error in exec callback from handle changed.\n', e
83 @return one of the possible choices
86 return self.choices[self.index]
88 ##############################################################################################
90 ##############################################################################################
91 class button_control(_chooser_control_base):
92 """House a button for variable control."""
95 self.button = wx.Button(self.get_window(), label=self.labels[self.index])
96 self.button.Bind(wx.EVT_BUTTON, self._handle_changed)
97 self.Add(self.button, 0, wx.ALIGN_CENTER)
100 self.index = (self.index + 1)%len(self.choices) #circularly increment index
101 self.button.SetLabel(self.labels[self.index])
103 ##############################################################################################
105 ##############################################################################################
106 class drop_down_control(_chooser_control_base):
107 """House a drop down for variable control."""
110 self.drop_down = wx.Choice(self.get_window(), choices=self.labels)
111 self.Add(self.drop_down, 0, wx.ALIGN_CENTER)
112 self.drop_down.Bind(wx.EVT_CHOICE, self._handle_changed)
113 self.drop_down.SetSelection(self.index)
116 self.index = self.drop_down.GetSelection()
118 ##############################################################################################
119 # Radio Buttons Control
120 ##############################################################################################
121 class _radio_buttons_control_base(_chooser_control_base):
122 """House radio buttons for variable control."""
125 #create box for radio buttons
126 radio_box = wx.BoxSizer(self.radio_box_orientation)
127 panel = wx.Panel(self.get_window())
128 panel.SetSizer(radio_box)
129 self.Add(panel, 0, wx.ALIGN_CENTER)
130 #create radio buttons
131 self.radio_buttons = list()
132 for label in self.labels:
133 radio_button = wx.RadioButton(panel, label=label)
134 radio_button.SetValue(False)
135 self.radio_buttons.append(radio_button)
136 radio_box.Add(radio_button, 0, self.radio_button_align)
137 radio_button.Bind(wx.EVT_RADIOBUTTON, self._handle_changed)
138 #set one radio button active
139 self.radio_buttons[self.index].SetValue(True)
142 selected_radio_button = filter(lambda rb: rb.GetValue(), self.radio_buttons)[0]
143 self.index = self.radio_buttons.index(selected_radio_button)
145 class radio_buttons_horizontal_control(_radio_buttons_control_base):
146 radio_box_orientation = wx.HORIZONTAL
147 radio_button_align = wx.ALIGN_CENTER
148 class radio_buttons_vertical_control(_radio_buttons_control_base):
149 radio_box_orientation = wx.VERTICAL
150 radio_button_align = wx.ALIGN_LEFT
152 ##############################################################################################
154 ##############################################################################################
155 class _slider_control_base(_control_base):
156 """House a Slider and a Text Box for variable control."""
158 def __init__(self, window, callback, label='Label', value=50, min=0, max=100, num_steps=100, slider_length=200):
161 Create the slider, text box, and label.
162 @param window the wx parent window
163 @param callback call the callback on changes
164 @param label the label title
165 @param value the default value
168 @param num_steps the number of steps
169 @param slider_length the length of the slider bar in pixels
172 _control_base.__init__(self, window, callback)
173 self.min = float(min)
174 self.max = float(max)
175 self.num_steps = int(num_steps)
176 self.slider_length = slider_length
178 label_text_sizer = wx.BoxSizer(self.label_text_orientation) #label and text box container
179 label_text = LabelText(self.get_window(), '%s: '%str(label))
180 self.text_box = text_box = wx.TextCtrl(self.get_window(), style=wx.TE_PROCESS_ENTER)
181 text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this special enter hotkey event
182 for obj in (label_text, text_box): #fill the container with label and text entry box
183 label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER)
184 self.Add(label_text_sizer, 0, wx.ALIGN_CENTER)
186 self.slider = slider = wx.Slider(self.get_window(), size=wx.Size(*self.get_slider_size()), style=self.slider_style)
187 try: slider.SetRange(0, num_steps)
189 print >> sys.stderr, 'Error in set slider range: "%s".'%e
191 slider.Bind(wx.EVT_SCROLL, self._handle_scroll) #bind the scrolling event
192 self.Add(slider, 0, wx.ALIGN_CENTER)
193 #init slider and text box
194 self.set_value(value)
198 Get the current set value.
199 @return the value (float)
203 def set_value(self, value):
205 Set the current set value.
206 @param value the value (float)
209 self._update_slider()
210 self._update_text_box()
212 def _update_slider(self):
214 Translate the real numerical value into a slider value.
216 slider_value = (float(self.get_value()) - self.min)*self.num_steps/(self.max - self.min)
217 self.slider.SetValue(slider_value)
219 def _update_text_box(self):
221 Update the text box value.
222 Convert the value into engineering notation.
224 self.text_box.SetValue(eng_notation.num_to_str(self.get_value()))
226 def _handle_scroll(self, event=None):
228 A scroll event is detected. Read the slider, call the callback.
230 slider_value = self.slider.GetValue()
231 new_value = slider_value*(self.max - self.min)/self.num_steps + self.min
232 self.set_value(new_value)
234 except Exception, e: print >> sys.stderr, 'Error in exec callback from handle scroll.\n', e
236 def _handle_enter(self, event=None):
238 An enter key was pressed. Read the text box, call the callback.
240 new_value = eng_notation.str_to_num(self.text_box.GetValue())
241 self.set_value(new_value)
243 except Exception, e: print >> sys.stderr, 'Error in exec callback from handle enter.\n', e
245 class slider_horizontal_control(_slider_control_base):
246 label_text_orientation = wx.HORIZONTAL
247 slider_style = wx.SL_HORIZONTAL
248 def get_slider_size(self): return self.slider_length, -1
249 class slider_vertical_control(_slider_control_base):
250 label_text_orientation = wx.VERTICAL
251 slider_style = wx.SL_VERTICAL
252 def get_slider_size(self): return -1, self.slider_length
254 ##############################################################################################
256 ##############################################################################################
257 class text_box_control(_control_base):
258 """House a Text Box for variable control."""
260 def __init__(self, window, callback, label='Label', value=50):
263 Create the text box, and label.
264 @param window the wx parent window
265 @param callback call the callback on changes
266 @param label the label title
267 @param value the default value
270 _control_base.__init__(self, window, callback)
272 label_text_sizer = wx.BoxSizer(wx.HORIZONTAL) #label and text box container
273 label_text = LabelText(self.get_window(), '%s: '%str(label))
274 self.text_box = text_box = wx.TextCtrl(self.get_window(), value=str(value), style=wx.TE_PROCESS_ENTER)
275 text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this special enter hotkey event
276 for obj in (label_text, text_box): #fill the container with label and text entry box
277 label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER)
278 self.Add(label_text_sizer, 0, wx.ALIGN_CENTER)
280 self._string_mode = isinstance(value, str)
284 Get the current set value.
285 @return the value (float)
289 def _handle_enter(self, event=None):
291 An enter key was pressed. Read the text box, call the callback.
292 If the text cannot be evaluated, do not try callback.
293 Do not evaluate the text box value in string mode.
295 if self._string_mode:
296 self._value = str(self.text_box.GetValue())
298 try: self._value = eval(self.text_box.GetValue())
300 print >> sys.stderr, 'Error in evaluate value from handle enter.\n', e
303 except Exception, e: print >> sys.stderr, 'Error in exec callback from handle enter.\n', e