def __init__(self, motion_publisher, robot_config): super(MotionEditorWidget, self).__init__() self.robot_config = robot_config self._motion_publisher = motion_publisher self._motion_data = MotionData(robot_config) self._filter_pattern = '' self._playback_marker = None self._playback_timer = None ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'motion_editor.ui') loadUi(ui_file, self) self.list_widgets = {} for group_type in robot_config.group_types(): list_widget = QListWidget() list_widget.setSortingEnabled(True) list_widget.setDragDropMode(QAbstractItemView.DragOnly) list_widget.setContextMenuPolicy(Qt.CustomContextMenu) list_widget.customContextMenuRequested.connect( lambda pos, _group_type=group_type: self. positions_list_context_menu(_group_type, pos)) list_widget.itemChanged.connect(self.on_list_item_changed) self.position_lists_layout.addWidget(list_widget) self.list_widgets[group_type] = list_widget self._timeline_widget = TimelineWidget() for track_name in self.robot_config.sorted_groups(): track_type = self.robot_config.groups[track_name].group_type track = self._timeline_widget.add_track(track_name, track_type) list_widget = self.list_widgets[track_type] palette = list_widget.palette() palette.setColor(QPalette.Base, track._colors['track']) list_widget.setPalette(palette) self.timeline_group.layout().addWidget(self._timeline_widget) for group_type in robot_config.group_types(): label = QLabel(group_type) label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.group_label_layout.addWidget(label) self.update_motion_name_combo() self.stop_motion_button.pressed.connect(self.on_motion_stop_pressed)
def __init__(self, motion_publisher, robot_config): super(MotionEditorWidget, self).__init__() self.robot_config = robot_config self._motion_publisher = motion_publisher self._motion_data = MotionData(robot_config) self._filter_pattern = '' self._playback_marker = None self._playback_timer = None ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'motion_editor.ui') loadUi(ui_file, self) self.list_widgets = {} for group_type in robot_config.group_types(): list_widget = QListWidget() list_widget.setSortingEnabled(True) list_widget.setDragDropMode(QAbstractItemView.DragOnly) list_widget.setContextMenuPolicy(Qt.CustomContextMenu) list_widget.customContextMenuRequested.connect( lambda pos, _group_type=group_type: self.positions_list_context_menu(_group_type, pos) ) list_widget.itemChanged.connect(self.on_list_item_changed) self.position_lists_layout.addWidget(list_widget) self.list_widgets[group_type] = list_widget self._timeline_widget = TimelineWidget() for track_name in self.robot_config.sorted_groups(): track_type = self.robot_config.groups[track_name].group_type track = self._timeline_widget.add_track(track_name, track_type) list_widget = self.list_widgets[track_type] palette = list_widget.palette() palette.setColor(QPalette.Base, track._colors['track']) list_widget.setPalette(palette) self.timeline_group.layout().addWidget(self._timeline_widget) for group_type in robot_config.group_types(): label = QLabel(group_type) label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.group_label_layout.addWidget(label) self.update_motion_name_combo() self.stop_motion_button.pressed.connect(self.on_motion_stop_pressed)
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 SelectDialog(QDialog): ''' This dialog creates an input mask for a string list and return selected entries. ''' def __init__(self, items=list(), buttons=QDialogButtonBox.Cancel | QDialogButtonBox.Ok, exclusive=False, preselect_all=False, title='', description='', icon='', parent=None, select_if_single=True, checkitem1='', checkitem2='', closein=0): ''' Creates an input dialog. @param items: a list with strings @type items: C{list()} ''' QDialog.__init__(self, parent=parent) self.setObjectName(' - '.join(['SelectDialog', utf8(items)])) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setContentsMargins(1, 1, 1, 1) # add filter row self.filter_frame = QFrame(self) filterLayout = QHBoxLayout(self.filter_frame) filterLayout.setContentsMargins(1, 1, 1, 1) label = QLabel("Filter:", self.filter_frame) self.filter_field = EnchancedLineEdit(self.filter_frame) filterLayout.addWidget(label) filterLayout.addWidget(self.filter_field) self.filter_field.textChanged.connect(self._on_filter_changed) self.verticalLayout.addWidget(self.filter_frame) if description: self.description_frame = QFrame(self) descriptionLayout = QHBoxLayout(self.description_frame) # descriptionLayout.setContentsMargins(1, 1, 1, 1) if icon: self.icon_label = QLabel(self.description_frame) self.icon_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.icon_label.setPixmap( QPixmap(icon).scaled(30, 30, Qt.KeepAspectRatio)) descriptionLayout.addWidget(self.icon_label) self.description_label = QLabel(self.description_frame) self.description_label.setWordWrap(True) self.description_label.setText(description) descriptionLayout.addWidget(self.description_label) self.verticalLayout.addWidget(self.description_frame) # create area for the parameter self.content = MainBox(self) if items: self.scroll_area = QScrollArea(self) self.scroll_area.setFocusPolicy(Qt.NoFocus) self.scroll_area.setObjectName("scroll_area") self.scroll_area.setWidgetResizable(True) self.scroll_area.setWidget(self.content) self.verticalLayout.addWidget(self.scroll_area) self.checkitem1 = checkitem1 self.checkitem1_result = False self.checkitem2 = checkitem2 self.checkitem2_result = False # add select all option if not exclusive and items: self._ignore_next_toggle = False self.select_all_checkbox = QCheckBox('all entries') self.select_all_checkbox.setTristate(True) self.select_all_checkbox.stateChanged.connect( self._on_select_all_checkbox_stateChanged) self.verticalLayout.addWidget(self.select_all_checkbox) self.content.toggled.connect(self._on_main_toggle) if self.checkitem1: self.checkitem1_checkbox = QCheckBox(self.checkitem1) self.checkitem1_checkbox.stateChanged.connect( self._on_select_checkitem1_checkbox_stateChanged) self.verticalLayout.addWidget(self.checkitem1_checkbox) if self.checkitem2: self.checkitem2_checkbox = QCheckBox(self.checkitem2) self.checkitem2_checkbox.stateChanged.connect( self._on_select_checkitem2_checkbox_stateChanged) self.verticalLayout.addWidget(self.checkitem2_checkbox) if not items: spacerItem = QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Expanding) self.verticalLayout.addItem(spacerItem) self._close_timer = None self._closein = closein - 1 if closein > 0: self.closein_label = QLabel("OK in %d sec..." % closein) self.closein_label.setAlignment(Qt.AlignRight) self.verticalLayout.addWidget(self.closein_label) self._close_timer = threading.Timer(1.0, self._on_close_timer) self._close_timer.start() # create buttons self.buttonBox = QDialogButtonBox(self) self.buttonBox.setObjectName("buttonBox") self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(buttons) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.verticalLayout.addWidget(self.buttonBox) # set the input fields if items: self.content.createFieldsFromValues(items, exclusive) if (select_if_single and len(items) == 1) or preselect_all: self.select_all_checkbox.setCheckState(Qt.Checked) if not items or len(items) < 7: self.filter_frame.setVisible(False) # print '=============== create', self.objectName() # # def __del__(self): # print "************ destroy", self.objectName() def _on_main_toggle(self, state): self.cancel_autoclose() self._ignore_next_toggle = state != self.select_all_checkbox.checkState( ) self.select_all_checkbox.setCheckState(state) def _on_select_all_checkbox_stateChanged(self, state): self.cancel_autoclose() if not self._ignore_next_toggle: self.content.setState(state) self._ignore_next_toggle = False def _on_select_checkitem1_checkbox_stateChanged(self, state): self.cancel_autoclose() if state == Qt.Checked: self.checkitem1_result = True elif state == Qt.Unchecked: self.checkitem1_result = False def _on_select_checkitem2_checkbox_stateChanged(self, state): self.cancel_autoclose() if state == Qt.Checked: self.checkitem2_result = True elif state == Qt.Unchecked: self.checkitem2_result = False def _on_filter_changed(self): self.content.filter(self.filter_field.text()) def _on_close_timer(self): self.closein_label.setText("OK in %d sec..." % self._closein) if self._closein == 0: self.buttonBox.accepted.emit() return self._closein -= 1 self._close_timer = threading.Timer(1.0, self._on_close_timer) self._close_timer.start() def cancel_autoclose(self): if self._close_timer is not None: self._close_timer.cancel() self.closein_label.setVisible(False) def getSelected(self): return self.content.getSelected() @staticmethod def getValue(title, description='', items=list(), exclusive=False, preselect_all=False, icon='', parent=None, select_if_single=True, checkitem1='', checkitem2='', closein=0): selectDia = SelectDialog(items, exclusive=exclusive, preselect_all=preselect_all, description=description, icon=icon, parent=parent, select_if_single=select_if_single, checkitem1=checkitem1, checkitem2=checkitem2, closein=closein) selectDia.setWindowTitle(title) selectDia.resize(480, 256) if selectDia.exec_(): if selectDia.checkitem2: return selectDia.getSelected( ), True, selectDia.checkitem1_result, selectDia.checkitem2_result if selectDia.checkitem1: return selectDia.getSelected( ), True, selectDia.checkitem1_result return selectDia.getSelected(), True if selectDia.checkitem2: return list(), False, False, False if selectDia.checkitem1: return list(), False, False return list(), False # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # %%%%%%%%%%%%%%%%%% close handling %%%%%%%%%%%%%%%%%%%%% # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% def accept(self): self.cancel_autoclose() self.setResult(QDialog.Accepted) self.hide() def reject(self): self.cancel_autoclose() self.setResult(QDialog.Rejected) self.hide() def hideEvent(self, event): self.close() def closeEvent(self, event): ''' Test the open files for changes and save this if needed. ''' self.cancel_autoclose() self.setAttribute(Qt.WA_DeleteOnClose, True) QDialog.closeEvent(self, event)
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)
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)
class CalibrationMovementsGUI(QWidget): NOT_INITED_YET = 0 BAD_PLAN = 1 GOOD_PLAN = 2 MOVED_TO_POSE = 3 BAD_STARTING_POSITION = 4 GOOD_STARTING_POSITION = 5 CHECKING_STARTING_POSITION = 6 MOVEMENT_FAILED = 7 def __init__(self): super(CalibrationMovementsGUI, self).__init__() self.handeye_client = HandeyeClient() self.current_target_pose = -1 # -1 is home self.target_poses = None self.plan_was_successful = None self.state = CalibrationMovementsGUI.NOT_INITED_YET self.layout = QVBoxLayout() self.labels_layout = QHBoxLayout() self.buttons_layout = QHBoxLayout() self.progress_bar = QProgressBar() self.pose_number_lbl = QLabel('0/0') self.bad_plan_lbl = QLabel('No plan yet') self.bad_plan_lbl.setAlignment(Qt.AlignCenter) self.guide_lbl = QLabel('Hello') self.guide_lbl.setWordWrap(True) self.check_start_pose_btn = QPushButton('Check starting pose') self.check_start_pose_btn.clicked.connect( self.handle_check_current_state) self.next_pose_btn = QPushButton('Next Pose') self.next_pose_btn.clicked.connect(self.handle_next_pose) self.plan_btn = QPushButton('Plan') self.plan_btn.clicked.connect(self.handle_plan) self.execute_btn = QPushButton('Execute') self.execute_btn.clicked.connect(self.handle_execute) self.labels_layout.addWidget(self.pose_number_lbl) self.labels_layout.addWidget(self.bad_plan_lbl) self.buttons_layout.addWidget(self.check_start_pose_btn) self.buttons_layout.addWidget(self.next_pose_btn) self.buttons_layout.addWidget(self.plan_btn) self.buttons_layout.addWidget(self.execute_btn) self.layout.addWidget(self.progress_bar) self.layout.addLayout(self.labels_layout) self.layout.addWidget(self.guide_lbl) self.layout.addLayout(self.buttons_layout) self.setLayout(self.layout) self.plan_btn.setEnabled(False) self.execute_btn.setEnabled(False) self.setWindowTitle('Local Mover') self.show() def update_ui(self): if self.target_poses: count_target_poses = len(self.target_poses) else: count_target_poses = 1 self.progress_bar.setMaximum(count_target_poses) self.progress_bar.setValue(self.current_target_pose + 1) self.pose_number_lbl.setText('{}/{}'.format( self.current_target_pose + 1, count_target_poses)) if self.state == CalibrationMovementsGUI.BAD_PLAN: self.bad_plan_lbl.setText('BAD plan!! Don\'t do it!!!!') self.bad_plan_lbl.setStyleSheet('QLabel { background-color : red}') elif self.state == CalibrationMovementsGUI.GOOD_PLAN: self.bad_plan_lbl.setText('Good plan') self.bad_plan_lbl.setStyleSheet( 'QLabel { background-color : green}') else: self.bad_plan_lbl.setText('No plan yet') self.bad_plan_lbl.setStyleSheet('') if self.state == CalibrationMovementsGUI.NOT_INITED_YET: self.guide_lbl.setText( 'Bring the robot to a plausible position and check if it is a suitable starting pose' ) elif self.state == CalibrationMovementsGUI.CHECKING_STARTING_POSITION: self.guide_lbl.setText( 'Checking if the robot can translate and rotate in all directions from the current pose' ) elif self.state == CalibrationMovementsGUI.BAD_STARTING_POSITION: self.guide_lbl.setText('Cannot calibrate from current position') elif self.state == CalibrationMovementsGUI.GOOD_STARTING_POSITION: self.guide_lbl.setText('Ready to start: click on next pose') elif self.state == CalibrationMovementsGUI.GOOD_PLAN: self.guide_lbl.setText( 'The plan seems good: press execute to move the robot') elif self.state == CalibrationMovementsGUI.BAD_PLAN: self.guide_lbl.setText('Planning failed: try again') elif self.state == CalibrationMovementsGUI.MOVED_TO_POSE: self.guide_lbl.setText( 'Pose reached: take a sample and go on to next pose') can_plan = self.state == CalibrationMovementsGUI.GOOD_STARTING_POSITION self.plan_btn.setEnabled(can_plan) can_move = self.state == CalibrationMovementsGUI.GOOD_PLAN self.execute_btn.setEnabled(can_move) QCoreApplication.processEvents() def handle_check_current_state(self): self.state = CalibrationMovementsGUI.CHECKING_STARTING_POSITION self.update_ui() res = self.handeye_client.check_starting_pose() if res.can_calibrate: self.state = CalibrationMovementsGUI.GOOD_STARTING_POSITION else: self.state = CalibrationMovementsGUI.BAD_STARTING_POSITION self.current_target_pose = res.target_poses.current_target_pose_index self.target_poses = res.target_poses.target_poses self.plan_was_successful = None self.update_ui() def handle_next_pose(self): res = self.handeye_client.select_target_pose(self.current_target_pose + 1) self.current_target_pose = res.target_poses.current_target_pose_index self.target_poses = res.target_poses.target_poses self.plan_was_successful = None self.state = CalibrationMovementsGUI.GOOD_STARTING_POSITION self.update_ui() def handle_plan(self): self.guide_lbl.setText( 'Planning to the next position. Click on execute when a good one was found' ) res = self.handeye_client.plan_to_selected_target_pose() self.plan_was_successful = res.success if self.plan_was_successful: self.state = CalibrationMovementsGUI.GOOD_PLAN else: self.state = CalibrationMovementsGUI.BAD_PLAN self.update_ui() def handle_execute(self): if self.plan_was_successful: self.guide_lbl.setText('Going to the selected pose') res = self.handeye_client.execute_plan() if res.success: self.state = CalibrationMovementsGUI.MOVED_TO_POSE else: self.state = CalibrationMovementsGUI.MOVEMENT_FAILED self.update_ui()
class SelectDialog(QDialog): ''' This dialog creates an input mask for a string list and return selected entries. ''' def __init__(self, items=list(), buttons=QDialogButtonBox.Cancel | QDialogButtonBox.Ok, exclusive=False, preselect_all=False, title='', description='', icon='', parent=None, select_if_single=True, checkitem1='', checkitem2='', closein=0): ''' Creates an input dialog. @param items: a list with strings @type items: C{list()} ''' QDialog.__init__(self, parent=parent) self.setObjectName(' - '.join(['SelectDialog', utf8(items)])) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setContentsMargins(1, 1, 1, 1) # add filter row self.filter_frame = QFrame(self) filterLayout = QHBoxLayout(self.filter_frame) filterLayout.setContentsMargins(1, 1, 1, 1) label = QLabel("Filter:", self.filter_frame) self.filter_field = EnchancedLineEdit(self.filter_frame) filterLayout.addWidget(label) filterLayout.addWidget(self.filter_field) self.filter_field.textChanged.connect(self._on_filter_changed) self.verticalLayout.addWidget(self.filter_frame) if description: self.description_frame = QFrame(self) descriptionLayout = QHBoxLayout(self.description_frame) # descriptionLayout.setContentsMargins(1, 1, 1, 1) if icon: self.icon_label = QLabel(self.description_frame) self.icon_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.icon_label.setPixmap(QPixmap(icon).scaled(30, 30, Qt.KeepAspectRatio)) descriptionLayout.addWidget(self.icon_label) self.description_label = QLabel(self.description_frame) self.description_label.setWordWrap(True) self.description_label.setText(description) descriptionLayout.addWidget(self.description_label) self.verticalLayout.addWidget(self.description_frame) # create area for the parameter self.content = MainBox(self) if items: self.scroll_area = QScrollArea(self) self.scroll_area.setFocusPolicy(Qt.NoFocus) self.scroll_area.setObjectName("scroll_area") self.scroll_area.setWidgetResizable(True) self.scroll_area.setWidget(self.content) self.verticalLayout.addWidget(self.scroll_area) self.checkitem1 = checkitem1 self.checkitem1_result = False self.checkitem2 = checkitem2 self.checkitem2_result = False # add select all option if not exclusive and items: self._ignore_next_toggle = False self.select_all_checkbox = QCheckBox('all entries') self.select_all_checkbox.setTristate(True) self.select_all_checkbox.stateChanged.connect(self._on_select_all_checkbox_stateChanged) self.verticalLayout.addWidget(self.select_all_checkbox) self.content.toggled.connect(self._on_main_toggle) if self.checkitem1: self.checkitem1_checkbox = QCheckBox(self.checkitem1) self.checkitem1_checkbox.stateChanged.connect(self._on_select_checkitem1_checkbox_stateChanged) self.verticalLayout.addWidget(self.checkitem1_checkbox) if self.checkitem2: self.checkitem2_checkbox = QCheckBox(self.checkitem2) self.checkitem2_checkbox.stateChanged.connect(self._on_select_checkitem2_checkbox_stateChanged) self.verticalLayout.addWidget(self.checkitem2_checkbox) if not items: spacerItem = QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Expanding) self.verticalLayout.addItem(spacerItem) self._close_timer = None self._closein = closein - 1 if closein > 0: self.closein_label = QLabel("OK in %d sec..." % closein) self.closein_label.setAlignment(Qt.AlignRight) self.verticalLayout.addWidget(self.closein_label) self._close_timer = threading.Timer(1.0, self._on_close_timer) self._close_timer.start() # create buttons self.buttonBox = QDialogButtonBox(self) self.buttonBox.setObjectName("buttonBox") self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(buttons) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.verticalLayout.addWidget(self.buttonBox) # set the input fields if items: self.content.createFieldsFromValues(items, exclusive) if (select_if_single and len(items) == 1) or preselect_all: self.select_all_checkbox.setCheckState(Qt.Checked) if not items or len(items) < 7: self.filter_frame.setVisible(False) # print '=============== create', self.objectName() # # def __del__(self): # print "************ destroy", self.objectName() def _on_main_toggle(self, state): self.cancel_autoclose() self._ignore_next_toggle = state != self.select_all_checkbox.checkState() self.select_all_checkbox.setCheckState(state) def _on_select_all_checkbox_stateChanged(self, state): self.cancel_autoclose() if not self._ignore_next_toggle: self.content.setState(state) self._ignore_next_toggle = False def _on_select_checkitem1_checkbox_stateChanged(self, state): self.cancel_autoclose() if state == Qt.Checked: self.checkitem1_result = True elif state == Qt.Unchecked: self.checkitem1_result = False def _on_select_checkitem2_checkbox_stateChanged(self, state): self.cancel_autoclose() if state == Qt.Checked: self.checkitem2_result = True elif state == Qt.Unchecked: self.checkitem2_result = False def _on_filter_changed(self): self.content.filter(self.filter_field.text()) def _on_close_timer(self): self.closein_label.setText("OK in %d sec..." % self._closein) if self._closein == 0: self.buttonBox.accepted.emit() return self._closein -= 1 self._close_timer = threading.Timer(1.0, self._on_close_timer) self._close_timer.start() def cancel_autoclose(self): if self._close_timer is not None: self._close_timer.cancel() self.closein_label.setVisible(False) def getSelected(self): return self.content.getSelected() @staticmethod def getValue(title, description='', items=list(), exclusive=False, preselect_all=False, icon='', parent=None, select_if_single=True, checkitem1='', checkitem2='', closein=0): selectDia = SelectDialog(items, exclusive=exclusive, preselect_all=preselect_all, description=description, icon=icon, parent=parent, select_if_single=select_if_single, checkitem1=checkitem1, checkitem2=checkitem2, closein=closein) selectDia.setWindowTitle(title) selectDia.resize(480, 256) if selectDia.exec_(): if selectDia.checkitem2: return selectDia.getSelected(), True, selectDia.checkitem1_result, selectDia.checkitem2_result if selectDia.checkitem1: return selectDia.getSelected(), True, selectDia.checkitem1_result return selectDia.getSelected(), True if selectDia.checkitem2: return list(), False, False, False if selectDia.checkitem1: return list(), False, False return list(), False # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # %%%%%%%%%%%%%%%%%% close handling %%%%%%%%%%%%%%%%%%%%% # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% def accept(self): self.setResult(QDialog.Accepted) self.hide() def reject(self): self.setResult(QDialog.Rejected) self.hide() def hideEvent(self, event): self.close() def closeEvent(self, event): ''' Test the open files for changes and save this if needed. ''' self.setAttribute(Qt.WA_DeleteOnClose, True) QDialog.closeEvent(self, event)