class MainWindow(QMainWindow): def __init__(self, title): super().__init__() self.setWindowTitle(title) self.lib_path = "" self.final_title = "" analysis_icon = QIcon(os.path.join(icons_dir, "icon.png")) stack_icon = QIcon(os.path.join(icons_dir, "icon_stack.png")) self.analysis_button = QToolButton(self) self.analysis_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.analysis_button.setIcon(analysis_icon) # TODO use more general solution for text wrapping self.analysis_button.setText(ANALYSIS_NAME.replace(" ", "\n")) self.analysis_button.setIconSize(QSize(100, 100)) self.mask_button = QToolButton(self) self.mask_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.mask_button.setIcon(stack_icon) self.mask_button.setText(MASK_NAME.replace(" ", "\n")) self.mask_button.setIconSize(QSize(100, 100)) self.analysis_button.clicked.connect(self.launch_analysis) self.mask_button.clicked.connect(self.launch_mask) self.progress = QProgressBar() self.progress.setHidden(True) layout = QGridLayout() layout.addWidget(self.progress, 0, 0, 1, 2) layout.addWidget(self.analysis_button, 1, 1) layout.addWidget(self.mask_button, 1, 0) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) self.setWindowIcon(analysis_icon) self.prepare = None self.wind = None self._update_theme() def _update_theme(self): napari_settings = napari_get_settings(state_store.save_folder) with warnings.catch_warnings(): warnings.simplefilter("ignore", FutureWarning) theme = get_theme(napari_settings.appearance.theme) # TODO understand qss overwrite mechanism self.setStyleSheet(napari_template(get_stylesheet(), **theme)) def _launch_begin(self): self.progress.setVisible(True) self.progress.setRange(0, 0) self.analysis_button.setDisabled(True) self.mask_button.setDisabled(True) import_config() def launch_analysis(self): self._launch_begin() self._launch_analysis() self.prepare.start() def _launch_analysis(self): self.lib_path = "PartSeg._roi_analysis.main_window" self.final_title = f"{APP_NAME} {ANALYSIS_NAME}" self.prepare = Prepare(self.lib_path) self.prepare.finished.connect(self.launch) def launch_mask(self): self._launch_begin() self._launch_mask() self.prepare.start() def _launch_mask(self): self.lib_path = "PartSeg._roi_mask.main_window" self.final_title = f"{APP_NAME} {MASK_NAME}" self.prepare = Prepare(self.lib_path) self.prepare.finished.connect(self.launch) def window_shown(self): self.close() def launch(self): if self.prepare.result is None: self.close() return if self.prepare.errors: errors_message = QMessageBox() errors_message.setText("There are errors during start") errors_message.setInformativeText( "During load saved state some of data could not be load properly\n" "The files has prepared backup copies in state directory (Help > State directory)" ) errors_message.setStandardButtons(QMessageBox.Ok) text = "\n".join("File: " + x[0] + "\n" + str(x[1]) for x in self.prepare.errors) errors_message.setDetailedText(text) errors_message.exec_() wind = self.prepare.result(title=self.final_title, signal_fun=self.window_shown) wind.show() self.wind = wind
class MainWindow(QMainWindow): def __init__(self, title): super().__init__() self.setWindowTitle(title) self.lib_path = "" self.final_title = "" analysis_icon = QIcon(os.path.join(icons_dir, "icon.png")) stack_icon = QIcon(os.path.join(icons_dir, "icon_stack.png")) self.analysis_button = QToolButton(self) self.analysis_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.analysis_button.setIcon(analysis_icon) # TODO use more general solution for text wrapping self.analysis_button.setText(SEGMENTATION_NAME.replace(" ", "\n")) self.analysis_button.setIconSize(QSize(100, 100)) self.mask_button = QToolButton(self) self.mask_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.mask_button.setIcon(stack_icon) self.mask_button.setText(MASK_NAME.replace(" ", "\n")) self.mask_button.setIconSize(QSize(100, 100)) self.analysis_button.clicked.connect(self.launch_analysis) self.mask_button.clicked.connect(self.launch_mask) self.progress = QProgressBar() self.progress.setHidden(True) layout = QGridLayout() layout.addWidget(self.progress, 0, 0, 1, 2) layout.addWidget(self.analysis_button, 1, 1) layout.addWidget(self.mask_button, 1, 0) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) self.setWindowIcon(analysis_icon) self.prepare = None self.wind = None def _launch_begin(self): self.progress.setVisible(True) self.progress.setRange(0, 0) self.analysis_button.setDisabled(True) self.mask_button.setDisabled(True) import_config() def launch_analysis(self): self._launch_begin() self.lib_path = "PartSeg.segmentation_analysis.main_window" self.final_title = "PartSeg Segmentation Analysis" self.prepare = Prepare(self.lib_path) self.prepare.finished.connect(self.launch) self.prepare.start() def launch_mask(self): self._launch_begin() self.lib_path = "PartSeg.segmentation_mask.main_window" self.final_title = "PartSeg Mask Segmentation" self.prepare = Prepare(self.lib_path) self.prepare.finished.connect(self.launch) self.prepare.start() def window_shown(self): self.close() def launch(self): if self.prepare.result is None: self.close() return if self.prepare.errors: errors_message = QMessageBox() errors_message.setText("There are errors during start") errors_message.setInformativeText( "During load saved state some of data could not be load properly\n" "The files has prepared backup copies in state directory (Help > State directory)" ) errors_message.setStandardButtons(QMessageBox.Ok) text = "\n".join(["File: " + x[0] + "\n" + str(x[1]) for x in self.prepare.errors]) errors_message.setDetailedText(text) errors_message.exec() wind = self.prepare.result(title=self.final_title, signal_fun=self.window_shown) wind.show() self.wind = wind
class AlgorithmOptions(QWidget): def __init__(self, settings: StackSettings, image_view: StackImageView): super().__init__() self.settings = settings self.view_name = image_view.name self.show_result = QEnumComboBox( enum_class=LabelEnum) # QCheckBox("Show result") self._set_show_label_from_settings() self.opacity = QDoubleSpinBox() self.opacity.setRange(0, 1) self.opacity.setSingleStep(0.1) self._set_opacity_from_settings() self.only_borders = QCheckBox("Only borders") self._set_border_mode_from_settings() self.borders_thick = QSpinBox() self.borders_thick.setRange(1, 25) self.borders_thick.setSingleStep(1) self._set_border_thick_from_settings() self.execute_in_background_btn = QPushButton("Execute in background") self.execute_in_background_btn.setToolTip( "Run calculation in background. Put result in multiple files panel" ) self.execute_btn = QPushButton("Execute") self.execute_btn.setStyleSheet("QPushButton{font-weight: bold;}") self.execute_all_btn = QPushButton("Execute all") self.execute_all_btn.setToolTip( "Execute in batch mode segmentation with current parameter. File list need to be specified in image tab." ) self.execute_all_btn.setDisabled(True) self.save_parameters_btn = QPushButton("Save parameters") self.block_execute_all_btn = False self.algorithm_choose_widget = AlgorithmChoose(settings, mask_algorithm_dict) self.algorithm_choose_widget.result.connect(self.execution_result_set) self.algorithm_choose_widget.finished.connect(self.execution_finished) self.algorithm_choose_widget.progress_signal.connect( self.progress_info) # self.stack_layout = QStackedLayout() self.keep_chosen_components_chk = QCheckBox("Save selected components") self.keep_chosen_components_chk.setToolTip( "Save chosen components when loading segmentation form file\n or from multiple file widget." ) self.keep_chosen_components_chk.stateChanged.connect( self.set_keep_chosen_components) self.keep_chosen_components_chk.setChecked( settings.keep_chosen_components) self.show_parameters = QPushButton("Show parameters") self.show_parameters.setToolTip( "Show parameters of segmentation for each components") self.show_parameters_widget = SegmentationInfoDialog( self.settings, self.algorithm_choose_widget.change_algorithm) self.show_parameters.clicked.connect(self.show_parameters_widget.show) self.choose_components = ChosenComponents() self.choose_components.check_change_signal.connect( image_view.refresh_selected) self.choose_components.mouse_leave.connect(image_view.component_unmark) self.choose_components.mouse_enter.connect(image_view.component_mark) # WARNING works only with one channels algorithms # SynchronizeValues.add_synchronization("channels_chose", widgets_list) self.chosen_list = [] self.progress_bar2 = QProgressBar() self.progress_bar2.setHidden(True) self.progress_bar = QProgressBar() self.progress_bar.setHidden(True) self.progress_info_lab = QLabel() self.progress_info_lab.setHidden(True) self.file_list = [] self.batch_process = BatchProceed() self.batch_process.progress_signal.connect(self.progress_info) self.batch_process.error_signal.connect(self.execution_all_error) self.batch_process.execution_done.connect(self.execution_all_done) self.batch_process.range_signal.connect(self.progress_bar.setRange) self.is_batch_process = False self.setContentsMargins(0, 0, 0, 0) main_layout = QVBoxLayout() # main_layout.setSpacing(0) opt_layout = QHBoxLayout() opt_layout.setContentsMargins(0, 0, 0, 0) opt_layout.addWidget(self.show_result) opt_layout.addWidget(right_label("Opacity:")) opt_layout.addWidget(self.opacity) main_layout.addLayout(opt_layout) opt_layout2 = QHBoxLayout() opt_layout2.setContentsMargins(0, 0, 0, 0) opt_layout2.addWidget(self.only_borders) opt_layout2.addWidget(right_label("Border thick:")) opt_layout2.addWidget(self.borders_thick) main_layout.addLayout(opt_layout2) btn_layout = QGridLayout() btn_layout.setContentsMargins(0, 0, 0, 0) btn_layout.addWidget(self.execute_btn, 0, 0) btn_layout.addWidget(self.execute_in_background_btn, 0, 1) btn_layout.addWidget(self.execute_all_btn, 1, 0) btn_layout.addWidget(self.save_parameters_btn, 1, 1) main_layout.addLayout(btn_layout) main_layout.addWidget(self.progress_bar2) main_layout.addWidget(self.progress_bar) main_layout.addWidget(self.progress_info_lab) main_layout.addWidget(self.algorithm_choose_widget, 1) # main_layout.addWidget(self.algorithm_choose) # main_layout.addLayout(self.stack_layout, 1) main_layout.addWidget(self.choose_components) down_layout = QHBoxLayout() down_layout.addWidget(self.keep_chosen_components_chk) down_layout.addWidget(self.show_parameters) main_layout.addLayout(down_layout) main_layout.addStretch() main_layout.setContentsMargins(0, 0, 0, 0) # main_layout.setSpacing(0) self.setLayout(main_layout) # noinspection PyUnresolvedReferences self.execute_in_background_btn.clicked.connect( self.execute_in_background) self.execute_btn.clicked.connect(self.execute_action) self.execute_all_btn.clicked.connect(self.execute_all_action) self.save_parameters_btn.clicked.connect(self.save_parameters) # noinspection PyUnresolvedReferences self.opacity.valueChanged.connect(self._set_opacity) # noinspection PyUnresolvedReferences self.show_result.currentEnumChanged.connect(self._set_show_label) self.only_borders.stateChanged.connect(self._set_border_mode) # noinspection PyUnresolvedReferences self.borders_thick.valueChanged.connect(self._set_border_thick) image_view.component_clicked.connect( self.choose_components.other_component_choose) settings.chosen_components_widget = self.choose_components settings.components_change_list.connect( self.choose_components.new_choose) settings.image_changed.connect( self.choose_components.remove_components) settings.connect_to_profile( f"{self.view_name}.image_state.only_border", self._set_border_mode_from_settings) settings.connect_to_profile( f"{self.view_name}.image_state.border_thick", self._set_border_thick_from_settings) settings.connect_to_profile(f"{self.view_name}.image_state.opacity", self._set_opacity_from_settings) settings.connect_to_profile(f"{self.view_name}.image_state.show_label", self._set_show_label_from_settings) def _set_border_mode(self, value: bool): self.settings.set_in_profile( f"{self.view_name}.image_state.only_border", value) def _set_border_thick(self, value: int): self.settings.set_in_profile( f"{self.view_name}.image_state.border_thick", value) def _set_opacity(self, value: float): self.settings.set_in_profile(f"{self.view_name}.image_state.opacity", value) def _set_show_label(self, value: LabelEnum): self.settings.set_in_profile( f"{self.view_name}.image_state.show_label", value) def _set_border_mode_from_settings(self): self.only_borders.setChecked( self.settings.get_from_profile( f"{self.view_name}.image_state.only_border", True)) def _set_border_thick_from_settings(self): self.borders_thick.setValue( self.settings.get_from_profile( f"{self.view_name}.image_state.border_thick", 1)) def _set_opacity_from_settings(self): self.opacity.setValue( self.settings.get_from_profile( f"{self.view_name}.image_state.opacity", 1.0)) def _set_show_label_from_settings(self): self.show_result.setCurrentEnum( self.settings.get_from_profile( f"{self.view_name}.image_state.show_label", LabelEnum.Show_results)) @Slot(int) def set_keep_chosen_components(self, val): self.settings.set_keep_chosen_components(val) def save_parameters(self): dial = PSaveDialog(io_functions.save_parameters_dict, system_widget=False, settings=self.settings, path=IO_SAVE_DIRECTORY) if not dial.exec_(): return res = dial.get_result() res.save_class.save(res.save_destination, self.algorithm_choose_widget.current_parameters()) def file_list_change(self, val): self.file_list = val if len(self.file_list) > 0 and not self.block_execute_all_btn: self.execute_all_btn.setEnabled(True) else: self.execute_all_btn.setDisabled(True) def get_chosen_components(self): return sorted(self.choose_components.get_chosen()) @property def segmentation(self): return self.settings.roi @segmentation.setter def segmentation(self, val): self.settings.roi = val def _image_changed(self): self.settings.roi = None self.choose_components.set_chose([], []) def _execute_in_background_init(self): if self.batch_process.isRunning(): return self.progress_bar2.setVisible(True) self.progress_bar2.setRange(0, self.batch_process.queue.qsize()) self.progress_bar2.setValue(self.batch_process.index) self.progress_bar.setVisible(True) self.progress_bar.setValue(0) self.execute_btn.setDisabled(True) self.batch_process.start() def execute_in_background(self): # TODO check if components are properly passed widget = self.algorithm_choose_widget.current_widget() segmentation_profile = widget.get_segmentation_profile() task = BatchTask(self.settings.get_project_info(), segmentation_profile, None) self.batch_process.add_task(task) self.progress_bar2.setRange(0, self.progress_bar2.maximum() + 1) self._execute_in_background_init() def execute_all_action(self): dial = PSaveDialog( SaveROI, settings=self.settings, system_widget=False, path="io.save_batch", file_mode=PSaveDialog.Directory, ) if not dial.exec_(): return folder_path = str(dial.selectedFiles()[0]) widget = self.algorithm_choose_widget.current_widget() save_parameters = dial.values segmentation_profile = widget.get_segmentation_profile() for file_path in self.file_list: task = BatchTask(file_path, segmentation_profile, (folder_path, save_parameters)) self.batch_process.add_task(task) self.progress_bar2.setRange( 0, self.progress_bar2.maximum() + len(self.file_list)) self._execute_in_background_init() def execution_all_error(self, text): QMessageBox.warning(self, "Proceed error", text) def execution_all_done(self): if not self.batch_process.queue.empty(): self._execute_in_background_init() return self.execute_btn.setEnabled(True) self.block_execute_all_btn = False if len(self.file_list) > 0: self.execute_all_btn.setEnabled(True) self.progress_bar.setHidden(True) self.progress_bar2.setHidden(True) self.progress_info_lab.setHidden(True) def execute_action(self): self.execute_btn.setDisabled(True) self.execute_all_btn.setDisabled(True) self.block_execute_all_btn = True self.is_batch_process = False self.progress_bar.setRange(0, 0) self.choose_components.setDisabled(True) chosen = sorted(self.choose_components.get_chosen()) blank = get_mask(self.settings.roi, self.settings.mask, chosen) if blank is not None: # Problem with handling time data in algorithms # TODO Fix This blank = blank[0] self.progress_bar.setHidden(False) widget: AlgorithmSettingsWidget = self.algorithm_choose_widget.current_widget( ) widget.set_mask(blank) self.progress_bar.setRange(0, widget.algorithm.get_steps_num()) widget.execute() self.chosen_list = chosen def progress_info(self, text, num, file_name="", file_num=0): self.progress_info_lab.setVisible(True) if file_name != "": self.progress_info_lab.setText(file_name + "\n" + text) else: self.progress_info_lab.setText(text) self.progress_bar.setValue(num) self.progress_bar2.setValue(file_num) def execution_finished(self): self.execute_btn.setEnabled(True) self.block_execute_all_btn = False if len(self.file_list) > 0: self.execute_all_btn.setEnabled(True) self.progress_bar.setHidden(True) self.progress_info_lab.setHidden(True) self.choose_components.setDisabled(False) def execution_result_set(self, result): self.settings.set_segmentation_result(result) def showEvent(self, _): widget = self.algorithm_choose_widget.current_widget() widget.image_changed(self.settings.image)