param_editors.py
Go to the documentation of this file.
00001 # Software License Agreement (BSD License)
00002 #
00003 # Copyright (c) 2012, Willow Garage, Inc.
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions
00008 # are met:
00009 #
00010 #  * Redistributions of source code must retain the above copyright
00011 #    notice, this list of conditions and the following disclaimer.
00012 #  * Redistributions in binary form must reproduce the above
00013 #    copyright notice, this list of conditions and the following
00014 #    disclaimer in the documentation and/or other materials provided
00015 #    with the distribution.
00016 #  * Neither the name of Willow Garage, Inc. nor the names of its
00017 #    contributors may be used to endorse or promote products derived
00018 #    from this software without specific prior written permission.
00019 #
00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 # POSSIBILITY OF SUCH DAMAGE.
00032 #
00033 # Author: Isaac Saito, Ze'ev Klapow
00034 
00035 import math
00036 import os
00037 
00038 from dynamic_reconfigure.msg import Config as ConfigMsg
00039 from python_qt_binding import loadUi
00040 from python_qt_binding.QtCore import Qt, Signal
00041 from python_qt_binding.QtGui import QCheckBox, QComboBox, QDoubleValidator, QIntValidator, QHBoxLayout, QLabel, QLineEdit, QPainter, QSlider, QWidget 
00042 import rospy
00043 
00044 from .param_updater import ParamUpdater
00045 
00046 EDITOR_TYPES = {
00047     'bool': 'BooleanEditor',
00048     'str': 'StringEditor',
00049     'int': 'IntegerEditor',
00050     'double': 'DoubleEditor',
00051 }
00052 
00053 class EditorWidget(QWidget):
00054 
00055     def __init__(self, updater, config):
00056         """
00057         :param updater: 
00058         :type updater: rqt_param.ParamUpdater
00059         """
00060         
00061         super(EditorWidget, self).__init__()
00062         
00063         self.updater = updater
00064         self.name = config['name']
00065 
00066         self.old_value = None
00067 
00068     def _update(self, value):
00069         if value != self.old_value:
00070             self.update_configuration(value)
00071             self.old_value = value
00072 
00073     def update_value(self, value):
00074         pass
00075 
00076     def update_configuration(self, value):
00077         self.updater.update({self.name : value})
00078 
00079     def display(self, grid, row):
00080         """
00081         Should be overridden in subclass.
00082     
00083         :type grid: ???
00084         :type row: ???
00085         """  
00086         pass
00087 
00088     def close(self):
00089         """
00090         Should be overridden in subclass.
00091         """
00092         pass
00093 
00094 class BooleanEditor(EditorWidget):
00095     def __init__(self, updater, config): 
00096         super(BooleanEditor, self).__init__(updater, config)
00097 
00098         ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
00099                                'ui/editor_bool.ui')                
00100         loadUi(ui_file, self)  
00101         
00102         self.update_value(config['default'])
00103         self._checkbox.clicked.connect(self._update)
00104 
00105     def update_value(self, value):
00106         self._checkbox.setChecked(value)
00107 
00108     def display(self, grid, row):
00109         grid.addWidget(QLabel(self.name), row, 0, Qt.AlignRight)
00110         grid.addWidget(self, row, 1)
00111 
00112 class StringEditor(EditorWidget):
00113     def __init__(self, updater, config):
00114         super(StringEditor, self).__init__(updater, config)
00115         ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
00116                                'ui/editor_string.ui')    
00117         loadUi(ui_file, self) 
00118                 
00119         self._paramval_lineedit.editingFinished.connect(self.edit_finished)
00120 
00121     def update_value(self, value):
00122         self._paramval_lineedit.setText(value)
00123 
00124     def edit_finished(self):
00125         self._update(self._paramval_lineedit.text())
00126     
00127     def display(self, grid, row):
00128         grid.addWidget(QLabel(self.name), row, 0, Qt.AlignRight)
00129         grid.addWidget(self, row, 1)
00130 
00131 class IntegerEditor(EditorWidget):
00132     def __init__(self, updater, config):
00133         super(IntegerEditor, self).__init__(updater, config)
00134         
00135         ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
00136                                'ui/editor_number.ui')
00137         loadUi(ui_file, self) 
00138 
00139         self.min = int(config['min'])
00140         self.max = int(config['max'])
00141         self._min_val_label.setText(str(self.min))
00142         self._max_val_label.setText(str(self.max))
00143 
00144         self._slider_horizontal.setRange(self.min, self.max)
00145         self._slider_horizontal.sliderReleased.connect(self.slider_released)
00146         self._slider_horizontal.sliderMoved.connect(self.update_text)
00147         
00148         #TODO(Isaac) Fix that the naming of _paramval_lineEdit instance is not 
00149         #            consistent among Editor's subclasses. 
00150         self._paramval_lineEdit.setValidator(QIntValidator(self.min,
00151                                                            self.max, self))
00152         self._paramval_lineEdit.editingFinished.connect(self.editing_finished)
00153 
00154         # TODO: This should not always get set to the default it should be the current value
00155         self._paramval_lineEdit.setText(str(config['default']))
00156         self._slider_horizontal.setSliderPosition(int(config['default']))
00157 
00158     def slider_released(self):
00159         self.update_text(self._slider_horizontal.value())
00160         self._update(self._slider_horizontal.value())
00161 
00162     def update_text(self, val):
00163         rospy.logdebug(' IntegerEditor.update_text val=%s', str(val))
00164         self._paramval_lineEdit.setText(str(val))
00165 
00166     def editing_finished(self):
00167         self._slider_horizontal.setSliderPosition(
00168                                          int(self._paramval_lineEdit.text()))
00169         self._update(int(self._paramval_lineEdit.text()))
00170 
00171     def update_value(self, val):
00172         self._slider_horizontal.setSliderPosition(int(val))
00173         self._paramval_lineEdit.setText(str(val))
00174 
00175     def display(self, grid, row):
00176         grid.addWidget(QLabel(self.name), row, 0, Qt.AlignRight)
00177         grid.addWidget(self, row, 1)
00178 
00179 class DoubleEditor(EditorWidget):
00180     def __init__(self, updater, config):
00181         super(DoubleEditor, self).__init__(updater, config)
00182         
00183         ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
00184                                'ui/editor_number.ui')                
00185         loadUi(ui_file, self) 
00186 
00187         # Handle unbounded doubles nicely
00188         if config['min'] != -float('inf'):
00189             self.min = float(config['min'])
00190             self._min_val_label.setText(str(self.min))
00191             self.func = lambda x: x
00192             self.ifunc = self.func
00193         else:
00194             self.min = -1e10000 
00195             self._min_val_label.setText('-inf')
00196             self.func = lambda x: math.atan(x)
00197             self.ifunc = lambda x: math.tan(x)
00198 
00199         if config['max'] != float('inf'):
00200             self.max = float(config['max'])
00201             self._max_val_label.setText(str(self.max))
00202             self.func = lambda x: x
00203             self.ifunc = self.func
00204         else:
00205             self.max = 1e10000
00206             self.max_val_label.setText('inf')
00207             self.func = lambda x: math.atan(x)
00208             self.ifunc = lambda x: math.tan(x)
00209 
00210         self.scale = (self.func(self.max) - self.func(self.min)) / 100
00211         self.offset = self.func(self.min)
00212 
00213         self._slider_horizontal.setRange(self.slider_value(self.min),
00214                                          self.slider_value(self.max))
00215         self._slider_horizontal.sliderReleased.connect(self.slider_released)
00216         self._slider_horizontal.sliderMoved.connect(self.update_text)
00217 
00218         self._paramval_lineEdit.setValidator(QDoubleValidator(
00219                                                     self.min, self.max,
00220                                                     4, self))
00221         self._paramval_lineEdit.editingFinished.connect(self.editing_finished)
00222 
00223         self._paramval_lineEdit.setText(str(config['default']))
00224         self._slider_horizontal.setSliderPosition(
00225                                      self.slider_value(config['default']))
00226 
00227     def get_value(self):
00228         return self.ifunc(self._slider_horizontal.value() * self.scale)
00229 
00230     def slider_value(self, value):
00231         return int(round((self.func(value)) / self.scale))
00232 
00233     def slider_released(self):
00234         self.update_text(self.get_value())
00235         self._update(self.get_value())
00236 
00237     def update_text(self, value):
00238         self._paramval_lineEdit.setText(str(self.get_value()))
00239 
00240     def editing_finished(self):
00241         self._slider_horizontal.setSliderPosition(
00242                                self.slider_value(float(self._paramval_lineEdit.text())))
00243         self._update(float(self._paramval_lineEdit.text()))
00244 
00245     def update_value(self, val):
00246         self._slider_horizontal.setSliderPosition(
00247                                   self.slider_value(float(val)))
00248         self._paramval_lineEdit.setText(str(val))
00249 
00250     def display(self, grid, row):
00251         grid.addWidget(QLabel(self.name), row, 0, Qt.AlignRight)
00252         grid.addWidget(self, row, 1)
00253 
00254 class EnumEditor(EditorWidget):
00255     def __init__(self, updater, config):
00256         super(EnumEditor, self).__init__(updater, config)
00257 
00258         ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
00259                                'ui/editor_enum.ui')                
00260         loadUi(ui_file, self) 
00261         
00262         try:
00263             enum = eval(config['edit_method'])['enum']
00264         except:
00265             print("Malformed enum")
00266             return
00267 
00268         self.names = [item['name'] for item in enum]
00269         self.values = [item['value'] for item in enum]
00270 
00271         items = ["%s (%s)" % (self.names[i], self.values[i]) 
00272                  for i in range(0, len(self.names))]
00273 
00274         self._combobox.addItems(items)
00275         self._combobox.currentIndexChanged['int'].connect(self.selected)
00276 
00277     def selected(self, index):
00278         self._update(self.values[index])
00279 
00280     def update_value(self, val):
00281         self._combobox.setCurrentIndex(self.values.index(val))
00282 
00283     def display(self, grid, row):
00284         grid.addWidget(QLabel(self.name), row, 0, Qt.AlignRight)
00285         grid.addWidget(self, row, 1)
00286 


rqt_param
Author(s): Isaac Saito, Ze'ev Klapow
autogenerated on Fri Jan 3 2014 11:57:01