class SimpleParamTab(QWidget): """Base class shared by all simple parameter tabs""" item_changed = Signal(str, str) item_to_remove = Signal(str) def spnbox_finished(self): sender = self.sender() value = sender.value() str_path = str(sender.local_path) if sender.specialValueText() and value == sender.minimum(): self.item_to_remove.emit(str_path) else: str_value = str(value) self.item_changed.emit(str_path, str_value) def combobox_changed(self, value): sender = self.sender() str_value = str(sender.tmp_lst[value]) str_path = str(sender.local_path) if sender.currentIndex() == sender.default_index: self.item_to_remove.emit(str_path) else: self.item_changed.emit(str_path, str_value)
class CheckStatusThread(QThread): start_busy_box = Signal() end_busy_box = Signal() def __init__(self, parent=None): super(CheckStatusThread, self).__init__() def __call__(self, ref_to_controler): self.ref_to_controler = ref_to_controler self.start() def run(self): prev_stat = None while True: gen_info_stat = self.ref_to_controler.current_node.info_generating time.sleep(0.25) if prev_stat is None and gen_info_stat is True: self.start_busy_box.emit() if gen_info_stat is False: self.end_busy_box.emit() break prev_stat = gen_info_stat time.sleep(0.1)
class MaskPage(QWidget): update_command_lst_medium_level = Signal(list) mask_done = Signal() mask_set = Signal() """ This stacked widget appears when the user wants to do (...) apply_mask, there is no auto-generated GUI form Phil parameters in use withing this widget. """ def __init__(self, parent=None): super(MaskPage, self).__init__(parent=None) main_v_box = QVBoxLayout() label_font = QFont() sys_font_point_size = label_font.pointSize() label_font.setPointSize(sys_font_point_size + 2) step_label = QLabel(str("Apply Mask")) step_label.setFont(label_font) self.my_scroll_area = QScrollArea() self.my_scroll_area.setWidgetResizable(True) self.my_inner_widget = InnerMask(self) self.my_scroll_area.setWidget(self.my_inner_widget) main_v_box.addWidget(step_label) main_v_box.addWidget(self.my_scroll_area) self.setLayout(main_v_box) self.my_widget = self self.show() def gray_me_out(self): # self.something.setEnabled(False) print("gray_me_out(MaskPage)") self.mask_done.emit() def update_param(self, curr_step): print("update_param(MaskPage)") self.update_widget_dat(curr_step.ll_command_lst) def activate_me(self, cur_nod): self.update_widget_dat(cur_nod.ll_command_lst) self.mask_set.emit() def reset_par(self): print("reset_par(MaskPage)") self.command_lst = [["generate_mask"]] def set_par(self, lst_par): print("set_par(MaskPage)", lst_par) self.update_widget_dat(lst_par) self.update_command_lst_medium_level.emit(lst_par[0]) def update_widget_dat(self, lst_par): self.my_inner_widget.update_cmd_lst(lst_par) self.command_lst = lst_par
class QTreeWidgetDrag(QtGui.QTreeWidget): dropped = Signal(str) class QSizeDelegate(QtGui.QItemDelegate): def __init__(self): QtGui.QItemDelegate.__init__(self) def sizeHint(self, option, index): return QtCore.QSize(18, 18) def __init__(self, parent): QtGui.QTreeWidget.__init__(self, parent) self.setAcceptDrops(True) delegate = QTreeWidgetDrag.QSizeDelegate() self.setItemDelegate(delegate) # noinspection PyPep8Naming def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dragMoveEvent(self, event): if event.mimeData().hasUrls: event.setDropAction(QtCore.Qt.CopyAction) event.accept() else: event.ignore() # noinspection PyPep8Naming def dropEvent(self, event): file_list = list() for url in event.mimeData().urls(): path = url.toLocalFile() if os.path.isfile(path): file_list.append(path) if len(file_list) == 1: self.dropped.emit(str(file_list[0])) elif len(file_list) > 1: label_pattern = "Loading file \'%s\' into database" progress = QtGui.QProgressDialog(str(), "Abort", 0, len(file_list), self) progress.setWindowTitle("Import Objects") progress.setWindowModality(QtCore.Qt.WindowModal) progress.show() for k, path in enumerate(file_list): progress.setLabelText(label_pattern % helpers.GetFilename(path)) self.dropped.emit(str(path)) progress.setValue(k) if progress.wasCanceled(): break progress.setValue(len(file_list)) progress.close()
class ConfigurationTab(QStackWidgetTab): finished = Signal(SimulationSetsPayload) def __init__(self, parent, core): """ :param QtGui.QWidget parent: Parent widget """ super(ConfigurationTab, self).__init__(parent) self.__core = core self.__input_variables_box = InputVariablesBox(self, self.__core.options) self.__output_variables_box = OutputVariableBox(self, self.__core) connect(self.__input_variables_box.variablesChanged, self.__output_variables_box.set_input_variables) connect(self.__input_variables_box.valuesChanged, self.__output_variables_box.set_input_values) self.__layout = QtGui.QVBoxLayout(self) self.__layout.addWidget(self.__input_variables_box) self.__layout.addWidget(self.__output_variables_box) # self.__layout.addStretch() connect(self.__output_variables_box.finished, self.onFinished) # noinspection PyPep8Naming @Slot(SimulationSetsPayload) def onFinished(self, results): self.finished.emit(results) def onSetActive(self): self.__input_variables_box.setObject(self.__core.options)
class ParamWidget(QWidget): update_command_lst_medium_level = Signal(list) def __init__(self, label_str): super(ParamWidget, self).__init__() self.my_label = label_str inner_widgs = { "find_spots": [phil_scope_find_spots, FindspotsSimplerParameterTab], "index": [phil_scope_index, IndexSimplerParamTab], "refine_bravais_settings": [ phil_scope_r_b_settings, RefineBravaiSimplerParamTab, ], "refine": [phil_scope_refine, RefineSimplerParamTab], "integrate": [phil_scope_integrate, IntegrateSimplerParamTab], "symmetry": [phil_scope_symetry, SymmetrySimplerParamTab], "scale": [phil_scope_scale, ScaleSimplerParamTab], } if label_str == "import": self.my_widget = ImportPage() elif label_str == "export": self.my_widget = ExportPage() else: self.my_widget = ParamMainWidget( phl_obj=inner_widgs[label_str][0], simp_widg=inner_widgs[label_str][1], parent=self, upper_label=label_str, ) self.my_widget.command_lst = [[label_str]] self.my_widget.update_command_lst_low_level.connect( self.update_parent_lst) v_left_box = QVBoxLayout() v_left_box.addWidget(self.my_widget) self.setLayout(v_left_box) # comment next line to avoid ugly pops at launch # self.show() def update_param(self, curr_step): self.my_widget.update_param_w_lst(curr_step.ll_command_lst[0]) def update_parent_lst(self, command_lst): self.update_command_lst_medium_level.emit(command_lst)
class CommandThread(QThread): str_print_signal = Signal(str) str_fail_signal = Signal() busy_box_on = Signal(str) busy_box_off = Signal() def __init__(self, parent=None): super(CommandThread, self).__init__() def __call__(self, cmd_to_run, ref_to_controler): self.cmd_to_run = cmd_to_run self.ref_to_controler = ref_to_controler self.status_thread = CheckStatusThread() self.status_thread(self.ref_to_controler) self.status_thread.start_busy_box.connect(self.pop_busy_box) self.status_thread.end_busy_box.connect(self.close_busy_box) self.start() def run(self): print("self.cmd_to_run =", self.cmd_to_run) self.ref_to_controler.run(command=self.cmd_to_run, ref_to_class=self) def emit_print_signal(self, str_lin): self.str_print_signal.emit(str_lin) def emit_fail_signal(self): self.str_fail_signal.emit() def pop_busy_box(self): logger.debug("emiting pop busy box signal") self.busy_box_on.emit("Getting Predictions or Report") def close_busy_box(self): logger.debug("emiting close busy box signal") self.busy_box_off.emit()
class IndexSimplerParamTab(QWidget): """ This widget is the tool for tunning the simpler and most common parameters in the indexer, this widget is the first to appear once the button "Index" at the left side of the GUI is clicked """ item_changed = Signal(str, str) def __init__(self, phl_obj=None, parent=None): super(IndexSimplerParamTab, self).__init__() # self.param_widget_parent = parent.param_widget_parent # indexing_method_check = QCheckBox("indexing.method") hbox_method = QHBoxLayout() label_method_62 = QLabel("Indexing Method") hbox_method.addWidget(label_method_62) box_method_62 = QComboBox() box_method_62.tmp_lst = [] box_method_62.local_path = "indexing.method" box_method_62.tmp_lst.append("fft3d") box_method_62.tmp_lst.append("fft1d") box_method_62.tmp_lst.append("real_space_grid_search") box_method_62.tmp_lst.append("low_res_spot_match") for lst_itm in box_method_62.tmp_lst: box_method_62.addItem(lst_itm) box_method_62.currentIndexChanged.connect(self.combobox_changed) hbox_method.addWidget(box_method_62) localLayout = QVBoxLayout() localLayout.addLayout(hbox_method) self.inner_reset_btn = ResetButton() localLayout.addWidget(self.inner_reset_btn) localLayout.addStretch() self.setLayout(localLayout) self.lst_var_widg = _get_all_direct_layout_widget_children(localLayout) def combobox_changed(self, value): sender = self.sender() str_value = str(sender.tmp_lst[value]) str_path = str(sender.local_path) # self.param_widget_parent.update_lin_txt(str_path, str_value) self.item_changed.emit(str_path, str_value)
class RefineBravaiSimplerParamTab(QWidget): # TODO some doc string here item_changed = Signal(str, str) def __init__(self, parent=None): super(RefineBravaiSimplerParamTab, self).__init__() localLayout = QVBoxLayout() hbox_lay_outlier_algorithm = QHBoxLayout() label_outlier_algorithm = QLabel("Outlier Rejection Algorithm") hbox_lay_outlier_algorithm.addWidget(label_outlier_algorithm) box_outlier_algorithm = QComboBox() box_outlier_algorithm.local_path = "refinement.reflections.outlier.algorithm" box_outlier_algorithm.tmp_lst = [] box_outlier_algorithm.tmp_lst.append("null") box_outlier_algorithm.tmp_lst.append("auto") box_outlier_algorithm.tmp_lst.append("mcd") box_outlier_algorithm.tmp_lst.append("tukey") box_outlier_algorithm.tmp_lst.append("sauter_poon") for lst_itm in box_outlier_algorithm.tmp_lst: box_outlier_algorithm.addItem(lst_itm) box_outlier_algorithm.setCurrentIndex(1) box_outlier_algorithm.currentIndexChanged.connect( self.combobox_changed) hbox_lay_outlier_algorithm.addWidget(box_outlier_algorithm) localLayout.addLayout(hbox_lay_outlier_algorithm) self.inner_reset_btn = ResetButton() localLayout.addWidget(self.inner_reset_btn) localLayout.addStretch() self.setLayout(localLayout) self.lst_var_widg = [] self.lst_var_widg.append(box_outlier_algorithm) self.lst_var_widg.append(label_outlier_algorithm) def combobox_changed(self, value): sender = self.sender() str_value = str(sender.tmp_lst[value]) str_path = str(sender.local_path) # self.param_widget_parent.update_lin_txt(str_path, str_value) self.item_changed.emit(str_path, str_value)
class SymmetrySimplerParamTab(QWidget): """ This widget is the tool for tunning the simpler and most common parameters in the symmetry command, this widget is the first to appear once the button "Symmetry" at the left side of the GUI is clicked """ item_changed = Signal(str, str) def __init__(self, parent=None): super(SymmetrySimplerParamTab, self).__init__() hbox_d_min = QHBoxLayout() localLayout = QVBoxLayout() label_d_min = QLabel("d_min") hbox_d_min.addWidget(label_d_min) d_min_spn_bx = QDoubleSpinBox() d_min_spn_bx.local_path = "d_min" d_min_spn_bx.setSpecialValueText("Auto") d_min_spn_bx.setValue(0.0) hbox_d_min.addWidget(d_min_spn_bx) d_min_spn_bx.valueChanged.connect(self.spnbox_changed) localLayout.addLayout(hbox_d_min) self.inner_reset_btn = ResetButton() localLayout.addWidget(self.inner_reset_btn) localLayout.addStretch() self.setLayout(localLayout) self.lst_var_widg = [] self.lst_var_widg.append(d_min_spn_bx) self.lst_var_widg.append(label_d_min) def spnbox_changed(self, value): sender = self.sender() str_value = str(value) logger.debug(value) str_path = str(sender.local_path) self.item_changed.emit(str_path, str_value)
class ParamMainWidget(QWidget): update_command_lst_low_level = Signal(list) def __init__(self, phl_obj=None, simp_widg=None, parent=None, upper_label=None): super(ParamMainWidget, self).__init__() self.command_lst = [[None]] self.lst_pair = [] try: self.my_phl_obj = phl_obj self.simp_widg_in = simp_widg except BaseException as e: # We don't want to catch bare exceptions but don't know # what this was supposed to catch. Log it. logger.info("Caught unknown exception #1 type %s: %s", type(e).__name__, e) logger.info("\n\n\n something went wrong here wiht the phil object \n\n\n") self.build_param_widget() label_font = QFont() sys_font_point_size = label_font.pointSize() label_font.setPointSize(sys_font_point_size + 2) self.step_label = QLabel(str(upper_label)) self.step_label.setFont(label_font) self._vbox = QVBoxLayout() self._vbox.addWidget(self.step_label) self._vbox.addWidget(self.dual_level_tab) self.setLayout(self._vbox) # self.show() def build_param_widget(self): self.dual_level_tab = QTabWidget() self.simpler_widget = self.simp_widg_in() self.advanced_widget = ParamAdvancedWidget(phl_obj=self.my_phl_obj, parent=self) self.advanced_widget.scrollable_widget.item_changed.connect(self.update_lin_txt) try: self.simpler_widget.item_changed.connect(self.update_advanced_widget) except BaseException as e: # We don't want to catch bare exceptions but don't know # what this was supposed to catch. Log it. logger.info("Caught unknown exception #2 type %s: %s", type(e).__name__, e) logger.info("found self.simpler_widget without << item_changed >> signal") try: self.simpler_widget.item_to_remove.connect(self.remove_one_par) except AttributeError: pass self.reset_btn = self.simpler_widget.inner_reset_btn self.dual_level_tab.addTab(self.simpler_widget, "Simple") self.dual_level_tab.addTab(self.advanced_widget, "Advanced") self.reset_btn.clicked.connect(self.reset_par) def reset_par(self): for i in reversed(list(range(self._vbox.count()))): widgetToRemove = self._vbox.itemAt(i).widget() self._vbox.removeWidget(widgetToRemove) widgetToRemove.setParent(None) self.build_param_widget() self._vbox.addWidget(self.step_label) self._vbox.addWidget(self.dual_level_tab) self.command_lst[0] = [self.command_lst[0][0]] self.lst_pair = [] self.update_command_lst_low_level.emit(self.command_lst[0]) try: max_nproc = self.simpler_widget.set_max_nproc() if max_nproc > 1: self.raise_nproc_str = ( str(self.simpler_widget.box_nproc.local_path) + "=" + str(max_nproc) ) QTimer.singleShot(1000, self.raise_nproc_to_max) except AttributeError: pass def raise_nproc_to_max(self): found_nproc = False for single_par in self.command_lst[0]: if "mp.nproc" in single_par: found_nproc = True if not found_nproc: self.command_lst[0].append(self.raise_nproc_str) self.update_command_lst_low_level.emit(self.command_lst[0]) def update_advanced_widget(self, str_path, str_value): for bg_widg in ( self.advanced_widget.scrollable_widget.lst_var_widg, self.simpler_widget.lst_var_widg, ): for widg in bg_widg: try: if widg.local_path == str_path: if not hasattr(widg, "tmp_lst") or widg.tmp_lst is None: try: num_val = float(str_value) widg.setValue(num_val) except BaseException: try: str_val = str(str_value) widg.setText(str_val) logger.debug( "widg.local_path = %s", widg.local_path ) except BaseException as ee: logger.info("ee = ", ee) else: for pos, val in enumerate(widg.tmp_lst): if val == str_value: try: widg.setCurrentIndex(pos) except BaseException as e: # We don't want to catch bare exceptions but # dont know what this was supposed to catch. logger.info( "Caught unknown exception #5 type: %s", e ) logger.info("failed to:") logger.info("widg.setCurrentIndex(pos)") except AttributeError: pass def update_simpler_widget(self, str_path, str_value): for widg in self.simpler_widget.lst_var_widg: try: if widg.local_path == str_path: logger.debug("found << widg.local_path == str_path >> ") try: num_val = float(str_value) widg.setValue(num_val) except ValueError: for pos, val in enumerate(widg.tmp_lst): if val == str_value: logger.info("found val, v= %s", val) widg.setCurrentIndex(pos) except AttributeError: pass def update_lin_txt(self, str_path, str_value): # cmd_to_run = str_path + "=" + str_value self.update_advanced_widget(str_path, str_value) self.update_simpler_widget(str_path, str_value) self.lst_pair = update_lst_pair(self.lst_pair, str_path, str_value) self.command_lst[0] = build_lst_str(self.command_lst[0][0], self.lst_pair) self.update_command_lst_low_level.emit(self.command_lst[0]) def update_param_w_lst(self, lst_in, do_reset=True): if do_reset: self.reset_par() if len(lst_in) > 1: self.lst_pair = buils_lst_pair(lst_in) self.command_lst[0] = build_lst_str(lst_in[0], self.lst_pair) for pair in self.lst_pair: self.update_advanced_widget(pair[0], pair[1]) else: self.lst_pair = [] self.command_lst[0] = lst_in def remove_one_par(self, path_str): nxt_lst = [] for single_param in self.command_lst[0]: if str(path_str) in single_param: pass else: nxt_lst.append(str(single_param)) self.update_param_w_lst(nxt_lst, do_reset=False) def gray_me_out(self): self.reset_btn.setEnabled(False) palt_gray = QPalette() palt_gray.setColor(QPalette.WindowText, QColor(88, 88, 88, 88)) for bg_widg in ( self.advanced_widget.scrollable_widget.lst_var_widg, self.advanced_widget.scrollable_widget.lst_label_widg, self.simpler_widget.lst_var_widg, ): for widg in bg_widg: widg.setStyleSheet("color: rgba(88, 88, 88, 88)") try: widg.setEnabled(False) except BaseException as e: # We don't want to catch bare exceptions but don't know # what this was supposed to catch. Log it. logger.info( "Caught unknown exception #9 type %s: %s", type(e).__name__, e ) pass def activate_me(self, cur_nod=None): self.reset_btn.setEnabled(True) for bg_widg in ( self.advanced_widget.scrollable_widget.lst_var_widg, self.advanced_widget.scrollable_widget.lst_label_widg, self.simpler_widget.lst_var_widg, ): for widg in bg_widg: widg.setStyleSheet("color: rgba(0, 0, 0, 255)") try: widg.setStyleSheet(widg.style_orign) except AttributeError: pass try: widg.setEnabled(True) except BaseException as e: # We don't want to catch bare exceptions but don't know # what this was supposed to catch. Log it. logger.info( "Caught unknown exception #11 type %s: %s", type(e).__name__, e )
class QProcessStack(QtGui.QGroupBox): rowChanged = Signal(int) def _create_button(self, icon_directory, handler): button = QtGui.QPushButton(str(), self) button.setIcon(Resources(icon_directory)) button.setIconSize(QtCore.QSize(26, 26)) button.setFixedSize(QtCore.QSize(36, 36)) button.setEnabled(False) connect(button.clicked, handler) self.__header_layout.addWidget(button) return button def __init__(self, parent, model, load_dialog): """ :param QtGui.QWidget parent: Widget parent :param QProcessStackModel model: GUI data model :param LoadMaterialDialog load_dialog: Material dialog loader """ QtGui.QGroupBox.__init__(self, "Process Stack", parent) self.setObjectName("QProcessStack") self.__data_model = model self.__load_material_dlg = load_dialog self.__header_layout = QtGui.QHBoxLayout() self.__add_button = self._create_button("icons/Plus", self.insert_layer) self.__remove_button = self._create_button("icons/Minus", self.remove_layer) self.__up_button = self._create_button("icons/ArrowUp", self.layer_upper) self.__down_button = self._create_button("icons/ArrowDown", self.layer_lower) self.__header_layout.addStretch(1) self.__process_table = QProcessStackTable(self, self.__data_model) # PySide crash if not create temporary variable selection_model = self.__process_table.selectionModel() connect(selection_model.selectionChanged, self._item_changed) # Even selection automatically changed when endMoveRows perform selectionChanged not emitted connect(self.__data_model.rowsMoved, self._item_changed) self.__layout = QtGui.QVBoxLayout(self) self.__layout.addLayout(self.__header_layout) self.__layout.addWidget(self.__process_table) def _can_stack_be_edit(self, *rows): """ Check if layer can be removed, move up or down in the stack :type rows: tuple of int :rtype: bool """ for row in rows: if row >= self.__data_model.rowCount() or \ isinstance(self.__data_model[row], (options.structures.Substrate, options.structures.Resist)): return False return True @Slot(QtCore.QModelIndex, int, int, QtCore.QModelIndex, int) @Slot(QtGui.QItemSelection, QtGui.QItemSelection) def _item_changed(self, *args): self.__add_button.setEnabled(True) row = self.__process_table.current_row() self.__remove_button.setEnabled(self._can_stack_be_edit(row)) # Because the top layer always must be resist self.__up_button.setEnabled(self._can_stack_be_edit(row - 1, row)) # Because bottom layer always must be substrate self.__down_button.setEnabled(self._can_stack_be_edit(row, row + 1)) self.rowChanged.emit(row) def insert_layer(self): logging.info("Insert layer") if self.__load_material_dlg.exec_(): logging.info("%s, parametric: %s" % (self.__load_material_dlg.material, self.__load_material_dlg.is_parametric)) # If top layer selected then add index because top layer must be resist row = self.__process_table.current_row( ) if self.__process_table.current_row() != 0 else 1 if self.__load_material_dlg.is_parametric: stack_layer = options.structures.StandardLayer.parametric( self.__data_model.resist.exposure.wavelength, config.DEFAULT_LAYER_REAL_INDEX, config.DEFAULT_LAYER_IMAG_INDEX, config.DEFAULT_LAYER_THICKNESS) else: stack_layer = options.structures.StandardLayer( self.__load_material_dlg.material, config.DEFAULT_LAYER_THICKNESS) self.__data_model.insertRow(row, stack_layer) self.__process_table.selectRow(row) def remove_layer(self): self.__data_model.removeRow(self.__process_table.current_row()) def layer_upper(self): row = self.__process_table.current_row() self.__data_model.moveRows(row, row - 1) def layer_lower(self): row = self.__process_table.current_row() self.__data_model.moveRows(row + 1, row) def current_row(self): return self.__process_table.current_row()
class BeamCentrPage(QWidget): update_command_lst_medium_level = Signal(list) """ This stacked widget appears when the user wants to set manually the beam center, there is no auto-generated GUI form Phil parameters in use withing this widget. """ b_centr_done = Signal() b_centr_set = Signal() def __init__(self, parent=None): super(BeamCentrPage, self).__init__(parent=None) main_v_box = QVBoxLayout() label_font = QFont() sys_font_point_size = label_font.pointSize() label_font.setPointSize(sys_font_point_size + 2) step_label = QLabel(str("Modify Geometry")) step_label.setFont(label_font) self.data_bc_label = QLabel(str("empty Data ... for now")) main_v_box.addWidget(step_label) main_v_box.addStretch() main_v_box.addWidget(self.data_bc_label) main_v_box.addStretch() self.setLayout(main_v_box) self.command_lst = [["modify_geometry"]] self.show() self.my_widget = self def gray_me_out(self): # self.something.setEnabled(False) self.b_centr_done.emit() logger.info("gray_me_out(BeamCentrPage)") def update_param(self, curr_step): logger.info("update_param(BeamCentrPage)") logger.info("curr_step.ll_command_lst:", curr_step.ll_command_lst) def activate_me(self, cur_nod=None): self.b_centr_set.emit() def reset_par(self): logger.info("reset_par(BeamCentrPage)") def set_par(self, lst_par): logger.info("set_par(BeamCentrPage)", lst_par) self.data_bc_label.setText( "New beam centre:\n (" + str(lst_par[0]) + ", " + str(lst_par[1]) + ") pixels" ) ml_lst_par = [ "modify_geometry", "geometry.detector.slow_fast_beam_centre=" + str(lst_par[1]) + "," + str(lst_par[0]), ] self.command_lst = [ml_lst_par] self.update_command_lst_medium_level.emit(ml_lst_par)
class FindspotsSimplerParameterTab(QWidget): """ This widget is the tool for tunning the simpler and most common parameters in the spot-finder, this widget is the first to appear once the button "Find Sots" at the left side of the GUI is clicked """ item_changed = Signal(str, str) def __init__(self, parent=None): super(FindspotsSimplerParameterTab, self).__init__() # self.param_widget_parent = parent.param_widget_parent #TODO thinks about making "None equivalent to 1" xds_gain_label = QLabel("Gain") xds_gain_spn_bx = QDoubleSpinBox() xds_gain_spn_bx.local_path = "spotfinder.threshold.dispersion.gain" xds_gain_spn_bx.setSpecialValueText("None") xds_gain_spn_bx.setValue(1.0) xds_gain_spn_bx.valueChanged.connect(self.spnbox_changed) xds_sigma_background_label = QLabel("Sigma Background") xds_sigma_background_spn_bx = QDoubleSpinBox() xds_sigma_background_spn_bx.setValue(6.0) xds_sigma_background_spn_bx.local_path = ( "spotfinder.threshold.dispersion.sigma_background") xds_sigma_background_spn_bx.valueChanged.connect(self.spnbox_changed) xds_sigma_strong_label = QLabel("Sigma Strong") xds_sigma_strong_spn_bx = QDoubleSpinBox() xds_sigma_strong_spn_bx.setValue(3.0) xds_sigma_strong_spn_bx.local_path = ( "spotfinder.threshold.dispersion.sigma_strong") xds_sigma_strong_spn_bx.valueChanged.connect(self.spnbox_changed) xds_global_threshold_label = QLabel("Global Threshold") xds_global_threshold_spn_bx = QDoubleSpinBox() xds_global_threshold_spn_bx.local_path = ( "spotfinder.threshold.dispersion.global_threshold") xds_global_threshold_spn_bx.valueChanged.connect(self.spnbox_changed) localLayout = QVBoxLayout() xds_gain_hb = QHBoxLayout() xds_gain_hb.addWidget(xds_gain_label) xds_gain_hb.addWidget(xds_gain_spn_bx) localLayout.addLayout(xds_gain_hb) xds_sigma_background_hb = QHBoxLayout() xds_sigma_background_hb.addWidget(xds_sigma_background_label) xds_sigma_background_hb.addWidget(xds_sigma_background_spn_bx) localLayout.addLayout(xds_sigma_background_hb) xds_sigma_strong_hb = QHBoxLayout() xds_sigma_strong_hb.addWidget(xds_sigma_strong_label) xds_sigma_strong_hb.addWidget(xds_sigma_strong_spn_bx) localLayout.addLayout(xds_sigma_strong_hb) xds_global_threshold_hb = QHBoxLayout() xds_global_threshold_hb.addWidget(xds_global_threshold_label) xds_global_threshold_hb.addWidget(xds_global_threshold_spn_bx) localLayout.addLayout(xds_global_threshold_hb) hbox_lay_nproc = QHBoxLayout() label_nproc = QLabel("Number of Jobs") # label_nproc.setPalette(palette_object) # label_nproc.setFont( QFont("Monospace", 10)) hbox_lay_nproc.addWidget(label_nproc) self.box_nproc = QSpinBox() self.box_nproc.local_path = "spotfinder.mp.nproc" self.box_nproc.valueChanged.connect(self.spnbox_changed) hbox_lay_nproc.addWidget(self.box_nproc) localLayout.addLayout(hbox_lay_nproc) self.inner_reset_btn = ResetButton() localLayout.addWidget(self.inner_reset_btn) localLayout.addStretch() self.setLayout(localLayout) self.lst_var_widg = _get_all_direct_layout_widget_children(localLayout) def spnbox_changed(self, value): sender = self.sender() str_value = str(value) logger.debug(value) str_path = str(sender.local_path) # self.param_widget_parent.update_lin_txt(str_path, str_value) self.item_changed.emit(str_path, str_value) def set_max_nproc(self): cpu_max_proc = int(libtbx.introspection.number_of_processors()) self.box_nproc.setValue(cpu_max_proc) return cpu_max_proc
class OutputVariableBox(AbstractGroupBox): finished = Signal(SimulationSetsPayload) def __init__(self, parent, core): super(OutputVariableBox, self).__init__("Output variable", parent) self.__output_variable_tree = OutputVariableTree(self, core) connect(self.__output_variable_tree.itemSelectionChanged, self.onTreeItemSelectionChanged) self.__control_widget = SimulationSetsControl(self, core) self.__layout_accres = QtGui.QHBoxLayout() self.__button_accept = QtGui.QPushButton("Accept", self) connect(self.__button_accept.clicked, self.onAcceptButtonClicked) self.__button_accept.setEnabled(False) self.__button_reset = QtGui.QPushButton("Reset", self) connect(self.__button_reset.clicked, self.onResetButtonClicked) self.__button_reset.setEnabled(False) self.__layout_accres.addWidget(self.__button_accept) self.__layout_accres.addWidget(self.__button_reset) self.__layout_tree = QtGui.QVBoxLayout() self.__layout_tree.addWidget(self.__output_variable_tree) self.__layout_tree.addLayout(self.__layout_accres) self.__layout = QtGui.QHBoxLayout(self) self.__layout.addLayout(self.__layout_tree) self.__layout.addWidget(self.__control_widget) connect(self.__control_widget.finished, self.onFinished) # noinspection PyPep8Naming @Slot(SimulationSetsPayload) def onFinished(self, results): self.finished.emit(results) # noinspection PyPep8Naming @Slot() def onTreeItemSelectionChanged(self): items = self.__output_variable_tree.selectedItems() self.__button_accept.setEnabled(self.__output_variable_tree.stage is None and bool(items)) self.__button_reset.setEnabled(self.__output_variable_tree.stage is not None) # noinspection PyPep8Naming @Slot() def onAcceptButtonClicked(self): items = self.__output_variable_tree.selectedItems() self.__output_variable_tree.stage = items[0].text(OutputVariableTree.NAME_COLUMN) self.__control_widget.stage = self.__output_variable_tree.stage self.__output_variable_tree.clearSelection() # noinspection PyPep8Naming @Slot() def onResetButtonClicked(self): self.__output_variable_tree.stage = None self.__control_widget.stage = None self.__output_variable_tree.clearSelection() @Slot(list) def set_input_variables(self, data): self.__control_widget.set_input_variables(data) @Slot(dict) def set_input_values(self, data): self.__control_widget.set_input_values(data)
class SimulationSetsControl(QtGui.QWidget): SET_NAME_PATTERN = "Set #%s" RESULT_VALUE_PATTERN = "%s" launched = Signal(str) finished = Signal(SimulationSetsPayload) def __init__(self, parent, core): super(SimulationSetsControl, self).__init__(parent) self.__core = core self.__layout = QtGui.QVBoxLayout(self) self.__label_info = QtGui.QLabel( "Pressing launch button simulation set will be performed \n" "for given input variable till final selected stage not reached.", self) self.__label_final_value = QtGui.QLabel("Simulation set result value:") self.__edit_final_value = QtGui.QLineEdit(self) self.__edit_final_value.setReadOnly(True) self.__edit_final_value.setFixedWidth(300) self.__layout_control = QtGui.QHBoxLayout() self.__button_launch = QtGui.QPushButton("Launch Simulations", self) self.__button_launch.setFixedWidth(165) self.__button_launch.setEnabled(False) self.__edit_set_name = QtGui.QLineEdit(self.SET_NAME_PATTERN % 1, self) self.__edit_set_name.setFixedWidth(125) self.__layout_control.addWidget(self.__edit_set_name) self.__layout_control.addWidget(self.__button_launch) self.__layout_control.setAlignment(QtCore.Qt.AlignLeft) connect(self.__button_launch.clicked, self.__onLaunchButtonClicked) self.__label_progress_info = QtGui.QLabel("Simulation set progress:") self.__progress_bar = QtGui.QProgressBar() self.__layout.addWidget(self.__label_info) self.__layout.addSpacing(20) self.__layout.addWidget(self.__label_final_value) self.__layout.addWidget(self.__edit_final_value) self.__layout.addLayout(self.__layout_control) self.__layout.addSpacing(20) self.__layout.addWidget(self.__label_progress_info) self.__layout.addWidget(self.__progress_bar) self.__layout.setAlignment(QtCore.Qt.AlignTop) self.wait_box = msgBox(msgBox.NoIcon, "Simulations", "Please, wait...", msgBox.Abort, self) self.__payload = SimulationSetsPayload() connect(self.launched, self.__payload.task) connect(self.__payload.taskStarted, self.__onTaskStarted) connect(self.__payload.taskDone, self.__onTaskDone) connect(self.__payload.calculationDone, self.__onCalculationDone) # noinspection PyPep8Naming @Slot() def __onLaunchButtonClicked(self): connect(self.__payload.stage.invalidated, self.__onStageInvalidated) worker = QWorker(self.__payload, objectName="WorkerThread") worker.start() self.launched.emit(self.__edit_set_name.text()) self.wait_box.exec_() if not self.__payload.done: worker.quit() worker.wait() # noinspection PyPep8Naming @Slot(int) def __onTaskStarted(self, count): # logging.info("Initialize progress bar in '%s'" % thread_name()) self.__progress_bar.setFormat("%%p%% (%%v/%s)" % count) self.__progress_bar.setRange(0, count) self.__progress_bar.setValue(0) # noinspection PyPep8Naming @Slot(bool) def __onTaskDone(self): # logging.info("Simulation set done '%s'" % thread_name()) self.wait_box.close() self.finished.emit(self.__payload) # noinspection PyPep8Naming @Slot() def __onCalculationDone(self): number = self.__progress_bar.value() + 1 # logging.info("Calculation #%s done reported by '%s'" % (number, thread_name())) self.__progress_bar.setValue(number) # noinspection PyPep8Naming @Slot() def __onStageInvalidated(self): # logging.info("Wake all waiting variable in '%s'" % thread_name()) self.__payload.variable_changed.wakeAll() @property def stage(self): return self.__stage @stage.setter def stage(self, stage): if stage is not None: text = self.RESULT_VALUE_PATTERN % stage.name self.__edit_final_value.setText(text) else: self.__edit_final_value.setText(str()) self.__payload.stage = stage self.__button_launch.setEnabled(self.__payload.is_config_ok) def set_input_variables(self, data): self.__payload.variables = data self.__button_launch.setEnabled(self.__payload.is_config_ok) def set_input_values(self, data): self.__payload.values = data self.__button_launch.setEnabled(self.__payload.is_config_ok)
class SimulationSetsPayload(QtCore.QObject): calculationDone = Signal() taskStarted = Signal(int) taskDone = Signal() def __init__(self): super(SimulationSetsPayload, self).__init__() self.name = None self.stage = None """:type: core.AbstractStage""" self.variables = [] """:type: list of QObjectNumeric""" self.values = dict() self.mutex = QtCore.QMutex() self.variable_changed = QtCore.QWaitCondition() self.calculation_results = None self.__aborted = False self.__done = False @property def aborted(self): return self.__aborted @property def done(self): return self.__done @property def is_config_ok(self): is_variables = bool(self.variables) is_stage = self.stage is not None is_values = True if len(self.variables) == len(self.values): for values in self.values.values(): # logging.info("Values: %s" % values) if set(values.keys()) != {"START", "STOP", "INTERVAL"}: is_values = False break else: is_values = False # logging.info("%s %s %s" % (is_variables, is_stage, is_values)) return is_variables and is_values and is_stage @Slot() def start(self): # logging.info( # "Starting simulation set in %s with %s to stage: %s" % # (thread_name(), self.variables, self.stage)) self.name = None self.__aborted = False self.__done = False def __move_to_main_thread(self): # noinspection PyArgumentList main_thread = QtGui.QApplication.instance().thread() self.moveToThread(main_thread) def __restore(self, backup): for variable in self.variables: variable.value = backup[variable] @Slot(str) def task(self, task_name): self.name = task_name # logging.info("Preparing calculation in '%s'" % thread_name()) backup_variables = {} arrays = [] for variable in self.variables: # self.mutex.lock() # variable.value = None backup_variables[variable] = variable.value arrays.append(make_range(**self.values[variable])) # self.variable_changed.wait(self.mutex) # self.mutex.unlock() calculation_points = cartesian(*arrays) self.taskStarted.emit(len(calculation_points)) self.calculation_results = list() # logging.info("Run calculation of the simulation set in '%s'" % thread_name()) for calculation_point in calculation_points: # logging.debug("Mutex lock") self.mutex.lock() for variable, value in zip(self.variables, calculation_point): # logging.debug("Change variable from thread %s to %s" % (thread_name(), value)) variable.value = value # Workaround for thread not to hangs up, wait no more than one second for k in range(100): # while self.stage.has_result: # logging.info("Waiting for all variables changed and stage invalidated in '%s'" % thread_name()) # if self.variable_changed.wait(self.mutex, 10): # logging.info("Variables changed done") if self.variable_changed.wait(self.mutex, 10) and not self.stage.has_result: break else: logging.warning("Stop waiting of all variables changed and stage invalidated in '%s'" % thread_name()) if self.__aborted: logging.info("Task abort reported by '%s'" % thread_name()) self.mutex.unlock() self.__restore(backup_variables) self.__move_to_main_thread() break # logging.info("Run stage calculation '%s'" % thread_name()) try: self.calculation_results.append(self.stage.calculate()) except Exception: self.calculation_results.append(None) logging.error("Error during calculation") # else: # logging.info("Stage calculation done '%s'" % thread_name()) # self.metrics[] = {metric: SimulationSetsPayload.calc(metric, result) for metric in self.stage.metrics} # logging.info("'%s': Result at %s = %s" % (thread_name(), calculation_point, metrics)) self.calculationDone.emit() # logging.debug("Mutex unlock") self.mutex.unlock() else: self.__done = True self.taskDone.emit() self.__restore(backup_variables) self.__move_to_main_thread() def abort(self): if not self.__done and not self.__aborted: # logging.info("Abort calculations signal obtained '%s'" % thread_name()) self.__aborted = True # logging.info("WakeAll threads for aborting calculation") self.variable_changed.wakeAll()
class InputVariablesBox(AbstractGroupBox): MAX_VARIABLES = 2 variablesChanged = Signal(list) valuesChanged = Signal(dict) def __init__(self, parent, options): """ :param QtGui.QWidget parent: Parent :param options.structures.Options options: Program options """ super(InputVariablesBox, self).__init__("Input variables", parent) self.__options = options self.__tree_layout = QtGui.QVBoxLayout() self.__input_variables_tree = InputVariablesTree(self, self.__options) connect(self.__input_variables_tree.itemSelectionChanged, self.onTreeSelectionChanged) self.__button_expand_all = QtGui.QPushButton("Expand all", self) self.__button_collapse_all = QtGui.QPushButton("Collapse all", self) connect(self.__button_expand_all.clicked, self.onExpandAllClicked) connect(self.__button_collapse_all.clicked, self.onCollapseAllClicked) self.__buttons_colexp_layout = QtGui.QHBoxLayout() self.__buttons_colexp_layout.addWidget(self.__button_expand_all) self.__buttons_colexp_layout.addWidget(self.__button_collapse_all) self.__tree_layout.addWidget(self.__input_variables_tree) self.__tree_layout.addLayout(self.__buttons_colexp_layout) self.__buttons_addrem_layout = QtGui.QVBoxLayout() self.__button_add = QtGui.QPushButton("+", self) self.__button_remove = QtGui.QPushButton("-", self) self.__button_add.setEnabled(False) self.__button_remove.setEnabled(False) connect(self.__button_add.clicked, self.onAddVariableButtonClicked) connect(self.__button_remove.clicked, self.onRemoveVariableButtonClicked) self.__buttons_addrem_layout.addWidget(self.__button_add) self.__buttons_addrem_layout.addWidget(self.__button_remove) self.__input_variables_table = InputVariablesTable(self) connect(self.__input_variables_table.itemSelectionChanged, self.onTableSelectionChanged) connect(self.__input_variables_table.variablesChanged, self.onVariablesChanged) connect(self.__input_variables_table.valuesChanged, self.onValuesChanged) self.__layout = QtGui.QHBoxLayout(self) self.__layout.addLayout(self.__tree_layout) self.__layout.addLayout(self.__buttons_addrem_layout) self.__layout.addWidget(self.__input_variables_table) # noinspection PyPep8Naming @Slot() def onTreeSelectionChanged(self): items = self.__input_variables_tree.selectedItems() # check whether item has item column (otherwise it's only header not a variable) self.__button_add.setEnabled( bool(items) and bool(items[0].text(InputVariablesTree.INDEX_COLUMN)) and self.__input_variables_table.rowCount() < self.MAX_VARIABLES ) # noinspection PyPep8Naming @Slot() def onTableSelectionChanged(self): items = self.__input_variables_table.selectedItems() self.__button_remove.setEnabled(bool(items)) # noinspection PyPep8Naming @Slot() def onAddVariableButtonClicked(self): items = self.__input_variables_tree.selectedItems() if items and items[0].text(InputVariablesTree.INDEX_COLUMN): name, index, variable = self.__input_variables_tree.check_variable(items[0]) self.__input_variables_table.add_variable(name, index, variable) # noinspection PyPep8Naming @Slot() def onRemoveVariableButtonClicked(self): row = self.__input_variables_table.currentRow() index = self.__input_variables_table.item(row, InputVariablesTable.INDEX_COLUMN) self.__input_variables_tree.uncheck_variable(index.text()) self.__input_variables_table.remove_variable(row) # noinspection PyPep8Naming @Slot() def onExpandAllClicked(self): self.__input_variables_tree.set_expand_collapse_all(True) # noinspection PyPep8Naming @Slot() def onCollapseAllClicked(self): self.__input_variables_tree.set_expand_collapse_all(False) # noinspection PyPep8Naming @Slot(list) def onVariablesChanged(self, data): self.variablesChanged.emit(data) # noinspection PyPep8Naming @Slot(dict) def onValuesChanged(self, data): self.valuesChanged.emit(data) def setObject(self, options): self.__options = options self.__input_variables_tree.setObject(options) selected_items = [] for variable in self.__input_variables_table.variables: indx = self.__input_variables_tree.indx_by_variable(variable) if indx is not None: item = self.__input_variables_tree.item_by_indx(indx) selected_items.append((item, self.__input_variables_table.values[variable])) self.__input_variables_table.clearContents() for item, values in selected_items: name, index, variable = self.__input_variables_tree.check_variable(item) row = self.__input_variables_table.add_variable(name, index, variable) inv_map = {v: k for k, v in self.__input_variables_table.VALUES_DICT_MAP.items()} for key, value in values.iteritems(): col = inv_map[key] self.__input_variables_table.setItem(row, col, QtGui.QTableWidgetItem(str(value)))
class InputVariablesTable(QtGui.QTableWidget): ORD_COLUMN = 0 NAME_COLUMN = 1 START_COLUMN = 2 STOP_COLUMN = 3 INTERVAL_COLUMN = 4 INDEX_COLUMN = 5 CHANGEABLE_COLUMNS = [START_COLUMN, STOP_COLUMN, INTERVAL_COLUMN] HEADER = { ORD_COLUMN: "#", NAME_COLUMN: "Variable name", START_COLUMN: "Start", STOP_COLUMN: "Stop", INTERVAL_COLUMN: "Interval", INDEX_COLUMN: "VariableIndex" } OVERSIZE = 0 HEIGHT = 20 ENABLED = QtCore.Qt.ItemIsEnabled READONLY = QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled EDITABLE = QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled variablesChanged = Signal(list) valuesChanged = Signal(dict) def __init__(self, parent): """ :param QtGui.QWidget parent: Widget parent """ super(InputVariablesTable, self).__init__(parent) self.setColumnCount(6) self.setColumnWidth(InputVariablesTable.ORD_COLUMN, 40) self.setColumnWidth(InputVariablesTable.NAME_COLUMN, 200) self.setColumnWidth(InputVariablesTable.START_COLUMN, 60) self.setColumnWidth(InputVariablesTable.STOP_COLUMN, 60) self.setColumnWidth(InputVariablesTable.INTERVAL_COLUMN, 60) self.setHorizontalHeaderLabels(listify(InputVariablesTable.HEADER)) self.setColumnHidden(InputVariablesTable.INDEX_COLUMN, True) self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.horizontalHeader().setClickable(False) self.verticalHeader().setVisible(False) self.verticalHeader().setDefaultSectionSize(self.HEIGHT) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setFixedWidth(calculate_table_width(self) + self.OVERSIZE) self.setMinimumHeight(_MINIMUM_HEIGHT) connect(self.itemChanged, self.onItemChanged) self.__variables = list() self.__values = dict() def clearContents(self, *args, **kwargs): super(InputVariablesTable, self).clearContents(*args, **kwargs) self.setRowCount(0) self.__variables = list() self.__values = dict() def __reord_rows(self): for k in xrange(self.rowCount()): ord_item = QtGui.QTableWidgetItem(str(k + 1)) ord_item.setFlags(InputVariablesTable.READONLY) ord_item.setTextAlignment(QtCore.Qt.AlignRight) self.setItem(k, InputVariablesTable.ORD_COLUMN, ord_item) def add_variable(self, name, index, wrapper): row = self.rowCount() self.__variables.append(wrapper) self.__values[wrapper] = dict() self.setRowCount(row + 1) name_item = QtGui.QTableWidgetItem(name) index_item = QtGui.QTableWidgetItem(str(index)) for item in (name_item, index_item): item.setFlags(InputVariablesTable.READONLY) self.setItem(row, InputVariablesTable.NAME_COLUMN, name_item) self.setItem(row, InputVariablesTable.START_COLUMN, QtGui.QTableWidgetItem()) self.setItem(row, InputVariablesTable.STOP_COLUMN, QtGui.QTableWidgetItem()) self.setItem(row, InputVariablesTable.INTERVAL_COLUMN, QtGui.QTableWidgetItem()) self.setItem(row, InputVariablesTable.INDEX_COLUMN, index_item) self.setRowHeight(row, InputVariablesTable.HEIGHT) self.__reord_rows() self.variablesChanged.emit(self.__variables) return row @property def variables(self): return self.__variables @property def values(self): return self.__values def remove_variable(self, row): del self.__values[self.__variables[row]] self.__variables.remove(self.__variables[row]) self.removeRow(row) self.__reord_rows() self.variablesChanged.emit(self.__variables) VALUES_DICT_MAP = { START_COLUMN: "START", STOP_COLUMN: "STOP", INTERVAL_COLUMN: "INTERVAL" } # noinspection PyPep8Naming @Slot(QtGui.QTreeWidgetItem) def onItemChanged(self, item): row = item.row() col = item.column() # logging.info("Current row/col: %s %s" % (row, col)) if row != -1 and col in InputVariablesTable.CHANGEABLE_COLUMNS: variable = self.__variables[row] key = self.VALUES_DICT_MAP[col] try: self.__values[variable][key] = float(item.text()) # logging.info("Change [%s, %s]: %s -> %s" % (row, col, self.__values[variable][key], item.text())) except ValueError: item.setText(str()) # logging.info("Change [%s, %s]: (rejected)" % (row, col)) else: self.valuesChanged.emit(self.__values)
class RefineSimplerParamTab(QWidget): """ This widget is the tool for tunning the simpler and most common parameters in the refiner, this widget is the first to appear once the button "Refine" at the left side of the GUI is clicked """ item_changed = Signal(str, str) item_to_remove = Signal(str) def __init__(self, parent=None): super(RefineSimplerParamTab, self).__init__() # self.param_widget_parent = parent.param_widget_parent localLayout = QVBoxLayout() hbox_lay_scan_varying = QHBoxLayout() label_scan_varying = QLabel("Scan Varying Refinement") hbox_lay_scan_varying.addWidget(label_scan_varying) box_scan_varying = QComboBox() box_scan_varying.local_path = "refinement.parameterisation.scan_varying" box_scan_varying.tmp_lst = [] box_scan_varying.tmp_lst.append("True") box_scan_varying.tmp_lst.append("False") box_scan_varying.tmp_lst.append("Auto") for lst_itm in box_scan_varying.tmp_lst: box_scan_varying.addItem(lst_itm) box_scan_varying.setCurrentIndex(2) box_scan_varying.currentIndexChanged.connect(self.combobox_changed) hbox_lay_scan_varying.addWidget(box_scan_varying) localLayout.addLayout(hbox_lay_scan_varying) ########################################################################### hbox_lay_outlier_algorithm = QHBoxLayout() label_outlier_algorithm = QLabel("Outlier Rejection Algorithm") hbox_lay_outlier_algorithm.addWidget(label_outlier_algorithm) box_outlier_algorithm = QComboBox() box_outlier_algorithm.local_path = "refinement.reflections.outlier.algorithm" box_outlier_algorithm.tmp_lst = [] box_outlier_algorithm.tmp_lst.append("null") box_outlier_algorithm.tmp_lst.append("auto") box_outlier_algorithm.tmp_lst.append("mcd") box_outlier_algorithm.tmp_lst.append("tukey") box_outlier_algorithm.tmp_lst.append("sauter_poon") for lst_itm in box_outlier_algorithm.tmp_lst: box_outlier_algorithm.addItem(lst_itm) box_outlier_algorithm.setCurrentIndex(1) box_outlier_algorithm.currentIndexChanged.connect( self.combobox_changed) hbox_lay_outlier_algorithm.addWidget(box_outlier_algorithm) localLayout.addLayout(hbox_lay_outlier_algorithm) self.inner_reset_btn = ResetButton() localLayout.addWidget(self.inner_reset_btn) localLayout.addStretch() self.setLayout(localLayout) self.lst_var_widg = [] self.lst_var_widg.append(box_scan_varying) self.lst_var_widg.append(label_scan_varying) # self.lst_var_widg.append(box_beam_fix) # self.lst_var_widg.append(label_beam_fix) # self.lst_var_widg.append(box_crystal_fix) # self.lst_var_widg.append(label_crystal_fix) # self.lst_var_widg.append(box_detector_fix) # self.lst_var_widg.append(label_detector_fix) # self.lst_var_widg.append(box_goniometer_fix) # self.lst_var_widg.append(label_goniometer_fix) self.lst_var_widg.append(box_outlier_algorithm) self.lst_var_widg.append(label_outlier_algorithm) def combobox_changed(self, value): sender = self.sender() str_value = str(sender.tmp_lst[value]) str_path = str(sender.local_path) logger.debug("str(sender.local_path) = %s", str(sender.local_path)) if str_value == "none": logger.debug("trying to emit [item_to_remove] = %s", str_path) self.item_to_remove.emit(str_path) else: self.item_changed.emit(str_path, str_value)
class IntegrateSimplerParamTab(QWidget): """ This widget is the tool for tunning the simpler and most common parameters in the integrate algorithm, this widget is the first to appear once the button "Integrate" at the left side of the GUI is clicked """ item_changed = Signal(str, str) def __init__(self, parent=None): super(IntegrateSimplerParamTab, self).__init__() # self.param_widget_parent = parent.param_widget_parent localLayout = QVBoxLayout() PrFit_lay_out = QHBoxLayout() label_PrFit = QLabel("Use Profile Fitting") PrFit_lay_out.addWidget(label_PrFit) PrFit_comb_bx = QComboBox() PrFit_comb_bx.local_path = "integration.profile.fitting" PrFit_comb_bx.tmp_lst = [] PrFit_comb_bx.tmp_lst.append("True") PrFit_comb_bx.tmp_lst.append("False") PrFit_comb_bx.tmp_lst.append("Auto") for lst_itm in PrFit_comb_bx.tmp_lst: PrFit_comb_bx.addItem(lst_itm) PrFit_comb_bx.currentIndexChanged.connect(self.combobox_changed) PrFit_lay_out.addWidget(PrFit_comb_bx) localLayout.addLayout(PrFit_lay_out) hbox_lay_algorithm_53 = QHBoxLayout() label_algorithm_53 = QLabel("Background Algorithm") hbox_lay_algorithm_53.addWidget(label_algorithm_53) box_algorithm_53 = QComboBox() box_algorithm_53.local_path = "integration.background.algorithm" box_algorithm_53.tmp_lst = [] box_algorithm_53.tmp_lst.append("simple") box_algorithm_53.tmp_lst.append("null") box_algorithm_53.tmp_lst.append("median") box_algorithm_53.tmp_lst.append("gmodel") box_algorithm_53.tmp_lst.append("glm") for lst_itm in box_algorithm_53.tmp_lst: box_algorithm_53.addItem(lst_itm) box_algorithm_53.setCurrentIndex(4) box_algorithm_53.currentIndexChanged.connect(self.combobox_changed) hbox_lay_algorithm_53.addWidget(box_algorithm_53) localLayout.addLayout(hbox_lay_algorithm_53) hbox_d_min = QHBoxLayout() label_d_min = QLabel("d_min") hbox_d_min.addWidget(label_d_min) d_min_spn_bx = QDoubleSpinBox() d_min_spn_bx.local_path = "prediction.d_min" d_min_spn_bx.setSpecialValueText("None") d_min_spn_bx.setValue(0.0) hbox_d_min.addWidget(d_min_spn_bx) d_min_spn_bx.valueChanged.connect(self.spnbox_changed) localLayout.addLayout(hbox_d_min) hbox_lay_nproc = QHBoxLayout() label_nproc = QLabel("Number of Jobs") # label_nproc.setFont( QFont("Monospace", 10)) hbox_lay_nproc.addWidget(label_nproc) self.box_nproc = QSpinBox() self.box_nproc.local_path = "integration.mp.nproc" self.box_nproc.valueChanged.connect(self.spnbox_changed) hbox_lay_nproc.addWidget(self.box_nproc) localLayout.addLayout(hbox_lay_nproc) self.inner_reset_btn = ResetButton() localLayout.addWidget(self.inner_reset_btn) localLayout.addStretch() self.setLayout(localLayout) self.box_nproc.tmp_lst = None self.lst_var_widg = _get_all_direct_layout_widget_children(localLayout) def combobox_changed(self, value): sender = self.sender() str_value = str(sender.tmp_lst[value]) str_path = str(sender.local_path) # self.param_widget_parent.update_lin_txt(str_path, str_value) self.item_changed.emit(str_path, str_value) def spnbox_changed(self, value): sender = self.sender() str_value = str(value) logger.debug(value) str_path = str(sender.local_path) self.item_changed.emit(str_path, str_value) def set_max_nproc(self): cpu_max_proc = int(libtbx.introspection.number_of_processors()) self.box_nproc.setValue(cpu_max_proc) return cpu_max_proc
class ReindexTable(QTableWidget): opt_signal = Signal(int) def __init__(self, parent=None): super(ReindexTable, self).__init__(parent) self.cellClicked.connect(self.opt_clicked) self.v_sliderBar = self.verticalScrollBar() self.h_sliderBar = self.horizontalScrollBar() self.tmp_sel = None sys_font = QFont() self.sys_font_point_size = sys_font.pointSize() # self.show() def opt_clicked(self, row, col): print("Solution clicked = %s", row + 1) # p_h_svar = self.horizontalScrollBar().value() # p_v_svar = self.verticalScrollBar().value() v_sliderValue = self.v_sliderBar.value() h_sliderValue = self.h_sliderBar.value() self.del_opts_lst() self.add_opts_lst(lst_labels=self.list_labl, selected_pos=row) self.v_sliderBar.setValue(v_sliderValue) self.h_sliderBar.setValue(h_sliderValue) self.opt_pick(row) def ok_clicked(self): self.opt_pick(self.tmp_sel) def opt_pick(self, row): if self.tmp_sel == row: logger.debug("\n selecting opt: %s %s", row + 1, "\n") self.opt_signal.emit(row) self.tmp_sel = row def find_best_solu(self): bst_sol = -1 for row, row_cont in enumerate(self.list_labl): if row_cont[self.rec_col] == " Y": if row > bst_sol: bst_sol = row logger.debug("bst_sol = %s", bst_sol) return bst_sol def add_opts_lst(self, lst_labels=None, json_path=None, selected_pos=None): if lst_labels is None: logger.debug("json_path = %s", json_path) self.list_labl = ops_list_from_json(json_path) n_row = len(self.list_labl) logger.debug("n_row = %s", n_row) n_col = len(self.list_labl[0]) logger.debug("n_col = %s", n_col) self.setRowCount(n_row) self.setColumnCount(n_col - 1) alpha_str = " " + u"\u03B1" + " " beta_str = " " + u"\u03B2" + " " gamma_str = " " + u"\u03B3" + " " low_delta_str = u"\u03B4" delta_max_str = "max " + low_delta_str header_label_lst = [ delta_max_str, "rmsd", " min cc", "max cc", "latt", " a ", " b ", " c ", alpha_str, beta_str, gamma_str, "Ok", ] self.setHorizontalHeaderLabels(header_label_lst) self.rec_col = None for row, row_cont in enumerate(self.list_labl): for col, col_cont in enumerate(row_cont[1:]): item = QTableWidgetItem(col_cont) item.setFlags(Qt.ItemIsEnabled) if col_cont == " Y": item.setBackground(Qt.green) item.setForeground(Qt.black) self.rec_col = col + 1 elif col_cont == " N": item.setBackground(Qt.red) item.setForeground(Qt.black) else: if row == selected_pos: item.setBackground(Qt.blue) item.setForeground(Qt.yellow) else: if float(row) / 2.0 == int(float(row) / 2.0): item.setBackground(QColor(50, 50, 50, 50)) else: item.setBackground(Qt.white) item.setForeground(Qt.black) item.setFont(QFont("Monospace", self.sys_font_point_size)) # , QFont.Bold)) self.setItem(row, col, item) self.resizeColumnsToContents() def del_opts_lst(self): logger.debug("del_opts_lst") self.clear() self.setRowCount(1) self.setColumnCount(1)
class ScaleSimplerParamTab(QWidget): """ This widget is the tool for tunning the simpler and most common parameters in the scale command, this widget is the first to appear once the button "Scale" at the left side of the GUI is clicked """ item_changed = Signal(str, str) def __init__(self, parent=None): super(ScaleSimplerParamTab, self).__init__() localLayout = QVBoxLayout() hbox_lay_mod = QHBoxLayout() label_mod = QLabel("Model") hbox_lay_mod.addWidget(label_mod) box_mod = QComboBox() box_mod.local_path = "model" box_mod.tmp_lst = [] box_mod.tmp_lst.append("physical") box_mod.tmp_lst.append("array") box_mod.tmp_lst.append("KB") for lst_itm in box_mod.tmp_lst: box_mod.addItem(lst_itm) box_mod.currentIndexChanged.connect(self.combobox_changed) hbox_lay_mod.addWidget(box_mod) hbox_lay_wgh_opt_err = QHBoxLayout() label_wgh_opt_err = QLabel("Optimise Errors Model") hbox_lay_wgh_opt_err.addWidget(label_wgh_opt_err) ''' weighting { error_model { error_model = *basic None ''' box_wgh_opt_err = QComboBox() box_wgh_opt_err.local_path = "weighting.error_model.error_model" box_wgh_opt_err.tmp_lst = [] box_wgh_opt_err.tmp_lst.append("basic") box_wgh_opt_err.tmp_lst.append("None") for lst_itm in box_wgh_opt_err.tmp_lst: box_wgh_opt_err.addItem(lst_itm) box_wgh_opt_err.currentIndexChanged.connect(self.combobox_changed) hbox_lay_wgh_opt_err.addWidget(box_wgh_opt_err) hbox_d_min = QHBoxLayout() d_min_label = QLabel("d_min") d_min_spn_bx = QDoubleSpinBox() d_min_spn_bx.local_path = "cut_data.d_min" d_min_spn_bx.setSpecialValueText("None") d_min_spn_bx.setValue(0.0) hbox_d_min.addWidget(d_min_label) hbox_d_min.addWidget(d_min_spn_bx) d_min_spn_bx.valueChanged.connect(self.spnbox_changed) localLayout.addLayout(hbox_lay_mod) localLayout.addLayout(hbox_lay_wgh_opt_err) localLayout.addLayout(hbox_d_min) self.inner_reset_btn = ResetButton() localLayout.addWidget(self.inner_reset_btn) localLayout.addStretch() self.setLayout(localLayout) self.lst_var_widg = [] self.lst_var_widg.append(box_mod) self.lst_var_widg.append(label_mod) self.lst_var_widg.append(box_wgh_opt_err) self.lst_var_widg.append(label_wgh_opt_err) self.lst_var_widg.append(d_min_spn_bx) self.lst_var_widg.append(d_min_label) def combobox_changed(self, value): sender = self.sender() str_value = str(sender.tmp_lst[value]) str_path = str(sender.local_path) # self.param_widget_parent.update_lin_txt(str_path, str_value) self.item_changed.emit(str_path, str_value) def spnbox_changed(self, value): sender = self.sender() str_value = str(value) logger.debug(value) str_path = str(sender.local_path) self.item_changed.emit(str_path, str_value)
class ExportPage(QWidget): update_command_lst_low_level = Signal(list) """ This stacked widget basically helps the user to export by generating an MTZ file, there is no auto-generated GUI form Phil parameters in use withing this widget. """ def __init__(self, parent=None): super(ExportPage, self).__init__(parent=None) main_v_box = QVBoxLayout() label_font = QFont() sys_font_point_size = label_font.pointSize() label_font.setPointSize(sys_font_point_size + 2) step_label = QLabel(str("Export")) step_label.setFont(label_font) out_file_label = QLabel(str("mtz output name:")) self.simple_lin = QLineEdit(self) self.simple_lin.textChanged.connect(self.update_command) self.check_scale = QCheckBox("Output Scaled Intensities") self.check_scale.setChecked(False) self.check_scale.stateChanged.connect(self.update_command) self.warning_label = QLabel(str(" ")) self.warning_label.setWordWrap(True) main_v_box.addWidget(step_label) main_v_box.addWidget(out_file_label) main_v_box.addWidget(self.simple_lin) main_v_box.addWidget(self.check_scale) main_v_box.addStretch() main_v_box.addWidget(self.warning_label) main_v_box.addStretch() self.setLayout(main_v_box) self.fist_time = False # self.show() self.simple_lin.setText("integrated.mtz") def update_command(self): self.command_lst = [["export"]] param1_com = str(self.simple_lin.text()) self.command_lst[0].append("mtz.hklout=" + param1_com) if self.check_scale.checkState(): param2_com = "intensity=scale" self.command_lst[0].append(param2_com) self.update_command_lst_low_level.emit(self.command_lst[0]) self.check_repeated_file() def check_repeated_file(self): param1_com = str(self.simple_lin.text()) cwd_path = os.path.join(sys_arg.directory, "dui_files") mtz_file_path = os.path.join(cwd_path, param1_com) if os.path.isfile(mtz_file_path): txt_warning = "Warning, file: " + param1_com + " already exists" self.warning_label.setText(txt_warning) self.warning_label.setStyleSheet("color: rgba(255, 55, 55, 255)") """ self.warning_label.setStyleSheet( "color: rgba(255, 55, 55, 255);" "background-color: yellow;" ) """ else: self.warning_label.setText(" ") self.warning_label.setStyleSheet("color: rgba(0, 155, 255, 255)") def gray_me_out(self): self.simple_lin.setEnabled(False) self.check_scale.setEnabled(False) self.fist_time = False def activate_me(self, cur_nod=None): self.simple_lin.setEnabled(True) self.check_scale.setEnabled(True) if self.fist_time is False: self.fist_time = True self.simple_lin.setText("integrated.mtz") self.check_scale.setChecked(False) my_node = cur_nod found_scale = False for iters in range(5): try: if my_node.ll_command_lst[0][0] == "scale": found_scale = True break except AttributeError as at_err: logger.info("found ", at_err, " in for loop, not to worry") my_node = my_node.prev_step if found_scale is True: self.simple_lin.setText("scaled.mtz") self.check_scale.setChecked(True) self.check_repeated_file() def reset_par(self): logger.info("command_lst(ExportPage.reset_par) = ", self.command_lst) logger.info(" Not supposed to reset export page")
class Scene(common.Scene): text_changed = Signal() def __init__(self): common.Scene.__init__(self) self.swap_buttons = False self.remaining = 0 self.mistakes = 0 self.solving = False @event_property def remaining(self): self.text_changed.emit() @event_property def mistakes(self): self.text_changed.emit() def set_swap_buttons(self, value): self.swap_buttons = value def drawForeground(self, g, rect): g.setBrush(Color.flower) g.setPen(no_pen) for it in self.all(Cell): if it.flower: poly = _flower_poly.translated(it.scenePos()) g.drawPolygon(poly) g.setBrush(QBrush(qt.NoBrush)) pen = QPen(Color.flower_border, 2) pen.setCosmetic(True) g.setPen(pen) for it in self.all(Cell): if it.flower: poly = _flower_poly.translated(it.scenePos()) g.drawPolygon(poly) g.setPen(no_pen) g.setBrush(Color.beam) for it in self.all(Column): if it.beam: poly = QPolygonF(QRectF(-0.03, 0.525, 0.06, 1e6)) poly = QTransform().translate(it.scenePos().x(), it.scenePos().y()).rotate( it.rotation()).map(poly) poly = poly.intersected(QPolygonF(rect)) g.drawConvexPolygon(poly) @cached_property def all_cells(self): return list(self.all(Cell)) @cached_property def all_columns(self): return list(self.all(Column)) def solve_step(self): """Derive everything that can be concluded from the current state. Return whether progress has been made.""" if self.solving: return self.confirm_proven() self.solving = True app.processEvents() progress = False for cell, value in solve(self): try: assert cell.actual == value except AssertionError: cell.setPen(QPen(qt.red, 0.2)) raise cell.proven = True cell.upd() progress = True self.solving = False return progress def solve_complete(self): """Continue solving until stuck. Return whether the entire level could be uncovered.""" while True: self.confirm_proven() app.processEvents() progress = True while progress: progress = False for cell, value in solve_simple(self): progress = True try: assert cell.actual == value except AssertionError: cell.setPen(QPen(qt.red, 0.2)) raise cell.kind = cell.actual cell.upd() if not self.solve_step(): break # If it identified all blue cells, it'll have the rest uncovered as well return self.remaining == 0 def confirm_proven(self): if self.solving: return for cell in self.all(Cell): try: del cell.proven cell.kind = cell.actual cell.upd() except AttributeError: pass def clear_proven(self): if self.solving: return for cell in self.all(Cell): try: del cell.proven cell.upd() except AttributeError: pass
class PhilWidget(QWidget): item_changed = Signal(str, str) def __init__(self, phl_obj, parent=None): # TODO fix the order of this two parameters super(PhilWidget, self).__init__(parent) self.original_parent = parent self.bg_box = QVBoxLayout(self) lst_obj = tree_2_lineal(phl_obj.objects) lst_phil_obj = lst_obj() self.phil_list2gui(lst_phil_obj) self.setLayout(self.bg_box) self._found_labels = [] self._current_label = 0 @staticmethod def _tooltip_from_phil_object(obj): if obj.help: tooltip = "<p>" + obj.help + "</p>" else: tooltip = "" return tooltip def user_searching(self, value): self.original_parent.search_next_button.setEnabled(False) self._found_labels = [] for nm, labl_obj in enumerate(self.lst_label_widg): labl_obj.setStyleSheet(labl_obj.style_orign) if len(value) < 2: return logger.debug("user searching for: %s", value) logger.debug("len = %s", len(value)) for nm, labl_obj in enumerate(self.lst_label_widg): labl_text = labl_obj.text() if value in labl_text: self._found_labels.append(labl_obj) logger.debug("pos_str = %s", nm) if self._found_labels: self.parent().parent().ensureWidgetVisible(self._found_labels[0]) self._found_labels[0].setStyleSheet( "color: rgba(0, 155, 255, 255);" "background-color: yellow;") self._current_label = 0 if len(self._found_labels) > 1: self.original_parent.search_next_button.setEnabled(True) def find_next(self): label = self._found_labels[self._current_label] label.setStyleSheet(label.style_orign) self._current_label += 1 self._current_label = self._current_label % len(self._found_labels) label = self._found_labels[self._current_label] self.parent().parent().ensureWidgetVisible(label) label.setStyleSheet("color: rgba(0, 155, 255, 255);" "background-color: yellow;") def phil_list2gui(self, lst_phil_obj): sys_font = QFont() sys_font_point_size = sys_font.pointSize() inde_step = 4 self.lst_label_widg = [] self.lst_var_widg = [] non_added_lst = [] for nm, obj in enumerate(lst_phil_obj): if isinstance(obj, ScopeData): tmp_str = " " * int(obj.indent * inde_step) + str(obj.name) # print tmp_str tmp_widg = QLabel(tmp_str) tmp_widg.setAutoFillBackground(True) # tmp_widg.setPalette(self.plt_scp) tmp_widg.setFont( QFont("Monospace", sys_font_point_size, QFont.Bold)) tmp_widg.style_orign = "color: rgba(85, 85, 85, 255)" tmp_widg.setStyleSheet(tmp_widg.style_orign) tooltip = self._tooltip_from_phil_object(obj) if tooltip: tmp_widg.setToolTip(tooltip) self.bg_box.addWidget(tmp_widg) tmp_widg.test_flag = "Yes" self.lst_label_widg.append(tmp_widg) else: tmp_h_box = QHBoxLayout() indent = str(obj.full_path()).count(".") tmp_str = " " * indent * inde_step + str(obj.name) tmp_label = QLabel(tmp_str) tmp_label.setAutoFillBackground(True) # tmp_label.setPalette(self.plt_obj) tmp_label.style_orign = "color: rgba(0, 0, 0, 255)" tmp_label.setStyleSheet(tmp_label.style_orign) tmp_label.setFont(QFont("Monospace", sys_font_point_size)) tmp_h_box.addWidget(tmp_label) self.lst_label_widg.append(tmp_label) if obj.type.phil_type == "bool": tmp_widg = MyQComboBox() tmp_widg.tmp_lst = [] tmp_widg.tmp_lst.append("True") tmp_widg.tmp_lst.append("False") tmp_widg.tmp_lst.append("Auto") # tmp_widg.setFocusPolicy(Qt.StrongFocus) for lst_itm in tmp_widg.tmp_lst: tmp_widg.addItem(lst_itm) if str(obj.extract()) == "True": tmp_widg.setCurrentIndex(0) tmp_str += " True" elif str(obj.extract()) == "False": tmp_widg.setCurrentIndex(1) tmp_str += " False" elif str(obj.extract()) == "Auto": tmp_widg.setCurrentIndex(2) tmp_str += " Auto" else: tmp_str = None # logger.info("tmp_widg.tmp_lst =", tmp_widg.tmp_lst) # logger.info("tmp_str =", tmp_str) tmp_widg.currentIndexChanged.connect(self.combobox_changed) elif obj.type.phil_type == "choice": # remember to ask david about the issue here # tmp_widg = QComboBox() # tmp_widg.tmp_lst=[] # pos = 0 # found_choise = False # for num, opt in enumerate(obj.words): # opt = str(opt) # if(opt[0] == "*"): # found_choise = True # opt = opt[1:] # pos = num # tmp_str += " " + opt # tmp_widg.tmp_lst.append(opt) # for lst_itm in tmp_widg.tmp_lst: # tmp_widg.addItem(lst_itm) # tmp_widg.setCurrentIndex(pos) # tmp_widg.currentIndexChanged.connect(self.combobox_changed) # if(found_choise == False): # tmp_str = None # non_added_lst.append(str(obj.full_path())) # begins pathed version tmp_widg = MyQComboBox() tmp_widg.tmp_lst = [] pos = 0 found_choise = False for num, opt in enumerate(obj.words): opt = str(opt) if opt[0] == "*": found_choise = True opt = opt[1:] pos = num tmp_str += " " + opt tmp_widg.tmp_lst.append(opt) if not found_choise: tmp_str += " " + str( obj.extract()) for lst_itm in tmp_widg.tmp_lst: tmp_widg.addItem(lst_itm) tmp_widg.setCurrentIndex(pos) tmp_widg.currentIndexChanged.connect(self.combobox_changed) # ends pathed version else: tmp_widg = QLineEdit() tmp_widg.setText("") tmp_widg.str_defl = None tmp_widg.textChanged.connect(self.spnbox_changed) # tmp_widg.tmp_lst = None tmp_str += " " + str( obj.extract()) if tmp_str is not None: tmp_widg.local_path = str(obj.full_path()) # tmp_h_box.addStretch() tooltip = self._tooltip_from_phil_object(obj) if tooltip: tmp_widg.setToolTip(tooltip) tmp_h_box.addWidget(tmp_widg) self.lst_var_widg.append(tmp_widg) self.bg_box.addLayout(tmp_h_box) # debugging = ''' logger.debug("Non added parameters:") for lin_to_print in non_added_lst: logger.debug(lin_to_print) def spnbox_changed(self, value): sender = self.sender() if sender.str_defl is not None and float(value) == 0.0: str_value = sender.str_defl else: str_value = str(value) logger.debug("sender = %s", sender) logger.debug("spnbox_changed to: %s", str_value) str_path = str(sender.local_path) logger.debug("local_path = %s", str_path) # self.param_widget_parent.update_lin_txt(str_path, str_value) self.item_changed.emit(str_path, str_value) def combobox_changed(self, value): sender = self.sender() str_value = str(sender.tmp_lst[value]) logger.debug("combobox_changed to: %s", str_value) str_path = str(sender.local_path) logger.debug("local_path = %s", str_path) # self.param_widget_parent.update_lin_txt(str_path, str_value) self.item_changed.emit(str_path, str_value)
class ControlWidget(QWidget): """Primarily, the action button widget. Also holds as a property (but not in the QT hierarchy) the stage-parameter widgets. Attributes: step_param_widg (QStackedWidget): Physical collection widget that holds every possible parameter page. param_widgets (Dict[str, ParamWidget]): Mapping of action ID to physical widget to handle the parameter page. btn_lst (List[MyActionButton]): The actual action button instances. Each has a .pr_widg written by this class that points to the associated ParamWidget instance, and a .action property to point to the action it represents. user_changed (Signal[str]): A signal emitted when the user has requested a command change """ user_changed = Signal(str) update_command_lst_high_level = Signal(list) finished_masking = Signal() finished_b_centr = Signal() click_mask = Signal() click_b_centr = Signal() def __init__(self, parent=None): super(ControlWidget, self).__init__() top_box = QVBoxLayout() # top_box.setMargin(0) top_box.setContentsMargins(0, 0, 0, 0) self.step_param_widg = QStackedWidget() self.step_param_widg.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.param_widgets = {} self.btn_lst = [] # We only show action buttons for a subset of possible actions button_actions = [ "import", # Leave in for now - currently pages must be precreated "find_spots", "index", "refine_bravais_settings", "refine", "integrate", "symmetry", "scale", "export", ] for x in button_actions: action = ACTIONS[x] new_btn = MyActionButton(action, parent=self) new_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Don't add import to our button list for now - but other code # currently assumes the order of this list so we can't not add and # create the parameter pages here if action.id == "import": new_btn.hide() else: new_btn.clicked.connect(self._action_button_clicked) top_box.addWidget(new_btn) param_widg = ParamWidget(action.id) new_btn.pr_widg = param_widg self.step_param_widg.addWidget(param_widg) self.param_widgets[action.id] = param_widg param_widg.update_command_lst_medium_level.connect(self.update_parent_lst) self.btn_lst.append(new_btn) param_widg.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.mask_page = MaskPage() self.mask_page.update_command_lst_medium_level.connect( self.singular_step_new_command ) self.mask_page.mask_done.connect(self.done_masking) self.mask_page.mask_set.connect(self.set_mask) self.step_param_widg.addWidget(self.mask_page) self.b_centr_page = BeamCentrPage() self.b_centr_page.update_command_lst_medium_level.connect( self.singular_step_new_command ) self.b_centr_page.b_centr_done.connect(self.done_b_centr) self.b_centr_page.b_centr_set.connect(self.set_b_centr) self.step_param_widg.addWidget(self.b_centr_page) self.setLayout(top_box) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) def singular_step_new_command(self, command_lst): self.user_changed.emit(command_lst[0]) self.update_command_lst_high_level.emit([command_lst]) def done_masking(self): self.finished_masking.emit() def set_mask(self): self.click_mask.emit() def done_b_centr(self): self.finished_b_centr.emit() def set_b_centr(self): self.click_b_centr.emit() def update_parent_lst(self, command_lst): self.update_command_lst_high_level.emit([command_lst]) def pass_sys_arg_object_to_import(self, sys_arg_in): """Explicitly pass the system argument object to the import page""" self.param_widgets["import"].my_widget.set_arg_obj(sys_arg_in) def set_widget(self, nxt_cmd=None, curr_step=None): """Switch to a different action parameter page. Arguments: nxt_cmd (str): Action ID for the page to switch to curr_step: Metadata about the current page state """ # Firstly try looking in the params widget lookup table if nxt_cmd in self.param_widgets: widget = self.param_widgets[nxt_cmd] self.step_param_widg.setCurrentWidget(widget) try: widget.update_param(curr_step) except AttributeError: logger.info("\n object has no attribute update_param \n") elif nxt_cmd == "reindex": # Reindex is a special step because it doesn't have it's own page logger.debug("Reindex mode") param_widget = self.param_widgets["refine_bravais_settings"] self.step_param_widg.setCurrentWidget(param_widget) elif nxt_cmd == "generate_mask": # Mask is a special step because it doesn't have it's own button logger.debug("Mask") self.mask_page.update_param(curr_step) self.step_param_widg.setCurrentWidget(self.mask_page) elif nxt_cmd == "modify_geometry": logger.info("\n modify_geometry \n") self.step_param_widg.setCurrentWidget(self.b_centr_page) else: logger.info("No action widget found in set_widget") logger.info("nxt_cmd =", nxt_cmd) def _action_button_clicked(self): "Slot: An action button was clicked" my_sender = self.sender() logger.debug("Action button clicked - %s", my_sender.action.id) # Switch to the pareter page for this action param_page = self.param_widgets[my_sender.action.id] self.step_param_widg.setCurrentWidget(param_page) # Appears to: Use my_label as a lookup of the action ID for this parameter page self.user_changed.emit(param_page.my_label) logger.debug( "my_label (action ID?) of parameter widget for clicked action: %s", param_page.my_label, ) # TODO make sure is [[..label]] and not [..label] command_lst = [[str(param_page.my_label)]] self.update_command_lst_high_level.emit(command_lst) self.finished_masking.emit() self.finished_b_centr.emit() def gray_outs_all(self): """Disable all action buttons.""" for btn in self.btn_lst: btn.setEnabled(False) def gray_outs_from_lst(self, lst_nxt): """ Disable any action buttons not in a list. Arguments: lst_nxt (List[str]): List of action ID's to leave enabled """ self.gray_outs_all() for btn in self.btn_lst: for cmd_str in lst_nxt: if btn.action.id == cmd_str: btn.setEnabled(True)
class ExternalProcDialog(QDialog): """Create a pop-up modal dialog to wait for an external process Args: parent (QWidget): The parent for the dialog. Passed to QDialog. Attributes: outputFileFound (Signal): A named output file was found. Signal is called with a list of full paths to the output files. """ outputFileFound = Signal(list) def __init__(self, parent=None): super(ExternalProcDialog, self).__init__(parent) vbox = QVBoxLayout() label = QLabel( ( "Running a pop-up viewer ...\n\n" "remember to close the viewer before\n" "performing any other task" ) ) label.setAlignment(Qt.AlignCenter) vbox.addWidget(label) kl_but = QPushButton("Close pop-up viewer") kl_but.clicked.connect(self.kill_my_proc) vbox.addWidget(kl_but) self.setLayout(vbox) self.setFixedSize(self.sizeHint()) self.setModal(True) self.setWindowTitle("External Tool") self.my_process = None def run_my_proc(self, command, json_path, pickle_path): """Run a process. Args: command (str): The command to run json_path (str): Path to the JSON file to pass in as first argument pickle_path (Sequence[Optional[str]]): An additional path to a pickle to pass in as an argument. Currently, all except the first argument is ignored. """ # assert isinstance(json_path, basestring) # # This function previously had strings as default parameters # # but appears to only accept Indexable lists of strings. Make # # sure we never try to use strings # assert not isinstance(pickle_path, basestring) # # Since we ignore everything after [0] assert they are None # assert all(x is None for x in pickle_path[1:]) # # Only one process running from each class # assert self.my_process is None # Build the command cmd_to_run = [find_executable(command), str(json_path)] logger.debug("Resolving %s as %s", command, cmd_to_run[0]) first_pikl_path = pickle_path[0] if first_pikl_path is not None: cmd_to_run.append(str(first_pikl_path)) # Save the working directory self.cwd_path = os.path.join(sys_arg.directory, "dui_files") logger.debug("\n running Popen>>>\n " + " ".join(cmd_to_run) + "\n<<<") self.my_process = subprocess.Popen(args=cmd_to_run, cwd=self.cwd_path) logger.debug("Running PID {}".format(self.my_process.pid)) # Track the process status in a separate thread self.thrd = ViewerThread(self.my_process) self.thrd.finished.connect(self.child_closed) self.thrd.start() # Show this dialog self.exec_() def kill_my_proc(self): """Kill the subprocess early""" logger.debug("self.kill_my_proc") kill_w_child(self.my_process.pid) self.my_process = None self.done(0) def child_closed(self): """The child process has closed by itself""" logger.debug("after ...close()") self.my_process = None # Just close ourself self.done(0) def closeEvent(self, event): """User has clicked 'close' window decorator on dialog box""" logger.debug("from << closeEvent (QDialog) >>") self.kill_my_proc()
class AbstractStage(QtCore.QObject): invalidated = Signal() def __init__(self, core_options, metrics, pre_stage=None): """ :type core_options: CoreSimulationOptions :type pre_stage: AbstractStage or None """ super(AbstractStage, self).__init__() self.__core_options = core_options self.__pre_stage = pre_stage """:type: AbstractStage or None""" if self.__pre_stage is not None: self.__pre_stage.add_post_stage(self) self.__post_stages = [] """:type: list of AbstractStage""" self.__result = None self.__metrics = [metric_class(self) for metric_class in metrics] @property def name(self): """:rtype: str""" raise NotImplementedError @property def pre_stage(self): return self.__pre_stage def add_post_stage(self, stage): """:type: AbstractStage""" self.__post_stages.append(stage) @property def has_result(self): return self.__result is not None @Slot() def invalidate(self): # logging.info("Invalidate: %s" % self.__class__.__name__) self.__result = None for stage in self.__post_stages: # if stage.has_result: stage.invalidate() self.invalidated.emit() @property def core_options(self): return self.__core_options @property def options(self): return self.core_options.options def _payload(self): """:rtype: optolithiumc.Diffraction or optolithiumc.ResistVolume""" raise NotImplementedError @property def metrics_kwargs(self): """:rtype: dict from str""" return dict() @property def metrics(self): """:rtype: list of metrology.MetrologyInterface""" return self.__metrics def calculate(self): logging.debug("Calculate %s" % self.__class__.__name__) if not self.has_result: self.__result = self._payload() else: logging.debug("%s not changed" % self.__class__.__name__) return self.__result
class ImportPage(QWidget): update_command_lst_low_level = Signal(list) """ This stacked widget basically helps the user to browse the input images path, there is no auto-generated GUI form Phil parameters in use withing this widget. """ def __init__(self, parent=None): super(ImportPage, self).__init__(parent=None) main_v_box = QVBoxLayout() label_font = QFont() sys_font_point_size = label_font.pointSize() label_font.setPointSize(sys_font_point_size + 2) step_label = QLabel(str("Import")) step_label.setFont(label_font) self.simple_lin = QLineEdit(self) self.simple_lin.textChanged.connect(self.update_command) self.x_spn_bx = QSpinBox() self.x_spn_bx.setMaximum(99999) self.x_spn_bx.setSpecialValueText(" ") self.y_spn_bx = QSpinBox() self.y_spn_bx.setMaximum(99999) self.y_spn_bx.setSpecialValueText(" ") self.x_spn_bx.valueChanged.connect(self.x_beam_changed) self.y_spn_bx.valueChanged.connect(self.y_beam_changed) self.chk_invert = QCheckBox("Invert rotation axis") self.chk_invert.stateChanged.connect(self.inv_rota_changed) self.opn_fil_btn = QPushButton(" \n Select file(s) \n ") main_path = get_main_path() self.opn_fil_btn.setIcon(QIcon(main_path + "/resources/import.png")) self.opn_fil_btn.setIconSize(QSize(80, 48)) main_v_box.addWidget(step_label) main_v_box.addWidget(self.opn_fil_btn) main_v_box.addWidget(self.simple_lin) self.b_cetre_label = QLabel("\n\n Beam centre") main_v_box.addWidget(self.b_cetre_label) cent_hbox = QHBoxLayout() self.x_label = QLabel(" X: ") cent_hbox.addWidget(self.x_label) cent_hbox.addWidget(self.x_spn_bx) self.y_label = QLabel(" Y: ") cent_hbox.addWidget(self.y_label) cent_hbox.addWidget(self.y_spn_bx) # cent_hbox.addWidget(QLabel(" \n ")) cent_hbox.addStretch() main_v_box.addLayout(cent_hbox) main_v_box.addWidget(self.chk_invert) main_v_box.addStretch() self.opn_fil_btn.clicked.connect(self.open_files) self.defa_dir = str(os.getcwd()) self.setLayout(main_v_box) # self.show() self.reset_par() def reset_par(self): logger.info("reset_par(ImportPage)") self.cmd_list = [] self.simple_lin.setText(" ? ") self.x_spn_bx.setValue(0.0) self.y_spn_bx.setValue(0.0) self.chk_invert.setChecked(False) self.x_beam, self.y_beam = 0.0, 0.0 self.path_file_str = "" self.second_half = "" self.third_half = "" def update_param_w_lst(self, lst_in): self.reset_par() logger.info("update_param_w_lst(ImportPage) \n lst: \n", lst_in) for singl_com in lst_in: if singl_com[0:1] == "/": self.path_file_str = str(singl_com) self.put_str_lin() if singl_com[0:12] == "image_range=": self.path_file_str += " " self.path_file_str += str(singl_com) self.put_str_lin() if singl_com == "invert_rotation_axis=True": self.chk_invert.setChecked(True) if singl_com[0:22] == "slow_fast_beam_centre=": yb_xb_str = singl_com[22:] yb_str, xb_str = yb_xb_str.split(",") yb = float(yb_str) xb = float(xb_str) self.y_spn_bx.setValue(yb) self.x_spn_bx.setValue(xb) def inv_rota_changed(self): if self.chk_invert.checkState(): self.third_half = "invert_rotation_axis=True" else: self.third_half = "" self.put_str_lin() def x_beam_changed(self, value): self.x_beam = value self.build_second_half() def y_beam_changed(self, value): self.y_beam = value self.build_second_half() def build_second_half(self): if self.x_beam != 0.0 and self.y_beam != 0.0: self.second_half = ( "slow_fast_beam_centre=" + str(self.y_beam) + "," + str(self.x_beam) ) else: self.second_half = "" self.put_str_lin() def open_files(self): lst_file_path = QFileDialog.getOpenFileNames( self, "Open File(s)", self.defa_dir, "All Files (*.*)" ) if len(lst_file_path) > 0: new_dir, new_command = get_import_run_string(lst_file_path) # logger.info("\n new_dir=", new_dir, ">>") # logger.info("\n new_command =", new_command, ">>") self.path_file_str = new_command self.defa_dir = new_dir self.put_str_lin() def put_str_lin(self): # logger.info("self.path_file_str =", self.path_file_str, ">>") self.cmd_list = [ self.path_file_str, self.second_half.lstrip(), self.third_half.lstrip(), ] txt_lin = " ".join(self.cmd_list).rstrip() while " " in txt_lin: txt_lin = txt_lin.replace(" ", " ") self.simple_lin.setText(txt_lin) def set_arg_obj(self, sys_arg_in): """Pass the system argument object to handle launch arguments.""" if sys_arg_in.template is not None: str_arg = str(sys_arg_in.template) self.simple_lin.setText(str_arg) def update_command(self): self.command_lst = [["import"]] param_com = str(self.simple_lin.text()) cmd_lst = param_com.split(" ") for single_com in cmd_lst: self.command_lst[0].append(single_com) self.update_command_lst_low_level.emit(self.command_lst[0]) def gray_me_out(self): self.simple_lin.setEnabled(False) self.opn_fil_btn.setEnabled(False) self.x_spn_bx.setEnabled(False) self.y_spn_bx.setEnabled(False) self.x_label.setEnabled(False) self.y_label.setEnabled(False) self.b_cetre_label.setEnabled(False) self.chk_invert.setEnabled(False) def activate_me(self, cur_nod=None): self.simple_lin.setEnabled(True) self.opn_fil_btn.setEnabled(True) self.y_spn_bx.setEnabled(True) self.x_spn_bx.setEnabled(True) self.x_label.setEnabled(True) self.y_label.setEnabled(True) self.b_cetre_label.setEnabled(True) self.chk_invert.setEnabled(True)