Пример #1
0
class LogScaleIntensity(ComposableItemImageView):
    def __init__(self, *args, **kwargs):
        # Composes a new type consisting of any ImageItem types in imageItem_bases with this classes's helper ImageItem
        # class (LogScaleImageItem)
        self.imageItem_bases += (LogScaleImageItem,)
        imageItem = type("DynamicImageItem", tuple(self.imageItem_bases), {})()
        if "imageItem" in kwargs:
            del kwargs["imageItem"]
        super(LogScaleIntensity, self).__init__(imageItem=imageItem, *args, **kwargs)

        self.logScale = True

        # Setup log scale button
        self.logIntensityButton = QPushButton("Log Intensity")
        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.logIntensityButton.sizePolicy().hasHeightForWidth())
        self.logIntensityButton.setSizePolicy(sizePolicy)
        self.logIntensityButton.setObjectName("logIntensity")
        self.ui.gridLayout.addWidget(self.logIntensityButton, 3, 2, 1, 1)
        self.logIntensityButton.setCheckable(True)
        self.setLogScale(True)
        self.logIntensityButton.clicked.connect(self._setLogScale)

    def _setLogScale(self, value):
        self.imageItem.logScale = value
        self.imageItem.qimage = None
        self.imageItem.update()
        self.getHistogramWidget().region.setBounds([0 if value else None, None])

    def setLogScale(self, value):
        self._setLogScale(value)
        self.logIntensityButton.setChecked(value)
Пример #2
0
    def setup_btn_grid(self, n_lights_1axis):
        """Set up grid of buttons."""
        table = self.btn_grid_table
        if n_lights_1axis != table.rowCount():
            table.clear()
            table.setSelectionMode(QAbstractItemView.NoSelection)
            table.setColumnCount(n_lights_1axis)
            table.setRowCount(n_lights_1axis)
            table.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
            table.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)

            table.horizontalHeader().setDefaultSectionSize(CELL_SIZE)
            table.verticalHeader().setDefaultSectionSize(CELL_SIZE)

            table.horizontalHeader().hide()
            table.verticalHeader().hide()

            for idx_row in range(n_lights_1axis):
                for idx_col in range(n_lights_1axis):
                    btn = QPushButton(self)
                    btn.setStyleSheet(BTN_STYLE)
                    btn.setCheckable(True)
                    btn.setChecked(True)
                    btn.clicked.connect(
                        self.clicked_btn_of_grid_factory(idx_row, idx_col))
                    table.setCellWidget(idx_row, idx_col, btn)
        self.show_solution()
Пример #3
0
class LogButtons(BetterLayout):
    """Button mixin that can toggle x/y log modes."""
    def __init__(self, *args, **kwargs):
        super(LogButtons, self).__init__(*args, **kwargs)
        # Define single-source of text state
        self.X_ON_TEXT = "X Log Mode On"
        self.X_OFF_TEXT = "X Log Mode Off"
        self.Y_ON_TEXT = "Y Log Mode On"
        self.Y_OFF_TEXT = "Y Log Mode Off"

        # Create checkable buttons
        self.x_log_button = QPushButton(self.X_OFF_TEXT)
        self.x_log_button.setCheckable(True)
        self.x_log_button.toggled.connect(self.set_x_log_mode)
        self.y_log_button = QPushButton(self.Y_OFF_TEXT)
        self.y_log_button.setCheckable(True)
        self.y_log_button.toggled.connect(self.set_y_log_mode)

        # Update button check state when pyqtgraph log x checkbox is toggled by user
        self.getPlotItem().ctrl.logXCheck.toggled.connect(
            self._update_x_button)
        # Update button check state when pyqtgraph log y checkbox is toggled by user
        self.getPlotItem().ctrl.logYCheck.toggled.connect(
            self._update_y_button)

        # Create a layout to have these buttons side-by-side
        layout = QHBoxLayout()
        layout.addWidget(self.x_log_button)
        layout.addWidget(self.y_log_button)
        # TODO: BetterLayout
        #  RightLayout   BottomLayout
        #  add_widget    add_widget
        self.add_widget_to_bottom(layout)

    def _update_y_button(self, state: bool):
        self.y_log_button.setChecked(state)
        if state:
            self.y_log_button.setText(self.Y_ON_TEXT)
        else:
            self.y_log_button.setText(self.Y_OFF_TEXT)

    def _update_x_button(self, state: bool):
        self.x_log_button.setChecked(state)
        if state:
            self.x_log_button.setText(self.X_ON_TEXT)
        else:
            self.x_log_button.setText(self.X_OFF_TEXT)

    def set_x_log_mode(self, state: bool):
        self._update_x_button(state)
        # Grab existing x log state from pyqtgraph
        y_log_mode = self.getPlotItem().ctrl.logYCheck.isChecked()
        self.setLogMode(x=state, y=y_log_mode)

    def set_y_log_mode(self, state: bool):
        self._update_y_button(state)
        # Grab existing y log state from pyqtgraph
        x_log_mode = self.getPlotItem().ctrl.logXCheck.isChecked()
        self.setLogMode(x=x_log_mode, y=state)
