class JobCodeDialog(QDialog): def __init__(self, parent, on_download: bool, job_codes: List[str]) -> None: """ Prompt user to enter a Job Code, either at the time a download starts, or to zero or more selected files before the download begins. :param parent: rapidApp main window :param on_download: if True, dialog is being prompted for before a download starts. :param job_codes: """ super().__init__(parent) self.rapidApp = parent # type: 'RapidWindow' self.prefs = self.rapidApp.prefs # type: Preferences thumbnailModel = self.rapidApp.thumbnailModel # Whether the user has opened this dialog before a download starts without # having selected any files first no_selection_made = None # type: Optional[bool] if on_download: directive = _("Enter a new Job Code, or select a previous one") file_types = thumbnailModel.getNoFilesJobCodeNeeded() details = file_types.file_types_present_details(title_case=False) if sum(file_types.values()) == 1: # Translators: the value substituted will be something like '1 photo'. file_details = (_( "The Job Code will be applied to %s that does not yet have a " "Job Code.") % details) else: # Translators: the value substituted will be something like # '85 photos and 5 videos'. file_details = (_( "The Job Code will be applied to %s that do not yet have a " "Job Code.") % details) hint = ( "<b>Hint:</b> To assign Job Codes before the download begins, select " "photos or videos and apply a new or existing Job Code to them via the " "Job Code panel.") file_details = "{}<br><br><i>{}</i>".format(file_details, hint) title = _("Apply Job Code to Download") else: directive = _("Enter a new Job Code") file_types = thumbnailModel.getNoFilesSelected() no_selection_made = sum(file_types.values()) == 0 if no_selection_made: file_details = ("<i>" + _( "<b>Hint:</b> Select photos or videos before entering a new " "Job Code to have the Job Code applied to them.") + "</i>") _("") else: details = file_types.file_types_present_details( title_case=False) # Translators: the value substituted will be something like # '100 photos and 5 videos'. file_details = ( "<i>" + _("The new Job Code will be applied to %s.") % details + "</i>") title = _("New Job Code") instructionLabel = QLabel("<b>%s</b><br><br>%s<br>" % (directive, file_details)) instructionLabel.setWordWrap(True) self.jobCodeComboBox = QComboBox() self.jobCodeComboBox.addItems(job_codes) self.jobCodeComboBox.setEditable(True) if not self.prefs.strip_characters: exp = "[^/\\0]+" else: exp = '[^\\:\*\?"<>|\\0/]+' self.jobCodeExp = QRegularExpression() self.jobCodeExp.setPattern(exp) self.jobCodeValidator = QRegularExpressionValidator( self.jobCodeExp, self.jobCodeComboBox) self.jobCodeComboBox.setValidator(self.jobCodeValidator) if not on_download: self.jobCodeComboBox.clearEditText() if self.prefs.job_code_sort_key == 0: if self.prefs.job_code_sort_order == 0: self.jobCodeComboBox.setInsertPolicy(QComboBox.InsertAtTop) else: self.jobCodeComboBox.setInsertPolicy(QComboBox.InsertAtBottom) else: self.jobCodeComboBox.setInsertPolicy( QComboBox.InsertAlphabetically) icon = QIcon(":/rapid-photo-downloader.svg").pixmap(standardIconSize()) iconLabel = QLabel() iconLabel.setPixmap(icon) iconLabel.setAlignment(Qt.AlignTop | Qt.AlignLeft) iconLabel.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) jobCodeLabel = QLabel(_("&Job Code:")) jobCodeLabel.setBuddy(self.jobCodeComboBox) if on_download or not no_selection_made: self.rememberCheckBox = QCheckBox(_("&Remember this Job Code")) self.rememberCheckBox.setChecked(parent.prefs.remember_job_code) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) translateDialogBoxButtons(buttonBox) grid = QGridLayout() grid.addWidget(iconLabel, 0, 0, 4, 1) grid.addWidget(instructionLabel, 0, 1, 1, 2) grid.addWidget(jobCodeLabel, 1, 1) grid.addWidget(self.jobCodeComboBox, 1, 2) if hasattr(self, "rememberCheckBox"): grid.addWidget(self.rememberCheckBox, 2, 1, 1, 2) grid.addWidget(buttonBox, 3, 0, 1, 3) else: grid.addWidget(buttonBox, 2, 0, 1, 3) grid.setColumnStretch(2, 1) self.setLayout(grid) self.setWindowTitle(title) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) @pyqtSlot() def accept(self) -> None: self.job_code = self.jobCodeComboBox.currentText() if hasattr(self, "rememberCheckBox"): self.remember = self.rememberCheckBox.isChecked() self.rapidApp.prefs.remember_job_code = self.remember else: self.remember = True super().accept()
def home(self): # self.configs = self.load_configs() def get_vals(): update_config() self.save_config() a_lims = (range_a.range_min(), range_a.range_max()) if pairs.checkState(): b_lims = None range_type = fc.RangeTypes.InnerProduct else: b_lims = (range_b.range_min(), range_b.range_max()) range_type = fc.RangeTypes.OuterProduct return fc.generate_pairs(a_lims, b_lims, range_type) def on_addition_clicked(): self.deck = fc.generate_addition( get_vals(), time_threshold=mastery_time.value()) self.run_deck() def on_subtraction_clicked(): self.deck = fc.generate_subtraction( get_vals(), time_threshold=mastery_time.value()) self.run_deck() def on_multiplication_clicked(): self.deck = fc.generate_multiplication( get_vals(), time_threshold=mastery_time.value()) self.run_deck() def on_division_clicked(): self.deck = fc.generate_division( get_vals(), time_threshold=mastery_time.value()) self.run_deck() def on_sqrt_clicked(): self.deck = fc.generate_square_roots( get_vals(), time_threshold=mastery_time.value()) self.run_deck() def on_custom_clicked(): update_config() self.save_config() file, _ = QFileDialog.getOpenFileName( self.window, "Open Flashcard Deck", str(self.current_config["log_file_dir"]), "Flashcard decks (*.yml)") self.deck = fc.load_deck(file) for c in self.deck.cards: c.responses = [] self.run_deck() def update_config(): self.current_config["name"] = config_name.currentText() self.current_config["mastery_time"] = mastery_time.value() self.current_config["min_val"] = range_a.range_min() self.current_config["max_val"] = range_a.range_max() self.current_config["min_val_b"] = range_b.range_min() self.current_config["max_val_b"] = range_b.range_max() def on_config_change(): print(config_name.currentIndex()) config = self.configs[config_name.currentIndex()] mastery_time.setValue(config["mastery_time"]) range_a.set_range(config["min_val"], config["max_val"]) range_b.set_range(config["min_val_b"], config["max_val_b"]) self.current_config = config def update_configs(): config_name.clear() for cfg in self.configs: config_name.addItem(cfg["name"]) config_name.setCurrentText(self.current_config["name"]) def remove_config(): if self.current_config["name"] == config_name.currentText(): self.delete_config() config_name.removeItem(config_name.currentIndex()) class RangeSelect(QWidget): def __init__(self, label="Min/Max Values", min_val=0, max_val=15): super().__init__() self.layout = QHBoxLayout() self.label = QLabel(label) self.start_val = QSpinBox() self.start_val.setRange(0, max_val) self.stop_val = QSpinBox() self.stop_val.setRange(min_val, 25) self.start_val.setValue(min_val) self.stop_val.setValue(max_val) self.start_val.valueChanged.connect(self.on_change) self.stop_val.valueChanged.connect(self.on_change) self.layout.addWidget(self.label) self.layout.addStretch() self.layout.addWidget(self.start_val) self.layout.addWidget(self.stop_val) self.setLayout(self.layout) def on_change(self): self.start_val.setRange(0, self.stop_val.value()) self.stop_val.setRange(self.start_val.value(), 25) def range_min(self): return int(self.start_val.value()) def range_max(self): return int(self.stop_val.value()) def set_range(self, min_val, max_val): self.start_val.setRange(0, max_val) self.stop_val.setRange(min_val, 25) self.start_val.setValue(min_val) self.stop_val.setValue(max_val) # print(f'Setting range to ({min_val}, {max_val}).') def on_pairs_changed(pairs_mode): range_b.setDisabled(pairs_mode) if pairs_mode: division.setText('Square Roots (√(A×A))') division.clicked.disconnect(on_division_clicked) division.clicked.connect(on_sqrt_clicked) else: division.setText('Division ((A×B) ÷ A)') division.clicked.disconnect(on_sqrt_clicked) division.clicked.connect(on_division_clicked) layout = QVBoxLayout() layout.addStretch() layout_config = QHBoxLayout() add_config = QPushButton('Add Config') add_config.setMaximumWidth(400) layout_config.addWidget(add_config) config_name = QComboBox() update_configs() config_name.currentTextChanged.connect(on_config_change) add_config.clicked.connect(lambda _: (config_name.setEditable(True), config_name.clearEditText())) layout_config.addWidget(config_name) rm_config = QPushButton('Remove Config') rm_config.setMaximumWidth(500) rm_config.clicked.connect(remove_config) layout_config.addWidget(rm_config) layout.addLayout(layout_config) layout.addStretch() layout_mastery_time = QHBoxLayout() layout_mastery_time.addWidget( QLabel("Response time for a problem to be mastered (seconds)")) mastery_time = QSpinBox() mastery_time.setRange(1, 15) mastery_time.setValue(self.current_config["mastery_time"]) layout_mastery_time.addWidget(mastery_time) layout.addLayout(layout_mastery_time) layout.addStretch() range_a = RangeSelect("Min/Max Range for A", min_val=self.current_config["min_val"], max_val=self.current_config["max_val"]) layout.addWidget(range_a) range_b = RangeSelect("Min/Max Range for B", min_val=self.current_config["min_val_b"], max_val=self.current_config["max_val_b"]) layout.addWidget(range_b) pairs_layout = QHBoxLayout() pairs_layout.addWidget(QLabel('Pairs?')) pairs_layout.addStretch() pairs = QCheckBox() pairs_layout.addWidget(pairs) pairs.stateChanged.connect(on_pairs_changed) layout.addLayout(pairs_layout) hline = QFrame() hline.setFrameShape(QFrame.HLine) hline.setFrameShadow(QFrame.Sunken) hline.setMinimumHeight(40) layout.addWidget(hline) type_selection_layout = QHBoxLayout() type_selection_layout.addWidget(QLabel("Select type of flashcards:")) button_layout = QVBoxLayout() addition = QPushButton("Addition (A + B)") subtraction = QPushButton("Subtraction ((A+B) - A)") multiplication = QPushButton("Multiplication (A × B)") division = QPushButton("Division ((A×B) ÷ A)") custom = QPushButton("Load from File ") addition.clicked.connect(on_addition_clicked) subtraction.clicked.connect(on_subtraction_clicked) multiplication.clicked.connect(on_multiplication_clicked) division.clicked.connect(on_division_clicked) custom.clicked.connect(on_custom_clicked) button_layout.addWidget(addition) button_layout.addWidget(subtraction) button_layout.addWidget(multiplication) button_layout.addWidget(division) button_layout.addWidget(custom) type_selection_layout.addLayout(button_layout) layout.addStretch() layout.addLayout(type_selection_layout) layout.addStretch() # on_config_change() return layout