def __init__(self, target_properties: List[str], parent=None): super().__init__(parent) self.target_properties = target_properties self.target = None layout = QGridLayout() for i in range(0, 8): label = QLabel(text=_EDITOR_LABELS[i]) layout.addWidget(label, 0, i + 1) self.editors = [] for i in range(0, len(target_properties)): self.editors.append([]) label = QLabel(target_properties[i]) label.setFixedWidth(80) layout.addWidget(label, i + 1, 0) for j in range(0, 8): editor = QSpinBox() editor.setRange(-128, 127) editor.setMaximumWidth(60) layout.addWidget(editor, row=i + 1, column=j + 1) self.editors[-1].append(editor) editor.valueChanged.connect(lambda v=None, e=editor, r=i, c=j: self._on_edit(v, e, r, c)) self.setLayout(layout) self.setFixedHeight(200)
class ScoresDialog(QDialog): def __init__(self): super().__init__(GlobalAccess().get_main_window()) def exec_(self): self.init_ui() return super().exec_() def init_ui(self): self.setWindowTitle(_('Scores assign')) self.setWindowIcon(QIcon(config.ICON)) self.setSizeGripEnabled(False) self.setModal(False) self.setMinimumWidth(650) self.layout = QFormLayout(self) self.label_list = QRadioButton(_('Value list')) self.label_list.setChecked(True) self.item_list = QLineEdit() self.item_list.setText( '40;37;35;33;32;31;30;29;28;27;26;25;24;23;22;21;20;19;18;17;16;15;14;13;12;11;10;9;8;7;6;5;4;3;2;1' ) self.layout.addRow(self.label_list, self.item_list) self.label_formula = QRadioButton(_('Formula')) self.item_formula = QLineEdit() self.layout.addRow(self.label_formula, self.item_formula) self.label_formula_hint = QLabel( 'Hint: You can use following variables: LeaderTime, Time, Year, Place, Length' ) self.layout.addRow(self.label_formula_hint) self.label_limit = QCheckBox(_('Limit per team')) self.item_limit = QSpinBox() self.item_limit.setMaximumWidth(50) self.layout.addRow(self.label_limit, self.item_limit) def cancel_changes(): self.close() def apply_changes(): try: self.apply_changes_impl() except Exception as e: logging.error(str(e)) self.close() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = button_box.button(QDialogButtonBox.Ok) self.button_ok.setText(_('OK')) self.button_ok.clicked.connect(apply_changes) self.button_cancel = button_box.button(QDialogButtonBox.Cancel) self.button_cancel.setText(_('Cancel')) self.button_cancel.clicked.connect(cancel_changes) self.layout.addRow(button_box) self.show() def apply_changes_impl(self): cur_race = race() cur_race.set_setting('score_list', self.item_list.text()) cur_race.set_setting('score_formula', self.item_formula.text()) cur_race.set_setting('score_team_limit', self.item_limit.value()) cur_race.set_setting('score_use_team_limit', self.item_limit.value())
class ParametersComponent(QGroupBox): def __init__(self): super().__init__() self.setTitle("Paramètres") self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) # Main layout main_layout = QHBoxLayout(self) main_layout.setSpacing(20) left_layout = QFormLayout() left_layout.setHorizontalSpacing(20) left_layout.setVerticalSpacing(14) self._threshold_sbox = QSpinBox() self._threshold_sbox.setRange(1, 99) self._threshold_sbox.setSuffix(" %") self._threshold_sbox.setMaximumWidth(250) left_layout.addRow("Seuil de détection :", self._threshold_sbox) self._devices_list = QComboBox() self._devices_list.setMaximumWidth(250) self._setDevicesList() left_layout.addRow("Processeur à utiliser :", self._devices_list) morphotype_layout = QGridLayout() morphotype_layout.setSpacing(5) morphotype_layout.addWidget(QLabel("Morphotypes à détecter :"), 0, 0, 1, 4) self._tab_cbox = {} for k,m in Loader.SpongesMorphotypes().items(): sponge_cbox = QCheckBox(m.name()) self._tab_cbox[k] = sponge_cbox x = k%2 + 1 y = k//2 + 1 morphotype_layout.addWidget(sponge_cbox, x, y) morphotype_layout.setColumnMinimumWidth(0, 15) morphotype_layout.setColumnStretch(0, 0) main_layout.addLayout(left_layout) main_layout.addLayout(morphotype_layout) self.setLayout(main_layout) def _setDevicesList(self): self._devices_list.clear() available_devices = NeuralNetwork.getAvailableCalculationDevices() for device_id, device_name in available_devices.items(): self._devices_list.addItem(device_name, device_id) if len(available_devices) == 1: self._devices_list.addItem("GPU (Indisponible)", None) self._devices_list.model().item(1).setEnabled(False) else: self._devices_list.setCurrentIndex(1) def reset(self, parameters: Parameters): self._threshold_sbox.setValue(parameters.threshold()*100) for k,v in parameters.morphotypes().items(): self._tab_cbox[k].setChecked(v) def updateParameters(self, parameters: Parameters): parameters.setThreshold(self._threshold_sbox.value()/100) parameters.setDeviceId(self._devices_list.currentData()) for k in parameters.morphotypes(): parameters.morphotypes()[k] = self._tab_cbox[k].isChecked()
class MainWindow(QMainWindow): def __init__(self) -> None: QMainWindow.__init__(self) self.lib_chapters = self.__create_libchapters() self.prefs = Prefs() self.current_file: Optional[str] = None self.current_file_type: Optional[str] = None # UI components self.setWindowTitle(libchapters.APPLICATION_NAME) self.setMinimumSize(480, 320) self.resize(900, 500) self.__create_menu() self.podcast_title = QLineEdit() self.episode_title = QLineEdit() self.episode_number = QSpinBox() self.episode_number.setMaximumWidth(55) self.chapters_table_view = QTableView() self.chapters_table_model = ChaptersTableModel( self.chapters_table_view) self.chapters_table_view.setModel(self.chapters_table_model) self.chapters_table_view.horizontalHeader().setStretchLastSection(True) self.add_chapter_button = QPushButton("Add") self.add_chapter_button.clicked.connect( self.chapters_table_model.add_chapter) self.delete_chapter_button = QPushButton("Delete") self.delete_chapter_button.clicked.connect( self.chapters_table_model.remove_selected_chapters) self.progress_bar = QProgressBar() self.setCentralWidget(self.__create_center_widget()) self.__create_status_bar() def __create_libchapters(self) -> LibChapters: listener = LibChaptersListener() listener.signals.encode_started.connect(self.__encode_started) listener.signals.encode_progress.connect(self.__encode_progress) listener.signals.encode_complete.connect(self.__encode_complete) listener.signals.read_metadata_started.connect( self.__read_metadata_started) listener.signals.read_metadata_complete.connect( self.__read_metadata_complete) listener.signals.write_mp3_file_started.connect( self.__write_mp3_started) listener.signals.write_mp3_file_progress.connect( self.__write_mp3_progress) listener.signals.write_mp3_file_complete.connect( self.__write_mp3_complete) return LibChapters(listener) def __create_center_widget(self) -> QWidget: episode_info_layout = QFormLayout() episode_info_layout.addRow("Podcast Title:", self.podcast_title) episode_info_layout.addRow("Episode Title:", self.episode_title) episode_info_layout.addRow("Episode Number:", self.episode_number) add_remove_chapters_layout = QHBoxLayout() add_remove_chapters_layout.addWidget(self.add_chapter_button) add_remove_chapters_layout.addWidget(self.delete_chapter_button) add_remove_chapters_layout.setAlignment(Qt.AlignLeft) center_widget_layout = QVBoxLayout() center_widget_layout.addLayout(episode_info_layout) center_widget_layout.addWidget(self.chapters_table_view) center_widget_layout.addLayout(add_remove_chapters_layout) center_widget = QWidget() center_widget.setLayout(center_widget_layout) return center_widget def __create_menu(self) -> None: menu_bar = self.menuBar() file_menu = menu_bar.addMenu("File") import_action = file_menu.addAction("Import Audio...") import_action.setShortcut(QKeySequence("Ctrl+I")) import_action.triggered.connect(self.__import_audio) open_file_action = file_menu.addAction("Open...") open_file_action.setShortcut(QKeySequence("Ctrl+O")) open_file_action.triggered.connect(self.__open_file) file_menu.addSeparator() save_action = file_menu.addAction("Save") save_action.setShortcut(QKeySequence("Ctrl+S")) save_action.triggered.connect(self.__save_current_file) save_as_action = file_menu.addAction("Save As...") save_as_action.setShortcut(QKeySequence("Ctrl+Shift+S")) save_as_action.triggered.connect(self.__save_current_file_as) file_menu.addSeparator() exit_action = file_menu.addAction("Exit") exit_action.setShortcut(QKeySequence("Alt+f4")) exit_action.triggered.connect(QCoreApplication.quit) help_menu = menu_bar.addMenu("Help") documentation_action = help_menu.addAction("Open Documentation...") documentation_action.triggered.connect( lambda: QDesktopServices.openUrl(libchapters.DOCUMENTATION)) help_menu.addSeparator() about_action = help_menu.addAction("About...") about_action.triggered.connect(self.__show_about_dialog) def __create_status_bar(self) -> None: status_bar = self.statusBar() status_bar.addPermanentWidget(self.progress_bar) def __import_audio(self) -> None: file = self.__show_open_dialog("*.wav") if file: self.__set_current_file(file, "wav") self.lib_chapters.read_metadata_from_wav_file(file) self.lib_chapters.encode_wav_file(file) def __open_file(self) -> None: file = self.__show_open_dialog("*.mp3") if file: self.__set_current_file(file, "mp3") self.lib_chapters.read_metadata_from_mp3_file(file) def __encode_started(self) -> None: self.progress_bar.setValue(0) self.statusBar().showMessage("Importing file...") def __encode_progress(self, progress: int) -> None: self.progress_bar.setValue(progress) def __encode_complete(self) -> None: self.centralWidget().setDisabled(False) self.menuBar().setDisabled(False) self.statusBar().showMessage("Import complete") def __read_metadata_started(self) -> None: self.chapters_table_view.setDisabled(True) def __read_metadata_complete(self, metadata: MetaData) -> None: self.chapters_table_view.setDisabled(False) if metadata.podcast_title: self.podcast_title.setText(metadata.podcast_title) else: self.podcast_title.clear() if metadata.episode_title: self.episode_title.setText(metadata.episode_title) else: self.episode_title.clear() if metadata.episode_number: self.episode_number.setValue(metadata.episode_number) else: self.episode_number.clear() if metadata.chapters: self.chapters_table_model.set_chapters(metadata.chapters) else: self.chapters_table_model.clear_chapters() def __save_current_file(self) -> None: if self.current_file: meta_data = MetaData( podcast_title=self.podcast_title.text(), episode_title=self.episode_title.text(), episode_number=self.episode_number.value(), chapters=self.chapters_table_model.get_chapters()) if self.current_file_type == "wav": output_file = self.__show_save_dialog("*.mp3") if output_file: self.lib_chapters.write_mp3_data_with_metadata( meta_data, output_file) elif self.current_file_type == "mp3": self.lib_chapters.write_metadata_to_file( meta_data, self.current_file) def __save_current_file_as(self) -> None: if self.current_file: output_file = self.__show_save_dialog("*.mp3") if output_file: meta_data = MetaData( podcast_title=self.podcast_title.text(), episode_title=self.episode_title.text(), episode_number=self.episode_number.value(), chapters=self.chapters_table_model.get_chapters()) if self.current_file_type == "wav": self.lib_chapters.write_mp3_data_with_metadata( meta_data, output_file) elif self.current_file_type == "mp3": self.lib_chapters.copy_mp3_with_metadata( self.current_file, output_file, meta_data) def __write_mp3_started(self) -> None: self.menuBar().setDisabled(True) self.centralWidget().setDisabled(True) self.progress_bar.setValue(0) self.statusBar().showMessage("Saving MP3...") def __write_mp3_progress(self, progress: int) -> None: self.progress_bar.setValue(progress) def __write_mp3_complete(self, path_to_mp3: str) -> None: self.menuBar().setDisabled(False) self.centralWidget().setDisabled(False) self.__set_current_file(path_to_mp3, "mp3") self.statusBar().showMessage("Save complete") def __show_about_dialog(self) -> None: about_dialog = AboutDialog(self) about_dialog.show() def __set_current_file(self, current_file: str, current_file_type: str) -> None: self.current_file = current_file self.current_file_type = current_file_type self.setWindowTitle( f"{libchapters.APPLICATION_NAME} - {os.path.basename(current_file)}" ) def __show_open_dialog(self, type_filter: str) -> Optional[str]: file, _ = QFileDialog.getOpenFileName( parent=self, dir=self.prefs.get_pref_open_dir(), filter=type_filter) if file: self.prefs.set_pref_open_dir(file) return file def __show_save_dialog(self, type_filter: str) -> Optional[str]: file, _ = QFileDialog.getSaveFileName( parent=self, dir=self.prefs.get_pref_save_dir(), filter=type_filter) if file: self.prefs.set_pref_save_dir(file) return file
class TimekeepingPropertiesDialog(QDialog): def __init__(self): super().__init__(GlobalAccess().get_main_window()) self.time_format = 'hh:mm:ss' def exec_(self): self.init_ui() return super().exec_() def init_ui(self): # self.setFixedWidth(500) self.setWindowTitle(_('Timekeeping settings')) # self.setWindowIcon(QIcon(icon_dir('sportident.png'))) self.setSizeGripEnabled(False) self.setModal(True) self.tab_widget = QTabWidget() # timekeeping tab self.timekeeping_tab = QWidget() self.tk_layout = QFormLayout() self.label_zero_time = QLabel(_('Zero time')) self.item_zero_time = QTimeEdit() self.item_zero_time.setDisplayFormat("HH:mm") self.item_zero_time.setMaximumSize(60, 20) self.item_zero_time.setDisabled(True) self.tk_layout.addRow(self.label_zero_time, self.item_zero_time) self.label_si_port = QLabel(_('Available Ports')) self.item_si_port = AdvComboBox() self.item_si_port.addItems(SIReaderClient().get_ports()) self.tk_layout.addRow(self.label_si_port, self.item_si_port) self.start_group_box = QGroupBox(_('Start time')) self.start_layout = QFormLayout() self.item_start_protocol = QRadioButton(_('From protocol')) self.start_layout.addRow(self.item_start_protocol) self.item_start_station = QRadioButton(_('Start station')) self.start_layout.addRow(self.item_start_station) self.item_start_cp = QRadioButton(_('Control point')) self.item_start_cp_value = QSpinBox() self.item_start_cp_value.setMaximumSize(60, 20) self.start_layout.addRow(self.item_start_cp, self.item_start_cp_value) self.item_start_gate = QRadioButton(_('Start gate')) self.item_start_gate.setDisabled(True) self.start_layout.addRow(self.item_start_gate) self.start_group_box.setLayout(self.start_layout) self.tk_layout.addRow(self.start_group_box) self.finish_group_box = QGroupBox(_('Finish time')) self.finish_layout = QFormLayout() self.item_finish_station = QRadioButton(_('Finish station')) self.finish_layout.addRow(self.item_finish_station) self.item_finish_cp = QRadioButton(_('Control point')) self.item_finish_cp_value = QSpinBox() self.item_finish_cp_value.setMinimum(-1) self.item_finish_cp_value.setMaximumSize(60, 20) self.finish_layout.addRow(self.item_finish_cp, self.item_finish_cp_value) self.item_finish_beam = QRadioButton(_('Light beam')) self.item_finish_beam.setDisabled(True) self.finish_layout.addRow(self.item_finish_beam) self.finish_group_box.setLayout(self.finish_layout) self.tk_layout.addRow(self.finish_group_box) self.chip_reading_box = QGroupBox(_('Assigning a chip when reading')) self.chip_reading_layout = QFormLayout() self.chip_reading_off = QRadioButton(_('Off')) self.chip_reading_layout.addRow(self.chip_reading_off) self.chip_reading_unknown = QRadioButton(_('Only unknown members')) self.chip_reading_layout.addRow(self.chip_reading_unknown) self.chip_reading_always = QRadioButton(_('Always')) self.chip_reading_layout.addRow(self.chip_reading_always) self.chip_reading_autocreate = QRadioButton(_('Athlete auto create')) self.chip_reading_layout.addRow(self.chip_reading_autocreate) self.chip_reading_box.setLayout(self.chip_reading_layout) self.tk_layout.addRow(self.chip_reading_box) self.chip_duplicate_box = QGroupBox(_('Several readout of chip')) self.chip_duplicate_layout = QFormLayout() self.chip_duplicate_serveral_results = QRadioButton(_('Several results')) self.chip_duplicate_layout.addRow(self.chip_duplicate_serveral_results) self.chip_duplicate_bib_request = QRadioButton(_('Ask for a bib when re-reading the card')) self.chip_duplicate_layout.addRow(self.chip_duplicate_bib_request) self.chip_duplicate_relay_find_leg = QRadioButton(_('Find next relay leg')) self.chip_duplicate_layout.addRow(self.chip_duplicate_relay_find_leg) self.chip_duplicate_merge = QRadioButton(_('Merge punches')) self.chip_duplicate_layout.addRow(self.chip_duplicate_merge) self.chip_duplicate_box.setLayout(self.chip_duplicate_layout) self.tk_layout.addRow(self.chip_duplicate_box) self.assignment_mode = QCheckBox(_('Assignment mode')) self.assignment_mode.stateChanged.connect(self.on_assignment_mode) self.tk_layout.addRow(self.assignment_mode) self.timekeeping_tab.setLayout(self.tk_layout) # result processing tab self.result_proc_tab = QWidget() self.result_proc_layout = QFormLayout() self.rp_time_radio = QRadioButton(_('by time')) self.result_proc_layout.addRow(self.rp_time_radio) self.rp_scores_radio = QRadioButton(_('by scores')) self.result_proc_layout.addRow(self.rp_scores_radio) self.rp_scores_group = QGroupBox() self.rp_scores_layout = QFormLayout(self.rp_scores_group) self.rp_rogain_scores_radio = QRadioButton(_('rogain scores')) self.rp_scores_layout.addRow(self.rp_rogain_scores_radio) self.rp_fixed_scores_radio = QRadioButton(_('fixed scores')) self.rp_fixed_scores_edit = QSpinBox() self.rp_fixed_scores_edit.setMaximumWidth(50) self.rp_scores_layout.addRow(self.rp_fixed_scores_radio, self.rp_fixed_scores_edit) self.rp_scores_minute_penalty_label = QLabel(_('minute penalty')) self.rp_scores_minute_penalty_edit = QSpinBox() self.rp_scores_minute_penalty_edit.setMaximumWidth(50) self.rp_scores_layout.addRow(self.rp_scores_minute_penalty_label, self.rp_scores_minute_penalty_edit) self.result_proc_layout.addRow(self.rp_scores_group) self.result_proc_tab.setLayout(self.result_proc_layout) # marked route settings self.marked_route_tab = QWidget() self.mr_layout = QFormLayout() self.mr_off_radio = QRadioButton(_('no penalty')) self.mr_layout.addRow(self.mr_off_radio) self.mr_time_radio = QRadioButton(_('penalty time')) self.mr_time_edit = QTimeEdit() self.mr_time_edit.setDisplayFormat(self.time_format) self.mr_layout.addRow(self.mr_time_radio, self.mr_time_edit) self.mr_laps_radio = QRadioButton(_('penalty laps')) self.mr_layout.addRow(self.mr_laps_radio) self.mr_counting_lap_check = QCheckBox(_('counting lap')) self.mr_counting_lap_check.setDisabled(True) # TODO self.mr_layout.addRow(self.mr_counting_lap_check) self.mr_lap_station_check = QCheckBox(_('lap station')) self.mr_lap_station_check.setDisabled(True) # TODO self.mr_lap_station_edit = QSpinBox() self.mr_lap_station_edit.setMaximumWidth(50) self.mr_layout.addRow(self.mr_lap_station_check, self.mr_lap_station_edit) self.mr_dont_dqs_check = QCheckBox(_("Don't disqualify")) self.mr_layout.addRow(self.mr_dont_dqs_check) self.mr_max_penalty_by_cp = QCheckBox(_("Max penalty = quantity of cp")) self.mr_layout.addRow(self.mr_max_penalty_by_cp) self.marked_route_tab.setLayout(self.mr_layout) # scores """ Scores [ x ] scores array 40, 37, 35, 33, ... 2, 1 [ Edit ] [ ] scores formula 1000 - 1000 * result / leader [ Edit ] """ self.scores_tab = QWidget() self.scores_layout = QFormLayout() self.scores_off = QRadioButton(_('scores off')) self.scores_array = QRadioButton(_('scores array')) self.scores_array_edit = QLineEdit() self.scores_formula = QRadioButton(_('scores formula')) self.scores_formula_edit = QLineEdit() self.scores_formula_hint = QLabel(_('scores formula hint')) self.scores_formula_hint.setWordWrap(True) self.scores_layout.addRow(self.scores_off) self.scores_layout.addRow(self.scores_array) self.scores_layout.addRow(self.scores_array_edit) self.scores_layout.addRow(self.scores_formula) self.scores_layout.addRow(self.scores_formula_edit) self.scores_layout.addRow(self.scores_formula_hint) self.scores_tab.setLayout(self.scores_layout) # time settings self.time_settings_tab = QWidget() self.time_settings_layout = QFormLayout() self.time_settings_accuracy_label = QLabel(_('Accuracy')) self.time_settings_accuracy_edit = QSpinBox() self.time_settings_accuracy_edit.setMaximumWidth(50) self.time_settings_accuracy_edit.setMaximum(3) self.time_settings_layout.addRow(self.time_settings_accuracy_label, self.time_settings_accuracy_edit) self.time_settings_format = QGroupBox() self.time_settings_format.setTitle(_('Format of competitions')) self.time_settings_format_less = QRadioButton(_('< 24')) self.time_settings_format_more = QRadioButton(_('> 24')) self.time_settings_format_layout = QFormLayout() self.time_settings_format_layout.addRow(self.time_settings_format_less) self.time_settings_format_layout.addRow(self.time_settings_format_more) self.time_settings_format.setLayout(self.time_settings_format_layout) self.time_settings_layout.addRow(self.time_settings_format) self.time_settings_tab.setLayout(self.time_settings_layout) self.tab_widget.addTab(self.timekeeping_tab, _('SPORTident (Sportiduino, ...) settings')) self.tab_widget.addTab(self.result_proc_tab, _('Result processing')) self.tab_widget.addTab(self.scores_tab, _('Scores')) self.tab_widget.addTab(self.marked_route_tab, _('Penalty calculation')) self.tab_widget.addTab(self.time_settings_tab, _('Time settings')) def cancel_changes(): self.close() def apply_changes(): try: self.apply_changes_impl() except Exception as e: logging.error(str(e)) self.close() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = button_box.button(QDialogButtonBox.Ok) self.button_ok.setText(_('OK')) self.button_ok.clicked.connect(apply_changes) self.button_cancel = button_box.button(QDialogButtonBox.Cancel) self.button_cancel.setText(_('Cancel')) self.button_cancel.clicked.connect(cancel_changes) self.layout = QFormLayout(self) self.layout.addRow(self.tab_widget) self.layout.addRow(button_box) self.set_values_from_model() self.show() def on_assignment_mode(self): mode = False if self.assignment_mode.isChecked(): mode = True self.start_group_box.setDisabled(mode) self.finish_group_box.setDisabled(mode) self.chip_reading_box.setDisabled(mode) self.chip_duplicate_box.setDisabled(mode) def set_values_from_model(self): cur_race = race() zero_time = cur_race.get_setting('system_zero_time', (8, 0, 0)) start_source = cur_race.get_setting('system_start_source', 'protocol') start_cp_number = cur_race.get_setting('system_start_cp_number', 31) finish_source = cur_race.get_setting('system_finish_source', 'station') finish_cp_number = cur_race.get_setting('system_finish_cp_number', 90) assign_chip_reading = cur_race.get_setting('system_assign_chip_reading', 'off') duplicate_chip_processing = cur_race.get_setting('system_duplicate_chip_processing', 'several_results') assignment_mode = cur_race.get_setting('system_assignment_mode', False) si_port = cur_race.get_setting('system_port', '') self.item_zero_time.setTime(QTime(zero_time[0], zero_time[1])) self.item_si_port.setCurrentText(si_port) if start_source == 'protocol': self.item_start_protocol.setChecked(True) elif start_source == 'station': self.item_start_station.setChecked(True) elif start_source == 'cp': self.item_start_cp.setChecked(True) elif start_source == 'gate': self.item_start_gate.setChecked(True) self.item_start_cp_value.setValue(start_cp_number) if finish_source == 'station': self.item_finish_station.setChecked(True) elif finish_source == 'cp': self.item_finish_cp.setChecked(True) elif finish_source == 'beam': self.item_finish_beam.setChecked(True) self.item_finish_cp_value.setValue(finish_cp_number) if assign_chip_reading == 'off': self.chip_reading_off.setChecked(True) elif assign_chip_reading == 'only_unknown_members': self.chip_reading_unknown.setChecked(True) elif assign_chip_reading == 'always': self.chip_reading_always.setChecked(True) elif assign_chip_reading == 'autocreate': self.chip_reading_autocreate.setChecked(True) if duplicate_chip_processing == 'several_results': self.chip_duplicate_serveral_results.setChecked(True) elif duplicate_chip_processing == 'bib_request': self.chip_duplicate_bib_request.setChecked(True) elif duplicate_chip_processing == 'relay_find_leg': self.chip_duplicate_relay_find_leg.setChecked(True) elif duplicate_chip_processing == 'merge': self.chip_duplicate_merge.setChecked(True) self.assignment_mode.setChecked(assignment_mode) # result processing obj = cur_race rp_mode = obj.get_setting('result_processing_mode', 'time') rp_score_mode = obj.get_setting('result_processing_score_mode', 'rogain') rp_fixed_scores_value = obj.get_setting('result_processing_fixed_score_value', 1) rp_scores_minute_penalty = obj.get_setting('result_processing_scores_minute_penalty', 1) if rp_mode == 'time': self.rp_time_radio.setChecked(True) else: self.rp_scores_radio.setChecked(True) if rp_score_mode == 'rogain': self.rp_rogain_scores_radio.setChecked(True) else: self.rp_fixed_scores_radio.setChecked(True) self.rp_fixed_scores_edit.setValue(rp_fixed_scores_value) self.rp_scores_minute_penalty_edit.setValue(rp_scores_minute_penalty) # penalty calculation mr_mode = obj.get_setting('marked_route_mode', 'off') mr_penalty_time = OTime(msec=obj.get_setting('marked_route_penalty_time', 60000)) mr_if_counting_lap = obj.get_setting('marked_route_if_counting_lap', True) mr_if_station_check = obj.get_setting('marked_route_if_station_check', False) mr_station_code = obj.get_setting('marked_route_station_code', 80) mr_if_dont_dsq_check = obj.get_setting('marked_route_dont_dsq', False) mr_if_max_penalty_by_cp = obj.get_setting('marked_route_max_penalty_by_cp', False) if mr_mode == 'off': self.mr_off_radio.setChecked(True) elif mr_mode == 'time': self.mr_time_radio.setChecked(True) else: self.mr_laps_radio.setChecked(True) self.mr_time_edit.setTime(mr_penalty_time.to_time()) self.mr_counting_lap_check.setChecked(mr_if_counting_lap) self.mr_lap_station_check.setChecked(mr_if_station_check) self.mr_lap_station_edit.setValue(mr_station_code) self.mr_dont_dqs_check.setChecked(mr_if_dont_dsq_check) self.mr_max_penalty_by_cp.setChecked(mr_if_max_penalty_by_cp) # score settings scores_mode = obj.get_setting('scores_mode', 'off') scores_array = obj.get_setting('scores_array', '40,37,35,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,' '16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1') scores_formula = obj.get_setting('scores_formula', '200 - 100 * time / leader') if scores_mode == 'off': self.scores_off.setChecked(True) elif scores_mode == 'array': self.scores_array.setChecked(True) elif scores_mode == 'formula': self.scores_formula.setChecked(True) self.scores_array_edit.setText(scores_array) self.scores_formula_edit.setText(scores_formula) # time settings time_accuracy = obj.get_setting('time_accuracy', 0) time_format_24 = obj.get_setting('time_format_24', 'less24') self.time_settings_accuracy_edit.setValue(time_accuracy) if time_format_24 == 'less24': self.time_settings_format_less.setChecked(True) elif time_format_24 == 'more24': self.time_settings_format_more.setChecked(True) def apply_changes_impl(self): obj = race() start_source = 'protocol' if self.item_start_station.isChecked(): start_source = 'station' elif self.item_start_cp.isChecked(): start_source = 'cp' elif self.item_start_gate.isChecked(): start_source = 'gate' finish_source = 'station' if self.item_finish_cp.isChecked(): finish_source = 'cp' elif self.item_finish_beam.isChecked(): finish_source = 'beam' assign_chip_reading = 'off' if self.chip_reading_unknown.isChecked(): assign_chip_reading = 'only_unknown_members' elif self.chip_reading_always.isChecked(): assign_chip_reading = 'always' elif self.chip_reading_autocreate.isChecked(): assign_chip_reading = 'autocreate' duplicate_chip_processing = 'several_results' if self.chip_duplicate_bib_request.isChecked(): duplicate_chip_processing = 'bib_request' elif self.chip_duplicate_relay_find_leg.isChecked(): duplicate_chip_processing = 'relay_find_leg' elif self.chip_duplicate_merge.isChecked(): duplicate_chip_processing = 'merge' start_cp_number = self.item_start_cp_value.value() finish_cp_number = self.item_finish_cp_value.value() old_start_cp_number = obj.get_setting('system_start_cp_number', 31) old_finish_cp_number = obj.get_setting('system_finish_cp_number', 90) if old_start_cp_number != start_cp_number or old_finish_cp_number != finish_cp_number: race().clear_results() obj.set_setting('system_port', self.item_si_port.currentText()) obj.set_setting('system_start_source', start_source) obj.set_setting('system_finish_source', finish_source) obj.set_setting('system_start_cp_number', start_cp_number) obj.set_setting('system_finish_cp_number', finish_cp_number) obj.set_setting('system_assign_chip_reading', assign_chip_reading) obj.set_setting('system_duplicate_chip_processing', duplicate_chip_processing) obj.set_setting('system_assignment_mode', self.assignment_mode.isChecked()) # result processing rp_mode = 'time' if self.rp_scores_radio.isChecked(): rp_mode = 'scores' rp_score_mode = 'rogain' if self.rp_fixed_scores_radio.isChecked(): rp_score_mode = 'fixed' rp_fixed_scores_value = self.rp_fixed_scores_edit.value() rp_scores_minute_penalty = self.rp_scores_minute_penalty_edit.value() obj.set_setting('result_processing_mode', rp_mode) obj.set_setting('result_processing_score_mode', rp_score_mode) obj.set_setting('result_processing_fixed_score_value', rp_fixed_scores_value) obj.set_setting('result_processing_scores_minute_penalty', rp_scores_minute_penalty) # marked route mr_mode = 'off' if self.mr_laps_radio.isChecked(): mr_mode = 'laps' if self.mr_time_radio.isChecked(): mr_mode = 'time' obj.set_setting('marked_route_mode', mr_mode) mr_penalty_time = time_to_otime(self.mr_time_edit.time()).to_msec() mr_if_counting_lap = self.mr_counting_lap_check.isChecked() mr_if_station_check = self.mr_lap_station_check.isChecked() mr_station_code = self.mr_lap_station_edit.value() mr_if_dont_dsq = self.mr_dont_dqs_check.isChecked() mr_if_max_penalty_by_cp = self.mr_max_penalty_by_cp.isChecked() obj.set_setting('marked_route_mode', mr_mode) obj.set_setting('marked_route_penalty_time', mr_penalty_time) obj.set_setting('marked_route_if_counting_lap', mr_if_counting_lap) obj.set_setting('marked_route_if_station_check', mr_if_station_check) obj.set_setting('marked_route_station_code', mr_station_code) obj.set_setting('marked_route_dont_dsq', mr_if_dont_dsq) obj.set_setting('marked_route_max_penalty_by_cp', mr_if_max_penalty_by_cp) # score settings scores_mode = 'off' if self.scores_array.isChecked(): scores_mode = 'array' elif self.scores_formula.isChecked(): scores_mode = 'formula' scores_array = self.scores_array_edit.text() scores_formula = self.scores_formula_edit.text() obj.set_setting('scores_mode', scores_mode) obj.set_setting('scores_array', scores_array) obj.set_setting('scores_formula', scores_formula) # time settings time_accuracy = self.time_settings_accuracy_edit.value() time_format_24 = 'less24' if self.time_settings_format_more.isChecked(): time_format_24 = 'more24' obj.set_setting('time_accuracy', time_accuracy) obj.set_setting('time_format_24', time_format_24) ResultCalculation(race()).process_results()
class Dashboard(QWidget): def __init__(self): super().__init__() self.layout = QGridLayout() self.setMaximumHeight(300) # View available_cameras = self.get_available_cameras() self.available_cameras_combobox = QComboBox() self.available_cameras_combobox.addItems(available_cameras) self.layout.addWidget(QLabel("Camera:"), 1, 0, Qt.AlignRight) self.layout.addWidget(self.available_cameras_combobox, 1, 1) # HSV color self.hsv_min_hue_sb = QSpinBox(minimum=0, maximum=255, value=DEFAULT_HSV_MIN_HUE) self.hsv_max_hue_sb = QSpinBox(minimum=0, maximum=255, value=DEFAULT_HSV_MAX_HUE) self.hsv_min_value_sb = QSpinBox(minimum=0, maximum=255, value=DEFAULT_HSV_MIN_VALUE) self.hsv_max_value_sb = QSpinBox(minimum=0, maximum=255, value=DEFAULT_HSV_MAX_VALUE) self.hsv_min_saturation_sb = QSpinBox(minimum=0, maximum=255, value=DEFAULT_HSV_MIN_SATURATION) self.hsv_max_saturation_sb = QSpinBox(minimum=0, maximum=255, value=DEFAULT_HSV_MAX_SATURATION) self.hsv_min_hue_s = QSlider(minimum=0, maximum=255, value=DEFAULT_HSV_MIN_HUE, orientation=Qt.Horizontal) self.hsv_max_hue_s = QSlider(minimum=0, maximum=255, value=DEFAULT_HSV_MAX_HUE, orientation=Qt.Horizontal) self.hsv_min_value_s = QSlider( minimum=0, maximum=255, value=DEFAULT_HSV_MIN_VALUE, orientation=Qt.Horizontal, ) self.hsv_max_value_s = QSlider( minimum=0, maximum=255, value=DEFAULT_HSV_MAX_VALUE, orientation=Qt.Horizontal, ) self.hsv_min_saturation_s = QSlider( minimum=0, maximum=255, value=DEFAULT_HSV_MIN_SATURATION, orientation=Qt.Horizontal, ) self.hsv_max_saturation_s = QSlider( minimum=0, maximum=255, value=DEFAULT_HSV_MAX_SATURATION, orientation=Qt.Horizontal, ) max_width = 300 self.hsv_min_hue_sb.setMaximumWidth(max_width) self.hsv_max_hue_sb.setMaximumWidth(max_width) self.hsv_min_value_sb.setMaximumWidth(max_width) self.hsv_max_value_sb.setMaximumWidth(max_width) self.hsv_min_saturation_sb.setMaximumWidth(max_width) self.hsv_max_saturation_sb.setMaximumWidth(max_width) self.hsv_min_hue_s.setMaximumWidth(max_width) self.hsv_max_hue_s.setMaximumWidth(max_width) self.hsv_min_value_s.setMaximumWidth(max_width) self.hsv_max_value_s.setMaximumWidth(max_width) self.hsv_min_saturation_s.setMaximumWidth(max_width) self.hsv_max_saturation_s.setMaximumWidth(max_width) self.layout.addWidget(QLabel("Min"), 0, 3, Qt.AlignBottom | Qt.AlignHCenter) self.layout.addWidget(QLabel("Max"), 0, 4, Qt.AlignBottom | Qt.AlignHCenter) self.layout.addWidget(QLabel("Hue:"), 1, 2, Qt.AlignRight) self.layout.addWidget(self.hsv_min_hue_sb, 1, 3) self.layout.addWidget(self.hsv_max_hue_sb, 1, 4) self.layout.addWidget(self.hsv_min_hue_s, 2, 3) self.layout.addWidget(self.hsv_max_hue_s, 2, 4) self.layout.addWidget(QLabel("Value:"), 3, 2, Qt.AlignRight) self.layout.addWidget(self.hsv_min_value_sb, 3, 3) self.layout.addWidget(self.hsv_max_value_sb, 3, 4) self.layout.addWidget(self.hsv_min_value_s, 4, 3) self.layout.addWidget(self.hsv_max_value_s, 4, 4) self.layout.addWidget(QLabel("Saturation:"), 5, 2, Qt.AlignRight) self.layout.addWidget(self.hsv_min_saturation_sb, 5, 3) self.layout.addWidget(self.hsv_max_saturation_sb, 5, 4) self.layout.addWidget(self.hsv_min_saturation_s, 6, 3) self.layout.addWidget(self.hsv_max_saturation_s, 6, 4) # Color selection self.current_color = QLabel() self.current_color.setFixedSize(50, 50) self.current_color.setAutoFillBackground(True) self.layout.addWidget(QLabel("Current color:"), 1, 5, Qt.AlignRight) self.layout.addWidget(self.current_color, 1, 6) self.selected_color = QLabel() self.selected_color.setFixedSize(50, 50) self.selected_color.setAutoFillBackground(True) self.layout.addWidget(QLabel("Base filtered color:"), 2, 5, Qt.AlignRight) self.layout.addWidget(self.selected_color, 2, 6) self.lower_filtered_color = QLabel() self.lower_filtered_color.setFixedSize(50, 50) self.lower_filtered_color.setAutoFillBackground(True) self.layout.addWidget(QLabel("Lower filtered color:"), 3, 5, Qt.AlignRight) self.layout.addWidget(self.lower_filtered_color, 3, 6) self.upper_filtered_color = QLabel() self.upper_filtered_color.setFixedSize(50, 50) self.upper_filtered_color.setAutoFillBackground(True) self.layout.addWidget(QLabel("Upper filtered color:"), 4, 5, Qt.AlignRight) self.layout.addWidget(self.upper_filtered_color, 4, 6) self.setLayout(self.layout) self.hsv_min_hue_sb.valueChanged.connect(self.update_hsv) self.hsv_min_hue_sb.valueChanged.connect(self.hsv_min_hue_s.setValue) self.hsv_min_hue_s.valueChanged.connect(self.hsv_min_hue_sb.setValue) self.hsv_max_hue_sb.valueChanged.connect(self.update_hsv) self.hsv_max_hue_sb.valueChanged.connect(self.hsv_max_hue_s.setValue) self.hsv_max_hue_s.valueChanged.connect(self.hsv_max_hue_sb.setValue) self.hsv_min_value_sb.valueChanged.connect(self.update_hsv) self.hsv_min_value_sb.valueChanged.connect( self.hsv_min_value_s.setValue) self.hsv_min_value_s.valueChanged.connect( self.hsv_min_value_sb.setValue) self.hsv_max_value_sb.valueChanged.connect(self.update_hsv) self.hsv_max_value_sb.valueChanged.connect( self.hsv_max_value_s.setValue) self.hsv_max_value_s.valueChanged.connect( self.hsv_max_value_sb.setValue) self.hsv_min_saturation_sb.valueChanged.connect(self.update_hsv) self.hsv_min_saturation_sb.valueChanged.connect( self.hsv_min_saturation_s.setValue) self.hsv_min_saturation_s.valueChanged.connect( self.hsv_min_saturation_sb.setValue) self.hsv_max_saturation_sb.valueChanged.connect(self.update_hsv) self.hsv_max_saturation_sb.valueChanged.connect( self.hsv_max_saturation_s.setValue) self.hsv_max_saturation_s.valueChanged.connect( self.hsv_max_saturation_sb.setValue) def get_available_cameras(self): available_cameras = [""] q_camera_info = QCameraInfo() for available_camera in q_camera_info.availableCameras(): device_name = available_camera.deviceName() available_cameras.append(device_name) return available_cameras # ----------------------------------------------------------------------------- # --- SLOTS # ----------------------------------------------------------------------------- def set_current_color(self, r, g, b): palette = QPalette() palette.setColor(QPalette.Background, QColor(r, g, b)) self.current_color.setPalette(palette) def set_selected_color(self, r, g, b): palette = QPalette() palette.setColor(QPalette.Background, QColor(r, g, b)) self.selected_color.setPalette(palette) def update_hsv(self, _): color = self.selected_color.palette().color(QPalette.Background) r, g, b = color.red(), color.green(), color.blue() lower_hsv, upper_hsv = rgb_to_hsv_range( r, g, b, min_h=self.hsv_min_hue_sb.value(), max_h=self.hsv_max_hue_sb.value(), min_s=self.hsv_min_saturation_sb.value(), max_s=self.hsv_max_saturation_sb.value(), min_v=self.hsv_min_value_sb.value(), max_v=self.hsv_max_value_sb.value(), ) r, g, b = hsv_to_rgb(*lower_hsv) palette = QPalette() palette.setColor(QPalette.Background, QColor(r, g, b)) self.lower_filtered_color.setPalette(palette) r, g, b = hsv_to_rgb(*upper_hsv) palette = QPalette() palette.setColor(QPalette.Background, QColor(r, g, b)) self.upper_filtered_color.setPalette(palette)