class ParameterControlWidget(QWidget):
    parameter_type_id = None
    parameter_type_name = None
    spinbox = None

    editingFinished = pyqtSignal(QWidget)

    def __init__(self, parameter_name, parameter_type, parent=None):
        super(ParameterControlWidget, self).__init__(parent)

        self.parameter_type_id = parameter_type

        self.spinbox = QSpinBox(self)
        # Hier steht im Gegensatz zu C++ -2147483648 weil nicht: http://bit.ly/uflXkq
        self.spinbox.setMinimum(-2147483648)
        self.spinbox.setMaximum(2147483647)
        self.spinbox.editingFinished.connect(self.someEditingFinished)
        self.spinbox.setFixedWidth(80)

        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(QLabel(parameter_name + ":"))
        layout.addWidget(self.spinbox)

        self.current_value = self.spinbox.value()

        self.setLayout(layout)

    def parameterTypeId(self):
        return self.parameter_type_id

    def parameterTypeName(self):
        return self.parameter_type_name

    def setParameterTypeName(self, parameter_type_name):
        self.parameter_type_name = parameter_type_name

    def value(self):
        return self.spinbox.value()

    def setValue(self, value):
        self.current_value = value
        self.spinbox.blockSignals(True)
        self.spinbox.setValue(value)
        self.spinbox.blockSignals(False)

    def setReadOnly(self, readonly):
        return self.spinbox.setReadOnly(readonly)

    @pyqtSlot()
    def someEditingFinished(self):
        if self.spinbox.value() != self.current_value:
            self.current_value = self.spinbox.value()

            if not self.spinbox.isReadOnly() and self.isEnabled():
                self.editingFinished.emit(self)

    def contextMenuEvent(self, event):
        # TODO big numbers widget
        pass
Esempio n. 2
0
class _CPaginationJumpBar(QWidget):
    """跳转控件
    """
    valueChanged = pyqtSignal(int)

    def __init__(self, totalPages, *args, **kwargs):
        super(_CPaginationJumpBar, self).__init__(*args, **kwargs)

        self.setAttribute(Qt.WA_StyledBackground, True)
        layout = QHBoxLayout(self)
        layout.setSpacing(4)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(QLabel('前往', self, alignment=Qt.AlignCenter))
        self.editPage = QSpinBox(self)
        layout.addWidget(self.editPage)
        layout.addWidget(QLabel('页', self, alignment=Qt.AlignCenter))

        self.setTotalPages(totalPages)
        self.editPage.setObjectName('CPaginationBar_editJump')
        self.editPage.setFrame(False)
        self.editPage.setAlignment(Qt.AlignCenter)
        self.editPage.setButtonSymbols(QSpinBox.NoButtons)
        self.editPage.editingFinished.connect(self.onValueChanged)
        # 禁止鼠标滑轮
        self.editPage.wheelEvent = self._wheelEvent

    def _wheelEvent(self, event):
        event.ignore()

    def onValueChanged(self):
        self.valueChanged.emit(self.editPage.value())

    def setCurrentPage(self, currentPage):
        """设置当前页
        :param currentPage:
        """
        self.editPage.blockSignals(True)
        self.editPage.setValue(currentPage)
        self.editPage.blockSignals(False)

    def setTotalPages(self, totalPages):
        """设置最大值
        :param totalPages:
        """
        self.totalPages = max(1, totalPages)
        self.editPage.setRange(1, self.totalPages)
Esempio n. 3
0
class IntegerOption(GenericOption):
    def __init__(self, option, container):
        super().__init__(option, container)

        self.spinbox = QSpinBox()
        self.spinbox.setMinimum(option["min"])
        self.spinbox.setMaximum(option["max"])
        self.spinbox.valueChanged.connect(self.on_change)
        self.container.addWidget(self.spinbox, self.row, 1)

    def reload(self, keyboard):
        value = super().reload(keyboard)
        self.spinbox.blockSignals(True)
        self.spinbox.setValue(value)
        self.spinbox.blockSignals(False)

    def value(self):
        return self.spinbox.value()

    def delete(self):
        super().delete()
        self.spinbox.hide()
        self.spinbox.deleteLater()
Esempio n. 4
0
class WeatherStationBrowser(QWidget):
    """
    Widget that allows the user to browse and select ECCC climate stations.
    """

    ConsoleSignal = QSignal(str)
    staListSignal = QSignal(list)

    PROV_NAME = [x[0].title() for x in PROV_NAME_ABB]
    PROV_ABB = [x[1] for x in PROV_NAME_ABB]

    def __init__(self, parent=None):
        super(WeatherStationBrowser, self).__init__(parent)
        self.stn_finder_worker = WeatherStationFinder()
        self.stn_finder_worker.sig_load_database_finished.connect(
                self.receive_load_database)
        self.stn_finder_thread = QThread()
        self.stn_finder_worker.moveToThread(self.stn_finder_thread)

        self.station_table = WeatherSationView()
        self.waitspinnerbar = WaitSpinnerBar()
        self.stn_finder_worker.sig_progress_msg.connect(
                self.waitspinnerbar.set_label)
        self.__initUI__()

        self.start_load_database()

    def __initUI__(self):
        self.setWindowTitle('Weather Stations Browser')
        self.setWindowIcon(icons.get_icon('master'))
        self.setWindowFlags(Qt.Window)

        now = datetime.now()

        # ---- Tab Widget Search

        # ---- Proximity filter groupbox

        label_Lat = QLabel('Latitude :')
        label_Lat2 = QLabel('North')

        self.lat_spinBox = QDoubleSpinBox()
        self.lat_spinBox.setAlignment(Qt.AlignCenter)
        self.lat_spinBox.setSingleStep(0.1)
        self.lat_spinBox.setValue(0)
        self.lat_spinBox.setMinimum(0)
        self.lat_spinBox.setMaximum(180)
        self.lat_spinBox.setSuffix(u' °')
        self.lat_spinBox.valueChanged.connect(self.proximity_grpbox_toggled)

        label_Lon = QLabel('Longitude :')
        label_Lon2 = QLabel('West')

        self.lon_spinBox = QDoubleSpinBox()
        self.lon_spinBox.setAlignment(Qt.AlignCenter)
        self.lon_spinBox.setSingleStep(0.1)
        self.lon_spinBox.setValue(0)
        self.lon_spinBox.setMinimum(0)
        self.lon_spinBox.setMaximum(180)
        self.lon_spinBox.setSuffix(u' °')
        self.lon_spinBox.valueChanged.connect(self.proximity_grpbox_toggled)

        self.radius_SpinBox = QComboBox()
        self.radius_SpinBox.addItems(['25 km', '50 km', '100 km', '200 km'])
        self.radius_SpinBox.currentIndexChanged.connect(
                self.search_filters_changed)

        prox_search_grid = QGridLayout()
        row = 0
        prox_search_grid.addWidget(label_Lat, row, 1)
        prox_search_grid.addWidget(self.lat_spinBox, row, 2)
        prox_search_grid.addWidget(label_Lat2, row, 3)
        row += 1
        prox_search_grid.addWidget(label_Lon, row, 1)
        prox_search_grid.addWidget(self.lon_spinBox, row, 2)
        prox_search_grid.addWidget(label_Lon2, row, 3)
        row += 1
        prox_search_grid.addWidget(QLabel('Search Radius :'), row, 1)
        prox_search_grid.addWidget(self.radius_SpinBox, row, 2)

        prox_search_grid.setColumnStretch(0, 100)
        prox_search_grid.setColumnStretch(4, 100)
        prox_search_grid.setRowStretch(row+1, 100)
        prox_search_grid.setHorizontalSpacing(20)
        prox_search_grid.setContentsMargins(10, 10, 10, 10)  # (L, T, R, B)

        self.prox_grpbox = QGroupBox("Proximity filter :")
        self.prox_grpbox.setCheckable(True)
        self.prox_grpbox.setChecked(False)
        self.prox_grpbox.toggled.connect(self.proximity_grpbox_toggled)
        self.prox_grpbox.setLayout(prox_search_grid)

        # ---- Province filter

        prov_names = ['All']
        prov_names.extend(self.PROV_NAME)
        self.prov_widg = QComboBox()
        self.prov_widg.addItems(prov_names)
        self.prov_widg.setCurrentIndex(0)
        self.prov_widg.currentIndexChanged.connect(self.search_filters_changed)

        layout = QGridLayout()
        layout.addWidget(self.prov_widg, 2, 1)
        layout.setColumnStretch(2, 100)
        layout.setVerticalSpacing(10)

        prov_grpbox = QGroupBox("Province filter :")
        prov_grpbox.setLayout(layout)

        # ---- Data availability filter

        # Number of years with data

        self.nbrYear = QSpinBox()
        self.nbrYear.setAlignment(Qt.AlignCenter)
        self.nbrYear.setSingleStep(1)
        self.nbrYear.setMinimum(0)
        self.nbrYear.setValue(3)
        self.nbrYear.valueChanged.connect(self.search_filters_changed)

        subgrid1 = QGridLayout()
        subgrid1.addWidget(self.nbrYear, 0, 0)
        subgrid1.addWidget(QLabel('years of data between'), 0, 1)

        subgrid1.setHorizontalSpacing(10)
        subgrid1.setContentsMargins(0, 0, 0, 0)  # (L, T, R, B)
        subgrid1.setColumnStretch(2, 100)

        # Year range

        self.minYear = QSpinBox()
        self.minYear.setAlignment(Qt.AlignCenter)
        self.minYear.setSingleStep(1)
        self.minYear.setMinimum(1840)
        self.minYear.setMaximum(now.year)
        self.minYear.setValue(1840)
        self.minYear.valueChanged.connect(self.minYear_changed)

        label_and = QLabel('and')
        label_and.setAlignment(Qt.AlignCenter)

        self.maxYear = QSpinBox()
        self.maxYear.setAlignment(Qt.AlignCenter)
        self.maxYear.setSingleStep(1)
        self.maxYear.setMinimum(1840)
        self.maxYear.setMaximum(now.year)
        self.maxYear.setValue(now.year)
        self.maxYear.valueChanged.connect(self.maxYear_changed)

        subgrid2 = QGridLayout()
        subgrid2.addWidget(self.minYear, 0, 0)
        subgrid2.addWidget(label_and, 0, 1)
        subgrid2.addWidget(self.maxYear, 0, 2)

        subgrid2.setHorizontalSpacing(10)
        subgrid2.setContentsMargins(0, 0, 0, 0)  # (L, T, R, B)
        subgrid2.setColumnStretch(4, 100)

        # Subgridgrid assembly

        grid = QGridLayout()

        grid.addWidget(QLabel('Search for stations with at least'), 0, 0)
        grid.addLayout(subgrid1, 1, 0)
        grid.addLayout(subgrid2, 2, 0)

        grid.setVerticalSpacing(5)
        grid.setRowStretch(0, 100)
        # grid.setContentsMargins(0, 0, 0, 0)  # (L, T, R, B)

        self.year_widg = QGroupBox("Data Availability filter :")
        self.year_widg.setLayout(grid)

        # ---- Toolbar

        self.btn_addSta = btn_addSta = QPushButton('Add')
        btn_addSta.setIcon(icons.get_icon('add2list'))
        btn_addSta.setIconSize(icons.get_iconsize('small'))
        btn_addSta.setToolTip('Add selected found weather stations to the '
                              'current list of weather stations.')
        btn_addSta.clicked.connect(self.btn_addSta_isClicked)

        btn_save = QPushButton('Save')
        btn_save.setIcon(icons.get_icon('save'))
        btn_save.setIconSize(icons.get_iconsize('small'))
        btn_save.setToolTip('Save current found stations info in a csv file.')
        btn_save.clicked.connect(self.btn_save_isClicked)

        self.btn_fetch = btn_fetch = QPushButton('Fetch')
        btn_fetch.setIcon(icons.get_icon('refresh'))
        btn_fetch.setIconSize(icons.get_iconsize('small'))
        btn_fetch.setToolTip("Updates the climate station database by"
                             " fetching it again from the ECCC ftp server.")
        btn_fetch.clicked.connect(self.btn_fetch_isClicked)

        toolbar_grid = QGridLayout()
        toolbar_widg = QWidget()

        for col, btn in enumerate([btn_addSta, btn_save, btn_fetch]):
            toolbar_grid.addWidget(btn, 0, col+1)

        toolbar_grid.setColumnStretch(toolbar_grid.columnCount(), 100)
        toolbar_grid.setSpacing(5)
        toolbar_grid.setContentsMargins(0, 30, 0, 0)  # (L, T, R, B)

        toolbar_widg.setLayout(toolbar_grid)

        # ---- Left Panel

        panel_title = QLabel('<b>Weather Station Search Criteria :</b>')

        left_panel = QFrame()
        left_panel_grid = QGridLayout()

        left_panel_grid.addWidget(panel_title, 0, 0)
        left_panel_grid.addWidget(self.prox_grpbox, 1, 0)
        left_panel_grid.addWidget(prov_grpbox, 2, 0)
        left_panel_grid.addWidget(self.year_widg, 3, 0)
        left_panel_grid.setRowStretch(4, 100)
        left_panel_grid.addWidget(toolbar_widg, 5, 0)

        left_panel_grid.setVerticalSpacing(20)
        left_panel_grid.setContentsMargins(0, 0, 0, 0)   # (L, T, R, B)
        left_panel.setLayout(left_panel_grid)

        # ----- Main grid

        # Widgets

        vLine1 = QFrame()
        vLine1.setFrameStyle(StyleDB().VLine)

        # Grid

        main_layout = QGridLayout(self)

        main_layout.addWidget(left_panel, 0, 0)
        main_layout.addWidget(vLine1, 0, 1)
        main_layout.addWidget(self.station_table, 0, 2)
        main_layout.addWidget(self.waitspinnerbar, 0, 2)

        main_layout.setContentsMargins(10, 10, 10, 10)  # (L,T,R,B)
        main_layout.setRowStretch(0, 100)
        main_layout.setHorizontalSpacing(15)
        main_layout.setVerticalSpacing(5)
        main_layout.setColumnStretch(col, 100)

    @property
    def stationlist(self):
        return self.station_table.get_stationlist()

    @property
    def search_by(self):
        return ['proximity', 'province'][self.tab_widg.currentIndex()]

    @property
    def prov(self):
        if self.prov_widg.currentIndex() == 0:
            return self.PROV_ABB
        else:
            return self.PROV_ABB[self.prov_widg.currentIndex()-1]

    @property
    def lat(self):
        return self.lat_spinBox.value()

    def set_lat(self, x, silent=True):
        if silent:
            self.lat_spinBox.blockSignals(True)
        self.lat_spinBox.setValue(x)
        self.lat_spinBox.blockSignals(False)
        self.proximity_grpbox_toggled()

    @property
    def lon(self):
        return self.lon_spinBox.value()

    def set_lon(self, x, silent=True):
        if silent:
            self.lon_spinBox.blockSignals(True)
        self.lon_spinBox.setValue(x)
        self.lon_spinBox.blockSignals(False)
        self.proximity_grpbox_toggled()

    @property
    def rad(self):
        return int(self.radius_SpinBox.currentText()[:-3])

    @property
    def prox(self):
        if self.prox_grpbox.isChecked():
            return (self.lat, -self.lon, self.rad)
        else:
            return None

    @property
    def year_min(self):
        return int(self.minYear.value())

    def set_yearmin(self, x, silent=True):
        if silent:
            self.minYear.blockSignals(True)
        self.minYear.setValue(x)
        self.minYear.blockSignals(False)

    @property
    def year_max(self):
        return int(self.maxYear.value())

    def set_yearmax(self, x, silent=True):
        if silent:
            self.maxYear.blockSignals(True)
        self.maxYear.setValue(x)
        self.maxYear.blockSignals(False)

    @property
    def nbr_of_years(self):
        return int(self.nbrYear.value())

    def set_yearnbr(self, x, silent=True):
        if silent:
            self.nbrYear.blockSignals(True)
        self.nbrYear.setValue(x)
        self.nbrYear.blockSignals(False)

    # ---- Weather Station Finder Handlers

    def start_load_database(self, force_fetch=False):
        """Start the process of loading the climate station database."""
        if self.stn_finder_thread.isRunning():
            return

        self.station_table.clear()
        self.waitspinnerbar.show()

        # Start the downloading process.
        if force_fetch:
            self.stn_finder_thread.started.connect(
                    self.stn_finder_worker.fetch_database)
        else:
            self.stn_finder_thread.started.connect(
                    self.stn_finder_worker.load_database)
        self.stn_finder_thread.start()

    @QSlot()
    def receive_load_database(self):
        """Handles when loading the database is finished."""
        # Disconnect the thread.
        self.stn_finder_thread.started.disconnect()

        # Quit the thread.
        self.stn_finder_thread.quit()
        waittime = 0
        while self.stn_finder_thread.isRunning():
            sleep(0.1)
            waittime += 0.1
            if waittime > 15:                                # pragma: no cover
                print("Unable to quit the thread.")
                break
        # Force an update of the GUI.
        self.proximity_grpbox_toggled()
        if self.stn_finder_worker.data is None:
            self.waitspinnerbar.show_warning_icon()
        else:
            self.waitspinnerbar.hide()

    # ---- GUI handlers

    def show(self):
        super(WeatherStationBrowser, self).show()
        qr = self.frameGeometry()
        if self.parent():
            parent = self.parent()
            wp = parent.frameGeometry().width()
            hp = parent.frameGeometry().height()
            cp = parent.mapToGlobal(QPoint(wp/2, hp/2))
        else:
            cp = QDesktopWidget().availableGeometry().center()

        qr.moveCenter(cp)
        self.move(qr.topLeft())

    # -------------------------------------------------------------------------

    def minYear_changed(self):
        min_yr = min_yr = max(self.minYear.value(), 1840)

        now = datetime.now()
        max_yr = now.year

        self.maxYear.setRange(min_yr, max_yr)
        self.search_filters_changed()

    def maxYear_changed(self):
        min_yr = 1840

        now = datetime.now()
        max_yr = min(self.maxYear.value(), now.year)

        self.minYear.setRange(min_yr, max_yr)
        self.search_filters_changed()

    # ---- Toolbar Buttons Handlers

    def btn_save_isClicked(self):
        ddir = os.path.join(os.getcwd(), 'weather_station_list.csv')
        filename, ftype = QFileDialog().getSaveFileName(
                self, 'Save normals', ddir, '*.csv;;*.xlsx;;*.xls')
        self.station_table.save_stationlist(filename)

    def btn_addSta_isClicked(self):
        rows = self.station_table.get_checked_rows()
        if len(rows) > 0:
            staList = self.station_table.get_content4rows(rows)
            self.staListSignal.emit(staList)
            print('Selected stations sent to list')
        else:
            print('No station currently selected')

    def btn_fetch_isClicked(self):
        """Handles when the button fetch is clicked."""
        self.start_load_database(force_fetch=True)

    # ---- Search Filters Handlers

    def proximity_grpbox_toggled(self):
        """
        Set the values for the reference geo coordinates that are used in the
        WeatherSationView to calculate the proximity values and forces a
        refresh of the content of the table.
        """
        if self.prox_grpbox.isChecked():
            self.station_table.set_geocoord((self.lat, -self.lon))
        else:
            self.station_table.set_geocoord(None)
        self.search_filters_changed()

    def search_filters_changed(self):
        """
        Search for weather stations with the current filter values and forces
        an update of the station table content.
        """
        if self.stn_finder_worker.data is not None:
            stnlist = self.stn_finder_worker.get_stationlist(
                    prov=self.prov, prox=self.prox,
                    yrange=(self.year_min, self.year_max, self.nbr_of_years))
            self.station_table.populate_table(stnlist)
