root / gr-wxgui / src / python / forms / forms.py @ 51af4269
History | View | Annotate | Download (25.1 kB)
| 1 | #
|
|---|---|
| 2 | # Copyright 2009 Free Software Foundation, Inc.
|
| 3 | #
|
| 4 | # This file is part of GNU Radio
|
| 5 | #
|
| 6 | # GNU Radio is free software; you can redistribute it and/or modify
|
| 7 | # it under the terms of the GNU General Public License as published by
|
| 8 | # the Free Software Foundation; either version 3, or (at your option)
|
| 9 | # any later version.
|
| 10 | #
|
| 11 | # GNU Radio is distributed in the hope that it will be useful,
|
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 | # GNU General Public License for more details.
|
| 15 | #
|
| 16 | # You should have received a copy of the GNU General Public License
|
| 17 | # along with GNU Radio; see the file COPYING. If not, write to
|
| 18 | # the Free Software Foundation, Inc., 51 Franklin Street,
|
| 19 | # Boston, MA 02110-1301, USA.
|
| 20 | #
|
| 21 | |
| 22 | """
|
| 23 | The forms module contains general purpose wx-gui forms for gnuradio apps.
|
| 24 | |
| 25 | The forms follow a layered model:
|
| 26 | * internal layer
|
| 27 | * deals with the wxgui objects directly
|
| 28 | * implemented in event handler and update methods
|
| 29 | * translation layer
|
| 30 | * translates the between the external and internal layers
|
| 31 | * handles parsing errors between layers
|
| 32 | * external layer
|
| 33 | * provided external access to the user
|
| 34 | * set_value, get_value, and optional callback
|
| 35 | * set and get through optional pubsub and key
|
| 36 | |
| 37 | Known problems:
|
| 38 | * An empty label in the radio box still consumes space.
|
| 39 | * The static text cannot resize the parent at runtime.
|
| 40 | """
|
| 41 | |
| 42 | EXT_KEY = 'external'
|
| 43 | INT_KEY = 'internal'
|
| 44 | |
| 45 | import wx |
| 46 | import sys |
| 47 | from gnuradio.gr.pubsub import pubsub |
| 48 | import converters |
| 49 | |
| 50 | EVT_DATA = wx.PyEventBinder(wx.NewEventType()) |
| 51 | class DataEvent(wx.PyEvent): |
| 52 | def __init__(self, data): |
| 53 | wx.PyEvent.__init__(self, wx.NewId(), EVT_DATA.typeId)
|
| 54 | self.data = data
|
| 55 | |
| 56 | def make_bold(widget): |
| 57 | font = widget.GetFont() |
| 58 | font.SetWeight(wx.FONTWEIGHT_BOLD) |
| 59 | widget.SetFont(font) |
| 60 | |
| 61 | ########################################################################
|
| 62 | # Base Class Form
|
| 63 | ########################################################################
|
| 64 | class _form_base(pubsub, wx.BoxSizer): |
| 65 | def __init__(self, parent=None, sizer=None, proportion=0, flag=wx.EXPAND, ps=None, key='', value=None, callback=None, converter=converters.identity_converter()): |
| 66 | pubsub.__init__(self)
|
| 67 | wx.BoxSizer.__init__(self, wx.HORIZONTAL)
|
| 68 | self._parent = parent
|
| 69 | self._key = key
|
| 70 | self._converter = converter
|
| 71 | self._callback = callback
|
| 72 | self._widgets = list() |
| 73 | #add to the sizer if provided
|
| 74 | if sizer: sizer.Add(self, proportion, flag) |
| 75 | #proxy the pubsub and key into this form
|
| 76 | if ps is not None: |
| 77 | assert key
|
| 78 | self.proxy(EXT_KEY, ps, key)
|
| 79 | #no pubsub passed, must set initial value
|
| 80 | else: self.set_value(value) |
| 81 | |
| 82 | def __str__(self): |
| 83 | return "Form: %s -> %s"%(self.__class__, self._key) |
| 84 | |
| 85 | def _add_widget(self, widget, label='', flag=0, label_prop=0, widget_prop=1): |
| 86 | """
|
| 87 | Add the main widget to this object sizer.
|
| 88 | If label is passed, add a label as well.
|
| 89 | Register the widget and the label in the widgets list (for enable/disable).
|
| 90 | Bind the update handler to the widget for data events.
|
| 91 | This ensures that the gui thread handles updating widgets.
|
| 92 | Setup the pusub triggers for external and internal.
|
| 93 | @param widget the main widget
|
| 94 | @param label the optional label
|
| 95 | @param flag additional flags for widget
|
| 96 | @param label_prop the proportion for the label
|
| 97 | @param widget_prop the proportion for the widget
|
| 98 | """ |
| 99 | #setup data event
|
| 100 | widget.Bind(EVT_DATA, lambda x: self._update(x.data)) |
| 101 | update = lambda x: wx.PostEvent(widget, DataEvent(x))
|
| 102 | #register widget
|
| 103 | self._widgets.append(widget)
|
| 104 | #create optional label
|
| 105 | if not label: self.Add(widget, widget_prop, wx.ALIGN_CENTER_VERTICAL | flag) |
| 106 | else:
|
| 107 | label_text = wx.StaticText(self._parent, label='%s: '%label) |
| 108 | self._widgets.append(label_text)
|
| 109 | self.Add(label_text, label_prop, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
|
| 110 | self.Add(widget, widget_prop, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | flag)
|
| 111 | #initialize without triggering pubsubs
|
| 112 | self._translate_external_to_internal(self[EXT_KEY]) |
| 113 | update(self[INT_KEY])
|
| 114 | #subscribe all the functions
|
| 115 | self.subscribe(INT_KEY, update)
|
| 116 | self.subscribe(INT_KEY, self._translate_internal_to_external) |
| 117 | self.subscribe(EXT_KEY, self._translate_external_to_internal) |
| 118 | if self._callback: self.subscribe(EXT_KEY, self._callback) |
| 119 | |
| 120 | def _translate_external_to_internal(self, external): |
| 121 | try:
|
| 122 | internal = self._converter.external_to_internal(external)
|
| 123 | #prevent infinite loop between internal and external pubsub keys by only setting if changed
|
| 124 | if self[INT_KEY] != internal: self[INT_KEY] = internal |
| 125 | except Exception, e: |
| 126 | self._err_msg(external, e)
|
| 127 | self[INT_KEY] = self[INT_KEY] #reset to last good setting |
| 128 | |
| 129 | def _translate_internal_to_external(self, internal): |
| 130 | try:
|
| 131 | external = self._converter.internal_to_external(internal)
|
| 132 | #prevent infinite loop between internal and external pubsub keys by only setting if changed
|
| 133 | if self[EXT_KEY] != external: self[EXT_KEY] = external |
| 134 | except Exception, e: |
| 135 | self._err_msg(internal, e)
|
| 136 | self[EXT_KEY] = self[EXT_KEY] #reset to last good setting |
| 137 | |
| 138 | def _err_msg(self, value, e): |
| 139 | print >> sys.stderr, self, 'Error translating value: "%s"\n\t%s\n\t%s'%(value, e, self._converter.help()) |
| 140 | |
| 141 | #override in subclasses to handle the wxgui object
|
| 142 | def _update(self, value): raise NotImplementedError |
| 143 | def _handle(self, event): raise NotImplementedError |
| 144 | |
| 145 | #provide a set/get interface for this form
|
| 146 | def get_value(self): return self[EXT_KEY] |
| 147 | def set_value(self, value): self[EXT_KEY] = value |
| 148 | |
| 149 | def Disable(self, disable=True): self.Enable(not disable) |
| 150 | def Enable(self, enable=True): |
| 151 | if enable:
|
| 152 | for widget in self._widgets: widget.Enable() |
| 153 | else:
|
| 154 | for widget in self._widgets: widget.Disable() |
| 155 | |
| 156 | ########################################################################
|
| 157 | # Base Class Chooser Form
|
| 158 | ########################################################################
|
| 159 | class _chooser_base(_form_base): |
| 160 | def __init__(self, choices=[], labels=None, **kwargs): |
| 161 | _form_base.__init__(self, converter=converters.chooser_converter(choices), **kwargs)
|
| 162 | self._choices = choices
|
| 163 | self._labels = map(str, labels or choices) |
| 164 | |
| 165 | ########################################################################
|
| 166 | # Base Class Slider Form
|
| 167 | ########################################################################
|
| 168 | class _slider_base(_form_base): |
| 169 | def __init__(self, label='', length=-1, converter=None, num_steps=100, style=wx.SL_HORIZONTAL, **kwargs): |
| 170 | _form_base.__init__(self, converter=converter, **kwargs)
|
| 171 | if style & wx.SL_HORIZONTAL: slider_size = wx.Size(length, -1) |
| 172 | elif style & wx.SL_VERTICAL: slider_size = wx.Size(-1, length) |
| 173 | else: raise NotImplementedError |
| 174 | self._slider = wx.Slider(self._parent, minValue=0, maxValue=num_steps, size=slider_size, style=style) |
| 175 | self._slider.Bind(wx.EVT_SCROLL, self._handle) |
| 176 | self._add_widget(self._slider, label, flag=wx.EXPAND) |
| 177 | |
| 178 | def _handle(self, event): self[INT_KEY] = self._slider.GetValue() |
| 179 | def _update(self, value): self._slider.SetValue(value) |
| 180 | |
| 181 | ########################################################################
|
| 182 | # Static Text Form
|
| 183 | ########################################################################
|
| 184 | class static_text(_form_base): |
| 185 | """
|
| 186 | A text box form.
|
| 187 | @param parent the parent widget
|
| 188 | @param sizer add this widget to sizer if provided (optional)
|
| 189 | @param proportion the proportion when added to the sizer (default=0)
|
| 190 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 191 | @param ps the pubsub object (optional)
|
| 192 | @param key the pubsub key (optional)
|
| 193 | @param value the default value (optional)
|
| 194 | @param label title label for this widget (optional)
|
| 195 | @param width the width of the form in px
|
| 196 | @param bold true to bold-ify the text (default=False)
|
| 197 | @param converter forms.str_converter(), int_converter(), float_converter()...
|
| 198 | """ |
| 199 | def __init__(self, label='', width=-1, bold=False, converter=converters.str_converter(), **kwargs): |
| 200 | _form_base.__init__(self, converter=converter, **kwargs)
|
| 201 | self._static_text = wx.StaticText(self._parent, size=wx.Size(width, -1)) |
| 202 | if bold: make_bold(self._static_text) |
| 203 | self._add_widget(self._static_text, label) |
| 204 | |
| 205 | def _update(self, label): self._static_text.SetLabel(label); self._parent.Layout() |
| 206 | |
| 207 | ########################################################################
|
| 208 | # Text Box Form
|
| 209 | ########################################################################
|
| 210 | class text_box(_form_base): |
| 211 | """
|
| 212 | A text box form.
|
| 213 | @param parent the parent widget
|
| 214 | @param sizer add this widget to sizer if provided (optional)
|
| 215 | @param proportion the proportion when added to the sizer (default=0)
|
| 216 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 217 | @param ps the pubsub object (optional)
|
| 218 | @param key the pubsub key (optional)
|
| 219 | @param value the default value (optional)
|
| 220 | @param label title label for this widget (optional)
|
| 221 | @param width the width of the form in px
|
| 222 | @param converter forms.str_converter(), int_converter(), float_converter()...
|
| 223 | """ |
| 224 | def __init__(self, label='', width=-1, converter=converters.eval_converter(), **kwargs): |
| 225 | _form_base.__init__(self, converter=converter, **kwargs)
|
| 226 | self._text_box = wx.TextCtrl(self._parent, size=wx.Size(width, -1), style=wx.TE_PROCESS_ENTER) |
| 227 | self._text_box.Bind(wx.EVT_TEXT_ENTER, self._handle) |
| 228 | self._add_widget(self._text_box, label) |
| 229 | |
| 230 | def _handle(self, event): self[INT_KEY] = self._text_box.GetValue() |
| 231 | def _update(self, value): self._text_box.SetValue(value) |
| 232 | |
| 233 | ########################################################################
|
| 234 | # Slider Form
|
| 235 | # Linear Slider
|
| 236 | # Logarithmic Slider
|
| 237 | ########################################################################
|
| 238 | class slider(_slider_base): |
| 239 | """
|
| 240 | A generic linear slider.
|
| 241 | @param parent the parent widget
|
| 242 | @param sizer add this widget to sizer if provided (optional)
|
| 243 | @param proportion the proportion when added to the sizer (default=0)
|
| 244 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 245 | @param ps the pubsub object (optional)
|
| 246 | @param key the pubsub key (optional)
|
| 247 | @param value the default value (optional)
|
| 248 | @param label title label for this widget (optional)
|
| 249 | @param length the length of the slider in px (optional)
|
| 250 | @param style wx.SL_HORIZONTAL or wx.SL_VERTICAL (default=horizontal)
|
| 251 | @param minimum the minimum value
|
| 252 | @param maximum the maximum value
|
| 253 | @param num_steps the number of slider steps (or specify step_size)
|
| 254 | @param step_size the step between slider jumps (or specify num_steps)
|
| 255 | @param cast a cast function, int, or float (default=float)
|
| 256 | """ |
| 257 | def __init__(self, minimum=-100, maximum=100, num_steps=100, step_size=None, cast=float, **kwargs): |
| 258 | assert step_size or num_steps |
| 259 | if step_size is not None: num_steps = (maximum - minimum)/step_size |
| 260 | converter = converters.slider_converter(minimum=minimum, maximum=maximum, num_steps=num_steps, cast=cast) |
| 261 | _slider_base.__init__(self, converter=converter, num_steps=num_steps, **kwargs)
|
| 262 | |
| 263 | class log_slider(_slider_base): |
| 264 | """
|
| 265 | A generic logarithmic slider.
|
| 266 | The sliders min and max values are base**min_exp and base**max_exp.
|
| 267 | @param parent the parent widget
|
| 268 | @param sizer add this widget to sizer if provided (optional)
|
| 269 | @param proportion the proportion when added to the sizer (default=0)
|
| 270 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 271 | @param ps the pubsub object (optional)
|
| 272 | @param key the pubsub key (optional)
|
| 273 | @param value the default value (optional)
|
| 274 | @param label title label for this widget (optional)
|
| 275 | @param length the length of the slider in px (optional)
|
| 276 | @param style wx.SL_HORIZONTAL or wx.SL_VERTICAL (default=horizontal)
|
| 277 | @param min_exp the minimum exponent
|
| 278 | @param max_exp the maximum exponent
|
| 279 | @param base the exponent base in base**exp
|
| 280 | @param num_steps the number of slider steps (or specify step_size)
|
| 281 | @param step_size the exponent step size (or specify num_steps)
|
| 282 | """ |
| 283 | def __init__(self, min_exp=0, max_exp=1, base=10, num_steps=100, step_size=None, **kwargs): |
| 284 | assert step_size or num_steps |
| 285 | if step_size is not None: num_steps = (max_exp - min_exp)/step_size |
| 286 | converter = converters.log_slider_converter(min_exp=min_exp, max_exp=max_exp, num_steps=num_steps, base=base) |
| 287 | _slider_base.__init__(self, converter=converter, num_steps=num_steps, **kwargs)
|
| 288 | |
| 289 | ########################################################################
|
| 290 | # Gauge Form
|
| 291 | ########################################################################
|
| 292 | class gauge(_form_base): |
| 293 | """
|
| 294 | A gauge bar.
|
| 295 | The gauge displays floating point values between the minimum and maximum.
|
| 296 | @param parent the parent widget
|
| 297 | @param sizer add this widget to sizer if provided (optional)
|
| 298 | @param proportion the proportion when added to the sizer (default=0)
|
| 299 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 300 | @param ps the pubsub object (optional)
|
| 301 | @param key the pubsub key (optional)
|
| 302 | @param value the default value (optional)
|
| 303 | @param label title label for this widget (optional)
|
| 304 | @param length the length of the slider in px (optional)
|
| 305 | @param style wx.GA_HORIZONTAL or wx.GA_VERTICAL (default=horizontal)
|
| 306 | @param minimum the minimum value
|
| 307 | @param maximum the maximum value
|
| 308 | @param num_steps the number of slider steps (or specify step_size)
|
| 309 | @param step_size the step between slider jumps (or specify num_steps)
|
| 310 | """ |
| 311 | def __init__(self, label='', length=-1, minimum=-100, maximum=100, num_steps=100, step_size=None, style=wx.GA_HORIZONTAL, **kwargs): |
| 312 | assert step_size or num_steps |
| 313 | if step_size is not None: num_steps = (maximum - minimum)/step_size |
| 314 | converter = converters.slider_converter(minimum=minimum, maximum=maximum, num_steps=num_steps, cast=float)
|
| 315 | _form_base.__init__(self, converter=converter, **kwargs)
|
| 316 | if style & wx.SL_HORIZONTAL: gauge_size = wx.Size(length, -1) |
| 317 | elif style & wx.SL_VERTICAL: gauge_size = wx.Size(-1, length) |
| 318 | else: raise NotImplementedError |
| 319 | self._gauge = wx.Gauge(self._parent, range=num_steps, size=gauge_size, style=style) |
| 320 | self._add_widget(self._gauge, label, flag=wx.EXPAND) |
| 321 | |
| 322 | def _update(self, value): self._gauge.SetValue(value) |
| 323 | |
| 324 | ########################################################################
|
| 325 | # Check Box Form
|
| 326 | ########################################################################
|
| 327 | class check_box(_form_base): |
| 328 | """
|
| 329 | Create a check box form.
|
| 330 | @param parent the parent widget
|
| 331 | @param sizer add this widget to sizer if provided (optional)
|
| 332 | @param proportion the proportion when added to the sizer (default=0)
|
| 333 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 334 | @param ps the pubsub object (optional)
|
| 335 | @param key the pubsub key (optional)
|
| 336 | @param value the default value (optional)
|
| 337 | @param true the value for form when checked (default=True)
|
| 338 | @param false the value for form when unchecked (default=False)
|
| 339 | @param label title label for this widget (optional)
|
| 340 | """ |
| 341 | def __init__(self, label='', true=True, false=False, **kwargs): |
| 342 | _form_base.__init__(self, converter=converters.bool_converter(true=true, false=false), **kwargs)
|
| 343 | self._check_box = wx.CheckBox(self._parent, style=wx.CHK_2STATE, label=label) |
| 344 | self._check_box.Bind(wx.EVT_CHECKBOX, self._handle) |
| 345 | self._add_widget(self._check_box) |
| 346 | |
| 347 | def _handle(self, event): self[INT_KEY] = self._check_box.IsChecked() |
| 348 | def _update(self, checked): self._check_box.SetValue(checked) |
| 349 | |
| 350 | ########################################################################
|
| 351 | # Drop Down Chooser Form
|
| 352 | ########################################################################
|
| 353 | class drop_down(_chooser_base): |
| 354 | """
|
| 355 | Create a drop down menu form.
|
| 356 | @param parent the parent widget
|
| 357 | @param sizer add this widget to sizer if provided (optional)
|
| 358 | @param proportion the proportion when added to the sizer (default=0)
|
| 359 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 360 | @param ps the pubsub object (optional)
|
| 361 | @param key the pubsub key (optional)
|
| 362 | @param value the default value (optional)
|
| 363 | @param choices list of possible values
|
| 364 | @param labels list of labels for each choice (default=choices)
|
| 365 | @param label title label for this widget (optional)
|
| 366 | @param width the form width in px (optional)
|
| 367 | """ |
| 368 | def __init__(self, label='', width=-1, **kwargs): |
| 369 | _chooser_base.__init__(self, **kwargs)
|
| 370 | self._drop_down = wx.Choice(self._parent, choices=self._labels, size=wx.Size(width, -1)) |
| 371 | self._drop_down.Bind(wx.EVT_CHOICE, self._handle) |
| 372 | self._add_widget(self._drop_down, label, widget_prop=0, label_prop=1) |
| 373 | |
| 374 | def _handle(self, event): self[INT_KEY] = self._drop_down.GetSelection() |
| 375 | def _update(self, i): self._drop_down.SetSelection(i) |
| 376 | |
| 377 | ########################################################################
|
| 378 | # Button Chooser Form
|
| 379 | # Circularly move through the choices with each click.
|
| 380 | # Can be a single-click button with one choice.
|
| 381 | # Can be a 2-state button with two choices.
|
| 382 | ########################################################################
|
| 383 | class button(_chooser_base): |
| 384 | """
|
| 385 | Create a multi-state button.
|
| 386 | @param parent the parent widget
|
| 387 | @param sizer add this widget to sizer if provided (optional)
|
| 388 | @param proportion the proportion when added to the sizer (default=0)
|
| 389 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 390 | @param ps the pubsub object (optional)
|
| 391 | @param key the pubsub key (optional)
|
| 392 | @param value the default value (optional)
|
| 393 | @param choices list of possible values
|
| 394 | @param labels list of labels for each choice (default=choices)
|
| 395 | @param width the width of the button in pixels (optional)
|
| 396 | @param style style arguments (optional)
|
| 397 | @param label title label for this widget (optional)
|
| 398 | """ |
| 399 | def __init__(self, label='', style=0, width=-1, **kwargs): |
| 400 | _chooser_base.__init__(self, **kwargs)
|
| 401 | self._button = wx.Button(self._parent, size=wx.Size(width, -1), style=style) |
| 402 | self._button.Bind(wx.EVT_BUTTON, self._handle) |
| 403 | self._add_widget(self._button, label, widget_prop=((not style&wx.BU_EXACTFIT) and 1 or 0)) |
| 404 | |
| 405 | def _handle(self, event): self[INT_KEY] = (self[INT_KEY] + 1)%len(self._choices) #circularly increment index |
| 406 | def _update(self, i): self._button.SetLabel(self._labels[i]); self.Layout() |
| 407 | |
| 408 | class toggle_button(button): |
| 409 | """
|
| 410 | Create a dual-state button.
|
| 411 | This button will alternate between True and False when clicked.
|
| 412 | @param parent the parent widget
|
| 413 | @param sizer add this widget to sizer if provided (optional)
|
| 414 | @param proportion the proportion when added to the sizer (default=0)
|
| 415 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 416 | @param ps the pubsub object (optional)
|
| 417 | @param key the pubsub key (optional)
|
| 418 | @param value the default value (optional)
|
| 419 | @param width the width of the button in pixels (optional)
|
| 420 | @param style style arguments (optional)
|
| 421 | @param true_label the button's label in the true state
|
| 422 | @param false_label the button's label in the false state
|
| 423 | """ |
| 424 | def __init__(self, true_label='On (click to stop)', false_label='Off (click to start)', **kwargs): |
| 425 | button.__init__(self, choices=[True, False], labels=[true_label, false_label], **kwargs) |
| 426 | |
| 427 | class single_button(toggle_button): |
| 428 | """
|
| 429 | Create a single state button.
|
| 430 | This button will callback() when clicked.
|
| 431 | For use when state holding is not important.
|
| 432 | @param parent the parent widget
|
| 433 | @param sizer add this widget to sizer if provided (optional)
|
| 434 | @param proportion the proportion when added to the sizer (default=0)
|
| 435 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 436 | @param ps the pubsub object (optional)
|
| 437 | @param key the pubsub key (optional)
|
| 438 | @param value the default value (optional)
|
| 439 | @param width the width of the button in pixels (optional)
|
| 440 | @param style style arguments (optional)
|
| 441 | @param label the button's label
|
| 442 | """ |
| 443 | def __init__(self, label='click for callback', **kwargs): |
| 444 | toggle_button.__init__(self, true_label=label, false_label=label, value=True, **kwargs) |
| 445 | |
| 446 | ########################################################################
|
| 447 | # Radio Buttons Chooser Form
|
| 448 | ########################################################################
|
| 449 | class radio_buttons(_chooser_base): |
| 450 | """
|
| 451 | Create a radio button form.
|
| 452 | @param parent the parent widget
|
| 453 | @param sizer add this widget to sizer if provided (optional)
|
| 454 | @param proportion the proportion when added to the sizer (default=0)
|
| 455 | @param flag the flag argument when added to the sizer (default=wx.EXPAND)
|
| 456 | @param ps the pubsub object (optional)
|
| 457 | @param key the pubsub key (optional)
|
| 458 | @param value the default value (optional)
|
| 459 | @param choices list of possible values
|
| 460 | @param labels list of labels for each choice (default=choices)
|
| 461 | @param major_dimension the number of rows/cols (default=auto)
|
| 462 | @param label title label for this widget (optional)
|
| 463 | @param style useful style args: wx.RA_HORIZONTAL, wx.RA_VERTICAL, wx.NO_BORDER (default=wx.RA_HORIZONTAL)
|
| 464 | """ |
| 465 | def __init__(self, style=wx.RA_HORIZONTAL, label='', major_dimension=0, **kwargs): |
| 466 | _chooser_base.__init__(self, **kwargs)
|
| 467 | #create radio buttons
|
| 468 | self._radio_buttons = wx.RadioBox(self._parent, choices=self._labels, style=style, label=label, majorDimension=major_dimension) |
| 469 | self._radio_buttons.Bind(wx.EVT_RADIOBOX, self._handle) |
| 470 | self._add_widget(self._radio_buttons) |
| 471 | |
| 472 | def _handle(self, event): self[INT_KEY] = self._radio_buttons.GetSelection() |
| 473 | def _update(self, i): self._radio_buttons.SetSelection(i) |
| 474 | |
| 475 | ########################################################################
|
| 476 | # Notebook Chooser Form
|
| 477 | # The notebook pages/tabs are for selecting between choices.
|
| 478 | # A page must be added to the notebook for each choice.
|
| 479 | ########################################################################
|
| 480 | class notebook(_chooser_base): |
| 481 | def __init__(self, pages, notebook, **kwargs): |
| 482 | _chooser_base.__init__(self, **kwargs)
|
| 483 | assert len(pages) == len(self._choices) |
| 484 | self._notebook = notebook
|
| 485 | self._notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self._handle) |
| 486 | #add pages, setting the label on each tab
|
| 487 | for i, page in enumerate(pages): |
| 488 | self._notebook.AddPage(page, self._labels[i]) |
| 489 | self._add_widget(self._notebook) |
| 490 | |
| 491 | def _handle(self, event): self[INT_KEY] = self._notebook.GetSelection() |
| 492 | def _update(self, i): self._notebook.SetSelection(i) |
| 493 | |
| 494 | # ----------------------------------------------------------------
|
| 495 | # Stand-alone test application
|
| 496 | # ----------------------------------------------------------------
|
| 497 | |
| 498 | import wx |
| 499 | from gnuradio.wxgui import gui |
| 500 | |
| 501 | class app_gui (object): |
| 502 | def __init__(self, frame, panel, vbox, top_block, options, args): |
| 503 | |
| 504 | def callback(v): print v |
| 505 | |
| 506 | radio_buttons( |
| 507 | sizer=vbox, |
| 508 | parent=panel, |
| 509 | choices=[2, 4, 8, 16], |
| 510 | labels=['two', 'four', 'eight', 'sixteen'], |
| 511 | value=4,
|
| 512 | style=wx.RA_HORIZONTAL, |
| 513 | label='test radio long string',
|
| 514 | callback=callback, |
| 515 | #major_dimension = 2,
|
| 516 | ) |
| 517 | |
| 518 | radio_buttons( |
| 519 | sizer=vbox, |
| 520 | parent=panel, |
| 521 | choices=[2, 4, 8, 16], |
| 522 | labels=['two', 'four', 'eight', 'sixteen'], |
| 523 | value=4,
|
| 524 | style=wx.RA_VERTICAL, |
| 525 | label='test radio long string',
|
| 526 | callback=callback, |
| 527 | #major_dimension = 2,
|
| 528 | ) |
| 529 | |
| 530 | radio_buttons( |
| 531 | sizer=vbox, |
| 532 | parent=panel, |
| 533 | choices=[2, 4, 8, 16], |
| 534 | labels=['two', 'four', 'eight', 'sixteen'], |
| 535 | value=4,
|
| 536 | style=wx.RA_VERTICAL | wx.NO_BORDER, |
| 537 | callback=callback, |
| 538 | #major_dimension = 2,
|
| 539 | ) |
| 540 | |
| 541 | button( |
| 542 | sizer=vbox, |
| 543 | parent=panel, |
| 544 | choices=[2, 4, 8, 16], |
| 545 | labels=['two', 'four', 'eight', 'sixteen'], |
| 546 | value=2,
|
| 547 | label='button value',
|
| 548 | callback=callback, |
| 549 | #width=100,
|
| 550 | ) |
| 551 | |
| 552 | |
| 553 | drop_down( |
| 554 | sizer=vbox, |
| 555 | parent=panel, |
| 556 | choices=[2, 4, 8, 16], |
| 557 | value=2,
|
| 558 | label='Choose One',
|
| 559 | callback=callback, |
| 560 | ) |
| 561 | check_box( |
| 562 | sizer=vbox, |
| 563 | parent=panel, |
| 564 | value=False,
|
| 565 | label='check me',
|
| 566 | callback=callback, |
| 567 | ) |
| 568 | text_box( |
| 569 | sizer=vbox, |
| 570 | parent=panel, |
| 571 | value=3,
|
| 572 | label='text box',
|
| 573 | callback=callback, |
| 574 | width=200,
|
| 575 | ) |
| 576 | |
| 577 | static_text( |
| 578 | sizer=vbox, |
| 579 | parent=panel, |
| 580 | value='bob',
|
| 581 | label='static text',
|
| 582 | width=-1,
|
| 583 | bold=True,
|
| 584 | ) |
| 585 | |
| 586 | slider( |
| 587 | sizer=vbox, |
| 588 | parent=panel, |
| 589 | value=12,
|
| 590 | label='slider',
|
| 591 | callback=callback, |
| 592 | ) |
| 593 | |
| 594 | log_slider( |
| 595 | sizer=vbox, |
| 596 | parent=panel, |
| 597 | value=12,
|
| 598 | label='slider',
|
| 599 | callback=callback, |
| 600 | ) |
| 601 | |
| 602 | slider( |
| 603 | sizer=vbox, |
| 604 | parent=panel, |
| 605 | value=12,
|
| 606 | label='slider',
|
| 607 | callback=callback, |
| 608 | style=wx.SL_VERTICAL, |
| 609 | length=30,
|
| 610 | ) |
| 611 | |
| 612 | toggle_button( |
| 613 | sizer=vbox, |
| 614 | parent=panel, |
| 615 | value=True,
|
| 616 | label='toggle it',
|
| 617 | callback=callback, |
| 618 | ) |
| 619 | |
| 620 | single_button( |
| 621 | sizer=vbox, |
| 622 | parent=panel, |
| 623 | label='sig test',
|
| 624 | callback=callback, |
| 625 | ) |
| 626 | |
| 627 | if __name__ == "__main__": |
| 628 | try:
|
| 629 | |
| 630 | # Create the GUI application
|
| 631 | app = gui.app( |
| 632 | gui=app_gui, # User interface class
|
| 633 | title="Test Forms", # Top window title |
| 634 | ) |
| 635 | |
| 636 | # And run it
|
| 637 | app.MainLoop() |
| 638 | |
| 639 | except RuntimeError, e: |
| 640 | print e
|
| 641 | sys.exit(1)
|