def updateView(self, value): if type(value) == type(''): value = value == self.onam or value == '1' widget = self QCheckBox.blockSignals(widget, True) QCheckBox.setChecked(widget, value) QCheckBox.blockSignals(widget, False)
class msgBox: def __init__(self, title="", text="", info="", detail="", icon=QMessageBox.NoIcon, stdButton=QMessageBox.Ok, defButton=QMessageBox.NoButton, escButton=QMessageBox.NoButton, dontShowAgain=False, dontShowChecked=False): self.msg = QMessageBox() self.msg.setWindowTitle(title) self.msg.setText(text) self.msg.setInformativeText(info) self.msg.setDetailedText(detail) self.msg.setIcon(icon) self.chkDontShow = QCheckBox("Don't show confirmation again") self.chkDontShow.setChecked(dontShowChecked) self.chkDontShow.blockSignals(True) if dontShowAgain: self.msg.addButton(self.chkDontShow, QMessageBox.ResetRole) self.msg.setStandardButtons(stdButton) self.msg.setDefaultButton(defButton) self.msg.setEscapeButton(escButton) def afficheMsg(self): return (self.msg.exec())
class QScenes(ZoneDlg): zonename = "Scene" title = "Scene Editor" def createNewFilterInstance(self): return Scenes() def _createModeBox(self): self.modeBox = comboBox = QComboBox(self) comboBox.addItem("Input", 1) self._mode = 1 def _createGlobalControls(self, layout=None, index=None): if layout is None: layout = self.layout() self.fixPtsCheckBox = QCheckBox( "Fix PTS times (for variable frame rate video)", self) self.fixPtsCheckBox.stateChanged.connect(self.toggleFixPts) layout.addWidget(self.fixPtsCheckBox) def _resetGlobalControls(self): self.fixPtsCheckBox.blockSignals(True) self.fixPtsCheckBox.setCheckState(2 if self.filtercopy.fixpts else 0) self.fixPtsCheckBox.blockSignals(False) def toggleFixPts(self, checkstate): if checkstate == Qt.Checked: self.filtercopy.fixpts = 1 else: self.filtercopy.fixpts = 0 self.isModified()
class BooleanOption(GenericOption): def __init__(self, option, container): super().__init__(option, container) self.qsid_bit = self.option["bit"] self.checkbox = QCheckBox() self.checkbox.stateChanged.connect(self.on_change) self.container.addWidget(self.checkbox, self.row, 1) def reload(self, keyboard): value = super().reload(keyboard) checked = value & (1 << self.qsid_bit) self.checkbox.blockSignals(True) self.checkbox.setChecked(checked != 0) self.checkbox.blockSignals(False) def value(self): checked = int(self.checkbox.isChecked()) return checked << self.qsid_bit def delete(self): super().delete() self.checkbox.hide() self.checkbox.deleteLater()
def createSignalsGroupBox(self) -> QGroupBox: """ create a grid layout for display of observed signals / channels """ gb = QGroupBox('Signals') gb.setStyleSheet(self.styleSheet) gbSignalsType = QGroupBox() gbSignalsType.setFlat(True) gbSignalsType.setStyleSheet("border:0;margin: 0em;") gbSignalsType.setContentsMargins(0, 0, 0, 0) hbox = QHBoxLayout() self.cbSignalsType = [] self.cbSignalsType.append(QCheckBox('Pseudo Range')) self.cbSignalsType.append(QCheckBox('Carrier Phase')) self.cbSignalsType.append(QCheckBox('Signal Strength')) self.cbSignalsType.append(QCheckBox('Doppler Frequency')) hbox.addStretch(1) hbox.addWidget(QLabel('Select:')) for cb in self.cbSignalsType: hbox.addWidget((cb)) cb.toggled.connect(self.onToggledSignalsType) gbSignalsType.setLayout(hbox) # create a list of radio buttons and add them to a grid loGrid = QGridLayout() self.cbSignals = [] for iSignal, signal in enumerate(self.Signals): cb = QCheckBox(self.Signals[iSignal]) self.cbSignals.append(cb) cb.toggled.connect(self.onToggledSignal) # disable the signals of type SSI (Signal Strength Indicator) or LLI (Los Lock Indicator) if signal.endswith('lli') or signal.endswith('ssi'): cb.blockSignals(True) cb.setEnabled(False) # add to gridlayout curRow, curCol = divmod(iSignal, self.nrCols) print( 'createSignalsGroupBox: signal = {!s} iSignal = {:d} curpos = {:d}:{:d}' .format(self.Signals[iSignal], iSignal, curRow, curCol)) loGrid.addWidget(cb, curRow, curCol) vbox = QVBoxLayout() vbox.addWidget(gbSignalsType) vbox.addLayout(loGrid) gb.setLayout(vbox) return gb
def _change_checkbox(self, checkbox: QCheckBox, checked: bool, attr: str = None, trigger: bool = True): if not trigger: checkbox.blockSignals(True) checkbox.setChecked(checked) if not trigger: setattr(self, attr, checked) checkbox.blockSignals(False)
class ParentTreeItemWidget(QFrame): def __init__(self, text, item): QWidget.__init__(self) self.setMouseTracking(True) self.text = text self.item = item self.label = QLabel() self.checkBox = QCheckBox("") self.checkBox.setTristate(True) self.checkBox.stateChanged.connect(self.check_box_state_changed) layout = QHBoxLayout() layout.setMargin(0) layout.addWidget(self.checkBox) layout.addWidget(self.label) layout.addStretch() self.setLayout(layout) def check_box_state_changed(self): total = self.item.childCount() if self.checkBox.isTristate(): self.checkBox.setTristate(False) self.checkBox.setChecked(False) else: for i in range(total): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) w.setChecked(self.checkBox.isChecked(), False) self.item.treeWidget().quadsSelectionChanged.emit() def update_name_and_checkbox(self): selected = 0 total = self.item.childCount() for i in range(total): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) if w.isSelected(): selected += 1 self.label.setText( f"<b>{self.text} - {selected} of {total} selected</b>") self.checkBox.blockSignals(True) if selected == total: self.checkBox.setTristate(False) self.checkBox.setCheckState(Qt.Checked) elif selected == 0: self.checkBox.setTristate(False) self.checkBox.setCheckState(Qt.Unchecked) else: self.checkBox.setTristate(True) self.checkBox.setCheckState(Qt.PartiallyChecked) self.checkBox.blockSignals(False)
class DirViewWidget(QWidget): loadFiles = pyqtSignal(object, list, bool, name='loadFiles') removeFolders = pyqtSignal(list, bool, name='removeFolders') def __init__(self, parent=None, subfolders=False, status=None): super(DirViewWidget, self).__init__(parent) self._status = status self.dirview = DirView(self, subfolders, status) self.dirview.loadFiles.connect(self.loadFiles) self.dirview.removeFolders.connect(self.removeFolders) self.receives = [ ('dirschanged', self.dirview.selectDirs), ('dirsmoved', self.dirview.dirMoved), ] self.emits = ['loadFiles', 'removeFolders'] self.subfolderCheck = QCheckBox(translate('Dirview', 'Subfolders'), self) self.subfolderCheck.stateChanged.connect(self.setSubFolders) layout = QVBoxLayout() layout.addWidget(self.dirview, 1) layout.addWidget(self.subfolderCheck, 0) self.setLayout(layout) def loadSettings(self): self.dirview.loadSettings() self.subfolderCheck.blockSignals(True) if load_gen_settings([('Su&bfolders', True)])[0][1]: self.subfolderCheck.setChecked(True) else: self.subfolderCheck.setChecked(False) self.subfolderCheck.blockSignals(False) def saveSettings(self): self.dirview.saveSettings() def setSubFolders(self, check): if check == Qt.Checked: value = True else: value = False self.dirview.subfolders = value save_gen_settings({'Su&bfolders': value}) self._status['table'].subFolders = value
def display_warning(self): if not CONFIG.getboolean("Options", "show_startup_warning", fallback=True) or not self.just_launched: return self.just_launched = False warning_box = QMessageBox(self) warning_box.setIcon(QMessageBox.Warning) dont_show_cb = QCheckBox(tr_str("warning_dialog.dont_show_again")) dont_show_cb.setCheckable(True) dont_show_cb.blockSignals(True) confirm_button = QPushButton() ok_text = tr_str("warning_dialog.ok") confirm_button.setText(ok_text) confirm_button.setEnabled(False) warning_box.addButton(dont_show_cb, QMessageBox.ResetRole) warning_box.addButton(confirm_button, QMessageBox.AcceptRole) warning_box.setTextFormat(Qt.RichText) warning_box.setText(tr_str("warning_dialog.warning")) warning_box.setWindowTitle(tr_str("warning_dialog.title")) def button_timer(): for i in range(5, -1, -1): time.sleep(1) confirm_button.setText(f"{ok_text} ({i})") confirm_button.setText(ok_text) confirm_button.setEnabled(True) threading._start_new_thread(button_timer, ()) warning_box.exec() if dont_show_cb.checkState() == Qt.Checked: CONFIG["Options"]["show_startup_warning"] = "no" save_config()
class OptionsDialog(QDialog): def __init__(self, setting: Settings, have_dutils, parent=None): super(OptionsDialog, self).__init__(parent) self.settings = setting self.enabled_video = True # temporary toggle to disable video features as they do not exist self.enabled_logging = True self.enabled_keybindings = True self.enabled_dutils = have_dutils self.setWindowTitle("Tcam-Capture Options") self.layout = QVBoxLayout(self) self.setLayout(self.layout) self.tabs = QTabWidget() self.general_widget = QWidget() self.keybindings_widget = QWidget() self.logging_widget = QWidget() self.saving_widget = QWidget() self._setup_general_ui() self.tabs.addTab(self.general_widget, "General") self._setup_saving_ui() self.tabs.addTab(self.saving_widget, "Image/Video") self.layout.addWidget(self.tabs) # OK and Cancel buttons self.buttons = QDialogButtonBox( QDialogButtonBox.Reset | QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.layout.addWidget(self.buttons) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) self.buttons.clicked.connect(self.clicked) def _setup_general_ui(self): """ Create everything related to the general tab """ layout = QFormLayout() layout.setSpacing(20) layout.setVerticalSpacing(20) self.device_dialog_checkbox = QCheckBox(self) device_dialog_label = QLabel("Open device dialog on start:") layout.addRow(device_dialog_label, self.device_dialog_checkbox) self.reopen_device_checkbox = QCheckBox(self) reopen_device_label = QLabel( "Reopen device on start(ignores device dialog):", self) layout.addRow(reopen_device_label, self.reopen_device_checkbox) self.use_dutils_checkbox = QCheckBox(self) self.use_dutils_label = QLabel("Use tiscamera dutils, if present:", self) layout.addRow(self.use_dutils_label, self.use_dutils_checkbox) if not self.enabled_dutils: self.use_dutils_label.setToolTip( "Enabled when tiscamera-dutils are installed") self.use_dutils_label.setEnabled(False) self.use_dutils_checkbox.setToolTip( "Enabled when tiscamera-dutils are installed") self.use_dutils_checkbox.setEnabled(False) self.general_widget.setLayout(layout) def _setup_saving_ui(self): """ Create everything related to the image/video saving tab """ encoder_dict = Encoder.get_encoder_dict() form_layout = QFormLayout() layout = QVBoxLayout() layout.addLayout(form_layout) location_layout = QHBoxLayout() location_label = QLabel("Where to save images/videos:", self) self.location_edit = QLineEdit(self) location_dialog_button = QPushButton("...", self) location_dialog_button.clicked.connect(self.open_file_dialog) location_layout.addWidget(self.location_edit) location_layout.addWidget(location_dialog_button) # maintain descriptions as own labels # pyqt seems to loose the descriptions somewhere # when simple strings are used or the qlabel does not have self as owner form_layout.addRow(location_label, location_layout) self.image_type_combobox = QComboBox(self) for key, value in encoder_dict.items(): if value.encoder_type == Encoder.MediaType.image: self.image_type_combobox.addItem(key) image_type_label = QLabel("Save images as:") self.image_type_combobox.currentIndexChanged['QString'].connect( self.image_name_suffix_changed) form_layout.addRow(image_type_label, self.image_type_combobox) if self.enabled_video: self.video_type_combobox = QComboBox(self) for key, value in encoder_dict.items(): if value.encoder_type == Encoder.MediaType.video: self.video_type_combobox.addItem(key) self.video_type_combobox.currentIndexChanged['QString'].connect( self.video_name_suffix_changed) video_type_label = QLabel("Save videos as:", self) form_layout.addRow(video_type_label, self.video_type_combobox) image_name_groupbox = QGroupBox("Image File Names") groupbox_layout = QFormLayout() image_name_groupbox.setLayout(groupbox_layout) self.image_name_preview = QLabel( "<USER-PREFIX>-<SERIAL>-<FORMAT>-<TIMESTAMP>-<COUNTER>.png") self.image_name_preview_description = QLabel( "Images will be named like:") groupbox_layout.addRow(self.image_name_preview_description, self.image_name_preview) self.image_name_prefix = QLineEdit() self.image_name_prefix.textChanged.connect( self.image_name_prefix_changed) self.image_name_prefix.setMaxLength(100) self.image_name_prefix_description = QLabel("User Prefix:", self) groupbox_layout.addRow(self.image_name_prefix_description, self.image_name_prefix) self.image_name_serial = QCheckBox(self) self.image_name_serial.toggled.connect( self.image_name_properties_toggled) self.image_name_serial_description = QLabel("Include Serial:") groupbox_layout.addRow(self.image_name_serial_description, self.image_name_serial) self.image_name_format = QCheckBox(self) self.image_name_format.toggled.connect( self.image_name_properties_toggled) self.image_name_format_description = QLabel("Include Format:") groupbox_layout.addRow(self.image_name_format_description, self.image_name_format) self.image_name_counter = QCheckBox(self) self.image_name_counter.toggled.connect( self.image_name_properties_toggled) self.image_name_counter_description = QLabel("Include Counter:") groupbox_layout.addRow(self.image_name_counter_description, self.image_name_counter) self.image_name_counter_box = QSpinBox(self) self.image_name_counter_box.setRange(1, 10) self.image_name_counter_box.valueChanged.connect( self.image_name_counter_changed) self.image_name_counter_box_description = QLabel("Counter Size:") groupbox_layout.addRow(self.image_name_counter_box_description, self.image_name_counter_box) self.image_name_counter.toggled.connect( self.toggle_image_counter_box_availability) self.image_name_counter.toggled.connect( self.image_name_properties_toggled) self.image_name_timestamp = QCheckBox(self) self.image_name_timestamp.toggled.connect( self.image_name_properties_toggled) self.image_name_timestamp_description = QLabel("Include Timestamp:") groupbox_layout.addRow(self.image_name_timestamp_description, self.image_name_timestamp) layout.addWidget(image_name_groupbox) video_groupbox = QGroupBox("Video File Names") video_layout = QFormLayout() video_groupbox.setLayout(video_layout) self.video_name_preview = QLabel( "<USER-PREFIX>-<SERIAL>-<FORMAT>-<TIMESTAMP>-<COUNTER>.png") self.video_name_preview_description = QLabel( "Videos will be named like:") video_layout.addRow(self.video_name_preview_description, self.video_name_preview) self.video_name_prefix = QLineEdit() self.video_name_prefix.textChanged.connect( self.video_name_prefix_changed) self.video_name_prefix.setMaxLength(100) self.video_name_prefix_description = QLabel("User Prefix:", self) video_layout.addRow(self.video_name_prefix_description, self.video_name_prefix) self.video_name_serial = QCheckBox(self) self.video_name_serial.toggled.connect( self.video_name_properties_toggled) self.video_name_serial_description = QLabel("Include Serial:") video_layout.addRow(self.video_name_serial_description, self.video_name_serial) self.video_name_format = QCheckBox(self) self.video_name_format.toggled.connect( self.video_name_properties_toggled) self.video_name_format_description = QLabel("Include Format:") video_layout.addRow(self.video_name_format_description, self.video_name_format) self.video_name_counter = QCheckBox(self) self.video_name_counter.toggled.connect( self.video_name_properties_toggled) self.video_name_counter_description = QLabel("Include Counter:") video_layout.addRow(self.video_name_counter_description, self.video_name_counter) self.video_name_counter_box = QSpinBox(self) self.video_name_counter_box.setRange(1, 10) self.video_name_counter_box.valueChanged.connect( self.video_name_counter_changed) self.video_name_counter_box_description = QLabel("Counter Size:") video_layout.addRow(self.video_name_counter_box_description, self.video_name_counter_box) self.video_name_counter.toggled.connect( self.toggle_video_counter_box_availability) self.video_name_counter.toggled.connect( self.video_name_properties_toggled) self.video_name_timestamp = QCheckBox(self) self.video_name_timestamp.toggled.connect( self.video_name_properties_toggled) self.video_name_timestamp_description = QLabel("Include Timestamp:") video_layout.addRow(self.video_name_timestamp_description, self.video_name_timestamp) layout.addWidget(video_groupbox) self.saving_widget.setLayout(layout) def image_name_prefix_changed(self, name: str): """""" self.settings.image_name.user_prefix = self.image_name_prefix.text() self.update_image_name_preview() def image_name_suffix_changed(self, suffix: str): """""" self.update_image_name_preview() def image_name_counter_changed(self, name: str): """""" self.settings.image_name.counter_size = self.image_name_counter_box.value( ) self.update_image_name_preview() def image_name_properties_toggled(self): """""" self.settings.image_name.include_timestamp = self.image_name_timestamp.isChecked( ) self.settings.image_name.include_counter = self.image_name_counter.isChecked( ) self.settings.image_name.include_format = self.image_name_format.isChecked( ) self.settings.image_name.include_serial = self.image_name_serial.isChecked( ) self.update_image_name_preview() def update_image_name_preview(self): preview_string = "" if self.settings.image_name.user_prefix != "": max_prefix_length = 15 prefix = ( self.settings.image_name.user_prefix[:max_prefix_length] + '..') if len( self.settings.image_name.user_prefix ) > max_prefix_length else self.settings.image_name.user_prefix preview_string += prefix if self.settings.image_name.include_serial: if preview_string != "": preview_string += "-" preview_string += "00001234" if self.settings.image_name.include_format: if preview_string != "": preview_string += "-" preview_string += "gbrg_1920x1080_15_1" if self.settings.image_name.include_timestamp: if preview_string != "": preview_string += "-" preview_string += "19701230T125503" if self.settings.image_name.include_counter: if preview_string != "": preview_string += "-" preview_string += '{message:0>{fill}}'.format( message=1, fill=self.settings.image_name.counter_size) if preview_string == "": preview_string = "image" preview_string += "." + self.image_type_combobox.currentText() self.image_name_preview.setText(preview_string) def video_name_prefix_changed(self, name: str): """""" self.settings.video_name.user_prefix = self.video_name_prefix.text() self.update_video_name_preview() def video_name_suffix_changed(self, suffix: str): """""" self.update_video_name_preview() def video_name_counter_changed(self, name: str): """""" self.settings.video_name.counter_size = self.video_name_counter_box.value( ) self.update_video_name_preview() def video_name_properties_toggled(self): """""" self.settings.video_name.include_timestamp = self.video_name_timestamp.isChecked( ) self.settings.video_name.include_counter = self.video_name_counter.isChecked( ) self.settings.video_name.include_format = self.video_name_format.isChecked( ) self.settings.video_name.include_serial = self.video_name_serial.isChecked( ) self.update_video_name_preview() def update_video_name_preview(self): preview_string = "" if self.settings.video_name.user_prefix != "": # This is a convenience change to the displayed string. # We only display an amount of max_prefix_length # chars to save screen space max_prefix_length = 15 prefix = ( self.settings.video_name.user_prefix[:max_prefix_length] + '..') if len( self.settings.video_name.user_prefix ) > max_prefix_length else self.settings.video_name.user_prefix preview_string += prefix if self.settings.video_name.include_serial: if preview_string != "": preview_string += "-" preview_string += "00001234" if self.settings.video_name.include_format: if preview_string != "": preview_string += "-" preview_string += "gbrg_1920x1080_15_1" if self.settings.video_name.include_timestamp: if preview_string != "": preview_string += "-" preview_string += "19701230T125503" if self.settings.video_name.include_counter: if preview_string != "": preview_string += "-" preview_string += '{message:0>{fill}}'.format( message=1, fill=self.settings.video_name.counter_size) if preview_string == "": preview_string = "video" preview_string += "." + self.video_type_combobox.currentText() self.video_name_preview.setText(preview_string) def toggle_image_counter_box_availability(self): """""" if self.image_name_counter.isChecked(): self.image_name_counter_box.setEnabled(True) else: self.image_name_counter_box.setEnabled(False) def toggle_video_counter_box_availability(self): """""" if self.video_name_counter.isChecked(): self.video_name_counter_box.setEnabled(True) else: self.video_name_counter_box.setEnabled(False) def set_settings(self, settings: Settings): self.location_edit.setText(settings.get_save_location()) self.image_type_combobox.setCurrentText(settings.get_image_type()) if self.enabled_video: self.video_type_combobox.setCurrentText(settings.get_video_type()) self.device_dialog_checkbox.setChecked( settings.show_device_dialog_on_startup) self.reopen_device_checkbox.setChecked( settings.reopen_device_on_startup) self.use_dutils_checkbox.setChecked(settings.use_dutils) if settings.image_name.include_timestamp: self.image_name_timestamp.blockSignals(True) self.image_name_timestamp.toggle() self.image_name_timestamp.blockSignals(False) if settings.image_name.include_counter: self.image_name_counter.blockSignals(True) self.image_name_counter.toggle() self.image_name_counter.blockSignals(False) self.image_name_counter_box.blockSignals(True) self.image_name_counter_box.setValue(settings.image_name.counter_size) self.image_name_counter_box.blockSignals(False) self.toggle_image_counter_box_availability() if settings.image_name.include_format: self.image_name_format.blockSignals(True) self.image_name_format.toggle() self.image_name_format.blockSignals(False) if settings.image_name.include_serial: self.image_name_serial.blockSignals(True) self.image_name_serial.toggle() self.image_name_serial.blockSignals(False) self.image_name_prefix.blockSignals(True) self.image_name_prefix.setText(settings.image_name.user_prefix) self.image_name_prefix.blockSignals(False) self.update_image_name_preview() if settings.video_name.include_timestamp: self.video_name_timestamp.blockSignals(True) self.video_name_timestamp.toggle() self.video_name_timestamp.blockSignals(False) if settings.video_name.include_counter: self.video_name_counter.blockSignals(True) self.video_name_counter.toggle() self.video_name_counter.blockSignals(False) self.video_name_counter_box.blockSignals(True) self.video_name_counter_box.setValue(settings.video_name.counter_size) self.video_name_counter_box.blockSignals(False) self.toggle_video_counter_box_availability() if settings.video_name.include_format: self.video_name_format.blockSignals(True) self.video_name_format.toggle() self.video_name_format.blockSignals(False) if settings.video_name.include_serial: self.video_name_serial.blockSignals(True) self.video_name_serial.toggle() self.video_name_serial.blockSignals(False) self.video_name_prefix.blockSignals(True) self.video_name_prefix.setText(settings.video_name.user_prefix) self.video_name_prefix.blockSignals(False) self.update_video_name_preview() def save_settings(self): self.settings.save_location = self.location_edit.text() self.settings.image_type = self.image_type_combobox.currentText() if self.enabled_video: self.settings.video_type = self.video_type_combobox.currentText() self.settings.show_device_dialog_on_startup = self.device_dialog_checkbox.isChecked( ) self.settings.reopen_device_on_startup = self.reopen_device_checkbox.isChecked( ) self.settings.use_dutils = self.use_dutils_checkbox.isChecked() self.settings.image_name.include_timestamp = self.image_name_timestamp.isChecked( ) self.settings.image_name.include_counter = self.image_name_counter.isChecked( ) if self.image_name_counter.isChecked(): self.settings.image_name.counter_size = self.image_name_counter_box.value( ) self.settings.image_name.include_format = self.image_name_format.isChecked( ) self.settings.image_name.include_serial = self.image_name_serial.isChecked( ) self.settings.image_name.user_prefix = self.image_name_prefix.text() self.settings.video_name.include_timestamp = self.video_name_timestamp.isChecked( ) self.settings.video_name.include_counter = self.video_name_counter.isChecked( ) if self.video_name_counter.isChecked(): self.settings.video_name.counter_size = self.video_name_counter_box.value( ) self.settings.video_name.include_format = self.video_name_format.isChecked( ) self.settings.video_name.include_serial = self.video_name_serial.isChecked( ) self.settings.video_name.user_prefix = self.video_name_prefix.text() def open_file_dialog(self): fdia = QFileDialog() fdia.setFileMode(QFileDialog.Directory) fdia.setWindowTitle("Select Directory for saving images and videos") if fdia.exec_(): self.location_edit.setText(fdia.selectedFiles()[0]) def get_location(self): return self.location_edit.text() def get_image_format(self): return self.image_type_combobox.currentText() def get_video_format(self): return self.video_type_combobox.currentText() def clicked(self, button): if self.buttons.buttonRole(button) == QDialogButtonBox.ResetRole: self.reset() def reset(self): """""" log.info("reset called") self.settings.reset() self.set_settings(self.settings) @staticmethod def get_options(settings, parent=None): dialog = OptionsDialog(settings, parent) if settings is not None: dialog.set_settings(settings) result = dialog.exec_() if result == QDialog.Accepted: dialog.save_settings() settings.save() return result == QDialog.Accepted
class ApplicationPage(QWidget): """ The GUI for the application page of a project. """ # The page's label. label = "Application Source" # Emitted when the user changes the PyQt version. pyqt_version_changed = pyqtSignal(bool) # Emitted when the user changes the Python target version. python_target_version_changed = pyqtSignal() @property def project(self): """ The project property getter. """ return self._project @project.setter def project(self, value): """ The project property setter. """ if self._project != value: self._project = value self._script_edit.set_project(value) self._package_edit.set_project(value) self._update_page() def __init__(self): """ Initialise the page. """ super().__init__() self._project = None # Create the page's GUI. layout = QGridLayout() form = BetterForm() self._name_edit = QLineEdit( placeholderText="Application name", whatsThis="The name of the application. It will default to " "the base name of the application script without any " "extension.", textEdited=self._name_changed) form.addRow("Name", self._name_edit) self._script_edit = FilenameEditor("Application Script", placeholderText="Application script", whatsThis="The name of the application's optional main script " "file.", textEdited=self._script_changed) form.addRow("Main script file", self._script_edit) self._entry_point_edit = QLineEdit( placeholderText="Entry point in application package", whatsThis="The name of the optional entry point in the " "application's package.", textEdited=self._entry_point_changed) form.addRow("Entry point", self._entry_point_edit) self._sys_path_edit = QLineEdit( placeholderText="Additional sys.path directories", whatsThis="A space separated list of additional directories, " "ZIP files and eggs to add to <tt>sys.path</tt>. Only " "set this if you want to allow external packages to " "be imported.", textEdited=self._sys_path_changed) form.addRow("sys.path", self._sys_path_edit) layout.addLayout(form, 0, 0) options_layout = BetterForm() self._py_version_edit = QComboBox( whatsThis="Select the target Python version.") self._py_version_edit.addItems(get_supported_python_versions()) self._py_version_edit.currentIndexChanged.connect( self._py_version_changed) options_layout.addRow("Target Python version", self._py_version_edit) self._pyqt_version_edit = QComboBox( whatsThis="Select the PyQt version.") self._pyqt_version_edit.addItems(["PyQt4", "PyQt5"]) self._pyqt_version_edit.currentIndexChanged.connect( self._pyqt_version_changed) options_layout.addRow("Target PyQt version", self._pyqt_version_edit) self._console_edit = QCheckBox("Use console (Windows)", whatsThis="Enable console output for Windows applications. " "Console output will be enabled automatically if no " "graphical PyQt modules are used.", stateChanged=self._console_changed) options_layout.addRow(self._console_edit) self._bundle_edit = QCheckBox("Application bundle (OS X)", whatsThis="Build an application bundle on OS X. If it is not " "checked then the application will be built as a " "simple executable.", stateChanged=self._bundle_changed) options_layout.addRow(self._bundle_edit) layout.addLayout(options_layout, 0, 1) self._package_edit = _ApplicationPackageEditor() self._package_edit.package_changed.connect(self._package_changed) package_edit_gb = QGroupBox(self._package_edit.title) package_edit_gb.setLayout(self._package_edit) layout.addWidget(package_edit_gb, 1, 0, 1, 2) layout.setRowStretch(1, 1) self.setLayout(layout) def _update_page(self): """ Update the page using the current project. """ project = self.project self._name_edit.setText(project.application_name) self._script_edit.setText(project.application_script) self._entry_point_edit.setText(project.application_entry_point) self._sys_path_edit.setText(project.sys_path) self._package_edit.configure(project.application_package, project) blocked = self._py_version_edit.blockSignals(True) self._py_version_edit.setCurrentIndex( get_supported_python_version_index( project.python_target_version)) self._py_version_edit.blockSignals(blocked) blocked = self._pyqt_version_edit.blockSignals(True) self._pyqt_version_edit.setCurrentIndex( 1 if project.application_is_pyqt5 else 0) self._pyqt_version_edit.blockSignals(blocked) blocked = self._console_edit.blockSignals(True) self._console_edit.setCheckState( Qt.Checked if project.application_is_console else Qt.Unchecked) self._console_edit.blockSignals(blocked) blocked = self._bundle_edit.blockSignals(True) self._bundle_edit.setCheckState( Qt.Checked if project.application_is_bundle else Qt.Unchecked) self._bundle_edit.blockSignals(blocked) def _py_version_changed(self, idx): """ Invoked when the user changes the Python version number. """ self.project.python_target_version = get_supported_python_version(idx) self.project.modified = True self.python_target_version_changed.emit() def _pyqt_version_changed(self, idx): """ Invoked when the user changes the PyQt version number. """ pyqt5 = (idx == 1) self.project.application_is_pyqt5 = pyqt5 self.project.modified = True self.pyqt_version_changed.emit(pyqt5) def _console_changed(self, state): """ Invoked when the user changes the console state. """ self.project.application_is_console = (state == Qt.Checked) self.project.modified = True def _bundle_changed(self, state): """ Invoked when the user changes the bundle state. """ self.project.application_is_bundle = (state == Qt.Checked) self.project.modified = True def _name_changed(self, value): """ Invoked when the user edits the application name. """ self.project.application_name = value self.project.modified = True def _script_changed(self, value): """ Invoked when the user edits the application script name. """ self.project.application_script = value self.project.modified = True def _entry_point_changed(self, value): """ Invoked when the user edits the entry point. """ self.project.application_entry_point = value self.project.modified = True def _sys_path_changed(self, value): """ Invoked when the user edits the sys.path directories. """ self.project.sys_path = value.strip() self.project.modified = True def _package_changed(self): """ Invoked when the user edits the application package. """ self.project.modified = True
class QtBoolEdit(QWidget): toggledSignal = pyqtSignal(bool) def __init__(self, parent=None): super(QtBoolEdit, self).__init__(parent) self.m_checkBox = QCheckBox(self) self.m_textVisible = True lt = QHBoxLayout() if (QApplication.layoutDirection() == Qt.LeftToRight): lt.setContentsMargins(4, 0, 0, 0) else: lt.setContentsMargins(0, 0, 4, 0) lt.addWidget(self.m_checkBox) self.setLayout(lt) self.m_checkBox.toggled.connect(self.toggledSignal) self.setFocusProxy(self.m_checkBox) self.m_checkBox.setText(self.tr("True")) def textVisible(self): return self.m_textVisible def setTextVisible(self, textVisible): if (self.m_textVisible == textVisible): return self.m_textVisible = textVisible if self.m_textVisible: if self.isChecked(): self.m_checkBox.setText(self.tr("True")) else: self.m_checkBox.setText(self.tr("False")) else: self.m_checkBox.setText('') def checkState(self): return self.m_checkBox.checkState() def setCheckState(self, state): self.m_checkBox.setCheckState(state) def isChecked(self): return self.m_checkBox.isChecked() def setChecked(self, c): self.m_checkBox.setChecked(c) if self.m_textVisible == False: return if self.isChecked(): self.m_checkBox.setText(self.tr("True")) else: self.m_checkBox.setText(self.tr("False")) def blockCheckBoxSignals(self, block): return self.m_checkBox.blockSignals(block) def mousePressEvent(self, event): if (event.buttons() == Qt.LeftButton): self.m_checkBox.click() event.accept() else: super(QtBoolEdit, self).mousePressEvent(event) def paintEvent(self, pt_QPaintEvent): opt = QStyleOption() opt.initFrom(self) p = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self)
class ConfigurationWidget(QWidget): # signals get constructed before init method because they hack things state_changed = pyqtSignal() def __init__(self, sample_tree): super().__init__() self.current_config = None self.sample_tree = sample_tree self.sample_tree.tree.currentItemChanged.connect( self.on_selected_sample_change) self.exclude_spot_checkbox = QCheckBox("Exclude spot") self.exclude_spot_checkbox.stateChanged.connect(self.on_state_changed) self.exclude_spot_checkbox.stateChanged.connect(self.on_spot_exclusion) self.sbm_check_box = QCheckBox("Normalise to sbm") self.sbm_check_box.stateChanged.connect(self.on_state_changed) self.background_button_group = QButtonGroup() self.buttons = [] for method in BackgroundCorrection: button = QRadioButton(method.value) button.method = method button.clicked.connect(self.on_state_changed) self.background_button_group.addButton(button) self.buttons.append(button) layout = QHBoxLayout() # The exclude spot widget is displayed elsewhere layout.addWidget(self.sbm_check_box) for button in self.buttons: layout.addWidget(button) self.setLayout(layout) def set_state(self, config: Configuration): self.blockSignals(True) for button in self.buttons: button.setChecked(button.method == config.background_method) self.sbm_check_box.setChecked(config.normalise_by_sbm) self.update_exclude_spot_checkbox(config) self.blockSignals(False) self.on_state_changed() def update_exclude_spot_checkbox(self, config=None): if config is None: config = self.current_config current_spot = self.sample_tree.current_spot() if current_spot is None: excluded = False enabled = False else: excluded = current_spot in config.excluded_spots enabled = True self.exclude_spot_checkbox.setEnabled(enabled) self.exclude_spot_checkbox.setChecked(excluded) def calculate_current_excluded_spots(self): config = self.current_config if config is None: return frozenset() previously_excluded_spots = config.excluded_spots current_spot = self.sample_tree.current_spot() if current_spot is None: return previously_excluded_spots is_excluded = self.exclude_spot_checkbox.isChecked() was_excluded = current_spot in previously_excluded_spots if is_excluded == was_excluded: return previously_excluded_spots excluded_spots = set(previously_excluded_spots) if is_excluded: excluded_spots.add(current_spot) else: excluded_spots.remove(current_spot) return frozenset(excluded_spots) ########### # Actions # ########### def on_selected_sample_change(self, current_tree_item, previous_tree_item): self.blockSignals(True) self.exclude_spot_checkbox.blockSignals(True) self.update_exclude_spot_checkbox() self.blockSignals(False) self.exclude_spot_checkbox.blockSignals(False) def on_state_changed(self): sbm_normalised = self.sbm_check_box.isChecked() background_method = self.background_button_group.checkedButton().method excluded_spots = self.calculate_current_excluded_spots() self.current_config = Configuration(sbm_normalised, background_method, excluded_spots) self.state_changed.emit() def on_spot_exclusion(self): is_flagged = self.exclude_spot_checkbox.isChecked() self.sample_tree.highlight_spot(is_flagged)
class LaserRangeFinderV2(COMCUPluginBase): def __init__(self, *args): super().__init__(BrickletLaserRangeFinderV2, *args) self.lrf = self.device self.cbe_distance = CallbackEmulator(self.lrf.get_distance, None, self.cb_distance, self.increase_error_count) self.cbe_velocity = CallbackEmulator(self.lrf.get_velocity, None, self.cb_velocity, self.increase_error_count) self.current_distance = CurveValueWrapper() # int, cm self.current_velocity = CurveValueWrapper() # float, m/s plots_distance = [('Distance', Qt.red, self.current_distance, format_distance)] plots_velocity = [('Velocity', Qt.red, self.current_velocity, '{:.2f} m/s'.format)] self.plot_widget_distance = PlotWidget('Distance [cm]', plots_distance, y_resolution=1.0) self.plot_widget_velocity = PlotWidget('Velocity [m/s]', plots_velocity, y_resolution=0.01) self.label_average_distance = QLabel('Moving Average for Distance:') self.spin_average_distance = QSpinBox() self.spin_average_distance.setMinimum(0) self.spin_average_distance.setMaximum(255) self.spin_average_distance.setSingleStep(1) self.spin_average_distance.setValue(10) self.spin_average_distance.editingFinished.connect( self.spin_average_finished) self.label_average_velocity = QLabel('Moving Average for Velocity:') self.spin_average_velocity = QSpinBox() self.spin_average_velocity.setMinimum(0) self.spin_average_velocity.setMaximum(255) self.spin_average_velocity.setSingleStep(1) self.spin_average_velocity.setValue(10) self.spin_average_velocity.editingFinished.connect( self.spin_average_finished) self.enable_laser = QCheckBox("Enable Laser") self.enable_laser.stateChanged.connect(self.enable_laser_changed) self.label_acquisition_count = QLabel('Acquisition Count:') self.spin_acquisition_count = QSpinBox() self.spin_acquisition_count.setMinimum(1) self.spin_acquisition_count.setMaximum(255) self.spin_acquisition_count.setSingleStep(1) self.spin_acquisition_count.setValue(128) self.enable_qick_termination = QCheckBox("Quick Termination") self.label_threshold = QLabel('Threshold:') self.threshold = QCheckBox("Automatic Threshold") self.spin_threshold = QSpinBox() self.spin_threshold.setMinimum(1) self.spin_threshold.setMaximum(255) self.spin_threshold.setSingleStep(1) self.spin_threshold.setValue(1) self.label_frequency = QLabel('Frequency [Hz]:') self.frequency = QCheckBox( "Automatic Frequency (Disable for Velocity)") self.spin_frequency = QSpinBox() self.spin_frequency.setMinimum(10) self.spin_frequency.setMaximum(500) self.spin_frequency.setSingleStep(1) self.spin_frequency.setValue(10) self.spin_acquisition_count.editingFinished.connect( self.configuration_changed) self.enable_qick_termination.stateChanged.connect( self.configuration_changed) self.spin_threshold.editingFinished.connect(self.configuration_changed) self.threshold.stateChanged.connect(self.configuration_changed) self.spin_frequency.editingFinished.connect(self.configuration_changed) self.frequency.stateChanged.connect(self.configuration_changed) layout_h1 = QHBoxLayout() layout_h1.addWidget(self.plot_widget_distance) layout_h1.addWidget(self.plot_widget_velocity) layout_h2 = QHBoxLayout() layout_h2.addWidget(self.label_average_distance) layout_h2.addWidget(self.spin_average_distance) layout_h2.addWidget(self.label_average_velocity) layout_h2.addWidget(self.spin_average_velocity) layout_h2.addStretch() layout_h2.addWidget(self.enable_laser) layout_h3 = QHBoxLayout() layout_h3.addWidget(self.label_frequency) layout_h3.addWidget(self.spin_frequency) layout_h3.addWidget(self.frequency) layout_h3.addStretch() layout_h3.addWidget(self.enable_qick_termination) layout_h4 = QHBoxLayout() layout_h4.addWidget(self.label_threshold) layout_h4.addWidget(self.spin_threshold) layout_h4.addWidget(self.threshold) layout_h4.addStretch() layout_h4.addWidget(self.label_acquisition_count) layout_h4.addWidget(self.spin_acquisition_count) self.widgets_distance = [ self.plot_widget_distance, self.spin_average_distance, self.label_average_distance ] self.widgets_velocity = [ self.plot_widget_velocity, self.spin_average_velocity, self.label_average_velocity ] line = QFrame() line.setObjectName("line") line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addLayout(layout_h1) layout.addWidget(line) layout.addLayout(layout_h2) layout.addLayout(layout_h3) layout.addLayout(layout_h4) def start(self): async_call(self.lrf.get_configuration, None, self.get_configuration_async, self.increase_error_count) async_call(self.lrf.get_enable, None, self.enable_laser.setChecked, self.increase_error_count) async_call(self.lrf.get_moving_average, None, self.get_moving_average_async, self.increase_error_count) self.cbe_distance.set_period(25) self.cbe_velocity.set_period(25) self.plot_widget_distance.stop = False self.plot_widget_velocity.stop = False def stop(self): self.cbe_distance.set_period(0) self.cbe_velocity.set_period(0) self.plot_widget_distance.stop = True self.plot_widget_velocity.stop = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletLaserRangeFinderV2.DEVICE_IDENTIFIER def enable_laser_changed(self, state): self.lrf.set_enable(state == Qt.Checked) def cb_distance(self, distance): self.current_distance.value = distance def cb_velocity(self, velocity): self.current_velocity.value = velocity / 100.0 def configuration_changed(self): acquisition_count = self.spin_acquisition_count.value() enable_quick_termination = self.enable_qick_termination.isChecked() if self.threshold.isChecked(): threshold = 0 else: threshold = self.spin_threshold.value() if self.frequency.isChecked(): frequency = 0 for w in self.widgets_velocity: w.hide() else: frequency = self.spin_frequency.value() for w in self.widgets_velocity: w.show() self.spin_threshold.setDisabled(threshold == 0) self.spin_frequency.setDisabled(frequency == 0) self.lrf.set_configuration(acquisition_count, enable_quick_termination, threshold, frequency) def get_configuration_async(self, conf): self.spin_acquisition_count.blockSignals(True) self.spin_acquisition_count.setValue(conf.acquisition_count) self.spin_acquisition_count.blockSignals(False) self.enable_qick_termination.blockSignals(True) self.enable_qick_termination.setChecked(conf.enable_quick_termination) self.enable_qick_termination.blockSignals(False) self.spin_threshold.blockSignals(True) self.spin_threshold.setValue(conf.threshold_value) self.spin_threshold.setDisabled(conf.threshold_value == 0) self.spin_threshold.blockSignals(False) self.spin_frequency.blockSignals(True) self.spin_frequency.setValue(conf.measurement_frequency) self.spin_frequency.setDisabled(conf.measurement_frequency == 0) self.spin_frequency.blockSignals(False) self.threshold.blockSignals(True) self.threshold.setChecked(conf.threshold_value == 0) self.threshold.blockSignals(False) self.frequency.blockSignals(True) self.frequency.setChecked(conf.measurement_frequency == 0) self.frequency.blockSignals(False) self.configuration_changed() def get_moving_average_async(self, avg): self.spin_average_distance.setValue(avg.distance_average_length) self.spin_average_velocity.setValue(avg.velocity_average_length) def spin_average_finished(self): self.lrf.set_moving_average(self.spin_average_distance.value(), self.spin_average_velocity.value())
class StandardLibraryPage(QSplitter): """ The GUI for the standard library page of a project. """ # The page's label. label = "Standard Library" @property def project(self): """ The project property getter. """ return self._project @project.setter def project(self, value): """ The project property setter. """ if self._project != value: self._project = value self._update_page() def __init__(self): """ Initialise the page. """ super().__init__() self._project = None # Create the page's GUI. stdlib_pane = QWidget() stdlib_layout = QVBoxLayout() self._stdlib_edit = QTreeWidget( whatsThis="This shows the packages and modules in the target " "Python version's standard library. Check those " "packages and modules that are explicitly imported by " "the application. A module will be partially checked " "(and automatically included) if another module " "requires it.") self._stdlib_edit.setHeaderLabels(["Package"]) self._stdlib_edit.itemChanged.connect(self._module_changed) stdlib_layout.addWidget(self._stdlib_edit) stdlib_pane.setLayout(stdlib_layout) self.addWidget(stdlib_pane) extlib_pane = QWidget() extlib_layout = QVBoxLayout() extlib_sublayout = QFormLayout() self._version_edit = QComboBox( whatsThis="Select the target Python version. This will cause " "the standard library package hierarchy to be " "updated.") self._version_edit.addItems(get_supported_python_versions()) self._version_edit.currentIndexChanged.connect(self._version_changed) extlib_sublayout.addRow("Target Python version", self._version_edit) self._ssl_edit = QCheckBox( whatsThis="Enable SSL for the standard library modules " "that have optional support for it.", stateChanged=self._ssl_changed) extlib_sublayout.addRow("Enable optional SSL support", self._ssl_edit) extlib_layout.addLayout(extlib_sublayout) plat_gb = QGroupBox("Use standard Python shared library") plat_gb_layout = QVBoxLayout() self._platform_buttons = [] for scope, plat, subscopes in PLATFORM_SCOPES: plat_cb = QCheckBox(plat, whatsThis="Enable the use of the standard Python shared " "library on {0} rather than a statically compiled " "library.".format(plat), stateChanged=self._platforms_changed) plat_cb._scope = scope plat_gb_layout.addWidget(plat_cb) self._platform_buttons.append(plat_cb) plat_gb.setLayout(plat_gb_layout) extlib_layout.addWidget(plat_gb) self._extlib_edit = QTreeView( whatsThis="This is the list of external libraries that must " "be linked with the application. A library will only " "be enabled if a module in the standard library uses " "it. Double-click in the <b>DEFINES</b>, " "<b>INCLUDEPATH</b> and <b>LIBS</b> columns to modify " "the corresponding <tt>qmake</tt> variable as " "required. Values may be prefixed by a platform " "specific <tt>qmake</tt> scope.") self._extlib_edit.setRootIsDecorated(False) self._extlib_edit.setEditTriggers( QTreeView.DoubleClicked|QTreeView.SelectedClicked| QTreeView.EditKeyPressed) model = QStandardItemModel(self._extlib_edit) model.setHorizontalHeaderLabels( ("External Library", 'DEFINES', 'INCLUDEPATH', 'LIBS')) model.itemChanged.connect(self._extlib_changed) for extlib in external_libraries_metadata: name_itm = QStandardItem(extlib.user_name) extlib._items = (name_itm, QStandardItem(), QStandardItem(), QStandardItem()) model.appendRow(extlib._items) self._extlib_edit.setModel(model) for col in range(3): self._extlib_edit.resizeColumnToContents(col) extlib_layout.addWidget(self._extlib_edit) self._ignore_extlib_changes = False extlib_pane.setLayout(extlib_layout) self.addWidget(extlib_pane) def _update_page(self): """ Update the page using the current project. """ project = self.project blocked = self._version_edit.blockSignals(True) self._version_edit.setCurrentIndex( get_supported_python_version_index( project.python_target_version)) self._version_edit.blockSignals(blocked) blocked = self._ssl_edit.blockSignals(True) self._ssl_edit.setCheckState( Qt.Checked if project.python_ssl else Qt.Unchecked) self._ssl_edit.blockSignals(blocked) for plat in self._platform_buttons: blocked = plat.blockSignals(True) plat.setCheckState( Qt.Checked if plat._scope in project.python_use_platform else Qt.Unchecked) plat.blockSignals(blocked) self._update_extlib_editor() self._update_stdlib_editor() def _update_stdlib_editor(self): """ Update the standard library module editor. """ project = self.project editor = self._stdlib_edit metadata = get_python_metadata(project.python_target_version) blocked = editor.blockSignals(True) editor.clear() def add_module(name, module, parent): itm = QTreeWidgetItem(parent, name.split('.')[-1:]) itm.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable) itm._name = name # Handle any sub-modules. if module.modules is not None: for submodule_name in module.modules: # We assume that a missing sub-module is because it is not # in the current version rather than bad meta-data. submodule = metadata.get(submodule_name) if submodule is not None: add_module(submodule_name, submodule, itm) for name, module in metadata.items(): if not module.internal and '.' not in name: add_module(name, module, editor) editor.sortItems(0, Qt.AscendingOrder) editor.blockSignals(blocked) self._set_dependencies() def _set_dependencies(self): """ Set the dependency information. """ project = self.project editor = self._stdlib_edit required_modules, required_libraries = project.get_stdlib_requirements() blocked = editor.blockSignals(True) it = QTreeWidgetItemIterator(editor) itm = it.value() while itm is not None: external = required_modules.get(itm._name) expanded = False if external is None: state = Qt.Unchecked elif external: state = Qt.Checked expanded = True else: state = Qt.PartiallyChecked itm.setCheckState(0, state) # Make sure every explicitly checked item is visible. if expanded: parent = itm.parent() while parent is not None: parent.setExpanded(True) parent = parent.parent() it += 1 itm = it.value() editor.blockSignals(blocked) model = self._extlib_edit.model() # Note that we can't simply block the model's signals as this would # interfere with the model/view interactions. self._ignore_extlib_changes = True for extlib in external_libraries_metadata: if extlib.name in required_libraries: for idx, itm in enumerate(extlib._items): itm.setFlags( Qt.ItemIsEnabled|Qt.ItemIsEditable if idx != 0 else Qt.ItemIsEnabled) else: for itm in extlib._items: itm.setFlags(Qt.NoItemFlags) self._ignore_extlib_changes = False def _update_extlib_editor(self): """ Update the external library editor. """ project = self.project model = self._extlib_edit.model() blocked = model.blockSignals(True) for extlib in external_libraries_metadata: _, defs, incp, libs = extlib._items for prj_extlib in project.external_libraries: if prj_extlib.name == extlib.name: defs.setText(prj_extlib.defines) incp.setText(prj_extlib.includepath) libs.setText(prj_extlib.libs) break else: defs.setText('') incp.setText('') libs.setText(extlib.libs) model.blockSignals(blocked) def _version_changed(self, idx): """ Invoked when the target Python version changes. """ project = self.project project.python_target_version = get_supported_python_version(idx) self._update_page() project.modified = True def _ssl_changed(self, state): """ Invoked when the SSL support changes. """ project = self.project project.python_ssl = (state == Qt.Checked) self._set_dependencies() project.modified = True def _platforms_changed(self, state): """ Invoked when the platforms change. """ project = self._project project.python_use_platform = [] for plat in self._platform_buttons: if plat.checkState() == Qt.Checked: project.python_use_platform.append(plat._scope) project.modified = True def _module_changed(self, itm, col): """ Invoked when a standard library module has changed. """ project = self._project name = itm._name if name in project.standard_library: project.standard_library.remove(name) else: project.standard_library.append(name) self._set_dependencies() project.modified = True def _extlib_changed(self, itm): """ Invoked when an external library has changed. """ if self._ignore_extlib_changes: return self._ignore_extlib_changes = True project = self.project idx = self._extlib_edit.model().indexFromItem(itm) extlib = external_libraries_metadata[idx.row()] col = idx.column() # Get the project entry, creating it if necessary. for prj_extlib in project.external_libraries: if prj_extlib.name == extlib.name: break else: prj_extlib = ExternalLibrary(extlib.name, '', '', extlib.libs) project.external_libraries.append(prj_extlib) # Update the project. text = itm.text().strip() if col == 1: prj_extlib.defines = text elif col == 2: prj_extlib.includepath = text elif col == 3: if text == '': text = extlib.libs itm.setText(text) prj_extlib.libs = text # If the project entry corresponds to the default then remove it. if prj_extlib.defines == '' and prj_extlib.includepath == '' and prj_extlib.libs == extlib.libs: project.external_libraries.remove(prj_extlib) project.modified = True self._ignore_extlib_changes = False
class DirViewWidget(QWidget): loadFiles = pyqtSignal(object, list, bool, name='loadFiles') removeFolders = pyqtSignal(list, bool, name='removeFolders') def __init__(self, parent=None, subfolders=False, status=None): super(DirViewWidget, self).__init__(parent) self._status = status self.dirview = DirView(self, subfolders, status) self.dirview.loadFiles.connect(self.loadFiles) self.dirview.removeFolders.connect(self.removeFolders) self.receives = [ ('dirschanged', self.dirview.selectDirs), ('dirsmoved', self.dirview.dirMoved), ] self.emits = ['loadFiles', 'removeFolders'] self.subfolderCheck = QCheckBox(translate('Dirview', 'Subfolders'), self) self.subfolderCheck.stateChanged.connect(self.setSubFolders) layout = QVBoxLayout() layout.addWidget(self.dirview, 1) layout.addWidget(self.subfolderCheck, 0) self.setLayout(layout) def loadSettings(self): self.dirview.loadSettings() self.subfolderCheck.blockSignals(True) if load_gen_settings([('Su&bfolders', True)])[0][1]: self.subfolderCheck.setChecked(True) else: self.subfolderCheck.setChecked(False) self.subfolderCheck.blockSignals(False) def saveSettings(self): self.dirview.saveSettings() def setSubFolders(self, check): if check == Qt.CheckState.Checked: value = True else: value = False self.dirview.subfolders = value save_gen_settings({'Su&bfolders': value}) self._status['table'].subFolders = value def _focusDir(self, dir_path): """Focuses the Filesystem component on the given path """ self.parentWidget().show() self.dirview.focusDir(dir_path) def focusCurrentFileParent(parent=None): """Focuses the Filesystem component on the parent folder of the currently selected file """ files = parent._status['selectedfiles'] if not files: return dir_path = files[0].dirpath parent._focusDir(dir_path)
class DataViewer(QTableView): FNAME_TEMPLATE = 'DataViewer.{0!s}' def __init__(self, parent=None, **kwargs): super().__init__(parent) self.par_ = parent self.grid = False self.data = pd.DataFrame((0, 0)) self.col_idx = self.data.columns[0] self.col_names = [] self.language = kwargs['language'] self.show_data() if 'log' in kwargs: self.log = kwargs['log'] else: self.log = logger.Logger('data_viewer') self.canvas_controller = kwargs['canvas_controller'] self.log.write_log( app_defs.INFO_MSG, '{0!s} executed successfully'.format( self.FNAME_TEMPLATE.format('init'))) def create_dock(self): main_tools_dock = QDockWidget(str_defs.DOCK_TITLE[self.language], self) dock_tabs = QTabWidget() dock_tabs.addTab(self._create_tab_overall(), str_defs.OVRALL[self.language]) dock_tabs.addTab(self._create_tab_x(), 'X') dock_tabs.addTab(self._create_tab_y(), 'Y') main_tools_dock.setWidget(dock_tabs) return main_tools_dock def _create_tab_overall(self): tab = QWidget() layout = QFormLayout() # set grid for all plots self.set_grid_box = QCheckBox(str_defs.GRID[self.language], self) self.set_grid_box.setChecked(self.grid) self.set_grid_box.stateChanged.connect(self.set_grid) # set plot type self.plot_type_box = QComboBox() self.plot_type_box.addItems(str_defs.PLOT_TYPES[self.language]) self.plot_type_box.currentIndexChanged.connect(self.set_plot_type) # sort data sort_layout = QVBoxLayout() self.sort_items = QComboBox() self.sort_items.addItems(self.col_names) sort_cont = QGroupBox(str_defs.SORT_TOOL[self.language]) sort_btn = QPushButton() sort_btn.setText(str_defs.SORT[self.language]) sort_btn.clicked.connect(self.sort_values) sort_layout.addWidget(self.sort_items) sort_layout.addWidget(sort_btn) sort_cont.setLayout(sort_layout) # show histogram show_hist_btn = QPushButton('Histogram') show_hist_btn.clicked.connect(self.canvas_controller.show_hist) text_manipulators = self._title_manipulators() layout.addWidget(self.plot_type_box) layout.addWidget(self.set_grid_box) layout.addWidget(sort_cont) layout.addWidget(show_hist_btn) layout.addWidget(text_manipulators) tab.setLayout(layout) return tab def _title_manipulators(self): # add texts text_manipulators = QGroupBox(str_defs.TEXT_MANIPULTORS[self.language]) text_manipulators_layout = QFormLayout() # add title title = QGroupBox(str_defs.TITLE_ADD[self.language]) title_layout = QFormLayout() self.title_input = QLineEdit() title_set = QPushButton(str_defs.SET_STR[self.language]) title_set.clicked.connect(self.set_title) title_layout.addRow(self.title_input) title_layout.addRow(title_set) title.setLayout(title_layout) # add x labels x_axis = QGroupBox(str_defs.X_AXIS_LABELS[self.language]) x_axis_layout = QFormLayout() x_axis_items = QComboBox() x_axis_items.addItems(self.col_names) x_axis_layout.addRow(x_axis_items) x_axis.setLayout(x_axis_layout) # texts layout text_manipulators_layout.addRow(title) text_manipulators_layout.addRow(x_axis) text_manipulators.setLayout(text_manipulators_layout) return text_manipulators def _create_tab_y(self): tab_y = QWidget() layout = QFormLayout() self.y_column_types = QComboBox() self.y_column_types.currentIndexChanged.connect(self.set_y) layout.addWidget(self.y_column_types) tab_y.setLayout(layout) return tab_y def _create_tab_x(self): tab_x = QWidget() layout = QFormLayout() self.x_column_types = QComboBox() self.x_column_types.currentIndexChanged.connect(self.set_x) layout.addWidget(self.x_column_types) tab_x.setLayout(layout) return tab_x def set_data(self, data): fname = self.FNAME_TEMPLATE.format('set_data') self.log.write_log(app_defs.INFO_MSG, '{0!s}: Setting data into DataFrame'.format(fname)) self.data = pd.DataFrame() self.data = data self.col_names = ['index'] + list(self.data.columns.values) self.col_names = [str(item).strip() for item in self.col_names] self.y_column_types.clear() self.y_column_types.addItems(self.col_names) self.x_column_types.clear() self.x_column_types.addItems(self.col_names) self.sort_items.clear() self.sort_items.addItems(self.col_names) self.show_data() def get_data(self): return self.data def sort_values(self): fname = self.FNAME_TEMPLATE.format('sort_values') sort_by = self.col_names[self.sort_items.currentIndex()] try: if sort_by != 'index': self.data.sort_values( by=self.data.columns[self.sort_items.currentIndex() - 1], inplace=True, ignore_index=True) self.log.write_log( app_defs.INFO_MSG, '%s: all values in dataframe are sorted by {%s}' % (fname, self.data.columns[self.sort_items.currentIndex() - 1])) else: self.data.sort_index(inplace=True) self.log.write_log(app_defs.INFO_MSG, '%s: Data sorted by index' % fname) except Exception as e: self.log.write_log( app_defs.WARNING_MSG, '%s: unable to sort values, exception = {%s}' % (fname, e)) self.show_data() self.canvas_controller.upload_data(self.data) def show_data(self): model = TableModel(data=self.data) self.setModel(model) def set_y(self): y_pos = self.col_names[self.y_column_types.currentIndex()] if y_pos != 'index': self.col_idx = self.y_column_types.currentIndex() - 1 else: self.col_idx = -1 self.canvas_controller.set_values('y', self.col_idx) def set_x(self): x_pos = self.col_names[self.x_column_types.currentIndex()] if x_pos != 'index': col_idx = self.x_column_types.currentIndex() - 1 else: col_idx = -1 self.canvas_controller.set_values('x', col_idx) def set_plot_type(self, plot_type): # filtering data for pie chart (negative values are not possible) if plot_type + 1 == app_defs.PlotTypes.PIE_CHART: ret = data_utils.filter_negative_numbers(self.data, self.col_idx) ret = data_utils.dataframe_to_radius(ret, self.col_idx) self.set_data(ret) self.show_data() self.canvas_controller.change_plot_type(plot_type + 1) self.plot_type_box.blockSignals(True) self.plot_type_box.setCurrentIndex(plot_type) self.plot_type_box.blockSignals(False) self.plot_type_box.blockSignals(True) self.plot_type_box.setCurrentIndex(plot_type) self.plot_type_box.blockSignals(False) def set_grid(self): grid = self.canvas_controller.grid self.log.write_log(app_defs.INFO_MSG, 'grid set to {0}'.format(not grid)) self.canvas_controller.set_grid() self.set_grid_box.blockSignals(True) self.set_grid_box.setChecked(not grid) self.set_grid_box.blockSignals(False) self.data_viewer.upd_grid() def set_title(self): self.log.write_log( app_defs.INFO_MSG, 'Set plot title: {0}'.format(self.title_input.text())) self.par_.set_status('Set plot title: {0}'.format( self.title_input.text())) self.canvas_controller.set_title(self.title_input.text())
class QuadInstanceItemWidget(QFrame): quadSelected = pyqtSignal() def __init__(self, quad): QWidget.__init__(self) self.setMouseTracking(True) self.quad = quad self.nameLabel = QLabel( f'<b>{quad[ID]}</b><br><span style="color:grey;">' f'{quad[PERCENT_COVERED]} % covered</span>') self.iconLabel = QLabel() pixmap = QPixmap(PLACEHOLDER_THUMB, 'SVG') thumb = pixmap.scaled(48, 48, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.checkBox = QCheckBox("") self.checkBox.stateChanged.connect(self.check_box_state_changed) layout = QHBoxLayout() layout.setMargin(0) layout.addWidget(self.checkBox) vlayout = QVBoxLayout() vlayout.setMargin(0) vlayout.addWidget(self.iconLabel) self.iconWidget = QWidget() self.iconWidget.setFixedSize(48, 48) self.iconWidget.setLayout(vlayout) layout.addWidget(self.iconWidget) layout.addWidget(self.nameLabel) layout.addStretch() self.setLayout(layout) download_thumbnail(quad[LINKS][THUMBNAIL], self) self.footprint = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.footprint.setFillColor(QUADS_AOI_COLOR) self.footprint.setStrokeColor(QUADS_AOI_COLOR) self.footprint.setWidth(2) self.footprintfill = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.footprintfill.setFillColor(QUADS_AOI_BODY_COLOR) self.footprintfill.setWidth(0) self.update_footprint_brush() self.hide_solid_interior() self.show_footprint() self.setStyleSheet( "QuadInstanceItemWidget{border: 2px solid transparent;}") def set_thumbnail(self, img): pixmap = QPixmap(img) thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.iconLabel.setStyleSheet("") def check_box_state_changed(self): self.update_footprint_brush() self.quadSelected.emit() def show_footprint(self): coords = self.quad[BBOX] extent = qgsrectangle_for_canvas_from_4326_bbox_coords(coords) self.geom = QgsGeometry.fromRect(extent) self.footprint.setToGeometry(self.geom) self.footprintfill.setToGeometry(self.geom) def hide_footprint(self): self.footprint.reset(QgsWkbTypes.PolygonGeometry) self.footprintfill.reset(QgsWkbTypes.PolygonGeometry) def show_solid_interior(self): self.footprintfill.setBrushStyle(Qt.SolidPattern) self.footprintfill.updateCanvas() def hide_solid_interior(self): self.footprintfill.setBrushStyle(Qt.NoBrush) self.footprintfill.updateCanvas() def update_footprint_brush(self): self.footprint.setBrushStyle( Qt.BDiagPattern if self.checkBox.isChecked() else Qt.NoBrush) self.footprint.updateCanvas() def remove_footprint(self): iface.mapCanvas().scene().removeItem(self.footprint) iface.mapCanvas().scene().removeItem(self.footprintfill) def isSelected(self): return self.checkBox.isChecked() def setChecked(self, checked, emit=True): if not emit: self.checkBox.blockSignals(True) self.checkBox.setChecked(checked) if not emit: self.update_footprint_brush() self.checkBox.blockSignals(False) def enterEvent(self, event): self.setStyleSheet( "QuadInstanceItemWidget{border: 2px solid rgb(157, 165, 0);}") self.show_solid_interior() def leaveEvent(self, event): self.setStyleSheet( "QuadInstanceItemWidget{border: 2px solid transparent;}") self.hide_solid_interior()
class QtBoolEdit(QWidget): toggledSignal = pyqtSignal(bool) def __init__(self,parent=None): super(QtBoolEdit, self).__init__(parent) self.m_checkBox = QCheckBox(self) self.m_textVisible = True lt = QHBoxLayout() if (QApplication.layoutDirection() == Qt.LeftToRight): lt.setContentsMargins(4, 0, 0, 0) else: lt.setContentsMargins(0, 0, 4, 0) lt.addWidget(self.m_checkBox) self.setLayout(lt) self.m_checkBox.toggled.connect(self.toggledSignal) self.setFocusProxy(self.m_checkBox) self.m_checkBox.setText(self.tr("True")) def textVisible(self): return self.m_textVisible def setTextVisible(self,textVisible): if (self.m_textVisible == textVisible): return self.m_textVisible = textVisible if self.m_textVisible: if self.isChecked(): self.m_checkBox.setText(self.tr("True")) else: self.m_checkBox.setText(self.tr("False")) else: self.m_checkBox.setText('') def checkState(self): return self.m_checkBox.checkState() def setCheckState(self,state): self.m_checkBox.setCheckState(state) def isChecked(self): return self.m_checkBox.isChecked() def setChecked(self,c): self.m_checkBox.setChecked(c) if self.m_textVisible==False: return if self.isChecked(): self.m_checkBox.setText(self.tr("True")) else: self.m_checkBox.setText(self.tr("False")) def blockCheckBoxSignals(self,block): return self.m_checkBox.blockSignals(block) def mousePressEvent(self, event): if (event.buttons() == Qt.LeftButton): self.m_checkBox.click() event.accept() else: super(QtBoolEdit, self).mousePressEvent(event) def paintEvent(self, pt_QPaintEvent): opt = QStyleOption() opt.initFrom(self) p = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self)
class MotorizedLinearPoti(COMCUPluginBase): def __init__(self, *args): super().__init__(BrickletMotorizedLinearPoti, *args) self.mp = self.device self.cbe_position = CallbackEmulator(self.mp.get_position, None, self.cb_position, self.increase_error_count) self.current_position = CurveValueWrapper() self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, 100) self.slider.setMinimumWidth(200) self.slider.setEnabled(False) plots = [('Potentiometer Position', Qt.red, self.current_position, str) ] self.plot_widget = PlotWidget('Position', plots, extra_key_widgets=[self.slider], update_interval=0.025, y_resolution=1.0) self.motor_slider = QSlider(Qt.Horizontal) self.motor_slider.setRange(0, 100) self.motor_slider.valueChanged.connect(self.motor_slider_value_changed) self.motor_hold_position = QCheckBox("Hold Position") self.motor_drive_mode = QComboBox() self.motor_drive_mode.addItem('Fast') self.motor_drive_mode.addItem('Smooth') def get_motor_slider_value(): return self.motor_slider.value() self.motor_hold_position.stateChanged.connect( lambda x: self.motor_slider_value_changed(get_motor_slider_value() )) self.motor_drive_mode.currentIndexChanged.connect( lambda x: self.motor_slider_value_changed(get_motor_slider_value() )) self.motor_position_label = MotorPositionLabel( 'Motor Target Position:') hlayout = QHBoxLayout() hlayout.addWidget(self.motor_position_label) hlayout.addWidget(self.motor_slider) hlayout.addWidget(self.motor_drive_mode) hlayout.addWidget(self.motor_hold_position) line = QFrame() line.setObjectName("line") line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addWidget(self.plot_widget) layout.addWidget(line) layout.addLayout(hlayout) def start(self): async_call(self.mp.get_motor_position, None, self.get_motor_position_async, self.increase_error_count) self.cbe_position.set_period(25) self.plot_widget.stop = False def stop(self): self.cbe_position.set_period(0) self.plot_widget.stop = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletMotorizedLinearPoti.DEVICE_IDENTIFIER def cb_position(self, position): self.current_position.value = position self.slider.setValue(position) def get_motor_position_async(self, motor): self.motor_slider.blockSignals(True) self.motor_hold_position.blockSignals(True) self.motor_drive_mode.blockSignals(True) self.motor_hold_position.setChecked(motor.hold_position) self.motor_drive_mode.setCurrentIndex(motor.drive_mode) self.motor_position_label.setText(str(motor.position)) self.motor_slider.setValue(motor.position) self.motor_slider.blockSignals(False) self.motor_hold_position.blockSignals(False) self.motor_drive_mode.blockSignals(False) def motor_slider_value_changed(self, position): self.motor_position_label.setText(str(position)) self.mp.set_motor_position(self.motor_slider.value(), self.motor_drive_mode.currentIndex(), self.motor_hold_position.isChecked())
class OptionsDialog(QDialog): def __init__(self, setting: Settings, have_dutils, parent=None): super(OptionsDialog, self).__init__(parent) self.settings = setting self.enabled_video = True # temporary toggle to disable video features as they do not exist self.enabled_logging = True self.enabled_keybindings = True self.enabled_dutils = have_dutils self.setWindowTitle("Tcam-Capture Options") self.layout = QVBoxLayout(self) self.setLayout(self.layout) self.tabs = QTabWidget() self.general_widget = QWidget() self.keybindings_widget = QWidget() self.logging_widget = QWidget() self.saving_widget = QWidget() self._setup_general_ui() self.tabs.addTab(self.general_widget, "General") if self.enabled_keybindings: self._setup_keybindings_ui() self.tabs.addTab(self.keybindings_widget, "Keybindings") self._setup_saving_ui() self.tabs.addTab(self.saving_widget, "Image/Video") self.layout.addWidget(self.tabs) # OK and Cancel buttons self.buttons = QDialogButtonBox( QDialogButtonBox.Reset | QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.layout.addWidget(self.buttons) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) self.buttons.clicked.connect(self.clicked) def _setup_general_ui(self): """ Create everything related to the general tab """ layout = QFormLayout() layout.setSpacing(20) layout.setVerticalSpacing(20) self.device_dialog_checkbox = QCheckBox(self) device_dialog_label = QLabel("Open device dialog on start:") layout.addRow(device_dialog_label, self.device_dialog_checkbox) self.reopen_device_checkbox = QCheckBox(self) reopen_device_label = QLabel("Reopen device on start(ignores device dialog):", self) layout.addRow(reopen_device_label, self.reopen_device_checkbox) self.use_dutils_checkbox = QCheckBox(self) self.use_dutils_label = QLabel("Use tiscamera dutils, if present:", self) layout.addRow(self.use_dutils_label, self.use_dutils_checkbox) if not self.enabled_dutils: self.use_dutils_label.setToolTip("Enabled when tiscamera-dutils are installed") self.use_dutils_label.setEnabled(False) self.use_dutils_checkbox.setToolTip("Enabled when tiscamera-dutils are installed") self.use_dutils_checkbox.setEnabled(False) self.general_widget.setLayout(layout) def _setup_saving_ui(self): """ Create everything related to the image/video saving tab """ encoder_dict = Encoder.get_encoder_dict() form_layout = QFormLayout() layout = QVBoxLayout() layout.addLayout(form_layout) location_layout = QHBoxLayout() location_label = QLabel("Where to save images/videos:", self) self.location_edit = QLineEdit(self) location_dialog_button = QPushButton("...", self) location_dialog_button.clicked.connect(self.open_file_dialog) location_layout.addWidget(self.location_edit) location_layout.addWidget(location_dialog_button) # maintain descriptions as own labels # pyqt seems to loose the descriptions somewhere # when simple strings are used or the qlabel does not have self as owner form_layout.addRow(location_label, location_layout) self.image_type_combobox = QComboBox(self) for key, value in encoder_dict.items(): if value.encoder_type == Encoder.MediaType.image: self.image_type_combobox.addItem(key) image_type_label = QLabel("Save images as:") self.image_type_combobox.currentIndexChanged['QString'].connect(self.image_name_suffix_changed) form_layout.addRow(image_type_label, self.image_type_combobox) if self.enabled_video: self.video_type_combobox = QComboBox(self) for key, value in encoder_dict.items(): if value.encoder_type == Encoder.MediaType.video: self.video_type_combobox.addItem(key) self.video_type_combobox.currentIndexChanged['QString'].connect(self.video_name_suffix_changed) video_type_label = QLabel("Save videos as:", self) form_layout.addRow(video_type_label, self.video_type_combobox) image_name_groupbox = QGroupBox("Image File Names") groupbox_layout = QFormLayout() image_name_groupbox.setLayout(groupbox_layout) self.image_name_preview = QLabel("<USER-PREFIX>-<SERIAL>-<FORMAT>-<TIMESTAMP>-<COUNTER>.png") self.image_name_preview_description = QLabel("Images will be named like:") groupbox_layout.addRow(self.image_name_preview_description, self.image_name_preview) self.image_name_prefix = QLineEdit() self.image_name_prefix.textChanged.connect(self.image_name_prefix_changed) self.image_name_prefix.setMaxLength(100) self.image_name_prefix_description = QLabel("User Prefix:", self) groupbox_layout.addRow(self.image_name_prefix_description, self.image_name_prefix) self.image_name_serial = QCheckBox(self) self.image_name_serial.toggled.connect(self.image_name_properties_toggled) self.image_name_serial_description = QLabel("Include Serial:") groupbox_layout.addRow(self.image_name_serial_description, self.image_name_serial) self.image_name_format = QCheckBox(self) self.image_name_format.toggled.connect(self.image_name_properties_toggled) self.image_name_format_description = QLabel("Include Format:") groupbox_layout.addRow(self.image_name_format_description, self.image_name_format) self.image_name_counter = QCheckBox(self) self.image_name_counter.toggled.connect(self.image_name_properties_toggled) self.image_name_counter_description = QLabel("Include Counter:") groupbox_layout.addRow(self.image_name_counter_description, self.image_name_counter) self.image_name_counter_box = QSpinBox(self) self.image_name_counter_box.setRange(1, 10) self.image_name_counter_box.valueChanged.connect(self.image_name_counter_changed) self.image_name_counter_box_description = QLabel("Counter Size:") groupbox_layout.addRow(self.image_name_counter_box_description, self.image_name_counter_box) self.image_name_counter.toggled.connect(self.toggle_image_counter_box_availability) self.image_name_counter.toggled.connect(self.image_name_properties_toggled) self.image_name_timestamp = QCheckBox(self) self.image_name_timestamp.toggled.connect(self.image_name_properties_toggled) self.image_name_timestamp_description = QLabel("Include Timestamp:") groupbox_layout.addRow(self.image_name_timestamp_description, self.image_name_timestamp) layout.addWidget(image_name_groupbox) video_groupbox = QGroupBox("Video File Names") video_layout = QFormLayout() video_groupbox.setLayout(video_layout) self.video_name_preview = QLabel("<USER-PREFIX>-<SERIAL>-<FORMAT>-<TIMESTAMP>-<COUNTER>.png") self.video_name_preview_description = QLabel("Videos will be named like:") video_layout.addRow(self.video_name_preview_description, self.video_name_preview) self.video_name_prefix = QLineEdit() self.video_name_prefix.textChanged.connect(self.video_name_prefix_changed) self.video_name_prefix.setMaxLength(100) self.video_name_prefix_description = QLabel("User Prefix:", self) video_layout.addRow(self.video_name_prefix_description, self.video_name_prefix) self.video_name_serial = QCheckBox(self) self.video_name_serial.toggled.connect(self.video_name_properties_toggled) self.video_name_serial_description = QLabel("Include Serial:") video_layout.addRow(self.video_name_serial_description, self.video_name_serial) self.video_name_format = QCheckBox(self) self.video_name_format.toggled.connect(self.video_name_properties_toggled) self.video_name_format_description = QLabel("Include Format:") video_layout.addRow(self.video_name_format_description, self.video_name_format) self.video_name_counter = QCheckBox(self) self.video_name_counter.toggled.connect(self.video_name_properties_toggled) self.video_name_counter_description = QLabel("Include Counter:") video_layout.addRow(self.video_name_counter_description, self.video_name_counter) self.video_name_counter_box = QSpinBox(self) self.video_name_counter_box.setRange(1, 10) self.video_name_counter_box.valueChanged.connect(self.video_name_counter_changed) self.video_name_counter_box_description = QLabel("Counter Size:") video_layout.addRow(self.video_name_counter_box_description, self.video_name_counter_box) self.video_name_counter.toggled.connect(self.toggle_video_counter_box_availability) self.video_name_counter.toggled.connect(self.video_name_properties_toggled) self.video_name_timestamp = QCheckBox(self) self.video_name_timestamp.toggled.connect(self.video_name_properties_toggled) self.video_name_timestamp_description = QLabel("Include Timestamp:") video_layout.addRow(self.video_name_timestamp_description, self.video_name_timestamp) layout.addWidget(video_groupbox) self.saving_widget.setLayout(layout) def image_name_prefix_changed(self, name: str): """""" self.settings.image_name.user_prefix = self.image_name_prefix.text() self.update_image_name_preview() def image_name_suffix_changed(self, suffix: str): """""" self.update_image_name_preview() def image_name_counter_changed(self, name: str): """""" self.settings.image_name.counter_size = self.image_name_counter_box.value() self.update_image_name_preview() def image_name_properties_toggled(self): """""" self.settings.image_name.include_timestamp = self.image_name_timestamp.isChecked() self.settings.image_name.include_counter = self.image_name_counter.isChecked() self.settings.image_name.include_format = self.image_name_format.isChecked() self.settings.image_name.include_serial = self.image_name_serial.isChecked() self.update_image_name_preview() def update_image_name_preview(self): preview_string = "" if self.settings.image_name.user_prefix != "": max_prefix_length = 15 prefix = (self.settings.image_name.user_prefix[:max_prefix_length] + '..') if len(self.settings.image_name.user_prefix) > max_prefix_length else self.settings.image_name.user_prefix preview_string += prefix if self.settings.image_name.include_serial: if preview_string != "": preview_string += "-" preview_string += "00001234" if self.settings.image_name.include_format: if preview_string != "": preview_string += "-" preview_string += "gbrg_1920x1080_15_1" if self.settings.image_name.include_timestamp: if preview_string != "": preview_string += "-" preview_string += "19701230T125503" if self.settings.image_name.include_counter: if preview_string != "": preview_string += "-" preview_string += '{message:0>{fill}}'.format(message=1, fill=self.settings.image_name.counter_size) if preview_string == "": preview_string = "image" preview_string += "." + self.image_type_combobox.currentText() self.image_name_preview.setText(preview_string) def video_name_prefix_changed(self, name: str): """""" self.settings.video_name.user_prefix = self.video_name_prefix.text() self.update_video_name_preview() def video_name_suffix_changed(self, suffix: str): """""" self.update_video_name_preview() def video_name_counter_changed(self, name: str): """""" self.settings.video_name.counter_size = self.video_name_counter_box.value() self.update_video_name_preview() def video_name_properties_toggled(self): """""" self.settings.video_name.include_timestamp = self.video_name_timestamp.isChecked() self.settings.video_name.include_counter = self.video_name_counter.isChecked() self.settings.video_name.include_format = self.video_name_format.isChecked() self.settings.video_name.include_serial = self.video_name_serial.isChecked() self.update_video_name_preview() def update_video_name_preview(self): preview_string = "" if self.settings.video_name.user_prefix != "": # This is a convenience change to the displayed string. # We only display an amount of max_prefix_length # chars to save screen space max_prefix_length = 15 prefix = (self.settings.video_name.user_prefix[:max_prefix_length] + '..') if len(self.settings.video_name.user_prefix) > max_prefix_length else self.settings.video_name.user_prefix preview_string += prefix if self.settings.video_name.include_serial: if preview_string != "": preview_string += "-" preview_string += "00001234" if self.settings.video_name.include_format: if preview_string != "": preview_string += "-" preview_string += "gbrg_1920x1080_15_1" if self.settings.video_name.include_timestamp: if preview_string != "": preview_string += "-" preview_string += "19701230T125503" if self.settings.video_name.include_counter: if preview_string != "": preview_string += "-" preview_string += '{message:0>{fill}}'.format(message=1, fill=self.settings.video_name.counter_size) if preview_string == "": preview_string = "video" preview_string += "." + self.video_type_combobox.currentText() self.video_name_preview.setText(preview_string) def toggle_image_counter_box_availability(self): """""" if self.image_name_counter.isChecked(): self.image_name_counter_box.setEnabled(True) else: self.image_name_counter_box.setEnabled(False) def toggle_video_counter_box_availability(self): """""" if self.video_name_counter.isChecked(): self.video_name_counter_box.setEnabled(True) else: self.video_name_counter_box.setEnabled(False) def _setup_keybindings_ui(self): """ Create everything related to the keybindings tab """ layout = QFormLayout() self.keybinding_fullscreen_label = QLabel("Toggle Fullscreen:") self.keybinding_fullscreen = QKeySequenceEdit() layout.addRow(self.keybinding_fullscreen_label, self.keybinding_fullscreen) self.keybinding_save_image_label = QLabel("Save image:") self.keybinding_save_image = QKeySequenceEdit(QKeySequence(self.settings.keybinding_save_image)) layout.addRow(self.keybinding_save_image_label, self.keybinding_save_image) self.keybinding_trigger_image_label = QLabel("Trigger images via softwaretrigger:") self.keybinding_trigger_image = QKeySequenceEdit(QKeySequence(self.settings.keybinding_trigger_image)) layout.addRow(self.keybinding_trigger_image_label, self.keybinding_trigger_image) self.keybinding_open_dialog_label = QLabel("Open device dialog:") self.keybinding_open_dialog = QKeySequenceEdit(QKeySequence(self.settings.keybinding_open_dialog)) layout.addRow(self.keybinding_open_dialog_label, self.keybinding_open_dialog) self.keybindings_widget.setLayout(layout) def set_settings(self, settings: Settings): self.location_edit.setText(settings.get_save_location()) self.image_type_combobox.setCurrentText(settings.get_image_type()) if self.enabled_video: self.video_type_combobox.setCurrentText(settings.get_video_type()) self.device_dialog_checkbox.setChecked(settings.show_device_dialog_on_startup) self.reopen_device_checkbox.setChecked(settings.reopen_device_on_startup) self.use_dutils_checkbox.setChecked(settings.use_dutils) # # keybindings # if self.enabled_keybindings: self.keybinding_fullscreen.setKeySequence(QKeySequence(self.settings.keybinding_fullscreen)) self.keybinding_save_image.setKeySequence(QKeySequence(self.settings.keybinding_save_image)) self.keybinding_trigger_image.setKeySequence(QKeySequence(self.settings.keybinding_trigger_image)) self.keybinding_open_dialog.setKeySequence(QKeySequence(self.settings.keybinding_open_dialog)) # # image saving # if settings.image_name.include_timestamp: self.image_name_timestamp.blockSignals(True) self.image_name_timestamp.toggle() self.image_name_timestamp.blockSignals(False) if settings.image_name.include_counter: self.image_name_counter.blockSignals(True) self.image_name_counter.toggle() self.image_name_counter.blockSignals(False) self.image_name_counter_box.blockSignals(True) self.image_name_counter_box.setValue(settings.image_name.counter_size) self.image_name_counter_box.blockSignals(False) self.toggle_image_counter_box_availability() if settings.image_name.include_format: self.image_name_format.blockSignals(True) self.image_name_format.toggle() self.image_name_format.blockSignals(False) if settings.image_name.include_serial: self.image_name_serial.blockSignals(True) self.image_name_serial.toggle() self.image_name_serial.blockSignals(False) self.image_name_prefix.blockSignals(True) self.image_name_prefix.setText(settings.image_name.user_prefix) self.image_name_prefix.blockSignals(False) self.update_image_name_preview() # # video saving # if settings.video_name.include_timestamp: self.video_name_timestamp.blockSignals(True) self.video_name_timestamp.toggle() self.video_name_timestamp.blockSignals(False) if settings.video_name.include_counter: self.video_name_counter.blockSignals(True) self.video_name_counter.toggle() self.video_name_counter.blockSignals(False) self.video_name_counter_box.blockSignals(True) self.video_name_counter_box.setValue(settings.video_name.counter_size) self.video_name_counter_box.blockSignals(False) self.toggle_video_counter_box_availability() if settings.video_name.include_format: self.video_name_format.blockSignals(True) self.video_name_format.toggle() self.video_name_format.blockSignals(False) if settings.video_name.include_serial: self.video_name_serial.blockSignals(True) self.video_name_serial.toggle() self.video_name_serial.blockSignals(False) self.video_name_prefix.blockSignals(True) self.video_name_prefix.setText(settings.video_name.user_prefix) self.video_name_prefix.blockSignals(False) self.update_video_name_preview() def save_settings(self): self.settings.save_location = self.location_edit.text() self.settings.image_type = self.image_type_combobox.currentText() if self.enabled_video: self.settings.video_type = self.video_type_combobox.currentText() self.settings.show_device_dialog_on_startup = self.device_dialog_checkbox.isChecked() self.settings.reopen_device_on_startup = self.reopen_device_checkbox.isChecked() self.settings.use_dutils = self.use_dutils_checkbox.isChecked() # # keybindings # if self.enabled_keybindings: self.settings.keybinding_fullscreen = self.keybinding_fullscreen.keySequence().toString() self.settings.keybinding_save_image = self.keybinding_save_image.keySequence().toString() self.settings.keybinding_trigger_image = self.keybinding_trigger_image.keySequence().toString() self.settings.keybinding_open_dialog = self.keybinding_open_dialog.keySequence().toString() # # image saving # self.settings.image_name.include_timestamp = self.image_name_timestamp.isChecked() self.settings.image_name.include_counter = self.image_name_counter.isChecked() if self.image_name_counter.isChecked(): self.settings.image_name.counter_size = self.image_name_counter_box.value() self.settings.image_name.include_format = self.image_name_format.isChecked() self.settings.image_name.include_serial = self.image_name_serial.isChecked() self.settings.image_name.user_prefix = self.image_name_prefix.text() # # video saving # self.settings.video_name.include_timestamp = self.video_name_timestamp.isChecked() self.settings.video_name.include_counter = self.video_name_counter.isChecked() if self.video_name_counter.isChecked(): self.settings.video_name.counter_size = self.video_name_counter_box.value() self.settings.video_name.include_format = self.video_name_format.isChecked() self.settings.video_name.include_serial = self.video_name_serial.isChecked() self.settings.video_name.user_prefix = self.video_name_prefix.text() def open_file_dialog(self): fdia = QFileDialog() fdia.setFileMode(QFileDialog.Directory) fdia.setWindowTitle("Select Directory for saving images and videos") if fdia.exec_(): self.location_edit.setText(fdia.selectedFiles()[0]) def get_location(self): return self.location_edit.text() def get_image_format(self): return self.image_type_combobox.currentText() def get_video_format(self): return self.video_type_combobox.currentText() def clicked(self, button): if self.buttons.buttonRole(button) == QDialogButtonBox.ResetRole: self.reset() def reset(self): """""" log.info("reset called") self.settings.reset() self.set_settings(self.settings) @staticmethod def get_options(settings, parent=None): dialog = OptionsDialog(settings, parent) if settings is not None: dialog.set_settings(settings) result = dialog.exec_() if result == QDialog.Accepted: dialog.save_settings() settings.save() return result == QDialog.Accepted
def setEditorData(self, editor: QCheckBox, index: QModelIndex): editor.blockSignals(True) editor.setChecked(index.model().data(index)) self.enabled = editor.isChecked() editor.blockSignals(False)
class QTGui: def __init__(self): self.allCenters = [] self.checkedCenters = dict() self.removeAfter = 1000 self.dose = 1 def window(self): try: app = QApplication(sys.argv) window = QWidget() window.setWindowTitle('COWIN Slot Finder') window.setMinimumWidth(1000) window.setMinimumHeight(800) layout = QGridLayout() timer = QTimer() timer.timeout.connect(self.tick) timer.start(100) self.states = QComboBox() for elem in self.stateDict['states']: itemStr = str(elem["state_id"]) + ":" + str(elem["state_name"]) self.states.addItem(itemStr) row = 1 labelState = QLabel("States") labelState.setFont(QFont("Times", weight=QFont.Bold)) labelDist = QLabel("Districts") labelDist.setFont(QFont("Times", weight=QFont.Bold)) layout.addWidget(labelState, row, 1, 1, 2) layout.addWidget(labelDist, row, 4, 1, 2) row += 1 self.states.currentIndexChanged.connect(self.stateSelectionchange) layout.addWidget(self.states, row, 1, 1, 2) self.districts = QComboBox() self.districts.currentIndexChanged.connect(self.districtSelectionchange) layout.addWidget(self.districts, row, 4, 1, 2) row += 1 self.searchBox = QLineEdit() self.searchBox.setPlaceholderText("Search...") self.searchBox.textChanged.connect(self.textChanged) layout.addWidget(self.searchBox, row, 1, 1, 3) labelDose = QLabel("Select Dose:") # labelDose.setFont(QFont("Times", weight=QFont.Bold)) layout.addWidget(labelDose, row, 4, 1, 1) radiobutton = QRadioButton("Dose 1") radiobutton.setChecked(True) radiobutton.dose = 1 radiobutton.toggled.connect(lambda: self.onSelectRadio(radiobutton)) layout.addWidget(radiobutton, row, 5, 1, 1) radiobutton2 = QRadioButton("Dose 2") radiobutton2.setChecked(False) radiobutton2.dose = 2 radiobutton2.toggled.connect(lambda: self.onSelectRadio(radiobutton2)) layout.addWidget(radiobutton2, row, 6, 1, 1) row += 1 labelCenter = QLabel("Available Centers") labelCenter.setFont(QFont("Times", weight=QFont.Bold)) layout.addWidget(labelCenter, row, 1, 1, 3) labelSelect = QLabel("Selected Centers") labelSelect.setFont(QFont("Times", weight=QFont.Bold)) layout.addWidget(labelSelect, row, 4, 1, 3) row += 1 self.selectAllChk = QCheckBox("Select All") self.selectAllChk.stateChanged.connect(lambda: self.selectAll(self.selectAllChk)) layout.addWidget(self.selectAllChk, row, 1, 1, 3) row += 1 self.centreLayout = QVBoxLayout() self.checks = [] widget = QWidget() widget.setLayout(self.centreLayout) # Scroll Area Properties scroll = QScrollArea() # scroll.setFrameShape(frame) scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) scroll.setWidgetResizable(True) scroll.setWidget(widget) layout.addWidget(scroll, row, 1, 1, 3) self.selectedLayout = QVBoxLayout() widget2 = QWidget() widget2.setLayout(self.selectedLayout) # Scroll Area Properties scroll2 = QScrollArea() # scroll.setFrameShape(frame) scroll2.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # scroll2.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) scroll2.setWidgetResizable(True) scroll2.setWidget(widget2) layout.addWidget(scroll2, row, 4, 1, 3) row += 1 self.button1 = QPushButton() self.button1.setText("Run Slot Notifier") self.button1.clicked.connect(self.runService) layout.addWidget(self.button1, row, 3, 1, 2) self.buttonClear = QPushButton() self.buttonClear.setText("Clear") self.buttonClear.clicked.connect(self.clearSelections) layout.addWidget(self.buttonClear, row, 6, 1, 1) row += 1 self.button2 = QPushButton() self.button2.setText("Stop Slot Notifier") self.button2.clicked.connect(self.stopService) layout.addWidget(self.button2, row, 3, 1, 2) row += 1 self.msgLayout = QVBoxLayout() widget3 = QWidget() widget3.setLayout(self.msgLayout) # Scroll Area Properties self.scroll3 = QScrollArea() # scroll.setFrameShape(frame) self.scroll3.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # scroll3.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scroll3.setWidgetResizable(True) self.scroll3.setWidget(widget3) layout.addWidget(self.scroll3, row, 1, 1, 6) row += 1 app.aboutToQuit.connect(self.closeEvent) window.setLayout(layout) window.show() sys.exit(app.exec_()) except BaseException as e: raise def stateSelectionchange(self, i): currentState = self.states.currentText() # print("Current index", i, "selection changed ", currentState) state_id = currentState[:currentState.index(":")] # print(state_id) distResp = self.getters.getDistricts(state_id) # print(distResp) self.districts.clear() for elem in distResp['districts']: itemStr = str(elem["district_id"]) + ":" + str(elem["district_name"]) self.districts.addItem(itemStr) self.districts.update() def districtSelectionchange(self, i): if i == -1: return currentDist = self.districts.currentText() # print("Current index", i, "selection changed ", currentDist) self.dist_id = currentDist[:currentDist.index(":")] # print(self.dist_id) curr_date = datetime.datetime.now().strftime("%d-%m-%Y") calendar = self.getters.getCalendarByDistrict(self.dist_id, curr_date) # print(calendar['centers']) for i in reversed(range(self.centreLayout.count())): widgetToRemove = self.centreLayout.itemAt(i).widget() # remove it from the layout list self.centreLayout.removeWidget(widgetToRemove) # remove it from the gui widgetToRemove.setParent(None) self.allCenters = [] self.checks = [] self.searchBox.setText("") anyUnchecked = False for elem in calendar['centers']: label = str(elem["center_id"]) + ":" + elem["name"] + "," + elem["address"] + "," + str(elem["pincode"]) self.allCenters.append(label) c = QCheckBox(label) self.centreLayout.addWidget(c) if label in self.checkedCenters.keys(): c.setChecked(True) else: anyUnchecked = True c.stateChanged.connect(self.selectionStateChanged) self.checks.append(c) self.centreLayout.update() self.selectAllChk.blockSignals(True) self.selectAllChk.setChecked(not anyUnchecked) self.selectAllChk.blockSignals(False) def selectionStateChanged(self, int): for elem in self.checks: if elem.isChecked() and elem.text() not in self.checkedCenters.keys(): self.checkedCenters[elem.text()] = self.dist_id if not elem.isChecked() and elem.text() in self.checkedCenters.keys(): del self.checkedCenters[elem.text()] # print(self.checkedCenters) for i in reversed(range(self.selectedLayout.count())): widgetToRemove = self.selectedLayout.itemAt(i).widget() # remove it from the layout list self.selectedLayout.removeWidget(widgetToRemove) # remove it from the gui widgetToRemove.setParent(None) for elem in self.checkedCenters.keys(): c = QLabel(elem) self.selectedLayout.addWidget(c) self.selectedLayout.update() def runService(self): MsgPass.MsgPass.runstatus = True slotNotifier = SlotNotifier.SlotNotifier() centers = copy.deepcopy(self.checkedCenters) t1 = threading.Thread(target=slotNotifier.runService, args=(centers, self.dose,)) t1.start() def stopService(self): MsgPass.MsgPass.runstatus = False def tick(self): if MsgPass.MsgPass.runstatus == False: self.button2.setEnabled(False) else: self.button2.setEnabled(True) if MsgPass.MsgPass.threadrunning == True: self.button1.setEnabled(False) else: self.button1.setEnabled(True) while len(MsgPass.MsgPass.msgQ) > 0: c = QLabel(MsgPass.MsgPass.msgQ.pop()) self.msgLayout.addWidget(c) if self.msgLayout.count() > self.removeAfter: for i in range(self.msgLayout.count() - self.removeAfter): widgetToRemove = self.msgLayout.itemAt(i).widget() # remove it from the layout list self.msgLayout.removeWidget(widgetToRemove) # remove it from the gui widgetToRemove.setParent(None) self.msgLayout.update() try: if self.scroll3.verticalScrollBar().maximum() - self.scroll3.verticalScrollBar().value() < 100: self.scroll3.verticalScrollBar().setValue(self.scroll3.verticalScrollBar().maximum()) except: pass def textChanged(self, text): for i in reversed(range(self.centreLayout.count())): widgetToRemove = self.centreLayout.itemAt(i).widget() # remove it from the layout list self.centreLayout.removeWidget(widgetToRemove) # remove it from the gui widgetToRemove.setParent(None) self.checks = [] for elem in self.allCenters: if text.lower() in elem.lower() or len(text) == 0: c = QCheckBox(elem) self.centreLayout.addWidget(c) if elem in self.checkedCenters.keys(): c.setChecked(True) c.stateChanged.connect(self.selectionStateChanged) self.checks.append(c) self.centreLayout.update() def selectAll(self, chk): for i in range(self.centreLayout.count() - 1): chkbox = self.centreLayout.itemAt(i).widget() chkbox.blockSignals(True) for i in range(self.centreLayout.count() - 1): chkbox = self.centreLayout.itemAt(i).widget() chkbox.setChecked(chk.isChecked()) for i in range(self.centreLayout.count() - 1): chkbox = self.centreLayout.itemAt(i).widget() chkbox.blockSignals(False) self.centreLayout.itemAt(self.centreLayout.count() - 1).widget().setChecked(chk.isChecked()) def onSelectRadio(self, button): if button.isChecked(): self.dose = button.dose def clearSelections(self): self.checkedCenters = {} for i in reversed(range(self.selectedLayout.count())): widgetToRemove = self.selectedLayout.itemAt(i).widget() # remove it from the layout list self.selectedLayout.removeWidget(widgetToRemove) # remove it from the gui widgetToRemove.setParent(None) self.districtSelectionchange(0) def closeEvent(self): print("Closing app") MsgPass.MsgPass.runstatus = False def start(self): try: self.getters = Getters.Getters() self.stateDict = self.getters.getStates() # print(self.stateDict) self.window() except BaseException as e: raise
class ApplicationPage(QWidget): """ The GUI for the application page of a project. """ # The page's label. label = "Application Source" @property def project(self): """ The project property getter. """ return self._project @project.setter def project(self, value): """ The project property setter. """ if self._project != value: self._project = value self._script_edit.set_project(value) self._package_edit.set_project(value) self._update_page() def __init__(self): """ Initialise the page. """ super().__init__() self._project = None # Create the page's GUI. layout = QGridLayout() form = BetterForm() self._name_edit = QLineEdit( placeholderText="Application name", whatsThis="The name of the application. It will default to " "the base name of the application script without any " "extension.", textEdited=self._name_changed) form.addRow("Name", self._name_edit) self._script_edit = FilenameEditor( "Application Script", placeholderText="Application script", whatsThis="The name of the application's optional main script " "file.", textEdited=self._script_changed) form.addRow("Main script file", self._script_edit) self._entry_point_edit = QLineEdit( placeholderText="Entry point in application package", whatsThis="The name of the optional entry point in the " "application's package.", textEdited=self._entry_point_changed) form.addRow("Entry point", self._entry_point_edit) self._sys_path_edit = QLineEdit( placeholderText="Additional sys.path directories", whatsThis="A space separated list of additional directories, " "ZIP files and eggs to add to <tt>sys.path</tt>. Only " "set this if you want to allow external packages to " "be imported.", textEdited=self._sys_path_changed) form.addRow("sys.path", self._sys_path_edit) layout.addLayout(form, 0, 0) options_layout = BetterForm() self._console_edit = QCheckBox( "Use console (Windows)", whatsThis="Enable console output for Windows applications. " "Console output will be enabled automatically if no " "graphical PyQt modules are used.", stateChanged=self._console_changed) options_layout.addRow(self._console_edit) self._bundle_edit = QCheckBox( "Application bundle (macOS)", whatsThis="Build an application bundle on macOS. If it is not " "checked then the application will be built as a " "simple executable.", stateChanged=self._bundle_changed) options_layout.addRow(self._bundle_edit) layout.addLayout(options_layout, 0, 1) # Extra space is needed before the application package editor. layout.setRowMinimumHeight( 1, 1.4 * QFontInfo(QGuiApplication.font()).pixelSize()) self._package_edit = _ApplicationPackageEditor() self._package_edit.package_changed.connect(self._package_changed) package_edit_gb = QGroupBox(self._package_edit.title) package_edit_gb.setFlat(True) package_edit_gb.setLayout(self._package_edit) layout.addWidget(package_edit_gb, 2, 0, 1, 2) qmake = CollapsibleWidget("Additional qmake Configuration") self._qmake_edit = QPlainTextEdit( whatsThis="Any text entered here will be appended to the " "generated <tt>.pro</tt> that will be processed by " "<tt>qmake</tt>.", textChanged=self._qmake_changed) qmake.setWidget(self._qmake_edit) layout.addWidget(qmake, 3, 0, 1, 2) self.setLayout(layout) def _update_page(self): """ Update the page using the current project. """ project = self.project self._name_edit.setText(project.application_name) self._script_edit.setText(project.application_script) self._entry_point_edit.setText(project.application_entry_point) self._sys_path_edit.setText(project.sys_path) self._package_edit.configure(project.application_package, project) blocked = self._console_edit.blockSignals(True) self._console_edit.setCheckState( Qt.Checked if project.application_is_console else Qt.Unchecked) self._console_edit.blockSignals(blocked) blocked = self._bundle_edit.blockSignals(True) self._bundle_edit.setCheckState( Qt.Checked if project.application_is_bundle else Qt.Unchecked) self._bundle_edit.blockSignals(blocked) blocked = self._qmake_edit.blockSignals(True) self._qmake_edit.setPlainText(self._project.qmake_configuration) self._qmake_edit.blockSignals(blocked) def _console_changed(self, state): """ Invoked when the user changes the console state. """ self.project.application_is_console = (state == Qt.Checked) self.project.modified = True def _bundle_changed(self, state): """ Invoked when the user changes the bundle state. """ self.project.application_is_bundle = (state == Qt.Checked) self.project.modified = True def _name_changed(self, value): """ Invoked when the user edits the application name. """ self.project.application_name = value self.project.modified = True def _script_changed(self, value): """ Invoked when the user edits the application script name. """ self.project.application_script = value self.project.modified = True def _entry_point_changed(self, value): """ Invoked when the user edits the entry point. """ self.project.application_entry_point = value self.project.modified = True def _sys_path_changed(self, value): """ Invoked when the user edits the sys.path directories. """ self.project.sys_path = value.strip() self.project.modified = True def _package_changed(self): """ Invoked when the user edits the application package. """ self.project.modified = True def _qmake_changed(self): """ Invoked when the user edits the qmake configuration. """ self.project.qmake_configuration = self._qmake_edit.toPlainText() self.project.modified = True
class LaserRangeFinder(PluginBase): def __init__(self, *args): super().__init__(BrickletLaserRangeFinder, *args) self.lrf = self.device # the firmware version of a EEPROM Bricklet can (under common circumstances) # not change during the lifetime of an EEPROM Bricklet plugin. therefore, # it's okay to make final decisions based on it here self.has_sensor_hardware_version_api = self.firmware_version >= (2, 0, 3) self.has_configuration_api = self.firmware_version >= (2, 0, 3) self.cbe_distance = CallbackEmulator(self.lrf.get_distance, None, self.cb_distance, self.increase_error_count) self.cbe_velocity = CallbackEmulator(self.lrf.get_velocity, None, self.cb_velocity, self.increase_error_count) self.current_distance = CurveValueWrapper() # int, cm self.current_velocity = CurveValueWrapper() # float, m/s plots_distance = [('Distance', Qt.red, self.current_distance, format_distance)] plots_velocity = [('Velocity', Qt.red, self.current_velocity, '{:.2f} m/s'.format)] self.plot_widget_distance = PlotWidget('Distance [cm]', plots_distance, y_resolution=1.0) self.plot_widget_velocity = PlotWidget('Velocity [m/s]', plots_velocity, y_resolution=0.01) self.mode_label = QLabel('Mode:') self.mode_combo = QComboBox() self.mode_combo.addItem("Distance: 1cm resolution, 40m max") self.mode_combo.addItem("Velocity: 0.10 m/s resolution, 12.70m/s max") self.mode_combo.addItem("Velocity: 0.25 m/s resolution, 31.75m/s max") self.mode_combo.addItem("Velocity: 0.50 m/s resolution, 63.50m/s max") self.mode_combo.addItem("Velocity: 1.00 m/s resolution, 127.00m/s max") self.mode_combo.currentIndexChanged.connect(self.mode_changed) self.mode_combo.hide() self.label_average_distance = QLabel('Moving Average for Distance:') self.spin_average_distance = QSpinBox() self.spin_average_distance.setMinimum(0) self.spin_average_distance.setMaximum(50) self.spin_average_distance.setSingleStep(1) self.spin_average_distance.setValue(10) self.spin_average_distance.editingFinished.connect( self.spin_average_finished) self.label_average_velocity = QLabel('Moving Average for Velocity:') self.spin_average_velocity = QSpinBox() self.spin_average_velocity.setMinimum(0) self.spin_average_velocity.setMaximum(50) self.spin_average_velocity.setSingleStep(1) self.spin_average_velocity.setValue(10) self.spin_average_velocity.editingFinished.connect( self.spin_average_finished) self.enable_laser = QCheckBox("Enable Laser") self.enable_laser.stateChanged.connect(self.enable_laser_changed) self.label_acquisition_count = QLabel('Acquisition Count:') self.spin_acquisition_count = QSpinBox() self.spin_acquisition_count.setMinimum(1) self.spin_acquisition_count.setMaximum(255) self.spin_acquisition_count.setSingleStep(1) self.spin_acquisition_count.setValue(128) self.enable_qick_termination = QCheckBox("Quick Termination") self.label_threshold = QLabel('Threshold:') self.threshold = QCheckBox("Automatic Threshold") self.spin_threshold = QSpinBox() self.spin_threshold.setMinimum(1) self.spin_threshold.setMaximum(255) self.spin_threshold.setSingleStep(1) self.spin_threshold.setValue(1) self.label_frequency = QLabel('Frequency [Hz]:') self.frequency = QCheckBox( "Automatic Frequency (Disable for Velocity)") self.spin_frequency = QSpinBox() self.spin_frequency.setMinimum(10) self.spin_frequency.setMaximum(500) self.spin_frequency.setSingleStep(1) self.spin_frequency.setValue(10) self.spin_acquisition_count.editingFinished.connect( self.configuration_changed) self.enable_qick_termination.stateChanged.connect( self.configuration_changed) self.spin_threshold.editingFinished.connect(self.configuration_changed) self.threshold.stateChanged.connect(self.configuration_changed) self.spin_frequency.editingFinished.connect(self.configuration_changed) self.frequency.stateChanged.connect(self.configuration_changed) layout_h1 = QHBoxLayout() layout_h1.addWidget(self.plot_widget_distance) layout_h1.addWidget(self.plot_widget_velocity) layout_h2 = QHBoxLayout() layout_h2.addWidget(self.mode_label) layout_h2.addWidget(self.mode_combo) layout_h2.addWidget(self.label_average_distance) layout_h2.addWidget(self.spin_average_distance) layout_h2.addWidget(self.label_average_velocity) layout_h2.addWidget(self.spin_average_velocity) layout_h2.addStretch() layout_h2.addWidget(self.enable_laser) layout_h3 = QHBoxLayout() layout_h3.addWidget(self.label_frequency) layout_h3.addWidget(self.spin_frequency) layout_h3.addWidget(self.frequency) layout_h3.addStretch() layout_h3.addWidget(self.enable_qick_termination) layout_h4 = QHBoxLayout() layout_h4.addWidget(self.label_threshold) layout_h4.addWidget(self.spin_threshold) layout_h4.addWidget(self.threshold) layout_h4.addStretch() layout_h4.addWidget(self.label_acquisition_count) layout_h4.addWidget(self.spin_acquisition_count) self.widgets_distance = [ self.plot_widget_distance, self.spin_average_distance, self.label_average_distance ] self.widgets_velocity = [ self.plot_widget_velocity, self.spin_average_velocity, self.label_average_velocity ] for w in self.widgets_distance: w.hide() for w in self.widgets_velocity: w.hide() line = QFrame() line.setObjectName("line") line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addLayout(layout_h1) layout.addWidget(line) layout.addLayout(layout_h2) layout.addLayout(layout_h3) layout.addLayout(layout_h4) def start(self): if self.has_sensor_hardware_version_api: async_call(self.lrf.get_sensor_hardware_version, None, self.get_sensor_hardware_version_async, self.increase_error_count) else: self.get_sensor_hardware_version_async(1) if self.has_configuration_api: async_call(self.lrf.get_configuration, None, self.get_configuration_async, self.increase_error_count) async_call(self.lrf.get_mode, None, self.get_mode_async, self.increase_error_count) async_call(self.lrf.is_laser_enabled, None, self.enable_laser.setChecked, self.increase_error_count) async_call(self.lrf.get_moving_average, None, self.get_moving_average_async, self.increase_error_count) self.cbe_distance.set_period(25) self.cbe_velocity.set_period(25) self.plot_widget_distance.stop = False self.plot_widget_velocity.stop = False def stop(self): self.cbe_distance.set_period(0) self.cbe_velocity.set_period(0) self.plot_widget_distance.stop = True self.plot_widget_velocity.stop = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletLaserRangeFinder.DEVICE_IDENTIFIER def enable_laser_changed(self, state): if state == Qt.Checked: self.lrf.enable_laser() else: self.lrf.disable_laser() def mode_changed(self, value): if value < 0 or value > 4: return self.lrf.set_mode(value) if value == 0: for w in self.widgets_velocity: w.hide() for w in self.widgets_distance: w.show() else: for w in self.widgets_distance: w.hide() for w in self.widgets_velocity: w.show() def cb_distance(self, distance): self.current_distance.value = distance def cb_velocity(self, velocity): self.current_velocity.value = velocity / 100.0 def configuration_changed(self): acquisition_count = self.spin_acquisition_count.value() enable_quick_termination = self.enable_qick_termination.isChecked() if self.threshold.isChecked(): threshold = 0 else: threshold = self.spin_threshold.value() if self.frequency.isChecked(): frequency = 0 for w in self.widgets_velocity: w.hide() else: frequency = self.spin_frequency.value() for w in self.widgets_velocity: w.show() self.spin_threshold.setDisabled(threshold == 0) self.spin_frequency.setDisabled(frequency == 0) self.lrf.set_configuration(acquisition_count, enable_quick_termination, threshold, frequency) def get_configuration_async(self, conf): self.spin_acquisition_count.blockSignals(True) self.spin_acquisition_count.setValue(conf.acquisition_count) self.spin_acquisition_count.blockSignals(False) self.enable_qick_termination.blockSignals(True) self.enable_qick_termination.setChecked(conf.enable_quick_termination) self.enable_qick_termination.blockSignals(False) self.spin_threshold.blockSignals(True) self.spin_threshold.setValue(conf.threshold_value) self.spin_threshold.setDisabled(conf.threshold_value == 0) self.spin_threshold.blockSignals(False) self.spin_frequency.blockSignals(True) self.spin_frequency.setValue(conf.measurement_frequency) self.spin_frequency.setDisabled(conf.measurement_frequency == 0) self.spin_frequency.blockSignals(False) self.threshold.blockSignals(True) self.threshold.setChecked(conf.threshold_value == 0) self.threshold.blockSignals(False) self.frequency.blockSignals(True) self.frequency.setChecked(conf.measurement_frequency == 0) self.frequency.blockSignals(False) self.configuration_changed() def get_sensor_hardware_version_async(self, value): if value == 1: self.mode_combo.show() self.mode_label.show() self.label_acquisition_count.hide() self.spin_acquisition_count.hide() self.enable_qick_termination.hide() self.label_threshold.hide() self.spin_threshold.hide() self.threshold.hide() self.label_frequency.hide() self.spin_frequency.hide() self.frequency.hide() else: self.mode_combo.hide() self.mode_label.hide() self.label_acquisition_count.show() self.spin_acquisition_count.show() self.enable_qick_termination.show() self.label_threshold.show() self.spin_threshold.show() self.threshold.show() self.label_frequency.show() self.spin_frequency.show() self.frequency.show() for w in self.widgets_distance: w.show() for w in self.widgets_velocity: w.show() def get_mode_async(self, value): self.mode_combo.setCurrentIndex(value) self.mode_changed(value) def get_moving_average_async(self, avg): self.spin_average_distance.setValue(avg.distance_average_length) self.spin_average_velocity.setValue(avg.velocity_average_length) def spin_average_finished(self): self.lrf.set_moving_average(self.spin_average_distance.value(), self.spin_average_velocity.value())
class iv(QMainWindow): zoom_factor = 1.1 x_zoom = True y_zoom = True x_stop_at_orig = True y_stop_at_orig = True def __init__(self, *args, **kwargs): app = QtCore.QCoreApplication.instance() if app is None: app = QApplication(['']) QMainWindow.__init__(self, parent=None) timestamp = datetime.now().strftime("%y%m%d_%H%M%S") self.setWindowTitle('iv ' + timestamp) shell = get_ipython() shell.magic('%matplotlib qt') # store list of input images if len(args) == 1 and isinstance(args[0], torch.Tensor): # handle torch.Tensor input if args[0].ndim <= 3: self.images = [args[0].detach().cpu().numpy()] elif args[0].ndim == 4: # probably a torch tensor with dimensions [batch, channels, y, x] self.images = [[]] * args[0].shape[0] tmp = args[0].detach().cpu().numpy().transpose((2, 3, 1, 0)) for imind in range(tmp.shape[3]): self.images[imind] = tmp[:, :, :, imind] del tmp else: raise Exception('torch tensors can at most have 4 dimensions') elif len(args) == 1 and isinstance(args[0], np.ndarray) and len( args[0].shape) == 4: # handle 4D numpy.ndarray input by slicing in 4th dimension self.images = [[]] * args[0].shape[3] for imind in range(args[0].shape[3]): self.images[imind] = args[0][:, :, :, imind] elif len(args) == 1 and (isinstance(args[0], list) or isinstance(args[0], tuple)): self.images = list(args[0]) else: self.images = list(args) for imind in range(len(self.images)): if isinstance(self.images[imind], torch.Tensor): self.images[imind] = self.images[imind].detach().cpu().numpy() if self.images[imind].ndim == 4: # probably a torch tensor with dimensions [batch, channels, y, x] self.images[imind] = self.images[imind].transpose( (2, 3, 1, 0)) elif self.images[imind].ndim > 4: raise Exception( 'torch tensors can at most have 4 dimensions') self.images[imind] = np.atleast_3d(self.images[imind]) if self.images[imind].shape[2] != 1 and self.images[imind].shape[ 2] != 3: if self.images[imind].ndim == 4: self.images[imind] = self.images[imind].transpose( (2, 3, 1, 0)) self.imind = 0 # currently selected image self.nims = len(self.images) self.scale = 1. self.gamma = 1. self.offset = 0. self.autoscalePrctile = 0.1 self.autoscaleUsePrctiles = True self.autoscaleOnChange = False self.autoscalePerImg = False self.collageActive = False self.collageTranspose = False self.collageTransposeIms = False self.collage_nc = int(np.ceil(np.sqrt(self.nims))) self.collage_nr = int(np.ceil(self.nims / self.collage_nc)) self.collage_border_width = 0 self.collage_border_value = 0. self.crop = kwargs.get('crop', False) self.crop_global = kwargs.get('crop_global', True) self.zoom_factor = 1.1 self.x_zoom = True self.y_zoom = True self.x_stop_at_orig = True self.y_stop_at_orig = True self.annotate = False self.font_size = 12 self.crop_bounds() self.initUI() self.ax.set_xticks([]) self.ax.set_yticks([]) #plt.tight_layout() self.updateImage() if self.autoscaleOnChange: self.autoscale() self.cur_xlims = self.ih.axes.axis()[0:2] self.cur_ylims = self.ih.axes.axis()[2:] self.mouse_down = 0 self.x_start = 0 self.y_start = 0 self.cid = self.fig.canvas.mpl_connect('button_press_event', self.onclick) self.cid = self.fig.canvas.mpl_connect('button_release_event', self.onrelease) self.cid = self.fig.canvas.mpl_connect('motion_notify_event', self.onmotion) self.cid = self.fig.canvas.mpl_connect( 'key_press_event', self.keyPressEvent) #onkeypress) self.cid = self.fig.canvas.mpl_connect( 'key_release_event', self.keyReleaseEvent) #onkeyrelease) self.cid = self.fig.canvas.mpl_connect('scroll_event', self.onscroll) self.alt = False self.control = False self.shift = False self.prev_delta_x = 0 self.prev_delta_y = 0 #plt.show(block=True) #plt.pause(10) #plt.show(block=False) self.setWindowModality(QtCore.Qt.WindowModal) self.show() def crop_bounds(self): # pre-compute cropping bounds (tight bounding box around non-zero pixels) nzs = [np.where(np.sum(im, axis=2) > 0) for im in self.images] self.xmins = [np.min(nz[1]) if len(nz[1]) else 0 for nz in nzs] self.xmaxs = [ np.max(nz[1]) + 1 if len(nz[1]) else im.shape[1] for nz, im in zip(nzs, self.images) ] # +1 to allow easier indexing self.ymins = [np.min(nz[0]) if len(nz[0]) else 0 for nz in nzs] self.ymaxs = [ np.max(nz[0]) + 1 if len(nz[0]) else im.shape[0] for nz, im in zip(nzs, self.images) ] # +1 to allow easier indexing if self.crop_global: self.xmins = [np.min(self.xmins) for _ in self.xmins] self.xmaxs = [np.max(self.xmaxs) for _ in self.xmaxs] self.ymins = [np.min(self.ymins) for _ in self.ymins] self.ymaxs = [np.max(self.ymaxs) for _ in self.ymaxs] def initUI(self): #self.fig = plt.figure(figsize = (10, 10)) #self.ax = plt.axes([0,0,1,1])#, self.gs[0]) self.widget = QWidget() self.fig = Figure(dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.widget) #self.ax = Axes(fig=self.fig, rect=[0,0,1,1]) self.ax = self.fig.add_subplot(111) self.ax.set_position(Bbox([[0, 0], [1, 1]])) self.ax.set_anchor('NW') try: self.ax.get_yaxis().set_inverted(True) except Exception: self.ax.invert_yaxis() self.uiLabelModifiers = QLabel('') self.uiLEScale = QLineEdit(str(self.scale)) self.uiLEScale.setMinimumWidth(200) self.uiLEScale.editingFinished.connect( lambda: self.callbackLineEdit(self.uiLEScale)) self.uiLEGamma = QLineEdit(str(self.gamma)) self.uiLEGamma.setMinimumWidth(200) self.uiLEGamma.editingFinished.connect( lambda: self.callbackLineEdit(self.uiLEGamma)) self.uiLEOffset = QLineEdit(str(self.offset)) self.uiLEOffset.setMinimumWidth(200) self.uiLEOffset.editingFinished.connect( lambda: self.callbackLineEdit(self.uiLEOffset)) self.uiLEAutoscalePrctile = QLineEdit(str(self.autoscalePrctile)) self.uiLEAutoscalePrctile.setMinimumWidth(200) self.uiLEAutoscalePrctile.editingFinished.connect( lambda: self.callbackLineEdit(self.uiLEAutoscalePrctile)) self.uiCBAutoscaleUsePrctiles = QCheckBox('use percentiles') self.uiCBAutoscaleUsePrctiles.setCheckState(self.autoscaleUsePrctiles) self.uiCBAutoscaleUsePrctiles.setTristate(False) self.uiCBAutoscaleUsePrctiles.stateChanged.connect( lambda state: self.callbackCheckBox(self.uiCBAutoscaleUsePrctiles, state)) self.uiCBAutoscaleOnChange = QCheckBox('on change') self.uiCBAutoscaleOnChange.setCheckState(self.autoscaleOnChange) self.uiCBAutoscaleOnChange.setTristate(False) self.uiCBAutoscaleOnChange.stateChanged.connect( lambda state: self.callbackCheckBox(self.uiCBAutoscaleOnChange, state)) if self.nims > 1: self.uiCBAutoscalePerImg = QCheckBox('per image') self.uiCBAutoscalePerImg.setCheckState(self.autoscalePerImg) self.uiCBAutoscalePerImg.setTristate(False) self.uiCBAutoscalePerImg.stateChanged.connect( lambda state: self.callbackCheckBox(self.uiCBAutoscalePerImg, state)) self.uiCBCollageActive = QCheckBox('enable') self.uiCBCollageActive.setCheckState(self.collageActive) self.uiCBCollageActive.setTristate(False) self.uiCBCollageActive.stateChanged.connect( lambda state: self.callbackCheckBox(self.uiCBCollageActive, state)) self.uiCBCollageTranspose = QCheckBox('transpose') self.uiCBCollageTranspose.setCheckState(self.collageTranspose) self.uiCBCollageTranspose.setTristate(False) self.uiCBCollageTranspose.stateChanged.connect( lambda state: self.callbackCheckBox(self.uiCBCollageTranspose, state)) self.uiCBCollageTransposeIms = QCheckBox('transpose images') self.uiCBCollageTransposeIms.setCheckState( self.collageTransposeIms) self.uiCBCollageTransposeIms.setTristate(False) self.uiCBCollageTransposeIms.stateChanged.connect( lambda state: self.callbackCheckBox( self.uiCBCollageTransposeIms, state)) self.uiLECollageNr = QLineEdit(str(self.collage_nr)) self.uiLECollageNr.setMinimumWidth(200) self.uiLECollageNr.editingFinished.connect( lambda: self.callbackLineEdit(self.uiLECollageNr)) self.uiLECollageNc = QLineEdit(str(self.collage_nc)) self.uiLECollageNc.setMinimumWidth(200) self.uiLECollageNc.editingFinished.connect( lambda: self.callbackLineEdit(self.uiLECollageNc)) self.uiLECollageBW = QLineEdit(str(self.collage_border_width)) self.uiLECollageBW.setMinimumWidth(200) self.uiLECollageBW.editingFinished.connect( lambda: self.callbackLineEdit(self.uiLECollageBW)) self.uiLECollageBV = QLineEdit(str(self.collage_border_value)) self.uiLECollageBV.setMinimumWidth(200) self.uiLECollageBV.editingFinished.connect( lambda: self.callbackLineEdit(self.uiLECollageBV)) self.uiCBCrop = QCheckBox('enable') self.uiCBCrop.setCheckState(self.crop) self.uiCBCrop.setTristate(False) self.uiCBCrop.stateChanged.connect( lambda state: self.callbackCheckBox(self.uiCBCrop, state)) self.uiCBCropGlobal = QCheckBox('enable') self.uiCBCropGlobal.setCheckState(self.crop_global) self.uiCBCropGlobal.setTristate(False) self.uiCBCropGlobal.stateChanged.connect( lambda state: self.callbackCheckBox(self.uiCBCropGlobal, state)) self.uiCBAnnotate = QCheckBox('enable') self.uiCBAnnotate.setCheckState(self.annotate) self.uiCBAnnotate.setTristate(False) self.uiCBAnnotate.stateChanged.connect( lambda state: self.callbackCheckBox(self.uiCBAnnotate, state)) self.uiLEFontSize = QLineEdit(str(self.font_size)) self.uiLEFontSize.setMinimumWidth(200) self.uiLEFontSize.editingFinished.connect( lambda: self.callbackLineEdit(self.uiLEFontSize)) self.uiPBCopyClipboard = QPushButton('©') self.uiPBCopyClipboard.clicked.connect( lambda: self.callbackPushButton(self.uiPBCopyClipboard)) form = QFormLayout() form.addRow(QLabel('modifiers:'), self.uiLabelModifiers) form.addRow(QLabel('scale:'), self.uiLEScale) form.addRow(QLabel('gamma:'), self.uiLEGamma) form.addRow(QLabel('offset:'), self.uiLEOffset) form.addRow(QLabel('autoScale:'), self.uiCBAutoscaleUsePrctiles) form.addRow(QLabel('percentile:'), self.uiLEAutoscalePrctile) form.addRow(QLabel('autoScale:'), self.uiCBAutoscaleOnChange) if self.nims > 1: form.addRow(QLabel('autoScale:'), self.uiCBAutoscalePerImg) form.addRow(QLabel('collage:'), self.uiCBCollageActive) form.addRow(QLabel('collage:'), self.uiCBCollageTranspose) form.addRow(QLabel('collage:'), self.uiCBCollageTransposeIms) form.addRow(QLabel('collage #rows:'), self.uiLECollageNr) form.addRow(QLabel('collage #cols:'), self.uiLECollageNc) form.addRow(QLabel('collage #BW:'), self.uiLECollageBW) form.addRow(QLabel('collage #BV:'), self.uiLECollageBV) form.addRow(QLabel('crop:'), self.uiCBCrop) form.addRow(QLabel('crop global:'), self.uiCBCropGlobal) form.addRow(QLabel('annotate:'), self.uiCBAnnotate) form.addRow(QLabel('font size:'), self.uiLEFontSize) form_bottom = QFormLayout() form_bottom.addRow(self.uiPBCopyClipboard) vbox = QVBoxLayout() vbox.addLayout(form) vbox.addItem(QSpacerItem(1, 1, vPolicy=QSizePolicy.Expanding)) vbox.addLayout(form_bottom) hbox = QHBoxLayout() hbox.addWidget(self.canvas) hbox.addLayout(vbox) self.widget.setLayout(hbox) self.setCentralWidget(self.widget) # make image canvas expand with window sp = self.canvas.sizePolicy() sp.setHorizontalStretch(1) sp.setVerticalStretch(1) self.canvas.setSizePolicy(sp) self.ih = self.ax.imshow(np.zeros(self.get_img().shape[:2] + (3, )), origin='upper') self.ax.set_position(Bbox([[0, 0], [1, 1]])) try: self.ax.get_yaxis().set_inverted(True) except Exception: self.ax.invert_yaxis() # keyboard shortcuts #scaleShortcut = QShortcut(QKeySequence('Ctrl+Shift+a'), self.widget) #scaleShortcut.activated.connect(self.autoscale) closeShortcut = QShortcut(QKeySequence('Escape'), self.widget) closeShortcut.activated.connect(self.close) QShortcut(QKeySequence('a'), self.widget).activated.connect(self.autoscale) QShortcut(QKeySequence('Shift+a'), self.widget).activated.connect( self.toggleautoscaleUsePrctiles) #@MyPyQtSlot("bool") def callbackLineEdit(self, ui): try: tmp = float(ui.text()) except: return if ui == self.uiLEScale: self.setScale(tmp) elif ui == self.uiLEGamma: self.setGamma(tmp) elif ui == self.uiLEOffset: self.setOffset(tmp) elif ui == self.uiLEAutoscalePrctile: self.autoscalePrctile = tmp self.autoscale() elif ui == self.uiLECollageNr: self.collage_nr = int(tmp) self.collage() elif ui == self.uiLECollageNc: self.collage_nc = int(tmp) self.collage() elif ui == self.uiLECollageBW: self.collage_border_width = int(tmp) self.collage() elif ui == self.uiLECollageBV: self.collage_border_value = float(tmp) self.collage() elif ui == self.uiLEFontSize: self.font_size = int(tmp) self.updateImage() #@MyPyQtSlot("bool") def callbackCheckBox(self, ui, state): if ui == self.uiCBAutoscaleUsePrctiles: self.autoscaleUsePrctiles = bool(state) if self.autoscaleOnChange: self.autoscale() elif ui == self.uiCBAutoscaleOnChange: self.autoscaleOnChange = bool(state) if self.autoscaleOnChange: self.autoscale() elif ui == self.uiCBAutoscalePerImg: self.autoscalePerImg = bool(state) self.autoscale() elif ui == self.uiCBCollageActive: self.collageActive = bool(state) self.updateImage() elif ui == self.uiCBCollageTranspose: self.collageTranspose = bool(state) self.updateImage() elif ui == self.uiCBCollageTransposeIms: self.collageTransposeIms = bool(state) self.updateImage() elif ui == self.uiCBCrop: self.crop = bool(state) self.updateImage() elif ui == self.uiCBCropGlobal: self.crop_global = bool(state) self.crop_bounds() self.updateImage() elif ui == self.uiCBAnnotate: self.annotate = bool(state) self.updateImage() def callbackPushButton(self, ui): if ui == self.uiPBCopyClipboard: self.copy_to_clipboard() ''' @MyPyQtSlot() def slot_text(self):#, ui=None): ui = self.uiLEScale if ui == self.uiLEScale: print('scale: ' + str(self.scale)) tmp = self.scale try: tmp = float(self.uiLEScale.text()) except ValueError: print('error') self.uiLEScale.setText(str(self.scale)) self.scale = tmp self.updateImage() elif ui == self.uiLEGamma: print('gamma') elif ui == self.uiLEOffset: print('offset') def on_draw(self): """ Redraws the figure """ #self.axes.grid(self.grid_cb.isChecked()) self.canvas.draw() ''' def print_usage(self): print(' ') print('hotkeys: ') print('a: trigger autoscale') print('A: toggle autoscale of [min, max] or ') print(' [prctile_low, prctile_high] -> [0, 1], ') print(' prctiles can be changed via ctrl+shift+wheel') print('c: toggle autoscale on image change') print('G: reset gamma to 1') print('L: create collage by arranging all images in a ') print(' rectangular manner') print('O: reset offset to 0') print('p: toggle per image auto scale limit computations ') print(' (vs. globally over all images)') print('S: reset scale to 1') print('Z: reset zoom to 100%') print('left / right: switch to next / previous image') print('page down / up: go through images in ~10% steps') print('') print('wheel: zoom in / out (inside image axes)') print('wheel: switch to next / previous image') print(' (outside image axes)') print('ctrl + wheel: scale up / down') print('shift + wheel: gamma up / down') print('ctrl + shift + wheel: increase / decrease autoscale') print(' percentiles') print('left mouse dragged: pan image') print('') def get_img(self, i=None): if i is None: i = self.imind im = self.images[i] if self.crop: im = im[self.ymins[i]:self.ymaxs[i], self.xmins[i]:self.xmaxs[i], :] if self.annotate: from pytb.utils import annotate_image im = annotate_image(im, str(i), font_size=self.font_size) return im def get_imgs(self): return [self.get_img(ind) for ind in range(len(self.images))] def copy_to_clipboard(self): from PyQt5.Qt import QImage im = (255 * self.ih.get_array()).astype(np.uint8) h, w, nc = im.shape[:3] im = QImage(im.tobytes(), w, h, nc * w, QImage.Format_RGB888) c = QApplication.clipboard() c.setImage(im) def autoscale(self): # autoscale between user-selected percentiles if self.autoscaleUsePrctiles: if self.autoscalePerImg: lower, upper = np.percentile( self.get_img(), (self.autoscalePrctile, 100 - self.autoscalePrctile)) else: limits = [ np.percentile( image, (self.autoscalePrctile, 100 - self.autoscalePrctile)) for image in self.get_imgs() ] lower = np.min([lims[0] for lims in limits]) upper = np.max([lims[1] for lims in limits]) else: if self.autoscalePerImg: lower = np.min(self.get_img()) upper = np.max(self.get_img()) else: lower = np.min([np.min(image) for image in self.get_imgs()]) upper = np.max([np.max(image) for image in self.get_imgs()]) self.setOffset(lower, False) self.setScale(1. / (upper - lower), True) def toggleautoscaleUsePrctiles(self): self.autoscaleUsePrctiles = not self.autoscaleUsePrctiles self.autoscale() def collage(self): if self.collage_nr * self.collage_nc < self.nims: nc = int(np.ceil(np.sqrt(self.nims))) nr = int(np.ceil(self.nims / nc)) self.collage_nr = nr self.collage_nc = nc self.uiLECollageNr.blockSignals(True) self.uiLECollageNc.blockSignals(True) self.uiLECollageNr.setText(str(nr)) self.uiLECollageNc.setText(str(nc)) self.uiLECollageNr.blockSignals(False) self.uiLECollageNc.blockSignals(False) else: nc = self.collage_nc nr = self.collage_nr # pad array so it matches the product nc * nr padding = nc * nr - self.nims ims = self.get_imgs() h = np.max([im.shape[0] for im in ims]) w = np.max([im.shape[1] for im in ims]) numChans = np.max([im.shape[2] for im in ims]) ims = [ pad(im, new_width=w, new_height=h, new_num_channels=numChans) for im in ims ] ims += [np.zeros((h, w, numChans))] * padding coll = np.stack(ims, axis=3) coll = np.reshape(coll, (h, w, numChans, nc, nr)) # 0 1 2 3 4 # y, x, ch, co, ro if self.collage_border_width: # pad each patch by border if requested coll = np.append( coll, self.collage_border_value * np.ones((self.collage_border_width, ) + coll.shape[1:5]), axis=0) coll = np.append( coll, self.collage_border_value * np.ones((coll.shape[0], self.collage_border_width) + coll.shape[2:5]), axis=1) if self.collageTranspose: nim0 = nr nim1 = nc if self.collageTransposeIms: dim0 = w dim1 = h # nr w nc h ch coll = np.transpose(coll, (4, 1, 3, 0, 2)) else: dim0 = h dim1 = w # nr h nc w ch coll = np.transpose(coll, (4, 0, 3, 1, 2)) else: nim0 = nc nim1 = nr if self.collageTransposeIms: dim0 = w dim1 = h # nc w nr h ch coll = np.transpose(coll, (3, 1, 4, 0, 2)) else: dim0 = h dim1 = w # nc h nr w ch coll = np.transpose(coll, (3, 0, 4, 1, 2)) coll = np.reshape( coll, ((dim0 + self.collage_border_width) * nim0, (dim1 + self.collage_border_width) * nim1, numChans)) #self.ih.set_data(self.tonemap(coll)) self.ax.clear() self.ih = self.ax.imshow(self.tonemap(coll), origin='upper') height, width = self.ih.get_size() lims = (-0.5, width - 0.5, -0.5, height - 0.5) self.ax.set(xlim=lims[0:2], ylim=lims[2:4]) try: self.ax.get_yaxis().set_inverted(True) except Exception: self.ax.invert_yaxis() self.fig.canvas.draw() def switch_to_single_image(self): if self.collageActive: self.ax.clear() self.ih = self.ax.imshow(np.zeros(self.get_img().shape[:3]), origin='upper') self.collageActive = False def reset_zoom(self): height, width = self.ih.get_size() lims = (-0.5, width - 0.5, -0.5, height - 0.5) self.ih.axes.axis(lims) self.ax.set_position(Bbox([[0, 0], [1, 1]])) try: self.ax.get_yaxis().set_inverted(True) except Exception: self.ax.invert_yaxis() self.fig.canvas.draw() def zoom(self, pos, factor): lims = self.ih.axes.axis() xlim = lims[0:2] ylim = lims[2:] # compute interval lengths left, right, below and above cursor left = pos[0] - xlim[0] right = xlim[1] - pos[0] below = pos[1] - ylim[0] above = ylim[1] - pos[1] # zoom in or out if self.x_zoom: xlim = [pos[0] - factor * left, pos[0] + factor * right] if self.y_zoom: ylim = [pos[1] - factor * below, pos[1] + factor * above] # no zooming out beyond original zoom level height, width = self.ih.get_size() if self.x_stop_at_orig: xlim = [ np.maximum(-0.5, xlim[0]), np.minimum(width - 0.5, xlim[1]) ] if self.y_stop_at_orig: ylim = [ np.maximum(-0.5, ylim[0]), np.minimum(height - 0.5, ylim[1]) ] # update axes if xlim[0] != xlim[1] and ylim[0] != ylim[1]: lims = (xlim[0], xlim[1], ylim[0], ylim[1]) self.ih.axes.axis(lims) try: self.ax.get_yaxis().set_inverted(True) except Exception: self.ax.invert_yaxis() self.ax.set_position(Bbox([[0, 0], [1, 1]])) self.fig.canvas.draw() return def tonemap(self, im): if isinstance(im, np.matrix): im = np.array(im) if im.shape[2] == 1: im = np.repeat(im, 3, axis=2) elif im.shape[2] == 2: im = np.concatenate( (im, np.zeros((im.shape[0], im.shape[1], 2), dtype=im.dtype)), axis=2) elif im.shape[2] != 3: # project to RGB raise Exception('spectral to RGB conversion not implemented') return np.power( np.maximum(0., np.minimum(1., (im - self.offset) * self.scale)), 1. / self.gamma) def updateImage(self): if self.collageActive: self.collage() else: if self.nims > 1: self.uiCBCollageActive.blockSignals(True) self.uiCBCollageActive.setChecked(False) self.uiCBCollageActive.blockSignals(False) height, width = self.ih.get_size() im = self.get_img() if height != im.shape[0] or width != im.shape[1]: # image size changed, create new axes self.ax.clear() self.ih = self.ax.imshow(self.tonemap(im)) else: self.ih.set_data(self.tonemap(im)) height, width = self.ih.get_size() lims = (-0.5, width - 0.5, -0.5, height - 0.5) self.ax.set(xlim=lims[0:2], ylim=lims[2:4]) try: self.ax.get_yaxis().set_inverted(True) except Exception: self.ax.invert_yaxis() self.fig.canvas.draw() def setScale(self, scale, update=True): self.scale = scale self.uiLEScale.setText(str(self.scale)) if update: self.updateImage() def setGamma(self, gamma, update=True): self.gamma = gamma self.uiLEGamma.setText(str(self.gamma)) if update: self.updateImage() def setOffset(self, offset, update=True): self.offset = offset self.uiLEOffset.setText(str(self.offset)) if update: self.updateImage() def onclick(self, event): if event.dblclick: self.reset_zoom() self.mouse_down ^= event.button elif event.inaxes: self.x_start = event.xdata self.y_start = event.ydata self.prev_delta_x = 0 self.prev_delta_y = 0 self.cur_xlims = self.ih.axes.axis()[0:2] self.cur_ylims = self.ih.axes.axis()[2:] self.mouse_down |= event.button def onrelease(self, event): self.mouse_down ^= event.button def onmotion(self, event): if self.mouse_down == 1 and event.inaxes: delta_x = self.x_start - event.xdata delta_y = self.y_start - event.ydata self.ih.axes.axis( (self.cur_xlims[0] + delta_x, self.cur_xlims[1] + delta_x, self.cur_ylims[0] + delta_y, self.cur_ylims[1] + delta_y)) self.fig.canvas.draw() self.x_start += (delta_x - self.prev_delta_x) self.y_start += (delta_y - self.prev_delta_y) self.prev_delta_x = delta_x self.prev_delta_y = delta_y def keyPressEvent(self, event): #def onkeypress(self, event): key = event.key() mod = event.modifiers() if key == Qt.Key_Question: # ? self.print_usage() elif key == Qt.Key_A: # a # trigger autoscale self.autoscale() return elif key == Qt.Key_A and mod == Qt.Key_Shift: # A # toggle autoscale between user-selected percentiles or min-max self.autoscaleUsePrctiles = not self.autoscaleUsePrctiles self.autoscale() return elif key == Qt.Key_C: # toggle on-change autoscale self.autoscaleOnChange = not self.autoscaleOnChange print('on-change autoscaling is %s' % ('on' if self.autoscaleOnChange else 'off')) elif key == Qt.Key_G: self.gamma = 1. elif key == Qt.Key_L: # update axes for single image dimensions if self.collageActive: self.switch_to_single_image() else: # toggle showing collage self.collageActive = not self.collageActive # also disable per-image scaling limit computation self.autoscalePerImg = not self.autoscalePerImg elif key == Qt.Key_O: self.offset = 0. elif key == Qt.Key_P: self.autoscalePerImg = not self.autoscalePerImg print('per-image scaling is %s' % ('on' if self.autoscalePerImg else 'off')) self.autoscale() elif key == Qt.Key_S: self.scale = 1. elif key == Qt.Key_Z: # reset zoom self.ih.axes.autoscale(True) elif key == Qt.Key_Alt: self.alt = True self.uiLabelModifiers.setText('alt: %d, ctrl: %d, shift: %d' % (self.alt, self.control, self.shift)) return elif key == Qt.Key_Control: self.control = True self.uiLabelModifiers.setText('alt: %d, ctrl: %d, shift: %d' % (self.alt, self.control, self.shift)) return elif key == Qt.Key_Shift: self.shift = True self.uiLabelModifiers.setText('alt: %d, ctrl: %d, shift: %d' % (self.alt, self.control, self.shift)) return elif key == Qt.Key_Left: self.switch_to_single_image() self.imind = np.mod(self.imind - 1, self.nims) print('image %d / %d' % (self.imind + 1, self.nims)) if self.autoscaleOnChange: self.autoscale() return elif key == Qt.Key_Right: self.switch_to_single_image() self.imind = np.mod(self.imind + 1, self.nims) print('image %d / %d' % (self.imind + 1, self.nims)) if self.autoscaleOnChange: self.autoscale() return else: return self.updateImage() def keyReleaseEvent(self, event): #def onkeyrelease(self, event): key = event.key() if key == Qt.Key_Alt: self.alt = False elif key == Qt.Key_Control: self.control = False elif key == Qt.Key_Shift: self.shift = False self.uiLabelModifiers.setText('alt: %d, ctrl: %d, shift: %d' % (self.alt, self.control, self.shift)) def onscroll(self, event): if self.control and self.shift: # autoscale percentiles self.autoscalePrctile *= np.power(1.1, event.step) self.autoscalePrctile = np.minimum(100, self.autoscalePrctile) print('auto percentiles: [%3.5f, %3.5f]' % (self.autoscalePrctile, 100 - self.autoscalePrctile)) self.autoscaleUsePrctiles = True self.autoscale() elif self.control: # scale #self.setScale(self.scale * np.power(1.1, event.step)) self.setScale(self.scale * np.power(1.1, event.step)) elif self.shift: # gamma self.setGamma(self.gamma * np.power(1.1, event.step)) elif event.inaxes: # zoom when inside image axes factor = np.power(self.zoom_factor, -event.step) self.zoom([event.xdata, event.ydata], factor) return else: # scroll through images when outside of axes self.switch_to_single_image() self.imind = int(np.mod(self.imind - event.step, self.nims)) print('image %d / %d' % (self.imind + 1, self.nims)) if self.autoscaleOnChange: self.autoscale() return self.updateImage() def save(self, ofname): imageio.imwrite(ofname, np.array(self.ih.get_array()))
class QLevels(ZoneDlg): allowedtypes = ("video", ) zonename = "Levels Zone" title = "Levels Editor" def createNewFilterInstance(self): return Levels() def _createControls(self): self.setWindowTitle("Configure Levels Zones") self.rchan = ChannelEditor((128, 0, 0), self) self.gchan = ChannelEditor((0, 128, 0), self) self.bchan = ChannelEditor((0, 0, 128), self) self.rchan.minSpinBox.valueChanged.connect(self.widgetValuesChanged) self.rchan.gammaSpinBox.valueChanged.connect(self.widgetValuesChanged) self.rchan.maxSpinBox.valueChanged.connect(self.widgetValuesChanged) self.gchan.minSpinBox.valueChanged.connect(self.widgetValuesChanged) self.gchan.gammaSpinBox.valueChanged.connect(self.widgetValuesChanged) self.gchan.maxSpinBox.valueChanged.connect(self.widgetValuesChanged) self.bchan.minSpinBox.valueChanged.connect(self.widgetValuesChanged) self.bchan.gammaSpinBox.valueChanged.connect(self.widgetValuesChanged) self.bchan.maxSpinBox.valueChanged.connect(self.widgetValuesChanged) layout = QHBoxLayout(self) self.setLayout(layout) llayout = QVBoxLayout() rlayout = QVBoxLayout() layout.addLayout(llayout) layout.addLayout(rlayout) llayout.addWidget(self.rchan) llayout.addWidget(self.gchan) llayout.addWidget(self.bchan) self.sourceWidget = QWidget(self) self.sourceSelection = self.createSourceControl(self.sourceWidget) self.sourceSelection.currentDataChanged.connect(self.setFilterSource) srclayout = QHBoxLayout() srclayout.addWidget(QLabel("Source: ", self.sourceWidget)) srclayout.addWidget(self.sourceSelection) self.sourceWidget.setLayout(srclayout) rlayout.addWidget(self.sourceWidget) self._createImageView(rlayout) self.imageView.mousePressed.connect(self.setFocus) self._createZoneNavControls(rlayout) self._createZoneControls(rlayout) self._createZoneButtons(rlayout) self._createGlobalControls(rlayout) self._createDlgButtons(rlayout) def _createZoneControls(self, layout=None, index=None): if layout is None: layout = self.layout() self.prevColor = ColorPreview(QColor(), self) self.prevColor.setFixedSize(32, 32) self.prevColorLabel = QLabel("—", self) self.nextColor = ColorPreview(QColor(), self) self.nextColor.setFixedSize(32, 32) self.nextColorLabel = QLabel("—", self) self.transitionCheckBox = QCheckBox("Transition Zone", self) self.transitionCheckBox.stateChanged.connect( self.setCurrentZoneTransition) self.analyzeBtn = QPushButton("Anal&yze Zone", self) self.analyzeBtn.clicked.connect(self.analyzeZone) # 162523 self.gammaLabel = QLabel("Gamma:", self) self.gammaSpinBox = QDoubleSpinBox(self) self.gammaSpinBox.setSingleStep(0.1) self.gammaSpinBox.setDecimals(2) self.gammaSpinBox.setMinimum(0.25) self.gammaSpinBox.setMaximum(4) self.gammaSpinBox.valueChanged.connect(self.widgetValuesChanged) self.suggBtn = QPushButton("&Suggestion", self) self.suggBtn.clicked.connect(self.useAutoGamma) # 162523 inpLabel = QLabel("Input", self) outLabel = QLabel("Output", self) self.redAvgIntensIn = QLabel("Avg Red Intensity: —", self) self.greenAvgIntensIn = QLabel("Avg Green Intensity: —", self) self.blueAvgIntensIn = QLabel("Avg Blue Intensity: —", self) self.redAvgIntensOut = QLabel("Avg Red Intensity: —", self) self.greenAvgIntensOut = QLabel("Avg Green Intensity: —", self) self.blueAvgIntensOut = QLabel("Avg Blue Intensity: —", self) sublayout = QHBoxLayout() sublayout.addStretch() sublayout.addWidget(self.prevColor) sublayout.addWidget(self.prevColorLabel) sublayout.addStretch() sublayout.addWidget(self.nextColor) sublayout.addWidget(self.nextColorLabel) sublayout.addStretch() sublayout.addWidget(self.transitionCheckBox) sublayout.addStretch() sublayout.addWidget(self.analyzeBtn) sublayout.addStretch() sublayout.addWidget(self.gammaLabel) sublayout.addWidget(self.gammaSpinBox) sublayout.addWidget(self.suggBtn) sublayout.addStretch() layout.addLayout(sublayout) sublayout = QHBoxLayout() sublayout.addStretch() sublayout.addWidget(inpLabel) sublayout.addStretch() sublayout.addWidget(self.redAvgIntensIn) sublayout.addStretch() sublayout.addWidget(self.greenAvgIntensIn) sublayout.addStretch() sublayout.addWidget(self.blueAvgIntensIn) sublayout.addStretch() layout.addLayout(sublayout) sublayout = QHBoxLayout() sublayout.addStretch() sublayout.addWidget(outLabel) sublayout.addStretch() sublayout.addWidget(self.redAvgIntensOut) sublayout.addStretch() sublayout.addWidget(self.greenAvgIntensOut) sublayout.addStretch() sublayout.addWidget(self.blueAvgIntensOut) sublayout.addStretch() layout.addLayout(sublayout) self.currentFrame = None self.setFocus(None, None) @pyqtSlot(float, float) def setFocus(self, x, y): self._x = x self._y = y if (self.currentFrame is not None and self._x is not None and self._y is not None): A = self.currentFrame.to_rgb().to_ndarray() h, w, n = A.shape X = arange(w) Y = arange(h) X, Y = meshgrid(X, Y) G = exp(-((X - self._x)**2 + (Y - self._y)**2) / 6) self._ker = G / G.sum() else: self._ker = None self.updateColors() def loadFrame(self, n, t): super().loadFrame(n, t) try: self.updateColors() except Exception: for line in traceback.format_exception(*sys.exc_info()): print(line, file=sys.stderr, end="") def generatePreview(self, n): self.currentFrame = next( self.filtercopy.prev.iterFrames(n, whence="framenumber")) return super().generatePreview(n) def updateColors(self): if (self.currentFrame is not None and self._x is not None and self._y is not None and self._ker is not None): A = self.currentFrame.to_rgb().to_ndarray() avg = int0((moveaxis(A, 2, 0) * self._ker).sum(axis=(1, 2)) + 0.5) R, G, B = avg self.prevColor.setColor(QColor(R, G, B)) self.prevColorLabel.setText(f"({R}, {G}, {B})") N = arange(256, dtype=float64) n = self.slider.slider.value() if (self.transitionCheckBox.checkState() and self.zonecopy.prev is not None and self.zonecopy.next is not None): t = (n - self.zonecopy.prev_start + 1) / \ (self.zonecopy.prev_framecount + 1) rmin = (1 - t)*self.zonecopy.prev.rmin + \ t*self.zonecopy.next.rmin gmin = (1 - t)*self.zonecopy.prev.gmin + \ t*self.zonecopy.next.gmin bmin = (1 - t)*self.zonecopy.prev.bmin + \ t*self.zonecopy.next.bmin rmax = (1 - t)*self.zonecopy.prev.rmax + \ t*self.zonecopy.next.rmax gmax = (1 - t)*self.zonecopy.prev.gmax + \ t*self.zonecopy.next.gmax bmax = (1 - t)*self.zonecopy.prev.bmax + \ t*self.zonecopy.next.bmax rgamma = (1 - t)*self.zonecopy.prev.rgamma + \ t*self.zonecopy.next.rgamma ggamma = (1 - t)*self.zonecopy.prev.ggamma + \ t*self.zonecopy.next.ggamma bgamma = (1 - t)*self.zonecopy.prev.bgamma + \ t*self.zonecopy.next.bgamma gamma = (1 - t)*self.zonecopy.prev.gamma + \ t*self.zonecopy.next.gamma else: rmin = self.rchan.minSpinBox.value() gmin = self.gchan.minSpinBox.value() bmin = self.bchan.minSpinBox.value() rmax = self.rchan.maxSpinBox.value() gmax = self.gchan.maxSpinBox.value() bmax = self.bchan.maxSpinBox.value() rgamma = self.rchan.gammaSpinBox.value() ggamma = self.gchan.gammaSpinBox.value() bgamma = self.bchan.gammaSpinBox.value() gamma = self.gammaSpinBox.value() RR = (N.clip(min=rmin, max=rmax) - rmin) / (rmax - rmin) RR = 1 - (1 - RR)**(rgamma * gamma) RR = uint8((256 * RR).clip(max=255) + 0.5) GG = (N.clip(min=gmin, max=gmax) - gmin) / (gmax - gmin) GG = 1 - (1 - GG)**(ggamma * gamma) GG = uint8((256 * GG).clip(max=255) + 0.5) BB = (N.clip(min=bmin, max=bmax) - bmin) / (bmax - bmin) BB = 1 - (1 - BB)**(bgamma * gamma) BB = uint8((256 * BB).clip(max=255) + 0.5) R = RR[R] G = GG[G] B = BB[B] self.nextColor.setColor(QColor(R, G, B)) self.nextColorLabel.setText(f"({R}, {G}, {B})") def analyzeZone(self): dlg = ZoneAnalysis(self.zonecopy, self) dlg.exec_() self.zoneModified() if self.zonecopy.histogram is not None: self.rchan.setHistogram(self.zonecopy.histogram[0]) self.gchan.setHistogram(self.zonecopy.histogram[1]) self.bchan.setHistogram(self.zonecopy.histogram[2]) self.suggBtn.setEnabled(True) gamma = self.autogamma() self.suggBtn.setText(f"Suggestion: {gamma:.2f}") def autogamma(self): zone = self.zonecopy a = arange(0, 256, 0.25) Ia = -log(1 - a / 256) r, g, b = self.rchan.minSpinBox.value(), self.gchan.minSpinBox.value( ), self.bchan.minSpinBox.value() R, G, B = self.rchan.maxSpinBox.value(), self.gchan.maxSpinBox.value( ), self.bchan.maxSpinBox.value() rg, gg, bg = self.rchan.gammaSpinBox.value( ), self.gchan.gammaSpinBox.value(), self.bchan.gammaSpinBox.value() IR = -log(1 - (a.clip(min=r, max=R + 0.75) - r) / (R + 1 - r)) * rg IG = -log(1 - (a.clip(min=g, max=G + 0.75) - g) / (G + 1 - g)) * gg IB = -log(1 - (a.clip(min=b, max=B + 0.75) - b) / (B + 1 - b)) * bg gamma = (((Ia * zone.histogram[0]).sum() + (Ia * zone.histogram[1]).sum() + (Ia * zone.histogram[2]).sum()) / ((IR * zone.histogram[0]).sum() + (IG * zone.histogram[1]).sum() + (IB * zone.histogram[2]).sum())) return float(gamma) def useAutoGamma(self): gamma = self.autogamma() self.gammaSpinBox.setValue(gamma) def setCurrentZoneTransition(self, state): flag = state == Qt.Unchecked self.rchan.setEnabled(flag) self.gchan.setEnabled(flag) self.bchan.setEnabled(flag) self.gammaSpinBox.setEnabled(flag) self.widgetValuesChanged() def _resetZoneControls(self): zone = self.zonecopy if self.zonecopy.transition: self.transitionCheckBox.blockSignals(True) self.transitionCheckBox.setChecked(True) self.transitionCheckBox.blockSignals(False) self.transitionCheckBox.setEnabled(True) self.rchan.setEnabled(False) self.gchan.setEnabled(False) self.bchan.setEnabled(False) self.gammaSpinBox.setEnabled(False) self.rchan.setHistogram(None) self.gchan.setHistogram(None) self.bchan.setHistogram(None) else: self.transitionCheckBox.blockSignals(True) self.transitionCheckBox.setChecked(False) self.transitionCheckBox.blockSignals(False) self.transitionCheckBox.setEnabled( self.zone not in (self.zone.parent.start, self.zone.parent.end) and not (self.zone.prev.transition or self.zone.next.transition)) self.rchan.setEnabled(True) self.gchan.setEnabled(True) self.bchan.setEnabled(True) self.gammaSpinBox.setEnabled(True) self.rchan.minSpinBox.blockSignals(True) self.rchan.minSpinBox.setValue(zone.rmin) self.rchan.histogram.setClipMinimum(zone.rmin) self.rchan.histogram.setGamma(zone.rgamma * zone.gamma) self.rchan.minSpinBox.blockSignals(False) self.rchan.maxSpinBox.blockSignals(True) self.rchan.maxSpinBox.setValue(zone.rmax) self.rchan.histogram.setClipMaximum(zone.rmax) self.rchan.maxSpinBox.blockSignals(False) self.rchan.gammaSpinBox.blockSignals(True) self.rchan.gammaSpinBox.setValue(zone.rgamma) self.rchan.gammaSpinBox.blockSignals(False) self.gchan.minSpinBox.blockSignals(True) self.gchan.minSpinBox.setValue(zone.gmin) self.gchan.histogram.setClipMinimum(zone.gmin) self.gchan.minSpinBox.blockSignals(False) self.gchan.maxSpinBox.blockSignals(True) self.gchan.maxSpinBox.setValue(zone.gmax) self.gchan.histogram.setClipMaximum(zone.gmax) self.gchan.histogram.setGamma(zone.ggamma * zone.gamma) self.gchan.maxSpinBox.blockSignals(False) self.gchan.gammaSpinBox.blockSignals(True) self.gchan.gammaSpinBox.setValue(zone.ggamma) self.gchan.gammaSpinBox.blockSignals(False) self.bchan.minSpinBox.blockSignals(True) self.bchan.minSpinBox.setValue(zone.bmin) self.bchan.histogram.setClipMinimum(zone.bmin) self.bchan.minSpinBox.blockSignals(False) self.bchan.maxSpinBox.blockSignals(True) self.bchan.maxSpinBox.setValue(zone.bmax) self.bchan.histogram.setClipMaximum(zone.bmax) self.bchan.histogram.setGamma(zone.bgamma * zone.gamma) self.bchan.maxSpinBox.blockSignals(False) self.bchan.gammaSpinBox.blockSignals(True) self.bchan.gammaSpinBox.setValue(zone.bgamma) self.bchan.gammaSpinBox.blockSignals(False) self.gammaSpinBox.blockSignals(True) self.gammaSpinBox.setValue(zone.gamma) self.gammaSpinBox.blockSignals(False) self.updateStats() def updateStats(self): if self.zonecopy.histogram is not None: R, G, B = self.zonecopy.histogram self.rchan.setHistogram(R) self.gchan.setHistogram(G) self.bchan.setHistogram(B) self.suggBtn.setEnabled(True) gamma = self.autogamma() self.suggBtn.setText(f"Suggestion: {gamma:.2f}") if not self.zonecopy.transition: N = arange(0, 256, 0.25) Ia = -log(1 - N / 256) / log(2) rmin = self.zonecopy.rmin rmax = self.zonecopy.rmax Nr = (N.clip(min=rmin, max=rmax - 0.25) - rmin) / (rmax - rmin) Ir = -self.zonecopy.gamma * \ self.zonecopy.rgamma*log(1 - Nr)/log(2) gmin = self.zonecopy.gmin gmax = self.zonecopy.gmax Ng = (N.clip(min=gmin, max=gmax - 0.25) - gmin) / (gmax - gmin) Ig = -self.zonecopy.gamma * \ self.zonecopy.ggamma*log(1 - Ng)/log(2) bmin = self.zonecopy.bmin bmax = self.zonecopy.bmax Nb = (N.clip(min=bmin, max=bmax - 0.25) - bmin) / (bmax - bmin) Ib = -self.zonecopy.gamma * \ self.zonecopy.bgamma*log(1 - Nb)/log(2) self.redAvgIntensIn.setText( f"Avg Red Intensity: {(Ia*R).sum()/R.sum():.2f}") self.greenAvgIntensIn.setText( f"Avg Green Intensity: {(Ia*G).sum()/G.sum():.2f}") self.blueAvgIntensIn.setText( f"Avg Blue Intensity: {(Ia*B).sum()/B.sum():.2f}") self.redAvgIntensOut.setText( f"Avg Red Intensity: {(Ir*R).sum()/R.sum():.2f}") self.greenAvgIntensOut.setText( f"Avg Green Intensity: {(Ig*G).sum()/G.sum():.2f}") self.blueAvgIntensOut.setText( f"Avg Blue Intensity: {(Ib*B).sum()/B.sum():.2f}") else: self.redAvgIntensOut.setText("Avg Red Intensity: —") self.greenAvgIntensOut.setText("Avg Green Intensity: —") self.blueAvgIntensOut.setText("Avg Blue Intensity: —") self.redAvgIntensIn.setText("Avg Red Intensity: —") self.greenAvgIntensIn.setText("Avg Green Intensity: —") self.blueAvgIntensIn.setText("Avg Blue Intensity: —") else: self.rchan.setHistogram(None) self.gchan.setHistogram(None) self.bchan.setHistogram(None) self.suggBtn.setEnabled(False) self.suggBtn.setText("No Suggestion") self.redAvgIntensOut.setText("Avg Red Intensity: —") self.greenAvgIntensOut.setText("Avg Green Intensity: —") self.blueAvgIntensOut.setText("Avg Blue Intensity: —") self.redAvgIntensIn.setText("Avg Red Intensity: —") self.greenAvgIntensIn.setText("Avg Green Intensity: —") self.blueAvgIntensIn.setText("Avg Blue Intensity: —") def updateZoneValues(self): self.zonecopy.transition = bool(self.transitionCheckBox.checkState()) if self.zonecopy is not None and not self.zonecopy.transition: self.zonecopy.rmin = self.rchan.minSpinBox.value() self.zonecopy.rgamma = self.rchan.gammaSpinBox.value() self.zonecopy.rmax = self.rchan.maxSpinBox.value() self.zonecopy.gmin = self.gchan.minSpinBox.value() self.zonecopy.ggamma = self.gchan.gammaSpinBox.value() self.zonecopy.gmax = self.gchan.maxSpinBox.value() self.zonecopy.bmin = self.bchan.minSpinBox.value() self.zonecopy.bgamma = self.bchan.gammaSpinBox.value() self.zonecopy.bmax = self.bchan.maxSpinBox.value() self.zonecopy.gamma = self.gammaSpinBox.value() self.updateStats() self.loadFrame(self.slider.slider.value(), self.slider.currentTime.time()) def widgetValuesChanged(self): self.updateColors() self.updateZoneValues() self.zoneModified() zone = self.zonecopy self.rchan.histogram.setGamma(zone.rgamma * zone.gamma) self.gchan.histogram.setGamma(zone.ggamma * zone.gamma) self.bchan.histogram.setGamma(zone.bgamma * zone.gamma) def apply(self): self.updateZoneValues() super().apply()
class PropertyWidget(QWidget): value_changed = pyqtSignal(object) """display widget for tcam property""" def __init__(self, data: TcamCaptureData, prop: Prop, app_property: bool = False): super().__init__() self.app_property = app_property self.tcam = data.tcam self.signals = data.signals self.prop = prop self.is_log = False self.setup_ui() def __repr__(self): return repr((self.prop.name, self.prop.valuetype, self.prop.category, self.prop.group)) def __setup_ui_boolean(self): """ Helper function that contains all setup code for bool UIs """ self.toggle = QCheckBox(self) self.toggle.setCheckable(True) if self.prop.value: self.toggle.toggle() self.toggle.toggled.connect(self.button_clicked) self.layout.addWidget(self.toggle) def __setup_ui_integer(self): """ """ self.value_box = TcamSpinBox.TcamSpinBox(self) try: self.value_box.setRange(self.prop.minval, self.prop.maxval) except OverflowError: log.error("Property {} reported a range " "that could not be handled".format(self.prop.name)) self.value_box.setSingleStep(self.prop.step) self.value_box.blockSignals(True) self.value_box.setValue(self.prop.value) self.value_box.blockSignals(False) self.value_box.valueChanged[int].connect(self.set_property_box) self.value_box.setKeyboardTracking(False) if self.is_log: log.debug("Adding log slider for {}".format(self.prop.name)) self.sld = TcamSlider.TcamLogSlider(self) self.sld.valueLogChanged.connect(self.set_property) else: self.sld = TcamSlider.TcamSlider(self) self.sld.valueChanged[int].connect(self.set_property) self.sld.setFocusPolicy(Qt.NoFocus) try: self.sld.blockSignals(True) self.sld.setRange(self.prop.minval, self.prop.maxval) self.sld.setValue(self.prop.value) self.sld.blockSignals(False) except OverflowError: log.error("Property {} reported a range " "that could not be handled".format(self.prop.name)) self.sld.setSingleStep(self.prop.step) self.sld.doubleClicked.connect(self.reset) self.layout.addWidget(self.sld) self.layout.addWidget(self.value_box) def __setup_ui_double(self): """ Helper function that contains all setup code for doube UIs """ self.value_box = TcamSpinBox.TcamDoubleSpinBox(self) try: self.value_box.setRange(self.prop.minval, self.prop.maxval) except OverflowError: log.error("Property {} reported a range " "that could not be handled".format(self.prop.name)) self.value_box.setSingleStep(self.prop.step) self.value_box.blockSignals(True) self.value_box.setValue(self.prop.value) self.value_box.blockSignals(False) self.value_box.valueChanged[float].connect(self.set_property_box) self.value_box.setKeyboardTracking(False) if self.is_log: self.sld = TcamSlider.TcamLogSlider(self) self.sld.valueLogChanged.connect(self.set_property) else: self.sld = TcamSlider.TcamSlider(self) self.sld.valueChanged[int].connect(self.set_property) self.sld.setFocusPolicy(Qt.NoFocus) try: self.sld.blockSignals(True) self.sld.setRange(int(self.prop.minval * 100), int(self.prop.maxval * 100)) self.sld.setValue(int(self.prop.value * 100)) self.sld.blockSignals(False) except OverflowError: log.warning("Property {} reported a range " "that could not be handled min: {} max: {}".format( self.prop.name, self.prop.minval, self.prop.maxval)) self.sld.setSingleStep(int(self.prop.step * 100)) self.sld.doubleClicked.connect(self.reset) self.sld.setGeometry(30, 40, 100, 30) self.layout.addWidget(self.sld) self.layout.addWidget(self.value_box) def setup_ui(self): self.layout = QHBoxLayout() def should_be_logarithmic(prop): """ Returns True when the range is > 5000 """ if prop.valuetype == "integer": if (prop.maxval - prop.minval) >= 5000: return True elif prop.valuetype == "double": if (prop.maxval - prop.minval) >= 5000: return True return False self.setLayout(self.layout) self.is_log = should_be_logarithmic(self.prop) if self.prop.valuetype == "integer": self.__setup_ui_integer() elif self.prop.valuetype == "double": self.__setup_ui_double() elif self.prop.valuetype == "button": self.checkbox = QPushButton(self) self.checkbox.clicked.connect(self.set_property) self.layout.addWidget(self.checkbox) elif self.prop.valuetype == "boolean": self.__setup_ui_boolean() elif self.prop.valuetype == "string": pass elif self.prop.valuetype == "enum": self.combo = QComboBox(self) entry_list = self.tcam.get_tcam_menu_entries(self.prop.name) for e in entry_list: self.combo.addItem(e) self.combo.setCurrentText(self.prop.value) self.combo.currentIndexChanged['QString'].connect( self.set_property) self.layout.addWidget(self.combo) def button_clicked(self): log.debug("button clicked") self.signals.change_property.emit(self.tcam, self.prop.name, self.toggle.isChecked(), self.prop.valuetype) self.value_changed.emit(self) def set_property(self, value, emit_value_changed=True): self.prop.value = value if self.prop.valuetype == "integer": self.update_box_value(self.value_box, value) if self.prop.valuetype == "double": self.update_box_value(self.value_box, value / 100) self.signals.change_property.emit(self.tcam, self.prop.name, float(value / 100), self.prop.valuetype) return self.signals.change_property.emit(self.tcam, self.prop.name, value, self.prop.valuetype) if emit_value_changed: self.value_changed.emit(self) def set_property_box(self, value): if self.prop.valuetype == "integer": self.update_slider_value(self.sld, value) if self.prop.valuetype == "double": self.update_slider_value(self.sld, value) self.signals.change_property.emit(self.tcam, self.prop.name, float(value), self.prop.valuetype) return self.signals.change_property.emit(self.tcam, self.prop.name, value, self.prop.valuetype) self.value_changed.emit(self) def update_box_value(self, box, value): box.blockSignals(True) box.setValue(value) box.blockSignals(False) def update_box_range(self, box, minval, maxval): """""" box.blockSignals(True) box.setRange(self.prop.minval, self.prop.maxval) box.blockSignals(False) def update_slider_value(self, slider, value): slider.blockSignals(True) try: if self.prop.valuetype == "double": slider.setValue(int(value * 100)) else: slider.setValue(value) except OverflowError: log.info("The slider for '{}' had a value outside of the integer " "range. That should no happen.".format(self.prop.name)) finally: slider.blockSignals(False) def update_slider_range(self, slider, minval, maxval): """""" self.sld.blockSignals(True) try: if self.prop.valuetype == "double": self.sld.setRange(self.prop.minval * 100, self.prop.maxval * 100) else: self.sld.setRange(self.prop.minval, self.prop.maxval) except OverflowError: log.error("The slider for '{}' had a value outside of the integer " "range. That should no happen. " "Min: '{}' Max: {}".format(self.prop.name, self.prop.minval, self.prop.maxval)) finally: self.sld.blockSignals(False) def update(self, prop: Prop): emit_value_changed = False if self.prop.value != prop.value: emit_value_changed = True self.prop = prop if self.prop.valuetype == "integer": if type(self.value_box) is TcamSpinBox.TcamSpinBox: if self.value_box.active(): # box.setValue(value) return self.update_slider_value(self.sld, self.prop.value) self.update_slider_range(self.sld, self.prop.minval, self.prop.maxval) self.update_box_range(self.value_box, self.prop.minval, self.prop.maxval) self.update_box_value(self.value_box, self.prop.value) elif self.prop.valuetype == "double": self.update_slider_range(self.sld, self.prop.minval, self.prop.maxval) self.update_slider_value(self.sld, self.prop.value) self.update_box_range(self.value_box, self.prop.minval, self.prop.maxval) self.update_box_value(self.value_box, self.prop.value) elif self.prop.valuetype == "button": pass elif self.prop.valuetype == "boolean": if self.prop.value and not self.toggle.isChecked(): self.toggle.blockSignals(True) self.toggle.toggle() self.toggle.blockSignals(False) elif self.prop.valuetype == "string": pass elif self.prop.valuetype == "enum": self.combo.blockSignals(True) self.combo.setCurrentText(prop.value) self.combo.blockSignals(False) if emit_value_changed: self.value_changed.emit(self) def reset(self): if self.prop.valuetype == "integer": self.update_box_value(self.value_box, self.prop.defval) self.update_slider_value(self.sld, self.prop.defval) elif self.prop.valuetype == "double": self.update_box_value(self.value_box, self.prop.defval) self.update_slider_value(self.sld, self.prop.defval) elif self.prop.valuetype == "button": pass elif self.prop.valuetype == "boolean": if self.prop.defval and not self.toggle.isChecked(): self.toggle.toggle() elif self.prop.valuetype == "string": pass elif self.prop.valuetype == "enum": self.combo.setCurrentText(self.prop.defval) self.value_changed.emit(self) self.signals.change_property.emit(self.tcam, self.prop.name, self.prop.defval, self.prop.valuetype)
class LaserRangeFinderV2(COMCUPluginBase): def __init__(self, *args): super().__init__(BrickletLaserRangeFinderV2, *args) self.lrf = self.device self.cbe_distance = CallbackEmulator(self.lrf.get_distance, None, self.cb_distance, self.increase_error_count) self.cbe_velocity = CallbackEmulator(self.lrf.get_velocity, None, self.cb_velocity, self.increase_error_count) self.current_distance = CurveValueWrapper() # int, cm self.current_velocity = CurveValueWrapper() # float, m/s plots_distance = [('Distance', Qt.red, self.current_distance, format_distance)] plots_velocity = [('Velocity', Qt.red, self.current_velocity, '{:.2f} m/s'.format)] self.plot_widget_distance = PlotWidget('Distance [cm]', plots_distance, y_resolution=1.0) self.plot_widget_velocity = PlotWidget('Velocity [m/s]', plots_velocity, y_resolution=0.01) self.label_average_distance = QLabel('Moving Average for Distance:') self.spin_average_distance = QSpinBox() self.spin_average_distance.setMinimum(0) self.spin_average_distance.setMaximum(255) self.spin_average_distance.setSingleStep(1) self.spin_average_distance.setValue(10) self.spin_average_distance.editingFinished.connect(self.spin_average_finished) self.label_average_velocity = QLabel('Moving Average for Velocity:') self.spin_average_velocity = QSpinBox() self.spin_average_velocity.setMinimum(0) self.spin_average_velocity.setMaximum(255) self.spin_average_velocity.setSingleStep(1) self.spin_average_velocity.setValue(10) self.spin_average_velocity.editingFinished.connect(self.spin_average_finished) self.enable_laser = QCheckBox("Enable Laser") self.enable_laser.stateChanged.connect(self.enable_laser_changed) self.label_acquisition_count = QLabel('Acquisition Count:') self.spin_acquisition_count = QSpinBox() self.spin_acquisition_count.setMinimum(1) self.spin_acquisition_count.setMaximum(255) self.spin_acquisition_count.setSingleStep(1) self.spin_acquisition_count.setValue(128) self.enable_qick_termination = QCheckBox("Quick Termination") self.label_threshold = QLabel('Threshold:') self.threshold = QCheckBox("Automatic Threshold") self.spin_threshold = QSpinBox() self.spin_threshold.setMinimum(1) self.spin_threshold.setMaximum(255) self.spin_threshold.setSingleStep(1) self.spin_threshold.setValue(1) self.label_frequency = QLabel('Frequency [Hz]:') self.frequency = QCheckBox("Automatic Frequency (Disable for Velocity)") self.spin_frequency = QSpinBox() self.spin_frequency.setMinimum(10) self.spin_frequency.setMaximum(500) self.spin_frequency.setSingleStep(1) self.spin_frequency.setValue(10) self.spin_acquisition_count.editingFinished.connect(self.configuration_changed) self.enable_qick_termination.stateChanged.connect(self.configuration_changed) self.spin_threshold.editingFinished.connect(self.configuration_changed) self.threshold.stateChanged.connect(self.configuration_changed) self.spin_frequency.editingFinished.connect(self.configuration_changed) self.frequency.stateChanged.connect(self.configuration_changed) layout_h1 = QHBoxLayout() layout_h1.addWidget(self.plot_widget_distance) layout_h1.addWidget(self.plot_widget_velocity) layout_h2 = QHBoxLayout() layout_h2.addWidget(self.label_average_distance) layout_h2.addWidget(self.spin_average_distance) layout_h2.addWidget(self.label_average_velocity) layout_h2.addWidget(self.spin_average_velocity) layout_h2.addStretch() layout_h2.addWidget(self.enable_laser) layout_h3 = QHBoxLayout() layout_h3.addWidget(self.label_frequency) layout_h3.addWidget(self.spin_frequency) layout_h3.addWidget(self.frequency) layout_h3.addStretch() layout_h3.addWidget(self.enable_qick_termination) layout_h4 = QHBoxLayout() layout_h4.addWidget(self.label_threshold) layout_h4.addWidget(self.spin_threshold) layout_h4.addWidget(self.threshold) layout_h4.addStretch() layout_h4.addWidget(self.label_acquisition_count) layout_h4.addWidget(self.spin_acquisition_count) self.widgets_distance = [self.plot_widget_distance, self.spin_average_distance, self.label_average_distance] self.widgets_velocity = [self.plot_widget_velocity, self.spin_average_velocity, self.label_average_velocity] line = QFrame() line.setObjectName("line") line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addLayout(layout_h1) layout.addWidget(line) layout.addLayout(layout_h2) layout.addLayout(layout_h3) layout.addLayout(layout_h4) def start(self): async_call(self.lrf.get_configuration, None, self.get_configuration_async, self.increase_error_count) async_call(self.lrf.get_enable, None, self.enable_laser.setChecked, self.increase_error_count) async_call(self.lrf.get_moving_average, None, self.get_moving_average_async, self.increase_error_count) self.cbe_distance.set_period(25) self.cbe_velocity.set_period(25) self.plot_widget_distance.stop = False self.plot_widget_velocity.stop = False def stop(self): self.cbe_distance.set_period(0) self.cbe_velocity.set_period(0) self.plot_widget_distance.stop = True self.plot_widget_velocity.stop = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletLaserRangeFinderV2.DEVICE_IDENTIFIER def enable_laser_changed(self, state): self.lrf.set_enable(state == Qt.Checked) def cb_distance(self, distance): self.current_distance.value = distance def cb_velocity(self, velocity): self.current_velocity.value = velocity / 100.0 def configuration_changed(self): acquisition_count = self.spin_acquisition_count.value() enable_quick_termination = self.enable_qick_termination.isChecked() if self.threshold.isChecked(): threshold = 0 else: threshold = self.spin_threshold.value() if self.frequency.isChecked(): frequency = 0 for w in self.widgets_velocity: w.hide() else: frequency = self.spin_frequency.value() for w in self.widgets_velocity: w.show() self.spin_threshold.setDisabled(threshold == 0) self.spin_frequency.setDisabled(frequency == 0) self.lrf.set_configuration(acquisition_count, enable_quick_termination, threshold, frequency) def get_configuration_async(self, conf): self.spin_acquisition_count.blockSignals(True) self.spin_acquisition_count.setValue(conf.acquisition_count) self.spin_acquisition_count.blockSignals(False) self.enable_qick_termination.blockSignals(True) self.enable_qick_termination.setChecked(conf.enable_quick_termination) self.enable_qick_termination.blockSignals(False) self.spin_threshold.blockSignals(True) self.spin_threshold.setValue(conf.threshold_value) self.spin_threshold.setDisabled(conf.threshold_value == 0) self.spin_threshold.blockSignals(False) self.spin_frequency.blockSignals(True) self.spin_frequency.setValue(conf.measurement_frequency) self.spin_frequency.setDisabled(conf.measurement_frequency == 0) self.spin_frequency.blockSignals(False) self.threshold.blockSignals(True) self.threshold.setChecked(conf.threshold_value == 0) self.threshold.blockSignals(False) self.frequency.blockSignals(True) self.frequency.setChecked(conf.measurement_frequency == 0) self.frequency.blockSignals(False) self.configuration_changed() def get_moving_average_async(self, avg): self.spin_average_distance.setValue(avg.distance_average_length) self.spin_average_velocity.setValue(avg.velocity_average_length) def spin_average_finished(self): self.lrf.set_moving_average(self.spin_average_distance.value(), self.spin_average_velocity.value())
class QCrossFade(QFilterConfig): allowedtypes = ("video", "audio") def _createControls(self): self.setWindowTitle("Configure Crossfade") layout = QVBoxLayout(self) self.setLayout(layout) self.sourceWidget = QWidget(self) self.source1Selection = self.createSourceControl(self.sourceWidget) self.source1Selection.setSelectFunc(self.isValidSource1) self.source1Selection.currentDataChanged.connect(self.setFilterSource1) self.source1Fade = QCheckBox("Fade Out", self) self.source1Fade.stateChanged.connect(self.setSource1Fade) self.source2Selection = self.createSourceControl(self.sourceWidget) self.source2Selection.setSelectFunc(self.isValidSource2) self.source2Selection.currentDataChanged.connect(self.setFilterSource2) self.source2Fade = QCheckBox("Fade In", self) self.source2Fade.stateChanged.connect(self.setSource2Fade) srclayout = QVBoxLayout() src1layout = QHBoxLayout() src2layout = QHBoxLayout() srclayout.addLayout(src1layout) srclayout.addLayout(src2layout) src1layout.addWidget(QLabel("Source 1: ", self.sourceWidget)) src1layout.addWidget(self.source1Selection) src1layout.addWidget(self.source1Fade) src2layout.addWidget(QLabel("Source 2: ", self.sourceWidget)) src2layout.addWidget(self.source2Selection) src2layout.addWidget(self.source2Fade) self.sourceWidget.setLayout(srclayout) layout.addWidget(self.sourceWidget) self.imageView = QImageView(self) self.frameSelect = QFrameSelect(self) self.frameSelect.frameSelectionChanged.connect( self.handleFrameSelectionChange) layout.addWidget(self.imageView) layout.addWidget(self.frameSelect) self._prepareDlgButtons() def _resetSourceModels(self): self._resetSourceModel(self.source1Selection) self._resetSourceModel(self.source2Selection) @pyqtSlot(int, QTime) def handleFrameSelectionChange(self, n, t): self.setFrame(n) def setSource1Fade(self, value): if value: self.filtercopy.flags &= ~1 else: self.filtercopy.flags |= 1 if (self.filtercopy.prev is not None and self.filtercopy.prev.type == "video"): self.setFrame(self.frameSelect.slider.value()) self.isModified() def setSource2Fade(self, value): if value: self.filtercopy.flags &= ~2 else: self.filtercopy.flags |= 2 if (self.filtercopy.prev is not None and self.filtercopy.prev.type == "video"): self.setFrame(self.frameSelect.slider.value()) self.isModified() def setFrame(self, n): try: frame = next(self.filtercopy.iterFrames(n, whence="framenumber")) except StopIteration: self.imageView.setFrame( QPixmap(self.filtercopy.width, self.filtercopy.height)) return im = frame.to_image() pixmap = im.convert("RGBA").toqpixmap() self.imageView.setFrame(pixmap) def createNewFilterInstance(self): return CrossFade() def _resetSourceControls(self): self._showSourceControls(self.inputFiles or self.availableFilters) self._setSourceSelection(self.source1Selection, self.filtercopy.source1) self._setSourceSelection(self.source2Selection, self.filtercopy.source2) def _resetControls(self): if self.filtercopy is not None: self.source1Fade.blockSignals(True) self.source1Fade.setCheckState(0 if ( 1 & self.filtercopy.flags) else 2) self.source1Fade.blockSignals(False) self.source2Fade.blockSignals(True) self.source2Fade.setCheckState(0 if ( 2 & self.filtercopy.flags) else 2) self.source2Fade.blockSignals(False) self.frameSelect.setVisible(self.filtercopy.type == "video") self.imageView.setVisible(self.filtercopy.type == "video") if self.filtercopy.type == "video": self.frameSelect.setPtsTimeArray(self.filtercopy.pts_time) self.setFrame(0) self.setEnabled(True) else: self.source1Fade.blockSignals(True) self.source1Fade.setCheckState(2) self.source1Fade.blockSignals(False) self.source2Fade.blockSignals(True) self.source2Fade.setCheckState(2) self.source2Fade.blockSignals(False) self.frameSelect.setVisible(False) self.imageView.setVisible(False) self.setEnabled(False) def setFilterSource1(self, source): self.imageView.setVisible(source is not None and source.type == "video") self.filtercopy.source1 = source self.isModified() if (source is not None and self.filtercopy.source2 is not None and source.type == "video"): self.frameSelect.setPtsTimeArray(source.pts_time) self.setFrame(self.frameSelect.slider.value()) def setFilterSource2(self, source): self.imageView.setVisible(source is not None and source.type == "video") self.filtercopy.source2 = source self.isModified() if (source is not None and self.filtercopy.source1 is not None and source.type == "video"): self.frameSelect.setPtsTimeArray(source.pts_time) self.setFrame(self.frameSelect.slider.value()) def isValidSource1(self, other): if other is self.filter: return False if (isinstance(other, BaseFilter) and self.filter in other.dependencies): return False if self.filtercopy.source2 is None: return other.type in ("video", "audio") if other.type is None: return True elif self.filtercopy.source2.type == "video": return (self.filtercopy.source2.framecount == other.framecount and self.filtercopy.source2.width == other.width and self.filtercopy.source2.height == other.height and (abs(self.filtercopy.source2.pts_time - other.pts_time) < 0.008).all()) elif self.filtercopy.source2.type == "audio": return (self.filtercopy.source2.channels == other.channels and abs(self.filtercopy.source2.duration - other.duration) < 0.00001) def isValidSource2(self, other): if other is self.filter: return False if isinstance(other, BaseFilter) and self.filter in other.dependencies: return False if other.type is None: return True if self.filtercopy.source1 is None: return other.type in ("video", "audio") elif self.filtercopy.source1.type == "video": return (self.filtercopy.source1.framecount == other.framecount and self.filtercopy.source1.width == other.width and self.filtercopy.source1.height == other.height and (abs(self.filtercopy.source1.pts_time - other.pts_time) < 0.008).all()) elif self.filtercopy.source1.type == "audio": return (self.filtercopy.source1.channels == other.channels and abs(self.filtercopy.source1.duration - other.duration) < 0.00001)
class PropertyWidget(QWidget): value_changed = pyqtSignal(object) """display widget for tcam property""" def __init__(self, data: TcamCaptureData, prop: Prop, app_property: bool=False): super().__init__() self.app_property = app_property self.tcam = data.tcam self.signals = data.signals self.prop = prop self.setup_ui() def __repr__(self): return repr((self.prop.name, self.prop.valuetype, self.prop.category, self.prop.group)) def setup_ui(self): self.layout = QHBoxLayout() self.setLayout(self.layout) if self.prop.valuetype == "integer": self.sld = QSlider(Qt.Horizontal, self) self.sld.setFocusPolicy(Qt.NoFocus) try: self.sld.setRange(self.prop.minval, self.prop.maxval) self.sld.setValue(self.prop.value) except OverflowError: log.error("Property {} reported a range that could not be handled".format(self.prop.name)) self.sld.setSingleStep(self.prop.step) self.sld.valueChanged[int].connect(self.set_property) self.layout.addWidget(self.sld) self.value_box = QSpinBox(self) try: self.value_box.setRange(self.prop.minval, self.prop.maxval) except OverflowError: log.error("Property {} reported a range that could not be handled".format(self.prop.name)) self.value_box.setSingleStep(self.prop.step) self.value_box.setValue(self.prop.value) self.value_box.valueChanged[int].connect(self.set_property_box) self.value_box.setKeyboardTracking(False) self.layout.addWidget(self.value_box) elif self.prop.valuetype == "double": self.sld = QSlider(Qt.Horizontal, self) self.sld.setFocusPolicy(Qt.NoFocus) try: self.sld.setRange(self.prop.minval, self.prop.maxval) self.sld.setValue(self.prop.value) except OverflowError: log.error("Property {} reported a range that could not be handled".format(self.prop.name)) self.sld.setSingleStep(self.prop.step * 1000) self.sld.valueChanged[int].connect(self.set_property) self.sld.setGeometry(30, 40, 100, 30) self.layout.addWidget(self.sld) self.value_box = QDoubleSpinBox(self) try: self.value_box.setRange(self.prop.minval, self.prop.maxval) except OverflowError: log.error("Property {} reported a range that could not be handled".format(self.prop.name)) self.value_box.setSingleStep(self.prop.step) self.value_box.setValue(self.prop.value) self.value_box.valueChanged[float].connect(self.set_property_box) self.value_box.setKeyboardTracking(False) self.layout.addWidget(self.value_box) elif self.prop.valuetype == "button": self.checkbox = QPushButton(self) self.checkbox.clicked.connect(self.set_property) self.layout.addWidget(self.checkbox) elif self.prop.valuetype == "boolean": self.toggle = QCheckBox(self) self.toggle.setCheckable(True) if self.prop.value: self.toggle.toggle() self.toggle.toggled.connect(self.button_clicked) self.layout.addWidget(self.toggle) elif self.prop.valuetype == "string": pass elif self.prop.valuetype == "enum": self.combo = QComboBox(self) entry_list = self.tcam.get_tcam_menu_entries(self.prop.name) for e in entry_list: self.combo.addItem(e) self.combo.setCurrentText(self.prop.value) self.combo.currentIndexChanged['QString'].connect(self.set_property) self.layout.addWidget(self.combo) def button_clicked(self): log.debug("button clicked") self.signals.change_property.emit(self.tcam, self.prop.name, self.toggle.isChecked(), self.prop.valuetype) self.value_changed.emit(self) def set_property(self, value, emit_value_changed=True): self.prop.value = value if self.prop.valuetype == "integer": self.update_box_value(self.value_box, value) if self.prop.valuetype == "double": self.update_box_value(self.value_box, value) self.signals.change_property.emit(self.tcam, self.prop.name, float(value), self.prop.valuetype) return self.signals.change_property.emit(self.tcam, self.prop.name, value, self.prop.valuetype) if emit_value_changed: self.value_changed.emit(self) def set_property_box(self, value): if self.prop.valuetype == "integer": self.update_slider_value(self.sld, value) if self.prop.valuetype == "double": self.update_slider_value(self.sld, value) self.signals.change_property.emit(self.tcam, self.prop.name, float(value), self.prop.valuetype) return self.signals.change_property.emit(self.tcam, self.prop.name, value, self.prop.valuetype) self.value_changed.emit(self) def update_box_value(self, box, value): box.blockSignals(True) box.setValue(value) box.blockSignals(False) def update_box_range(self, box, minval, maxval): """""" box.blockSignals(True) box.setRange(self.prop.minval, self.prop.maxval) box.blockSignals(False) def update_slider_value(self, slider, value): slider.blockSignals(True) try: slider.setValue(value) except OverflowError: log.error("A slider had a value outside of the integer range. That should no happen.") finally: slider.blockSignals(False) def update_slider_range(self, slider, minval, maxval): """""" self.sld.blockSignals(True) try: self.sld.setRange(self.prop.minval, self.prop.maxval) except OverflowError: log.error("A slider had a value outside of the integer range. That should no happen.") finally: self.sld.blockSignals(False) def update(self, prop: Prop): emit_value_changed = False if self.prop.value != prop.value: emit_value_changed = True self.prop = prop if self.prop.valuetype == "integer": self.update_slider_value(self.sld, self.prop.value) self.update_slider_range(self.sld, self.prop.minval, self.prop.maxval) self.update_box_range(self.value_box, self.prop.minval, self.prop.maxval) self.update_box_value(self.value_box, self.prop.value) elif self.prop.valuetype == "double": self.update_slider_range(self.sld, self.prop.minval, self.prop.maxval) self.update_slider_value(self.sld, self.prop.value) self.update_box_range(self.value_box, self.prop.minval, self.prop.maxval) self.update_box_value(self.value_box, self.prop.value) elif self.prop.valuetype == "button": pass elif self.prop.valuetype == "boolean": if self.prop.value and not self.toggle.isChecked(): self.toggle.blockSignals(True) self.toggle.toggle() self.toggle.blockSignals(False) elif self.prop.valuetype == "string": pass elif self.prop.valuetype == "enum": self.combo.blockSignals(True) self.combo.setCurrentText(prop.value) self.combo.blockSignals(False) if emit_value_changed: self.value_changed.emit(self) def reset(self): if self.prop.valuetype == "integer": self.update_box_value(self.value_box, self.prop.defval) self.sld.setValue(self.prop.defval) elif self.prop.valuetype == "double": self.update_box_value(self.value_box, self.prop.defval) self.sld.setValue(self.prop.defval * 1000) elif self.prop.valuetype == "button": pass elif self.prop.valuetype == "boolean": if self.prop.defval and not self.toggle.isChecked(): self.toggle.toggle() elif self.prop.valuetype == "string": pass elif self.prop.valuetype == "enum": self.combo.setCurrentText(self.prop.defval) self.value_changed.emit(self)
class AnalyizeDataWindow(QWidget): def __init__(self): super().__init__() self.setGeometry(100, 100, 500, 200) self.setWindowTitle("Analyze Datafile") self.layout = QGridLayout() # self.rangeDict = {"Default" : [[0,1],[0,100],[0,100], # [0,100],[0,100],[0,1]]} self.dataAnalDict = {} # self.dataAnalDict['force settings'] = {} self.dataAnalDict['Vertical force'] = {} self.dataAnalDict['Lateral force'] = {} self.initialize_dict("Default", range_clear=True) self.dataAnalDict['misc settings'] = {} self.home() #call this when your are adding a new roi label. #initialize force settings in dict def initialize_dict(self, roi_label, range_clear=True): # self.dataAnalDict['force settings'][roi_label] = {} # self.init_force_dict(roi_label, "Vertical force") # self.init_force_dict(roi_label, "Lateral force") if range_clear == True: self.dataAnalDict["Vertical force"]["ranges"] = {} self.dataAnalDict["Lateral force"]["ranges"] = {} self.init_force_dict("Vertical force", roi_label) self.init_force_dict("Lateral force", roi_label) #initialize sub properties of force def init_force_dict(self, force, roi_label): self.dataAnalDict[force]["ranges"][roi_label] = {} self.dataAnalDict[force]["ranges"][roi_label]["Zero"] = "100,200" self.dataAnalDict[force]["ranges"][roi_label]["Force"] = "100,200" self.dataAnalDict[force]["ranges"][roi_label]["Preload"] = "100,200" self.dataAnalDict[force]["transform"] = {} self.dataAnalDict[force]["transform"]["Filter"] = False self.dataAnalDict[force]["transform"]["Filter window"] = 43 self.dataAnalDict[force]["transform"]["Filter order"] = 2 self.dataAnalDict[force]["transform"]["Cross Talk"] = 0 self.dataAnalDict[force]["transform"]["Zero subtract"] = False # self.dataAnalDict['force settings'][roi_label][force] = {} # self.dataAnalDict['force settings'][roi_label][force]["Zero"] = "0,10" # self.dataAnalDict['force settings'][roi_label][force]["Force"] = "0,10" # self.dataAnalDict['force settings'][roi_label][force]["Preload"] = "0,10" # self.dataAnalDict['force settings'][roi_label][force]["Filter"] = False # self.dataAnalDict['force settings'][roi_label][force]["Filter window"] = 43 # self.dataAnalDict['force settings'][roi_label][force]["Filter order"] = 2 # self.dataAnalDict['force settings'][roi_label][force]["Cross Talk"] = 0 def home(self): # self.showContactArea = QCheckBox('contact area', self) #contact area # self.showContactArea.setChecked(True) # self.showROIArea = QCheckBox('ROI area', self) #roi area # self.showContactLength = QCheckBox('contact length', self) #contact length # self.showROILength = QCheckBox('ROI length', self) #roi length # self.showContactNumber = QCheckBox('contact number', self) #contact number # self.showEcc = QCheckBox('eccentricity', self) #median eccentricity # self.showLateralForce = QCheckBox('lateral force', self) #lateral force # self.showZPiezo = QCheckBox('vertical piezo', self) #z piezo # self.showXPiezo = QCheckBox('lateral piezo', self) #x piezo # self.showAdhesion = QCheckBox('adhesion calculation', self) #adhesion/preload calc line # self.showFriction = QCheckBox('friction calculation', self) #friction calc lines # self.showStress = QCheckBox('stress', self) #stress # self.showDeformation = QCheckBox('deformation', self) #deformation # self.showTitle = QCheckBox('title', self) #plt title # self.showTitle.setChecked(True) # self.showLegend2 = QCheckBox('legend2', self) #plt title # self.showLegend2.setChecked(True) # self.showWidgets = [self.showContactArea, self.showROIArea, self.showZPiezo, # self.showXPiezo, self.showAdhesion, self.showFriction, # self.showLateralForce, self.showContactLength, self.showROILength, # self.showContactNumber, self.showEcc, self.showStress, # self.showDeformation, self.showTitle, self.showLegend2] # self.xAxisLabel = QLabel("<b>X Axis:</b>", self) # self.xAxisParam = QComboBox(self) #x axis parameter # self.xAxisParam.addItem("Time (s)") # self.xAxisParam.addItem("Vertical Position (μm)") # self.xAxisParam.addItem("Lateral Position (μm)") # self.xAxisParam.addItem("Deformation (μm)") # self.fontLabel = QLabel("Font Size:", self) # self.fontSize = QDoubleSpinBox(self) #vertical force zero range start # self.fontSize.setValue(12) # self.fontSize.setSingleStep(1) # self.fontSize.setRange(1, 100) roiChoiceLabel = QLabel("ROI Label:", self) self.roiChoice = QComboBox(self) #choose ROI self.roiChoice.addItem("Default") self.roiChoice.setCurrentIndex(0) self.roiChoice.currentIndexChanged.connect(self.update_widgets) dataChoiceLabel = QLabel("Data:", self) self.dataChoice = QComboBox(self) #force data self.dataChoiceDict = { "Vertical force": "Adhesion", "Lateral force": "Friction" } self.dataChoice.addItems(list(self.dataChoiceDict.keys())) self.dataChoice.setCurrentIndex(0) self.dataChoice.currentIndexChanged.connect(self.update_widgets) self.zeroBtn = QPushButton("Zero Range", self) #zero self.zeroLabel = QLineEdit(self) self.zeroLabel.setReadOnly(True) self.zeroLabel.setText("100,200") self.forceBtn = QPushButton( self.dataChoiceDict[self.dataChoice.currentText()] + " Range", self) #adhesion/friction self.forceLabel = QLineEdit(self) self.forceLabel.setReadOnly(True) self.forceLabel.setText("100,200") self.preloadBtn = QPushButton("Preload Range", self) #preload self.preloadLabel = QLineEdit(self) self.preloadLabel.setReadOnly(True) self.preloadLabel.setText("100,200") # self.startLabel = QLabel("Start (%):", self) # self.endLabel = QLabel("End (%):", self) # self.zeroLabel = QLabel("Zero Range", self) # self.adhLabel = QLabel("Adhesion Range", self) # self.prl1Label = QLabel("Preload Range", self) # self.zeroRange1 = QDoubleSpinBox(self) #vertical force zero range start # self.zeroRange1.setValue(0) # self.zeroRange1.setSingleStep(1) # self.zeroRange1.setRange(0, 100) # self.zeroRange1.valueChanged.connect(self.update_dict) # self.zeroRange2 = QDoubleSpinBox(self) #vertical force zero range end # self.zeroRange2.setValue(1) # self.zeroRange2.setSingleStep(1) # self.zeroRange2.setRange(0, 100) # self.zeroRange2.valueChanged.connect(self.update_dict) # self.adhRange1 = QDoubleSpinBox(self) #adhesion peak range start # self.adhRange1.setValue(0) # self.adhRange1.setSingleStep(1) # self.adhRange1.setRange(0, 100) # self.adhRange1.valueChanged.connect(self.update_dict) # self.adhRange2 = QDoubleSpinBox(self) #adhesion peak range start # self.adhRange2.setValue(100) # self.adhRange2.setSingleStep(1) # self.adhRange2.setRange(0, 100) # self.adhRange2.valueChanged.connect(self.update_dict) # self.prl1Range1 = QDoubleSpinBox(self) #preload peak range start # self.prl1Range1.setValue(0) # self.prl1Range1.setSingleStep(1) # self.prl1Range1.setRange(0, 100) # self.prl1Range1.valueChanged.connect(self.update_dict) # self.prl1Range2 = QDoubleSpinBox(self) #preload peak range start # self.prl1Range2.setValue(100) # self.prl1Range2.setSingleStep(1) # self.prl1Range2.setRange(0, 100) # self.prl1Range2.valueChanged.connect(self.update_dict) # self.zero2Range1 = QDoubleSpinBox(self) #lateral force zero range start # self.zero2Range1.setValue(0) # self.zero2Range1.setSingleStep(1) # self.zero2Range1.setRange(0, 100) # self.zero2Range1.valueChanged.connect(self.update_dict) # self.zero2Range2 = QDoubleSpinBox(self) #lateral force zero range end # self.zero2Range2.setValue(1) # self.zero2Range2.setSingleStep(1) # self.zero2Range2.setRange(0, 100) # self.zero2Range2.valueChanged.connect(self.update_dict) # self.filterLatF = QCheckBox('Filter stress curve', self) #filter self.filter = QCheckBox('Filter', self) #filter # self.filter.stateChanged.connect(self.update_dict) windLabel = QLabel("Window Length:", self) self.filter_wind = QSpinBox(self) #filter window self.filter_wind.setValue(43) self.filter_wind.setSingleStep(20) self.filter_wind.setRange(3, 10001) # self.filter_wind.valueChanged.connect(self.filter_change) polyLabel = QLabel("Polynomial Order:", self) self.filter_poly = QSpinBox(self) #filter polynom self.filter_poly.setValue(2) self.filter_poly.setSingleStep(1) self.filter_poly.setRange(1, 20000) # self.filter_poly.valueChanged.connect(self.update_dict) self.zero_subtract = QCheckBox('Zero subtract', self) #filter # self.startLabel2 = QLabel("Start (%):", self) # self.endLabel2 = QLabel("End (%):", self) # self.frLabel = QLabel("Friction Range", self) # self.prl2Label = QLabel("Preload Range", self) # self.zero2Label = QLabel("Zero Range", self) eqLabel = QLabel("Lateral Calib. Equation (μN):", self) self.latCalibEq = QLineEdit(self) #lateral force calib equation self.latCalibEq.setText("29181.73*x") noiseStepsLabel = QLabel("Noisy Steps:", self) noiseSteps = QLineEdit(self) #remove first data point from steps noiseSteps.setText("") # self.legendPosLabel = QLabel("Legend:", self) #legend position # self.legendPos = QLineEdit(self) # self.legendPos.setText("upper right") # self.startFullLabel = QLabel("Start (%):", self) # self.endFullLabel = QLabel("End (%):", self) # self.startFull = QDoubleSpinBox(self) #plot range start # self.startFull.setValue(0) # self.startFull.setSingleStep(1) # self.startFull.setRange(0, 100) # self.endFull = QDoubleSpinBox(self) #plot range end # self.endFull.setValue(100) # self.endFull.setSingleStep(1) # self.endFull.setRange(0, 100) # self.invertLatForce = QCheckBox('Invert Lateral Force', self) #invert applyCrossTalk = QCheckBox('Apply Cross Talk', self) #cross talk flag # self.zeroShift = QCheckBox('Shift to Zero', self) #force curve shift to zero # self.vertCrossTalk = QDoubleSpinBox(self) #vertical cross talk slope # self.vertCrossTalk.setValue(0) # self.vertCrossTalk.setSingleStep(0.1) # self.vertCrossTalk.setDecimals(4) # self.vertCrossTalk.setRange(-1000, 1000) # self.vertCTlabel = QLabel("Cross Talk (μN/μN):", self) # self.latCrossTalk = QDoubleSpinBox(self) #lateral cross talk slope # self.latCrossTalk.setValue(0) # self.latCrossTalk.setSingleStep(0.1) # self.latCrossTalk.setDecimals(4) # self.latCrossTalk.setRange(-1000, 1000) # self.latCTlabel = QLabel("Cross Talk (μN/μN):", self) CTlabel = QLabel("Cross Talk (μN/μN):", self) # cross talk slope self.crossTalk = QDoubleSpinBox(self) self.crossTalk.setValue(0) self.crossTalk.setSingleStep(0.1) self.crossTalk.setDecimals(4) self.crossTalk.setRange(-1000, 1000) # self.crossTalk.valueChanged.connect(self.update_dict) # self.frictionRange1 = QDoubleSpinBox(self) #friction range start # self.frictionRange1.setValue(0) # self.frictionRange1.setSingleStep(1) # self.frictionRange1.setRange(0, 100) # self.frictionRange1.valueChanged.connect(self.update_dict) # self.frictionRange2 = QDoubleSpinBox(self) #friction range end # self.frictionRange2.setValue(100) # self.frictionRange2.setSingleStep(1) # self.frictionRange2.setRange(0, 100) # self.frictionRange2.valueChanged.connect(self.update_dict) # self.prl2Range1 = QDoubleSpinBox(self) #friction preload peak range start # self.prl2Range1.setValue(0) # self.prl2Range1.setSingleStep(1) # self.prl2Range1.setRange(0, 100) # self.prl2Range1.valueChanged.connect(self.update_dict) # self.prl2Range2 = QDoubleSpinBox(self) #friction preload peak range start # self.prl2Range2.setValue(100) # self.prl2Range2.setSingleStep(1) # self.prl2Range2.setRange(0, 100) # self.prl2Range2.valueChanged.connect(self.update_dict) # self.fitPosLabel = QLabel("Fit Position\n(x,y):", self) #fit eq. position # self.fitPos = QLineEdit(self) # self.fitPos.setText('0.5,0.5') # self.showFitEq = QCheckBox('Show Slope', self) #display equation on plot kBeamLabel = QLabel("Beam Spring Constant (μN/μm):", self) #beam dpring constant kBeam = QLineEdit(self) kBeam.setText('30,1') # deformStartLabel = QLabel("Deformation Start:", self) #contact start tolerance auto detect self.deformBtn = QPushButton("Deformation Range", self) #deformation self.deformLabel = QLineEdit(self) self.deformLabel.setReadOnly(True) # self.deformLabel.textChanged.connect(self.updateRange) self.deformLabel.setText("100,200") # self.deformStart = QSpinBox(self) # self.deformStart.setValue(100) # self.deformStart.setSingleStep(1) # self.deformStart.setRange(0, 10000) # self.dataAnalDict['misc'] = {} self.dataAnalDict['misc settings']['apply cross talk'] = applyCrossTalk self.dataAnalDict['misc settings']['noise steps'] = noiseSteps self.dataAnalDict['misc settings'][ 'deformation range'] = self.deformLabel self.dataAnalDict['misc settings']['beam spring constant'] = kBeam self.okBtn = QPushButton("OK", self) #Close window self.updateBtn = QPushButton("Update", self) #Update #update dictionary on widget value change self.zeroLabel.textChanged.connect(self.update_dict) self.forceLabel.textChanged.connect(self.update_dict) self.preloadLabel.textChanged.connect(self.update_dict) self.filter.stateChanged.connect(self.update_dict) self.filter_wind.valueChanged.connect(self.filter_change) self.filter_poly.valueChanged.connect(self.update_dict) self.zero_subtract.stateChanged.connect(self.update_dict) self.crossTalk.valueChanged.connect(self.update_dict) self.zeroLabel.textChanged.connect(self.update_dict) self.forceLabel.textChanged.connect(self.update_dict) self.preloadLabel.textChanged.connect(self.update_dict) # self.zeroGroupBox = QGroupBox("Configure Vertical Force") # filterGroupBox = QGroupBox("Configure Plot") # flagGroupBox = QGroupBox("Show") # self.latCalibGroupBox = QGroupBox("Configure Lateral Force") # self.fittingGroupBox = QGroupBox("Fit Data") forceGroupBox = QGroupBox("Force") miscGroupBox = QGroupBox("Misc") buttonGroupBox = QGroupBox() forceGroupBox.setStyleSheet("QGroupBox { font-weight: bold; } ") miscGroupBox.setStyleSheet("QGroupBox { font-weight: bold; } ") # self.zeroGroupBox.setStyleSheet("QGroupBox { font-weight: bold; } ") # filterGroupBox.setStyleSheet("QGroupBox { font-weight: bold; } ") # flagGroupBox.setStyleSheet("QGroupBox { font-weight: bold; } ") # self.latCalibGroupBox.setStyleSheet("QGroupBox { font-weight: bold; } ") # self.fittingGroupBox.setStyleSheet("QGroupBox { font-weight: bold; } ") # self.fittingGroupBox.setCheckable(True) # self.fittingGroupBox.setChecked(False) # self.layout.addWidget(self.roiChoice, 0, 0, 1, 2) # self.layout.addWidget(self.zeroGroupBox, 1, 0) # self.layout.addWidget(filterGroupBox, 2, 1) # self.layout.addWidget(flagGroupBox, 2, 0) # self.layout.addWidget(self.latCalibGroupBox, 1, 1) # self.layout.addWidget(self.fittingGroupBox, 3, 0) self.layout.addWidget(forceGroupBox, 0, 0) self.layout.addWidget(miscGroupBox, 1, 0) self.layout.addWidget(buttonGroupBox, 2, 0) self.setLayout(self.layout) buttonVbox = QGridLayout() buttonGroupBox.setLayout(buttonVbox) buttonVbox.addWidget(self.updateBtn, 0, 0) buttonVbox.addWidget(self.okBtn, 0, 1) forceLayout = QGridLayout() forceGroupBox.setLayout(forceLayout) forceLayout.addWidget(roiChoiceLabel, 0, 0, 1, 1) forceLayout.addWidget(self.roiChoice, 0, 1, 1, 1) forceLayout.addWidget(dataChoiceLabel, 0, 2, 1, 1) forceLayout.addWidget(self.dataChoice, 0, 3, 1, 1) forceLayout.addWidget(self.zeroBtn, 1, 0, 1, 1) forceLayout.addWidget(self.zeroLabel, 1, 1, 1, 1) forceLayout.addWidget(self.forceBtn, 2, 0, 1, 1) forceLayout.addWidget(self.forceLabel, 2, 1, 1, 1) forceLayout.addWidget(self.preloadBtn, 3, 0, 1, 1) forceLayout.addWidget(self.preloadLabel, 3, 1, 1, 1) forceLayout.addWidget(self.filter, 1, 2, 1, 2) forceLayout.addWidget(windLabel, 2, 2, 1, 1) forceLayout.addWidget(self.filter_wind, 2, 3, 1, 1) forceLayout.addWidget(polyLabel, 3, 2, 1, 1) forceLayout.addWidget(self.filter_poly, 3, 3, 1, 1) forceLayout.addWidget(self.zero_subtract, 4, 2, 1, 2) forceLayout.addWidget(CTlabel, 4, 0, 1, 1) forceLayout.addWidget(self.crossTalk, 4, 1, 1, 1) miscLayout = QGridLayout() miscGroupBox.setLayout(miscLayout) miscLayout.addWidget(applyCrossTalk, 0, 0, 1, 2) miscLayout.addWidget(self.deformBtn, 1, 0, 1, 1) miscLayout.addWidget(self.deformLabel, 1, 1, 1, 1) miscLayout.addWidget(noiseStepsLabel, 0, 2, 1, 1) miscLayout.addWidget(noiseSteps, 0, 3, 1, 1) miscLayout.addWidget(kBeamLabel, 1, 2, 1, 1) miscLayout.addWidget(kBeam, 1, 3, 1, 1) miscLayout.addWidget(eqLabel, 2, 0, 1, 1) #remove miscLayout.addWidget(self.latCalibEq, 2, 1, 1, 1) #remove # miscLayout.addWidget(self.zeroShift, 2, 2, 1, 2) #remove # zeroVbox = QGridLayout() # self.zeroGroupBox.setLayout(zeroVbox) # zeroVbox.addWidget(self.zeroLabel, 0, 1, 1, 1) # zeroVbox.addWidget(self.adhLabel, 0, 2, 1, 1) # zeroVbox.addWidget(self.prl1Label, 0, 3, 1, 1) # zeroVbox.addWidget(self.startLabel, 1, 0, 1, 1) # zeroVbox.addWidget(self.endLabel, 2, 0, 1, 1) # zeroVbox.addWidget(self.zeroRange1, 1, 1, 1, 1) # zeroVbox.addWidget(self.zeroRange2, 2, 1, 1, 1) # zeroVbox.addWidget(self.adhRange1, 1, 2, 1, 1) # zeroVbox.addWidget(self.adhRange2, 2, 2, 1, 1) # zeroVbox.addWidget(self.prl1Range1, 1, 3, 1, 1) # zeroVbox.addWidget(self.prl1Range2, 2, 3, 1, 1) # zeroVbox.addWidget(self.vertCTlabel, 3, 0, 1, 1) # zeroVbox.addWidget(self.vertCrossTalk, 3, 1, 1, 1) # filterVbox = QGridLayout() # filterGroupBox.setLayout(filterVbox) # filterVbox.addWidget(self.filterLatF, 1, 0, 1, 2) # filterVbox.addWidget(self.windLabel, 2, 0, 1, 1) # filterVbox.addWidget(self.filter_wind, 2, 1, 1, 1) # filterVbox.addWidget(self.polyLabel, 3, 0, 1, 1) # filterVbox.addWidget(self.filter_poly, 3, 1, 1, 1) # # filterVbox.addWidget(self.fontLabel, 2, 2, 1, 1) # # filterVbox.addWidget(self.fontSize, 2, 3, 1, 1) # filterVbox.addWidget(self.eqLabel, 3, 2, 1, 1) # filterVbox.addWidget(self.latCalibEq, 3, 3, 1, 1) # # filterVbox.addWidget(self.invertLatForce, 0, 2, 1, 2) # filterVbox.addWidget(self.zeroShift, 0, 0, 1, 1) # filterVbox.addWidget(self.applyCrossTalk, 1, 2, 1, 2) # # filterVbox.addWidget(self.xAxisLabel, 0, 3, 1, 1) # # filterVbox.addWidget(self.xAxisParam, 1, 3, 1, 1) # filterVbox.addWidget(self.noiseStepsLabel, 4, 2, 1, 1) # filterVbox.addWidget(self.noiseSteps, 5, 2, 1, 1) # # filterVbox.addWidget(self.legendPosLabel, 4, 3, 1, 1) # # filterVbox.addWidget(self.legendPos, 5, 3, 1, 1) # # filterVbox.addWidget(self.startFullLabel, 4, 0, 1, 1) # # filterVbox.addWidget(self.endFullLabel, 5, 0, 1, 1) # # filterVbox.addWidget(self.startFull, 4, 1, 1, 1) # # filterVbox.addWidget(self.endFull, 5, 1, 1, 1) # filterVbox.addWidget(self.kBeamLabel, 6, 2, 1, 1) # filterVbox.addWidget(self.kBeam, 6, 3, 1, 1) # filterVbox.addWidget(self.deformStartLabel, 6, 0, 1, 1) # filterVbox.addWidget(self.deformStart, 6, 1, 1, 1) # flagVbox = QGridLayout() # flagGroupBox.setLayout(flagVbox) # flagVbox.addWidget(self.showContactArea, 0, 0) # flagVbox.addWidget(self.showROIArea, 0, 1) # flagVbox.addWidget(self.showZPiezo, 0, 2) # flagVbox.addWidget(self.showXPiezo, 1, 0) # flagVbox.addWidget(self.showAdhesion, 1, 1) # flagVbox.addWidget(self.showFriction, 1, 2) # flagVbox.addWidget(self.showLateralForce, 2, 0) # flagVbox.addWidget(self.showContactLength, 2, 1) # flagVbox.addWidget(self.showROILength, 2, 2) # flagVbox.addWidget(self.showContactNumber, 3, 0) # flagVbox.addWidget(self.showEcc, 3, 1) # flagVbox.addWidget(self.showStress, 3, 2) # flagVbox.addWidget(self.showDeformation, 4, 0) # flagVbox.addWidget(self.showTitle, 4, 1) # flagVbox.addWidget(self.showLegend2, 4, 2) # lastCalibVbox = QGridLayout() # self.latCalibGroupBox.setLayout(lastCalibVbox) # lastCalibVbox.addWidget(self.frLabel, 0, 1, 1, 1) # lastCalibVbox.addWidget(self.prl2Label, 0, 2, 1, 1) # lastCalibVbox.addWidget(self.zero2Label, 0, 3, 1, 1) # lastCalibVbox.addWidget(self.startLabel2, 1, 0, 1, 1) # lastCalibVbox.addWidget(self.frictionRange1, 1, 1, 1, 1) # lastCalibVbox.addWidget(self.endLabel2, 2, 0, 1, 1) # lastCalibVbox.addWidget(self.frictionRange2, 2, 1, 1, 1) # lastCalibVbox.addWidget(self.prl2Range1, 1, 2, 1, 1) # lastCalibVbox.addWidget(self.prl2Range2, 2, 2, 1, 1) # lastCalibVbox.addWidget(self.zero2Range1, 1, 3, 1, 1) # lastCalibVbox.addWidget(self.zero2Range2, 2, 3, 1, 1) # lastCalibVbox.addWidget(self.latCTlabel, 3, 0, 1, 1) # lastCalibVbox.addWidget(self.latCrossTalk, 3, 1, 1, 1) # fittingVbox = QGridLayout() # self.fittingGroupBox.setLayout(fittingVbox) # fittingVbox.addWidget(self.startFitLabel, 0, 0, 1, 1) # fittingVbox.addWidget(self.endFitLabel, 1, 0, 1, 1) # fittingVbox.addWidget(self.fitStart, 0, 1, 1, 1) # fittingVbox.addWidget(self.fitStop, 1, 1, 1, 1) # fittingVbox.addWidget(self.xFitLabel, 0, 2, 1, 1) # fittingVbox.addWidget(self.yFitLabel, 1, 2, 1, 1) # fittingVbox.addWidget(self.xFit, 0, 3, 1, 1) # fittingVbox.addWidget(self.yFit, 1, 3, 1, 1) # fittingVbox.addWidget(self.fitPosLabel, 0, 4, 1, 1) # fittingVbox.addWidget(self.fitPos, 0, 5, 1, 1) # fittingVbox.addWidget(self.showFitEq, 1, 4, 1, 2) def filter_change(self): if self.filter_wind.value() % 2 == 0: #make sure its odd self.filter_wind.blockSignals(True) self.filter_wind.setValue(self.filter_wind.value() + 1) self.filter_wind.blockSignals(False) self.update_dict() # def update_range(self): # key = self.roiChoice.currentText() # if key not in self.rangeDict.keys(): # key = "Default" # self.zeroRange1.blockSignals(True) # self.zeroRange1.setValue(self.rangeDict[key][0][0]) # self.zeroRange1.blockSignals(False) # self.zeroRange2.blockSignals(True) # self.zeroRange2.setValue(self.rangeDict[key][0][1]) # self.zeroRange2.blockSignals(False) # self.adhRange1.blockSignals(True) # self.adhRange1.setValue(self.rangeDict[key][1][0]) # self.adhRange1.blockSignals(False) # self.adhRange2.blockSignals(True) # self.adhRange2.setValue(self.rangeDict[key][1][1]) # self.adhRange2.blockSignals(False) # self.prl1Range1.blockSignals(True) # self.prl1Range1.setValue(self.rangeDict[key][2][0]) # self.prl1Range1.blockSignals(False) # self.prl1Range2.blockSignals(True) # self.prl1Range2.setValue(self.rangeDict[key][2][1]) # self.prl1Range2.blockSignals(False) # self.frictionRange1.blockSignals(True) # self.frictionRange1.setValue(self.rangeDict[key][3][0]) # self.frictionRange1.blockSignals(False) # self.frictionRange2.blockSignals(True) # self.frictionRange2.setValue(self.rangeDict[key][3][1]) # self.frictionRange2.blockSignals(False) # self.prl2Range1.blockSignals(True) # self.prl2Range1.setValue(self.rangeDict[key][4][0]) # self.prl2Range1.blockSignals(False) # self.prl2Range2.blockSignals(True) # self.prl2Range2.setValue(self.rangeDict[key][4][1]) # self.prl2Range2.blockSignals(False) # self.zero2Range1.blockSignals(True) # self.zero2Range1.setValue(self.rangeDict[key][5][0]) # self.zero2Range1.blockSignals(False) # self.zero2Range2.blockSignals(True) # self.zero2Range2.setValue(self.rangeDict[key][5][1]) # self.zero2Range2.blockSignals(False) def update_widgets(self): self.forceBtn.setText( self.dataChoiceDict[self.dataChoice.currentText()] + " Range") # range_dict = self.dataAnalDict['force settings'][self.roiChoice.currentText()][self.dataChoice.currentText()] range_dict = self.dataAnalDict[self.dataChoice.currentText( )]["ranges"][self.roiChoice.currentText()] transform_dict = self.dataAnalDict[ self.dataChoice.currentText()]["transform"] self.zeroLabel.blockSignals(True) self.zeroLabel.setText(range_dict["Zero"]) self.zeroLabel.blockSignals(False) self.forceLabel.blockSignals(True) self.forceLabel.setText(range_dict["Force"]) self.forceLabel.blockSignals(False) self.preloadLabel.blockSignals(True) self.preloadLabel.setText(range_dict["Preload"]) self.preloadLabel.blockSignals(False) self.filter.blockSignals(True) self.filter.setChecked(transform_dict["Filter"]) self.filter.blockSignals(False) self.filter_wind.blockSignals(True) self.filter_wind.setValue(transform_dict["Filter window"]) self.filter_wind.blockSignals(False) self.filter_poly.blockSignals(True) self.filter_poly.setValue(transform_dict["Filter order"]) self.filter_poly.blockSignals(False) self.zero_subtract.blockSignals(True) self.zero_subtract.setChecked(transform_dict["Zero subtract"]) self.zero_subtract.blockSignals(False) self.crossTalk.blockSignals(True) self.crossTalk.setValue(transform_dict["Cross Talk"]) self.crossTalk.blockSignals(False) def update_dict(self): # range_dict = self.dataAnalDict['force settings'][self.roiChoice.currentText()][self.dataChoice.currentText()] range_dict = self.dataAnalDict[self.dataChoice.currentText( )]["ranges"][self.roiChoice.currentText()] transform_dict = self.dataAnalDict[ self.dataChoice.currentText()]["transform"] range_dict["Zero"] = self.zeroLabel.text() range_dict["Force"] = self.forceLabel.text() range_dict["Preload"] = self.preloadLabel.text() transform_dict["Filter"] = self.filter.isChecked() transform_dict["Filter window"] = self.filter_wind.value() transform_dict["Filter order"] = self.filter_poly.value() transform_dict["Zero subtract"] = self.zero_subtract.isChecked() transform_dict["Cross Talk"] = self.crossTalk.value() # self.rangeDict[self.roiChoice.currentText()] = [[self.zeroRange1.value(), # self.zeroRange2.value()], # [self.adhRange1.value(), # self.adhRange2.value()], # [self.prl1Range1.value(), # self.prl1Range2.value()], # [self.frictionRange1.value(), # self.frictionRange2.value()], # [self.prl2Range1.value(), # self.prl2Range2.value()], # [self.zero2Range1.value(), # self.zero2Range2.value()]] logging.debug('%s', self.dataAnalDict) def show_window(self): #show window # self.update_range() self.update_dict() self.show()
class ApplicationPage(QWidget): """ The GUI for the application page of a project. """ # The page's label. label = "Application Source" # Emitted when the user changes the PyQt version. pyqt_version_changed = pyqtSignal(bool) # Emitted when the user changes the Python target version. python_target_version_changed = pyqtSignal() @property def project(self): """ The project property getter. """ return self._project @project.setter def project(self, value): """ The project property setter. """ if self._project != value: self._project = value self._script_edit.set_project(value) self._package_edit.set_project(value) self._update_page() def __init__(self): """ Initialise the page. """ super().__init__() self._project = None # Create the page's GUI. layout = QGridLayout() form = BetterForm() self._name_edit = QLineEdit( placeholderText="Application name", whatsThis="The name of the application. It will default to " "the base name of the application script without any " "extension.", textEdited=self._name_changed) form.addRow("Name", self._name_edit) self._script_edit = FilenameEditor( "Application Script", placeholderText="Application script", whatsThis="The name of the application's optional main script " "file.", textEdited=self._script_changed) form.addRow("Main script file", self._script_edit) self._entry_point_edit = QLineEdit( placeholderText="Entry point in application package", whatsThis="The name of the optional entry point in the " "application's package.", textEdited=self._entry_point_changed) form.addRow("Entry point", self._entry_point_edit) self._sys_path_edit = QLineEdit( placeholderText="Additional sys.path directories", whatsThis="A space separated list of additional directories, " "ZIP files and eggs to add to <tt>sys.path</tt>. Only " "set this if you want to allow external packages to " "be imported.", textEdited=self._sys_path_changed) form.addRow("sys.path", self._sys_path_edit) layout.addLayout(form, 0, 0) options_layout = BetterForm() self._py_version_edit = QComboBox( whatsThis="Select the target Python version.") for major, minor, patch in supported_python_versions: self._py_version_edit.addItem("v{0}.{1}.{2}".format( major, minor, patch)) self._py_version_edit.currentIndexChanged.connect( self._py_version_changed) options_layout.addRow("Target Python version", self._py_version_edit) self._pyqt_version_edit = QComboBox( whatsThis="Select the PyQt version.") self._pyqt_version_edit.addItems(["PyQt4", "PyQt5"]) self._pyqt_version_edit.currentIndexChanged.connect( self._pyqt_version_changed) options_layout.addRow("Target PyQt version", self._pyqt_version_edit) self._console_edit = QCheckBox( "Use console (Windows)", whatsThis="Enable console output for Windows applications. " "Console output will be enabled automatically if no " "graphical PyQt modules are used.", stateChanged=self._console_changed) options_layout.addRow(self._console_edit) self._bundle_edit = QCheckBox( "Application bundle (macOS)", whatsThis="Build an application bundle on macOS. If it is not " "checked then the application will be built as a " "simple executable.", stateChanged=self._bundle_changed) options_layout.addRow(self._bundle_edit) layout.addLayout(options_layout, 0, 1) self._package_edit = _ApplicationPackageEditor() self._package_edit.package_changed.connect(self._package_changed) package_edit_gb = QGroupBox(self._package_edit.title) package_edit_gb.setLayout(self._package_edit) layout.addWidget(package_edit_gb, 1, 0, 1, 2) layout.setRowStretch(1, 1) self.setLayout(layout) def _update_page(self): """ Update the page using the current project. """ project = self.project self._name_edit.setText(project.application_name) self._script_edit.setText(project.application_script) self._entry_point_edit.setText(project.application_entry_point) self._sys_path_edit.setText(project.sys_path) self._package_edit.configure(project.application_package, project) blocked = self._py_version_edit.blockSignals(True) self._py_version_edit.setCurrentIndex( supported_python_versions.index(project.python_target_version)) self._py_version_edit.blockSignals(blocked) blocked = self._pyqt_version_edit.blockSignals(True) self._pyqt_version_edit.setCurrentIndex( 1 if project.application_is_pyqt5 else 0) self._pyqt_version_edit.blockSignals(blocked) blocked = self._console_edit.blockSignals(True) self._console_edit.setCheckState( Qt.Checked if project.application_is_console else Qt.Unchecked) self._console_edit.blockSignals(blocked) blocked = self._bundle_edit.blockSignals(True) self._bundle_edit.setCheckState( Qt.Checked if project.application_is_bundle else Qt.Unchecked) self._bundle_edit.blockSignals(blocked) def _py_version_changed(self, idx): """ Invoked when the user changes the Python version number. """ self.project.python_target_version = supported_python_versions[idx] self.project.modified = True self.python_target_version_changed.emit() def _pyqt_version_changed(self, idx): """ Invoked when the user changes the PyQt version number. """ pyqt5 = (idx == 1) self.project.application_is_pyqt5 = pyqt5 self.project.modified = True self.pyqt_version_changed.emit(pyqt5) def _console_changed(self, state): """ Invoked when the user changes the console state. """ self.project.application_is_console = (state == Qt.Checked) self.project.modified = True def _bundle_changed(self, state): """ Invoked when the user changes the bundle state. """ self.project.application_is_bundle = (state == Qt.Checked) self.project.modified = True def _name_changed(self, value): """ Invoked when the user edits the application name. """ self.project.application_name = value self.project.modified = True def _script_changed(self, value): """ Invoked when the user edits the application script name. """ self.project.application_script = value self.project.modified = True def _entry_point_changed(self, value): """ Invoked when the user edits the entry point. """ self.project.application_entry_point = value self.project.modified = True def _sys_path_changed(self, value): """ Invoked when the user edits the sys.path directories. """ self.project.sys_path = value.strip() self.project.modified = True def _package_changed(self): """ Invoked when the user edits the application package. """ self.project.modified = True
class LaserRangeFinder(PluginBase): def __init__(self, *args): super().__init__(BrickletLaserRangeFinder, *args) self.lrf = self.device # the firmware version of a EEPROM Bricklet can (under common circumstances) # not change during the lifetime of an EEPROM Bricklet plugin. therefore, # it's okay to make final decisions based on it here self.has_sensor_hardware_version_api = self.firmware_version >= (2, 0, 3) self.has_configuration_api = self.firmware_version >= (2, 0, 3) self.cbe_distance = CallbackEmulator(self.lrf.get_distance, None, self.cb_distance, self.increase_error_count) self.cbe_velocity = CallbackEmulator(self.lrf.get_velocity, None, self.cb_velocity, self.increase_error_count) self.current_distance = CurveValueWrapper() # int, cm self.current_velocity = CurveValueWrapper() # float, m/s plots_distance = [('Distance', Qt.red, self.current_distance, format_distance)] plots_velocity = [('Velocity', Qt.red, self.current_velocity, '{:.2f} m/s'.format)] self.plot_widget_distance = PlotWidget('Distance [cm]', plots_distance, y_resolution=1.0) self.plot_widget_velocity = PlotWidget('Velocity [m/s]', plots_velocity, y_resolution=0.01) self.mode_label = QLabel('Mode:') self.mode_combo = QComboBox() self.mode_combo.addItem("Distance: 1cm resolution, 40m max") self.mode_combo.addItem("Velocity: 0.10 m/s resolution, 12.70m/s max") self.mode_combo.addItem("Velocity: 0.25 m/s resolution, 31.75m/s max") self.mode_combo.addItem("Velocity: 0.50 m/s resolution, 63.50m/s max") self.mode_combo.addItem("Velocity: 1.00 m/s resolution, 127.00m/s max") self.mode_combo.currentIndexChanged.connect(self.mode_changed) self.mode_combo.hide() self.label_average_distance = QLabel('Moving Average for Distance:') self.spin_average_distance = QSpinBox() self.spin_average_distance.setMinimum(0) self.spin_average_distance.setMaximum(50) self.spin_average_distance.setSingleStep(1) self.spin_average_distance.setValue(10) self.spin_average_distance.editingFinished.connect(self.spin_average_finished) self.label_average_velocity = QLabel('Moving Average for Velocity:') self.spin_average_velocity = QSpinBox() self.spin_average_velocity.setMinimum(0) self.spin_average_velocity.setMaximum(50) self.spin_average_velocity.setSingleStep(1) self.spin_average_velocity.setValue(10) self.spin_average_velocity.editingFinished.connect(self.spin_average_finished) self.enable_laser = QCheckBox("Enable Laser") self.enable_laser.stateChanged.connect(self.enable_laser_changed) self.label_acquisition_count = QLabel('Acquisition Count:') self.spin_acquisition_count = QSpinBox() self.spin_acquisition_count.setMinimum(1) self.spin_acquisition_count.setMaximum(255) self.spin_acquisition_count.setSingleStep(1) self.spin_acquisition_count.setValue(128) self.enable_qick_termination = QCheckBox("Quick Termination") self.label_threshold = QLabel('Threshold:') self.threshold = QCheckBox("Automatic Threshold") self.spin_threshold = QSpinBox() self.spin_threshold.setMinimum(1) self.spin_threshold.setMaximum(255) self.spin_threshold.setSingleStep(1) self.spin_threshold.setValue(1) self.label_frequency = QLabel('Frequency [Hz]:') self.frequency = QCheckBox("Automatic Frequency (Disable for Velocity)") self.spin_frequency = QSpinBox() self.spin_frequency.setMinimum(10) self.spin_frequency.setMaximum(500) self.spin_frequency.setSingleStep(1) self.spin_frequency.setValue(10) self.spin_acquisition_count.editingFinished.connect(self.configuration_changed) self.enable_qick_termination.stateChanged.connect(self.configuration_changed) self.spin_threshold.editingFinished.connect(self.configuration_changed) self.threshold.stateChanged.connect(self.configuration_changed) self.spin_frequency.editingFinished.connect(self.configuration_changed) self.frequency.stateChanged.connect(self.configuration_changed) layout_h1 = QHBoxLayout() layout_h1.addWidget(self.plot_widget_distance) layout_h1.addWidget(self.plot_widget_velocity) layout_h2 = QHBoxLayout() layout_h2.addWidget(self.mode_label) layout_h2.addWidget(self.mode_combo) layout_h2.addWidget(self.label_average_distance) layout_h2.addWidget(self.spin_average_distance) layout_h2.addWidget(self.label_average_velocity) layout_h2.addWidget(self.spin_average_velocity) layout_h2.addStretch() layout_h2.addWidget(self.enable_laser) layout_h3 = QHBoxLayout() layout_h3.addWidget(self.label_frequency) layout_h3.addWidget(self.spin_frequency) layout_h3.addWidget(self.frequency) layout_h3.addStretch() layout_h3.addWidget(self.enable_qick_termination) layout_h4 = QHBoxLayout() layout_h4.addWidget(self.label_threshold) layout_h4.addWidget(self.spin_threshold) layout_h4.addWidget(self.threshold) layout_h4.addStretch() layout_h4.addWidget(self.label_acquisition_count) layout_h4.addWidget(self.spin_acquisition_count) self.widgets_distance = [self.plot_widget_distance, self.spin_average_distance, self.label_average_distance] self.widgets_velocity = [self.plot_widget_velocity, self.spin_average_velocity, self.label_average_velocity] for w in self.widgets_distance: w.hide() for w in self.widgets_velocity: w.hide() line = QFrame() line.setObjectName("line") line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addLayout(layout_h1) layout.addWidget(line) layout.addLayout(layout_h2) layout.addLayout(layout_h3) layout.addLayout(layout_h4) def start(self): if self.has_sensor_hardware_version_api: async_call(self.lrf.get_sensor_hardware_version, None, self.get_sensor_hardware_version_async, self.increase_error_count) else: self.get_sensor_hardware_version_async(1) if self.has_configuration_api: async_call(self.lrf.get_configuration, None, self.get_configuration_async, self.increase_error_count) async_call(self.lrf.get_mode, None, self.get_mode_async, self.increase_error_count) async_call(self.lrf.is_laser_enabled, None, self.enable_laser.setChecked, self.increase_error_count) async_call(self.lrf.get_moving_average, None, self.get_moving_average_async, self.increase_error_count) self.cbe_distance.set_period(25) self.cbe_velocity.set_period(25) self.plot_widget_distance.stop = False self.plot_widget_velocity.stop = False def stop(self): self.cbe_distance.set_period(0) self.cbe_velocity.set_period(0) self.plot_widget_distance.stop = True self.plot_widget_velocity.stop = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletLaserRangeFinder.DEVICE_IDENTIFIER def enable_laser_changed(self, state): if state == Qt.Checked: self.lrf.enable_laser() else: self.lrf.disable_laser() def mode_changed(self, value): if value < 0 or value > 4: return self.lrf.set_mode(value) if value == 0: for w in self.widgets_velocity: w.hide() for w in self.widgets_distance: w.show() else: for w in self.widgets_distance: w.hide() for w in self.widgets_velocity: w.show() def cb_distance(self, distance): self.current_distance.value = distance def cb_velocity(self, velocity): self.current_velocity.value = velocity / 100.0 def configuration_changed(self): acquisition_count = self.spin_acquisition_count.value() enable_quick_termination = self.enable_qick_termination.isChecked() if self.threshold.isChecked(): threshold = 0 else: threshold = self.spin_threshold.value() if self.frequency.isChecked(): frequency = 0 for w in self.widgets_velocity: w.hide() else: frequency = self.spin_frequency.value() for w in self.widgets_velocity: w.show() self.spin_threshold.setDisabled(threshold == 0) self.spin_frequency.setDisabled(frequency == 0) self.lrf.set_configuration(acquisition_count, enable_quick_termination, threshold, frequency) def get_configuration_async(self, conf): self.spin_acquisition_count.blockSignals(True) self.spin_acquisition_count.setValue(conf.acquisition_count) self.spin_acquisition_count.blockSignals(False) self.enable_qick_termination.blockSignals(True) self.enable_qick_termination.setChecked(conf.enable_quick_termination) self.enable_qick_termination.blockSignals(False) self.spin_threshold.blockSignals(True) self.spin_threshold.setValue(conf.threshold_value) self.spin_threshold.setDisabled(conf.threshold_value == 0) self.spin_threshold.blockSignals(False) self.spin_frequency.blockSignals(True) self.spin_frequency.setValue(conf.measurement_frequency) self.spin_frequency.setDisabled(conf.measurement_frequency == 0) self.spin_frequency.blockSignals(False) self.threshold.blockSignals(True) self.threshold.setChecked(conf.threshold_value == 0) self.threshold.blockSignals(False) self.frequency.blockSignals(True) self.frequency.setChecked(conf.measurement_frequency == 0) self.frequency.blockSignals(False) self.configuration_changed() def get_sensor_hardware_version_async(self, value): if value == 1: self.mode_combo.show() self.mode_label.show() self.label_acquisition_count.hide() self.spin_acquisition_count.hide() self.enable_qick_termination.hide() self.label_threshold.hide() self.spin_threshold.hide() self.threshold.hide() self.label_frequency.hide() self.spin_frequency.hide() self.frequency.hide() else: self.mode_combo.hide() self.mode_label.hide() self.label_acquisition_count.show() self.spin_acquisition_count.show() self.enable_qick_termination.show() self.label_threshold.show() self.spin_threshold.show() self.threshold.show() self.label_frequency.show() self.spin_frequency.show() self.frequency.show() for w in self.widgets_distance: w.show() for w in self.widgets_velocity: w.show() def get_mode_async(self, value): self.mode_combo.setCurrentIndex(value) self.mode_changed(value) def get_moving_average_async(self, avg): self.spin_average_distance.setValue(avg.distance_average_length) self.spin_average_velocity.setValue(avg.velocity_average_length) def spin_average_finished(self): self.lrf.set_moving_average(self.spin_average_distance.value(), self.spin_average_velocity.value())
class _PlatformGui(QWidget): """ The platform-specific GUI. """ def __init__(self, platform_name): """ Initialise the object. """ super().__init__() self._project = None self._platform_name = platform_name self._ignore_extlib_changes = False layout = QVBoxLayout() self._pyshlib_cb = QCheckBox( "Use standard Python shared library", whatsThis="Use the standard Python shared library rather than " "a statically compiled library.", stateChanged=self._pyshlib_changed) layout.addWidget(self._pyshlib_cb) self._extlib_edit = QTreeView( whatsThis="This is the list of external libraries that must " "be linked with the application for this platform. A " "library will only be enabled if a module in the " "standard library uses it. Double-click in the " "<b>DEFINES</b>, <b>INCLUDEPATH</b> and <b>LIBS</b> " "columns to modify the corresponding <tt>qmake</tt> " "variable as required.") self._extlib_edit.setRootIsDecorated(False) self._extlib_edit.setEditTriggers(QTreeView.DoubleClicked | QTreeView.SelectedClicked | QTreeView.EditKeyPressed) model = QStandardItemModel(self._extlib_edit) model.setHorizontalHeaderLabels( ("External Library", 'DEFINES', 'INCLUDEPATH', 'LIBS')) model.itemChanged.connect(self._extlib_changed) model._items = {} for extlib in external_libraries_metadata: name_itm = QStandardItem(extlib.user_name) items = (name_itm, QStandardItem(), QStandardItem(), QStandardItem()) model.appendRow(items) model._items[extlib.name] = items self._extlib_edit.setModel(model) for col in range(3): self._extlib_edit.resizeColumnToContents(col) layout.addWidget(self._extlib_edit) self.setLayout(layout) def update_from_project(self, project): """ Update the GUI to reflect the current state of the project. """ self._project = project platform_name = self._platform_name # Update the shared library state. blocked = self._pyshlib_cb.blockSignals(True) self._pyshlib_cb.setCheckState(Qt.Checked if platform_name in project. python_use_platform else Qt.Unchecked) self._pyshlib_cb.blockSignals(blocked) # Update the external libraries. model = self._extlib_edit.model() blocked = model.blockSignals(True) external_libs = project.external_libraries.get(platform_name, []) for extlib in external_libraries_metadata: _, defs, incp, libs = model._items[extlib.name] for prj_extlib in external_libs: if prj_extlib.name == extlib.name: defs.setText(prj_extlib.defines) incp.setText(prj_extlib.includepath) libs.setText(prj_extlib.libs) break else: defs.setText(extlib.defines) incp.setText(extlib.includepath) libs.setText(extlib.get_libs(platform_name)) model.blockSignals(blocked) def update_from_required_libraries(self, required_libraries): """ Update the GUI as the required external libraries changes. """ items = self._extlib_edit.model()._items # Note that we can't simply block the model's signals as this would # interfere with the model/view interactions. self._ignore_extlib_changes = True for extlib in external_libraries_metadata: if extlib.name in required_libraries: for idx, itm in enumerate(items[extlib.name]): itm.setFlags( Qt.ItemIsEnabled | Qt.ItemIsEditable if idx != 0 else Qt.ItemIsEnabled) else: for itm in items[extlib.name]: itm.setFlags(Qt.NoItemFlags) self._ignore_extlib_changes = False def _pyshlib_changed(self, state): """ Invoked when the shared library state changes. """ project = self._project platform_name = self._platform_name if state == Qt.Checked: project.python_use_platform.append(platform_name) else: project.python_use_platform.remove(platform_name) project.modified = True def _extlib_changed(self, itm): """ Invoked when an external library has changed. """ if self._ignore_extlib_changes: return self._ignore_extlib_changes = True project = self._project platform_name = self._platform_name idx = self._extlib_edit.model().indexFromItem(itm) extlib = external_libraries_metadata[idx.row()] col = idx.column() # Get the project entry, creating it if necessary. external_libs = project.external_libraries.get(platform_name, []) for prj_extlib in external_libs: if prj_extlib.name == extlib.name: break else: prj_extlib = ExternalLibrary(extlib.name, '', '', extlib.get_libs(platform_name)) external_libs.append(prj_extlib) project.external_libraries[platform_name] = external_libs # Update the project. text = itm.text().strip() if col == 1: prj_extlib.defines = text elif col == 2: prj_extlib.includepath = text elif col == 3: prj_extlib.libs = text # If the project entry corresponds to the default then remove it. if prj_extlib.defines == extlib.defines and prj_extlib.includepath == extlib.includepath and prj_extlib.libs == extlib.get_libs( platform_name): external_libs.remove(prj_extlib) if len(external_libs) == 0: del project.external_libraries[platform_name] project.modified = True self._ignore_extlib_changes = False
class MotorizedLinearPoti(COMCUPluginBase): def __init__(self, *args): super().__init__(BrickletMotorizedLinearPoti, *args) self.mp = self.device self.cbe_position = CallbackEmulator(self.mp.get_position, None, self.cb_position, self.increase_error_count) self.current_position = CurveValueWrapper() self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, 100) self.slider.setMinimumWidth(200) self.slider.setEnabled(False) plots = [('Potentiometer Position', Qt.red, self.current_position, str)] self.plot_widget = PlotWidget('Position', plots, extra_key_widgets=[self.slider], update_interval=0.025, y_resolution=1.0) self.motor_slider = QSlider(Qt.Horizontal) self.motor_slider.setRange(0, 100) self.motor_slider.valueChanged.connect(self.motor_slider_value_changed) self.motor_hold_position = QCheckBox("Hold Position") self.motor_drive_mode = QComboBox() self.motor_drive_mode.addItem('Fast') self.motor_drive_mode.addItem('Smooth') def get_motor_slider_value(): return self.motor_slider.value() self.motor_hold_position.stateChanged.connect(lambda x: self.motor_slider_value_changed(get_motor_slider_value())) self.motor_drive_mode.currentIndexChanged.connect(lambda x: self.motor_slider_value_changed(get_motor_slider_value())) self.motor_position_label = MotorPositionLabel('Motor Target Position:') hlayout = QHBoxLayout() hlayout.addWidget(self.motor_position_label) hlayout.addWidget(self.motor_slider) hlayout.addWidget(self.motor_drive_mode) hlayout.addWidget(self.motor_hold_position) line = QFrame() line.setObjectName("line") line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addWidget(self.plot_widget) layout.addWidget(line) layout.addLayout(hlayout) def start(self): async_call(self.mp.get_motor_position, None, self.get_motor_position_async, self.increase_error_count) self.cbe_position.set_period(25) self.plot_widget.stop = False def stop(self): self.cbe_position.set_period(0) self.plot_widget.stop = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletMotorizedLinearPoti.DEVICE_IDENTIFIER def cb_position(self, position): self.current_position.value = position self.slider.setValue(position) def get_motor_position_async(self, motor): self.motor_slider.blockSignals(True) self.motor_hold_position.blockSignals(True) self.motor_drive_mode.blockSignals(True) self.motor_hold_position.setChecked(motor.hold_position) self.motor_drive_mode.setCurrentIndex(motor.drive_mode) self.motor_position_label.setText(str(motor.position)) self.motor_slider.setValue(motor.position) self.motor_slider.blockSignals(False) self.motor_hold_position.blockSignals(False) self.motor_drive_mode.blockSignals(False) def motor_slider_value_changed(self, position): self.motor_position_label.setText(str(position)) self.mp.set_motor_position(self.motor_slider.value(), self.motor_drive_mode.currentIndex(), self.motor_hold_position.isChecked())