Esempio n. 5
0
class StatusBar(QWidget):
    """
    Use the *sizeChanged* signal for size changes.

    TODO: specify only isFontTab/isGlyphTab and put the details
    in the widget internals
    """
    def __init__(self, parent=None):
        super().__init__(parent)
        self._shouldPropagateSize = True

        self.statusLabel = QLabel(self)

        btnColor = QColor(126, 126, 126)
        minusButton = Button()
        minusButton.setDrawingCommands([
            QSize(23, 25),
            (_minPath, '1', btnColor),
        ])
        minusButton.setProperty("delta", -10)
        minusButton.pressed.connect(self._sizeOffset)
        self.sizeEdit = QSpinBox(self)
        self.sizeEdit.setButtonSymbols(QSpinBox.NoButtons)
        self.sizeEdit.setFixedWidth(56)
        self.sizeEdit.setFrame(False)
        self.sizeEdit.lineEdit().setAlignment(Qt.AlignCenter)
        plusButton = Button()
        plusButton.setDrawingCommands([
            QSize(23, 25),
            (_plusPath, '1', btnColor),
        ])
        plusButton.setProperty("delta", 10)
        plusButton.pressed.connect(self._sizeOffset)

        layout = QHBoxLayout(self)
        layout.addWidget(self.statusLabel)
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        layout.addWidget(spacer)
        layout.addWidget(minusButton)
        layout.addWidget(self.sizeEdit)
        layout.addWidget(plusButton)
        layout.setContentsMargins(15, 0, 15, 0)
        layout.setSpacing(0)

        self.sizeChanged = self.sizeEdit.valueChanged

    def text(self):
        return self.statusLabel.text()

    def setText(self, text):
        self.statusLabel.setText(text)

    def textVisible(self):
        return self.statusLabel.isVisible()

    def setTextVisible(self, value):
        self.statusLabel.setVisible(value)

    def minimumSize(self):
        return self.sizeEdit.minimum()

    def setMinimumSize(self, value):
        self.sizeEdit.blockSignals(True)
        self.sizeEdit.setMinimum(value)
        self.sizeEdit.blockSignals(False)

    def maximumSize(self):
        return self.sizeEdit.maximum()

    def setMaximumSize(self, value):
        self.sizeEdit.blockSignals(True)
        self.sizeEdit.setMaximum(value)
        self.sizeEdit.blockSignals(False)

    def shouldPropagateSize(self):
        return self._shouldPropagateSize

    def setShouldPropagateSize(self, value):
        self._shouldPropagateSize = value

    def unit(self):
        return self.sizeEdit.suffix()

    def setUnit(self, txt):
        self.sizeEdit.setSuffix(txt)

    def size(self):
        return self.sizeEdit.value()

    def setSize(self, value):
        value = round(value)
        self.sizeEdit.blockSignals(True)
        self.sizeEdit.setValue(value)
        self.sizeEdit.blockSignals(False)
        if self._shouldPropagateSize:
            self.sizeEdit.valueChanged.emit(value)
        # nudge label w unclamped value
        self._sliderSizeChanged(value)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.fillRect(event.rect(), Qt.white)

    def _sizeOffset(self):
        delta = self.sender().property("delta")
        cellsize = self.sizeEdit.value()
        newValue = cellsize + delta
        self.sizeEdit.setValue(newValue)

    def _sliderSizeChanged(self, value):
        self.sizeEdit.setValue(value)
Esempio n. 6
0
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())
Esempio n. 7
0
class CColorInfos(QWidget):

    colorChanged = pyqtSignal(QColor, int)
    colorAdded = pyqtSignal(QColor)

    def __init__(self, *args, **kwargs):
        super(CColorInfos, self).__init__(*args, **kwargs)
        layout = QGridLayout(self)
        layout.setContentsMargins(11, 2, 11, 2)
        layout.setSpacing(8)

        self.editHex = QLineEdit('#FF0000',
                                 self,
                                 alignment=Qt.AlignCenter,
                                 objectName='editHex',
                                 textChanged=self.onHexChanged)
        self.editHex.setValidator(
            QRegExpValidator(QRegExp('#[0-9a-fA-F]{6}$'), self.editHex))
        self.labelHex = QLabel('HEX', self, alignment=Qt.AlignCenter)
        layout.addWidget(self.editHex, 0, 0)
        layout.addWidget(self.labelHex, 1, 0)

        layout.addItem(
            QSpacerItem(10, 20, QSizePolicy.Fixed, QSizePolicy.Minimum), 0, 1)

        self.editRed = QSpinBox(self,
                                buttonSymbols=QSpinBox.NoButtons,
                                alignment=Qt.AlignCenter,
                                valueChanged=self.onRgbaChanged)
        self.editRed.setRange(0, 255)
        self.labelRed = QLabel('R', self, alignment=Qt.AlignCenter)
        layout.addWidget(self.editRed, 0, 2)
        layout.addWidget(self.labelRed, 1, 2)

        self.editGreen = QSpinBox(self,
                                  buttonSymbols=QSpinBox.NoButtons,
                                  alignment=Qt.AlignCenter,
                                  valueChanged=self.onRgbaChanged)
        self.editGreen.setRange(0, 255)
        self.labelGreen = QLabel('G', self, alignment=Qt.AlignCenter)
        layout.addWidget(self.editGreen, 0, 3)
        layout.addWidget(self.labelGreen, 1, 3)

        self.editBlue = QSpinBox(self,
                                 buttonSymbols=QSpinBox.NoButtons,
                                 alignment=Qt.AlignCenter,
                                 valueChanged=self.onRgbaChanged)
        self.editBlue.setRange(0, 255)
        self.labelBlue = QLabel('B', self, alignment=Qt.AlignCenter)
        layout.addWidget(self.editBlue, 0, 4)
        layout.addWidget(self.labelBlue, 1, 4)

        self.editAlpha = QSpinBox(self,
                                  buttonSymbols=QSpinBox.NoButtons,
                                  alignment=Qt.AlignCenter,
                                  valueChanged=self.onRgbaChanged)
        self.editAlpha.setRange(0, 255)
        self.labelAlpha = QLabel('A', self, alignment=Qt.AlignCenter)
        layout.addWidget(self.editAlpha, 0, 5)
        layout.addWidget(self.labelAlpha, 1, 5)

        layout.addItem(
            QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum), 0,
            6)
        layout.addWidget(
            QPushButton('+',
                        self,
                        cursor=Qt.PointingHandCursor,
                        toolTip='添加自定义颜色',
                        clicked=self.onColorAdd), 0, 7)

        layout.setColumnStretch(0, 3)
        layout.setColumnStretch(1, 1)
        layout.setColumnStretch(2, 1)
        layout.setColumnStretch(3, 1)
        layout.setColumnStretch(4, 1)
        layout.setColumnStretch(5, 1)
        layout.setColumnStretch(6, 2)
        layout.setColumnStretch(7, 1)
        self.setFocus()
        self.editRed.setValue(255)
        self.editAlpha.setValue(255)

    def reset(self):
        pass

    def onColorAdd(self):
        self.colorAdded.emit(
            QColor(self.editRed.value(), self.editGreen.value(),
                   self.editBlue.value()))

    def setHex(self, code):
        self.editHex.setText(str(code))

    def updateColor(self, color):
        self.editRed.setValue(color.red())
        self.editGreen.setValue(color.green())
        self.editBlue.setValue(color.blue())

    def updateAlpha(self, _, alpha):
        self.editAlpha.setValue(alpha)

    def onHexChanged(self, code):
        if len(code) != 7:
            return
        color = QColor(code)
        if color.isValid():
            self.blockRgbaSignals(True)
            self.editHex.blockSignals(True)
            self.editRed.setValue(color.red())
            self.editGreen.setValue(color.green())
            self.editBlue.setValue(color.blue())
            self.editAlpha.setValue(color.alpha())
            self.colorChanged.emit(color, color.alpha())
            self.editHex.blockSignals(False)
            self.blockRgbaSignals(False)

    def onRgbaChanged(self, _):
        self.editHex.blockSignals(True)
        self.blockRgbaSignals(True)
        color = QColor(self.editRed.value(), self.editGreen.value(),
                       self.editBlue.value(), self.editAlpha.value())
        self.editHex.setText(color.name())
        self.colorChanged.emit(color, self.editAlpha.value())
        self.blockRgbaSignals(False)
        self.editHex.blockSignals(False)

    def blockRgbaSignals(self, block=True):
        self.editRed.blockSignals(block)
        self.editGreen.blockSignals(block)
        self.editBlue.blockSignals(block)
        self.editAlpha.blockSignals(block)

    def sizeHint(self):
        return QSize(280, 48)