Пример #4
0
class DataSelector(QWidget):
    """
    Simple button to create and hold information about a selection area
    in a pyqtgraph.PlotItem object
    """
    new_selection = Signal(float, float)
    abort_selection = Signal()

    def __init__(self, plotitem, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.plot = plotitem
        self.sele = None

        self.setLayout(QHBoxLayout())
        # remove annoying padding
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.toggle = QPushButton(self)
        self.toggle.setText('Select Area')
        self.toggle.setCheckable(True)
        self.toggle.setChecked(False)

        self.layout().addWidget(self.toggle)

        self.toggle.toggled.connect(self.toggle_selection)

    def toggle_selection(self, activated):
        if activated:
            self.toggle.setText('Stop Selecting')
            sele = pg.LinearRegionItem()
            sele.sigRegionChangeFinished.connect(self.on_selection_changed)
            self.sele = sele
            self.plot.addItem(sele)
        else:
            self.toggle.setText('Select Area')
            if self.sele is not None:
                self.sele.sigRegionChangeFinished.disconnect()
                self.plot.removeItem(self.sele)
                self.sele = None
            self.on_selection_changed(None)

    def on_selection_changed(self, region_changed):
        if region_changed is None:
            self.abort_selection.emit()
        else:
            left, right = region_changed.getRegion()
            self.new_selection.emit(left, right)

    def toggle_enabled(self, enabled):
        self.toggle.setVisible(enabled)
        if not enabled:
            self.toggle_selection(False)
Пример #5
0
    def createTopRightGroupBox(self):
        self.topRightGroupBox = QGroupBox("Group 2")

        defaultPushButton = QPushButton("Default Push Button")
        defaultPushButton.setDefault(True)

        togglePushButton = QPushButton("Toggle Push Button")
        togglePushButton.setCheckable(True)
        togglePushButton.setChecked(True)

        flatPushButton = QPushButton("Flat Push Button")
        flatPushButton.setFlat(True)

        layout = QVBoxLayout()
        layout.addWidget(defaultPushButton)
        layout.addWidget(togglePushButton)
        layout.addWidget(flatPushButton)
        layout.addStretch(1)
        self.topRightGroupBox.setLayout(layout)
Пример #6
0
class FixableWidgetParameterItem(parameterTypes.WidgetParameterItem):
    def __init__(self, param, depth):
        super(FixableWidgetParameterItem, self).__init__(param, depth)
        if param.opts.get("fixable"):
            self.fixbutton = QPushButton()
            self.fixbutton.setFixedWidth(20)
            self.fixbutton.setFixedHeight(20)
            self.fixbutton.setCheckable(True)
            self.fixbutton.setChecked(param.opts["fixed"])
            self.fixbutton.toggled.connect(param.sigFixToggled)
            self.fixbutton.toggled.connect(
                lambda fixed: param.setOpts(fixed=fixed))
            # self.fixbutton.toggled.connect(lambda fixed: self.widgetValueChanged())

            self.fixbutton.setIcon(QIcon(path("icons/anchor.png")))
            self.layoutWidget.layout().addWidget(self.fixbutton)

    def optsChanged(self, param, opts):
        """Called when any options are changed that are not
        name, value, default, or limits"""
        # print "opts changed:", opts
        ParameterItem.optsChanged(self, param, opts)

        if "readonly" in opts:
            self.updateDefaultBtn()
            if isinstance(self.widget, (QCheckBox, ColorButton)):
                self.widget.setEnabled(not opts["readonly"])

        ## If widget is a SpinBox, pass options straight through
        if isinstance(self.widget, SpinBox):
            if "units" in opts and "suffix" not in opts:
                opts["suffix"] = opts["units"]
            try:  # patch passes silently for 'fixed'
                self.widget.setOpts(**opts)
            except TypeError:
                pass
            self.updateDisplayLabel()
Пример #7
0
class LogScaleIntensity(ImageView):
    def __init__(self, *args, **kwargs):
        if kwargs.get("imageItem") and not isinstance(kwargs.get("imageItem"),
                                                      LogScaleImageItem):
            raise RuntimeError(
                "The imageItem set to a LogScaleIntensity ImageView must be a LogScaleImageItem."
            )

        kwargs["imageItem"] = LogScaleImageItem()
        super(LogScaleIntensity, self).__init__(*args, **kwargs)

        self.logScale = True

        # Setup log scale button
        self.logIntensityButton = QPushButton("Log Intensity")
        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(
            self.logIntensityButton.sizePolicy().hasHeightForWidth())
        self.logIntensityButton.setSizePolicy(sizePolicy)
        self.logIntensityButton.setObjectName("logIntensity")
        self.ui.gridLayout.addWidget(self.logIntensityButton, 3, 2, 1, 1)
        self.logIntensityButton.setCheckable(True)
        self.setLogScale(True)
        self.logIntensityButton.clicked.connect(self._setLogScale)

    def _setLogScale(self, value):
        self.imageItem.logScale = value
        self.imageItem.qimage = None
        self.imageItem.update()
        self.getHistogramWidget().region.setBounds(
            [0 if value else None, None])

    def setLogScale(self, value):
        self._setLogScale(value)
        self.logIntensityButton.setChecked(value)
Пример #8
0
    def __init__(self, layer: Image, parent=None) -> None:
        super().__init__(parent=parent)

        self.setLayout(QHBoxLayout())
        self.layout().setSpacing(2)
        self.layout().setContentsMargins(0, 0, 0, 0)
        once_btn = QPushButton(trans._('once'))
        once_btn.setFocusPolicy(Qt.NoFocus)

        auto_btn = QPushButton(trans._('continuous'))
        auto_btn.setCheckable(True)
        auto_btn.setFocusPolicy(Qt.NoFocus)
        once_btn.clicked.connect(lambda: auto_btn.setChecked(False))
        connect_no_arg(once_btn.clicked, layer, "reset_contrast_limits")
        connect_setattr(auto_btn.toggled, layer, "_keep_autoscale")
        connect_no_arg(auto_btn.clicked, layer, "reset_contrast_limits")

        self.layout().addWidget(once_btn)
        self.layout().addWidget(auto_btn)
Пример #9
0
class DimSwitch(QWidget):
    dimChanged = Signal(bool)

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QHBoxLayout()
        layout.addStretch(1)
        self.button_2d = QPushButton("2D")
        self.button_2d.setCheckable(True)
        self.button_2d.setChecked(True)
        self.button_2d.clicked.connect(functools.partial(self.set_2D, True))
        self.button_3d = QPushButton("3D")
        self.button_3d.setCheckable(True)
        self.button_3d.clicked.connect(functools.partial(self.set_2D, False))
        layout.addWidget(self.button_2d)
        layout.addWidget(self.button_3d)
        layout.addStretch(1)
        self.setLayout(layout)

    def set_2D(self, bool2d):
        self.button_2d.setChecked(bool2d)
        self.button_3d.setChecked(not bool2d)
        self.dimChanged.emit(bool2d)
Пример #10
0
class Dimension(QWidget):
    stateChanged = Signal(int)
    valueChanged = Signal()
    """
    pass in dimension

    state: one of (State.X, State.Y, State.NONE, State.DISABLE)

    Can be run independently by:

    from mantidqt.widgets.sliceviewer.dimensionwidget import Dimension
    from qtpy.QtWidgets import QApplication
    app = QApplication([])
    window = Dimension({'minimum':-1.1, 'number_of_bins':11, 'width':0.2, 'name':'Dim0', 'units':'A'})
    window.show()
    app.exec_()
    """
    def __init__(self, dim_info, number=0, state=State.NONE, parent=None):
        super().__init__(parent)

        self.minimum = dim_info['minimum']
        self.nbins = dim_info['number_of_bins']
        self.width = dim_info['width']
        self.number = number

        self.layout = QHBoxLayout(self)

        self.name = QLabel(dim_info['name'])
        self.units = QLabel(dim_info['units'])

        self.x = QPushButton('X')
        self.x.setFixedSize(32, 32)
        self.x.setCheckable(True)
        self.x.clicked.connect(self.x_clicked)

        self.y = QPushButton('Y')
        self.y.setFixedSize(32, 32)
        self.y.setCheckable(True)
        self.y.clicked.connect(self.y_clicked)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.nbins - 1)
        self.slider.valueChanged.connect(self.slider_changed)

        self.spinbox = QDoubleSpinBox()
        self.spinbox.setDecimals(3)
        self.spinbox.setRange(self.get_bin_center(0),
                              self.get_bin_center(self.nbins - 1))
        self.spinbox.setSingleStep(self.width)
        self.spinbox.editingFinished.connect(self.spinbox_changed)

        self.layout.addWidget(self.name)
        self.layout.addWidget(self.x)
        self.layout.addWidget(self.y)
        self.layout.addWidget(self.slider, stretch=1)
        self.layout.addStretch(0)
        self.layout.addWidget(self.spinbox)
        self.layout.addWidget(self.units)

        self.set_value(0)

        if self.nbins < 2:
            state = State.DISABLE

        self.set_state(state)

    def set_state(self, state):
        self.state = state
        if self.state == State.X:
            self.x.setChecked(True)
            self.y.setChecked(False)
            self.slider.hide()
            self.spinbox.hide()
            self.units.hide()
        elif self.state == State.Y:
            self.x.setChecked(False)
            self.y.setChecked(True)
            self.slider.hide()
            self.spinbox.hide()
            self.units.hide()
        elif self.state == State.NONE:
            self.x.setChecked(False)
            self.y.setChecked(False)
            self.slider.show()
            self.spinbox.show()
            self.units.show()
        else:
            self.x.setChecked(False)
            self.x.setDisabled(True)
            self.y.setChecked(False)
            self.y.setDisabled(True)
            self.slider.hide()
            self.spinbox.show()
            self.spinbox.setDisabled(True)
            self.units.show()

    def get_state(self):
        return self.state

    def x_clicked(self):
        old_state = self.state
        self.set_state(State.X)
        if self.state != old_state:
            self.stateChanged.emit(self.number)

    def y_clicked(self):
        old_state = self.state
        self.set_state(State.Y)
        if self.state != old_state:
            self.stateChanged.emit(self.number)

    def spinbox_changed(self):
        self.value = self.spinbox.value()
        self.update_slider()

    def slider_changed(self):
        self.value = self.get_bin_center(self.slider.value())
        self.update_spinbox()
        self.valueChanged.emit()

    def get_bin_center(self, n):
        return (n + 0.5) * self.width + self.minimum

    def update_slider(self):
        i = (self.value - self.minimum) / self.width
        self.slider.setValue(int(min(max(i, 0), self.nbins - 1)))

    def update_spinbox(self):
        self.spinbox.setValue(self.value)

    def set_value(self, value):
        self.value = value
        self.update_slider()
        self.update_spinbox()

    def get_value(self):
        return self.value
