Beispiel #1
0
 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)
Beispiel #2
0
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())
Beispiel #3
0
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()
Beispiel #4
0
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
Beispiel #6
0
    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)
Beispiel #7
0
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)
Beispiel #8
0
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
Beispiel #9
0
    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()
Beispiel #10
0
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
Beispiel #12
0
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
Beispiel #16
0
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())
Beispiel #18
0
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)
Beispiel #20
0
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
Beispiel #22
0
 def setEditorData(self, editor: QCheckBox, index: QModelIndex):
     editor.blockSignals(True)
     editor.setChecked(index.model().data(index))
     self.enabled = editor.isChecked()
     editor.blockSignals(False)
Beispiel #23
0
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
Beispiel #24
0
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
Beispiel #25
0
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())
Beispiel #26
0
Datei: iv.py Projekt: wi1k1n/pytb
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('&copy')
        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()))
Beispiel #27
0
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()
Beispiel #28
0
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)
Beispiel #29
0
 def setEditorData(self, editor: QCheckBox, index: QModelIndex):
     editor.blockSignals(True)
     editor.setChecked(index.model().data(index))
     self.enabled = editor.isChecked()
     editor.blockSignals(False)
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())
Beispiel #31
0
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)
Beispiel #32
0
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())