Esempio n. 8
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
Esempio n. 9
0
class FrameSelectWidget(QWidget):
    frameSelectionChanged = pyqtSignal(int, QTime)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setMaximumWidth(960)

        layout = QVBoxLayout()
        layout.setContentsMargins(4, 4, 4, 4)
        layout.setSpacing(4)
        self.setLayout(layout)

        self.imageView = QImageView(self)
        layout.addWidget(self.imageView)

        self.slider = Slider(self)
        self.slider.setOrientation(Qt.Horizontal)
        self.slider.valueChanged.connect(self.handleSliderChange)
        self.slider.setTickInterval(1)
        layout.addWidget(self.slider)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        self.prevLabel = QLabel(self)
        self.currentIndex = QSpinBox(self)
        self.currentIndex.valueChanged.connect(self.handleIndexChange)
        self.currentTime = QTimeEdit(self)
        self.currentTime.setDisplayFormat("H:mm:ss.zzz")
        self.currentTime.timeChanged.connect(self.handleTimeChange)
        self.nextLabel = QLabel(self)

        hlayout.addWidget(self.prevLabel)
        hlayout.addStretch()
        hlayout.addWidget(QLabel("Frame index:", self))
        hlayout.addWidget(self.currentIndex)
        hlayout.addWidget(QLabel("Timestamp:", self))
        hlayout.addWidget(self.currentTime)
        hlayout.addStretch()
        hlayout.addWidget(self.nextLabel)

        hlayout = QHBoxLayout()
        hlayout.setContentsMargins(0, 0, 0, 0)
        hlayout.setSpacing(4)
        layout.addLayout(hlayout)

        self.okayBtn = QPushButton("&OK", self)
        self.cancelBtn = QPushButton("&Cancel", self)

        hlayout.addStretch()
        hlayout.addWidget(self.okayBtn)
        hlayout.addWidget(self.cancelBtn)
        self.setFrameSource(None, None)

    def sizeHint(self):
        widgetHeights = (
            self.slider.height()
            + max([self.okayBtn.height(), self.cancelBtn.height()])
            + max([self.currentIndex.height(), self.currentTime.height()])
        )

        if isinstance(self.filters, BaseFilter):
            w, h = self.filters.width, self.filters.height
            sar = self.filters.sar

        elif isinstance(self.source, (Track, BaseFilter)):
            w, h = self.source.width, self.source.height
            sar = self.source.sar

        else:
            return super().sizeHint()

        dar = w*sar/h
        W, H = min([
            max([(w, h/sar), (w*sar, h)]),
            (960 - 8, (960 - 8)/dar),
            ((720 - 20 - widgetHeights)*dar, 720 - 20 - widgetHeights)
        ])

        return QSize(int(W + 8), int(H + 20 + widgetHeights))

    def setFrameSource(self, source, filters=None):
        self.source = source

        if source is not None:
            self.slider.setMaximum(self.source.framecount - 1)
            self.currentIndex.setMaximum(self.source.framecount - 1)
            self.filters = filters

            if self.filters is not None:
                lastpts = self.filters.pts_time[-1]
                self.slider.setSnapValues(self.filters.keyframes)

            else:
                lastpts = self.source.pts_time[-1]

                if isinstance(self.source, BaseFilter):
                    self.slider.setSnapValues(self.source.keyframes)

                else:
                    self.slider.setSnapValues(None)

            ms = int(lastpts*1000 + 0.5)
            s, ms = divmod(ms, 1000)
            m, s = divmod(s, 60)
            h, m = divmod(m, 60)
            self.currentTime.setMaximumTime(QTime(h, m, s, ms))
            self.slider.setValue(0)
            self._frameChange(0)

        else:
            self.slider.setSnapValues(None)

        self.update()

    def handleIndexChange(self, n):
        self._frameChange(n)

        self.slider.blockSignals(True)
        self.slider.setValue(n)
        self.slider.blockSignals(False)

    def handleSliderChange(self, n):
        self._frameChange(n)

        self.currentIndex.blockSignals(True)
        self.currentIndex.setValue(n)
        self.currentIndex.blockSignals(False)

    def _frameChange(self, n):
        if self.source is not None:
            if self.filters is not None:
                nn = n
                m = -1

                while m < 0 and nn < len(self.filters.indexMap):
                    m = self.filters.indexMap[nn]
                    nn += 1

                try:
                    pts = self.filters.pts_time[m]

                except Exception:
                    pts = None

                try:
                    frame = next(self.filters.iterFrames(
                        m, whence="framenumber"))

                except StopIteration:
                    frame = None

                sar = self.filters.sar

            else:
                try:
                    pts = self.source.pts_time[n]

                except IndexError:
                    pts = None

                try:
                    frame = next(self.source.iterFrames(
                        n, whence="framenumber"))

                except StopIteration:
                    frame = None

                sar = self.source.sar

            if frame is not None:
                im = frame.to_image()
                self.imageView.setFrame(im.toqpixmap())
                self.imageView.setSar(sar)

            if pts is not None:
                ms = int(pts*1000+0.5)
                s, ms = divmod(ms, 1000)
                m, s = divmod(s, 60)
                h, m = divmod(m, 60)

                self.currentTime.blockSignals(True)
                self.currentTime.setTime(QTime(h, m, s, ms))
                self.currentTime.blockSignals(False)

            self.frameSelectionChanged.emit(n, self.currentTime.time())

    def handleTimeChange(self, t):
        if self.source is not None:
            if self.filters is not None:
                pts = t.msecsSinceStartOfDay()/1000
                n = self.filters.frameIndexFromPtsTime(pts, dir="-")

            else:
                pts = t.msecsSinceStartOfDay()/1000
                n = self.source.frameIndexFromPtsTime(pts, dir="-")

            self.slider.blockSignals(True)
            self.slider.setValue(n)
            self.slider.blockSignals(False)

            self.currentIndex.blockSignals(True)
            self.currentIndex.setValue(n)
            self.currentIndex.blockSignals(False)

            self._frameChange(n)
Esempio n. 10
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())
class ConfigPlotWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(100, 100, 1000, 200)
        self.setWindowTitle("Configure Plot")
        self.layout = QGridLayout()
        self.home()
        self.rangeDict = {
            "Default": [[0, 1], [0, 100], [0, 100], [0, 100], [0, 100], [0, 1]]
        }

    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)

        self.roiChoice = QComboBox(self)  #choose ROI
        self.roiChoice.addItem("Default")
        self.roiChoice.setCurrentIndex(0)
        self.roiChoice.currentIndexChanged.connect(self.update_range)

        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_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)
        self.windLabel = QLabel("Window Length:", 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.polyLabel = QLabel("Polynomial Order:", self)

        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)

        self.eqLabel = QLabel("Lateral Calib. Equation (μN):", self)
        self.latCalibEq = QLineEdit(self)  #lateral force calib equation
        self.latCalibEq.setText("29181.73*x")

        self.noiseStepsLabel = QLabel("Noisy Steps:", self)
        self.noiseSteps = QLineEdit(self)  #remove first data point from steps
        self.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

        self.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)

        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.startFitLabel = QLabel("Start (%):", self)
        # self.endFitLabel = QLabel("End (%):", self)

        # self.fitStart = QDoubleSpinBox(self) #fitting range start
        # self.fitStart.setValue(0)
        # self.fitStart.setSingleStep(1)
        # self.fitStart.setRange(0, 100)

        # self.fitStop = QDoubleSpinBox(self) #fitting range end
        # self.fitStop.setValue(100)
        # self.fitStop.setSingleStep(1)
        # self.fitStop.setRange(0, 100)

        # self.xFitLabel = QLabel("X Parameter:", self)
        # self.yFitLabel = QLabel("Y Parameter:", self)

        # self.xFit = QComboBox(self) #x param
        # self.xFit.addItems(['Deformation (μm)',
        #                     'Vertical Position (μm)',
        #                     'Lateral Position (μm)',
        #                     'Time (s)'])
        # self.xFit.setCurrentIndex(0)

        # self.yFit = QComboBox(self) #x param
        # self.yFit.addItems(['Vertical Force (μN)', 'Lateral Force (μN)'])
        # self.yFit.setCurrentIndex(0)

        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

        self.kBeamLabel = QLabel("Beam Spring Constant (μN/μm):",
                                 self)  #beam dpring constant
        self.kBeam = QLineEdit(self)
        self.kBeam.setText('30,1')

        self.deformStartLabel = QLabel(
            "Deformation Start:", self)  #contact start tolerance auto detect
        self.deformStart = QSpinBox(self)
        self.deformStart.setValue(100)
        self.deformStart.setSingleStep(1)
        self.deformStart.setRange(0, 10000)

        self.okBtn = QPushButton("OK", self)  #Close window

        self.updateBtn = QPushButton("Update", self)  #Update

        self.zeroGroupBox = QGroupBox("Configure Vertical Force")
        filterGroupBox = QGroupBox("Configure Plot")
        flagGroupBox = QGroupBox("Show")
        self.latCalibGroupBox = QGroupBox("Configure Lateral Force")
        self.fittingGroupBox = QGroupBox("Fit Data")
        buttonGroupBox = QGroupBox()

        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(buttonGroupBox, 3, 1)

        self.setLayout(self.layout)

        buttonVbox = QGridLayout()
        buttonGroupBox.setLayout(buttonVbox)
        buttonVbox.addWidget(self.updateBtn, 0, 0)
        buttonVbox.addWidget(self.okBtn, 0, 1)

        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)

    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_dict(self):
        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()]
        ]
        print(self.rangeDict)

    def show_window(self):  #show window
        self.update_range()
        # self.update_dict()
        self.show()
Esempio n. 12
0
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())
Esempio n. 13
0
class DistanceIRV2(COMCUPluginBase):
    NUM_VALUES = 512
    DIVIDER = 2**12//NUM_VALUES

    def __init__(self, *args):
        super().__init__(BrickletDistanceIRV2, *args)

        self.dist = self.device

        self.cbe_distance = CallbackEmulator(self.dist.get_distance,
                                             None,
                                             self.cb_distance,
                                             self.increase_error_count)
        self.cbe_analog_value = CallbackEmulator(self.dist.get_analog_value,
                                                 None,
                                                 self.cb_analog_value,
                                                 self.increase_error_count)

        self.analog_label = AnalogLabel('Analog Value:')
        hlayout = QHBoxLayout()
        self.average_label = QLabel('Moving Average Length:')
        self.average_spin = QSpinBox()
        self.average_spin.setMinimum(1)
        self.average_spin.setMaximum(1000)
        self.average_spin.setSingleStep(1)
        self.average_spin.setValue(25)
        self.average_spin.editingFinished.connect(self.average_spin_finished)

        self.sensor_label = QLabel('Sensor Type:')
        self.sensor_combo = QComboBox()
        self.sensor_combo.addItem('2Y0A41 (4-30cm)')
        self.sensor_combo.addItem('2Y0A21 (10-80cm)')
        self.sensor_combo.addItem('2Y0A02 (20-150cm)')
        self.sensor_combo.currentIndexChanged.connect(self.sensor_combo_changed)

        hlayout.addWidget(self.average_label)
        hlayout.addWidget(self.average_spin)
        hlayout.addStretch()
        hlayout.addWidget(self.sensor_label)
        hlayout.addWidget(self.sensor_combo)

        self.current_distance = CurveValueWrapper() # float, cm

        plots = [('Distance', Qt.red, self.current_distance, '{} cm'.format)]
        self.plot_widget = PlotWidget('Distance [cm]', plots, extra_key_widgets=[self.analog_label], y_resolution=0.1)

        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 sensor_combo_changed(self, index):
        self.dist.set_sensor_type(index)

    def average_spin_finished(self):
        self.dist.set_moving_average_configuration(self.average_spin.value())

    def get_moving_average_configuration_async(self, average):
        self.average_spin.blockSignals(True)
        self.average_spin.setValue(average)
        self.average_spin.blockSignals(False)

    def get_sensor_type_async(self, sensor):
        self.sensor_combo.blockSignals(True)
        self.sensor_combo.setCurrentIndex(sensor)
        self.sensor_combo.blockSignals(False)

    def start(self):
        async_call(self.dist.get_moving_average_configuration, None, self.get_moving_average_configuration_async, self.increase_error_count)
        async_call(self.dist.get_sensor_type, None, self.get_sensor_type_async, self.increase_error_count)

        self.cbe_distance.set_period(10)
        self.cbe_analog_value.set_period(100)

        self.plot_widget.stop = False

    def stop(self):
        self.cbe_distance.set_period(0)
        self.cbe_analog_value.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletDistanceIRV2.DEVICE_IDENTIFIER

    def cb_distance(self, distance):
        self.current_distance.value = distance / 10.0

    def cb_analog_value(self, analog_value):
        self.analog_label.setText(analog_value)
Esempio n. 14
0
class WosFireActionWidget(QWidget):
    location_changed = pyqtSignal(int, int)

    def __init__(self, index, map_size_x, map_size_y, parent=None):
        QWidget.__init__(self, parent)
        self.index = index

        self.layout = QGridLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)

        self.layout.addWidget(QLabel("Bomb %s:" % index, self), 0, 0)

        self.attack_x_spinbox = QSpinBox(self)
        self.attack_x_spinbox.blockSignals(True)
        self.attack_x_spinbox.setRange(0, map_size_x - 1)
        self.layout.addWidget(self.attack_x_spinbox, 0, 1)
        self.attack_x_spinbox.valueChanged.connect(self.update_location)
        self.attack_x_spinbox.blockSignals(False)

        self.attack_y_spinbox = QSpinBox(self)
        self.attack_y_spinbox.blockSignals(True)
        self.attack_y_spinbox.setRange(0, map_size_y - 1)
        self.layout.addWidget(self.attack_y_spinbox, 0, 2)
        self.attack_y_spinbox.valueChanged.connect(self.update_location)
        self.attack_y_spinbox.blockSignals(False)

    def get_index(self):
        return self.index

    def get_fire_info(self):
        return self.attack_x_spinbox.value(), self.attack_y_spinbox.value()

    def set_fire_location(self, x, y):
        self.attack_x_spinbox.blockSignals(False)
        self.attack_x_spinbox.setValue(x)
        self.attack_x_spinbox.blockSignals(True)
        self.attack_y_spinbox.setValue(y)

    def update_location(self):
        self.location_changed.emit(self.attack_x_spinbox.value(),
                                   self.attack_y_spinbox.value())
