def __init__(self, parent, video: Video, index, first=False): self.loading = True super().__init__(parent) self.parent = parent self.index = index self.first = first self.last = False self.video = video.copy() self.setFixedHeight(60) self.widgets = Box( up_button=QtWidgets.QPushButton( QtGui.QIcon( get_icon("up-arrow", self.parent.app.fastflix.config.theme)), ""), down_button=QtWidgets.QPushButton( QtGui.QIcon( get_icon("down-arrow", self.parent.app.fastflix.config.theme)), ""), cancel_button=QtWidgets.QPushButton( QtGui.QIcon( get_icon("black-x", self.parent.app.fastflix.config.theme)), ""), reload_button=QtWidgets.QPushButton( QtGui.QIcon( get_icon("edit-box", self.parent.app.fastflix.config.theme)), ""), retry_button=QtWidgets.QPushButton( QtGui.QIcon( get_icon("undo", self.parent.app.fastflix.config.theme)), ""), ) for widget in self.widgets.values(): widget.setStyleSheet(no_border) title = QtWidgets.QLabel( video.video_settings.video_title if video.video_settings. video_title else video.video_settings.output_path.name) title.setFixedWidth(300) settings = Box(copy.deepcopy(video.video_settings.dict())) settings.output_path = str(settings.output_path) for i, o in enumerate(settings.attachment_tracks): if o.get("file_path"): o["file_path"] = str(o["file_path"]) del settings.conversion_commands title.setToolTip(settings.to_yaml()) open_button = QtWidgets.QPushButton( QtGui.QIcon(get_icon("play", self.parent.app.fastflix.config.theme)), t("Open Directory")) open_button.setLayoutDirection(QtCore.Qt.RightToLeft) open_button.setIconSize(QtCore.QSize(14, 14)) open_button.clicked.connect( lambda: open_folder(video.video_settings.output_path.parent)) view_button = QtWidgets.QPushButton( QtGui.QIcon(get_icon("play", self.parent.app.fastflix.config.theme)), t("Watch")) view_button.setLayoutDirection(QtCore.Qt.RightToLeft) view_button.setIconSize(QtCore.QSize(14, 14)) view_button.clicked.connect(lambda: QtGui.QDesktopServices.openUrl( QtCore.QUrl.fromLocalFile(str(video.video_settings.output_path)))) open_button.setStyleSheet(no_border) view_button.setStyleSheet(no_border) add_retry = False status = t("Ready to encode") if video.status.error: status = t("Encoding errored") elif video.status.complete: status = f"{t('Encoding complete')}" elif video.status.running: status = ( f"{t('Encoding command')} {video.status.current_command + 1} {t('of')} " f"{len(video.video_settings.conversion_commands)}") elif video.status.cancelled: status = t("Cancelled") add_retry = True if not self.video.status.running: self.widgets.cancel_button.clicked.connect( lambda: self.parent.remove_item(self.video)) self.widgets.reload_button.clicked.connect( lambda: self.parent.reload_from_queue(self.video)) self.widgets.cancel_button.setFixedWidth(25) self.widgets.reload_button.setFixedWidth(25) else: self.widgets.cancel_button.hide() self.widgets.reload_button.hide() grid = QtWidgets.QGridLayout() grid.addLayout(self.init_move_buttons(), 0, 0) # grid.addWidget(self.widgets.track_number, 0, 1) grid.addWidget(title, 0, 1, 1, 3) grid.addWidget( QtWidgets.QLabel( f"{video.video_settings.video_encoder_settings.name}"), 0, 4) grid.addWidget( QtWidgets.QLabel( f"{t('Audio Tracks')}: {len(video.video_settings.audio_tracks)}" ), 0, 5) grid.addWidget( QtWidgets.QLabel( f"{t('Subtitles')}: {len(video.video_settings.subtitle_tracks)}" ), 0, 6) grid.addWidget(QtWidgets.QLabel(status), 0, 7) if video.status.complete and not get_bool_env("FF_DOCKERMODE"): grid.addWidget(view_button, 0, 8) grid.addWidget(open_button, 0, 9) elif add_retry: grid.addWidget(self.widgets.retry_button, 0, 8) self.widgets.retry_button.setFixedWidth(25) self.widgets.retry_button.clicked.connect( lambda: self.parent.retry_video(self.video)) right_buttons = QtWidgets.QHBoxLayout() right_buttons.addWidget(self.widgets.reload_button) right_buttons.addWidget(self.widgets.cancel_button) grid.addLayout(right_buttons, 0, 10, alignment=QtCore.Qt.AlignRight) self.setLayout(grid) self.loading = False self.updating_burn = False
class MainWindow(QtWidgets.QMainWindow, UIMainWindow): # When a new patient file is opened from the main window open_patient_window = QtCore.Signal() # When the pyradiomics button is pressed run_pyradiomics = QtCore.Signal(str, dict, str) # When the image fusion button is pressed image_fusion_signal = QtCore.Signal() # When pt/ct button is pressed pt_ct_signal = QtCore.Signal() # Initialising the main window and setting up the UI def __init__(self): QtWidgets.QMainWindow.__init__(self) create_initial_model() self.setup_ui(self) self.action_handler.action_open.triggered.connect( self.open_new_patient) self.action_handler.action_image_fusion.triggered.connect( self.open_image_fusion) self.pyradi_trigger.connect(self.pyradiomics_handler) self.pet_ct_tab.load_pt_ct_signal.connect(self.initialise_pt_ct) def update_ui(self): create_initial_model() self.setup_central_widget() self.setup_actions() self.add_on_options_controller.update_ui() self.action_handler.action_open.triggered.connect( self.open_new_patient) self.action_handler.action_image_fusion.triggered.connect( self.open_image_fusion) self.pet_ct_tab.load_pt_ct_signal.connect(self.initialise_pt_ct) def initialise_pt_ct(self): self.pt_ct_signal.emit() def load_pt_ct_tab(self): pcd = PTCTDictContainer() if not pcd.is_empty(): self.pet_ct_tab.load_pet_ct() self.right_panel.setCurrentWidget(self.pet_ct_tab) def open_new_patient(self): """ Function to handle the Open patient button being clicked """ confirmation_dialog = QMessageBox.information( self, 'Open new patient?', 'Opening a new patient will close the currently opened patient. ' 'Would you like to continue?', QMessageBox.Yes | QMessageBox.No) if confirmation_dialog == QMessageBox.Yes: self.open_patient_window.emit() def open_image_fusion(self): self.image_fusion_signal.emit() def update_image_fusion_ui(self): mvd = MovingDictContainer() if not mvd.is_empty(): read_images_for_fusion() self.create_image_fusion_tab() def pyradiomics_handler(self, path, filepaths, hashed_path): """ Sends signal to initiate pyradiomics analysis """ if which('plastimatch') is not None: if hashed_path == '': confirm_pyradi = QMessageBox.information( self, "Confirmation", "Are you sure you want to perform pyradiomics? Once " "started the process cannot be terminated until it " "finishes.", QMessageBox.Yes, QMessageBox.No) if confirm_pyradi == QMessageBox.Yes: self.run_pyradiomics.emit(path, filepaths, hashed_path) if confirm_pyradi == QMessageBox.No: pass else: self.run_pyradiomics.emit(path, filepaths, hashed_path) else: exe_not_found = QMessageBox.information( self, "Error", "Plastimatch not installed. Please install Plastimatch " "(https://sourceforge.net/projects/plastimatch/) to carry out " "pyradiomics analysis. If using Windows, please ensure that " "your system's PATH variable inlcudes the directory where " "Plastimatch's executable is installed.") def cleanup(self): patient_dict_container = PatientDictContainer() patient_dict_container.clear() # Close 3d vtk widget self.three_dimension_view.close() self.cleanup_image_fusion() self.cleanup_pt_ct_viewer() def cleanup_image_fusion(self): # Explicity destroy objects - the purpose of this is to clear # any image fusion tabs that have been used previously. # Try-catch in the event user has not prompted image-fusion. try: del self.image_fusion_view_coronal del self.image_fusion_view_sagittal del self.image_fusion_view_axial del self.image_fusion_four_views_layout del self.image_fusion_four_views del self.image_fusion_single_view del self.image_fusion_view except: pass moving_dict_container = MovingDictContainer() moving_dict_container.clear() def cleanup_pt_ct_viewer(self): pt_ct_dict_container = PTCTDictContainer() pt_ct_dict_container.clear() self.pet_ct_tab.initialised = False try: del self.pet_ct_tab except: pass def closeEvent(self, event: QtGui.QCloseEvent) -> None: patient_dict_container = PatientDictContainer() if patient_dict_container.get("rtss_modified") \ and hasattr(self, "structures_tab"): confirmation_dialog = QMessageBox.information( self, 'Close without saving?', 'The RTSTRUCT file has been modified. Would you like to save ' 'before exiting the program?', QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) if confirmation_dialog == QMessageBox.Save: self.structures_tab.save_new_rtss_to_fixed_image_set() event.accept() self.cleanup() elif confirmation_dialog == QMessageBox.Discard: event.accept() self.cleanup() else: event.ignore() else: self.cleanup()
class StatusPanel(QtWidgets.QWidget): speed = QtCore.Signal(str) bitrate = QtCore.Signal(str) nvencc_signal = QtCore.Signal(str) tick_signal = QtCore.Signal() def __init__(self, parent, app: FastFlixApp): super().__init__(parent) self.app = app self.main = parent.main self.current_video: Optional[Video] = None self.started_at = None self.ticker_thread = ElapsedTimeTicker(self, self.tick_signal) self.ticker_thread.start() layout = QtWidgets.QGridLayout() self.hide_nal = QtWidgets.QCheckBox(t("Hide NAL unit messages")) self.hide_nal.setChecked(True) self.eta_label = QtWidgets.QLabel(f"{t('Time Left')}: N/A") self.eta_label.setToolTip(t("Estimated time left for current command")) self.eta_label.setStyleSheet("QLabel{margin-right:50px}") self.time_elapsed_label = QtWidgets.QLabel(f"{t('Time Elapsed')}: N/A") self.time_elapsed_label.setStyleSheet("QLabel{margin-right:50px}") self.size_label = QtWidgets.QLabel(f"{t('Size Estimate')}: N/A") self.size_label.setToolTip(t("Estimated file size based on bitrate")) h_box = QtWidgets.QHBoxLayout() h_box.addWidget(QtWidgets.QLabel(t("Encoder Output")), alignment=QtCore.Qt.AlignLeft) h_box.addStretch(1) h_box.addWidget(self.eta_label) h_box.addWidget(self.time_elapsed_label) h_box.addWidget(self.size_label) h_box.addStretch(1) h_box.addWidget(self.hide_nal, alignment=QtCore.Qt.AlignRight) layout.addLayout(h_box, 0, 0) self.inner_widget = Logs(self, self.app, self.main, self.app.fastflix.log_queue) layout.addWidget(self.inner_widget, 1, 0) self.setLayout(layout) self.speed.connect(self.update_speed) self.bitrate.connect(self.update_bitrate) self.nvencc_signal.connect(self.update_nvencc) self.main.status_update_signal.connect(self.on_status_update) self.tick_signal.connect(self.update_time_elapsed) def cleanup(self): self.inner_widget.log_updater.terminate() self.ticker_thread.stop_signal.emit() self.ticker_thread.terminate() def get_movie_length(self): if not self.current_video: return 0 return (self.current_video.video_settings.end_time or self.current_video.duration ) - self.current_video.video_settings.start_time def update_speed(self, combined): if not combined: self.eta_label.setText(f"{t('Time Left')}: N/A") return try: time_passed, speed = combined.split("|") if speed == "N/A": self.eta_label.setText(f"{t('Time Left')}: N/A") return time_passed = time_to_number(time_passed) speed = float(speed) if not speed: return assert speed > 0.0001, speed length = self.get_movie_length() if not length: return data = timedelta(seconds=(length - time_passed) // speed) except Exception: logger.exception("can't update size ETA") self.eta_label.setText(f"{t('Time Left')}: N/A") else: if not speed: self.eta_label.setText(f"{t('Time Left')}: N/A") self.eta_label.setText( f"{t('Time Left')}: {timedelta_to_str(data)}") def update_bitrate(self, bitrate): if not bitrate or bitrate.strip() == "N/A": self.size_label.setText(f"{t('Size Estimate')}: N/A") return try: bitrate, _ = bitrate.split("k", 1) bitrate = float(bitrate) size_eta = (self.get_movie_length() * bitrate) / 8000 except AttributeError: self.size_label.setText(f"{t('Size Estimate')}: N/A") except Exception: logger.exception( f"can't update bitrate: {bitrate} - length {self.get_movie_length()}" ) self.size_label.setText(f"{t('Size Estimate')}: N/A") else: if not size_eta: self.size_label.setText(f"{t('Size Estimate')}: N/A") self.size_label.setText(f"{t('Size Estimate')}: {size_eta:.2f}MB") def update_nvencc(self, raw_line): """ Example line: [53.1%] 19/35 frames: 150.57 fps, 5010 kb/s, remain 0:01:55, GPU 10%, VE 96%, VD 42%, est out size 920.6MB """ for section in raw_line.split(","): section = section.strip() if section.startswith("remain"): self.eta_label.setText( f"{t('Time Left')}: {section.rsplit(maxsplit=1)[1]}") elif section.startswith("est out size"): self.size_label.setText( f"{t('Size Estimate')}: {section.rsplit(maxsplit=1)[1]}") def update_time_elapsed(self): now = datetime.datetime.now(datetime.timezone.utc) if not self.started_at: logger.warning( "Unable to update time elapsed because start time isn't set") return try: time_elapsed = now - self.started_at except Exception: logger.exception("Unable to calculate elapsed time") return self.time_elapsed_label.setText( f"{t('Time Elapsed')}: {timedelta_to_str(time_elapsed)}") def on_status_update(self): # If there was a status change, we need to restart ticker no matter what self.started_at = datetime.datetime.now(datetime.timezone.utc) def close(self): self.ticker_thread.terminate() super().close()
def qCleanupResources(): QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
class Localization_GUI(QtWidgets.QWidget): output_setting_Tab_Localization_internal = QtCore.Signal(object) output_setting_Tab_Localization_external = QtCore.Signal(object) update_tab_index = QtCore.Signal(int) def __init__(self, parent=None): super(Localization_GUI, self).__init__(parent) self.flag_localization_setting = False self.flag_fineLocalization_setting = False self.flag_sfilter_setting = False self.min_radial = None self.max_radial = None self.rvt_kind = None self.highpass_size = None self.upsample = None self.rweights = None self.coarse_factor = None self.coarse_mode = None self.pad_mode = None self.min_sigma = None self.max_sigma = None self.sigma_ratio = None self.threshold = None self.overlap = None self.frame_num = 0 self.setting_localization = {} self.crappy_thr = None self.scale = None self.thr_sigma = None self.win_size_Fitting = None self.empty_value_box_flag = False self.flag_remove_box = True self.mode = None self.resize(300, 300) self.setWindowTitle('2D Localization') self.next = QtWidgets.QPushButton("Next") self.next.clicked.connect(self.update_tab) self.next.setFixedWidth(150) self.btn_FineLocalizationUpdate = QtWidgets.QPushButton("Update Fine Localization") self.btn_FineLocalizationUpdate.clicked.connect(self.do_fineLocalization) self.btn_FineLocalizationUpdate.setFixedWidth(150) self.btn_localizationUpdate = QtWidgets.QPushButton("Update Localization") self.btn_localizationUpdate.clicked.connect(self.do_localization) self.btn_localizationUpdate.setFixedWidth(150) self.btn_filtering = QtWidgets.QPushButton('Filtering', self) self.btn_filtering.clicked.connect(self.do_Filtering) self.btn_filtering.setIconSize(QtCore.QSize(24, 24)) self.btn_filtering.setMaximumSize(100, 70) self.mode_list = {"Bright PSF": "Bright", "Dark PSF": "Dark", "Bright & Dark PSF": "BOTH"} self.method_list = {"Difference of Gaussian": "dog", "Laplacian of Gaussian": "log", "Determinant of Hessian": "doh", "Radial Symmetry": "frst_one_psf", 'RVT': 'RVT'} self.output_setting_Tab_Localization_internal.connect(self.update_setting) self.combo = QtWidgets.QComboBox(self) self.combo.addItem("-Select the method-") self.combo.addItem("Difference of Gaussian") self.combo.addItem("Laplacian of Gaussian") self.combo.addItem("Determinant of Hessian") self.combo.addItem("Radial Symmetry") self.combo.addItem("RVT") self.combo.currentIndexChanged.connect(self.on_select) self.grid = QtWidgets.QGridLayout() self.grid.addWidget(self.createFirstExclusiveGroup(), 0, 0) self.grid.addWidget(self.createSecondExclusiveGroup(), 1, 0) self.grid.addWidget(self.createThirdExclusiveGroup(), 2, 0) self.grid.addWidget(self.createFourthExclusiveGroup(), 3, 0) self.grid.addWidget(self.next, 4, 0) self.setLayout(self.grid) def __del__(self): print('Destructor called, Employee deleted.') def createFirstExclusiveGroup(self): groupBox = QtWidgets.QGroupBox("PSF Localization") self.grid_Localization = QtWidgets.QGridLayout() self.grid_Localization.addWidget(self.combo, 0, 0) groupBox.setLayout(self.grid_Localization) return groupBox def createSecondExclusiveGroup(self): self.le_win_size = QtWidgets.QLineEdit() self.le_win_size.setPlaceholderText("win_size") self.le_win_size_label = QtWidgets.QLabel("Neighborhood size (px):") self.groupBox_fine_localization = QtWidgets.QGroupBox("Fine localization:") self.groupBox_fine_localization.setCheckable(True) self.groupBox_fine_localization.setChecked(False) self.gridFine_Localization = QtWidgets.QGridLayout() self.gridFine_Localization.addWidget(self.le_win_size_label, 0, 0) self.gridFine_Localization.addWidget(self.le_win_size, 0, 1) self.groupBox_fine_localization.setLayout(self.gridFine_Localization) return self.groupBox_fine_localization def createThirdExclusiveGroup(self): self.groupBox_update = QtWidgets.QGroupBox("Update:") self.grid_applyLocalization = QtWidgets.QGridLayout() self.grid_applyLocalization.addWidget(self.btn_localizationUpdate, 0, 1) self.grid_applyLocalization.addWidget(self.btn_FineLocalizationUpdate, 0, 2) self.groupBox_update.setLayout(self.grid_applyLocalization) return self.groupBox_update def createFourthExclusiveGroup(self): self.checkbox_filter_double_PSF = QtWidgets.QCheckBox("Filter dense PSFs", self) self.checkbox_filter_side_lobes_PSF = QtWidgets.QCheckBox("Filter side lobes PSFs", self) self.checkbox_filter_asymmetry_PSF = QtWidgets.QCheckBox("Filter asymmetry PSFs", self) self.checkbox_2DFitting = QtWidgets.QCheckBox("2D Gaussian Fitting", self) self.checkbox_crappy_frames = QtWidgets.QCheckBox("Filter outlier frames", self) self.checkbox_filter_asymmetry_PSF.toggled.connect(lambda: self.add_line_asymmetry_PSF()) self.checkbox_2DFitting.toggled.connect(lambda: self.add_line_2DFitting()) self.checkbox_crappy_frames.toggled.connect(lambda: self.add_line_crappy_frames()) self.groupBox_filters = QtWidgets.QGroupBox("Spatial filters:") self.groupBox_filters.setCheckable(True) self.groupBox_filters.setChecked(False) self.grid_filters = QtWidgets.QGridLayout() self.grid_filters.addWidget(self.checkbox_crappy_frames, 0, 0) self.grid_filters.addWidget(self.checkbox_filter_double_PSF, 1, 0) self.grid_filters.addWidget(self.checkbox_filter_side_lobes_PSF, 2, 0) self.grid_filters.addWidget(self.checkbox_filter_asymmetry_PSF, 3, 0) self.grid_filters.addWidget(self.checkbox_2DFitting, 4, 0) self.grid_filters.addWidget(self.btn_filtering, 5, 0) self.groupBox_filters.setLayout(self.grid_filters) return self.groupBox_filters def add_line_crappy_frames(self): if self.checkbox_crappy_frames.isChecked(): self.line_edit_crappy = QtWidgets.QLineEdit(self) self.line_edit_crappy.setPlaceholderText('Max number PSFs') self.line_edit_crappy_label = QtWidgets.QLabel("Max number PSFs:") self.grid_filters.addWidget(self.line_edit_crappy_label, 0, 1) self.grid_filters.addWidget(self.line_edit_crappy, 0, 2) if not self.checkbox_crappy_frames.isChecked(): for i_ in range(1, 5, 1): layout = self.grid_filters.itemAtPosition(0, i_) if layout is not None: layout.widget().deleteLater() self.grid_filters.removeItem(layout) def add_line_asymmetry_PSF(self): if self.checkbox_filter_asymmetry_PSF.isChecked(): self.line_asymmetry_PSF = QtWidgets.QLineEdit(self) self.line_asymmetry_PSF.setPlaceholderText('Scale based on sigma size') self.line_asymmetry_PSF_label = QtWidgets.QLabel("Win_size (px):") self.line_asymmetry_PSF_Thr = QtWidgets.QLineEdit(self) tmp_str = "\u03C3" self.line_asymmetry_PSF_Thr.setPlaceholderText(tmp_str + "_x" + "/" + tmp_str + "_y") self.line_asymmetry_PSF_Thr_label = QtWidgets.QLabel("Asymmetry threshold:") self.grid_filters.addWidget(self.line_asymmetry_PSF_label, 3, 1) self.grid_filters.addWidget(self.line_asymmetry_PSF, 3, 2) self.grid_filters.addWidget(self.line_asymmetry_PSF_Thr_label, 3, 3) self.grid_filters.addWidget(self.line_asymmetry_PSF_Thr, 3, 4) if not self.checkbox_filter_asymmetry_PSF.isChecked(): for i_ in range(1, 5, 1): layout = self.grid_filters.itemAtPosition(3, i_) if layout is not None: layout.widget().deleteLater() self.grid_filters.removeItem(layout) def add_line_2DFitting(self): if self.checkbox_2DFitting.isChecked(): self.line_2DFitting = QtWidgets.QLineEdit(self) self.line_2DFitting.setPlaceholderText('Scale based on sigma size') self.line_2DFitting_label = QtWidgets.QLabel("Win_size (px):") self.grid_filters.addWidget(self.line_2DFitting_label, 4, 1) self.grid_filters.addWidget(self.line_2DFitting, 4, 2) if not self.checkbox_2DFitting.isChecked(): for i_ in range(1, 5, 1): layout = self.grid_filters.itemAtPosition(4, i_) if layout is not None: layout.widget().deleteLater() self.grid_filters.removeItem(layout) def on_select(self): if self.combo.currentText() == "Difference of Gaussian": while self.flag_remove_box: self.remove_extra_box() self.flag_remove_box = True self.combo_item = self.method_list[self.combo.currentText()] self.PSF_mode() self.create_como_values() elif self.combo.currentText() == "Laplacian of Gaussian": while self.flag_remove_box: self.remove_extra_box() self.flag_remove_box = True self.combo_item = self.method_list[self.combo.currentText()] self.PSF_mode() self.create_como_values() elif self.combo.currentText() == "Determinant of Hessian": while self.flag_remove_box: self.remove_extra_box() self.flag_remove_box = True self.combo_item = self.method_list[self.combo.currentText()] self.create_como_values() elif self.combo.currentText() == "Radial Symmetry": while self.flag_remove_box: self.remove_extra_box() self.flag_remove_box = True self.combo_item = self.method_list[self.combo.currentText()] self.msg_box2 = QtWidgets.QMessageBox() self.msg_box2.setWindowTitle("Warning!") self.msg_box2.setText("This function only works when you have only one PSF in each frame!") self.msg_box2.exec_() elif self.combo.currentText() == "RVT": while self.flag_remove_box: self.remove_extra_box() self.flag_remove_box = True self.combo_item = self.method_list[self.combo.currentText()] self.create_rvt_como_values() def PSF_mode(self): self.combo_mode = QtWidgets.QComboBox(self) self.combo_mode.addItem("-Select the Mode-") self.combo_mode.addItem("Bright PSF") self.combo_mode.addItem("Dark PSF") self.combo_mode.addItem("Bright & Dark PSF") self.combo_mode.currentIndexChanged.connect(self.on_select_mode) self.grid_Localization.addWidget(self.combo_mode, 0, 1) def on_select_mode(self): self.mode = self.mode_list[self.combo_mode.currentText()] def create_como_values(self): self.le_1 = QtWidgets.QLineEdit() self.le_1.setPlaceholderText("Min Sigma") self.le_1_label = QtWidgets.QLabel("Min Sigma (px): ") self.le_2 = QtWidgets.QLineEdit() self.le_2.setPlaceholderText("Max Sigma") self.le_2_label = QtWidgets.QLabel("Max Sigma (px): ") self.le_3 = QtWidgets.QLineEdit() self.le_3.setPlaceholderText("Sigma Ratio/Num Sigma") self.le_3_label = QtWidgets.QLabel("Sigma Ratio/Num Sigma: ") self.le_4 = QtWidgets.QLineEdit() self.le_4.setPlaceholderText("Threshold") self.le_4_label = QtWidgets.QLabel("Threshold: ") self.le_5 = QtWidgets.QLineEdit() self.le_5.setPlaceholderText("Overlap") self.le_5_label = QtWidgets.QLabel("Overlap (px): ") self.grid_Localization.addWidget(self.le_1_label, 1, 0) self.grid_Localization.addWidget(self.le_2_label, 2, 0) self.grid_Localization.addWidget(self.le_3_label, 3, 0) self.grid_Localization.addWidget(self.le_4_label, 1, 2) self.grid_Localization.addWidget(self.le_5_label, 2, 2) self.grid_Localization.addWidget(self.le_1, 1, 1) self.grid_Localization.addWidget(self.le_2, 2, 1) self.grid_Localization.addWidget(self.le_3, 3, 1) self.grid_Localization.addWidget(self.le_4, 1, 3) self.grid_Localization.addWidget(self.le_5, 2, 3) def create_rvt_como_values(self): self.le_1 = QtWidgets.QLineEdit() self.le_1.setPlaceholderText("Min radius") self.le_1_label = QtWidgets.QLabel("Min radius (px): ") self.le_2 = QtWidgets.QLineEdit() self.le_2.setPlaceholderText("Max radius") self.le_2_label = QtWidgets.QLabel("Max radius (px): ") self.le_3 = QtWidgets.QLineEdit() self.le_3.setPlaceholderText("highpass_size") self.le_3_label = QtWidgets.QLabel("Highpass_size: ") self.le_4 = QtWidgets.QLineEdit() self.le_4.setPlaceholderText("upsample") self.le_4_label = QtWidgets.QLabel("Upsample: ") self.le_5 = QtWidgets.QLineEdit() self.le_5.setPlaceholderText("rweights") self.le_5_label = QtWidgets.QLabel("rweights: ") self.le_6 = QtWidgets.QLineEdit() self.le_6.setPlaceholderText("coarse_factor") self.le_6_label = QtWidgets.QLabel("Coarse_factor: ") self.le_7 = QtWidgets.QLineEdit() self.le_7.setPlaceholderText("Threshold") self.le_7_label = QtWidgets.QLabel("Threshold: ") self.pad_mode_group = QtWidgets.QButtonGroup() self.radio_pad_mode_constant = QtWidgets.QRadioButton("Pad mode (constant)") self.radio_pad_mode_reflect = QtWidgets.QRadioButton("Pad mode (reflect)") self.radio_pad_mode_edge = QtWidgets.QRadioButton("Pad mode (edge)") self.radio_pad_mode_fast = QtWidgets.QRadioButton("Pad mode (fast)") self.pad_mode_group.addButton(self.radio_pad_mode_constant) self.pad_mode_group.addButton(self.radio_pad_mode_reflect) self.pad_mode_group.addButton(self.radio_pad_mode_edge) self.pad_mode_group.addButton(self.radio_pad_mode_fast) self.radio_pad_mode_constant.setChecked(True) self.coarse_mode_group = QtWidgets.QButtonGroup() self.radio_coarse_mode_add = QtWidgets.QRadioButton("Coarse mode (add)") self.radio_coarse_mode_skip = QtWidgets.QRadioButton("Coarse mode (skip)") self.coarse_mode_group.addButton(self.radio_coarse_mode_add) self.coarse_mode_group.addButton(self.radio_coarse_mode_skip) self.radio_coarse_mode_add.setChecked(True) self.kind_group = QtWidgets.QButtonGroup() self.radio_kind_basic = QtWidgets.QRadioButton("Kind (basic)") self.radio_kind_normalized = QtWidgets.QRadioButton("Kind (normalized)") self.kind_group.addButton(self.radio_kind_basic) self.kind_group.addButton(self.radio_kind_normalized) self.radio_kind_basic.setChecked(True) self.grid_Localization.addWidget(self.le_1_label, 1, 0) self.grid_Localization.addWidget(self.le_2_label, 2, 0) self.grid_Localization.addWidget(self.le_3_label, 3, 0) self.grid_Localization.addWidget(self.le_4_label, 1, 2) self.grid_Localization.addWidget(self.le_5_label, 2, 2) self.grid_Localization.addWidget(self.le_6_label, 3, 2) self.grid_Localization.addWidget(self.le_7_label, 5, 2) self.grid_Localization.addWidget(self.le_1, 1, 1) self.grid_Localization.addWidget(self.le_2, 2, 1) self.grid_Localization.addWidget(self.le_3, 3, 1) self.grid_Localization.addWidget(self.le_4, 1, 3) self.grid_Localization.addWidget(self.le_5, 2, 3) self.grid_Localization.addWidget(self.le_6, 3, 3) self.grid_Localization.addWidget(self.le_7, 5, 3) self.grid_Localization.addWidget(self.radio_pad_mode_constant, 4, 0) self.grid_Localization.addWidget(self.radio_pad_mode_reflect, 4, 1) self.grid_Localization.addWidget(self.radio_pad_mode_edge, 4, 2) self.grid_Localization.addWidget(self.radio_pad_mode_fast, 4, 3) self.grid_Localization.addWidget(self.radio_coarse_mode_add, 5, 0) self.grid_Localization.addWidget(self.radio_coarse_mode_skip, 5, 1) self.grid_Localization.addWidget(self.radio_kind_basic, 6, 0) self.grid_Localization.addWidget(self.radio_kind_normalized, 6, 1) def remove_extra_box(self): layout_combo = self.grid_Localization.itemAtPosition(0, 1) if layout_combo is not None: layout_combo.widget().deleteLater() self.grid_Localization.removeItem(layout_combo) layout_pre_label = self.grid_Localization.itemAtPosition(1, 0) layout_pre = self.grid_Localization.itemAtPosition(1, 1) if layout_pre_label is not None: layout_pre_label.widget().deleteLater() self.grid_Localization.removeItem(layout_pre_label) if layout_pre is not None: layout_pre.widget().deleteLater() self.grid_Localization.removeItem(layout_pre) for i_ in range(1, 7, 1): for j_ in range(0, 6, 1): layout = self.grid_Localization.itemAtPosition(i_, j_) if layout is not None: layout.widget().deleteLater() self.grid_Localization.removeItem(layout) self.flag_remove_box = False def get_localization_method_parameters(self): try: if self.combo.currentText() != "Radial Symmetry" and self.combo.currentText() != "RVT": self.min_sigma = eval(self.le_1.text()) self.max_sigma = eval(self.le_2.text()) self.sigma_ratio = float(self.le_3.text()) self.threshold = float(self.le_4.text()) self.overlap = float(self.le_5.text()) elif self.combo.currentText() == "RVT": self.min_radial = eval(self.le_1.text()) self.max_radial = eval(self.le_2.text()) if self.radio_kind_basic.isChecked(): self.rvt_kind = 'basic' elif self.radio_kind_normalized.isChecked(): self.rvt_kind = 'normalized' self.highpass_size = self.le_3.text() if self.highpass_size == '': self.highpass_size = None else: self.highpass_size = float(self.highpass_size) self.upsample = self.le_4.text() if self.upsample == '': self.upsample = 1 else: self.upsample = int(self.upsample) self.rweights = self.le_5.text() if self.rweights == '': self.rweights = None else: self.rweights = eval(self.rweights) self.coarse_factor = self.le_6.text() if self.coarse_factor == '': self.coarse_factor = 1 else: self.coarse_factor = float(self.coarse_factor) if self.radio_coarse_mode_add.isChecked(): self.coarse_mode = 'add' elif self.radio_coarse_mode_skip.isChecked(): self.coarse_mode = 'skip' if self.radio_pad_mode_constant.isChecked(): self.pad_mode = "constant" elif self.radio_pad_mode_reflect.isChecked(): self.pad_mode = "reflect" elif self.radio_pad_mode_edge.isChecked(): self.pad_mode = "edge" elif self.radio_pad_mode_fast.isChecked(): self.pad_mode = "fast" if self.le_7.text() == '': self.threshold = 0 else: self.threshold = float(self.le_7.text()) if self.groupBox_fine_localization.isChecked() and self.combo.currentText() != "Radial Symmetry": self.win_size = int(self.le_win_size.text()) elif self.combo.currentText() == "Radial Symmetry" and self.groupBox_fine_localization.isChecked(): self.win_size = int(self.le_win_size.text()) elif self.combo.currentText() == "Radial Symmetry" and not self.groupBox_fine_localization.isChecked(): pass self.empty_value_box_flag = True except: self.msg_box3 = QtWidgets.QMessageBox() self.msg_box3.setWindowTitle("Warning!") self.msg_box3.setText("Please filled all parameters!") self.msg_box3.exec_() self.empty_value_box_flag = False def get_values_crappy_frames(self): try: self.crappy_thr = int(self.line_edit_crappy.text()) self.empty_value_box_flag = True except: self.msg_box3 = QtWidgets.QMessageBox() self.msg_box3.setWindowTitle("Warning!") self.msg_box3.setText("Please filled all parameters!") self.msg_box3.exec_() self.empty_value_box_flag = False def get_values_asymmetry_filtering(self): try: self.scale = int(self.line_asymmetry_PSF.text()) self.thr_sigma = float(self.line_asymmetry_PSF_Thr.text()) self.empty_value_box_flag = True except: self.msg_box3 = QtWidgets.QMessageBox() self.msg_box3.setWindowTitle("Warning!") self.msg_box3.setText("Please filled all parameters!") self.msg_box3.exec_() self.empty_value_box_flag = False def get_values_2DFitting(self): try: self.win_size_Fitting = int(self.line_2DFitting.text()) self.empty_value_box_flag = True except: self.msg_box3 = QtWidgets.QMessageBox() self.msg_box3.setWindowTitle("Warning!") self.msg_box3.setText("Please filled all parameters!") self.msg_box3.exec_() self.empty_value_box_flag = False def removekey(self, d, key): r = dict(d) try: del r[key] except: print('there is no key with the name ' + key) return r @QtCore.Slot() def do_localization(self): layout_combo = self.grid_Localization.itemAtPosition(0, 1) if layout_combo is not None: if self.combo.currentText() == "-Select the method-" or self.combo_mode.currentText() == "-Select the Mode-": self.msg_box1 = QtWidgets.QMessageBox() self.msg_box1.setWindowTitle("Warning!") self.msg_box1.setText("Please select one of the methods and modes.") self.msg_box1.exec_() flag_run = False else: flag_run = True elif layout_combo is None: if self.combo.currentText() == "-Select the method-": self.msg_box1 = QtWidgets.QMessageBox() self.msg_box1.setWindowTitle("Warning!") self.msg_box1.setText("Please select one of the methods.") self.msg_box1.exec_() flag_run = False else: flag_run = True if flag_run: self.get_localization_method_parameters() if self.empty_value_box_flag: self.setting_localization['function'] = self.combo_item self.setting_localization['min_sigma'] = self.min_sigma self.setting_localization['max_sigma'] = self.max_sigma self.setting_localization['sigma_ratio'] = self.sigma_ratio self.setting_localization['threshold'] = self.threshold self.setting_localization['overlap'] = self.overlap self.setting_localization['mode'] = self.mode self.setting_localization['min_radial'] = self.min_radial self.setting_localization['max_radial'] = self.max_radial self.setting_localization['highpass_size'] = self.highpass_size self.setting_localization['upsample'] = self.upsample self.setting_localization['rweights'] = self.rweights self.setting_localization['coarse_factor'] = self.coarse_factor self.setting_localization['coarse_mode'] = self.coarse_mode self.setting_localization['pad_mode'] = self.pad_mode self.setting_localization['rvt_kind'] = self.rvt_kind self.output_setting_Tab_Localization_internal.emit([self.setting_localization, 'localization']) self.empty_value_box_flag = False @QtCore.Slot() def do_fineLocalization(self): if self.groupBox_fine_localization.isChecked(): self.get_localization_method_parameters() if self.empty_value_box_flag: self.setting_localization['Flag_fine_localization'] = True self.setting_localization['Fine_localization_neighborhood_size (px)'] = self.win_size self.output_setting_Tab_Localization_internal.emit([self.setting_localization, 'fineLocalization']) self.empty_value_box_flag = False else: self.setting_localization['Flag_fine_localization'] = False self.setting_localization['Fine_localization_neighborhood_size (px)'] = None self.output_setting_Tab_Localization_internal.emit([self.setting_localization, 'fineLocalization']) @QtCore.Slot() def do_Filtering(self): if self.checkbox_crappy_frames.isChecked(): self.get_values_crappy_frames() if self.empty_value_box_flag: self.setting_localization['outlier_frames_filter'] = True self.setting_localization['Outlier_frames_filter_max_number_PSFs'] = self.crappy_thr self.empty_value_box_flag = False else: self.setting_localization['outlier_frames_filter'] = False self.setting_localization['Outlier_frames_filter_max_number_PSFs'] = None if self.checkbox_filter_double_PSF.isChecked(): self.setting_localization['Dense_Filter'] = True else: self.setting_localization['Dense_Filter'] = False if self.checkbox_filter_side_lobes_PSF.isChecked(): self.setting_localization['Side_lobes_Filter'] = True else: self.setting_localization['Side_lobes_Filter'] = False if self.checkbox_2DFitting.isChecked(): self.get_values_2DFitting() if self.empty_value_box_flag: self.setting_localization['Flag_fit_2DGaussian'] = True self.setting_localization['Fit_2DGaussian_win_size (px)'] = self.scale self.empty_value_box_flag = False else: self.setting_localization['Flag_fit_2DGaussian'] = False self.setting_localization['Fit_2DGaussian_win_size (px)'] = None if self.checkbox_filter_asymmetry_PSF.isChecked() and self.checkbox_2DFitting.isChecked(): self.get_values_asymmetry_filtering() if self.empty_value_box_flag: self.setting_localization['symmetric_PSFs_Filter'] = True self.setting_localization['Asymmetry_PSFs_filtering_threshold'] = self.thr_sigma self.setting_localization['Asymmetry_PSFs_filtering_win_size (px)'] = self.scale self.empty_value_box_flag = False else: self.setting_localization['symmetric_PSFs_Filter'] = False self.setting_localization['Asymmetry_PSFs_filtering_threshold'] = None self.setting_localization['Asymmetry_PSFs_filtering_win_size (px)'] = None self.output_setting_Tab_Localization_internal.emit([self.setting_localization, 'sfilter']) def update_setting(self, data_in): setting = data_in[0] key = data_in[1] if key == 'localization': self.flag_localization_setting = True elif key == 'fineLocalization': self.flag_fineLocalization_setting = True elif key == 'sfilter': self.flag_sfilter_setting = True @QtCore.Slot() def update_tab(self): if self.flag_localization_setting and self.flag_fineLocalization_setting and self.flag_sfilter_setting: self.update_tab_index.emit(3) self.output_setting_Tab_Localization_external.emit(self.setting_localization) else: self.msg_box3 = QtWidgets.QMessageBox() self.msg_box3.setWindowTitle("Warning!") self.msg_box3.setText("Please update the previous setting!") self.msg_box3.exec_() def closeEvent(self, event): QtCore.QCoreApplication.instance().quit()
class HiveAccount(QtCore.QObject): hiveAccExistsResult = QtCore.Signal(bool) hivePowerResult = QtCore.Signal(float) hiveRcResult = QtCore.Signal(str) hiveCommunitySubResult = QtCore.Signal(str) def __init__(self, settingsInstance: UserSettingsInstance) -> None: super().__init__() self.settingsInstance = settingsInstance @QtCore.Slot(bool) def exists(self, username): hive_accreq = { 'jsonrpc': '2.0', 'id': 1, 'method': 'condenser_api.get_accounts', 'params': [[username]] } account = requests.post(self.settingsInstance.get('hiveAPI'), json=hive_accreq) if account.status_code != 200 or 'error' in account.json() or len( account.json()['result']) == 0: return self.hiveAccExistsResult.emit(False) else: return self.hiveAccExistsResult.emit(True) @QtCore.Slot(str) def getHP(self, username): hive_accreq = { 'jsonrpc': '2.0', 'id': 1, 'method': 'condenser_api.get_accounts', 'params': [[username]] } hive_propsreq = { 'jsonrpc': '2.0', 'id': 1, 'method': 'condenser_api.get_dynamic_global_properties', 'params': [] } account = requests.post(self.settingsInstance.get('hiveAPI'), json=hive_accreq) props = requests.post(self.settingsInstance.get('hiveAPI'), json=hive_propsreq) if account.status_code != 200: return self.hivePowerResult.emit("Error") elif props.status_code != 200: return self.hivePowerResult.emit("Error") self.hivePowerResult.emit( float(props.json()['result']['total_vesting_fund_hive'][:-5]) / float(props.json()['result']['total_vesting_shares'][:-6]) * (float(account.json()['result'][0]['vesting_shares'][:-6]) - float( account.json()['result'][0]['delegated_vesting_shares'][:-6]) + float( account.json()['result'][0]['received_vesting_shares'][:-6]))) @QtCore.Slot(str) def getRC(self, username): hive_rcreq = { 'jsonrpc': '2.0', 'id': 1, 'method': 'rc_api.find_rc_accounts', 'params': { 'accounts': [username] } } rc = requests.post(self.settingsInstance.get('hiveAPI'), json=hive_rcreq) if rc.status_code != 200: self.hiveRcResult.emit("Error") else: self.hiveRcResult.emit(rc.text) @QtCore.Slot(str) def getCommunitySub(self, username): hive_communitysubreq = { 'jsonrpc': '2.0', 'id': 1, 'method': 'bridge.list_all_subscriptions', 'params': { 'account': username } } subs = requests.post(self.settingsInstance.get('hiveAPI'), json=hive_communitysubreq) if subs.status_code != 200: self.hiveCommunitySubResult.emit("Error") else: self.hiveCommunitySubResult.emit(subs.text)
class mainWindow(QtWidgets.QMainWindow): runAllSignal = QtCore.Signal() endAllSignal = QtCore.Signal() def __init__(self, parent=None): super().__init__(parent) # Load UI file dirPath = pathUtil.getFileDirPath(__file__) self.ui = loadingUtil.loadUiWidget(dirPath + "/" + MAIN_WINDOW_UI_FILE) self.mainModel = mainModel(self) # setup main output view model self.oViewModel = mainOutputViewModel(self) self.mainModel.updateOutputSignal.connect(self.oViewModel.receiveData) self.oViewModel.addOutputViewSignal.connect( self.mainModel.messageMainframe) self.mainModel.startupSignal.connect(self.oViewModel.onStartupMessage) # Create and add output view oView = mainOutputView(self.oViewModel, self.ui.tabWidget) self.ui.tabWidget.addTab(oView, "Output") # Create and connect logging window self.loggingWindow = loggingWindow(self) self.mainModel.updateLoggingSignal.connect( self.loggingWindow.loggingModel.receiveData) self.ui.loggingButton.clicked.connect( lambda: self.loggingWindow.ui.show()) # Create and connect status window self.statusWindow = statusWindow(self) self.mainModel.updateStatusSignal.connect( self.statusWindow.statusModel.receiveData) self.ui.statusButton.clicked.connect( lambda: self.statusWindow.ui.show()) # Create config window self.configWindow = configWindow(self) # Load Block and Handler view bTab = blockTab(self.ui.tabWidget) hTab = handlerTab(self.ui.tabWidget) self.ui.tabWidget.addTab(bTab, "Blocks") self.ui.tabWidget.addTab(hTab, "Handlers") # Set up signal and slots # For mysterious reasons this signal slot cannot be deleted for the rest of the UI to work # After brief investigation I have no idea why this is the case self.ui.configButton.clicked.connect( lambda: self.configWindow.ui.show()) # Spooky, noted to fix in later development self.ui.startAllButton.clicked.connect(self.OnStartAllButtonClicked) self.runAllSignal.connect(self.mainModel.sendCmdStart) self.endAllSignal.connect(self.mainModel.sendCmdEnd) self.configWindow.ui.loadConfigsButton.clicked.connect( self.slotLoadConfigs) self.ui.show() @QtCore.Slot() def slotLoadConfigs(self): pass # blockConfigFile = self.configWindow.ui.blockFileLine.text() # handlerConfigFile = self.configWindow.ui.handlerFileLine.text() # tell mainframe to load configs @QtCore.Slot() def OnStartAllButtonClicked(self): if self.ui.startAllButton.isChecked(): self.ui.startAllButton.setText("End All") self.runAllSignal.emit() else: self.ui.startAllButton.setText("Start All") self.endAllSignal.emit()
def closeEvent(self, event): self.settings = QtCore.QSettings("node-editor", "NodeEditor") self.settings.setValue("geometry", self.saveGeometry()) self.settings.setValue("splitterSize", self.splitter.saveState()) QtWidgets.QWidget.closeEvent(self, event)
class Histogram_GUI(QtWidgets.QWidget): update_tracking = QtCore.Signal(object) output_setting_Tab_tracking = QtCore.Signal(object) def __init__(self, parent=None): super(Histogram_GUI, self).__init__(parent) self.input_data = None self.lower_limit = None self.upper_limit = None self.max_n_components = None self.minPeak_width = None self.n_bins = None self.empty_value_box_flag = False self.step_limit = 1e-6 self.setting_tracking = {} self.resize(300, 300) self.setWindowTitle('Histogram') self.plot_hist = QtWidgets.QPushButton("plot_histogram") self.plot_hist.clicked.connect(self.do_hist) self.plot_hist.setFixedWidth(150) self.le_lower_contrast_trim = QtWidgets.QLineEdit() self.le_lower_contrast_trim.setPlaceholderText("lower_limitation") self.le_lower_contrast_trim_label = QtWidgets.QLabel( "lower limitation (Contrast):") self.le_lower_contrast_trim.setFixedWidth(150) self.le_upper_contrast_trim = QtWidgets.QLineEdit() self.le_upper_contrast_trim.setPlaceholderText("upper_limitation") self.le_upper_contrast_trim_label = QtWidgets.QLabel( "upper limitation (Contrast):") self.le_upper_contrast_trim.setFixedWidth(150) self.le_MaxGMM_mode = QtWidgets.QLineEdit() self.le_MaxGMM_mode.setPlaceholderText("max_n_components for GMM") self.le_MaxGMM_mode_label = QtWidgets.QLabel("max n_components:") self.le_MaxGMM_mode.setFixedWidth(150) self.le_hist_bin = QtWidgets.QLineEdit() self.le_hist_bin.setPlaceholderText("#bins") self.le_hist_bin_label = QtWidgets.QLabel("Histogram bins:") self.le_hist_bin.setFixedWidth(150) self.min_peak_width = QtWidgets.QLineEdit() self.min_peak_width.setPlaceholderText("Min Peak Width") self.min_peak_width_label = QtWidgets.QLabel("Min Peak Width:") self.min_peak_width.setFixedWidth(150) self.axis_limit = QtWidgets.QLineEdit() self.axis_limit.setPlaceholderText("scale * upper_limitation") self.le_axis_limit = QtWidgets.QLabel("Scale x-axis:") self.axis_limit.setFixedWidth(150) self.GMM_visualization_mode_group = QtWidgets.QButtonGroup() self.radio_mode_1 = QtWidgets.QRadioButton("Separate mixture") self.radio_mode_2 = QtWidgets.QRadioButton("Superposition mixture") self.GMM_visualization_mode_group.addButton(self.radio_mode_1) self.GMM_visualization_mode_group.addButton(self.radio_mode_2) self.grid = QtWidgets.QGridLayout() self.grid.addWidget(self.createFirstExclusiveGroup(), 0, 0) self.grid.addWidget(self.createSecondExclusiveGroup(), 1, 0) self.grid.addWidget(self.plot_hist, 2, 0) self.setLayout(self.grid) def __del__(self): print('Destructor called, Employee deleted.') def createFirstExclusiveGroup(self): self.groupBox_hist = QtWidgets.QGroupBox("Histogram setting") self.grid3 = QtWidgets.QGridLayout() self.grid3.addWidget(self.le_lower_contrast_trim_label, 0, 0) self.grid3.addWidget(self.le_lower_contrast_trim, 1, 0) self.grid3.addWidget(self.le_upper_contrast_trim_label, 0, 1) self.grid3.addWidget(self.le_upper_contrast_trim, 1, 1) self.grid3.addWidget(self.min_peak_width_label, 2, 0) self.grid3.addWidget(self.min_peak_width, 3, 0) self.grid3.addWidget(self.le_hist_bin_label, 2, 1) self.grid3.addWidget(self.le_hist_bin, 3, 1) self.grid3.addWidget(self.le_axis_limit, 4, 0) self.grid3.addWidget(self.axis_limit, 5, 0) self.groupBox_hist.setLayout(self.grid3) return self.groupBox_hist def createSecondExclusiveGroup(self): self.groupBox_gmm = QtWidgets.QGroupBox( "Gaussian mixture models (GMM):") self.groupBox_gmm.setCheckable(True) self.groupBox_gmm.setChecked(False) self.grid4 = QtWidgets.QGridLayout() self.grid4.addWidget(self.le_MaxGMM_mode_label, 0, 0) self.grid4.addWidget(self.le_MaxGMM_mode, 0, 1) self.grid4.addWidget(self.radio_mode_1, 0, 2) self.grid4.addWidget(self.radio_mode_2, 0, 3) self.groupBox_gmm.setLayout(self.grid4) return self.groupBox_gmm def do_hist(self): self.step_limit = 1e-6 self.get_values_histogram_plot() if self.empty_value_box_flag: if self.groupBox_gmm.isChecked(): his_ = PlotProteinHistogram(intersection_display_flag=False) his_(folder_name='', particles=self.input_data, batch_size=self.batch_size, video_frame_num=self.number_frames, MinPeakWidth=self.minPeak_width, MinPeakProminence=0) his_.plot_histogram(bins=self.n_bins, upper_limitation=self.upper_limit, lower_limitation=self.lower_limit, step_range=self.step_limit, face='g', edge='k', Flag_GMM_fit=True, max_n_components=self.max_n_components) else: his_ = PlotProteinHistogram(intersection_display_flag=False) his_(folder_name='', particles=self.input_data, batch_size=self.batch_size, video_frame_num=self.number_frames, MinPeakWidth=self.minPeak_width, MinPeakProminence=0) his_.plot_histogram(bins=self.n_bins, upper_limitation=self.upper_limit, lower_limitation=self.lower_limit, step_range=self.step_limit, face='g', edge='k', Flag_GMM_fit=False, max_n_components=self.max_n_components) self.empty_value_box_flag = False def get_values_histogram_plot(self): try: self.minPeak_width = float(self.min_peak_width.text()) self.lower_limit = float(self.le_lower_contrast_trim.text()) self.upper_limit = float(self.le_upper_contrast_trim.text()) self.n_bins = int(self.le_hist_bin.text()) try: self.max_n_components = int(self.le_MaxGMM_mode.text()) except: pass self.empty_value_box_flag = True except: self.msg_box3 = QtWidgets.QMessageBox() self.msg_box3.setWindowTitle("Warning!") self.msg_box3.setText("Please filled all parameters!") self.msg_box3.exec_() self.empty_value_box_flag = False @QtCore.Slot() def update_in_data(self, data_in): self.input_data = data_in[0] self.number_frames = data_in[1] self.batch_size = data_in[2] def closeEvent(self, event): QtCore.QCoreApplication.instance().quit()
class Tracking_GUI(QtWidgets.QWidget): output_setting_Tab_tracking = QtCore.Signal(object) update_tab_index = QtCore.Signal(int) def __init__(self, parent=None): super(Tracking_GUI, self).__init__(parent) self.his_all_particles = None self.memory = None self.search_range = None self.temporal_length = None self.setting_tracking = {} self.empty_value_box_flag = False self.empty_value_optional_box_flag_1 = False self.empty_value_optional_box_flag_2 = False self.resize(300, 300) self.setWindowTitle('PSFs Tracking') self.btn_filterLinking = QtWidgets.QPushButton("Next") self.btn_filterLinking.setFixedWidth(120) self.btn_filterLinking.setFixedHeight(30) self.btn_filterLinking.clicked.connect(self.do_update_tfilter) self.line_memory = QtWidgets.QLineEdit() self.line_memory.setPlaceholderText("Memory") self.line_memory_label = QtWidgets.QLabel("Memory (frame):") self.line_search_range = QtWidgets.QLineEdit() self.line_search_range.setPlaceholderText("Move") self.line_searchRange_label = QtWidgets.QLabel( "Neighborhood size(px):") self.line_min_V_shape = QtWidgets.QLineEdit() self.line_min_V_shape.setPlaceholderText( "Minimum_temporal_length (frame)") self.line_min_V_shape_label = QtWidgets.QLabel( "Minimum_temporal_length (frame):") self.grid = QtWidgets.QGridLayout() self.grid.addWidget(self.createFirstExclusiveGroup(), 0, 0) self.setLayout(self.grid) def __del__(self): print('Destructor called, Employee deleted.') def createFirstExclusiveGroup(self): groupBox = QtWidgets.QGroupBox("Linking") self.checkbox_sorting_based_lenght = QtWidgets.QCheckBox( "Sorting", self) self.grid_linking = QtWidgets.QGridLayout() self.grid_linking.addWidget(self.line_memory_label, 0, 0) self.grid_linking.addWidget(self.line_memory, 0, 1) self.grid_linking.addWidget(self.line_searchRange_label, 1, 0) self.grid_linking.addWidget(self.line_search_range, 1, 1) self.grid_linking.addWidget(self.line_min_V_shape_label, 2, 0) self.grid_linking.addWidget(self.line_min_V_shape, 2, 1) self.grid_linking.addWidget(self.btn_filterLinking, 3, 0) self.grid_linking.addWidget(self.checkbox_sorting_based_lenght, 3, 3) groupBox.setLayout(self.grid_linking) return groupBox def do_update_tfilter(self): self.get_values_1() self.get_values_2() if self.empty_value_box_flag: self.setting_tracking['Memory (frame)'] = self.memory self.setting_tracking['Neighborhood_size (px)'] = self.search_range self.setting_tracking[ 'Minimum_temporal_length (frame)'] = self.temporal_length self.output_setting_Tab_tracking.emit(self.setting_tracking) self.update_tab_index.emit(4) def get_values_1(self): try: self.memory = int(self.line_memory.text()) self.search_range = int(self.line_search_range.text()) self.empty_value_box_flag = True except: self.msg_box3 = QtWidgets.QMessageBox() self.msg_box3.setWindowTitle("Warning!") self.msg_box3.setText("Please filled all parameters!") self.msg_box3.exec_() self.empty_value_box_flag = False def get_values_2(self): try: self.temporal_length = int(self.line_min_V_shape.text()) self.empty_value_box_flag = True except: self.msg_box3 = QtWidgets.QMessageBox() self.msg_box3.setWindowTitle("Warning!") self.msg_box3.setText("Please filled all parameters!") self.msg_box3.exec_() self.empty_value_box_flag = False def closeEvent(self, event): QtCore.QCoreApplication.instance().quit()
class ResourceDatabaseEditor(QtWidgets.QDockWidget, Ui_ResourceDatabaseEditor): editor_for_template: dict[str, TemplateEditor] ResourceChanged = QtCore.Signal(object) def __init__(self, parent: QtWidgets.QWidget, db: ResourceDatabase): super().__init__(parent) self.setupUi(self) set_default_window_icon(self) self.db = db self.tab_item.setModel(ResourceDatabaseItemModel(db)) self.tab_event.setModel( ResourceDatabaseGenericModel(db, ResourceType.EVENT)) self.tab_trick.setModel(ResourceDatabaseTrickModel(db)) self.tab_damage.setModel( ResourceDatabaseGenericModel(db, ResourceType.DAMAGE)) self.tab_version.setModel( ResourceDatabaseGenericModel(db, ResourceType.VERSION)) self.tab_misc.setModel( ResourceDatabaseGenericModel(db, ResourceType.MISC)) for tab in self._all_tabs: tab.model().dataChanged.connect( functools.partial(self._on_data_changed, tab.model())) self.editor_for_template = {} for name in db.requirement_template.keys(): self.create_template_editor(name) self.create_new_template_button = QtWidgets.QPushButton() self.create_new_template_button.setText("Create new") self.create_new_template_button.clicked.connect( self.create_new_template) self.tab_template_layout.addWidget(self.create_new_template_button) @property def _all_tabs(self): return [ self.tab_item, self.tab_event, self.tab_trick, self.tab_damage, self.tab_version, self.tab_misc ] def _on_data_changed(self, model: ResourceDatabaseGenericModel, top_left: QtCore.QModelIndex, bottom_right: QtCore.QModelIndex, roles): first_row = top_left.row() last_row = bottom_right.row() if first_row == last_row: self.ResourceChanged.emit( self.db.get_by_type(model.resource_type)[first_row]) def set_allow_edits(self, value: bool): for tab in self._all_tabs: tab.model().set_allow_edits(value) self.create_new_template_button.setVisible(value) for editor in self.editor_for_template.values(): editor.edit_button.setVisible(value) def create_new_template(self): template_name, did_confirm = QtWidgets.QInputDialog.getText( self, "New Template", "Insert template name:") if not did_confirm or template_name == "": return self.db.requirement_template[template_name] = Requirement.trivial() self.create_template_editor(template_name) self.tab_template_layout.removeWidget(self.create_new_template_button) self.tab_template_layout.addWidget(self.create_new_template_button) def create_template_editor(self, name: str): template_box = Foldable(name) template_box.setObjectName(f"template_box {name}") template_layout = QtWidgets.QVBoxLayout() template_layout.setObjectName(f"template_layout {name}") template_box.set_content_layout(template_layout) edit_template_button = QtWidgets.QPushButton() edit_template_button.setText("Edit") edit_template_button.clicked.connect( functools.partial(self.edit_template, name)) template_layout.addWidget(edit_template_button) self.editor_for_template[name] = TemplateEditor( template_name=name, foldable=template_box, edit_button=edit_template_button, template_layout=template_layout, visualizer=None, connections_layout=None, ) self.editor_for_template[name].create_visualizer(self.db) self.tab_template_layout.addWidget(template_box) def edit_template(self, name: str): requirement = self.db.requirement_template[name] editor = ConnectionsEditor(self, self.db, requirement) result = editor.exec_() if result == QtWidgets.QDialog.Accepted: self.db.requirement_template[name] = editor.final_requirement self.editor_for_template[name].create_visualizer(self.db)
class SignalConnection(QtCore.QObject): updateProgress_ = QtCore.Signal(int) finished = Signal()
class StartupConfiguration(QtWidgets.QMainWindow): _availModules = { PROCESS_CAMERA: CameraWidget, # definitions.DisplayCfg.name: Display, PROCESS_GUI: ModuleWidget, PROCESS_IO: ModuleWidget } sig_reload_config = QtCore.Signal() def __init__(self): QtWidgets.QMainWindow.__init__(self) self.setWindowTitle('vxPy configuration') def setup_ui(self): self._configfile = None self._currentConfigChanged = False vSpacer = QtWidgets.QSpacerItem(1, 1, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) # Setup window self.resize(1200, 1000) # Set central widget self.setCentralWidget(QtWidgets.QWidget(self)) self.centralWidget().setLayout(QtWidgets.QVBoxLayout()) # Config file selection self.gb_select = QtWidgets.QGroupBox('Select config file...') self.gb_select.setLayout(QtWidgets.QHBoxLayout()) self.centralWidget().layout().addWidget(self.gb_select) # Selection self.gb_select.layout().addWidget( QtWidgets.QLabel('Select configuration file: ')) self.gb_select.cb_select = QtWidgets.QComboBox() self.gb_select.cb_select.currentTextChanged.connect(self.open_config) self.gb_select.layout().addWidget(self.gb_select.cb_select) # New self.gb_select.btn_new = QtWidgets.QPushButton('Add new...') self.gb_select.btn_new.clicked.connect(self._add_configfile) self.gb_select.layout().addWidget(self.gb_select.btn_new) # Use self.gb_select.btn_use = QtWidgets.QPushButton('Use') self.gb_select.btn_use.clicked.connect(self.start_application) self.gb_select.layout().addWidget(self.gb_select.btn_use) # Change configurations for current file self.gb_edit = QtWidgets.QGroupBox('Change config') self.gb_edit.setLayout(QtWidgets.QGridLayout()) self.centralWidget().layout().addWidget(self.gb_edit) # # Module selection self.gb_edit.gb_select_mod = QtWidgets.QGroupBox('Select modules') self.gb_edit.gb_select_mod.setMaximumWidth(200) self.gb_edit.gb_select_mod.setLayout(QtWidgets.QVBoxLayout()) self.gb_edit.layout().addWidget(self.gb_edit.gb_select_mod, 0, 0) # Set configurations widget self.gb_edit.tab_modules = QtWidgets.QTabWidget(self) self.gb_edit.tab_modules.setLayout(QtWidgets.QGridLayout()) self.gb_edit.layout().addWidget(self.gb_edit.tab_modules, 0, 1, 1, 2) # Add all available modules self.module_checkboxes = dict() self.module_widgets = dict() for name, widget in self._availModules.items(): cb = ModuleCheckbox(name) cb.setChecked(False) self.module_checkboxes[name] = cb self.gb_edit.gb_select_mod.layout().addWidget( self.module_checkboxes[name]) if widget.__name__ == 'ModuleWidget': wdgt = widget(name, self) else: wdgt = widget(self) self.module_widgets[name] = wdgt self.gb_edit.tab_modules.addTab(self.module_widgets[name], name.upper()) # (Debug option) Select module tab # self.gb_edit.tab_modules.setCurrentWidget(self.module_widgets['display']) # Spacer self.gb_edit.gb_select_mod.layout().addItem(vSpacer) self.btn_save_config = QtWidgets.QPushButton('Save changes') self.btn_save_config.clicked.connect(self.save_config) self.gb_edit.layout().addWidget(self.btn_save_config, 1, 1) self.btn_start_app = QtWidgets.QPushButton('Save and start') self.btn_start_app.clicked.connect(self.save_and_start_application) self.gb_edit.layout().addWidget(self.btn_start_app, 1, 2) # Update and show self.update_configfile_list() self.show() def update_configfile_list(self): self.gb_select.cb_select.clear() for fname in os.listdir(PATH_CONFIG): self.gb_select.cb_select.addItem(fname) def _add_configfile(self): name, confirmed = QtWidgets.QInputDialog.getText( self, 'Create new configurations file', 'Config name', QtWidgets.QLineEdit.Normal, '') if confirmed and name != '': if name[-4:] != '.ini': fname = '%s.ini' % name else: fname = name name = name[:-4] if fname not in os.listdir(PATH_CONFIG): with open(os.path.join(PATH_CONFIG, fname), 'w') as fobj: parser = ConfigParser() parser.write(fobj) self.update_configfile_list() self.gb_select.cb_select.setCurrentText(name) def open_config(self): name = self.gb_select.cb_select.currentText() if name == '': return print('Open config {}'.format(name)) self._configfile = name acc.cur_conf = misc.ConfigParser() acc.cur_conf.read(self._configfile) # Set display config for new_visual compat. config.Display = acc.cur_conf.getParsedSection( definitions.DisplayCfg.name) # Update module selection for module_name, checkbox in self.module_checkboxes.items(): use = acc.cur_conf.getParsed(module_name, definitions.Cfg.use) checkbox.setChecked(use) self.module_widgets[module_name].setEnabled(use) # Update module settings for module_name, wdgt in self.module_widgets.items(): if hasattr(wdgt, 'load_settings_from_config'): print( 'Load settings for module \"{}\" from config file'.format( module_name)) self.sig_reload_config.emit() else: print( 'Could not load settings for module \"{}\" from config file' .format(module_name)) def closeEvent(self, event): answer = None if self._currentConfigChanged: answer = QtWidgets.QMessageBox.question( self, 'Unsaved changes', 'Would you like to save the current changes?', QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes and not (self.configuration is None): acc.cur_conf.saveToFile() # Close widgets for wdgt_name, wdgt in self.module_widgets.items(): wdgt.closed_main_window() # Close MainWindow event.accept() def save_config(self): acc.cur_conf.saveToFile() def save_and_start_application(self): acc.cur_conf.saveToFile() self.start_application() def start_application(self): print('Start application') acc.configfile = self._configfile self.close()
def setup_ui(self): """ Set up the UI for the Structure Information section. """ layout = QtWidgets.QGridLayout(self.widget) layout.setContentsMargins(0, 0, 0, 0) # Structure Information: Information Icon icon = QtWidgets.QLabel(self.widget) icon.setText("") icon.setPixmap( QtGui.QPixmap(":/images//res/images/btn-icons/info.png")) # Structure Information: Header label = QtWidgets.QLabel(self.widget) label.setFont(QtGui.QFont("Laksaman", pointSize=10, weight=700)) # Structure Information: "Volume" volume_label = QtWidgets.QLabel(self.widget) volume_label.setGeometry(QtCore.QRect(10, 70, 68, 29)) volume_label.setStyleSheet("font: 10pt \"Laksaman\";") self.volume_value = QtWidgets.QLabel(self.widget) self.volume_value.setGeometry(QtCore.QRect(95, 70, 81, 31)) self.volume_value.setStyleSheet("font: 10pt \"Laksaman\";") volume_unit = QtWidgets.QLabel(self.widget) volume_unit.setGeometry(QtCore.QRect(160, 70, 81, 31)) volume_unit.setStyleSheet("font: 10pt \"Laksaman\";") # Structure Information: "Min Dose" min_dose_label = QtWidgets.QLabel(self.widget) min_dose_label.setGeometry(QtCore.QRect(10, 100, 68, 31)) min_dose_label.setStyleSheet("font: 10pt \"Laksaman\";") self.min_dose_value = QtWidgets.QLabel(self.widget) self.min_dose_value.setGeometry(QtCore.QRect(95, 100, 81, 31)) self.min_dose_value.setStyleSheet("font: 10pt \"Laksaman\";") min_dose_unit = QtWidgets.QLabel(self.widget) min_dose_unit.setGeometry(QtCore.QRect(160, 100, 81, 31)) min_dose_unit.setStyleSheet("font: 10pt \"Laksaman\";") # Structure Information: "Max Dose" max_dose_label = QtWidgets.QLabel(self.widget) max_dose_label.setGeometry(QtCore.QRect(10, 130, 68, 31)) max_dose_label.setStyleSheet("font: 10pt \"Laksaman\";") self.max_dose_value = QtWidgets.QLabel(self.widget) self.max_dose_value.setGeometry(QtCore.QRect(95, 130, 81, 31)) self.max_dose_value.setStyleSheet("font: 10pt \"Laksaman\";") max_dose_unit = QtWidgets.QLabel(self.widget) max_dose_unit.setGeometry(QtCore.QRect(160, 130, 81, 31)) max_dose_unit.setStyleSheet("font: 10pt \"Laksaman\";") # Structure Information: "Mean Dose" mean_dose_label = QtWidgets.QLabel(self.widget) mean_dose_label.setGeometry(QtCore.QRect(10, 160, 81, 31)) mean_dose_label.setStyleSheet("font: 10pt \"Laksaman\";") self.mean_dose_value = QtWidgets.QLabel(self.widget) self.mean_dose_value.setGeometry(QtCore.QRect(95, 160, 81, 31)) self.mean_dose_value.setStyleSheet("font: 10pt \"Laksaman\";") mean_dose_unit = QtWidgets.QLabel(self.widget) mean_dose_unit.setGeometry(QtCore.QRect(160, 160, 81, 31)) mean_dose_unit.setStyleSheet("font: 10pt \"Laksaman\";") layout.addWidget(icon, 0, 0, 1, 1) layout.addWidget(label, 0, 1, 1, 3) layout.addWidget(self.combobox, 1, 0, 1, 4) layout.addWidget(volume_label, 2, 0, 1, 2) layout.addWidget(self.volume_value, 2, 2, 1, 1) layout.addWidget(volume_unit, 2, 3, 1, 1) layout.addWidget(min_dose_label, 3, 0, 1, 2) layout.addWidget(self.min_dose_value, 3, 2, 1, 1) layout.addWidget(min_dose_unit, 3, 3, 1, 1) layout.addWidget(max_dose_label, 4, 0, 1, 2) layout.addWidget(self.max_dose_value, 4, 2, 1, 1) layout.addWidget(max_dose_unit, 4, 3, 1, 1) layout.addWidget(mean_dose_label, 5, 0, 1, 2) layout.addWidget(self.mean_dose_value, 5, 2, 1, 1) layout.addWidget(mean_dose_unit, 5, 3, 1, 1) icon.raise_() label.raise_() self.combobox.raise_() volume_label.raise_() min_dose_label.raise_() max_dose_label.raise_() mean_dose_label.raise_() self.volume_value.raise_() self.min_dose_value.raise_() self.max_dose_value.raise_() self.mean_dose_value.raise_() volume_unit.raise_() min_dose_unit.raise_() max_dose_unit.raise_() mean_dose_unit.raise_() self.widget.raise_() _translate = QtCore.QCoreApplication.translate # Set structure information labels label.setText(_translate("MainWindow", "Structure Information")) volume_label.setText(_translate("MainWindow", "Volume:")) min_dose_label.setText(_translate("MainWindow", "Min Dose:")) max_dose_label.setText(_translate("MainWindow", "Max Dose:")) mean_dose_label.setText(_translate("MainWindow", "Mean Dose:")) # # Set structure information units volume_unit.setText(_translate("MainWindow", "cm³")) min_dose_unit.setText(_translate("MainWindow", "cGy")) max_dose_unit.setText(_translate("MainWindow", "cGy")) mean_dose_unit.setText(_translate("MainWindow", "cGy"))
def _set_reloaded(self): with QtCore.QMutexLocker(self._lock): self._reloading = False self._reloading_cond.wakeAll()
def get(self, url: str): """Start downloading url. Emits signal, when done.""" logger.debug("Download %s", url) request = QtNetwork.QNetworkRequest(QtCore.QUrl(url)) request.setTransferTimeout(3000) self.manager.get(request)
class StructureWidget(QtWidgets.QWidget): structure_renamed = QtCore.Signal( tuple) # (new_dataset, change_description) def __init__(self, roi_id, color, text, structure_tab): super(StructureWidget, self).__init__() patient_dict_container = PatientDictContainer() self.dataset_rtss = patient_dict_container.get("dataset_rtss") self.roi_id = roi_id self.color = color self.text = text self.structure_tab = structure_tab self.standard_name = None self.layout = QtWidgets.QHBoxLayout() # Create color square color_square_label = QtWidgets.QLabel() color_square_pix = QtGui.QPixmap(15, 15) color_square_pix.fill(self.color) color_square_label.setPixmap(color_square_pix) self.layout.addWidget(color_square_label) # Create checkbox checkbox = QtWidgets.QCheckBox() checkbox.setFocusPolicy(QtCore.Qt.NoFocus) checkbox.clicked.connect(self.checkbox_clicked) if text in structure_tab.standard_organ_names or text in structure_tab.standard_volume_names: self.standard_name = True checkbox.setStyleSheet("font: 10pt \"Laksaman\";") else: self.standard_name = False checkbox.setStyleSheet("font: 10pt \"Laksaman\"; color: red;") for item in structure_tab.standard_volume_names: # Any suffix number will still be considered standard. if text.startswith(item): self.standard_name = True checkbox.setStyleSheet("font: 10pt \"Laksaman\";") checkbox.setText(text) self.layout.addWidget(checkbox) self.layout.setAlignment(Qt.AlignLeft) self.setLayout(self.layout) def checkbox_clicked(self, checked): self.structure_tab.structure_checked(checked, self.roi_id) def roi_suggestions(self): """ Get the top 3 suggestions for the selected ROI based on string matching with standard ROIs provided in .csv format. :return: two dimensional list with ROI name and string match percent i.e [('MANDIBLE', 100), ('SUBMAND_L', 59), ('LIVER', 51)] """ roi_list = self.structure_tab.standard_organ_names + self.structure_tab.standard_volume_names suggestions = process.extract(self.text, roi_list, limit=3) # will get the top 3 matches return suggestions def contextMenuEvent(self, event): """ This function is called whenever the QWidget is right clicked. This creates a right click menu for the widget. """ # Part 1: Construct context menu menu = QtWidgets.QMenu(self) menu.setStyleSheet("QMenu::item::selected {background-color: #9370DB}") rename_action = menu.addAction("Rename") if not self.standard_name: menu.addSeparator() suggestions = self.roi_suggestions() suggested_action1 = menu.addAction(suggestions[0][0]) suggested_action2 = menu.addAction(suggestions[1][0]) suggested_action3 = menu.addAction(suggestions[2][0]) # Part 2: Determine action taken action = menu.exec(self.mapToGlobal(event.pos())) if action == rename_action: rename_window = RenameROIWindow( self.structure_tab.standard_volume_names, self.structure_tab.standard_organ_names, self.dataset_rtss, self.roi_id, self.text, self.structure_renamed) rename_window.exec_() if not self.standard_name: if action == suggested_action1: rename_window = RenameROIWindow( self.structure_tab.standard_volume_names, self.structure_tab.standard_organ_names, self.dataset_rtss, self.roi_id, self.text, self.structure_renamed, suggestions[0][0]) rename_window.exec_() elif action == suggested_action2: rename_window = RenameROIWindow( self.structure_tab.standard_volume_names, self.structure_tab.standard_organ_names, self.dataset_rtss, self.roi_id, self.text, self.structure_renamed, suggestions[1][0]) rename_window.exec_() elif action == suggested_action3: rename_window = RenameROIWindow( self.structure_tab.standard_volume_names, self.structure_tab.standard_organ_names, self.dataset_rtss, self.roi_id, self.text, self.structure_renamed, suggestions[2][0]) rename_window.exec_()
class Communicate(QtCore.QObject): """TrayMenus' communication bus.""" on_download_finished = QtCore.Signal(str) on_download_failed = QtCore.Signal()
def __init__(self, parent=None): super().__init__(parent) self.lay_main_grid = QtWidgets.QGridLayout(self) self.lay_main_grid.setContentsMargins(QtCore.QMargins(1, 0, 1, 5))
class outputSelect(QtWidgets.QWidget): selectionFinished = QtCore.Signal(dict) def __init__(self, model): super().__init__() self.model = model # Load UI file dirPath = pathUtil.getFileDirPath(__file__) self.selectItemUI = loadingUtil.loadUiWidget(dirPath + "/" + OUTPUT_SELECT_ITEM_UI_FILE) self.selectTypeUI = loadingUtil.loadUiWidget(dirPath + "/" + OUTPUT_SELECT_TYPE_UI_FILE) self.selectSettingsUI = loadingUtil.loadUiWidget(dirPath + "/" + OUTPUT_SELECT_SETTINGS_UI_FILE) self.selectionSettings = {} self.initSelectItem() self.initSelectType() self.initSelectSettings() self.mainLayout = QtWidgets.QVBoxLayout() self.backButtonSetup() self.mainLayout.addWidget(self.selectItemUI) self.mainLayout.setSpacing(0) self.setLayout(self.mainLayout) self.show() self.item = None self.isBlockItem = False self.outputType = None def resetHandlerModel(self): self.selectItemUI.handlerComboBox.setCurrentIndex(-1) def resetBlockModel(self): self.selectItemUI.blockComboBox.setCurrentIndex(-1) def initSelectItem(self): self.selectItemUI.blockComboBox.setModel(self.model.blockComboModel) self.resetBlockModel() self.selectItemUI.blockComboBox.textActivated.connect(self.itemSelected) self.model.blockComboModel.rowsInserted.connect(self.resetBlockModel) self.model.blockComboModel.rowsRemoved.connect(self.resetBlockModel) self.selectItemUI.handlerComboBox.setModel(self.model.handlerComboModel) self.resetHandlerModel() self.selectItemUI.handlerComboBox.textActivated.connect(self.itemSelected) self.model.handlerComboModel.rowsInserted.connect(self.resetHandlerModel) self.model.handlerComboModel.rowsRemoved.connect(self.resetHandlerModel) def initSelectType(self): self.selectTypeUI.typeComboBox.setModel(self.model.typeModel) self.selectTypeUI.typeComboBox.setCurrentIndex(-1) self.selectTypeUI.typeComboBox.textActivated.connect(self.typeSelected) def initSelectSettings(self): self.selectSettingsUI.acceptButton.clicked.connect(self.settingsSelected) def backButtonSetup(self): backWidget = QtWidgets.QWidget(self) backLayout = QtWidgets.QHBoxLayout() # Unicode for a left arrow U+2190 self.backButton = QtWidgets.QPushButton("\u2190", backWidget) self.backButton.clicked.connect(self.backButtonClicked) backLayout.addWidget(self.backButton) backLayout.addSpacerItem(QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)) backWidget.setLayout(backLayout) backWidget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) self.mainLayout.addWidget(backWidget) def backButtonClicked(self): if self.mainLayout.indexOf(self.selectItemUI) != -1: pass elif self.mainLayout.indexOf(self.selectTypeUI) != -1: self.selectionSettings = {} animations.fadeStart(self, self.selectTypeUI, self.selectItemUI, self.mainLayout) elif self.mainLayout.indexOf(self.selectSettingsUI) != -1: animations.fadeStart(self, self.selectSettingsUI, self.selectTypeUI, self.mainLayout) @QtCore.Slot() def itemSelected(self, text): self.item = text self.isBlockItem = "block" in self.sender().objectName() if self.isBlockItem: self.selectTypeUI.itemLabel.setText("Block: " + str(self.item)) self.selectItemUI.handlerComboBox.setCurrentIndex(-1) else: self.selectTypeUI.itemLabel.setText("Handler: " + str(self.item)) self.selectItemUI.blockComboBox.setCurrentIndex(-1) self.selectionSettings[ITEM] = text animations.fadeStart(self, self.selectItemUI, self.selectTypeUI, self.mainLayout) @QtCore.Slot() def typeSelected(self, text): self.selectionSettings[TYPE] = text animations.fadeStart(self, self.selectTypeUI, self.selectSettingsUI, self.mainLayout) @QtCore.Slot() def settingsSelected(self): self.selectionSettings[PERIOD] = self.selectSettingsUI.periodSpinBox.value() self.selectionSettings[BACKTRACK] = min(self.selectionSettings[PERIOD], self.selectSettingsUI.backtrackSpinBox.value()) self.selectionFinished.emit(self.selectionSettings)
def qInitResources(): QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
class PyradiExtended(QtCore.QThread): copied_percent_signal = QtCore.Signal(int, str) def __init__(self, path, filepaths, target_path): super().__init__() self.path = path self.filepaths = filepaths self.target_path = target_path def run(self): """ Perform radiomics analysis """ # Set progress bar percentage to 0 # Set ROI name to empty string as ROI not being processed self.my_callback(0, '') # Read one ct file, done to later obtain patient hash ct_file = dcmread(self.filepaths[0], force=True) # Read RT-Struct file rtss_path = self.filepaths['rtss'] if self.target_path == '': patient_hash = os.path.basename(ct_file.PatientID) # Name of nrrd file nrrd_file_name = patient_hash + '.nrrd' # Location of folder where nrrd file saved nrrd_folder_path = self.path + '/nrrd/' # Location of folder where pyradiomics output saved csv_path = self.path + '/CSV/' else: patient_hash = os.path.basename(self.target_path) # Name of nrrd file nrrd_file_name = patient_hash + '.nrrd' # Location of folder where nrrd file saved nrrd_folder_path = self.target_path + '/nrrd/' # Location of folder where pyradiomics output saved csv_path = self.target_path + '/CSV/' # Complete path of converted file nrrd_file_path = nrrd_folder_path + nrrd_file_name # If folder does not exist if not os.path.exists(nrrd_folder_path): # Create folder os.makedirs(nrrd_folder_path) self.convert_to_nrrd(self.path, nrrd_file_path, self.my_callback) # Location of folder where converted masks saved mask_folder_path = nrrd_folder_path + 'structures' self.convert_rois_to_nrrd(self.path, rtss_path, mask_folder_path, self.my_callback) # Something went wrong, in this case PyRadiomics will also log an error if nrrd_file_path is None or nrrd_folder_path is None: print('Error getting testcase!') exit() radiomics_df = self.get_radiomics_df(self.path, patient_hash, nrrd_file_path, mask_folder_path, self.my_callback) self.convert_df_to_csv(radiomics_df, patient_hash, csv_path, self.my_callback) # Export radiomics to SR self.export_to_sr(csv_path, patient_hash) # Delete CSV file and NRRD folder shutil.rmtree(nrrd_folder_path) os.remove(csv_path + 'Pyradiomics_' + patient_hash + '.csv') def my_callback(self, percent, roi_name): """ Set pyradiomics progress bar percentage and name of ROI being processed. :param percent: Percentage to be set in the progress bar :param roi_name: Name of ROI currently being processed """ self.copied_percent_signal.emit(percent, roi_name) def convert_to_nrrd(self, path, nrrd_file_path, callback): """ Convert dicom files to nrrd using Plastimatch. :param path: Path to patient directory (str) :param nrrd_file_path: Path to nrrd folder (str) :param callback: Function to update progress bar """ path = '"' + path + '"' nrrd_file_path = '"' + nrrd_file_path + '"' # Command to convert dicom files to nrrd # Writes the result from the processing into a temporary file # rather than the terminal cmd_for_nrrd = 'plastimatch convert --input ' + path + \ ' --output-img ' + nrrd_file_path + ' 1>' + path + '/NUL' # Command to delete the temporary file generated before cmd_del_nul = 'rm ' + path + '/NUL' os.system(cmd_for_nrrd) os.system(cmd_del_nul) # Set completed percentage to 25% and blank for ROI name callback(25, '') def convert_rois_to_nrrd(self, path, rtss_path, mask_folder_path, callback): """ Generate an nrrd file for each region of interest using Plastimatch. :param path: Path to patient directory (str) :param rtss_path: Path to RT-Struct file (str) :param mask_folder_path: Folder to which the segmentation masks will be saved(str) :param callback: Function to update progress bar """ path = '"' + path + '"' mask_folder_path = '"' + mask_folder_path + '"' rtss_path = '"' + rtss_path + '"' # Command for generating an nrrd file for each region of interest cmd_for_segmask = 'plastimatch convert --input ' + rtss_path + \ ' --output-prefix ' + mask_folder_path + \ ' --prefix-format nrrd --referenced-ct ' + path + ' 1>' + \ path + '/NUL' cmd_del_nul = 'rm ' + path + '/NUL' os.system(cmd_for_segmask) os.system(cmd_del_nul) # Set progress bar percentage to 50% callback(50, '') def get_radiomics_df(self, path, patient_hash, nrrd_file_path, mask_folder_path, callback): """ Run pyradiomics and return pandas dataframe with all the computed data. :param path: Path to patient directory (str) :param patient_hash: Patient hash ID generated from their identifiers :param nrrd_file_path: Path to folder with converted nrrd file :param mask_folder_path: Path to ROI nrrd files :param callback: Function to update progress bar :return: Pandas dataframe """ # Initialize feature extractor using default pyradiomics settings # Default features: # first order, glcm, gldm, glrlm, glszm, ngtdm, shape # Default settings: # 'minimumROIDimensions': 2, 'minimumROISize': None, 'normalize': False, # 'normalizeScale': 1, 'removeOutliers': None, 'resampledPixelSpacing': None, # 'interpolator': 'sitkBSpline', 'preCrop': False, 'padDistance': 5, 'distances': [1], # 'force2D': False, 'force2Ddimension': 0, 'resegmentRange': None, 'label': 1, # 'additionalInfo': True extractor = featureextractor.RadiomicsFeatureExtractor() num_masks = len([file for file in os.listdir(mask_folder_path)]) progress_increment = (50 / num_masks) progress_percent = 50 # Contains the features for all the ROI all_features = [] # CSV headers radiomics_headers = [] feature_vector = '' for file in os.listdir(mask_folder_path): # Contains features for current ROI roi_features = [] roi_features.append(patient_hash) roi_features.append(path) # Full path of ROI nrrd file mask_name = mask_folder_path + '/' + file # Name of ROI image_id = file.split('.')[0] callback(progress_percent, image_id) feature_vector = extractor.execute(nrrd_file_path, mask_name) roi_features.append(image_id) # Add first order features to list for feature_name in feature_vector.keys(): roi_features.append(feature_vector[feature_name]) all_features.append(roi_features) progress_percent += progress_increment radiomics_headers.append('Hash ID') radiomics_headers.append('Directory Path') radiomics_headers.append('ROI') # Extract column/feature names for feature_name in feature_vector.keys(): radiomics_headers.append(feature_name) # Convert into dataframe radiomics_df = pd.DataFrame(all_features, columns=radiomics_headers) radiomics_df.set_index('Hash ID', inplace=True) return radiomics_df def convert_df_to_csv(self, radiomics_df, patient_hash, csv_path, callback): """ Export dataframe as a csv file. """ # If folder does not exist if not os.path.exists(csv_path): # Create folder os.makedirs(csv_path) # Export dataframe as csv radiomics_df.to_csv(csv_path + 'Pyradiomics_' + patient_hash + '.csv') callback(100, '') def export_to_sr(self, csv_path, patient_hash): """ Save CSV data into DICOM SR. Reads in CSV data and saves it to a DICOM SR file :param csv_path: the path that the CSV has been saved to. :param patient_hash: the patient's hash as a string. """ # Check CSV path exists file_path = csv_path + 'Pyradiomics_' + patient_hash + ".csv" if file_path == "": return # Get CSV data with open(file_path, newline="") as stream: data = list(csv.reader(stream)) # Write raw CSV data to DICOM SR # TODO: create better implementation of this - requires # generated SR files to be more structured. # Convert CSV data to text text = "" for line in data: for item in line: text += str(item) + "," text += "\n" # Create and save DICOM SR file patient_dict_container = PatientDictContainer() file_path = patient_dict_container.path file_path = Path(file_path).joinpath("Pyradiomics-SR.dcm") ds = patient_dict_container.dataset[0] dicom_sr = DICOMStructuredReport.generate_dicom_sr( file_path, ds, text, "PYRADIOMICS") dicom_sr.save_as(file_path) # Update patient dict container patient_dict_container.dataset['sr-pyrad'] = dicom_sr patient_dict_container.filepaths['sr-pyrad'] = file_path
def __init__(self, parent=None): super(Localization_GUI, self).__init__(parent) self.flag_localization_setting = False self.flag_fineLocalization_setting = False self.flag_sfilter_setting = False self.min_radial = None self.max_radial = None self.rvt_kind = None self.highpass_size = None self.upsample = None self.rweights = None self.coarse_factor = None self.coarse_mode = None self.pad_mode = None self.min_sigma = None self.max_sigma = None self.sigma_ratio = None self.threshold = None self.overlap = None self.frame_num = 0 self.setting_localization = {} self.crappy_thr = None self.scale = None self.thr_sigma = None self.win_size_Fitting = None self.empty_value_box_flag = False self.flag_remove_box = True self.mode = None self.resize(300, 300) self.setWindowTitle('2D Localization') self.next = QtWidgets.QPushButton("Next") self.next.clicked.connect(self.update_tab) self.next.setFixedWidth(150) self.btn_FineLocalizationUpdate = QtWidgets.QPushButton("Update Fine Localization") self.btn_FineLocalizationUpdate.clicked.connect(self.do_fineLocalization) self.btn_FineLocalizationUpdate.setFixedWidth(150) self.btn_localizationUpdate = QtWidgets.QPushButton("Update Localization") self.btn_localizationUpdate.clicked.connect(self.do_localization) self.btn_localizationUpdate.setFixedWidth(150) self.btn_filtering = QtWidgets.QPushButton('Filtering', self) self.btn_filtering.clicked.connect(self.do_Filtering) self.btn_filtering.setIconSize(QtCore.QSize(24, 24)) self.btn_filtering.setMaximumSize(100, 70) self.mode_list = {"Bright PSF": "Bright", "Dark PSF": "Dark", "Bright & Dark PSF": "BOTH"} self.method_list = {"Difference of Gaussian": "dog", "Laplacian of Gaussian": "log", "Determinant of Hessian": "doh", "Radial Symmetry": "frst_one_psf", 'RVT': 'RVT'} self.output_setting_Tab_Localization_internal.connect(self.update_setting) self.combo = QtWidgets.QComboBox(self) self.combo.addItem("-Select the method-") self.combo.addItem("Difference of Gaussian") self.combo.addItem("Laplacian of Gaussian") self.combo.addItem("Determinant of Hessian") self.combo.addItem("Radial Symmetry") self.combo.addItem("RVT") self.combo.currentIndexChanged.connect(self.on_select) self.grid = QtWidgets.QGridLayout() self.grid.addWidget(self.createFirstExclusiveGroup(), 0, 0) self.grid.addWidget(self.createSecondExclusiveGroup(), 1, 0) self.grid.addWidget(self.createThirdExclusiveGroup(), 2, 0) self.grid.addWidget(self.createFourthExclusiveGroup(), 3, 0) self.grid.addWidget(self.next, 4, 0) self.setLayout(self.grid)
def inc_query_count(self): with QtCore.QMutexLocker(self._lock): while self._reloading: self._reloading_cond.wait(self._lock) self._query_count += 1
app = QtWidgets.QApplication(sys.argv) from twisted.application import reactors reactors.installReactor('pyside2') from twisted.internet import reactor from twisted.internet.task import LoopingCall mywindow = QtWidgets.QWidget() mywindow.resize(600, 400) mywindow.setWindowTitle('Hello, World!') mylabel = QtWidgets.QLabel(mywindow) mylabel.setGeometry(QtCore.QRect(200, 200, 200, 200)) count = 0 def set_label(): global count global mylabel count += 1 msg = 'Hello, World [count={}]!'.format(count) print(msg) mylabel.setText(msg) lc = LoopingCall(set_label) lc.start(1.)
def dec_query_count(self): with QtCore.QMutexLocker(self._lock): self._query_count -= 1 self._query_count_cond.wakeAll()
class Logs(QtWidgets.QTextBrowser): log_signal = QtCore.Signal(str) clear_window = QtCore.Signal(str) timer_signal = QtCore.Signal(str) def __init__(self, parent, app: FastFlixApp, main, log_queue): super(Logs, self).__init__(parent) self.parent = parent self.app = app self.main = main self.status_panel = parent self.current_video = None self.log_signal.connect(self.update_text) self.clear_window.connect(self.blank) self.timer_signal.connect(self.timer_update) self.log_updater = LogUpdater(self, log_queue) self.log_updater.start() def update_text(self, msg): if self.status_panel.hide_nal.isChecked() and msg.endswith( ("NAL unit 62", "NAL unit 63")): return if self.status_panel.hide_nal.isChecked() and msg.lstrip().startswith( "Last message repeated"): return if msg.startswith("frame="): try: output = [] for i in (x.strip().split() for x in msg.split("=")): output.extend(i) frame = dict(zip(output[0::2], output[1::2])) self.status_panel.speed.emit( f"{frame.get('time', '')}|{frame.get('speed', '').rstrip('x')}" ) self.status_panel.bitrate.emit(frame.get("bitrate", "")) except Exception: pass elif "remain" in msg: self.status_panel.nvencc_signal.emit(msg) self.append(msg) def blank(self, data): _, video_uuid, command_uuid = data.split(":") try: self.parent.current_video = self.main.find_video(video_uuid) self.current_command = self.main.find_command( self.parent.current_video, command_uuid) except FlixError: logger.error( f"Couldn't find video or command for UUID {video_uuid}:{command_uuid}" ) self.parent.current_video = None self.current_command = None self.setText("") self.parent.started_at = datetime.datetime.now(datetime.timezone.utc) def timer_update(self, cmd): self.parent.ticker_thread.state_signal.emit(cmd == "START") def closeEvent(self, event): self.hide()
class ScriptsManager(QtCore.QObject): scriptsChanged = QtCore.Signal(list) error = QtCore.Signal(str) def __init__(self, module_pkgname): super().__init__() self._module_pkgname = module_pkgname self._dirs_to_watch = set() self._files_to_watch = set() self._modules = set() self._event_handler = FileSystemEventHandler() self._event_handler.on_any_event = self._on_any_event self._observer = Observer() self._observer.start() self._timer = None self._lock = QtCore.QMutex() self._query_count = 0 self._query_count_cond = QtCore.QWaitCondition() self._reloading = False self._reloading_cond = QtCore.QWaitCondition() def start(self): self.reload() def resume(self): self._observer.unschedule_all() for path in self._dirs_to_watch: if path == "": path = "." try: self._observer.schedule(self._event_handler, path) except Exception as e: print(f"Failed to schedule watch for {path}: {e}") def pause(self): self._observer.unschedule_all() def _set_reloading(self): with QtCore.QMutexLocker(self._lock): while self._reloading: self._reloading_cond.wait(self._lock) self._reloading = True while self._query_count != 0: self._query_count_cond.wait(self._lock) def _set_reloaded(self): with QtCore.QMutexLocker(self._lock): self._reloading = False self._reloading_cond.wakeAll() @QtCore.Slot() def reload(self): self._set_reloading() self.pause() for name in self._modules: del sys.modules[name] self._modules = set() odict = query_list(self._module_pkgname) if "error" in odict: self.update_filelist(odict["filelist"]) self.update_modulelist(odict["modulelist"]) self.resume() self._set_reloaded() self.error.emit(odict["error"]) return self.error.emit(None) self.set_filelist(odict["filelist"]) self.set_modulelist(odict["modulelist"]) self.resume() self._set_reloaded() scripts = odict["scenes"] self.scriptsChanged.emit(scripts) def _on_any_event(self, event): def print_reload(): print("Reloading scene") self.reload() if event.src_path in self._files_to_watch: print("Change detected in %s" % event.src_path) if self._timer is not None: self._timer.cancel() self._timer = Timer(MIN_RELOAD_INTERVAL, print_reload, ()) self._timer.start() def _update_dirs_to_watch(self): self._dirs_to_watch = {op.dirname(f) for f in self._files_to_watch} @QtCore.Slot(list) def update_filelist(self, filelist): self._files_to_watch.update(filelist) self._update_dirs_to_watch() @QtCore.Slot(list) def set_filelist(self, filelist): self._files_to_watch = set(filelist) self._update_dirs_to_watch() def update_modulelist(self, modulelist): self._modules.update(modulelist) def set_modulelist(self, modulelist): self._modules = set(modulelist) def inc_query_count(self): with QtCore.QMutexLocker(self._lock): while self._reloading: self._reloading_cond.wait(self._lock) self._query_count += 1 def dec_query_count(self): with QtCore.QMutexLocker(self._lock): self._query_count -= 1 self._query_count_cond.wakeAll()
def readSettings(self): settings = QtCore.QSettings("Trolltech", "Application Example") pos = settings.value("pos", QtCore.QPoint(200, 200)) size = settings.value("size", QtCore.QSize(400, 400)) self.resize(size) self.move(pos)
class CompositionView(QtWidgets.QGraphicsView): open_stack = QtCore.Signal(otio.schema.Stack) selection_changed = QtCore.Signal(otio.core.SerializableObject) def __init__(self, stack, *args, **kwargs): super(CompositionView, self).__init__(*args, **kwargs) self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) self.setScene(CompositionWidget(stack, parent=self)) self.setAlignment((QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)) self.setStyleSheet('border: 0px;') self.scene().selectionChanged.connect(self.parse_selection_change) self._navigation_filter = None self._last_item_cache = { "key": None, "item": None, "previous_item": None } def parse_selection_change(self): selection = self.scene().selectedItems() if not selection: return # Exclude ruler from selection for item in selection: if isinstance(item, ruler_widget.Ruler): continue self.selection_changed.emit(item.item) break def mousePressEvent(self, mouse_event): modifiers = QtWidgets.QApplication.keyboardModifiers() self.setDragMode( QtWidgets.QGraphicsView.ScrollHandDrag if modifiers == QtCore.Qt.AltModifier else QtWidgets.QGraphicsView.NoDrag) self.setInteractive(not modifiers == QtCore.Qt.AltModifier) super(CompositionView, self).mousePressEvent(mouse_event) def mouseReleaseEvent(self, mouse_event): super(CompositionView, self).mouseReleaseEvent(mouse_event) self.setDragMode(QtWidgets.QGraphicsView.NoDrag) def wheelEvent(self, event): try: # PySide6: # https://doc.qt.io/qtforpython/PySide6/QtGui/QWheelEvent.html delta_point = event.angleDelta() delta = delta_point.y() except AttributeError: # PySide2: # https://doc.qt.io/qtforpython-5/PySide2/QtGui/QWheelEvent.html delta = event.delta() scale_by = 1.0 + float(delta) / 1000 self.scale(scale_by, 1) zoom_level = 1.0 / self.transform().m11() track_widgets.CURRENT_ZOOM_LEVEL = zoom_level self.scene().counteract_zoom(zoom_level) def _get_first_item(self): newXpos = 0 newYpos = track_widgets.TIME_SLIDER_HEIGHT newPosition = QtCore.QPointF(newXpos, newYpos) return self.scene().itemAt(newPosition, QtGui.QTransform()) def _get_left_item(self, curSelectedItem): curItemXpos = curSelectedItem.pos().x() if curSelectedItem.parentItem(): curTrackYpos = curSelectedItem.parentItem().pos().y() newXpos = curItemXpos - 1 newYpos = curTrackYpos if newXpos < 0: newXpos = 0 else: newXpos = curItemXpos newYpos = curSelectedItem.y() newPosition = QtCore.QPointF(newXpos, newYpos) return self.scene().itemAt(newPosition, QtGui.QTransform()) def _get_right_item(self, curSelectedItem): curItemXpos = curSelectedItem.pos().x() if curSelectedItem.parentItem(): curTrackYpos = curSelectedItem.parentItem().pos().y() newXpos = curItemXpos + curSelectedItem.rect().width() newYpos = curTrackYpos else: newXpos = curItemXpos newYpos = curSelectedItem.y() newPosition = QtCore.QPointF(newXpos, newYpos) return self.scene().itemAt(newPosition, QtGui.QTransform()) def _get_up_item(self, curSelectedItem): curItemXpos = curSelectedItem.pos().x() if curSelectedItem.parentItem(): curTrackYpos = curSelectedItem.parentItem().pos().y() newXpos = curItemXpos newYpos = curTrackYpos - track_widgets.TRACK_HEIGHT newSelectedItem = self.scene().itemAt( QtCore.QPointF(newXpos, newYpos), QtGui.QTransform()) if (not newSelectedItem or isinstance(newSelectedItem, otio.schema.Track)): newYpos = newYpos - track_widgets.TRANSITION_HEIGHT else: newXpos = curItemXpos newYpos = curSelectedItem.y() newPosition = QtCore.QPointF(newXpos, newYpos) return self.scene().itemAt(newPosition, QtGui.QTransform()) def _get_down_item(self, curSelectedItem): curItemXpos = curSelectedItem.pos().x() if curSelectedItem.parentItem(): curTrackYpos = curSelectedItem.parentItem().pos().y() newXpos = curItemXpos newYpos = curTrackYpos + track_widgets.TRACK_HEIGHT newSelectedItem = self.scene().itemAt( QtCore.QPointF(newXpos, newYpos), QtGui.QTransform()) if (not newSelectedItem or isinstance(newSelectedItem, otio.schema.Track)): newYpos = newYpos + track_widgets.TRANSITION_HEIGHT if newYpos < track_widgets.TRACK_HEIGHT: newYpos = track_widgets.TRACK_HEIGHT else: newXpos = curItemXpos newYpos = (track_widgets.MARKER_SIZE + track_widgets.TIME_SLIDER_HEIGHT + 1) newYpos = track_widgets.TIME_SLIDER_HEIGHT newPosition = QtCore.QPointF(newXpos, newYpos) return self.scene().itemAt(newPosition, QtGui.QTransform()) def _deselect_all_items(self): if self.scene().selectedItems: for selectedItem in self.scene().selectedItems(): selectedItem.setSelected(False) def _select_new_item(self, newSelectedItem): # Check for text item # Text item shouldn't be selected, # maybe a bug in the population of timeline. if isinstance(newSelectedItem, QtWidgets.QGraphicsSimpleTextItem): newSelectedItem = newSelectedItem.parentItem() # Validate new item for edge cases # If valid, set selected if (not isinstance(newSelectedItem, track_widgets.Track) and newSelectedItem): self._deselect_all_items() newSelectedItem.setSelected(True) self.centerOn(newSelectedItem) def _get_new_item(self, key_event, curSelectedItem): key = key_event.key() modifier = key_event.modifiers() if not (key in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Right, QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter) and not (modifier & QtCore.Qt.ControlModifier)): return None if key in [ QtCore.Qt.Key_Left, QtCore.Qt.Key_Right, QtCore.Qt.Key_Up, QtCore.Qt.Key_Down ]: # check if last key was the opposite direction of current one if KEY_SYM[key] == self._last_item_cache["key"] and \ curSelectedItem == self._last_item_cache["item"] and \ not curSelectedItem == self._last_item_cache["previous_item"]: newSelectedItem = self._last_item_cache["previous_item"] else: filters = self.get_filters() # make sure that the selected item is a BaseItem while (not isinstance(curSelectedItem, track_widgets.BaseItem) and curSelectedItem): curSelectedItem = curSelectedItem.parentItem() if not curSelectedItem: return None newSelectedItem = self.scene().get_next_item_filters( curSelectedItem, key, filters) # self._last_item_cache["item"] = curSelectedItem self._last_item_cache["item"] = newSelectedItem self._last_item_cache["previous_item"] = curSelectedItem self._last_item_cache["key"] = key elif key in [QtCore.Qt.Key_Return, QtCore.Qt.Key_Return]: if isinstance(curSelectedItem, track_widgets.NestedItem): curSelectedItem.keyPressEvent(key_event) newSelectedItem = None return newSelectedItem def keyPressEvent(self, key_event): super(CompositionView, self).keyPressEvent(key_event) self.setInteractive(True) # Remove ruler_widget.Ruler instance from selection selections = [ x for x in self.scene().selectedItems() if not isinstance(x, ruler_widget.Ruler) ] # Based on direction key, select new selected item if not selections: newSelectedItem = self._get_first_item() # No item selected, so select the first item else: curSelectedItem = selections[0] # Check to see if the current selected item is a rect item # If current selected item is not a rect, then extra tests # are needed. if not isinstance(curSelectedItem, QtWidgets.QGraphicsRectItem): if curSelectedItem.parentItem(): curSelectedItem = curSelectedItem.parentItem() newSelectedItem = self._get_new_item(key_event, curSelectedItem) self._keyPress_frame_all(key_event) self._snap(key_event, curSelectedItem) if newSelectedItem: self._select_new_item(newSelectedItem) def _snap(self, key_event, curSelectedItem): key = key_event.key() modifier = key_event.modifiers() if key in ( QtCore.Qt.Key_Left, QtCore.Qt.Key_Right, ) and (modifier & QtCore.Qt.ControlModifier): direction = 0 if key == QtCore.Qt.Key_Left: direction = -1.0 elif key == QtCore.Qt.Key_Right: direction = 1.0 if direction: ruler = self.scene().get_ruler() ruler.snap(direction=direction, scene_width=self.sceneRect().width()) self.ensureVisible(ruler) def _keyPress_frame_all(self, key_event): key = key_event.key() modifier = key_event.modifiers() if key == QtCore.Qt.Key_F and (modifier & QtCore.Qt.ControlModifier): self.frame_all() def frame_all(self): self.resetTransform() track_widgets.CURRENT_ZOOM_LEVEL = 1.0 self.scene().counteract_zoom() track_name_width = self.scene().track_name_width() view_width = self.size().width() - track_name_width scene_width = self.sceneRect().width() - track_name_width if not view_width or not scene_width: # Prevent zero division errors return scale_by = view_width / scene_width self.scale(scale_by, 1) zoom_level = 1.0 / self.transform().m11() track_widgets.CURRENT_ZOOM_LEVEL = zoom_level self.scene().counteract_zoom(zoom_level) def navigationfilter_changed(self, bitmask): ''' Update the navigation filter according to the filters checked in the navigation menu. Reset _last_item_cache ''' nav_d = namedtuple("navigation_filter", ["inclusive", "exclusive"]) incl_filter, excl_filter = group_filters(bitmask) self._navigation_filter = nav_d(incl_filter, excl_filter) self._last_item_cache = { "key": None, "item": None, "previous_item": None } def get_filters(self): return self._navigation_filter