1 from distutils.version
import LooseVersion
6 import python_qt_binding
7 import python_qt_binding.QtCore
as QtCore
8 from python_qt_binding.QtCore
import QEvent
9 from python_qt_binding.QtCore
import QSize
10 from python_qt_binding.QtCore
import Qt
11 from python_qt_binding.QtCore
import QTimer
12 from python_qt_binding.QtCore
import QTranslator
13 from python_qt_binding.QtCore
import qWarning
14 from python_qt_binding.QtCore
import Slot
15 import python_qt_binding.QtGui
as QtGui
16 from python_qt_binding.QtGui
import QBrush
17 from python_qt_binding.QtGui
import QColor
18 from python_qt_binding.QtGui
import QFont
19 from python_qt_binding.QtGui
import QIcon
20 from python_qt_binding.QtGui
import QPainter
21 from python_qt_binding.QtGui
import QPen
24 from resource_retriever
import get_filename
27 from std_msgs.msg
import Bool
28 from std_msgs.msg
import Time
29 from std_srvs.srv
import Empty
30 from std_srvs.srv
import SetBool
31 from std_srvs.srv
import Trigger
33 if LooseVersion(python_qt_binding.QT_BINDING_VERSION).version[0] >= 5:
34 from python_qt_binding.QtWidgets
import QAction
35 from python_qt_binding.QtWidgets
import QCompleter
36 from python_qt_binding.QtWidgets
import QFileDialog
37 from python_qt_binding.QtWidgets
import QGroupBox
38 from python_qt_binding.QtWidgets
import QHBoxLayout
39 from python_qt_binding.QtWidgets
import QMenu
40 from python_qt_binding.QtWidgets
import QMessageBox
41 from python_qt_binding.QtWidgets
import QRadioButton
42 from python_qt_binding.QtWidgets
import QSizePolicy
43 from python_qt_binding.QtWidgets
import QToolButton
44 from python_qt_binding.QtWidgets
import QVBoxLayout
45 from python_qt_binding.QtWidgets
import QWidget
48 from python_qt_binding.QtGui
import QAction
49 from python_qt_binding.QtGui
import QCompleter
50 from python_qt_binding.QtGui
import QFileDialog
51 from python_qt_binding.QtGui
import QGroupBox
52 from python_qt_binding.QtGui
import QHBoxLayout
53 from python_qt_binding.QtGui
import QMenu
54 from python_qt_binding.QtGui
import QMessageBox
55 from python_qt_binding.QtGui
import QRadioButton
56 from python_qt_binding.QtGui
import QSizePolicy
57 from python_qt_binding.QtGui
import QToolButton
58 from python_qt_binding.QtGui
import QVBoxLayout
59 from python_qt_binding.QtGui
import QWidget
64 Qt widget to visualize multiple buttons
67 super(ServiceButtonGeneralWidget, self).
__init__()
72 self.
_dialog.setFileMode(QFileDialog.ExistingFile)
74 if rospy.has_param(
"~layout_yaml_file"):
80 QMessageBox.about(self,
"ERROR", message)
85 layout_yaml_file = rospy.get_param(
"~layout_yaml_file", layout_param)
86 resolved_layout_yaml_file = get_filename(layout_yaml_file)
87 if (resolved_layout_yaml_file
is not None
88 and resolved_layout_yaml_file.startswith(
"file://")):
89 resolved_layout_yaml_file = resolved_layout_yaml_file[len(
"file://"):]
91 if os.path.exists(resolved_layout_yaml_file):
97 layout_yaml_file, resolved_layout_yaml_file))
102 Parse yaml file and setup Buttons.
104 with open(yaml_file)
as f:
105 yaml_data = yaml.safe_load(f)
110 Setup Buttons with yaml_data which is loaded in setupButtons. Format of the yaml file should be:
111 - name: 'button name' (required)
112 image: 'path to image for icon' (optional)
113 image_size: 'width and height of icon' (optional)
114 service: 'service' (required)
115 column: 'column index' (optional, defaults to 0)
120 direction =
'vertical'
123 if d[
'direction'] ==
'horizontal':
124 direction =
'horizontal'
126 direction =
'vertical'
130 column_indices = [d[
'column']
for d
in yaml_data]
131 if len(column_indices) > 1:
132 max_column_index = max(*column_indices)
134 max_column_index = column_indices[0]
135 if direction ==
'vertical':
138 for i
in range(max_column_index + 1)]
140 self.
layout = QVBoxLayout()
142 for i
in range(max_column_index + 1)]
144 for i
in range(max_column_index + 1)]
145 for button_data
in yaml_data:
147 if "name" not in button_data:
148 self.
showError(
"name field is missed in yaml")
149 raise Exception(
"name field is missed in yaml")
150 if "service" not in button_data:
151 self.
showError(
"service field is missed in yaml")
152 raise Exception(
"service field is missed in yaml")
154 button = QToolButton()
156 button = QRadioButton()
157 button.setSizePolicy(
158 QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred))
159 if "image" in button_data:
160 image_file = get_filename(
161 button_data[
"image"])[len(
"file://"):]
162 if os.path.exists(image_file):
163 icon = QtGui.QIcon(image_file)
165 if "image_size" in button_data:
166 button.setIconSize(QSize(
167 button_data[
"image_size"][0],
168 button_data[
"image_size"][1]))
170 button.setIconSize(QSize(100, 100))
171 if "name" in button_data:
172 name = button_data[
'name']
174 if 'service_type' in button_data:
175 if button_data[
'service_type'] ==
'Trigger':
176 service_type = Trigger
177 elif button_data[
'service_type'] ==
'Empty':
179 elif button_data[
'service_type'] ==
'SetBool':
180 service_type = SetBool
182 raise Exception(
"Unsupported service type: {}".format(
183 button_data[
'service_type']))
186 if service_type == SetBool:
187 button.setCheckable(
True)
189 sname = button_data[
'service']
190 if sname[0] ==
'/' or sname[0] ==
'~':
193 sname = namespace +
'/' + sname
194 button.clicked.connect(
197 button.clicked.connect(
198 self.
buttonCallback(button_data[
'service'], service_type, button))
200 button.setToolButtonStyle(
201 QtCore.Qt.ToolButtonTextUnderIcon)
202 if ((self.
button_type ==
"radio" or service_type == SetBool)
203 and (
"default_value" in button_data
204 and button_data[
'default_value'])):
205 button.setChecked(
True)
206 self.
layout_boxes[button_data[
'column']].addWidget(button)
211 self.
layout.addWidget(group)
212 self.setLayout(self.
layout)
216 return function as callback
218 return lambda checked: self.
buttonCallbackImpl(checked, service_name, service_type, button)
221 srv = rospy.ServiceProxy(service_name, service_type)
223 if service_type == SetBool:
227 if hasattr(res,
'success'):
228 success = res.success
231 "Succeeded to call {}, but service response is res.success=False"
232 .format(service_name))
233 if service_type == SetBool
and not button
is None:
234 button.setChecked(
not checked)
235 except rospy.ServiceException
as e:
236 self.
showError(
"Failed to call %s" % service_name)
237 if service_type == SetBool
and not button
is None:
238 button.setChecked(
not checked)
242 instance_settings.set_value(
"layout_param", self.
_layout_param)
243 rospy.loginfo(
"save setting is called. %s" % self.
_layout_param)
246 if instance_settings.value(
"layout_param"):
248 rospy.loginfo(
"restore setting is called. %s" % self.
_layout_param)
251 rospy.loginfo(
"succeeded to restore. %s" % self.
_layout_param)
258 self.
_translator.tr(
"YAML files (*.yaml *.yml)"))[0]