Esempio n. 15
0
class WosWaypointActionWidget(QWidget):
    waypoint_changed = pyqtSignal(int, int, int, int)
    waypoint_remove_pressed = pyqtSignal(int)

    def __init__(self, index, map_size_x, map_size_y, parent=None):
        QWidget.__init__(self, parent)
        self.index = index

        self.layout = QGridLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)

        self.waypoint_label = QLabel("Waypoint %s:" % index, self)
        self.layout.addWidget(self.waypoint_label, 0, 0)

        self.waypoint_x_spinbox = QSpinBox(self)
        self.waypoint_x_spinbox.blockSignals(True)
        self.waypoint_x_spinbox.setRange(0, map_size_x)
        self.layout.addWidget(self.waypoint_x_spinbox, 0, 1)
        self.waypoint_x_spinbox.valueChanged.connect(self.update_waypoint)
        self.waypoint_x_spinbox.blockSignals(False)

        self.waypoint_y_spinbox = QSpinBox(self)
        self.waypoint_y_spinbox.blockSignals(True)
        self.waypoint_y_spinbox.setRange(0, map_size_y)
        self.layout.addWidget(self.waypoint_y_spinbox, 0, 2)
        self.waypoint_y_spinbox.valueChanged.connect(self.update_waypoint)
        self.waypoint_y_spinbox.blockSignals(False)

        self.layout.addWidget(QLabel("Duration: ", self), 0, 3)
        self.duration_spinbox = QSpinBox(self)
        self.duration_spinbox.blockSignals(True)
        self.duration_spinbox.setRange(0, 10)
        self.layout.addWidget(self.duration_spinbox, 0, 4)
        self.duration_spinbox.valueChanged.connect(self.update_waypoint)
        self.duration_spinbox.blockSignals(False)

        self.remove_button = WosIconPushButton(
            qtawesome.icon('fa.minus-square-o'),
            qtawesome.icon('fa.minus-square'), self)
        self.remove_button.setToolTip('Remove Waypoint %s' % self.index)
        self.remove_button.released.connect(self.remove_button_pressed)
        self.layout.addWidget(self.remove_button, 0, 5)

    def get_index(self):
        return self.index

    def get_waypoint_info(self):
        return int(self.waypoint_x_spinbox.value()), int(
            self.waypoint_y_spinbox.value()), int(
                self.duration_spinbox.value())

    def set_index(self, index):
        self.index = index
        self.waypoint_label.setText("Waypoint %s:" % index)
        self.remove_button.setToolTip('Remove Waypoint %s' % self.index)

    def remove_button_pressed(self):
        self.waypoint_remove_pressed.emit(self.index)

    def update_waypoint(self):
        self.waypoint_changed.emit(self.index, self.waypoint_x_spinbox.value(),
                                   self.waypoint_y_spinbox.value(),
                                   self.duration_spinbox.value())
Esempio n. 16
0
class DistanceIRV2(COMCUPluginBase):
    NUM_VALUES = 512
    DIVIDER = 2**12 // NUM_VALUES

    def __init__(self, *args):
        super().__init__(BrickletDistanceIRV2, *args)

        self.dist = self.device

        self.cbe_distance = CallbackEmulator(self.dist.get_distance, None,
                                             self.cb_distance,
                                             self.increase_error_count)
        self.cbe_analog_value = CallbackEmulator(self.dist.get_analog_value,
                                                 None, self.cb_analog_value,
                                                 self.increase_error_count)

        self.analog_label = AnalogLabel('Analog Value:')
        hlayout = QHBoxLayout()
        self.average_label = QLabel('Moving Average Length:')
        self.average_spin = QSpinBox()
        self.average_spin.setMinimum(1)
        self.average_spin.setMaximum(1000)
        self.average_spin.setSingleStep(1)
        self.average_spin.setValue(25)
        self.average_spin.editingFinished.connect(self.average_spin_finished)

        self.sensor_label = QLabel('Sensor Type:')
        self.sensor_combo = QComboBox()
        self.sensor_combo.addItem('2Y0A41 (4-30cm)')
        self.sensor_combo.addItem('2Y0A21 (10-80cm)')
        self.sensor_combo.addItem('2Y0A02 (20-150cm)')
        self.sensor_combo.currentIndexChanged.connect(
            self.sensor_combo_changed)

        hlayout.addWidget(self.average_label)
        hlayout.addWidget(self.average_spin)
        hlayout.addStretch()
        hlayout.addWidget(self.sensor_label)
        hlayout.addWidget(self.sensor_combo)

        self.current_distance = CurveValueWrapper()  # float, cm

        plots = [('Distance', Qt.red, self.current_distance, '{} cm'.format)]
        self.plot_widget = PlotWidget('Distance [cm]',
                                      plots,
                                      extra_key_widgets=[self.analog_label],
                                      y_resolution=0.1)

        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 sensor_combo_changed(self, index):
        self.dist.set_sensor_type(index)

    def average_spin_finished(self):
        self.dist.set_moving_average_configuration(self.average_spin.value())

    def get_moving_average_configuration_async(self, average):
        self.average_spin.blockSignals(True)
        self.average_spin.setValue(average)
        self.average_spin.blockSignals(False)

    def get_sensor_type_async(self, sensor):
        self.sensor_combo.blockSignals(True)
        self.sensor_combo.setCurrentIndex(sensor)
        self.sensor_combo.blockSignals(False)

    def start(self):
        async_call(self.dist.get_moving_average_configuration, None,
                   self.get_moving_average_configuration_async,
                   self.increase_error_count)
        async_call(self.dist.get_sensor_type, None, self.get_sensor_type_async,
                   self.increase_error_count)

        self.cbe_distance.set_period(10)
        self.cbe_analog_value.set_period(100)

        self.plot_widget.stop = False

    def stop(self):
        self.cbe_distance.set_period(0)
        self.cbe_analog_value.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletDistanceIRV2.DEVICE_IDENTIFIER

    def cb_distance(self, distance):
        self.current_distance.value = distance / 10.0

    def cb_analog_value(self, analog_value):
        self.analog_label.setText(analog_value)
Esempio n. 17
0
class QTimeSlider(QWidget):
    """
    This will be slightly different from QTimeSelect in that time down
    to the nearest nanosecond can be selected, and need not be snapped to
    the nearest video frame.
    """
    timeSelectionChanged = pyqtSignal(int, float)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        layout = QVBoxLayout()
        self.setLayout(layout)

        self.slider = Slider(self)
        self.slider.setOrientation(Qt.Horizontal)
        self.slider.valueChanged.connect(self._handleSliderChange)
        self.slider.setTickInterval(1)

        layout.addWidget(self.slider)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        self.leftLabel = QLabel(self)

        self.spinBox = QSpinBox(self)
        self.spinBox.valueChanged.connect(self._handleSpinboxChange)

        self.timeSelect = QTimeSelect(self)
        self.timeSelect.valueChanged.connect(self._handleTimeEditChange)
        # self.timeSelect.editingFinished.connect(self._handleTimeEditFinished)

        self.rightLabel = QLabel(self)

        hlayout.addWidget(self.leftLabel)
        hlayout.addStretch()
        hlayout.addWidget(QLabel("Frame index:", self))
        hlayout.addWidget(self.spinBox)
        hlayout.addWidget(QLabel("Timestamp:", self))
        hlayout.addWidget(self.timeSelect)
        hlayout.addStretch()
        hlayout.addWidget(self.rightLabel)

        self.setPtsTimeArray(None)

    def setMinimum(self, n=0, t=None):
        self.slider.setMinimum(n)
        self.spinBox.setMinimum(n)

        if t is None:
            t = self.pts_time[n]

        self.timeSelect.setMinimum(t)

        m, s = divmod(self.pts_time[n], 60)
        h, m = divmod(int(m), 60)

        self.leftLabel.setText(f"{n} ({h}:{m:02d}:{s:012.9f})")

    def setMaximum(self, n=None, t=None):
        if n is None:
            n = len(self.pts_time) - 1

        self.slider.setMaximum(n)
        self.spinBox.setMaximum(n)

        if t is None:
            t = self.pts_time[n]

        self.timeSelect.setMaximum(t)

        m, s = divmod(self.pts_time[n], 60)
        h, m = divmod(int(m), 60)

        self.rightLabel.setText(f"{n} ({h}:{m:02d}:{s:012.9f})")

    def setStartEndVisible(self, value):
        self.leftLabel.setHidden(not bool(value))
        self.rightLabel.setHidden(not bool(value))

    def setPtsTimeArray(self, pts_time=None):
        self.pts_time = pts_time

        if pts_time is not None:
            N = len(pts_time)
            self.setMinimum(0)
            self.setMaximum(N - 1)

            self.slider.setValue(0)
            self.slider.setSnapValues(None)

            self.slider.setDisabled(False)
            self.spinBox.setDisabled(False)
            self.timeSelect.setDisabled(False)

        else:
            self.slider.setSnapValues(None)
            self.slider.setDisabled(True)
            self.spinBox.setDisabled(True)
            self.timeSelect.setDisabled(True)

    def _handleSliderChange(self, n):
        self.spinBox.blockSignals(True)
        self.spinBox.setValue(n)
        self.spinBox.blockSignals(False)

        if self.pts_time is None:
            self.timeSelectionChanged.emit(n, 0)
            return

        pts_time = self.pts_time[n]

        self.timeSelect.blockSignals(True)
        self.timeSelect.setValue(pts_time)
        self.timeSelect.blockSignals(False)

        self.timeSelectionChanged.emit(n, pts_time)

    def _handleSpinboxChange(self, n):
        self.slider.blockSignals(True)
        self.slider.setValue(n)
        self.slider.blockSignals(False)

        if self.pts_time is None:
            self.timeSelectionChanged.emit(n, 0)
            return

        pts_time = self.pts_time[n]

        self.timeSelect.blockSignals(True)
        self.timeSelect.setValue(pts_time)
        self.timeSelect.blockSignals(False)

        self.timeSelectionChanged.emit(n, pts_time)

    def _handleTimeEditChange(self, t):
        if self.pts_time is None:
            self.timeSelectionChanged.emit(0, t)
            return

        if t + 0.0005 >= self.pts_time[0]:
            n = search(self.pts_time, t + 0.0005, dir="-")

        else:
            n = 0

        if n != self.slider.value():
            self.slider.blockSignals(True)
            self.slider.setValue(n)
            self.slider.blockSignals(False)

            self.spinBox.blockSignals(True)
            self.spinBox.setValue(n)
            self.spinBox.blockSignals(False)

        self.timeSelectionChanged.emit(n, t)
Esempio n. 18
0
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()
Esempio n. 19
0
class QFrameSelect(QWidget):
    frameSelectionChanged = pyqtSignal(int, QTime)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        layout = QVBoxLayout()
        self.setLayout(layout)

        self.slider = Slider(self)
        self.slider.setOrientation(Qt.Horizontal)
        self.slider.valueChanged.connect(self._handleSliderChange)
        self.slider.setTickInterval(1)

        layout.addWidget(self.slider)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        self.leftLabel = QLabel(self)

        self.spinBox = QSpinBox(self)
        self.spinBox.valueChanged.connect(self._handleSpinboxChange)

        self.currentTime = QTimeEdit(self)
        self.currentTime.setDisplayFormat("H:mm:ss.zzz")
        self.currentTime.timeChanged.connect(self._handleTimeEditChange)
        self.currentTime.editingFinished.connect(self._handleTimeEditFinished)

        self.rightLabel = QLabel(self)

        hlayout.addWidget(self.leftLabel)
        hlayout.addStretch()
        hlayout.addWidget(QLabel("Frame index:", self))
        hlayout.addWidget(self.spinBox)
        hlayout.addWidget(QLabel("Timestamp:", self))
        hlayout.addWidget(self.currentTime)
        hlayout.addStretch()
        hlayout.addWidget(self.rightLabel)

        self.setPtsTimeArray(None)

    def setValue(self, n):
        self.slider.setValue(n)

    def setMinimum(self, n=0):
        self.slider.setMinimum(n)
        self.spinBox.setMinimum(n)

        ms = int(self.pts_time[n] * 1000 + 0.5)
        s, ms = divmod(ms, 1000)
        m, s = divmod(s, 60)
        h, m = divmod(m, 60)

        self.currentTime.setMinimumTime(QTime(h, m, s, ms))
        self.leftLabel.setText(f"{n} ({h}:{m:02d}:{s:02d}.{ms:03d})")

    def setMaximum(self, n=None):
        if n is None:
            n = len(self.pts_time) - 1

        self.slider.setMaximum(n)
        self.spinBox.setMaximum(n)

        ms = int(self.pts_time[n] * 1000 + 0.5)
        s, ms = divmod(ms, 1000)
        m, s = divmod(s, 60)
        h, m = divmod(m, 60)

        self.currentTime.setMaximumTime(QTime(h, m, s, ms))
        self.rightLabel.setText(f"{n} ({h}:{m:02d}:{s:02d}.{ms:03d})")

    def setStartEndVisible(self, value):
        self.leftLabel.setHidden(not bool(value))
        self.rightLabel.setHidden(not bool(value))

    def setPtsTimeArray(self, pts_time=None):
        self.pts_time = pts_time

        if pts_time is not None:
            N = len(pts_time)
            self.setMinimum(0)
            self.setMaximum(N - 1)

            self.slider.setValue(0)
            self.slider.setSnapValues(None)

            self.slider.setDisabled(False)
            self.spinBox.setDisabled(False)
            self.currentTime.setDisabled(False)

        else:
            self.slider.setMinimum(0)
            self.slider.setMaximum(0)
            self.slider.setSnapValues(None)
            self.slider.setDisabled(True)
            self.spinBox.setDisabled(True)
            self.currentTime.setDisabled(True)

    def _handleSliderChange(self, n):
        self.spinBox.blockSignals(True)
        self.spinBox.setValue(n)
        self.spinBox.blockSignals(False)

        pts_time = self.pts_time[n]
        ms = int(pts_time * 1000 + 0.5)
        s, ms = divmod(ms, 1000)
        m, s = divmod(s, 60)
        h, m = divmod(m, 60)

        self.currentTime.blockSignals(True)
        self.currentTime.setTime(QTime(h, m, s, ms))
        self.currentTime.blockSignals(False)

        self.frameSelectionChanged.emit(n, QTime(h, m, s, ms))

    def _handleSpinboxChange(self, n):
        self.slider.blockSignals(True)
        self.slider.setValue(n)
        self.slider.blockSignals(False)

        pts_time = self.pts_time[n]
        ms = int(pts_time * 1000 + 0.5)
        s, ms = divmod(ms, 1000)
        m, s = divmod(s, 60)
        h, m = divmod(m, 60)

        self.currentTime.blockSignals(True)
        self.currentTime.setTime(QTime(h, m, s, ms))
        self.currentTime.blockSignals(False)

        self.frameSelectionChanged.emit(n, QTime(h, m, s, ms))

    def _handleTimeEditChange(self, t):
        pts = t.msecsSinceStartOfDay() / 1000

        try:
            n = search(self.pts_time, pts + 0.0005, dir="-")

        except IndexError:
            n = 0

        if n != self.slider.value():
            self.slider.blockSignals(True)
            self.slider.setValue(n)
            self.slider.blockSignals(False)

            self.spinBox.blockSignals(True)
            self.spinBox.setValue(n)
            self.spinBox.blockSignals(False)

            pts_time = self.pts_time[n]
            ms = int(pts_time * 1000 + 0.5)
            s, ms = divmod(ms, 1000)
            m, s = divmod(s, 60)
            h, m = divmod(m, 60)

            self.frameSelectionChanged.emit(n, QTime(h, m, s, ms))

    def _handleTimeEditFinished(self):
        t = self.currentTime.time()
        pts = t.msecsSinceStartOfDay() / 1000
        n = search(self.pts_time, pts + 0.0005, dir="-")
        pts_time = self.pts_time[n]

        ms = int(pts_time * 1000 + 0.5)
        s, ms = divmod(ms, 1000)
        m, s = divmod(s, 60)
        h, m = divmod(m, 60)
        T = QTime(h, m, s, ms)

        if t != T:
            self.currentTime.setTime(T)
