def _add_track_label(self, track_name, background_color=None): label = QLabel(track_name) label.setMargin(5) palette = label.palette() palette.setColor(label.foregroundRole(), Qt.black) if background_color is not None: label.setAutoFillBackground(True) palette.setColor(label.backgroundRole(), background_color) label.setPalette(palette) label.setFont(QFont('sans', 13)) self.track_label_layout.addWidget(label)
class StringLabelWidget(QWidget): def __init__(self): super(StringLabelWidget, self).__init__() self.lock = Lock() vbox = QtGui.QVBoxLayout(self) self.label = QLabel() self.label.setAlignment(Qt.AlignLeft) self.label.setSizePolicy( QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)) font = QFont("Helvetica", 14) self.label.setFont(font) self.label.setWordWrap(True) vbox.addWidget(self.label) self.string_sub = None self._string_topics = [] self._update_topic_timer = QTimer(self) self._update_topic_timer.timeout.connect(self.updateTopics) self._update_topic_timer.start(1) self._active_topic = None self._dialog = ComboBoxDialog() def trigger_configuration(self): self._dialog.exec_() self.setupSubscriber(self._string_topics[self._dialog.number]) def updateTopics(self): need_to_update = False for (topic, topic_type) in rospy.get_published_topics(): if topic_type == "std_msgs/String": if not topic in self._string_topics: self._string_topics.append(topic) need_to_update = True if need_to_update: self._string_topics = sorted(self._string_topics) self._dialog.combo_box.clear() for topic in self._string_topics: self._dialog.combo_box.addItem(topic) if self._active_topic: if self._active_topic not in self._string_topics: self._string_topics.append(self._active_topic) self._dialog.combo_box.addItem(self._active_topic) self._dialog.combo_box.setCurrentIndex( self._string_topics.index(self._active_topic)) def setupSubscriber(self, topic): if self.string_sub: self.string_sub.unregister() self.string_sub = rospy.Subscriber(topic, String, self.stringCallback) self._active_topic = topic def onActivated(self, number): self.setupSubscriber(self._string_topics[number]) def stringCallback(self, msg): self.string = msg.data self.label.setText(self.string) def save_settings(self, plugin_settings, instance_settings): if self._active_topic: instance_settings.set_value("active_topic", self._active_topic) def restore_settings(self, plugin_settings, instance_settings): if instance_settings.value("active_topic"): topic = instance_settings.value("active_topic") self._dialog.combo_box.addItem(topic) self.setupSubscriber(topic)
class GroupWidget(QWidget): ''' (Isaac's guess as of 12/13/2012) This class bonds multiple Editor instances that are associated with a single node as a group. ''' # public signal sig_node_disabled_selected = Signal(str) def __init__(self, updater, config, nodename): ''' :param config: :type config: Dictionary? defined in dynamic_reconfigure.client.Client :type nodename: str ''' #TODO figure out what data type 'config' is. It is afterall returned # from dynamic_reconfigure.client.get_parameter_descriptions() # ros.org/doc/api/dynamic_reconfigure/html/dynamic_reconfigure.client-pysrc.html#Client super(GroupWidget, self).__init__() self.state = config['state'] self.name = config['name'] self._toplevel_treenode_name = nodename # TODO: .ui file needs to be back into usage in later phase. # ui_file = os.path.join(rp.get_path('rqt_reconfigure'), # 'resource', 'singlenode_parameditor.ui') # loadUi(ui_file, self) verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(QMargins(0, 0, 0, 0)) _widget_nodeheader = QWidget() _h_layout_nodeheader = QHBoxLayout(_widget_nodeheader) _h_layout_nodeheader.setContentsMargins(QMargins(0, 0, 0, 0)) self.nodename_qlabel = QLabel(self) font = QFont('Trebuchet MS, Bold') font.setUnderline(True) font.setBold(True) # Button to close a node. _icon_disable_node = QIcon.fromTheme('window-close') _bt_disable_node = QPushButton(_icon_disable_node, '', self) _bt_disable_node.setToolTip('Hide this node') _bt_disable_node_size = QSize(36, 24) _bt_disable_node.setFixedSize(_bt_disable_node_size) _bt_disable_node.pressed.connect(self._node_disable_bt_clicked) _h_layout_nodeheader.addWidget(self.nodename_qlabel) _h_layout_nodeheader.addWidget(_bt_disable_node) self.nodename_qlabel.setAlignment(Qt.AlignCenter) font.setPointSize(10) self.nodename_qlabel.setFont(font) grid_widget = QWidget(self) self.grid = QFormLayout(grid_widget) verticalLayout.addWidget(_widget_nodeheader) verticalLayout.addWidget(grid_widget, 1) # Again, these UI operation above needs to happen in .ui file. self.tab_bar = None # Every group can have one tab bar self.tab_bar_shown = False self.updater = updater self.editor_widgets = [] self._param_names = [] self._create_node_widgets(config) rospy.logdebug('Groups node name={}'.format(nodename)) self.nodename_qlabel.setText(nodename) # Labels should not stretch #self.grid.setColumnStretch(1, 1) #self.setLayout(self.grid) def collect_paramnames(self, config): pass def _create_node_widgets(self, config): ''' :type config: Dict? ''' i_debug = 0 for param in config['parameters']: begin = time.time() * 1000 editor_type = '(none)' if param['edit_method']: widget = EnumEditor(self.updater, param) elif param['type'] in EDITOR_TYPES: rospy.logdebug('GroupWidget i_debug=%d param type =%s', i_debug, param['type']) editor_type = EDITOR_TYPES[param['type']] widget = eval(editor_type)(self.updater, param) self.editor_widgets.append(widget) self._param_names.append(param['name']) rospy.logdebug('groups._create_node_widgets num editors=%d', i_debug) end = time.time() * 1000 time_elap = end - begin rospy.logdebug('ParamG editor={} loop=#{} Time={}msec'.format( editor_type, i_debug, time_elap)) i_debug += 1 for name, group in config['groups'].items(): if group['type'] == 'tab': widget = TabGroup(self, self.updater, group) elif group['type'] in _GROUP_TYPES.keys(): widget = eval(_GROUP_TYPES[group['type']])(self.updater, group) self.editor_widgets.append(widget) rospy.logdebug( 'groups._create_node_widgets ' + #'num groups=%d' + 'name=%s', name) for i, ed in enumerate(self.editor_widgets): ed.display(self.grid) rospy.logdebug('GroupWdgt._create_node_widgets len(editor_widgets)=%d', len(self.editor_widgets)) def display(self, grid, row): # groups span across all columns grid.addWidget(self, row, 0, 1, -1) def update_group(self, config): self.state = config['state'] # TODO: should use config.keys but this method doesnt exist names = [name for name in config.items()] for widget in self.editor_widgets: if isinstance(widget, EditorWidget): if widget.name in names: widget.update_value(config[widget.name]) elif isinstance(widget, GroupWidget): cfg = find_cfg(config, widget.name) widget.update_group(cfg) def close(self): for w in self.editor_widgets: w.close() def get_treenode_names(self): ''' :rtype: str[] ''' return self._param_names def _node_disable_bt_clicked(self): rospy.logdebug('param_gs _node_disable_bt_clicked') self.sig_node_disabled_selected.emit(self._toplevel_treenode_name)
def create_label(name, is_bold=False): qname = QLabel(name) f = QFont() f.setBold(is_bold) qname.setFont(f) return qname
class GroupWidget(QWidget): ''' (Isaac's guess as of 12/13/2012) This class bonds multiple Editor instances that are associated with a single node as a group. ''' # public signal sig_node_disabled_selected = Signal(str) def __init__(self, updater, config, nodename): ''' :param config: :type config: Dictionary? defined in dynamic_reconfigure.client.Client :type nodename: str ''' #TODO figure out what data type 'config' is. It is afterall returned # from dynamic_reconfigure.client.get_parameter_descriptions() # ros.org/doc/api/dynamic_reconfigure/html/dynamic_reconfigure.client-pysrc.html#Client super(GroupWidget, self).__init__() self.state = config['state'] self.name = config['name'] self._toplevel_treenode_name = nodename # TODO: .ui file needs to be back into usage in later phase. # ui_file = os.path.join(rp.get_path('rqt_reconfigure'), # 'resource', 'singlenode_parameditor.ui') # loadUi(ui_file, self) verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(QMargins(0, 0, 0, 0)) _widget_nodeheader = QWidget() _h_layout_nodeheader = QHBoxLayout(_widget_nodeheader) _h_layout_nodeheader.setContentsMargins(QMargins(0, 0, 0, 0)) self.nodename_qlabel = QLabel(self) font = QFont('Trebuchet MS, Bold') font.setUnderline(True) font.setBold(True) # Button to close a node. _icon_disable_node = QIcon.fromTheme('window-close') _bt_disable_node = QPushButton(_icon_disable_node, '', self) _bt_disable_node.setToolTip('Hide this node') _bt_disable_node_size = QSize(36, 24) _bt_disable_node.setFixedSize(_bt_disable_node_size) _bt_disable_node.pressed.connect(self._node_disable_bt_clicked) _h_layout_nodeheader.addWidget(self.nodename_qlabel) _h_layout_nodeheader.addWidget(_bt_disable_node) self.nodename_qlabel.setAlignment(Qt.AlignCenter) font.setPointSize(10) self.nodename_qlabel.setFont(font) grid_widget = QWidget(self) self.grid = QFormLayout(grid_widget) verticalLayout.addWidget(_widget_nodeheader) verticalLayout.addWidget(grid_widget, 1) # Again, these UI operation above needs to happen in .ui file. self.tab_bar = None # Every group can have one tab bar self.tab_bar_shown = False self.updater = updater self.editor_widgets = [] self._param_names = [] self._create_node_widgets(config) rospy.logdebug('Groups node name={}'.format(nodename)) self.nodename_qlabel.setText(nodename) # Labels should not stretch #self.grid.setColumnStretch(1, 1) #self.setLayout(self.grid) def collect_paramnames(self, config): pass def _create_node_widgets(self, config): ''' :type config: Dict? ''' i_debug = 0 for param in config['parameters']: begin = time.time() * 1000 editor_type = '(none)' if param['edit_method']: widget = EnumEditor(self.updater, param) elif param['type'] in EDITOR_TYPES: rospy.logdebug('GroupWidget i_debug=%d param type =%s', i_debug, param['type']) editor_type = EDITOR_TYPES[param['type']] widget = eval(editor_type)(self.updater, param) self.editor_widgets.append(widget) self._param_names.append(param['name']) rospy.logdebug('groups._create_node_widgets num editors=%d', i_debug) end = time.time() * 1000 time_elap = end - begin rospy.logdebug('ParamG editor={} loop=#{} Time={}msec'.format( editor_type, i_debug, time_elap)) i_debug += 1 for name, group in config['groups'].items(): if group['type'] == 'tab': widget = TabGroup(self, self.updater, group) elif group['type'] in _GROUP_TYPES.keys(): widget = eval(_GROUP_TYPES[group['type']])(self.updater, group) self.editor_widgets.append(widget) rospy.logdebug('groups._create_node_widgets ' + #'num groups=%d' + 'name=%s', name) for i, ed in enumerate(self.editor_widgets): ed.display(self.grid) rospy.logdebug('GroupWdgt._create_node_widgets len(editor_widgets)=%d', len(self.editor_widgets)) def display(self, grid, row): # groups span across all columns grid.addWidget(self, row, 0, 1, -1) def update_group(self, config): self.state = config['state'] # TODO: should use config.keys but this method doesnt exist names = [name for name in config.items()] for widget in self.editor_widgets: if isinstance(widget, EditorWidget): if widget.name in names: widget.update_value(config[widget.name]) elif isinstance(widget, GroupWidget): cfg = find_cfg(config, widget.name) widget.update_group(cfg) def close(self): for w in self.editor_widgets: w.close() def get_treenode_names(self): ''' :rtype: str[] ''' return self._param_names def _node_disable_bt_clicked(self): rospy.logdebug('param_gs _node_disable_bt_clicked') self.sig_node_disabled_selected.emit(self._toplevel_treenode_name)