Пример #11
0
class QtPluginDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.refresh_state = RefreshState.DONE
        self.already_installed = set()

        installer_type = "mamba" if running_as_constructor_app() else "pip"

        self.installer = Installer(installer=installer_type)
        self.setup_ui()
        self.installer.set_output_widget(self.stdout_text)
        self.installer.started.connect(self._on_installer_start)
        self.installer.finished.connect(self._on_installer_done)
        self.refresh()

    def _on_installer_start(self):
        self.cancel_all_btn.setVisible(True)
        self.working_indicator.show()
        self.process_error_indicator.hide()
        self.close_btn.setDisabled(True)

    def _on_installer_done(self, exit_code):
        self.working_indicator.hide()
        if exit_code:
            self.process_error_indicator.show()

        self.cancel_all_btn.setVisible(False)
        self.close_btn.setDisabled(False)
        self.refresh()

    def closeEvent(self, event):
        if self.close_btn.isEnabled():
            super().closeEvent(event)

        event.ignore()

    def refresh(self):
        if self.refresh_state != RefreshState.DONE:
            self.refresh_state = RefreshState.OUTDATED
            return
        self.refresh_state = RefreshState.REFRESHING
        self.installed_list.clear()
        self.available_list.clear()

        # fetch installed
        from npe2 import PluginManager

        from ...plugins import plugin_manager

        plugin_manager.discover()  # since they might not be loaded yet

        self.already_installed = set()

        def _add_to_installed(distname, enabled, npe_version=1):
            norm_name = normalized_name(distname or '')
            if distname:
                try:
                    meta = metadata(distname)
                except PackageNotFoundError:
                    self.refresh_state = RefreshState.OUTDATED
                    return  # a race condition has occurred and the package is uninstalled by another thread
                if len(meta) == 0:
                    # will not add builtins.
                    return
                self.already_installed.add(norm_name)
            else:
                meta = {}

            self.installed_list.addItem(
                PackageMetadata(
                    metadata_version="1.0",
                    name=norm_name,
                    version=meta.get('version', ''),
                    summary=meta.get('summary', ''),
                    home_page=meta.get('url', ''),
                    author=meta.get('author', ''),
                    license=meta.get('license', ''),
                ),
                installed=True,
                enabled=enabled,
                npe_version=npe_version,
            )

        pm2 = PluginManager.instance()
        for manifest in pm2.iter_manifests():
            distname = normalized_name(manifest.name or '')
            if distname in self.already_installed or distname == 'napari':
                continue
            enabled = not pm2.is_disabled(manifest.name)
            _add_to_installed(distname, enabled, npe_version=2)

        for (
                plugin_name,
                _mod_name,
                distname,
        ) in plugin_manager.iter_available():
            # not showing these in the plugin dialog
            if plugin_name in ('napari_plugin_engine', ):
                continue
            if distname in self.already_installed:
                continue
            _add_to_installed(distname,
                              not plugin_manager.is_blocked(plugin_name))

        self.installed_label.setText(
            trans._(
                "Installed Plugins ({amount})",
                amount=len(self.already_installed),
            ))

        # fetch available plugins
        settings = get_settings()
        use_hub = (running_as_bundled_app() or running_as_constructor_app()
                   or settings.plugins.plugin_api.name == "napari_hub")
        if use_hub:
            conda_forge = running_as_constructor_app()
            self.worker = create_worker(iter_hub_plugin_info,
                                        conda_forge=conda_forge)
        else:
            self.worker = create_worker(iter_napari_plugin_info)

        self.worker.yielded.connect(self._handle_yield)
        self.worker.finished.connect(self.working_indicator.hide)
        self.worker.finished.connect(self._update_count_in_label)
        self.worker.finished.connect(self._end_refresh)
        self.worker.start()

    def setup_ui(self):
        self.resize(1080, 640)
        vlay_1 = QVBoxLayout(self)
        self.h_splitter = QSplitter(self)
        vlay_1.addWidget(self.h_splitter)
        self.h_splitter.setOrientation(Qt.Horizontal)
        self.v_splitter = QSplitter(self.h_splitter)
        self.v_splitter.setOrientation(Qt.Vertical)
        self.v_splitter.setMinimumWidth(500)

        installed = QWidget(self.v_splitter)
        lay = QVBoxLayout(installed)
        lay.setContentsMargins(0, 2, 0, 2)
        self.installed_label = QLabel(trans._("Installed Plugins"))
        self.packages_filter = QLineEdit()
        self.packages_filter.setPlaceholderText(trans._("filter..."))
        self.packages_filter.setMaximumWidth(350)
        self.packages_filter.setClearButtonEnabled(True)
        mid_layout = QVBoxLayout()
        mid_layout.addWidget(self.packages_filter)
        mid_layout.addWidget(self.installed_label)
        lay.addLayout(mid_layout)

        self.installed_list = QPluginList(installed, self.installer)
        self.packages_filter.textChanged.connect(self.installed_list.filter)
        lay.addWidget(self.installed_list)

        uninstalled = QWidget(self.v_splitter)
        lay = QVBoxLayout(uninstalled)
        lay.setContentsMargins(0, 2, 0, 2)
        self.avail_label = QLabel(trans._("Available Plugins"))
        mid_layout = QHBoxLayout()
        mid_layout.addWidget(self.avail_label)
        mid_layout.addStretch()
        lay.addLayout(mid_layout)
        self.available_list = QPluginList(uninstalled, self.installer)
        self.packages_filter.textChanged.connect(self.available_list.filter)
        lay.addWidget(self.available_list)

        self.stdout_text = QTextEdit(self.v_splitter)
        self.stdout_text.setReadOnly(True)
        self.stdout_text.setObjectName("pip_install_status")
        self.stdout_text.hide()

        buttonBox = QHBoxLayout()
        self.working_indicator = QLabel(trans._("loading ..."), self)
        sp = self.working_indicator.sizePolicy()
        sp.setRetainSizeWhenHidden(True)
        self.working_indicator.setSizePolicy(sp)
        self.process_error_indicator = QLabel(self)
        self.process_error_indicator.setObjectName("error_label")
        self.process_error_indicator.hide()
        load_gif = str(Path(napari.resources.__file__).parent / "loading.gif")
        mov = QMovie(load_gif)
        mov.setScaledSize(QSize(18, 18))
        self.working_indicator.setMovie(mov)
        mov.start()

        visibility_direct_entry = not running_as_constructor_app()
        self.direct_entry_edit = QLineEdit(self)
        self.direct_entry_edit.installEventFilter(self)
        self.direct_entry_edit.setPlaceholderText(
            trans._('install by name/url, or drop file...'))
        self.direct_entry_edit.setVisible(visibility_direct_entry)
        self.direct_entry_btn = QPushButton(trans._("Install"), self)
        self.direct_entry_btn.setVisible(visibility_direct_entry)
        self.direct_entry_btn.clicked.connect(self._install_packages)

        self.show_status_btn = QPushButton(trans._("Show Status"), self)
        self.show_status_btn.setFixedWidth(100)

        self.cancel_all_btn = QPushButton(trans._("cancel all actions"), self)
        self.cancel_all_btn.setObjectName("remove_button")
        self.cancel_all_btn.setVisible(False)
        self.cancel_all_btn.clicked.connect(lambda: self.installer.cancel())

        self.close_btn = QPushButton(trans._("Close"), self)
        self.close_btn.clicked.connect(self.accept)
        self.close_btn.setObjectName("close_button")
        buttonBox.addWidget(self.show_status_btn)
        buttonBox.addWidget(self.working_indicator)
        buttonBox.addWidget(self.direct_entry_edit)
        buttonBox.addWidget(self.direct_entry_btn)
        if not visibility_direct_entry:
            buttonBox.addStretch()
        buttonBox.addWidget(self.process_error_indicator)
        buttonBox.addSpacing(20)
        buttonBox.addWidget(self.cancel_all_btn)
        buttonBox.addSpacing(20)
        buttonBox.addWidget(self.close_btn)
        buttonBox.setContentsMargins(0, 0, 4, 0)
        vlay_1.addLayout(buttonBox)

        self.show_status_btn.setCheckable(True)
        self.show_status_btn.setChecked(False)
        self.show_status_btn.toggled.connect(self._toggle_status)

        self.v_splitter.setStretchFactor(1, 2)
        self.h_splitter.setStretchFactor(0, 2)

        self.packages_filter.setFocus()

    def _update_count_in_label(self):
        count = self.available_list.count()
        self.avail_label.setText(
            trans._("Available Plugins ({count})", count=count))

    def _end_refresh(self):
        refresh_state = self.refresh_state
        self.refresh_state = RefreshState.DONE
        if refresh_state == RefreshState.OUTDATED:
            self.refresh()

    def eventFilter(self, watched, event):
        if event.type() == QEvent.DragEnter:
            # we need to accept this event explicitly to be able
            # to receive QDropEvents!
            event.accept()
        if event.type() == QEvent.Drop:
            md = event.mimeData()
            if md.hasUrls():
                files = [url.toLocalFile() for url in md.urls()]
                self.direct_entry_edit.setText(files[0])
                return True
        return super().eventFilter(watched, event)

    def _toggle_status(self, show):
        if show:
            self.show_status_btn.setText(trans._("Hide Status"))
            self.stdout_text.show()
        else:
            self.show_status_btn.setText(trans._("Show Status"))
            self.stdout_text.hide()

    def _install_packages(self, packages: Sequence[str] = ()):
        if not packages:
            _packages = self.direct_entry_edit.text()
            if os.path.exists(_packages):
                packages = [_packages]
            else:
                packages = _packages.split()
            self.direct_entry_edit.clear()

        if packages:
            self.installer.install(packages)

    def _handle_yield(self, data: Tuple[PackageMetadata, bool]):
        project_info, is_available = data
        if project_info.name in self.already_installed:
            self.installed_list.tag_outdated(project_info, is_available)
        else:
            self.available_list.addItem(project_info)
            if not is_available:
                self.available_list.tag_unavailable(project_info)

        self.filter()

    def filter(self, text: str = None) -> None:
        """Filter by text or set current text as filter."""
        if text is None:
            text = self.packages_filter.text()
        else:
            self.packages_filter.setText(text)

        self.installed_list.filter(text)
        self.available_list.filter(text)