Esempio n. 20
0
class QHSLAdjDlg(QFilterConfig):
    allowedtypes = ("video",)

    def _createControls(self):
        self.setWindowTitle("Configure Hue/Saturation/Luminosity")

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        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)
        layout.addWidget(self.sourceWidget)

        self.imageView = QImageView(self)
        layout.addWidget(self.imageView)

        self.slider = QFrameSelect(self)
        self.slider.frameSelectionChanged.connect(self.loadFrame)
        layout.addWidget(self.slider)

        hueLabel = QLabel("Hue adjustment:", self)
        self.hueSpinBox = QSpinBox(self)
        self.hueSpinBox.setMinimum(-179)
        self.hueSpinBox.setMaximum(180)
        self.hueSpinBox.valueChanged.connect(
            self._handleHueSpinBoxValueChanged)

        satLabel = QLabel("Saturation factor:", self)
        self.satSpinBox = QDoubleSpinBox(self)
        self.satSpinBox.setDecimals(2)
        self.satSpinBox.setSingleStep(0.1)
        self.satSpinBox.setMinimum(0)
        self.satSpinBox.setMaximum(10)
        self.satSpinBox.valueChanged.connect(
            self._handleSatSpinBoxValueChanged)

        lumLabel = QLabel("Luminosity factor:", self)
        self.lumSpinBox = QDoubleSpinBox(self)
        self.lumSpinBox.setDecimals(2)
        self.lumSpinBox.setMinimum(0)
        self.lumSpinBox.setMaximum(10)
        self.lumSpinBox.valueChanged.connect(
            self._handleLumSpinBoxValueChanged)

        hlayout = QHBoxLayout()

        hlayout.addStretch()
        hlayout.addWidget(hueLabel)
        hlayout.addWidget(self.hueSpinBox)

        hlayout.addStretch()
        hlayout.addWidget(satLabel)
        hlayout.addWidget(self.satSpinBox)

        hlayout.addStretch()
        hlayout.addWidget(lumLabel)
        hlayout.addWidget(self.lumSpinBox)

        hlayout.addStretch()

        layout.addLayout(hlayout)

        self._prepareDlgButtons()

    def createNewFilterInstance(self):
        return HSLAdjust()

    def _resetControls(self):
        self.hueSpinBox.blockSignals(True)
        self.hueSpinBox.setValue(self.filtercopy.dh)
        self.hueSpinBox.blockSignals(False)

        self.satSpinBox.blockSignals(True)
        self.satSpinBox.setValue(self.filtercopy.sfactor)
        self.satSpinBox.blockSignals(False)

        self.lumSpinBox.blockSignals(True)
        self.lumSpinBox.setValue(self.filtercopy.lgamma)
        self.lumSpinBox.blockSignals(False)

        if self.filtercopy.prev is not None:
            self.slider.setPtsTimeArray(self.filtercopy.prev.pts_time)
            self.loadFrame(self.slider.slider.value(), QTime())

    def _handleHueSpinBoxValueChanged(self, value):
        self.filtercopy.dh = value
        self.isModified()
        self.loadFrame(self.slider.slider.value(), None)

    def _handleSatSpinBoxValueChanged(self, value):
        self.filtercopy.sfactor = value
        self.isModified()
        self.loadFrame(self.slider.slider.value(), None)

    def _handleLumSpinBoxValueChanged(self, value):
        self.filtercopy.sfactor = value
        self.isModified()
        self.loadFrame(self.slider.slider.value(), None)

    @pyqtSlot(int, QTime)
    def loadFrame(self, n, t):
        if self.filtercopy.prev is not None:
            frame = next(self.filtercopy.iterFrames(n, whence="framenumber"))
            im = frame.to_image()
            pixmap = im.convert("RGBA").toqpixmap()
            self.imageView.setFrame(pixmap)

    def _prevChanged(self, source):
        self.slider.setPtsTimeArray(source.pts_time)
        self.loadFrame(self.slider.slider.value(),
                       self.slider.currentTime.time())
Esempio n. 21
0
class PlotWidget(QWidget):
    def __init__(self,
                 y_scale_title_text,
                 curve_configs,
                 clear_button='default',
                 parent=None,
                 x_scale_visible=True,
                 y_scale_visible=True,
                 curve_outer_border_visible=True,
                 curve_motion_granularity=1.0, # seconds
                 canvas_color=QColor(245, 245, 245),
                 external_timer=None,
                 key='top-value', # top-value, right-no-icon
                 extra_key_widgets=None,
                 update_interval=0.1, # seconds
                 curve_start='left',
                 moving_average_config=None,
                 x_scale_title_text='Time [s]',
                 x_diff=20,
                 x_scale_skip_last_tick=True,
                 y_resolution=None,
                 y_scale_shrinkable=True):
        super().__init__(parent)

        self.setMinimumSize(300, 250)

        if y_resolution != None:
            y_diff_min = y_resolution * 20
        else:
            y_diff_min = None

        self._stop = True
        self.curve_configs = [CurveConfig(*curve_config) for curve_config in curve_configs]

        for curve_config in self.curve_configs:
            if curve_config.value_wrapper != None:
                assert isinstance(curve_config.value_wrapper, CurveValueWrapper)

        self.plot = Plot(self, x_scale_title_text, y_scale_title_text, x_scale_skip_last_tick,
                         self.curve_configs, x_scale_visible, y_scale_visible, curve_outer_border_visible,
                         curve_motion_granularity, canvas_color, curve_start, x_diff, y_diff_min,
                         y_scale_shrinkable, update_interval)
        self.set_x_scale = self.plot.set_x_scale
        self.set_fixed_y_scale = self.plot.set_fixed_y_scale
        self.key = key
        self.key_items = []
        self.key_has_values = key.endswith('-value') if key != None else False
        self.first_show = True
        self.timestamp = 0 # seconds
        self.update_interval = update_interval # seconds

        h1layout = QHBoxLayout()
        h1layout.setContentsMargins(0, 0, 0, 0)
        h1layout_empty = True

        if clear_button == 'default':
            self.clear_button = QToolButton()
            self.clear_button.setText('Clear Graph')

            h1layout.addWidget(self.clear_button)
            h1layout.addStretch(1)
            h1layout_empty = False
        else:
            self.clear_button = clear_button

        if self.clear_button != None:
            self.clear_button.clicked.connect(self.clear_clicked)

        v1layout = None

        if self.key != None:
            if len(self.curve_configs) == 1:
                label = FixedSizeLabel(self)
                label.setText(self.curve_configs[0].title)

                self.key_items.append(label)
            else:
                for i, curve_config in enumerate(self.curve_configs):

                    button = FixedSizeToolButton(self)
                    button.setText(curve_config.title)

                    if self.key.endswith('-no-icon'):
                        button.setStyleSheet('color: ' + QColor(curve_config.color).name())
                    else:
                        pixmap = QPixmap(10, 2)
                        QPainter(pixmap).fillRect(0, 0, 10, 2, curve_config.color)

                        button.setIcon(QIcon(pixmap))

                    button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
                    button.setCheckable(True)
                    button.setChecked(True)
                    button.toggled.connect(functools.partial(self.plot.show_curve, i))

                    self.key_items.append(button)

            if self.key.startswith('top-'):
                for key_item in self.key_items:
                    h1layout.addWidget(key_item)
                    h1layout_empty = False
            elif self.key.startswith('right-'):
                v1layout = QVBoxLayout()
                v1layout.setContentsMargins(0, 0, 0, 0)
                v1layout.addSpacing(self.plot.get_legend_offset_y())

                for key_item in self.key_items:
                    v1layout.addWidget(key_item)

                v1layout.addStretch(1)
            else:
                assert False, 'unknown key: ' + self.key

        if not h1layout_empty:
            h1layout.addStretch(1)

        if extra_key_widgets != None:
            if self.key == None or self.key.startswith('top'):
                for widget in extra_key_widgets:
                    h1layout.addWidget(widget)
                    h1layout_empty = False
            elif self.key.startswith('right'):
                if v1layout == None:
                    v1layout = QVBoxLayout()
                    v1layout.setContentsMargins(0, 0, 0, 0)
                    v1layout.addSpacing(self.plot.get_legend_offset_y())

                if self.key.startswith('top'):
                    for widget in extra_key_widgets:
                        v1layout.addWidget(widget)

        v2layout = QVBoxLayout(self)
        v2layout.setContentsMargins(0, 0, 0, 0)

        if not h1layout_empty:
            v2layout.addLayout(h1layout)

        if v1layout != None:
            h2layout = QHBoxLayout()
            h2layout.setContentsMargins(0, 0, 0, 0)

            h2layout.addWidget(self.plot)
            h2layout.addLayout(v1layout)

            v2layout.addLayout(h2layout)
        else:
            v2layout.addWidget(self.plot)

        self.moving_average_config = moving_average_config

        if moving_average_config != None:
            self.moving_average_label = QLabel('Moving Average Length:')
            self.moving_average_spinbox = QSpinBox()
            self.moving_average_spinbox.setMinimum(moving_average_config.min_length)
            self.moving_average_spinbox.setMaximum(moving_average_config.max_length)
            self.moving_average_spinbox.setSingleStep(1)

            self.moving_average_layout = QHBoxLayout()
            self.moving_average_layout.addStretch()
            self.moving_average_layout.addWidget(self.moving_average_label)
            self.moving_average_layout.addWidget(self.moving_average_spinbox)
            self.moving_average_layout.addStretch()

            self.moving_average_spinbox.valueChanged.connect(self.moving_average_spinbox_value_changed)

            v2layout.addLayout(self.moving_average_layout)

        if external_timer == None:
            self.timer = QTimer(self)
            self.timer.timeout.connect(self.add_new_data)
            self.timer.start(self.update_interval * 1000)
        else:
            # assuming that the external timer runs with the configured interval
            external_timer.timeout.connect(self.add_new_data)

    def update_y_scale_sibling(self, plot_widget): # internal
        total_unpadded_width_diff = plot_widget.plot.y_scale.total_unpadded_width - self.plot.y_scale.total_unpadded_width

        self.plot.y_scale.set_title_text_padding(total_unpadded_width_diff)

    def add_y_scale_sibling(self, plot_widget):
        plot_widget.plot.y_scale.total_width_changed.connect(functools.partial(self.update_y_scale_sibling, plot_widget))

    def set_moving_average_value(self, value):
        self.moving_average_spinbox.blockSignals(True)
        self.moving_average_spinbox.setValue(value)
        self.moving_average_spinbox.blockSignals(False)

    def get_moving_average_value(self):
        return self.moving_average_spinbox.value()

    def moving_average_spinbox_value_changed(self, value):
        if self.moving_average_config != None:
            if self.moving_average_config.callback != None:
                self.moving_average_config.callback(value)

    # overrides QWidget.showEvent
    def showEvent(self, event):
        QWidget.showEvent(self, event)

        if self.first_show:
            self.first_show = False

            if len(self.key_items) > 1 and self.key.startswith('right'):
                width = max([key_item.width() for key_item in self.key_items])

                for key_item in self.key_items:
                    size = key_item.minimumSize()

                    size.setWidth(width)

                    key_item.setMinimumSize(size)

    def get_key_item(self, i):
        return self.key_items[i]

    def set_data(self, i, x, y):
        # FIXME: how to set potential key items from this?
        self.plot.set_data(i, x, y)

    @property
    def stop(self):
        return self._stop

    @stop.setter
    def stop(self, stop):
        for i, curve_config in enumerate(self.curve_configs):
            if curve_config.value_wrapper == None:
                continue

            curve_config.value_wrapper.valid = False
            curve_config.value_wrapper.locked = stop

            if stop:
                self.plot.add_jump(i)

        self._stop = stop

    # internal
    def add_new_data(self):
        if self.stop:
            return

        any_valid = False

        for i, curve_config in enumerate(self.curve_configs):
            if curve_config.value_wrapper == None:
                continue

            valid = curve_config.value_wrapper.valid
            value = curve_config.value_wrapper.value

            if valid:
                assert value != None

                any_valid = True

                if len(self.key_items) > 0 and self.key_has_values:
                    self.key_items[i].setText(curve_config.title + ': ' + curve_config.value_formatter(value))

                self.plot.add_data(i, self.timestamp, value)
            elif len(self.key_items) > 0 and self.key_has_values:
                self.key_items[i].setText(curve_config.title)

        if any_valid:
            self.timestamp += self.update_interval

    # internal
    def clear_clicked(self):
        self.plot.clear_graph()
        self.timestamp = 0
