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.
24 class LabelText(wx.StaticText):
25 """Label text class for uniform labels among all controls."""
27 def __init__(self, window, label):
28 wx.StaticText.__init__(self, window, -1, str(label))
30 font.SetWeight(wx.FONTWEIGHT_BOLD)
33 class _control_base(wx.BoxSizer):
34 """Control base class"""
36 def __init__(self, window, callback):
38 self.callback = callback
39 wx.BoxSizer.__init__(self, wx.VERTICAL)
41 def get_window(self): return self.window
43 def call(self): return self.callback(self.get_value())
45 def get_value(self): raise NotImplementedError
47 class _chooser_control_base(_control_base):
48 """House a drop down or radio buttons for variable control."""
50 def __init__(self, window, callback, label='Label', index=0, choices=[0], labels=[]):
53 Create the slider, text box, and label.
54 @param window the wx parent window
55 @param callback call the callback on changes
56 @param label the label title
57 @param index the default choice index
58 @param choices a list of choices
59 @param labels the choice labels or empty list
62 _control_base.__init__(self, window, callback)
63 label_text = LabelText(self.get_window(), label)
64 self.Add(label_text, 0, wx.ALIGN_CENTER)
66 self.choices = choices
67 self.labels = map(str, labels or choices)
70 def _handle_changed(self, event=None):
72 A change is detected. Call the callback.
75 except Exception, e: print >> sys.stderr, 'Error in exec callback from handle changed.\n', e
80 @return one of the possible choices
83 return self.choices[self.index]
85 ##############################################################################################
87 ##############################################################################################
88 class button_control(_chooser_control_base):
89 """House a button for variable control."""
92 self.button = wx.Button(self.get_window(), -1, self.labels[self.index])
93 self.button.Bind(wx.EVT_BUTTON, self._handle_changed)
94 self.Add(self.button, 0, wx.ALIGN_CENTER)
97 self.index = (self.index + 1)%len(self.choices) #circularly increment index
98 self.button.SetLabel(self.labels[self.index])
100 ##############################################################################################
102 ##############################################################################################
103 class drop_down_control(_chooser_control_base):
104 """House a drop down for variable control."""
107 self.drop_down = wx.Choice(self.get_window(), -1, choices=self.labels)
108 self.Add(self.drop_down, 0, wx.ALIGN_CENTER)
109 self.drop_down.Bind(wx.EVT_CHOICE, self._handle_changed)
110 self.drop_down.SetSelection(self.index)
113 self.index = self.drop_down.GetSelection()
115 ##############################################################################################
116 # Radio Buttons Control
117 ##############################################################################################
118 class _radio_buttons_control_base(_chooser_control_base):
119 """House radio buttons for variable control."""
122 #create box for radio buttons
123 radio_box = wx.BoxSizer(self.radio_box_orientation)
124 panel = wx.Panel(self.get_window(), -1)
125 panel.SetSizer(radio_box)
126 self.Add(panel, 0, wx.ALIGN_CENTER)
127 #create radio buttons
128 self.radio_buttons = list()
129 for label in self.labels:
130 radio_button = wx.RadioButton(panel, -1, label)
131 radio_button.SetValue(False)
132 self.radio_buttons.append(radio_button)
133 radio_box.Add(radio_button, 0, self.radio_button_align)
134 radio_button.Bind(wx.EVT_RADIOBUTTON, self._handle_changed)
135 #set one radio button active
136 self.radio_buttons[self.index].SetValue(True)
139 selected_radio_button = filter(lambda rb: rb.GetValue(), self.radio_buttons)[0]
140 self.index = self.radio_buttons.index(selected_radio_button)
142 class radio_buttons_horizontal_control(_radio_buttons_control_base):
143 radio_box_orientation = wx.HORIZONTAL
144 radio_button_align = wx.ALIGN_CENTER
145 class radio_buttons_vertical_control(_radio_buttons_control_base):
146 radio_box_orientation = wx.VERTICAL
147 radio_button_align = wx.ALIGN_LEFT
149 ##############################################################################################
151 ##############################################################################################
152 class _slider_control_base(_control_base):
153 """House a Slider and a Text Box for variable control."""
155 def __init__(self, window, callback, label='Label', value=50, min=0, max=100, num_steps=100):
158 Create the slider, text box, and label.
159 @param window the wx parent window
160 @param callback call the callback on changes
161 @param label the label title
162 @param value the default value
165 @param num_steps the number of steps
168 _control_base.__init__(self, window, callback)
169 self.min = float(min)
170 self.max = float(max)
171 self.num_steps = int(num_steps)
173 label_text_sizer = wx.BoxSizer(self.label_text_orientation) #label and text box container
174 label_text = LabelText(self.get_window(), '%s: '%str(label))
175 self.text_box = text_box = wx.TextCtrl(self.get_window(), -1, str(value), style=wx.TE_PROCESS_ENTER)
176 text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this special enter hotkey event
177 for obj in (label_text, text_box): #fill the container with label and text entry box
178 label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
179 self.Add(label_text_sizer, 0, wx.ALIGN_CENTER)
181 self.slider = slider = wx.Slider(self.get_window(), -1, size=wx.Size(*self.slider_size), style=self.slider_style)
182 try: slider.SetRange(0, num_steps)
184 print >> sys.stderr, 'Error in set slider range: "%s".'%e
186 slider.Bind(wx.EVT_SCROLL, self._handle_scroll) #bind the scrolling event
187 self.Add(slider, 0, wx.ALIGN_CENTER)
188 #init slider and text box
190 self._set_slider_value(self._value) #sets the slider's value
191 self.text_box.SetValue(str(self._value))
195 Get the current set value.
196 @return the value (float)
200 def _set_slider_value(self, real_value):
202 Translate the real numerical value into a slider value and,
203 write the value to the slider.
204 @param real_value the numeric value the slider should represent
206 slider_value = (float(real_value) - self.min)*self.num_steps/(self.max - self.min)
207 self.slider.SetValue(slider_value)
209 def _handle_scroll(self, event=None):
211 A scroll event is detected. Read the slider, call the callback.
213 slider_value = self.slider.GetValue()
214 new_value = slider_value*(self.max - self.min)/self.num_steps + self.min
215 self.text_box.SetValue(str(new_value))
216 self._value = new_value
218 except Exception, e: print >> sys.stderr, 'Error in exec callback from handle scroll.\n', e
220 def _handle_enter(self, event=None):
222 An enter key was pressed. Read the text box, call the callback.
224 new_value = float(self.text_box.GetValue())
225 self._set_slider_value(new_value)
226 self._value = new_value
228 except Exception, e: print >> sys.stderr, 'Error in exec callback from handle enter.\n', e
230 class slider_horizontal_control(_slider_control_base):
231 label_text_orientation = wx.HORIZONTAL
232 slider_style = wx.SL_HORIZONTAL
233 slider_size = 200, 20
234 class slider_vertical_control(_slider_control_base):
235 label_text_orientation = wx.VERTICAL
236 slider_style = wx.SL_VERTICAL
237 slider_size = 20, 200
239 ##############################################################################################
241 ##############################################################################################
242 class text_box_control(_control_base):
243 """House a Text Box for variable control."""
245 def __init__(self, window, callback, label='Label', value=50):
248 Create the text box, and label.
249 @param window the wx parent window
250 @param callback call the callback on changes
251 @param label the label title
252 @param value the default value
255 _control_base.__init__(self, window, callback)
257 label_text_sizer = wx.BoxSizer(wx.HORIZONTAL) #label and text box container
258 label_text = LabelText(self.get_window(), '%s: '%str(label))
259 self.text_box = text_box = wx.TextCtrl(self.get_window(), -1, str(value), style=wx.TE_PROCESS_ENTER)
260 text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this special enter hotkey event
261 for obj in (label_text, text_box): #fill the container with label and text entry box
262 label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
263 self.Add(label_text_sizer, 0, wx.ALIGN_CENTER)
264 self.text_box.SetValue(str(value))
268 Get the current set value.
269 @return the value (float)
273 def _handle_enter(self, event=None):
275 An enter key was pressed. Read the text box, call the callback.
276 If the text cannot be evaluated, do not try callback.
278 try: self._value = eval(self.text_box.GetValue())
281 except Exception, e: print >> sys.stderr, 'Error in exec callback from handle enter.\n', e