Пример #12
0
class PlotNameWidget(QWidget):
    """A widget to display the plot name, and edit and close buttons

    This widget is added to the table widget to support the renaming
    and close buttons, as well as the direct renaming functionality.
    """
    def __init__(self, presenter, plot_number, parent=None):
        super(PlotNameWidget, self).__init__(parent)

        self.presenter = presenter
        self.plot_number = plot_number

        self.mutex = QMutex()

        self.line_edit = QLineEdit(
            self.presenter.get_plot_name_from_number(plot_number))
        self.line_edit.setReadOnly(True)
        self.line_edit.setFrame(False)
        # changes the line edit to look like normal even when
        self.line_edit.setStyleSheet(
            """* { background-color: rgba(0, 0, 0, 0); }
        QLineEdit:disabled { color: black; }""")
        self.line_edit.setAttribute(Qt.WA_TransparentForMouseEvents, True)
        self.line_edit.editingFinished.connect(self.rename_plot)
        # Disabling the line edit prevents it from temporarily
        # grabbing focus when changing code editors - this triggered
        # the editingFinished signal, which was causing #26305
        self.line_edit.setDisabled(True)

        shown_icon = get_icon('mdi.eye')
        self.hide_button = QPushButton(shown_icon, "")
        self.hide_button.setToolTip('Hide')
        self.hide_button.setFlat(True)
        self.hide_button.setMaximumWidth(self.hide_button.iconSize().width() *
                                         5 / 3)
        self.hide_button.clicked.connect(self.toggle_visibility)

        rename_icon = get_icon('mdi.square-edit-outline')
        self.rename_button = QPushButton(rename_icon, "")
        self.rename_button.setToolTip('Rename')
        self.rename_button.setFlat(True)
        self.rename_button.setMaximumWidth(
            self.rename_button.iconSize().width() * 5 / 3)
        self.rename_button.setCheckable(True)
        self.rename_button.toggled.connect(self.rename_button_toggled)

        close_icon = get_icon('mdi.close')
        self.close_button = QPushButton(close_icon, "")
        self.close_button.setToolTip('Delete')
        self.close_button.setFlat(True)
        self.close_button.setMaximumWidth(
            self.close_button.iconSize().width() * 5 / 3)
        self.close_button.clicked.connect(
            lambda: self.close_pressed(self.plot_number))

        self.layout = QHBoxLayout()

        # Get rid of the top and bottom margins - the button provides
        # some natural margin anyway. Get rid of right margin and
        # reduce spacing to get buttons closer together.
        self.layout.setContentsMargins(5, 0, 0, 0)
        self.layout.setSpacing(0)

        self.layout.addWidget(self.line_edit)
        self.layout.addWidget(self.hide_button)
        self.layout.addWidget(self.rename_button)
        self.layout.addWidget(self.close_button)

        self.layout.sizeHint()
        self.setLayout(self.layout)

    def set_plot_name(self, new_name):
        """
        Sets the internally stored and displayed plot name
        :param new_name: The name to set
        """
        self.line_edit.setText(new_name)

    def close_pressed(self, plot_number):
        """
        Close the plot with the given name
        :param plot_number: The unique number in GlobalFigureManager
        """
        self.presenter.close_single_plot(plot_number)

    def rename_button_toggled(self, checked):
        """
        If the rename button is pressed from being unchecked then
        make the line edit item editable
        :param checked: True if the rename toggle is now pressed
        """
        if checked:
            self.toggle_plot_name_editable(True, toggle_rename_button=False)

    def toggle_plot_name_editable(self, editable, toggle_rename_button=True):
        """
        Set the line edit item to be editable or not editable. If
        editable move the cursor focus to the editable name and
        highlight it all.
        :param editable: If true make the plot name editable, else
                         make it read only
        :param toggle_rename_button: If true also toggle the rename
                                     button state
        """
        self.line_edit.setReadOnly(not editable)
        self.line_edit.setDisabled(not editable)
        self.line_edit.setAttribute(Qt.WA_TransparentForMouseEvents,
                                    not editable)

        # This is a sneaky way to avoid the issue of two calls to
        # this toggle method, by effectively disabling the button
        # press in edit mode.
        self.rename_button.setAttribute(Qt.WA_TransparentForMouseEvents,
                                        editable)

        if toggle_rename_button:
            self.rename_button.setChecked(editable)

        if editable:
            self.line_edit.setFocus()
            self.line_edit.selectAll()
        else:
            self.line_edit.setSelection(0, 0)

    def toggle_visibility(self):
        """
        Calls the presenter to hide the selected plot
        """
        self.presenter.toggle_plot_visibility(self.plot_number)

    def set_visibility_icon(self, is_shown):
        """
        Change the widget icon between shown and hidden
        :param is_shown: True if plot is shown, false if hidden
        """
        if is_shown:
            self.hide_button.setIcon(get_icon('mdi.eye'))
            self.hide_button.setToolTip('Hide')
        else:
            self.hide_button.setIcon(get_icon('mdi.eye', 'lightgrey'))
            self.hide_button.setToolTip('Show')

    def rename_plot(self):
        """
        Called when the editing is finished, gets the presenter to
        do the real renaming of the plot
        """
        self.presenter.rename_figure(self.plot_number, self.line_edit.text())

        self.toggle_plot_name_editable(False)