Esempio n. 22
0
class DateTimeDialog(QDialog):
    """Dialog to specify time in the recordings, either as seconds from the
    start of the recordings or absolute time.

    Parameters
    ----------
    title : str
        'Lights out' or 'Lights on'
    start_time : datetime
        absolute start time of the recordings
    dur : int
        total duration of the recordings

    Notes
    -----
    The value of interest is in self.idx_seconds.value(), which is seconds
    from the start of the recordings.
    """
    def __init__(self, title, start_time, dur):
        super().__init__()

        self.start_time = start_time
        self.dur = dur
        end_time = start_time + timedelta(seconds=dur)

        self.setWindowTitle(title)

        bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.idx_ok = bbox.button(QDialogButtonBox.Ok)
        self.idx_cancel = bbox.button(QDialogButtonBox.Cancel)

        bbox.clicked.connect(self.button_clicked)

        self.idx_seconds = QSpinBox()
        self.idx_seconds.setMinimum(0)
        self.idx_seconds.setMaximum(dur)
        self.idx_seconds.valueChanged.connect(self.changed_spin)

        self.idx_datetime = QDateTimeEdit(start_time)
        self.idx_datetime.setMinimumDate(start_time)
        self.idx_datetime.setMaximumDate(end_time)
        self.idx_datetime.setDisplayFormat('dd-MMM-yyyy HH:mm:ss')
        self.idx_datetime.dateTimeChanged.connect(self.changed_datetime)

        layout = QFormLayout()
        layout.addRow('', QLabel('Enter ' + title + ' time'))
        layout.addRow('Seconds from recording start', self.idx_seconds)
        layout.addRow('Absolute time', self.idx_datetime)
        layout.addRow(bbox)

        self.setLayout(layout)

    def button_clicked(self, button):
        if button == self.idx_ok:
            self.accept()

        elif button == self.idx_cancel:
            self.reject()

    def changed_spin(self, i):
        self.idx_datetime.blockSignals(True)
        self.idx_datetime.setDateTime(self.start_time + timedelta(seconds=i))
        self.idx_datetime.blockSignals(False)

    def changed_datetime(self, dt):
        val = (dt.toPyDateTime() - self.start_time).total_seconds()

        if val < 0 or val >= self.dur:
            val = min(self.dur, max(val, 0))
            self.changed_spin(val)

        self.idx_seconds.blockSignals(True)
        self.idx_seconds.setValue(val)
        self.idx_seconds.blockSignals(False)
Esempio n. 23
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")

        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
Esempio n. 24
0
class WeatherStationBrowser(QWidget):
    """
    Widget that allows the user to browse and select ECCC climate stations.
    """

    ConsoleSignal = QSignal(str)
    staListSignal = QSignal(list)

    PROV_NAME = [x[0].title() for x in PROV_NAME_ABB]
    PROV_ABB = [x[1] for x in PROV_NAME_ABB]

    def __init__(self, parent=None):
        super(WeatherStationBrowser, self).__init__(parent)
        self.stn_finder_worker = WeatherStationFinder()
        self.stn_finder_worker.sig_load_database_finished.connect(
            self.receive_load_database)
        self.stn_finder_thread = QThread()
        self.stn_finder_worker.moveToThread(self.stn_finder_thread)

        self.station_table = WeatherSationView()
        self.waitspinnerbar = WaitSpinnerBar()
        self.stn_finder_worker.sig_progress_msg.connect(
            self.waitspinnerbar.set_label)
        self.__initUI__()

        self.start_load_database()

    def __initUI__(self):
        self.setWindowTitle('Weather Stations Browser')
        self.setWindowIcon(icons.get_icon('master'))
        self.setWindowFlags(Qt.Window)

        now = datetime.now()

        # ---- Tab Widget Search

        # ---- Proximity filter groupbox

        label_Lat = QLabel('Latitude :')
        label_Lat2 = QLabel('North')

        self.lat_spinBox = QDoubleSpinBox()
        self.lat_spinBox.setAlignment(Qt.AlignCenter)
        self.lat_spinBox.setSingleStep(0.1)
        self.lat_spinBox.setValue(0)
        self.lat_spinBox.setMinimum(0)
        self.lat_spinBox.setMaximum(180)
        self.lat_spinBox.setSuffix(u' °')
        self.lat_spinBox.valueChanged.connect(self.proximity_grpbox_toggled)

        label_Lon = QLabel('Longitude :')
        label_Lon2 = QLabel('West')

        self.lon_spinBox = QDoubleSpinBox()
        self.lon_spinBox.setAlignment(Qt.AlignCenter)
        self.lon_spinBox.setSingleStep(0.1)
        self.lon_spinBox.setValue(0)
        self.lon_spinBox.setMinimum(0)
        self.lon_spinBox.setMaximum(180)
        self.lon_spinBox.setSuffix(u' °')
        self.lon_spinBox.valueChanged.connect(self.proximity_grpbox_toggled)

        self.radius_SpinBox = QComboBox()
        self.radius_SpinBox.addItems(['25 km', '50 km', '100 km', '200 km'])
        self.radius_SpinBox.currentIndexChanged.connect(
            self.search_filters_changed)

        prox_search_grid = QGridLayout()
        row = 0
        prox_search_grid.addWidget(label_Lat, row, 1)
        prox_search_grid.addWidget(self.lat_spinBox, row, 2)
        prox_search_grid.addWidget(label_Lat2, row, 3)
        row += 1
        prox_search_grid.addWidget(label_Lon, row, 1)
        prox_search_grid.addWidget(self.lon_spinBox, row, 2)
        prox_search_grid.addWidget(label_Lon2, row, 3)
        row += 1
        prox_search_grid.addWidget(QLabel('Search Radius :'), row, 1)
        prox_search_grid.addWidget(self.radius_SpinBox, row, 2)

        prox_search_grid.setColumnStretch(0, 100)
        prox_search_grid.setColumnStretch(4, 100)
        prox_search_grid.setRowStretch(row + 1, 100)
        prox_search_grid.setHorizontalSpacing(20)
        prox_search_grid.setContentsMargins(10, 10, 10, 10)  # (L, T, R, B)

        self.prox_grpbox = QGroupBox("Proximity filter :")
        self.prox_grpbox.setCheckable(True)
        self.prox_grpbox.setChecked(False)
        self.prox_grpbox.toggled.connect(self.proximity_grpbox_toggled)
        self.prox_grpbox.setLayout(prox_search_grid)

        # ---- Province filter

        prov_names = ['All']
        prov_names.extend(self.PROV_NAME)
        self.prov_widg = QComboBox()
        self.prov_widg.addItems(prov_names)
        self.prov_widg.setCurrentIndex(0)
        self.prov_widg.currentIndexChanged.connect(self.search_filters_changed)

        layout = QGridLayout()
        layout.addWidget(self.prov_widg, 2, 1)
        layout.setColumnStretch(2, 100)
        layout.setVerticalSpacing(10)

        prov_grpbox = QGroupBox("Province filter :")
        prov_grpbox.setLayout(layout)

        # ---- Data availability filter

        # Number of years with data

        self.nbrYear = QSpinBox()
        self.nbrYear.setAlignment(Qt.AlignCenter)
        self.nbrYear.setSingleStep(1)
        self.nbrYear.setMinimum(0)
        self.nbrYear.setValue(3)
        self.nbrYear.valueChanged.connect(self.search_filters_changed)

        subgrid1 = QGridLayout()
        subgrid1.addWidget(self.nbrYear, 0, 0)
        subgrid1.addWidget(QLabel('years of data between'), 0, 1)

        subgrid1.setHorizontalSpacing(10)
        subgrid1.setContentsMargins(0, 0, 0, 0)  # (L, T, R, B)
        subgrid1.setColumnStretch(2, 100)

        # Year range

        self.minYear = QSpinBox()
        self.minYear.setAlignment(Qt.AlignCenter)
        self.minYear.setSingleStep(1)
        self.minYear.setMinimum(1840)
        self.minYear.setMaximum(now.year)
        self.minYear.setValue(1840)
        self.minYear.valueChanged.connect(self.minYear_changed)

        label_and = QLabel('and')
        label_and.setAlignment(Qt.AlignCenter)

        self.maxYear = QSpinBox()
        self.maxYear.setAlignment(Qt.AlignCenter)
        self.maxYear.setSingleStep(1)
        self.maxYear.setMinimum(1840)
        self.maxYear.setMaximum(now.year)
        self.maxYear.setValue(now.year)
        self.maxYear.valueChanged.connect(self.maxYear_changed)

        subgrid2 = QGridLayout()
        subgrid2.addWidget(self.minYear, 0, 0)
        subgrid2.addWidget(label_and, 0, 1)
        subgrid2.addWidget(self.maxYear, 0, 2)

        subgrid2.setHorizontalSpacing(10)
        subgrid2.setContentsMargins(0, 0, 0, 0)  # (L, T, R, B)
        subgrid2.setColumnStretch(4, 100)

        # Subgridgrid assembly

        grid = QGridLayout()

        grid.addWidget(QLabel('Search for stations with at least'), 0, 0)
        grid.addLayout(subgrid1, 1, 0)
        grid.addLayout(subgrid2, 2, 0)

        grid.setVerticalSpacing(5)
        grid.setRowStretch(0, 100)
        # grid.setContentsMargins(0, 0, 0, 0)  # (L, T, R, B)

        self.year_widg = QGroupBox("Data Availability filter :")
        self.year_widg.setLayout(grid)

        # ---- Toolbar

        self.btn_addSta = btn_addSta = QPushButton('Add')
        btn_addSta.setIcon(icons.get_icon('add2list'))
        btn_addSta.setIconSize(icons.get_iconsize('small'))
        btn_addSta.setToolTip('Add selected found weather stations to the '
                              'current list of weather stations.')
        btn_addSta.clicked.connect(self.btn_addSta_isClicked)

        btn_save = QPushButton('Save')
        btn_save.setIcon(icons.get_icon('save'))
        btn_save.setIconSize(icons.get_iconsize('small'))
        btn_save.setToolTip('Save current found stations info in a csv file.')
        btn_save.clicked.connect(self.btn_save_isClicked)

        self.btn_fetch = btn_fetch = QPushButton('Fetch')
        btn_fetch.setIcon(icons.get_icon('refresh'))
        btn_fetch.setIconSize(icons.get_iconsize('small'))
        btn_fetch.setToolTip("Updates the climate station database by"
                             " fetching it again from the ECCC ftp server.")
        btn_fetch.clicked.connect(self.btn_fetch_isClicked)

        toolbar_grid = QGridLayout()
        toolbar_widg = QWidget()

        for col, btn in enumerate([btn_addSta, btn_save, btn_fetch]):
            toolbar_grid.addWidget(btn, 0, col + 1)

        toolbar_grid.setColumnStretch(toolbar_grid.columnCount(), 100)
        toolbar_grid.setSpacing(5)
        toolbar_grid.setContentsMargins(0, 30, 0, 0)  # (L, T, R, B)

        toolbar_widg.setLayout(toolbar_grid)

        # ---- Left Panel

        panel_title = QLabel('<b>Weather Station Search Criteria :</b>')

        left_panel = QFrame()
        left_panel_grid = QGridLayout()

        left_panel_grid.addWidget(panel_title, 0, 0)
        left_panel_grid.addWidget(self.prox_grpbox, 1, 0)
        left_panel_grid.addWidget(prov_grpbox, 2, 0)
        left_panel_grid.addWidget(self.year_widg, 3, 0)
        left_panel_grid.setRowStretch(4, 100)
        left_panel_grid.addWidget(toolbar_widg, 5, 0)

        left_panel_grid.setVerticalSpacing(20)
        left_panel_grid.setContentsMargins(0, 0, 0, 0)  # (L, T, R, B)
        left_panel.setLayout(left_panel_grid)

        # ----- Main grid

        # Widgets

        vLine1 = QFrame()
        vLine1.setFrameStyle(StyleDB().VLine)

        # Grid

        main_layout = QGridLayout(self)

        main_layout.addWidget(left_panel, 0, 0)
        main_layout.addWidget(vLine1, 0, 1)
        main_layout.addWidget(self.station_table, 0, 2)
        main_layout.addWidget(self.waitspinnerbar, 0, 2)

        main_layout.setContentsMargins(10, 10, 10, 10)  # (L,T,R,B)
        main_layout.setRowStretch(0, 100)
        main_layout.setHorizontalSpacing(15)
        main_layout.setVerticalSpacing(5)
        main_layout.setColumnStretch(col, 100)

    @property
    def stationlist(self):
        return self.station_table.get_stationlist()

    @property
    def search_by(self):
        return ['proximity', 'province'][self.tab_widg.currentIndex()]

    @property
    def prov(self):
        if self.prov_widg.currentIndex() == 0:
            return self.PROV_ABB
        else:
            return self.PROV_ABB[self.prov_widg.currentIndex() - 1]

    @property
    def lat(self):
        return self.lat_spinBox.value()

    def set_lat(self, x, silent=True):
        if silent:
            self.lat_spinBox.blockSignals(True)
        self.lat_spinBox.setValue(x)
        self.lat_spinBox.blockSignals(False)
        self.proximity_grpbox_toggled()

    @property
    def lon(self):
        return self.lon_spinBox.value()

    def set_lon(self, x, silent=True):
        if silent:
            self.lon_spinBox.blockSignals(True)
        self.lon_spinBox.setValue(x)
        self.lon_spinBox.blockSignals(False)
        self.proximity_grpbox_toggled()

    @property
    def rad(self):
        return int(self.radius_SpinBox.currentText()[:-3])

    @property
    def prox(self):
        if self.prox_grpbox.isChecked():
            return (self.lat, -self.lon, self.rad)
        else:
            return None

    @property
    def year_min(self):
        return int(self.minYear.value())

    def set_yearmin(self, x, silent=True):
        if silent:
            self.minYear.blockSignals(True)
        self.minYear.setValue(x)
        self.minYear.blockSignals(False)

    @property
    def year_max(self):
        return int(self.maxYear.value())

    def set_yearmax(self, x, silent=True):
        if silent:
            self.maxYear.blockSignals(True)
        self.maxYear.setValue(x)
        self.maxYear.blockSignals(False)

    @property
    def nbr_of_years(self):
        return int(self.nbrYear.value())

    def set_yearnbr(self, x, silent=True):
        if silent:
            self.nbrYear.blockSignals(True)
        self.nbrYear.setValue(x)
        self.nbrYear.blockSignals(False)

    # ---- Weather Station Finder Handlers

    def start_load_database(self, force_fetch=False):
        """Start the process of loading the climate station database."""
        if self.stn_finder_thread.isRunning():
            return

        self.station_table.clear()
        self.waitspinnerbar.show()

        # Start the downloading process.
        if force_fetch:
            self.stn_finder_thread.started.connect(
                self.stn_finder_worker.fetch_database)
        else:
            self.stn_finder_thread.started.connect(
                self.stn_finder_worker.load_database)
        self.stn_finder_thread.start()

    @QSlot()
    def receive_load_database(self):
        """Handles when loading the database is finished."""
        # Disconnect the thread.
        self.stn_finder_thread.started.disconnect()

        # Quit the thread.
        self.stn_finder_thread.quit()
        waittime = 0
        while self.stn_finder_thread.isRunning():
            sleep(0.1)
            waittime += 0.1
            if waittime > 15:  # pragma: no cover
                print("Unable to quit the thread.")
                break
        # Force an update of the GUI.
        self.proximity_grpbox_toggled()
        if self.stn_finder_worker.data is None:
            self.waitspinnerbar.show_warning_icon()
        else:
            self.waitspinnerbar.hide()

    # ---- GUI handlers

    def show(self):
        super(WeatherStationBrowser, self).show()
        qr = self.frameGeometry()
        if self.parent():
            parent = self.parent()
            wp = parent.frameGeometry().width()
            hp = parent.frameGeometry().height()
            cp = parent.mapToGlobal(QPoint(wp / 2, hp / 2))
        else:
            cp = QDesktopWidget().availableGeometry().center()

        qr.moveCenter(cp)
        self.move(qr.topLeft())

    # -------------------------------------------------------------------------

    def minYear_changed(self):
        min_yr = min_yr = max(self.minYear.value(), 1840)

        now = datetime.now()
        max_yr = now.year

        self.maxYear.setRange(min_yr, max_yr)
        self.search_filters_changed()

    def maxYear_changed(self):
        min_yr = 1840

        now = datetime.now()
        max_yr = min(self.maxYear.value(), now.year)

        self.minYear.setRange(min_yr, max_yr)
        self.search_filters_changed()

    # ---- Toolbar Buttons Handlers

    def btn_save_isClicked(self):
        ddir = os.path.join(os.getcwd(), 'weather_station_list.csv')
        filename, ftype = QFileDialog().getSaveFileName(
            self, 'Save normals', ddir, '*.csv;;*.xlsx;;*.xls')
        self.station_table.save_stationlist(filename)

    def btn_addSta_isClicked(self):
        rows = self.station_table.get_checked_rows()
        if len(rows) > 0:
            staList = self.station_table.get_content4rows(rows)
            self.staListSignal.emit(staList)
            print('Selected stations sent to list')
        else:
            print('No station currently selected')

    def btn_fetch_isClicked(self):
        """Handles when the button fetch is clicked."""
        self.start_load_database(force_fetch=True)

    # ---- Search Filters Handlers

    def proximity_grpbox_toggled(self):
        """
        Set the values for the reference geo coordinates that are used in the
        WeatherSationView to calculate the proximity values and forces a
        refresh of the content of the table.
        """
        if self.prox_grpbox.isChecked():
            self.station_table.set_geocoord((self.lat, -self.lon))
        else:
            self.station_table.set_geocoord(None)
        self.search_filters_changed()

    def search_filters_changed(self):
        """
        Search for weather stations with the current filter values and forces
        an update of the station table content.
        """
        if self.stn_finder_worker.data is not None:
            stnlist = self.stn_finder_worker.get_stationlist(
                prov=self.prov,
                prox=self.prox,
                yrange=(self.year_min, self.year_max, self.nbr_of_years))
            self.station_table.populate_table(stnlist)
