summaryrefslogtreecommitdiff
path: root/gr-qtgui/src/python
diff options
context:
space:
mode:
authorJosh Blum2010-12-05 19:15:37 -0500
committerJosh Blum2011-03-01 17:02:06 -0800
commit0e076c5835ea624c25e7be964e946d9f6425f414 (patch)
treeaabfe30774eaf99c91af689227a54f0b21f693de /gr-qtgui/src/python
parent7ed83c72dbd079a50a421661a874c3ac94a34bd6 (diff)
downloadgnuradio-0e076c5835ea624c25e7be964e946d9f6425f414.tar.gz
gnuradio-0e076c5835ea624c25e7be964e946d9f6425f414.tar.bz2
gnuradio-0e076c5835ea624c25e7be964e946d9f6425f414.zip
qtgui: an attempt at a slider form
Diffstat (limited to 'gr-qtgui/src/python')
-rw-r--r--gr-qtgui/src/python/Makefile.am7
-rw-r--r--gr-qtgui/src/python/forms/__init__.py32
-rw-r--r--gr-qtgui/src/python/forms/converters.py154
-rw-r--r--gr-qtgui/src/python/forms/forms.py82
4 files changed, 275 insertions, 0 deletions
diff --git a/gr-qtgui/src/python/Makefile.am b/gr-qtgui/src/python/Makefile.am
index 31df63a44..c24ba14d9 100644
--- a/gr-qtgui/src/python/Makefile.am
+++ b/gr-qtgui/src/python/Makefile.am
@@ -36,3 +36,10 @@ qtguipythondir = $(grpythondir)/qtgui
qtguipython_PYTHON = \
__init__.py
+
+qtguiformspythondir = $(grpythondir)/qtgui/forms
+
+qtguiformspython_PYTHON = \
+ forms/__init__.py \
+ forms/converters.py \
+ forms/forms.py
diff --git a/gr-qtgui/src/python/forms/__init__.py b/gr-qtgui/src/python/forms/__init__.py
new file mode 100644
index 000000000..bb8ac2057
--- /dev/null
+++ b/gr-qtgui/src/python/forms/__init__.py
@@ -0,0 +1,32 @@
+#
+# Copyright 2010 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.
+#
+
+########################################################################
+# External Converters
+########################################################################
+from converters import \
+ eval_converter, str_converter, \
+ float_converter, int_converter
+
+########################################################################
+# External Forms
+########################################################################
+from forms import slider
diff --git a/gr-qtgui/src/python/forms/converters.py b/gr-qtgui/src/python/forms/converters.py
new file mode 100644
index 000000000..53c966d32
--- /dev/null
+++ b/gr-qtgui/src/python/forms/converters.py
@@ -0,0 +1,154 @@
+#
+# Copyright 2009 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 gnuradio import eng_notation
+import math
+
+class abstract_converter(object):
+ def external_to_internal(self, v):
+ """
+ Convert from user specified value to value acceptable to underlying primitive.
+ The underlying primitive usually expects strings.
+ """
+ raise NotImplementedError
+ def internal_to_external(self, s):
+ """
+ Convert from underlying primitive value to user specified value.
+ The underlying primitive usually expects strings.
+ """
+ raise NotImplementedError
+ def help(self):
+ return "Any string is acceptable"
+
+class identity_converter(abstract_converter):
+ def external_to_internal(self,v):
+ return v
+ def internal_to_external(self, s):
+ return s
+
+########################################################################
+# Commonly used converters
+########################################################################
+class chooser_converter(abstract_converter):
+ """
+ Convert between a set of possible choices and an index.
+ Used in the chooser base and all sub-classes.
+ """
+ def __init__(self, choices):
+ #choices must be a list because tuple does not have .index() in python2.5
+ self._choices = list(choices)
+ def external_to_internal(self, choice):
+ return self._choices.index(choice)
+ def internal_to_external(self, index):
+ return self._choices[index]
+ def help(self):
+ return 'Enter a possible value in choices: "%s"'%str(self._choices)
+
+class bool_converter(abstract_converter):
+ """
+ The internal representation is boolean.
+ The external representation is specified.
+ Used in the check box form.
+ """
+ def __init__(self, true, false):
+ self._true = true
+ self._false = false
+ def external_to_internal(self, v):
+ if v == self._true: return True
+ if v == self._false: return False
+ raise Exception, 'Value "%s" is not a possible option.'%v
+ def internal_to_external(self, v):
+ if v: return self._true
+ else: return self._false
+ def help(self):
+ return "Value must be in (%s, %s)."%(self._true, self._false)
+
+class eval_converter(abstract_converter):
+ """
+ A catchall converter when int and float are not enough.
+ Evaluate the internal representation with python's eval().
+ Possible uses, set a complex number, constellation points.
+ Used in text box.
+ """
+ def __init__(self, formatter=lambda x: '%s'%(x)):
+ self._formatter = formatter
+ def external_to_internal(self, v):
+ return self._formatter(v)
+ def internal_to_external(self, s):
+ return eval(s)
+ def help(self):
+ return "Value must be evaluatable by python's eval."
+
+class str_converter(abstract_converter):
+ def __init__(self, formatter=lambda x: '%s'%(x)):
+ self._formatter = formatter
+ def external_to_internal(self, v):
+ return self._formatter(v)
+ def internal_to_external(self, s):
+ return str(s)
+
+class int_converter(abstract_converter):
+ def __init__(self, formatter=lambda x: '%d'%round(x)):
+ self._formatter = formatter
+ def external_to_internal(self, v):
+ return self._formatter(v)
+ def internal_to_external(self, s):
+ return int(s, 0)
+ def help(self):
+ return "Enter an integer. Leading 0x indicates hex"
+
+class float_converter(abstract_converter):
+ def __init__(self, formatter=eng_notation.num_to_str):
+ self._formatter = formatter
+ def external_to_internal(self, v):
+ return self._formatter(v)
+ def internal_to_external(self, s):
+ return eng_notation.str_to_num(s)
+ def help(self):
+ return "Enter a float with optional scale suffix. E.g., 100.1M"
+
+class slider_converter(abstract_converter):
+ """
+ Scale values to and from the slider.
+ """
+ def __init__(self, start, stop, num_steps, cast):
+ assert start < stop
+ assert num_steps > 0
+ self._offset = start
+ self._scaler = float(stop - start)/num_steps
+ self._cast = cast
+ def external_to_internal(self, v):
+ return (v - self._offset)/self._scaler
+ def internal_to_external(self, v):
+ return self._cast(v*self._scaler + self._offset)
+ def help(self):
+ return "Value should be within slider range"
+
+class log_slider_converter(slider_converter):
+ def __init__(self, min_exp, max_exp, num_steps, base):
+ assert min_exp < max_exp
+ assert num_steps > 0
+ self._base = base
+ slider_converter.__init__(self, start=min_exp, stop=max_exp, num_steps=num_steps, cast=float)
+ def external_to_internal(self, v):
+ return slider_converter.external_to_internal(self, math.log(v, self._base))
+ def internal_to_external(self, v):
+ return self._base**slider_converter.internal_to_external(self, v)
diff --git a/gr-qtgui/src/python/forms/forms.py b/gr-qtgui/src/python/forms/forms.py
new file mode 100644
index 000000000..c6b7c9fcf
--- /dev/null
+++ b/gr-qtgui/src/python/forms/forms.py
@@ -0,0 +1,82 @@
+#
+# Copyright 2010 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 PyQt4 import QtGui
+from PyQt4 import QtCore
+
+import converters
+
+class _form_base(QtGui.QWidget):
+ def __init__(self, parent=None, converter=None, callback=None, value=None):
+ QtGui.QWidget.__init__(self, parent)
+ self._converter = converter
+ self._callback = callback
+ self.set_value(value)
+
+ def get_value(self):
+ return self._value
+
+ def set_value(self, value):
+ self._value = value
+ self._base_update(self._converter.external_to_internal(value))
+
+ def _base_update(self, int_val):
+ self._update(int_val)
+
+ def _base_handle(self, int_val):
+ self._value = self._converter.internal_to_external(int_val)
+ if self._callback: self._callback(self._value)
+
+class _slider_base(_form_base):
+ def __init__(self, label='', length=-1, num_steps=100, orient=QtCore.Qt.Horizontal, **kwargs):
+ _form_base.__init__(self, **kwargs)
+ self._slider = QtGui.QSlider(parent=self)
+ self._slider.setOrientation(orient)
+ self._slider.setRange(0, num_steps)
+ if length > 0:
+ if orient == QtCore.Qt.Horizontal:
+ slider_size = self._slider.setWidth(length)
+ if orient == QtCore.Qt.Vertical:
+ slider_size = self._slider.setHeight(length)
+ self.slider.valueChanged.connect(self._handle)
+
+ def _handle(self, event): self._base_handle(self._slider.value())
+ def _update(self, value): self._slider.setValue(int(round(value)))
+
+class slider(_slider_base):
+ """
+ A generic linear slider.
+ @param parent the parent widget
+ @param value the default value
+ @param label title label for this widget (optional)
+ @param length the length of the slider in px (optional)
+ @param orient Qt.Horizontal Veritcal (default=horizontal)
+ @param start the start value
+ @param stop the stop value
+ @param num_steps the number of slider steps (or specify step_size)
+ @param step_size the step between slider jumps (or specify num_steps)
+ @param cast a cast function, int, or float (default=float)
+ """
+ def __init__(self, start, stop, num_steps=100, step_size=None, cast=float, **kwargs):
+ assert step_size or num_steps
+ if step_size is not None: num_steps = (stop - start)/step_size
+ converter = converters.slider_converter(start=start, stop=stop, num_steps=num_steps, cast=cast)
+ _slider_base.__init__(self, converter=converter, num_steps=num_steps, **kwargs)