Пример #13
0
class QtPluginDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.installer = Installer()
        self.setup_ui()
        self.installer.set_output_widget(self.stdout_text)
        self.installer.process.started.connect(self._on_installer_start)
        self.installer.process.finished.connect(self._on_installer_done)
        self.refresh()

    def _on_installer_start(self):
        self.show_status_btn.setChecked(True)
        self.working_indicator.show()
        self.process_error_indicator.hide()

    def _on_installer_done(self, exit_code, exit_status):
        self.working_indicator.hide()
        if exit_code:
            self.process_error_indicator.show()
        else:
            self.show_status_btn.setChecked(False)
        self.refresh()
        self.plugin_sorter.refresh()

    def refresh(self):
        self.installed_list.clear()
        self.available_list.clear()

        # fetch installed
        from ...plugins import plugin_manager

        plugin_manager.discover()  # since they might not be loaded yet

        already_installed = set()

        for plugin_name, mod_name, distname in plugin_manager.iter_available():
            # not showing these in the plugin dialog
            if plugin_name in ('napari_plugin_engine', ):
                continue
            if distname:
                already_installed.add(distname)
                meta = standard_metadata(distname)
            else:
                meta = {}
            self.installed_list.addItem(
                ProjectInfo(
                    normalized_name(distname or ''),
                    meta.get('version', ''),
                    meta.get('url', ''),
                    meta.get('summary', ''),
                    meta.get('author', ''),
                    meta.get('license', ''),
                ),
                plugin_name=plugin_name,
                enabled=plugin_name in plugin_manager.plugins,
            )
        # self.v_splitter.setSizes([70 * self.installed_list.count(), 10, 10])

        # fetch available plugins
        self.worker = create_worker(iter_napari_plugin_info)

        def _handle_yield(project_info):
            if project_info.name in already_installed:
                self.installed_list.tag_outdated(project_info)
            else:
                self.available_list.addItem(project_info)

        self.worker.yielded.connect(_handle_yield)
        self.worker.finished.connect(self.working_indicator.hide)
        self.worker.finished.connect(self._update_count_in_label)
        self.worker.start()

    def setup_ui(self):
        self.resize(1080, 640)
        vlay_1 = QVBoxLayout(self)
        self.h_splitter = QSplitter(self)
        vlay_1.addWidget(self.h_splitter)
        self.h_splitter.setOrientation(Qt.Horizontal)
        self.v_splitter = QSplitter(self.h_splitter)
        self.v_splitter.setOrientation(Qt.Vertical)
        self.v_splitter.setMinimumWidth(500)
        self.plugin_sorter = QtPluginSorter(parent=self.h_splitter)
        self.plugin_sorter.layout().setContentsMargins(2, 0, 0, 0)
        self.plugin_sorter.hide()

        installed = QWidget(self.v_splitter)
        lay = QVBoxLayout(installed)
        lay.setContentsMargins(0, 2, 0, 2)
        lay.addWidget(QLabel(trans._("Installed Plugins")))
        self.installed_list = QPluginList(installed, self.installer)
        lay.addWidget(self.installed_list)

        uninstalled = QWidget(self.v_splitter)
        lay = QVBoxLayout(uninstalled)
        lay.setContentsMargins(0, 2, 0, 2)
        self.avail_label = QLabel(trans._("Available Plugins"))
        lay.addWidget(self.avail_label)
        self.available_list = QPluginList(uninstalled, self.installer)
        lay.addWidget(self.available_list)

        self.stdout_text = QTextEdit(self.v_splitter)
        self.stdout_text.setReadOnly(True)
        self.stdout_text.setObjectName("pip_install_status")
        self.stdout_text.hide()

        buttonBox = QHBoxLayout()
        self.working_indicator = QLabel(trans._("loading ..."), self)
        sp = self.working_indicator.sizePolicy()
        sp.setRetainSizeWhenHidden(True)
        self.working_indicator.setSizePolicy(sp)
        self.process_error_indicator = QLabel(self)
        self.process_error_indicator.setObjectName("error_label")
        self.process_error_indicator.hide()
        load_gif = str(Path(napari.resources.__file__).parent / "loading.gif")
        mov = QMovie(load_gif)
        mov.setScaledSize(QSize(18, 18))
        self.working_indicator.setMovie(mov)
        mov.start()

        self.direct_entry_edit = QLineEdit(self)
        self.direct_entry_edit.installEventFilter(self)
        self.direct_entry_edit.setPlaceholderText(
            trans._('install by name/url, or drop file...'))
        self.direct_entry_btn = QPushButton(trans._("Install"), self)
        self.direct_entry_btn.clicked.connect(self._install_packages)

        self.show_status_btn = QPushButton(trans._("Show Status"), self)
        self.show_status_btn.setFixedWidth(100)
        self.show_sorter_btn = QPushButton(trans._("<< Show Sorter"), self)
        self.close_btn = QPushButton(trans._("Close"), self)
        self.close_btn.clicked.connect(self.reject)
        buttonBox.addWidget(self.show_status_btn)
        buttonBox.addWidget(self.working_indicator)
        buttonBox.addWidget(self.direct_entry_edit)
        buttonBox.addWidget(self.direct_entry_btn)
        buttonBox.addWidget(self.process_error_indicator)
        buttonBox.addSpacing(60)
        buttonBox.addWidget(self.show_sorter_btn)
        buttonBox.addWidget(self.close_btn)
        buttonBox.setContentsMargins(0, 0, 4, 0)
        vlay_1.addLayout(buttonBox)

        self.show_status_btn.setCheckable(True)
        self.show_status_btn.setChecked(False)
        self.show_status_btn.toggled.connect(self._toggle_status)

        self.show_sorter_btn.setCheckable(True)
        self.show_sorter_btn.setChecked(False)
        self.show_sorter_btn.toggled.connect(self._toggle_sorter)

        self.v_splitter.setStretchFactor(1, 2)
        self.h_splitter.setStretchFactor(0, 2)

    def _update_count_in_label(self):
        count = self.available_list.count()
        self.avail_label.setText(
            trans._("Available Plugins ({count})".format(count=count)))

    def eventFilter(self, watched, event):
        if event.type() == QEvent.DragEnter:
            # we need to accept this event explicitly to be able
            # to receive QDropEvents!
            event.accept()
        if event.type() == QEvent.Drop:
            md = event.mimeData()
            if md.hasUrls():
                files = [url.toLocalFile() for url in md.urls()]
                self.direct_entry_edit.setText(files[0])
                return True
        return super().eventFilter(watched, event)

    def _toggle_sorter(self, show):
        if show:
            self.show_sorter_btn.setText(trans._(">> Hide Sorter"))
            self.plugin_sorter.show()
        else:
            self.show_sorter_btn.setText(trans._("<< Show Sorter"))
            self.plugin_sorter.hide()

    def _toggle_status(self, show):
        if show:
            self.show_status_btn.setText(trans._("Hide Status"))
            self.stdout_text.show()
        else:
            self.show_status_btn.setText(trans._("Show Status"))
            self.stdout_text.hide()

    def _install_packages(self, packages: Sequence[str] = ()):
        if not packages:
            _packages = self.direct_entry_edit.text()
            if os.path.exists(_packages):
                packages = [_packages]
            else:
                packages = _packages.split()
            self.direct_entry_edit.clear()
        if packages:
            self.installer.install(packages)
Пример #14
0
class QtReQueueControls(QWidget):
    def __init__(self, model, parent=None):
        super().__init__(parent)
        self.model = model

        self._lb_queue_state = QLabel("STOPPED")

        self._pb_queue_start = QPushButton("Start")
        self._pb_queue_start.setEnabled(False)
        self._pb_queue_start.clicked.connect(self._pb_queue_start_clicked)

        self._pb_queue_stop = QPushButton("Stop")
        self._pb_queue_stop.setEnabled(False)
        self._pb_queue_stop.setCheckable(True)
        self._pb_queue_stop.clicked.connect(self._pb_queue_stop_clicked)

        self._group_box = QGroupBox("Queue")

        vbox = QVBoxLayout()
        vbox.addWidget(self._lb_queue_state, alignment=Qt.AlignHCenter)
        vbox.addWidget(self._pb_queue_start)
        vbox.addWidget(self._pb_queue_stop)

        self._group_box.setLayout(vbox)

        vbox = QVBoxLayout()
        vbox.addWidget(self._group_box)
        self.setLayout(vbox)

        self.model.events.status_changed.connect(self.on_update_widgets)

    def on_update_widgets(self, event):
        # None should be converted to False:
        is_connected = bool(event.is_connected)
        status = event.status
        worker_exists = status.get("worker_environment_exists", False)
        running_item_uid = status.get("running_item_uid", None)
        queue_stop_pending = status.get("queue_stop_pending", False)

        s = "RUNNING" if running_item_uid else "STOPPED"
        self._lb_queue_state.setText(s)

        self._pb_queue_start.setEnabled(is_connected and worker_exists
                                        and not bool(running_item_uid))
        self._pb_queue_stop.setEnabled(is_connected and worker_exists
                                       and bool(running_item_uid))
        self._pb_queue_stop.setChecked(queue_stop_pending)

    def _pb_queue_start_clicked(self):
        try:
            self.model.queue_start()
        except Exception as ex:
            print(f"Exception: {ex}")

    def _pb_queue_stop_clicked(self):
        try:
            if self._pb_queue_stop.isChecked():
                print("Stopping the queue")
                self.model.queue_stop()
            else:
                print("Cancelling stop")
                self.model.queue_stop_cancel()
        except Exception as ex:
            print(f"Exception: {ex}")