Esempio n. 25
0
class SpinnerDialComboWidget(QWidget):
    value_changed = pyqtSignal()

    # name: The string name that will be displayed on top of the widget
    # default_value: The value that will be initially set as the widget's value
    # min_val: The minimum value that will be initially set
    # max_val: The maximum value that will be initially set
    def __init__(self,
                 name="",
                 default_value=0,
                 min_val=0,
                 max_val=100,
                 parent=None):
        QWidget.__init__(self, parent=parent)

        # The minimum value that can be set
        self.min_val = min_val

        # The maximum value that can be set
        self.max_val = max_val

        # The widget's current value
        self.value = default_value

        self.title_label = QLabel(name)

        # The widget's dial
        self.dial = QDial(self)
        self.dial.setSingleStep(1)
        self.dial.setPageStep(1)
        self.dial.setMinimum(min_val)
        self.dial.setMaximum(max_val)
        self.dial.setValue(default_value)
        self.dial.valueChanged.connect(self.on_dial_changed)

        # The widget's spin box
        self.spinner = QSpinBox(self)
        self.spinner.setMinimum(min_val)
        self.spinner.setMaximum(max_val)
        self.spinner.setValue(default_value)
        self.spinner.valueChanged.connect(self.on_spinner_changed)

        self.setup_gui()

    # Sets up the positioning of the UI elements
    def setup_gui(self):
        vertical_layout = QVBoxLayout(self)

        vertical_layout.addStretch(1)
        vertical_layout.addWidget(self.title_label)
        vertical_layout.addWidget(self.spinner)
        vertical_layout.addWidget(self.dial)

    # The callback for when the dial is changes
    @pyqtSlot()
    def on_dial_changed(self):
        self.value = self.dial.value()

        self.spinner.blockSignals(True)

        self.spinner.setValue(self.dial.value())

        self.spinner.blockSignals(False)

        self.value_changed.emit()

    # The callback for when the spin box is changed
    @pyqtSlot()
    def on_spinner_changed(self):
        self.value = self.spinner.value()

        self.dial.blockSignals(True)

        self.dial.setValue(self.spinner.value())

        self.dial.blockSignals(False)

        self.value_changed.emit()

    # Sets the minimum value
    # new_min: The new minimum value to be set
    def set_min(self, new_min):
        if new_min > self.max_val:
            return

        self.min_val = new_min

        self.dial.blockSignals(True)
        self.spinner.blockSignals(True)

        self.spinner.setMinimum(new_min)
        self.dial.setMinimum(new_min)

        self.dial.blockSignals(False)
        self.spinner.blockSignals(False)

        self.value_changed.emit()

    # Sets the maximum value
    # new_max: The new maximum value to be set
    def set_max(self, new_max):
        if new_max < self.min_val:
            return

        self.max_val = new_max

        self.dial.blockSignals(True)
        self.spinner.blockSignals(True)

        self.spinner.setMaximum(new_max)
        self.dial.setMaximum(new_max)

        self.dial.blockSignals(False)
        self.spinner.blockSignals(False)

        self.value_changed.emit()

    # Sets the widget value
    # value: The value to be set
    def set_value(self, value):
        self.value = value

        self.dial.blockSignals(True)
        self.spinner.blockSignals(True)

        self.dial.setValue(value)
        self.spinner.setValue(value)

        self.dial.blockSignals(False)
        self.spinner.blockSignals(False)

        self.value_changed.emit()
Esempio n. 26
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())
Esempio n. 27
0
class WeatherStationDownloader(QMainWindow):
    """
    Widget that allows the user to browse and select ECCC climate stations.
    """
    sig_download_process_ended = QSignal()
    ConsoleSignal = QSignal(str)
    staListSignal = QSignal(list)

    PROV_NAME = [x[0].title() for x in PROV_NAME_ABB]
    PROV_ABB = [x[1] for x in PROV_NAME_ABB]

    def __init__(self, parent=None, workdir=None):
        super().__init__(parent)
        self.workdir = workdir or get_home_dir()

        self.stn_finder_worker = WeatherStationFinder()
        self.stn_finder_worker.sig_load_database_finished.connect(
            self.receive_load_database)
        self.stn_finder_thread = QThread()
        self.stn_finder_worker.moveToThread(self.stn_finder_thread)
        self._database_isloading = False

        self.station_table = WeatherSationView()
        self.waitspinnerbar = WaitSpinnerBar()
        self.stn_finder_worker.sig_progress_msg.connect(
            self.waitspinnerbar.set_label)

        self.__initUI__()
        self._restore_window_geometry()

        # Setup the raw data downloader.
        self._dwnld_inprogress = False
        self._dwnld_stations_list = []
        self.dwnld_thread = QThread()
        self.dwnld_worker = RawDataDownloader()
        self.dwnld_worker.moveToThread(self.dwnld_thread)

        self.dwnld_worker.sig_download_finished.connect(
            self.process_station_data)
        self.dwnld_worker.sig_update_pbar.connect(self.progressbar.setValue)

        self.start_load_database()

    def __initUI__(self):
        self.setWindowTitle('Download Weather Data')
        self.setWindowIcon(get_icon('master'))
        self.setWindowFlags(Qt.Window)

        now = datetime.now()

        # Setup the proximity filter group.
        self.lat_spinBox = QDoubleSpinBox()
        self.lat_spinBox.setAlignment(Qt.AlignCenter)
        self.lat_spinBox.setSingleStep(0.1)
        self.lat_spinBox.setDecimals(3)
        self.lat_spinBox.setValue(CONF.get('download_data', 'latitude', 0))
        self.lat_spinBox.setMinimum(0)
        self.lat_spinBox.setMaximum(180)
        self.lat_spinBox.setSuffix(u' °')
        self.lat_spinBox.valueChanged.connect(self.proximity_grpbox_toggled)

        self.lon_spinBox = QDoubleSpinBox()
        self.lon_spinBox.setAlignment(Qt.AlignCenter)
        self.lon_spinBox.setSingleStep(0.1)
        self.lon_spinBox.setDecimals(3)
        self.lon_spinBox.setValue(CONF.get('download_data', 'longitude', 0))
        self.lon_spinBox.setMinimum(0)
        self.lon_spinBox.setMaximum(180)
        self.lon_spinBox.setSuffix(u' °')
        self.lon_spinBox.valueChanged.connect(self.proximity_grpbox_toggled)

        self.radius_SpinBox = QComboBox()
        self.radius_SpinBox.addItems(['25 km', '50 km', '100 km', '200 km'])
        self.radius_SpinBox.setCurrentIndex(
            CONF.get('download_data', 'radius_index', 0))
        self.radius_SpinBox.currentIndexChanged.connect(
            self.search_filters_changed)

        self.prox_grpbox = QGroupBox("Proximity Filter")
        self.prox_grpbox.setCheckable(True)
        self.prox_grpbox.setChecked(
            CONF.get('download_data', 'proximity_filter', False))
        self.prox_grpbox.toggled.connect(self.proximity_grpbox_toggled)

        prox_search_grid = QGridLayout(self.prox_grpbox)
        prox_search_grid.addWidget(QLabel('Latitude:'), 0, 0)
        prox_search_grid.addWidget(self.lat_spinBox, 0, 1)
        prox_search_grid.addWidget(QLabel('North'), 0, 2)
        prox_search_grid.addWidget(QLabel('Longitude:'), 1, 0)
        prox_search_grid.addWidget(self.lon_spinBox, 1, 1)
        prox_search_grid.addWidget(QLabel('West'), 1, 2)
        prox_search_grid.addWidget(QLabel('Search Radius:'), 2, 0)
        prox_search_grid.addWidget(self.radius_SpinBox, 2, 1)
        prox_search_grid.setColumnStretch(0, 100)
        prox_search_grid.setRowStretch(3, 100)

        # ---- Province filter
        self.prov_widg = QComboBox()
        self.prov_widg.addItems(['All'] + self.PROV_NAME)
        self.prov_widg.setCurrentIndex(
            CONF.get('download_data', 'province_index', 0))
        self.prov_widg.currentIndexChanged.connect(self.search_filters_changed)

        prov_grpbox = QGroupBox()
        prov_layout = QGridLayout(prov_grpbox)
        prov_layout.addWidget(QLabel('Province:'), 0, 0)
        prov_layout.addWidget(self.prov_widg, 0, 1)
        prov_layout.setColumnStretch(0, 1)
        prov_layout.setRowStretch(1, 1)

        # ---- Data availability filter

        # Number of years with data
        self.nbrYear = QSpinBox()
        self.nbrYear.setAlignment(Qt.AlignCenter)
        self.nbrYear.setSingleStep(1)
        self.nbrYear.setMinimum(0)
        self.nbrYear.setValue(CONF.get('download_data', 'min_nbr_of_years', 3))
        self.nbrYear.valueChanged.connect(self.search_filters_changed)

        subgrid1 = QGridLayout()
        subgrid1.setContentsMargins(0, 0, 0, 0)
        subgrid1.addWidget(QLabel('for at least'), 0, 0)
        subgrid1.addWidget(self.nbrYear, 0, 1)
        subgrid1.addWidget(QLabel('year(s)'), 0, 2)
        subgrid1.setColumnStretch(3, 100)
        subgrid1.setHorizontalSpacing(5)

        # Year range
        self.minYear = QSpinBox()
        self.minYear.setAlignment(Qt.AlignCenter)
        self.minYear.setSingleStep(1)
        self.minYear.setMinimum(1840)
        self.minYear.setMaximum(now.year)
        self.minYear.setValue(
            CONF.get('download_data', 'year_range_left_bound', 1840))
        self.minYear.valueChanged.connect(self.minYear_changed)

        label_and = QLabel('and')
        label_and.setAlignment(Qt.AlignCenter)

        self.maxYear = QSpinBox()
        self.maxYear.setAlignment(Qt.AlignCenter)
        self.maxYear.setSingleStep(1)
        self.maxYear.setMinimum(1840)
        self.maxYear.setMaximum(now.year)
        self.maxYear.setValue(
            CONF.get('download_data', 'year_range_right_bound', now.year))

        self.maxYear.valueChanged.connect(self.maxYear_changed)

        subgrid2 = QGridLayout()
        subgrid2.addWidget(QLabel('between'), 0, 0)
        subgrid2.addWidget(self.minYear, 0, 1)
        subgrid2.addWidget(label_and, 0, 2)
        subgrid2.addWidget(self.maxYear, 0, 3)
        subgrid2.setContentsMargins(0, 0, 0, 0)
        subgrid2.setColumnStretch(4, 100)
        subgrid2.setHorizontalSpacing(5)

        # Subgridgrid assembly
        self.year_widg = QGroupBox("Data Availability filter")
        self.year_widg.setCheckable(True)
        self.year_widg.setChecked(
            CONF.get('download_data', 'data_availability_filter', False))
        self.year_widg.toggled.connect(self.search_filters_changed)

        grid = QGridLayout(self.year_widg)
        grid.setRowMinimumHeight(0, 10)
        grid.addWidget(QLabel('Search for stations with data available'), 1, 0)
        grid.addLayout(subgrid1, 2, 0)
        grid.addLayout(subgrid2, 3, 0)
        grid.setRowStretch(4, 100)
        grid.setVerticalSpacing(8)

        # Setup the toolbar.
        self.btn_addSta = QPushButton('Add')
        self.btn_addSta.setIcon(get_icon('add2list'))
        self.btn_addSta.setIconSize(get_iconsize('small'))
        self.btn_addSta.setToolTip(
            'Add selected stations to the current list of weather stations.')
        self.btn_addSta.clicked.connect(self.btn_addSta_isClicked)
        self.btn_addSta.hide()

        btn_save = QPushButton('Save')
        btn_save.setToolTip('Save the list of selected stations to a file.')
        btn_save.clicked.connect(self.btn_save_isClicked)
        btn_save.hide()

        self.btn_download = QPushButton('Download')
        self.btn_download.clicked.connect(self.start_download_process)

        btn_close = QPushButton('Close')
        btn_close.clicked.connect(self.close)

        self.btn_fetch = btn_fetch = QPushButton('Refresh')
        btn_fetch.setToolTip(
            "Update the list of climate stations by fetching it from "
            "the ECCC remote location.")
        btn_fetch.clicked.connect(self.btn_fetch_isClicked)

        toolbar_widg = QWidget()
        toolbar_grid = QGridLayout(toolbar_widg)
        toolbar_grid.addWidget(self.btn_addSta, 1, 1)
        toolbar_grid.addWidget(btn_save, 1, 2)
        toolbar_grid.addWidget(btn_fetch, 1, 3)
        toolbar_grid.addWidget(self.btn_download, 1, 4)
        toolbar_grid.addWidget(btn_close, 1, 5)
        toolbar_grid.setColumnStretch(0, 100)
        toolbar_grid.setContentsMargins(0, 10, 0, 0)

        # Setup the left panel.
        self.left_panel = QFrame()
        left_panel_grid = QGridLayout(self.left_panel)
        left_panel_grid.setContentsMargins(0, 0, 0, 0)
        left_panel_grid.addWidget(QLabel('Search Criteria'), 0, 0)
        left_panel_grid.addWidget(prov_grpbox, 1, 0)
        left_panel_grid.addWidget(self.prox_grpbox, 2, 0)
        left_panel_grid.addWidget(self.year_widg, 3, 0)
        left_panel_grid.setRowStretch(3, 100)

        # Setup the progress bar.
        self.progressbar = QProgressBar()
        self.progressbar.setValue(0)
        self.progressbar.hide()

        # Setup the central widget.
        main_widget = QWidget()
        main_layout = QGridLayout(main_widget)
        main_layout.addWidget(self.left_panel, 0, 0)
        main_layout.addWidget(self.station_table, 0, 1)
        main_layout.addWidget(self.waitspinnerbar, 0, 1)
        main_layout.addWidget(toolbar_widg, 1, 0, 1, 2)
        main_layout.addWidget(self.progressbar, 2, 0, 1, 2)
        main_layout.setColumnStretch(1, 100)

        self.setCentralWidget(main_widget)

    @property
    def stationlist(self):
        return self.station_table.get_stationlist()

    @property
    def search_by(self):
        return ['proximity', 'province'][self.tab_widg.currentIndex()]

    @property
    def prov(self):
        if self.prov_widg.currentIndex() == 0:
            return self.PROV_NAME
        else:
            return [self.PROV_NAME[self.prov_widg.currentIndex() - 1]]

    @property
    def lat(self):
        return self.lat_spinBox.value()

    def set_lat(self, x, silent=True):
        if silent:
            self.lat_spinBox.blockSignals(True)
        self.lat_spinBox.setValue(x)
        self.lat_spinBox.blockSignals(False)
        self.proximity_grpbox_toggled()

    @property
    def lon(self):
        return self.lon_spinBox.value()

    def set_lon(self, x, silent=True):
        if silent:
            self.lon_spinBox.blockSignals(True)
        self.lon_spinBox.setValue(x)
        self.lon_spinBox.blockSignals(False)
        self.proximity_grpbox_toggled()

    @property
    def rad(self):
        return int(self.radius_SpinBox.currentText()[:-3])

    @property
    def prox(self):
        if self.prox_grpbox.isChecked():
            return (self.lat, -self.lon, self.rad)
        else:
            return None

    @property
    def year_min(self):
        return int(self.minYear.value())

    def set_yearmin(self, x, silent=True):
        if silent:
            self.minYear.blockSignals(True)
        self.minYear.setValue(x)
        self.minYear.blockSignals(False)

    @property
    def year_max(self):
        return int(self.maxYear.value())

    def set_yearmax(self, x, silent=True):
        if silent:
            self.maxYear.blockSignals(True)
        self.maxYear.setValue(x)
        self.maxYear.blockSignals(False)

    @property
    def nbr_of_years(self):
        return int(self.nbrYear.value())

    def set_yearnbr(self, x, silent=True):
        if silent:
            self.nbrYear.blockSignals(True)
        self.nbrYear.setValue(x)
        self.nbrYear.blockSignals(False)

    # ---- Load Station Database
    def start_load_database(self, force_fetch=False):
        """Start the process of loading the climate station database."""
        if self._database_isloading is False:
            self._database_isloading = True

            self.station_table.clear()
            self.waitspinnerbar.show()

            # Start the downloading process.
            if force_fetch:
                self.stn_finder_thread.started.connect(
                    self.stn_finder_worker.fetch_database)
            else:
                self.stn_finder_thread.started.connect(
                    self.stn_finder_worker.load_database)
            self.stn_finder_thread.start()

    @QSlot()
    def receive_load_database(self):
        """Handles when loading the database is finished."""
        # Disconnect the thread.
        self.stn_finder_thread.started.disconnect()

        # Quit the thread.
        self.stn_finder_thread.quit()
        waittime = 0
        while self.stn_finder_thread.isRunning():
            sleep(0.1)
            waittime += 0.1
            if waittime > 15:
                print("Unable to quit the thread.")
                break
        # Force an update of the GUI.
        self.proximity_grpbox_toggled()
        if self.stn_finder_worker.data is None:
            self.waitspinnerbar.show_warning_icon()
        else:
            self.waitspinnerbar.hide()
        self._database_isloading = False

    # ---- GUI handlers
    def minYear_changed(self):
        min_yr = min_yr = max(self.minYear.value(), 1840)

        now = datetime.now()
        max_yr = now.year

        self.maxYear.setRange(min_yr, max_yr)
        self.search_filters_changed()

    def maxYear_changed(self):
        min_yr = 1840

        now = datetime.now()
        max_yr = min(self.maxYear.value(), now.year)

        self.minYear.setRange(min_yr, max_yr)
        self.search_filters_changed()

    # ---- Toolbar Buttons Handlers
    def btn_save_isClicked(self):
        ddir = os.path.join(os.getcwd(), 'weather_station_list.csv')
        filename, ftype = QFileDialog().getSaveFileName(
            self, 'Save normals', ddir, '*.csv;;*.xlsx;;*.xls')
        self.station_table.save_stationlist(filename)

    def btn_addSta_isClicked(self):
        rows = self.station_table.get_checked_rows()
        if len(rows) > 0:
            staList = self.station_table.get_content4rows(rows)
            self.staListSignal.emit(staList)
            print('Selected stations sent to list')
        else:
            print('No station currently selected')

    def btn_fetch_isClicked(self):
        """Handles when the button fetch is clicked."""
        self.start_load_database(force_fetch=True)

    # ---- Search Filters Handlers
    def proximity_grpbox_toggled(self):
        """
        Set the values for the reference geo coordinates that are used in the
        WeatherSationView to calculate the proximity values and forces a
        refresh of the content of the table.
        """
        if self.prox_grpbox.isChecked():
            self.station_table.set_geocoord((self.lat, -self.lon))
        else:
            self.station_table.set_geocoord(None)
        self.search_filters_changed()

    def search_filters_changed(self):
        """
        Search for weather stations with the current filter values and forces
        an update of the station table content.
        """
        if self.stn_finder_worker.data is not None:
            stnlist = self.stn_finder_worker.get_stationlist(
                prov=self.prov,
                prox=self.prox,
                yrange=((self.year_min, self.year_max, self.nbr_of_years)
                        if self.year_widg.isChecked() else None))
            self.station_table.populate_table(stnlist)

    # ---- Download weather data
    def start_download_process(self):
        """Start the downloading process of raw weather data files."""
        if self._dwnld_inprogress is True:
            self.stop_download_process()
            return

        # Grab the info of the weather stations that are selected.
        rows = self.station_table.get_checked_rows()
        self._dwnld_stations_list = self.station_table.get_content4rows(rows)
        if len(self._dwnld_stations_list) == 0:
            QMessageBox.warning(self, 'Warning',
                                "No weather station currently selected.",
                                QMessageBox.Ok)
            return

        # Update the UI.
        self.progressbar.show()
        self.btn_download.setText("Cancel")
        self.left_panel.setEnabled(False)
        self.station_table.setEnabled(False)
        self.btn_fetch.setEnabled(False)

        # Set thread working directory.
        self.dwnld_worker.dirname = self.workdir

        # Start downloading data.
        self._dwnld_inprogress = True
        self.download_next_station()

    def stop_download_process(self):
        """Stop the downloading process."""
        print('Stopping the download process...')
        self.dwnld_worker.stop_download()
        self._dwnld_stations_list = []
        self.btn_download.setEnabled(False)

        self.wait_for_thread_to_quit()
        self.btn_download.setEnabled(True)
        self.btn_download.setText("Download")
        self.left_panel.setEnabled(True)
        self.station_table.setEnabled(True)
        self.btn_fetch.setEnabled(True)

        self._dwnld_inprogress = False
        self.sig_download_process_ended.emit()
        print('Download process stopped.')

    def download_next_station(self):
        self.wait_for_thread_to_quit()
        try:
            dwnld_station = self._dwnld_stations_list.pop(0)
        except IndexError:
            # There is no more data to download.
            print('Raw weather data downloaded for all selected stations.')
            self.btn_download.setText("Download")
            self.progressbar.hide()
            self.left_panel.setEnabled(True)
            self.station_table.setEnabled(True)
            self.btn_fetch.setEnabled(True)
            self._dwnld_inprogress = False
            self.sig_download_process_ended.emit()
            return

        # Set worker attributes.
        self.dwnld_worker.StaName = dwnld_station[0]
        self.dwnld_worker.stationID = dwnld_station[1]
        self.dwnld_worker.yr_start = dwnld_station[2]
        self.dwnld_worker.yr_end = dwnld_station[3]
        self.dwnld_worker.climateID = dwnld_station[5]

        # Highlight the row of the next station to download data from.
        self.station_table.selectRow(
            self.station_table.get_row_from_climateid(dwnld_station[5]))

        # Start the downloading process.
        try:
            self.dwnld_thread.started.disconnect(
                self.dwnld_worker.download_data)
        except TypeError:
            # The method self.dwnld_worker.download_data is not connected.
            pass
        finally:
            self.dwnld_thread.started.connect(self.dwnld_worker.download_data)
            self.dwnld_thread.start()

    def wait_for_thread_to_quit(self):
        self.dwnld_thread.quit()
        waittime = 0
        while self.dwnld_thread.isRunning():
            print('Waiting for the downloading thread to close')
            sleep(0.1)
            waittime += 0.1
            if waittime > 15:
                print("Unable to close the weather data dowloader thread.")
                return

    def process_station_data(self, climateid, file_list=None):
        """
        Read, concatenate, and save to csv the raw weather data that were
        just downloaded for the station corresponding to the specified
        climate ID.
        """
        if file_list:
            station_metadata = self.station_table.get_content4rows(
                [self.station_table.get_row_from_climateid(climateid)])[0]
            station_data = read_raw_datafiles(file_list)
            print(
                'Formating and concatenating raw data for station {}.'.format(
                    station_metadata[0]))

            # Define the concatenated filename.
            station_name = (station_metadata[0].replace('\\',
                                                        '_').replace('/', '_'))
            min_year = min(station_data.index).year
            max_year = max(station_data.index).year
            filename = osp.join("%s (%s)_%s-%s.csv" %
                                (station_name, climateid, min_year, max_year))

            # Save the concatenated data to csv.
            data_headers = [
                'Year', 'Month', 'Day', 'Max Temp (°C)', 'Min Temp (°C)',
                'Mean Temp (°C)', 'Total Precip (mm)'
            ]
            fcontent = [['Station Name', station_metadata[0]],
                        ['Province', station_metadata[4]],
                        ['Latitude (dd)', station_metadata[6]],
                        ['Longitude (dd)', station_metadata[7]],
                        ['Elevation (m)', station_metadata[8]],
                        ['Climate Identifier', station_metadata[5]], [],
                        data_headers]
            fcontent = fcontent + station_data[data_headers].values.tolist()

            # Save the data to csv.
            filepath = osp.join(self.dwnld_worker.dirname, filename)
            with open(filepath, 'w', encoding='utf-8') as f:
                writer = csv.writer(f, delimiter=',', lineterminator='\n')
                writer.writerows(fcontent)
        self.download_next_station()

    # ---- Main window settings
    def _restore_window_geometry(self):
        """
        Restore the geometry of this mainwindow from the value saved
        in the config.
        """
        hexstate = CONF.get('download_data', 'window/geometry', None)
        if hexstate:
            hexstate = hexstate_to_qbytearray(hexstate)
            self.restoreGeometry(hexstate)
        else:
            self.resize(1000, 450)

    def _save_window_geometry(self):
        """
        Save the geometry of this mainwindow to the config.
        """
        hexstate = qbytearray_to_hexstate(self.saveGeometry())
        CONF.set('download_data', 'window/geometry', hexstate)

    # ---- Qt overrides
    def closeEvent(self, event):
        self._save_window_geometry()

        # Proximity Filter Options.
        CONF.set('download_data', 'proximity_filter',
                 self.prox_grpbox.isChecked())
        CONF.set('download_data', 'latitude', self.lat)
        CONF.set('download_data', 'longitude', self.lon)
        CONF.set('download_data', 'radius_index',
                 self.radius_SpinBox.currentIndex())
        CONF.set('download_data', 'province_index',
                 self.prov_widg.currentIndex())

        # Data Availability Filter Options.
        CONF.set('download_data', 'data_availability_filter',
                 self.year_widg.isChecked())
        CONF.set('download_data', 'min_nbr_of_years', self.nbrYear.value())
        CONF.set('download_data', 'year_range_left_bound',
                 self.minYear.value())
        CONF.set('download_data', 'year_range_right_bound',
                 self.maxYear.value())
        event.accept()