Пример #15
0
class QtPluginDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.installer = Installer()
        self.setup_ui()
        self.installer.set_output_widget(self.stdout_text)
        self.installer.process.started.connect(self._on_installer_start)
        self.installer.process.finished.connect(self._on_installer_done)
        self.refresh()

    def _on_installer_start(self):
        self.show_status_btn.setChecked(True)
        self.working_indicator.show()
        self.process_error_indicator.hide()

    def _on_installer_done(self, exit_code, exit_status):
        self.working_indicator.hide()
        if exit_code:
            self.process_error_indicator.show()
        else:
            self.show_status_btn.setChecked(False)
        self.refresh()
        self.plugin_sorter.refresh()

    def refresh(self):
        self.installed_list.clear()
        self.available_list.clear()

        # fetch installed
        from ...plugins import plugin_manager

        plugin_manager.discover()  # since they might not be loaded yet

        already_installed = set()

        for plugin_name, mod_name, distname in plugin_manager.iter_available():
            # not showing these in the plugin dialog
            if plugin_name in ('napari_plugin_engine', ):
                continue
            if distname:
                already_installed.add(distname)
                meta = standard_metadata(distname)
            else:
                meta = {}
            self.installed_list.addItem(
                ProjectInfo(
                    normalized_name(distname or ''),
                    meta.get('version', ''),
                    meta.get('url', ''),
                    meta.get('summary', ''),
                    meta.get('author', ''),
                    meta.get('license', ''),
                ),
                plugin_name=plugin_name,
                enabled=plugin_name in plugin_manager.plugins,
            )
        # self.v_splitter.setSizes([70 * self.installed_list.count(), 10, 10])

        # fetch available plugins
        self.worker = create_worker(iter_napari_plugin_info)

        def _handle_yield(project_info):
            if project_info.name in already_installed:
                self.installed_list.tag_outdated(project_info)
            else:
                self.available_list.addItem(project_info)

        self.worker.yielded.connect(_handle_yield)
        self.worker.finished.connect(self.working_indicator.hide)
        self.worker.start()

    def setup_ui(self):
        self.resize(1080, 640)
        vlay_1 = QVBoxLayout(self)
        self.h_splitter = QSplitter(self)
        vlay_1.addWidget(self.h_splitter)
        self.h_splitter.setOrientation(Qt.Horizontal)
        self.v_splitter = QSplitter(self.h_splitter)
        self.v_splitter.setOrientation(Qt.Vertical)
        self.v_splitter.setMinimumWidth(500)
        self.plugin_sorter = QtPluginSorter(parent=self.h_splitter)
        self.plugin_sorter.layout().setContentsMargins(2, 0, 0, 0)
        self.plugin_sorter.hide()

        installed = QWidget(self.v_splitter)
        lay = QVBoxLayout(installed)
        lay.setContentsMargins(0, 2, 0, 2)
        lay.addWidget(QLabel("Installed Plugins"))
        self.installed_list = QPluginList(installed, self.installer)
        lay.addWidget(self.installed_list)

        uninstalled = QWidget(self.v_splitter)
        lay = QVBoxLayout(uninstalled)
        lay.setContentsMargins(0, 2, 0, 2)
        lay.addWidget(QLabel("Available Plugin Packages"))
        self.available_list = QPluginList(uninstalled, self.installer)
        lay.addWidget(self.available_list)

        self.stdout_text = QTextEdit(self.v_splitter)
        self.stdout_text.setReadOnly(True)
        self.stdout_text.setObjectName("pip_install_status")
        self.stdout_text.hide()

        buttonBox = QHBoxLayout()
        self.working_indicator = QLabel("loading ...", self)
        self.process_error_indicator = QLabel(self)
        self.process_error_indicator.setObjectName("error_label")
        self.process_error_indicator.hide()
        load_gif = str(Path(napari.resources.__file__).parent / "loading.gif")
        mov = QMovie(load_gif)
        mov.setScaledSize(QSize(18, 18))
        self.working_indicator.setMovie(mov)
        mov.start()
        self.show_status_btn = QPushButton("Show Status", self)
        self.show_status_btn.setFixedWidth(100)
        self.show_sorter_btn = QPushButton("<< Show Sorter", self)
        self.close_btn = QPushButton("Close", self)
        self.close_btn.clicked.connect(self.reject)
        buttonBox.addWidget(self.show_status_btn)
        buttonBox.addWidget(self.working_indicator)
        buttonBox.addWidget(self.process_error_indicator)
        buttonBox.addStretch()
        buttonBox.addWidget(self.show_sorter_btn)
        buttonBox.addWidget(self.close_btn)
        buttonBox.setContentsMargins(0, 0, 4, 0)
        vlay_1.addLayout(buttonBox)

        self.show_status_btn.setCheckable(True)
        self.show_status_btn.setChecked(False)
        self.show_status_btn.toggled.connect(self._toggle_status)

        self.show_sorter_btn.setCheckable(True)
        self.show_sorter_btn.setChecked(False)
        self.show_sorter_btn.toggled.connect(self._toggle_sorter)

        self.v_splitter.setStretchFactor(1, 2)
        self.h_splitter.setStretchFactor(0, 2)

    def _toggle_sorter(self, show):
        if show:
            self.show_sorter_btn.setText(">> Hide Sorter")
            self.plugin_sorter.show()
        else:
            self.show_sorter_btn.setText("<< Show Sorter")
            self.plugin_sorter.hide()

    def _toggle_status(self, show):
        if show:
            self.show_status_btn.setText("Hide Status")
            self.stdout_text.show()
        else:
            self.show_status_btn.setText("Show Status")
            self.stdout_text.hide()
Пример #16
0
class TogglePanel(QWidget):
    """
    Generic Panel Widget

    Displays a widget below QPushButton that hides and shows the contents. It
    is up to subclasses to re-point the attribute :attr:`.contents` to the
    widget whose visibility you would like to toggle.

    By default, it is assumed that the Panel is initialized with the
    :attr:`.contents` widget as visible, however the contents will be hidden
    and the button synced to the proper position if :meth:`.show_contents` is
    called after instance creation

    Parameters
    ----------
    title : str
        Title of Panel. This will be the text on the QPushButton

    parent : QWidget

    Attributes
    ----------
    contents : QWidget
        Widget whose visibility is controlled via the QPushButton
    """
    def __init__(self, title, parent=None):
        super().__init__(parent=parent)
        # Create Widget Infrastructure
        self.title = title
        self.setLayout(QVBoxLayout())
        self.layout().setContentsMargins(2, 2, 2, 2)
        self.layout().setSpacing(5)
        # Create button control
        # Assuming widget is visible, set the button as checked
        self.contents = None
        self.hide_button = QPushButton(self.title)
        self.hide_button.setCheckable(True)
        self.hide_button.setChecked(True)
        self.layout().addWidget(self.hide_button)
        self.hide_button.clicked.connect(self.show_contents)

    @Slot(bool)
    def show_contents(self, show):
        """
        Show the contents of the Widget

        Hides the :attr:`.contents` QWidget and sets the :attr:`.hide_button`
        to the proper status to indicate whether the widget is hidden or not

        Parameters
        ----------
        show : bool
        """
        # Configure our button in case this slot was called elsewhere
        self.hide_button.setChecked(show)
        # Show or hide the widget if the contents exist
        if self.contents:
            if show:
                self.show()
                self.contents.show()
            else:
                self.contents.hide()
Пример #17
0
class NotificationsWidget(QWidget, VCPWidget):
    notificationsCleared = Signal(object)

    def __init__(self, parent=None):
        super(NotificationsWidget, self).__init__(parent)
        self.notification_channel = getPlugin("notifications")

        self.main_layout = QVBoxLayout()
        self.button_layout = QHBoxLayout()

        self.all_button = QPushButton()
        self.info_button = QPushButton()
        self.warn_button = QPushButton()
        self.error_button = QPushButton()
        self.debug_button = QPushButton()
        self.clear_button = QPushButton()

        self.all_button.setText("all")
        self.info_button.setText("info")
        self.warn_button.setText("warn")
        self.error_button.setText("error")
        self.debug_button.setText("debug")
        self.clear_button.setText("clear")

        self.all_button.setCheckable(True)
        self.info_button.setCheckable(True)
        self.warn_button.setCheckable(True)
        self.error_button.setCheckable(True)
        self.debug_button.setCheckable(True)

        self.all_button.setChecked(True)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.clear_button.clicked.connect(self.clear_all_notifications)

        self.button_layout.addWidget(self.all_button)
        self.button_layout.addWidget(self.info_button)
        self.button_layout.addWidget(self.warn_button)
        self.button_layout.addWidget(self.error_button)
        self.button_layout.addWidget(self.debug_button)
        self.button_layout.addWidget(self.clear_button)

        self.notification_name = QLabel()
        self.notification_name.setAlignment(Qt.AlignCenter)
        self.notification_name.setText("All Notifications")

        self.all_notification_view = QListView()

        self.all_notification_model = QStandardItemModel(
            self.all_notification_view)
        self.all_notification_model_proxy = QSortFilterProxyModel(
            self.all_notification_view)

        self.all_notification_model_proxy.setSourceModel(
            self.all_notification_model)

        # self.all_notification_view.setModel(self.all_notification_model)
        self.all_notification_view.setModel(self.all_notification_model_proxy)

        self.all_notifications = list()

        self.main_layout.addWidget(self.notification_name)
        self.main_layout.addWidget(self.all_notification_view)
        self.main_layout.addLayout(self.button_layout)

        self.setLayout(self.main_layout)

        self.notification_channel.info_message.notify(self.on_info_message)
        self.notification_channel.warn_message.notify(self.on_warn_message)
        self.notification_channel.error_message.notify(self.on_error_message)
        self.notification_channel.debug_message.notify(self.on_debug_message)

        self.all_button.clicked.connect(self.show_all_notifications)
        self.info_button.clicked.connect(self.show_info_notifications)
        self.warn_button.clicked.connect(self.show_warn_notifications)
        self.error_button.clicked.connect(self.show_error_notifications)
        self.debug_button.clicked.connect(self.show_debug_notifications)

    @staticmethod
    def _get_time():
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)
        return dt_object.strftime("%d / %b / %Y  -  %H:%M:%S")

    @staticmethod
    def _strip_new_line(message):
        return message.replace('\n', ' ').replace('\r', '').replace(
            '    ', ' ').replace('   ', ' ').replace('  ', ' ')

    def on_info_message(self, message):
        msg = 'INFO - occurred at: [ {} ]\n{}'.format(
            NotificationsWidget._get_time(),
            NotificationsWidget._strip_new_line(message))
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-information'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_warn_message(self, message):
        msg = 'WARNING - occurred at: [ {} ]\n{}'.format(
            NotificationsWidget._get_time(),
            NotificationsWidget._strip_new_line(message))
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-warning'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_error_message(self, message):
        msg = 'ERROR - occurred at: [ {} ]\n{}'.format(
            NotificationsWidget._get_time(),
            NotificationsWidget._strip_new_line(message))
        LOG.debug('-----on_error_message called: {}'.format(message))
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-error'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_debug_message(self, message):
        msg = 'DEBUG - occurred at: [ {} ]\n{}'.format(
            NotificationsWidget._get_time(),
            NotificationsWidget._strip_new_line(message))
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-question'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def show_all_notifications(self):
        self.all_button.setChecked(True)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("All Notifications")
        self.all_notification_model_proxy.setFilterRegExp(None)

    def show_info_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(True)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Information Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("INFO", Qt.CaseSensitive, QRegExp.FixedString))

    def show_warn_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(True)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Warning Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("WANRNING", Qt.CaseSensitive, QRegExp.FixedString))

    def show_error_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(True)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Error Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("ERROR", Qt.CaseInsensitive, QRegExp.FixedString))

    def show_debug_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(True)

        self.notification_name.setText("Debug Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("DEBUG", Qt.CaseSensitive, QRegExp.FixedString))

    def clear_all_notifications(self):
        self.all_notification_model.clear()
        self.notificationsCleared.emit(self)
Пример #18
0
    def get_auto_correction_widget(self, parent):
        """."""
        auto_wid = QWidget(parent)
        vbl2 = QVBoxLayout(auto_wid)

        tabw = QTabWidget(auto_wid)
        vbl2.addWidget(tabw)

        # Add Main Tab
        gpbx = QWidget(tabw)
        gpbx_lay = QVBoxLayout(gpbx)
        tabw.addTab(gpbx, 'Main')

        fbl = QFormLayout()
        fbl.setHorizontalSpacing(9)
        gpbx_lay.addLayout(fbl)

        lbl = QLabel('Freq. [Hz]', gpbx)
        wid = self.create_pair(gpbx, 'LoopFreq')
        fbl.addRow(lbl, wid)

        lbl = QLabel('Max. Orb. Distortion [um]', gpbx)
        wid = self.create_pair(gpbx, 'LoopMaxOrbDistortion')
        fbl.addRow(lbl, wid)

        wid = QWidget(gpbx)
        wid.setLayout(QHBoxLayout())
        pbtn = QPushButton('Loop Performance', wid)
        pbtn.setIcon(qta.icon('mdi.poll'))
        wid.layout().addStretch()
        wid.layout().addWidget(pbtn)
        icon = qta.icon(
            'fa5s.hammer', color=_util.get_appropriate_color(self.acc))
        wind = create_window_from_widget(
            PerformanceWidget, title='Loop Performance', icon=icon)
        _util.connect_window(
            pbtn, wind, self, device=self.device, prefix=self.prefix)
        fbl.addRow(wid)

        # Add PID Tab
        gpbx = QWidget(tabw)
        gpbx_lay = QGridLayout(gpbx)
        gpbx_lay.setSpacing(1)
        tabw.addTab(gpbx, 'PID')

        gpbx_lay.addWidget(QLabel('CH', gpbx), 1, 0)
        gpbx_lay.addWidget(QLabel('CV', gpbx), 2, 0)
        tmpl = 'LoopPID{:s}{:s}'
        pairs = []
        for i, k in enumerate(('Kp', 'Ki', 'Kd'), 1):
            gpbx_lay.addWidget(
                QLabel(k, gpbx), 0, i, alignment=Qt.AlignCenter)
            pair = self.create_pair(wid, tmpl.format(k, 'CH'), is_vert=True)
            pairs.append(pair)
            gpbx_lay.addWidget(pair, 1, i)
            pair = self.create_pair(wid, tmpl.format(k, 'CV'), is_vert=True)
            pairs.append(pair)
            gpbx_lay.addWidget(pair, 2, i)
            if self.acc in {'SI', 'BO'}:
                pair = self.create_pair(
                    wid, tmpl.format(k, 'RF'), is_vert=True)
                pairs.append(pair)
                gpbx_lay.addWidget(pair, 3, i)
        if self.acc in {'SI', 'BO'}:
            gpbx_lay.addWidget(QLabel('RF', gpbx), 3, 0)

        pbc = QPushButton('SP')
        pbc.setStyleSheet('max-width:2.2em;')
        gpbx_lay.addWidget(pbc, 0, 0)
        pbc.setCheckable(True)
        pbc.setChecked(False)
        pbc.toggled.connect(
            lambda x: pbc.setText('RB' if x else 'SP'))
        for pair in pairs:
            pair.rb_wid.setVisible(False)
            pbc.toggled.connect(pair.rb_wid.setVisible)
            pbc.toggled.connect(pair.sp_wid.setHidden)
        gpbx_lay.setRowStretch(4, 2)
        return auto_wid
Пример #19
0
class Dimension(QWidget):
    stateChanged = Signal(int)
    valueChanged = Signal()
    """
    pass in dimension

    state: one of (State.X, State.Y, State.NONE, State.DISBALE)

    Can be run independently by:

    from mantidqt.widgets.sliceviewer.dimensionwidget import Dimension
    from qtpy.QtWidgets import QApplication
    app = QApplication([])
    window = Dimension({'minimum':-1.1, 'number_of_bins':11, 'width':0.2, 'name':'Dim0', 'units':'A'})
    window.show()
    app.exec_()
    """
    def __init__(self, dim_info, number=0, state=State.NONE, parent=None):
        super(Dimension, self).__init__(parent)

        self.minimum = dim_info['minimum']
        self.nbins = dim_info['number_of_bins']
        self.width = dim_info['width']
        self.number = number

        self.layout = QHBoxLayout(self)

        self.name = QLabel(dim_info['name'])
        self.units = QLabel(dim_info['units'])

        self.x = QPushButton('X')
        self.x.setFixedSize(32,32)
        self.x.setCheckable(True)
        self.x.clicked.connect(self.x_clicked)

        self.y = QPushButton('Y')
        self.y.setFixedSize(32,32)
        self.y.setCheckable(True)
        self.y.clicked.connect(self.y_clicked)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.nbins-1)
        self.slider.valueChanged.connect(self.slider_changed)

        self.spinbox = QDoubleSpinBox()
        self.spinbox.setDecimals(3)
        self.spinbox.setRange(self.get_bin_center(0), self.get_bin_center(self.nbins-1))
        self.spinbox.setSingleStep(self.width)
        self.spinbox.valueChanged.connect(self.spinbox_changed)

        self.layout.addWidget(self.name)
        self.layout.addWidget(self.x)
        self.layout.addWidget(self.y)
        self.layout.addWidget(self.slider, stretch=1)
        self.layout.addStretch(0)
        self.layout.addWidget(self.spinbox)
        self.layout.addWidget(self.units)

        self.set_value(0)

        if self.nbins < 2:
            state = State.DISABLE

        self.set_state(state)

    def set_state(self, state):
        self.state = state
        if self.state == State.X:
            self.x.setChecked(True)
            self.y.setChecked(False)
            self.slider.hide()
            self.spinbox.hide()
            self.units.hide()
        elif self.state == State.Y:
            self.x.setChecked(False)
            self.y.setChecked(True)
            self.slider.hide()
            self.spinbox.hide()
            self.units.hide()
        elif self.state == State.NONE:
            self.x.setChecked(False)
            self.y.setChecked(False)
            self.slider.show()
            self.spinbox.show()
            self.units.show()
        else:
            self.x.setChecked(False)
            self.x.setDisabled(True)
            self.y.setChecked(False)
            self.y.setDisabled(True)
            self.slider.hide()
            self.spinbox.show()
            self.spinbox.setDisabled(True)
            self.units.show()

    def get_state(self):
        return self.state

    def x_clicked(self):
        old_state = self.state
        self.set_state(State.X)
        if self.state != old_state:
            self.stateChanged.emit(self.number)

    def y_clicked(self):
        old_state = self.state
        self.set_state(State.Y)
        if self.state != old_state:
            self.stateChanged.emit(self.number)

    def spinbox_changed(self):
        self.value = self.spinbox.value()
        self.update_slider()
        self.valueChanged.emit()

    def slider_changed(self):
        self.value = self.get_bin_center(self.slider.value())
        self.update_spinbox()
        self.valueChanged.emit()

    def get_bin_center(self, n):
        return (n+0.5)*self.width+self.minimum

    def update_slider(self):
        i = (self.value-self.minimum)/self.width
        self.slider.setValue(int(min(max(i, 0), self.nbins-1)))

    def update_spinbox(self):
        self.spinbox.setValue(self.value)

    def set_value(self, value):
        self.value = value
        self.update_slider()
        self.update_spinbox()

    def get_value(self):
        return self.value
Пример #20
0
class NotificationWidget(QWidget, VCPWidget):
    def __init__(self, parent=None):
        super(NotificationWidget, self).__init__(parent)
        self.notification_channel = getPlugin("notifications")

        self.main_layout = QVBoxLayout()
        self.button_layout = QHBoxLayout()

        self.all_button = QPushButton()
        self.info_button = QPushButton()
        self.warn_button = QPushButton()
        self.error_button = QPushButton()
        self.debug_button = QPushButton()
        self.clear_button = QPushButton()

        self.all_button.setText("all")
        self.info_button.setText("info")
        self.warn_button.setText("warn")
        self.error_button.setText("error")
        self.debug_button.setText("debug")
        self.clear_button.setText("clear")

        self.all_button.setCheckable(True)
        self.info_button.setCheckable(True)
        self.warn_button.setCheckable(True)
        self.error_button.setCheckable(True)
        self.debug_button.setCheckable(True)

        self.all_button.setChecked(True)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.clear_button.clicked.connect(self.clear_all_notifications)

        self.button_layout.addWidget(self.all_button)
        self.button_layout.addWidget(self.info_button)
        self.button_layout.addWidget(self.warn_button)
        self.button_layout.addWidget(self.error_button)
        self.button_layout.addWidget(self.debug_button)
        self.button_layout.addWidget(self.clear_button)

        self.notification_name = QLabel()
        self.notification_name.setAlignment(Qt.AlignCenter)
        self.notification_name.setText("All Notifications")

        self.all_notification_view = QListView()

        self.all_notification_model = QStandardItemModel(
            self.all_notification_view)
        self.all_notification_model_proxy = QSortFilterProxyModel(
            self.all_notification_view)

        self.all_notification_model_proxy.setSourceModel(
            self.all_notification_model)

        # self.all_notification_view.setModel(self.all_notification_model)
        self.all_notification_view.setModel(self.all_notification_model_proxy)

        self.all_notifications = list()

        self.main_layout.addWidget(self.notification_name)
        self.main_layout.addWidget(self.all_notification_view)
        self.main_layout.addLayout(self.button_layout)

        self.setLayout(self.main_layout)

        self.notification_channel.info_message.notify(self.on_info_message)
        self.notification_channel.warn_message.notify(self.on_warn_message)
        self.notification_channel.error_message.notify(self.on_error_message)
        self.notification_channel.debug_message.notify(self.on_debug_message)

        self.all_button.clicked.connect(self.show_all_notifications)
        self.info_button.clicked.connect(self.show_info_notifications)
        self.warn_button.clicked.connect(self.show_warn_notifications)
        self.error_button.clicked.connect(self.show_error_notifications)
        self.debug_button.clicked.connect(self.show_debug_notifications)

    def on_info_message(self, message):
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)

        current_time = str(dt_object)

        msg = 'INFO:\nTIME {}\n  {}'.format(current_time, message)
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-information'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_warn_message(self, message):
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)

        current_time = str(dt_object)

        msg = 'WARNING:\nTIME {}\n  {}'.format(current_time, message)
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-warning'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_error_message(self, message):
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)

        current_time = str(dt_object)

        msg = 'ERROR:\nTIME {}\n  {}'.format(current_time, message)
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-error'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_debug_message(self, message):
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)

        current_time = str(dt_object)

        msg = 'DEBUG\nTIME {}\n  {}'.format(current_time, message)
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-question'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def show_all_notifications(self):
        self.all_button.setChecked(True)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("All Notifications")
        self.all_notification_model_proxy.setFilterRegExp(None)

    def show_info_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(True)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Information Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("INFO", Qt.CaseSensitive, QRegExp.FixedString))

    def show_warn_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(True)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Warning Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("WANRNING", Qt.CaseSensitive, QRegExp.FixedString))

    def show_error_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(True)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Error Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("ERROR", Qt.CaseInsensitive, QRegExp.FixedString))

    def show_debug_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(True)

        self.notification_name.setText("Debug Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("DEBUG", Qt.CaseSensitive, QRegExp.FixedString))

    def clear_all_notifications(self):
        self.all_notification_model.clear()
Пример #21
0
class PlotNameWidget(QWidget):
    """A widget to display the plot name, and edit and close buttons

    This widget is added to the table widget to support the renaming
    and close buttons, as well as the direct renaming functionality.
    """

    def __init__(self, presenter, plot_number, parent=None):
        super(PlotNameWidget, self).__init__(parent)

        self.presenter = presenter
        self.plot_number = plot_number

        self.mutex = QMutex()

        self.line_edit = QLineEdit(self.presenter.get_plot_name_from_number(plot_number))
        self.line_edit.setReadOnly(True)
        self.line_edit.setFrame(False)
        self.line_edit.setStyleSheet("* { background-color: rgba(0, 0, 0, 0); }")
        self.line_edit.setAttribute(Qt.WA_TransparentForMouseEvents, True)
        self.line_edit.editingFinished.connect(self.rename_plot)

        shown_icon = get_icon('mdi.eye')
        self.hide_button = QPushButton(shown_icon, "")
        self.hide_button.setToolTip('Hide')
        self.hide_button.setFlat(True)
        self.hide_button.setMaximumWidth(self.hide_button.iconSize().width() * 5 / 3)
        self.hide_button.clicked.connect(self.toggle_visibility)

        rename_icon = get_icon('mdi.square-edit-outline')
        self.rename_button = QPushButton(rename_icon, "")
        self.rename_button.setToolTip('Rename')
        self.rename_button.setFlat(True)
        self.rename_button.setMaximumWidth(self.rename_button.iconSize().width() * 5 / 3)
        self.rename_button.setCheckable(True)
        self.rename_button.toggled.connect(self.rename_button_toggled)

        close_icon = get_icon('mdi.close')
        self.close_button = QPushButton(close_icon, "")
        self.close_button.setToolTip('Delete')
        self.close_button.setFlat(True)
        self.close_button.setMaximumWidth(self.close_button.iconSize().width() * 5 / 3)
        self.close_button.clicked.connect(lambda: self.close_pressed(self.plot_number))

        self.layout = QHBoxLayout()

        # Get rid of the top and bottom margins - the button provides
        # some natural margin anyway. Get rid of right margin and
        # reduce spacing to get buttons closer together.
        self.layout.setContentsMargins(5, 0, 0, 0)
        self.layout.setSpacing(0)

        self.layout.addWidget(self.line_edit)
        self.layout.addWidget(self.hide_button)
        self.layout.addWidget(self.rename_button)
        self.layout.addWidget(self.close_button)

        self.layout.sizeHint()
        self.setLayout(self.layout)

    def set_plot_name(self, new_name):
        """
        Sets the internally stored and displayed plot name
        :param new_name: The name to set
        """
        self.line_edit.setText(new_name)

    def close_pressed(self, plot_number):
        """
        Close the plot with the given name
        :param plot_number: The unique number in GlobalFigureManager
        """
        self.presenter.close_single_plot(plot_number)

    def rename_button_toggled(self, checked):
        """
        If the rename button is pressed from being unchecked then
        make the line edit item editable
        :param checked: True if the rename toggle is now pressed
        """
        if checked:
            self.toggle_plot_name_editable(True, toggle_rename_button=False)

    def toggle_plot_name_editable(self, editable, toggle_rename_button=True):
        """
        Set the line edit item to be editable or not editable. If
        editable move the cursor focus to the editable name and
        highlight it all.
        :param editable: If true make the plot name editable, else
                         make it read only
        :param toggle_rename_button: If true also toggle the rename
                                     button state
        """
        self.line_edit.setReadOnly(not editable)
        self.line_edit.setAttribute(Qt.WA_TransparentForMouseEvents, not editable)

        # This is a sneaky way to avoid the issue of two calls to
        # this toggle method, by effectively disabling the button
        # press in edit mode.
        self.rename_button.setAttribute(Qt.WA_TransparentForMouseEvents, editable)

        if toggle_rename_button:
            self.rename_button.setChecked(editable)

        if editable:
            self.line_edit.setFocus()
            self.line_edit.selectAll()
        else:
            self.line_edit.setSelection(0, 0)

    def toggle_visibility(self):
        """
        Calls the presenter to hide the selected plot
        """
        self.presenter.toggle_plot_visibility(self.plot_number)

    def set_visibility_icon(self, is_shown):
        """
        Change the widget icon between shown and hidden
        :param is_shown: True if plot is shown, false if hidden
        """
        if is_shown:
            self.hide_button.setIcon(get_icon('mdi.eye'))
            self.hide_button.setToolTip('Hide')
        else:
            self.hide_button.setIcon(get_icon('mdi.eye', 'lightgrey'))
            self.hide_button.setToolTip('Show')

    def rename_plot(self):
        """
        Called when the editing is finished, gets the presenter to
        do the real renaming of the plot
        """
        self.presenter.rename_figure(self.plot_number, self.line_edit.text())
        self.toggle_plot_name_editable(False)