コード例 #1
0
class CodeList(QWidget):
    def __init__(self, parent):
        QWidget.__init__(self, parent)

        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)
        self.plugin = parent.plugin

    def insertCode(self, index, title='', code=''):
        codepane = CodePane(self, title, code)

        if index < self.layout.count():
            self.layout.insertWidget(index, codepane)
        else:
            self.layout.addWidget(codepane)

    def removeCode(self, index):
        item = self.layout.takeAt(index)
        item.widget().deleteLater()

    def removeAll(self):
        for _ in range(self.layout.count()):
            self.removeCode(0)

    def appendCode(self, title='', code=''):
        codepane = CodePane(self, title, code)
        self.layout.addWidget(codepane)
コード例 #2
0
class SPipelineListWidget(QWidget):
    """Widget that contains a list of widgets to build a pipeline"""
    def __init__(self):
        super().__init__()
        self.input_layer_name = ''
        self._count = 0

        list_widget = QWidget()
        list_widget.setAttribute(QtCore.Qt.WA_StyledBackground, True)
        scroll_widget = QScrollArea()
        scroll_widget.setWidgetResizable(True)
        scroll_widget.setWidget(list_widget)

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(scroll_widget)
        self.setLayout(layout)

        self.layout = QVBoxLayout()
        self.layout.addWidget(QWidget(), 1, QtCore.Qt.AlignTop)
        list_widget.setLayout(self.layout)

    def add_widget(self, name, widget):
        """add a widget to the pipeline"""
        self._count += 1
        widget_ = SProcessInListWidget(str(self._count), name, widget)
        widget_.remove.connect(self._on_remove_widget)
        index = self.layout.count()-1
        self.layout.insertWidget(index, widget_, 0, QtCore.Qt.AlignTop)

    def _on_remove_widget(self, uuid):
        """Remove a filter

        Parameters
        ----------
        uuid: int
            Unique id of the filter to remove
        """
        # remove from widget list
        for i in range(self.layout.count()):
            item = self.layout.itemAt(i)
            widget = item.widget()
            if widget:
                if hasattr(widget, 'uuid'):
                    if widget.uuid == uuid:
                        item_d = self.layout.takeAt(i)
                        item_d.widget().deleteLater()
                        break

    def widgets(self):
        """Returns all the widgets in the pipeline"""
        widgets_ = list()
        for i in range(self.layout.count()):
            item = self.layout.itemAt(i)
            widget = item.widget()
            if widget:
                if hasattr(widget, 'uuid'):
                    widgets_.append(widget)
                    #widgets_.append(widget.process_widget)
        return widgets_
コード例 #3
0
class NativeNotification(BaseDialog):
    signNotifyClose = Signal(str)

    def __init__(self, parent=None):
        super(NativeNotification, self).__init__(parent=parent,
                                                 stay_on_top=True,
                                                 frameless=True)
        time = datetime.now()

        current_time = "{}:{}".format(time.hour, time.minute)

        self.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint
                            | Qt.WindowStaysOnTopHint
                            | Qt.WindowSystemMenuHint)

        resolution = QDesktopWidget().screenGeometry(-1)
        screenWidth = resolution.width()
        screenHeight = resolution.height()

        self.maxMessages = 5
        self.nMessages = 0
        self.activeMessages = list()
        self.mainLayout = QVBoxLayout(self)
        self.move(screenWidth, 0)

    def setNotify(self, title, message):
        m = Message(title, message, self)
        self.mainLayout.insertWidget(0, m)
        m.buttonClose.clicked.connect(self.onClicked)
        self.nMessages += 1

        if self.nMessages > self.maxMessages:
            prev_message = self.activeMessages.pop(0)
            self.mainLayout.removeWidget(prev_message)
            prev_message.deleteLater()
            self.nMessages -= 1

        self.activeMessages.append(m)

        self.show()
        self.raise_()

    def onClicked(self):
        m = self.sender().parent()
        self.mainLayout.removeWidget(m)
        self.activeMessages.remove(m)
        m.deleteLater()
        self.nMessages -= 1
        self.adjustSize()
        if self.nMessages == 0:
            self.close()

    def popNotify(self):
        """Removes the last notification in the list"""
        pass
コード例 #4
0
ファイル: interpreter.py プロジェクト: MORTAL2000/mantid
class PythonFileInterpreter(QWidget):
    sig_editor_modified = Signal(bool)
    sig_filename_modified = Signal(str)
    sig_progress = Signal(int)
    sig_exec_error = Signal(object)
    sig_exec_success = Signal(object)

    def __init__(self, font=None, content=None, filename=None,
                 parent=None):
        """
        :param font: A reference to the font to be used by the editor. If not supplied use the system default
        :param content: An optional string of content to pass to the editor
        :param filename: The file path where the content was read.
        :param parent: An optional parent QWidget
        """
        super(PythonFileInterpreter, self).__init__(parent)
        self.parent = parent

        # layout
        font = font if font is not None else QFont()
        self.editor = CodeEditor("AlternateCSPython", font, self)
        self.find_replace_dialog = None
        self.status = QStatusBar(self)
        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.addWidget(self.editor)
        self.layout.addWidget(self.status)
        self.setLayout(self.layout)
        self._setup_editor(content, filename)

        self._presenter = PythonFileInterpreterPresenter(self, PythonCodeExecution(self.editor))
        self.code_commenter = CodeCommenter(self.editor)
        self.code_completer = CodeCompleter(self.editor, self._presenter.model.globals_ns)

        self.editor.modificationChanged.connect(self.sig_editor_modified)
        self.editor.fileNameChanged.connect(self.sig_filename_modified)

        self.setAttribute(Qt.WA_DeleteOnClose, True)

        # Connect the model signals to the view's signals so they can be accessed from outside the MVP
        self._presenter.model.sig_exec_error.connect(self.sig_exec_error)
        self._presenter.model.sig_exec_success.connect(self.sig_exec_success)

        # Re-populate the completion API after execution success
        self._presenter.model.sig_exec_success.connect(self.code_completer.update_completion_api)

    def closeEvent(self, event):
        self.deleteLater()
        if self.find_replace_dialog:
            self.find_replace_dialog.close()
        super(PythonFileInterpreter, self).closeEvent(event)

    def show_find_replace_dialog(self):
        if self.find_replace_dialog is None:
            self.find_replace_dialog = EmbeddedFindReplaceDialog(self, self.editor)
            self.layout.insertWidget(0, self.find_replace_dialog.view)

        self.find_replace_dialog.show()

    def hide_find_replace_dialog(self):
        if self.find_replace_dialog is not None:
            self.find_replace_dialog.hide()

    @property
    def filename(self):
        return self.editor.fileName()

    def confirm_close(self):
        """Confirm the widget can be closed. If the editor contents are modified then
        a user can interject and cancel closing.

        :return: True if closing was considered successful, false otherwise
        """
        return self.save(prompt_for_confirmation=self.parent.confirm_on_save)

    def abort(self):
        self._presenter.req_abort()

    def execute_async(self, ignore_selection=False):
        return self._presenter.req_execute_async(ignore_selection)

    def execute_async_blocking(self):
        self._presenter.req_execute_async_blocking()

    def save(self, prompt_for_confirmation=False, force_save=False):
        if self.editor.isModified():
            io = EditorIO(self.editor)
            return io.save_if_required(prompt_for_confirmation, force_save)
        else:
            return True

    def save_as(self):
        io = EditorIO(self.editor)
        new_filename = io.ask_for_filename()
        if new_filename:
            return io.write(save_as=new_filename), new_filename
        else:
            return False, None

    def set_editor_readonly(self, ro):
        self.editor.setReadOnly(ro)

    def set_status_message(self, msg):
        self.status.showMessage(msg)

    def replace_tabs_with_spaces(self):
        self.replace_text(TAB_CHAR, SPACE_CHAR * TAB_WIDTH)

    def replace_text(self, match_text, replace_text):
        if self.editor.selectedText() == '':
            self.editor.selectAll()
        new_text = self.editor.selectedText().replace(match_text, replace_text)
        self.editor.replaceSelectedText(new_text)

    def replace_spaces_with_tabs(self):
        self.replace_text(SPACE_CHAR * TAB_WIDTH, TAB_CHAR)

    def set_whitespace_visible(self):
        self.editor.setEolVisibility(True)
        self.editor.setWhitespaceVisibility(CodeEditor.WsVisible)

    def set_whitespace_invisible(self):
        self.editor.setEolVisibility(False)
        self.editor.setWhitespaceVisibility(CodeEditor.WsInvisible)

    def toggle_comment(self):
        self.code_commenter.toggle_comment()

    def _setup_editor(self, default_content, filename):
        editor = self.editor

        # Clear default QsciScintilla key bindings that we want to allow
        # to be users of this class
        self.clear_key_binding("Ctrl+/")

        # use tabs not spaces for indentation
        editor.setIndentationsUseTabs(False)
        editor.setTabWidth(TAB_WIDTH)

        # show current editing line but in a softer color
        editor.setCaretLineBackgroundColor(CURRENTLINE_BKGD_COLOR)
        editor.setCaretLineVisible(True)

        # set a margin large enough for sensible file sizes < 1000 lines
        # and the progress marker
        font_metrics = QFontMetrics(self.font())
        editor.setMarginWidth(1, font_metrics.averageCharWidth() * 3 + 20)

        # fill with content if supplied and set source filename
        if default_content is not None:
            editor.setText(default_content)
        if filename is not None:
            editor.setFileName(filename)
        # Default content does not count as a modification
        editor.setModified(False)

    def clear_key_binding(self, key_str):
        """Clear a keyboard shortcut bound to a Scintilla command"""
        self.editor.clearKeyBinding(key_str)
コード例 #5
0
class QtLayerList(QScrollArea):
    def __init__(self, layers):
        super().__init__()

        self.layers = layers
        self.setWidgetResizable(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scrollWidget = QWidget()
        self.setWidget(scrollWidget)
        self.vbox_layout = QVBoxLayout(scrollWidget)
        self.vbox_layout.addWidget(QtDivider())
        self.vbox_layout.addStretch(1)
        self.vbox_layout.setContentsMargins(0, 0, 0, 0)
        self.vbox_layout.setSpacing(2)
        self.centers = []

        # Create a timer to be used for autoscrolling the layers list up and
        # down when dragging a layer near the end of the displayed area
        self.dragTimer = QTimer()
        self.dragTimer.setSingleShot(False)
        self.dragTimer.setInterval(20)
        self.dragTimer.timeout.connect(self._force_scroll)
        self._scroll_up = True
        self._min_scroll_region = 24
        self.setAcceptDrops(True)
        self.setToolTip('Layer list')
        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)

        self.layers.events.added.connect(self._add)
        self.layers.events.removed.connect(self._remove)
        self.layers.events.reordered.connect(self._reorder)

        self.drag_start_position = np.zeros(2)
        self.drag_name = None

    def _add(self, event):
        """Insert widget for layer `event.item` at index `event.index`."""
        layer = event.item
        total = len(self.layers)
        index = 2 * (total - event.index) - 1
        widget = QtLayerWidget(layer)
        self.vbox_layout.insertWidget(index, widget)
        self.vbox_layout.insertWidget(index + 1, QtDivider())
        layer.events.select.connect(self._scroll_on_select)

    def _remove(self, event):
        """Remove widget for layer at index `event.index`."""
        layer_index = event.index
        total = len(self.layers)
        # Find property widget and divider for layer to be removed
        index = 2 * (total - layer_index) + 1
        widget = self.vbox_layout.itemAt(index).widget()
        divider = self.vbox_layout.itemAt(index + 1).widget()
        self.vbox_layout.removeWidget(widget)
        widget.deleteLater()
        self.vbox_layout.removeWidget(divider)
        divider.deleteLater()

    def _reorder(self, event=None):
        """Reorders list of layer widgets by looping through all
        widgets in list sequentially removing them and inserting
        them into the correct place in final list.
        """
        total = len(self.layers)

        # Create list of the current property and divider widgets
        widgets = [
            self.vbox_layout.itemAt(i + 1).widget() for i in range(2 * total)
        ]
        # Take every other widget to ignore the dividers and get just the
        # property widgets
        indices = [
            self.layers.index(w.layer)
            for i, w in enumerate(widgets)
            if i % 2 == 0
        ]

        # Move through the layers in order
        for i in range(total):
            # Find index of property widget in list of the current layer
            index = 2 * indices.index(i)
            widget = widgets[index]
            divider = widgets[index + 1]
            # Check if current index does not match new index
            index_current = self.vbox_layout.indexOf(widget)
            index_new = 2 * (total - i) - 1
            if index_current != index_new:
                # Remove that property widget and divider
                self.vbox_layout.removeWidget(widget)
                self.vbox_layout.removeWidget(divider)
                # Insert the property widget and divider into new location
                self.vbox_layout.insertWidget(index_new, widget)
                self.vbox_layout.insertWidget(index_new + 1, divider)

    def _force_scroll(self):
        """Force the scroll bar to automattically scroll either up or down."""
        cur_value = self.verticalScrollBar().value()
        if self._scroll_up:
            new_value = cur_value - self.verticalScrollBar().singleStep() / 4
            if new_value < 0:
                new_value = 0
            self.verticalScrollBar().setValue(new_value)
        else:
            new_value = cur_value + self.verticalScrollBar().singleStep() / 4
            if new_value > self.verticalScrollBar().maximum():
                new_value = self.verticalScrollBar().maximum()
            self.verticalScrollBar().setValue(new_value)

    def _scroll_on_select(self, event):
        """Scroll to ensure that the currently selected layer is visible."""
        layer = event.source
        self._ensure_visible(layer)

    def _ensure_visible(self, layer):
        """Ensure layer widget for at particular layer is visible."""
        total = len(self.layers)
        layer_index = self.layers.index(layer)
        # Find property widget and divider for layer to be removed
        index = 2 * (total - layer_index) - 1
        widget = self.vbox_layout.itemAt(index).widget()
        self.ensureWidgetVisible(widget)

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

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

    def mousePressEvent(self, event):
        # Check if mouse press happens on a layer properties widget or
        # a child of such a widget. If not, the press has happended on the
        # Layers Widget itself and should be ignored.
        widget = self.childAt(event.pos())
        layer = (
            getattr(widget, 'layer', None)
            or getattr(widget.parentWidget(), 'layer', None)
            or getattr(widget.parentWidget().parentWidget(), 'layer', None)
        )

        if layer is not None:
            self.drag_start_position = np.array(
                [event.pos().x(), event.pos().y()]
            )
            self.drag_name = layer.name
        else:
            self.drag_name = None

    def mouseReleaseEvent(self, event):
        if self.drag_name is None:
            # Unselect all the layers if not dragging a layer
            self.layers.unselect_all()
            return

        modifiers = event.modifiers()
        layer = self.layers[self.drag_name]
        if modifiers == Qt.ShiftModifier:
            # If shift select all layers in between currently selected one and
            # clicked one
            index = self.layers.index(layer)
            lastSelected = None
            for i in range(len(self.layers)):
                if self.layers[i].selected:
                    lastSelected = i
            r = [index, lastSelected]
            r.sort()
            for i in range(r[0], r[1] + 1):
                self.layers[i].selected = True
        elif modifiers == Qt.ControlModifier:
            # If control click toggle selected state
            layer.selected = not layer.selected
        else:
            # If otherwise unselect all and leave clicked one selected
            self.layers.unselect_all(ignore=layer)
            layer.selected = True

    def mouseMoveEvent(self, event):
        position = np.array([event.pos().x(), event.pos().y()])
        distance = np.linalg.norm(position - self.drag_start_position)
        if (
            distance < QApplication.startDragDistance()
            or self.drag_name is None
        ):
            return
        mimeData = QMimeData()
        mimeData.setText(self.drag_name)
        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(event.pos() - self.rect().topLeft())
        drag.exec_()
        if self.drag_name is not None:
            index = self.layers.index(self.drag_name)
            layer = self.layers[index]
            self._ensure_visible(layer)

    def dragLeaveEvent(self, event):
        """Unselects layer dividers."""
        event.ignore()
        self.dragTimer.stop()
        for i in range(0, self.vbox_layout.count(), 2):
            self.vbox_layout.itemAt(i).widget().setSelected(False)

    def dragEnterEvent(self, event):
        if event.source() == self:
            event.accept()
            divs = []
            for i in range(0, self.vbox_layout.count(), 2):
                widget = self.vbox_layout.itemAt(i).widget()
                divs.append(widget.y() + widget.frameGeometry().height() / 2)
            self.centers = [
                (divs[i + 1] + divs[i]) / 2 for i in range(len(divs) - 1)
            ]
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        """Set the appropriate layers list divider to be highlighted when
        dragging a layer to a new position in the layers list.
        """
        max_height = self.frameGeometry().height()
        if (
            event.pos().y() < self._min_scroll_region
            and not self.dragTimer.isActive()
        ):
            self._scroll_up = True
            self.dragTimer.start()
        elif (
            event.pos().y() > max_height - self._min_scroll_region
            and not self.dragTimer.isActive()
        ):
            self._scroll_up = False
            self.dragTimer.start()
        elif (
            self.dragTimer.isActive()
            and event.pos().y() >= self._min_scroll_region
            and event.pos().y() <= max_height - self._min_scroll_region
        ):
            self.dragTimer.stop()

        # Determine which widget center is the mouse currently closed to
        cord = event.pos().y() + self.verticalScrollBar().value()
        center_list = (i for i, x in enumerate(self.centers) if x > cord)
        divider_index = next(center_list, len(self.centers))
        # Determine the current location of the widget being dragged
        total = self.vbox_layout.count() // 2 - 1
        insert = total - divider_index
        index = self.layers.index(self.drag_name)
        # If the widget being dragged hasn't moved above or below any other
        # widgets then don't highlight any dividers
        selected = not (insert == index) and not (insert - 1 == index)
        # Set the selected state of all the dividers
        for i in range(0, self.vbox_layout.count(), 2):
            if i == 2 * divider_index:
                self.vbox_layout.itemAt(i).widget().setSelected(selected)
            else:
                self.vbox_layout.itemAt(i).widget().setSelected(False)

    def dropEvent(self, event):
        if self.dragTimer.isActive():
            self.dragTimer.stop()

        for i in range(0, self.vbox_layout.count(), 2):
            self.vbox_layout.itemAt(i).widget().setSelected(False)
        cord = event.pos().y() + self.verticalScrollBar().value()
        center_list = (i for i, x in enumerate(self.centers) if x > cord)
        divider_index = next(center_list, len(self.centers))
        total = self.vbox_layout.count() // 2 - 1
        insert = total - divider_index
        index = self.layers.index(self.drag_name)
        if index != insert and index + 1 != insert:
            if insert >= index:
                insert -= 1
            self.layers.move_selected(index, insert)
        event.accept()
コード例 #6
0
ファイル: qt_layerlist.py プロジェクト: zzalscv2/napari
class QtLayerList(QScrollArea):
    """Widget storing a list of all the layers present in the current window.

    Parameters
    ----------
    layers : napari.components.LayerList
        The layer list to track and display.

    Attributes
    ----------
    centers : list
        List of layer widgets center coordinates.
    layers : napari.components.LayerList
        The layer list to track and display.
    vbox_layout : QVBoxLayout
        The layout instance in which the layouts appear.
    """

    def __init__(self, layers: 'LayerList'):
        super().__init__()

        self.layers = layers
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setWidgetResizable(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scrollWidget = QWidget()
        self.setWidget(scrollWidget)
        self.vbox_layout = QVBoxLayout(scrollWidget)
        self.vbox_layout.addWidget(QtDivider())
        self.vbox_layout.addStretch(1)
        self.vbox_layout.setContentsMargins(0, 0, 0, 0)
        self.vbox_layout.setSpacing(2)
        self.centers = []

        # Create a timer to be used for autoscrolling the layers list up and
        # down when dragging a layer near the end of the displayed area
        self._drag_timer = QTimer()
        self._drag_timer.setSingleShot(False)
        self._drag_timer.setInterval(20)
        self._drag_timer.timeout.connect(self._force_scroll)
        self._scroll_up = True
        self._min_scroll_region = 24
        self.setAcceptDrops(True)
        self.setToolTip(trans._('Layer list'))
        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)

        self.layers.events.inserted.connect(self._add)
        self.layers.events.removed.connect(self._remove)
        self.layers.events.reordered.connect(self._reorder)
        self.layers.selection.events.changed.connect(self._on_selection_change)

        self._drag_start_position = np.zeros(2)
        self._drag_name = None

        self.chunk_receiver = _create_chunk_receiver(self)

    def _on_selection_change(self, event):
        for layer in event.added:
            w = self._find_widget(layer)
            if w:
                w.setSelected(True)
        for layer in event.removed:
            w = self._find_widget(layer)
            if w:
                w.setSelected(False)
        if event.added:
            self._ensure_visible(list(event.added)[-1])

    def _find_widget(self, layer):
        for i in range(self.vbox_layout.count()):
            w = self.vbox_layout.itemAt(i).widget()
            if getattr(w, 'layer', None) == layer:
                return w

    def _add(self, event):
        """Insert widget for layer `event.value` at index `event.index`.

        Parameters
        ----------
        event : napari.utils.event.Event
            The napari event that triggered this method.
        """
        layer = event.value
        total = len(self.layers)
        index = 2 * (total - event.index) - 1
        widget = QtLayerWidget(layer, selected=layer in self.layers.selection)
        self.vbox_layout.insertWidget(index, widget)
        self.vbox_layout.insertWidget(index + 1, QtDivider())

    def _remove(self, event):
        """Remove widget for layer at index `event.index`.

        Parameters
        ----------
        event : napari.utils.event.Event
            The napari event that triggered this method.
        """
        layer_index = event.index
        total = len(self.layers)
        # Find property widget and divider for layer to be removed
        index = 2 * (total - layer_index) + 1
        widget = self.vbox_layout.itemAt(index).widget()
        divider = self.vbox_layout.itemAt(index + 1).widget()
        self.vbox_layout.removeWidget(widget)
        disconnect_events(widget.layer.events, self)
        widget.close()
        self.vbox_layout.removeWidget(divider)
        divider.deleteLater()

    def _reorder(self, event=None):
        """Reorder list of layer widgets.

        Loops through all widgets in list, sequentially removing them
        and inserting them into the correct place in the final list.

        Parameters
        ----------
        event : napari.utils.event.Event, optional
            The napari event that triggered this method.
        """
        total = len(self.layers)

        # Create list of the current property and divider widgets
        widgets = [
            self.vbox_layout.itemAt(i + 1).widget() for i in range(2 * total)
        ]
        # Take every other widget to ignore the dividers and get just the
        # property widgets
        indices = [
            self.layers.index(w.layer)
            for i, w in enumerate(widgets)
            if i % 2 == 0
        ]

        # Move through the layers in order
        for i in range(total):
            # Find index of property widget in list of the current layer
            index = 2 * indices.index(i)
            widget = widgets[index]
            divider = widgets[index + 1]
            # Check if current index does not match new index
            index_current = self.vbox_layout.indexOf(widget)
            index_new = 2 * (total - i) - 1
            if index_current != index_new:
                # Remove that property widget and divider
                self.vbox_layout.removeWidget(widget)
                self.vbox_layout.removeWidget(divider)
                # Insert the property widget and divider into new location
                self.vbox_layout.insertWidget(index_new, widget)
                self.vbox_layout.insertWidget(index_new + 1, divider)

    def _force_scroll(self):
        """Force the scroll bar to automattically scroll either up or down."""
        cur_value = self.verticalScrollBar().value()
        if self._scroll_up:
            new_value = cur_value - self.verticalScrollBar().singleStep() / 4
            if new_value < 0:
                new_value = 0
            self.verticalScrollBar().setValue(new_value)
        else:
            new_value = cur_value + self.verticalScrollBar().singleStep() / 4
            if new_value > self.verticalScrollBar().maximum():
                new_value = self.verticalScrollBar().maximum()
            self.verticalScrollBar().setValue(new_value)

    def _ensure_visible(self, layer):
        """Ensure layer widget for at particular layer is visible.

        Parameters
        ----------
        layer : napari.layers.Layer
            An instance of a napari layer.

        """
        total = len(self.layers)
        layer_index = self.layers.index(layer)
        # Find property widget and divider for layer to be removed
        index = 2 * (total - layer_index) - 1
        widget = self.vbox_layout.itemAt(index).widget()
        self.ensureWidgetVisible(widget)

    def keyPressEvent(self, event):
        """Ignore a key press event.

        Allows the event to pass through a parent widget to its child widget
        without doing anything. If we did not use event.ignore() then the
        parent widget would catch the event and not pass it on to the child.

        Parameters
        ----------
        event : qtpy.QtCore.QEvent
            Event from the Qt context.
        """
        event.ignore()

    def keyReleaseEvent(self, event):
        """Ignore key release event.

        Allows the event to pass through a parent widget to its child widget
        without doing anything. If we did not use event.ignore() then the
        parent widget would catch the event and not pass it on to the child.

        Parameters
        ----------
        event : qtpy.QtCore.QEvent
            Event from the Qt context.
        """
        event.ignore()

    def mousePressEvent(self, event):
        """Register mouse click if it happens on a layer widget.

        Checks if mouse press happens on a layer properties widget or
        a child of such a widget. If not, the press has happened on the
        Layers Widget itself and should be ignored.

        Parameters
        ----------
        event : qtpy.QtCore.QEvent
            Event from the Qt context.
        """
        widget = self.childAt(event.pos())
        layer = (
            getattr(widget, 'layer', None)
            or getattr(widget.parentWidget(), 'layer', None)
            or getattr(widget.parentWidget().parentWidget(), 'layer', None)
        )

        if layer is not None:
            self._drag_start_position = np.array(
                [event.pos().x(), event.pos().y()]
            )
            self._drag_name = layer.name
        else:
            self._drag_name = None

    def mouseReleaseEvent(self, event):
        """Select layer using mouse click.

        Key modifiers:
        Shift - If the Shift button is pressed, select all layers in between
            currently selected one and the clicked one.
        Control - If the Control button is pressed, mouse click will
            toggle selected state of the layer.

        Parameters
        ----------
        event : qtpy.QtCore.QEvent
            Event from the Qt context.
        """
        if self._drag_name is None:
            # Unselect all the layers if not dragging a layer
            self.layers.selection.active = None
            return

        modifiers = event.modifiers()
        clicked_layer = self.layers[self._drag_name]
        if modifiers == Qt.ShiftModifier and self.layers.selection._current:
            # shift-click: select all layers between current and clicked
            clicked = self.layers.index(clicked_layer)
            current = self.layers.index(self.layers.selection._current)
            from_, to_ = sorted([clicked, current])
            _to_select = self.layers[slice(from_, to_ + 1)]  # inclusive range
            self.layers.selection.update(_to_select)
            self.layers.selection._current = clicked_layer
        elif modifiers == Qt.ControlModifier:
            # If control click toggle selected state of clicked layer
            self.layers.selection.toggle(clicked_layer)
        else:
            # If otherwise unselect all and leave clicked one selected
            self.layers.selection.active = clicked_layer

    def mouseMoveEvent(self, event):
        """Drag and drop layer with mouse movement.

        Parameters
        ----------
        event : qtpy.QtCore.QEvent
            Event from the Qt context.
        """
        position = np.array([event.pos().x(), event.pos().y()])
        distance = np.linalg.norm(position - self._drag_start_position)
        if (
            distance < QApplication.startDragDistance()
            or self._drag_name is None
        ):
            return
        mimeData = QMimeData()
        mimeData.setText(self._drag_name)
        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(event.pos() - self.rect().topLeft())
        drag.exec_()
        # Check if dragged layer still exists or was deleted during drag
        names = [layer.name for layer in self.layers]
        dragged_layer_exists = self._drag_name in names
        if self._drag_name is not None and dragged_layer_exists:
            index = self.layers.index(self._drag_name)
            layer = self.layers[index]
            self._ensure_visible(layer)

    def dragLeaveEvent(self, event):
        """Unselects layer dividers.

        Allows the event to pass through a parent widget to its child widget
        without doing anything. If we did not use event.ignore() then the
        parent widget would catch the event and not pass it on to the child.

        Parameters
        ----------
        event : qtpy.QtCore.QEvent
            Event from the Qt context.
        """
        event.ignore()
        self._drag_timer.stop()
        for i in range(0, self.vbox_layout.count(), 2):
            self.vbox_layout.itemAt(i).widget().setSelected(False)

    def dragEnterEvent(self, event):
        """Update divider position before dragging layer widget to new position

        Allows the event to pass through a parent widget to its child widget
        without doing anything. If we did not use event.ignore() then the
        parent widget would catch the event and not pass it on to the child.

        Parameters
        ----------
        event : qtpy.QtCore.QEvent
            Event from the Qt context.
        """
        if event.source() == self:
            event.accept()
            divs = []
            for i in range(0, self.vbox_layout.count(), 2):
                widget = self.vbox_layout.itemAt(i).widget()
                divs.append(widget.y() + widget.frameGeometry().height() / 2)
            self.centers = [
                (divs[i + 1] + divs[i]) / 2 for i in range(len(divs) - 1)
            ]
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        """Highlight appriate divider when dragging layer to new position.

        Sets the appropriate layers list divider to be highlighted when
        dragging a layer to a new position in the layers list.

        Parameters
        ----------
        event : qtpy.QtCore.QEvent
            Event from the Qt context.
        """
        max_height = self.frameGeometry().height()
        if (
            event.pos().y() < self._min_scroll_region
            and not self._drag_timer.isActive()
        ):
            self._scroll_up = True
            self._drag_timer.start()
        elif (
            event.pos().y() > max_height - self._min_scroll_region
            and not self._drag_timer.isActive()
        ):
            self._scroll_up = False
            self._drag_timer.start()
        elif (
            self._drag_timer.isActive()
            and event.pos().y() >= self._min_scroll_region
            and event.pos().y() <= max_height - self._min_scroll_region
        ):
            self._drag_timer.stop()

        # Determine which widget center is the mouse currently closed to
        cord = event.pos().y() + self.verticalScrollBar().value()
        center_list = (i for i, x in enumerate(self.centers) if x > cord)
        divider_index = next(center_list, len(self.centers))
        # Determine the current location of the widget being dragged
        total = self.vbox_layout.count() // 2 - 1
        insert = total - divider_index
        index = self.layers.index(self._drag_name)
        # If the widget being dragged hasn't moved above or below any other
        # widgets then don't highlight any dividers
        selected = not (insert == index) and not (insert - 1 == index)
        # Set the selected state of all the dividers
        for i in range(0, self.vbox_layout.count(), 2):
            if i == 2 * divider_index:
                self.vbox_layout.itemAt(i).widget().setSelected(selected)
            else:
                self.vbox_layout.itemAt(i).widget().setSelected(False)

    def dropEvent(self, event):
        """Drop dragged layer widget into new position in the list of layers.

        Parameters
        ----------
        event : qtpy.QtCore.QEvent
            Event from the Qt context.
        """
        if self._drag_timer.isActive():
            self._drag_timer.stop()

        for i in range(0, self.vbox_layout.count(), 2):
            self.vbox_layout.itemAt(i).widget().setSelected(False)
        cord = event.pos().y() + self.verticalScrollBar().value()
        center_list = (i for i, x in enumerate(self.centers) if x > cord)
        divider_index = next(center_list, len(self.centers))
        total = self.vbox_layout.count() // 2 - 1
        insert = total - divider_index
        index = self.layers.index(self._drag_name)
        if index != insert and index + 1 != insert:
            if insert >= index:
                insert -= 1
            self.layers.move_selected(index, insert)
        event.accept()
コード例 #7
0
ファイル: main.py プロジェクト: AllenCellModeling/napari
class QtLayers(QScrollArea):
    def __init__(self, layers):
        super().__init__()

        self.layers = layers
        self.setWidgetResizable(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scrollWidget = QWidget()
        self.setWidget(scrollWidget)
        self.vbox_layout = QVBoxLayout(scrollWidget)
        self.vbox_layout.addWidget(QtDivider())
        self.vbox_layout.addStretch(1)
        self.vbox_layout.setContentsMargins(0, 0, 0, 0)
        self.centers = []
        self.setAcceptDrops(True)
        self.setToolTip('Layer list')

        self.layers.events.added.connect(self._add)
        self.layers.events.removed.connect(self._remove)
        self.layers.events.reordered.connect(self._reorder)

    def _add(self, event):
        """Insert `event.widget` at index `event.index`."""
        layer = event.item
        index = event.index
        total = len(self.layers)
        if layer._qt_properties is not None:
            self.vbox_layout.insertWidget(2 * (total - index) - 1,
                                          layer._qt_properties)
            self.vbox_layout.insertWidget(2 * (total - index), QtDivider())

    def _remove(self, event):
        """Remove layer widget at index `event.index`."""
        layer = event.item
        if layer._qt_properties is not None:
            index = self.vbox_layout.indexOf(layer._qt_properties)
            divider = self.vbox_layout.itemAt(index + 1).widget()
            self.vbox_layout.removeWidget(layer._qt_properties)
            layer._qt_properties.deleteLater()
            layer._qt_properties = None
            self.vbox_layout.removeWidget(divider)
            divider.deleteLater()
            divider = None

    def _reorder(self, event):
        """Reorders list of layer widgets by looping through all
        widgets in list sequentially removing them and inserting
        them into the correct place in final list.
        """
        total = len(self.layers)
        for i in range(total):
            layer = self.layers[i]
            if layer._qt_properties is not None:
                index = self.vbox_layout.indexOf(layer._qt_properties)
                divider = self.vbox_layout.itemAt(index + 1).widget()
                self.vbox_layout.removeWidget(layer._qt_properties)
                self.vbox_layout.removeWidget(divider)
                self.vbox_layout.insertWidget(2 * (total - i) - 1,
                                              layer._qt_properties)
                self.vbox_layout.insertWidget(2 * (total - i), divider)

    def mouseReleaseEvent(self, event):
        """Unselects all layer widgets."""
        self.layers.unselect_all()

    def dragLeaveEvent(self, event):
        """Unselects layer dividers."""
        event.ignore()
        for i in range(0, self.vbox_layout.count(), 2):
            self.vbox_layout.itemAt(i).widget().setSelected(False)

    def dragEnterEvent(self, event):
        event.accept()
        divs = []
        for i in range(0, self.vbox_layout.count(), 2):
            widget = self.vbox_layout.itemAt(i).widget()
            divs.append(widget.y() + widget.frameGeometry().height() / 2)
        self.centers = [(divs[i + 1] + divs[i]) / 2
                        for i in range(len(divs) - 1)]

    def dragMoveEvent(self, event):
        """Set the appropriate layers list divider to be highlighted when
        dragging a layer to a new position in the layers list.
        """
        # Determine which widget center is the mouse currently closed to
        cord = event.pos().y()
        center_list = (i for i, x in enumerate(self.centers) if x > cord)
        divider_index = next(center_list, len(self.centers))
        # Determine the current location of the widget being dragged
        layerWidget = event.source()
        total = self.vbox_layout.count() // 2 - 1
        index = total - self.vbox_layout.indexOf(layerWidget) // 2 - 1
        insert = total - divider_index
        # If the widget being dragged hasn't moved above or below any other
        # widgets then don't highlight any dividers
        selected = (not (insert == index) and not (insert - 1 == index))
        # Set the selected state of all the dividers
        for i in range(0, self.vbox_layout.count(), 2):
            if i == 2 * divider_index:
                self.vbox_layout.itemAt(i).widget().setSelected(selected)
            else:
                self.vbox_layout.itemAt(i).widget().setSelected(False)

    def dropEvent(self, event):
        for i in range(0, self.vbox_layout.count(), 2):
            self.vbox_layout.itemAt(i).widget().setSelected(False)
        cord = event.pos().y()
        center_list = (i for i, x in enumerate(self.centers) if x > cord)
        divider_index = next(center_list, len(self.centers))
        layerWidget = event.source()
        total = self.vbox_layout.count() // 2 - 1
        index = total - self.vbox_layout.indexOf(layerWidget) // 2 - 1
        insert = total - divider_index
        if index != insert and index + 1 != insert:
            if not self.layers[index].selected:
                self.layers.unselect_all()
                self.layers[index].selected = True
            self.layers._move_layers(index, insert)
        event.accept()
コード例 #8
0
class PythonFileInterpreter(QWidget):
    sig_editor_modified = Signal(bool)
    sig_filename_modified = Signal(str)

    def __init__(self, content=None, filename=None, parent=None):
        """
        :param content: An optional string of content to pass to the editor
        :param filename: The file path where the content was read.
        :param parent: An optional parent QWidget
        """
        super(PythonFileInterpreter, self).__init__(parent)

        # layout
        self.editor = CodeEditor("AlternateCSPythonLexer", self)

        # Clear QsciScintilla key bindings that may override PyQt's bindings
        self.clear_key_binding("Ctrl+/")

        self.status = QStatusBar(self)
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.editor)
        self.layout.addWidget(self.status)
        self.setLayout(self.layout)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self._setup_editor(content, filename)

        self.setAttribute(Qt.WA_DeleteOnClose, True)

        self._presenter = PythonFileInterpreterPresenter(
            self, PythonCodeExecution(content))

        self.editor.modificationChanged.connect(self.sig_editor_modified)
        self.editor.fileNameChanged.connect(self.sig_filename_modified)
        self.find_replace_dialog = None
        self.find_replace_dialog_shown = False

    def closeEvent(self, event):
        self.deleteLater()
        if self.find_replace_dialog:
            self.find_replace_dialog.close()
        super(PythonFileInterpreter, self).closeEvent(event)

    def show_find_replace_dialog(self):
        if self.find_replace_dialog is None:
            self.find_replace_dialog = EmbeddedFindReplaceDialog(
                self, self.editor)
            self.layout.insertWidget(0, self.find_replace_dialog.view)

        self.find_replace_dialog.show()

    def hide_find_replace_dialog(self):
        if self.find_replace_dialog is not None:
            self.find_replace_dialog.hide()

    @property
    def filename(self):
        return self.editor.fileName()

    def confirm_close(self):
        """Confirm the widget can be closed. If the editor contents are modified then
        a user can interject and cancel closing.

        :return: True if closing was considered successful, false otherwise
        """
        return self.save(confirm=True)

    def abort(self):
        self._presenter.req_abort()

    def execute_async(self):
        self._presenter.req_execute_async()

    def save(self, confirm=False):
        if self.editor.isModified():
            io = EditorIO(self.editor)
            return io.save_if_required(confirm)
        else:
            return True

    def set_editor_readonly(self, ro):
        self.editor.setReadOnly(ro)

    def set_status_message(self, msg):
        self.status.showMessage(msg)

    def replace_tabs_with_spaces(self):
        self.replace_text(TAB_CHAR, SPACE_CHAR * TAB_WIDTH)

    def replace_text(self, match_text, replace_text):
        if self.editor.selectedText() == '':
            self.editor.selectAll()
        new_text = self.editor.selectedText().replace(match_text, replace_text)
        self.editor.replaceSelectedText(new_text)

    def replace_spaces_with_tabs(self):
        self.replace_text(SPACE_CHAR * TAB_WIDTH, TAB_CHAR)

    def set_whitespace_visible(self):
        self.editor.setWhitespaceVisibility(CodeEditor.WsVisible)

    def set_whitespace_invisible(self):
        self.editor.setWhitespaceVisibility(CodeEditor.WsInvisible)

    def clear_key_binding(self, key_str):
        """Clear a keyboard shortcut bound to a Scintilla command"""
        self.editor.clearKeyBinding(key_str)

    def toggle_comment(self):
        if self.editor.selectedText() == '':  # If nothing selected, do nothing
            return

        # Note selection indices to restore highlighting later
        selection_idxs = list(self.editor.getSelection())

        # Expand selection from first character on start line to end char on last line
        line_end_pos = len(
            self.editor.text().split('\n')[selection_idxs[2]].rstrip())
        line_selection_idxs = [
            selection_idxs[0], 0, selection_idxs[2], line_end_pos
        ]
        self.editor.setSelection(*line_selection_idxs)
        selected_lines = self.editor.selectedText().split('\n')

        if self._are_comments(selected_lines) is True:
            toggled_lines = self._uncomment_lines(selected_lines)
            # Track deleted characters to keep highlighting consistent
            selection_idxs[1] -= 2
            selection_idxs[-1] -= 2
        else:
            toggled_lines = self._comment_lines(selected_lines)
            selection_idxs[1] += 2
            selection_idxs[-1] += 2

        # Replace lines with commented/uncommented lines
        self.editor.replaceSelectedText('\n'.join(toggled_lines))

        # Restore highlighting
        self.editor.setSelection(*selection_idxs)

    def _comment_lines(self, lines):
        for i in range(len(lines)):
            lines[i] = '# ' + lines[i]
        return lines

    def _uncomment_lines(self, lines):
        for i in range(len(lines)):
            uncommented_line = lines[i].replace('# ', '', 1)
            if uncommented_line == lines[i]:
                uncommented_line = lines[i].replace('#', '', 1)
            lines[i] = uncommented_line
        return lines

    def _are_comments(self, code_lines):
        for line in code_lines:
            if line.strip():
                if not line.strip().startswith('#'):
                    return False
        return True

    def _setup_editor(self, default_content, filename):
        editor = self.editor

        # use tabs not spaces for indentation
        editor.setIndentationsUseTabs(False)
        editor.setTabWidth(TAB_WIDTH)

        # show current editing line but in a softer color
        editor.setCaretLineBackgroundColor(CURRENTLINE_BKGD_COLOR)
        editor.setCaretLineVisible(True)

        # set a margin large enough for sensible file sizes < 1000 lines
        # and the progress marker
        font_metrics = QFontMetrics(self.font())
        editor.setMarginWidth(1, font_metrics.averageCharWidth() * 3 + 20)

        # fill with content if supplied and set source filename
        if default_content is not None:
            editor.setText(default_content)
        if filename is not None:
            editor.setFileName(filename)
        # Default content does not count as a modification
        editor.setModified(False)

        editor.enableAutoCompletion(CodeEditor.AcsAll)
コード例 #9
0
ファイル: list.py プロジェクト: bryantChhun/napari-gui
class QtLayersList(QScrollArea):
    def __init__(self, layers):
        super().__init__()

        self.layers = layers
        self.setWidgetResizable(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scrollWidget = QWidget()
        self.setWidget(scrollWidget)
        self.vbox_layout = QVBoxLayout(scrollWidget)
        self.vbox_layout.addWidget(QtDivider())
        self.vbox_layout.addStretch(1)
        self.vbox_layout.setContentsMargins(0, 0, 0, 0)
        self.centers = []
        self.setAcceptDrops(True)
        self.setToolTip('Layer list')

        self.layers.events.added.connect(self._add)
        self.layers.events.removed.connect(self._remove)
        self.layers.events.reordered.connect(self._reorder)

    def _add(self, event):
        """Inserts a layer widget at a specific index
        """
        layer = event.item
        index = event.index
        total = len(self.layers)
        if layer._qt_properties is not None:
            self.vbox_layout.insertWidget(2 * (total - index) - 1,
                                          layer._qt_properties)
            self.vbox_layout.insertWidget(2 * (total - index), QtDivider())

    def _remove(self, event):
        """Removes a layer widget
        """
        layer = event.item
        if layer._qt_properties is not None:
            index = self.vbox_layout.indexOf(layer._qt_properties)
            divider = self.vbox_layout.itemAt(index + 1).widget()
            self.vbox_layout.removeWidget(layer._qt_properties)
            layer._qt_properties.deleteLater()
            layer._qt_properties = None
            self.vbox_layout.removeWidget(divider)
            divider.deleteLater()
            divider = None

    def _reorder(self, event):
        """Reorders list of layer widgets by looping through all
        widgets in list sequentially removing them and inserting
        them into the correct place in final list.
        """
        total = len(self.layers)
        for i in range(total):
            layer = self.layers[i]
            if layer._qt_properties is not None:
                index = self.vbox_layout.indexOf(layer._qt_properties)
                divider = self.vbox_layout.itemAt(index + 1).widget()
                self.vbox_layout.removeWidget(layer._qt_properties)
                self.vbox_layout.removeWidget(divider)
                self.vbox_layout.insertWidget(2 * (total - i) - 1,
                                              layer._qt_properties)
                self.vbox_layout.insertWidget(2 * (total - i), divider)

    def mouseReleaseEvent(self, event):
        """Unselects all layer widgets
        """
        self.layers.unselect_all()

    def dragLeaveEvent(self, event):
        """Unselects layer dividers
        """
        event.ignore()
        for i in range(0, self.vbox_layout.count(), 2):
            self.vbox_layout.itemAt(i).widget().setSelected(False)

    def dragEnterEvent(self, event):
        event.accept()
        divs = []
        for i in range(0, self.vbox_layout.count(), 2):
            widget = self.vbox_layout.itemAt(i).widget()
            divs.append(widget.y() + widget.frameGeometry().height() / 2)
        self.centers = [(divs[i + 1] + divs[i]) / 2
                        for i in range(len(divs) - 1)]

    def dragMoveEvent(self, event):
        cord = event.pos().y()
        center_list = (i for i, x in enumerate(self.centers) if x > cord)
        divider_index = next(center_list, len(self.centers))
        layerWidget = event.source()
        total = self.vbox_layout.count() // 2 - 1
        index = total - self.vbox_layout.indexOf(layerWidget) // 2 - 1
        insert = total - divider_index
        if not (insert == index) and not (insert - 1 == index):
            state = True
        else:
            state = False
        for i in range(0, self.vbox_layout.count(), 2):
            if i == 2 * divider_index:
                self.vbox_layout.itemAt(i).widget().setSelected(state)
            else:
                self.vbox_layout.itemAt(i).widget().setSelected(False)

    def dropEvent(self, event):
        for i in range(0, self.vbox_layout.count(), 2):
            self.vbox_layout.itemAt(i).widget().setSelected(False)
        cord = event.pos().y()
        center_list = (i for i, x in enumerate(self.centers) if x > cord)
        divider_index = next(center_list, len(self.centers))
        layerWidget = event.source()
        total = self.vbox_layout.count() // 2 - 1
        index = total - self.vbox_layout.indexOf(layerWidget) // 2 - 1
        insert = total - divider_index
        if index != insert and index + 1 != insert:
            if not self.layers[index].selected:
                self.layers.unselect_all()
                self.layers[index].selected = True
            self.layers._move_layers(index, insert)
        event.accept()
コード例 #10
0
ファイル: Window.py プロジェクト: desty2k/QRainbowStyleSheet
class FramelessWindowBase(QDialog):
    closeClicked = Signal()

    def __init__(self, parent):
        super(FramelessWindowBase, self).__init__(parent)
        self.__rect = QApplication.instance().desktop().availableGeometry(self)

        self.__resizingEnabled = True
        self.__contentWidgets = []

        self.setMouseTracking(True)
        self.setAttribute(Qt.WA_NoSystemBackground)
        super().setContentsMargins(0, 0, 0, 0)
        super().setWindowFlags(Qt.Window
                               | Qt.FramelessWindowHint
                               | Qt.WindowSystemMenuHint
                               | Qt.WindowMinimizeButtonHint
                               | Qt.WindowMaximizeButtonHint
                               | Qt.WindowCloseButtonHint)

        self.__centralWidget = QWidget(self)
        self.__centralWidget.setObjectName("__centralWidget")
        self.__centralWidget.setContentsMargins(0, 0, 0, 0)
        self.__centralWidget.setMouseTracking(True)

        self.__centralLayout = QVBoxLayout(self.__centralWidget)
        self.__centralLayout.setAlignment(Qt.AlignBottom)
        self.__centralLayout.setContentsMargins(0, 0, 0, 0)
        self.__centralLayout.setSpacing(0)

        self.__bar = Titlebar(self)
        self.__bar.showRestoreButton(False)
        self.__bar.showMinimizeButton(False)
        self.__bar.showMaximizeButton(False)
        self.__centralLayout.addWidget(self.__bar)
        self.__centralLayout.setAlignment(self.__bar, Qt.AlignVCenter)

        self.__contentWidget = QWidget(self)
        self.__contentWidget.setObjectName("__contentWidget")
        self.__contentWidget.setSizePolicy(QSizePolicy.Expanding,
                                           QSizePolicy.Expanding)
        self.__contentWidget.setContentsMargins(2, 0, 2, 2)
        self.__contentWidgetLayout = QVBoxLayout(self.__contentWidget)
        self.__contentWidgetLayout.setContentsMargins(0, 0, 0, 0)
        self.__centralLayout.addWidget(self.__contentWidget)

        self.__centralWidget.setLayout(self.__centralLayout)
        self.__contentWidget.setAutoFillBackground(True)

        self.__bar.closeClicked.connect(self.closeClicked.emit)
        self.closeClicked.connect(self.close)

        self.__main_layout = QVBoxLayout(self)
        self.__main_layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.__main_layout)
        self.__main_layout.addWidget(self.__centralWidget)

        QMetaObject.connectSlotsByName(self)
        self.showSizeControl(True)
        self.resize(
            QSize(int(self.__rect.width() / 2), int(self.__rect.height() / 2)))

    def setContentsMargins(self, left, top, right, bottom):
        self.__contentWidgetLayout.setContentsMargins(left, top, right, bottom)

    def showWindowShadow(self, value: bool):
        pass

    def setEdgeSnapping(self, value: bool):
        pass

    def setResizingEnabled(self, value: bool):
        """Enable window resizing

        Args:
            value (bool): Enable or disable window resizing
        """
        self.__resizingEnabled = value

    def addMenu(self, menu):
        self.__bar.addMenu(menu)

    def titlebar(self):
        return self.__bar

    def showSizeControl(self, value: bool):
        self.__bar.showMaximizeButton(value)
        self.__bar.showMinimizeButton(value)

    def isResizingEnabled(self) -> bool:
        """Return if window allows resizing

        Returns:
            value (bool): Window allow resizing.
        """
        return self.__resizingEnabled

    def setTitlebarHeight(self, height: int):
        """Set titlebar height.

        Args:
            height (int): Titlebar height.
        """
        self.__bar.setTitlebarHeight(height)

    def addContentWidget(self, widget: QWidget):
        """Add master widget to window.

        Args:
            widget (QWidget): Content widget.
        """
        self.__contentWidgets.append(widget)
        self.__contentWidgetLayout.addWidget(widget)

    def insertContentWidget(self, index, widget: QWidget):
        """Insert master widget to window at pos.

        Args:
            index (int): Index
            widget (QWidget): Content widget.
        """
        self.__contentWidgets.insert(index, widget)
        self.__contentWidgetLayout.insertWidget(index, widget)

    def setWindowIcon(self, icon: QIcon) -> None:
        self.__bar.setWindowIcon(icon)
        super().setWindowIcon(icon)

    def changeEvent(self, event: QEvent) -> None:
        if event.type(
        ) == QEvent.WindowStateChange and not qrainbowstyle.USE_DARWIN_BUTTONS:
            if self.isMaximized():
                self.__bar.showRestoreButton(True)
                self.__bar.showMaximizeButton(False)
            else:
                self.__bar.showRestoreButton(False)
                self.__bar.showMaximizeButton(True)
        return super().changeEvent(event)
コード例 #11
0
ファイル: mplwidget.py プロジェクト: bremme/QtPyWidgets
class QtMplWidget(QWidget):
    """
    """
    # Create the Qt Signals (wrappers)
    buttonPressed = Signal(MouseEvent, name="buttonPressed")
    buttonReleased = Signal(MouseEvent, name="buttonReleased")
    canvasRedrawn = Signal(DrawEvent, name="canvasRedrawn")
    keyPressed = Signal(KeyEvent, name="keyPressed")
    keyReleased = Signal(KeyEvent, name="keyReleased")
    mouseMotion = Signal(MouseEvent, name="mouseMotion")
    artistPicked = Signal(PickEvent, name="artistPicked")
    figureResized = Signal(ResizeEvent, name="figureResized")
    mouseScrolled = Signal(MouseEvent, name="mouseScrolled")
    figureEntered = Signal(Event, name="figureEntered")
    figureLeft = Signal(Event, name="figureLeft")
    axesEntered = Signal(MouseEvent, name="axesEntered")
    axesLeft = Signal(MouseEvent, name="axesLeft")
    figureClosed = Signal(CloseEvent, name="figureClosed")
    # new Qt signals
    toolbarMoved = Signal(str, name="toolbarMoved")
    toolbarShown = Signal(bool, name="toolbarShown")

    def __init__(self, toolbar=True, toolbarPosition="top", parent=None):
        super(QtMplWidget, self).__init__(parent)
        self.toolbarPosition = toolbarPosition
        self.__setup_ui(toolbar)
        self.__wrap_mpl_signals()

    def __setup_ui(self, toolbar):
        """Setup the matplotlib widget UI elements
        """
        self.canvas = QtMplCanvas(self)
        self.fig = self.canvas.fig
        self.axes = self.canvas.axes
        self.layout = QVBoxLayout(self)
        self.layout.addWidget(self.canvas)
        if toolbar is True:
            self.showToolbar()
        else:
            self.toolbar = None

    def __wrap_mpl_signals(self):
        """Wrap the mpl_connect events in Qt signals.
        """
        self.__buttonPressedCid = self.canvas.mpl_connect(
            "button_press_event", self.buttonPressed.emit)
        self.__buttonReleasedCid = self.canvas.mpl_connect(
            "button_release_event", self.buttonReleased.emit)
        self.__canvasRedrawnCid = self.canvas.mpl_connect(
            "draw_event", self.canvasRedrawn.emit)
        self.__keyPressedCid = self.canvas.mpl_connect("key_press_event",
                                                       self.keyPressed.emit)
        self.__keyReleasedCid = self.canvas.mpl_connect(
            "key_released_event", self.keyReleased.emit)
        self.__mouseMotionCid = self.canvas.mpl_connect(
            "motion_notify_event", self.mouseMotion.emit)
        self.pickCid = self.canvas.mpl_connect("pick_event",
                                               self.artistPicked.emit)
        self.__figureResizedCid = self.canvas.mpl_connect(
            "resize_event", self.figureResized.emit)
        self.__mouseScrolledCid = self.canvas.mpl_connect(
            "scroll_event", self.mouseScrolled.emit)
        self.__figureEnteredCid = self.canvas.mpl_connect(
            "figure_enter_event", self.figureEntered.emit)
        self.__figureLeftCid = self.canvas.mpl_connect("figure_leave_event",
                                                       self.figureLeft.emit)
        self.__axesEnteredCid = self.canvas.mpl_connect(
            "axes_enter_event", self.axesEntered.emit)
        self.__axesLeftCid = self.canvas.mpl_connect("axes_leave_event",
                                                     self.axesLeft.emit)
        self.__figureClosedCid = self.canvas.mpl_connect(
            "close_event", self.figureClosed.emit)

    @property
    def toolbarPosition(self):
        return self.toolbarPosition

    @toolbarPosition.setter
    def toolbarPosition(self, position):
        if position not in ["top", "bottom"]:
            raise ValueError("Toolbar position can only be 'top' or 'bottom'")
        self.toolbarPosition = position

    @Slot(bool)
    def showToolbar(self, show):
        if self.toolbar is None:
            self.moveToolbar(self.toolbarPosition)
        self.toolbar.setVisible(show)
        self.toolbarShown.emit(show)

    @Slot(str)
    def moveToolbar(self, position):
        self.toolbarPosition = position
        # if no toolbar, add it
        if self.toolbar is None:
            self.toolbar = NavigationToolbar(self.canvas,
                                             self,
                                             coordinates=True)
        else:
            self.layout.removeWidget(self.toolbar)
        if position == "top":
            self.layout.insertWidget(0, self.toolbar)
        else:
            self.layout.addWidget(self.toolbar)
        self.toolbarMoved.emit(self.toolbarPosition)

    @Slot()
    @Slot(bool)
    def clearAxes(self, draw=True):
        self.axes.clear()
        if draw:
            self.canvas.draw()
コード例 #12
0
ファイル: interpreter.py プロジェクト: mantidproject/mantid
class PythonFileInterpreter(QWidget):
    sig_editor_modified = Signal(bool)
    sig_filename_modified = Signal(str)
    sig_progress = Signal(int)
    sig_exec_error = Signal(object)
    sig_exec_success = Signal(object)

    def __init__(self, font=None, content=None, filename=None,
                 parent=None):
        """
        :param font: A reference to the font to be used by the editor. If not supplied use the system default
        :param content: An optional string of content to pass to the editor
        :param filename: The file path where the content was read.
        :param parent: An optional parent QWidget
        """
        super(PythonFileInterpreter, self).__init__(parent)
        self.parent = parent

        # layout
        font = font if font is not None else QFont()
        self.editor = CodeEditor("AlternateCSPython", font, self)
        self.find_replace_dialog = None
        self.status = QStatusBar(self)
        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.addWidget(self.editor)
        self.layout.addWidget(self.status)
        self.setLayout(self.layout)
        self._setup_editor(content, filename)

        self._presenter = PythonFileInterpreterPresenter(self, PythonCodeExecution(content))
        self.code_commenter = CodeCommenter(self.editor)

        self.editor.modificationChanged.connect(self.sig_editor_modified)
        self.editor.fileNameChanged.connect(self.sig_filename_modified)

        self.setAttribute(Qt.WA_DeleteOnClose, True)

        # Connect the model signals to the view's signals so they can be accessed from outside the MVP
        self._presenter.model.sig_exec_progress.connect(self.sig_progress)
        self._presenter.model.sig_exec_error.connect(self.sig_exec_error)
        self._presenter.model.sig_exec_success.connect(self.sig_exec_success)

    def closeEvent(self, event):
        self.deleteLater()
        if self.find_replace_dialog:
            self.find_replace_dialog.close()
        super(PythonFileInterpreter, self).closeEvent(event)

    def show_find_replace_dialog(self):
        if self.find_replace_dialog is None:
            self.find_replace_dialog = EmbeddedFindReplaceDialog(self, self.editor)
            self.layout.insertWidget(0, self.find_replace_dialog.view)

        self.find_replace_dialog.show()

    def hide_find_replace_dialog(self):
        if self.find_replace_dialog is not None:
            self.find_replace_dialog.hide()

    @property
    def filename(self):
        return self.editor.fileName()

    def confirm_close(self):
        """Confirm the widget can be closed. If the editor contents are modified then
        a user can interject and cancel closing.

        :return: True if closing was considered successful, false otherwise
        """
        return self.save(prompt_for_confirmation=self.parent.confirm_on_save)

    def abort(self):
        self._presenter.req_abort()

    def execute_async(self, ignore_selection=False):
        return self._presenter.req_execute_async(ignore_selection)

    def execute_async_blocking(self):
        self._presenter.req_execute_async_blocking()

    def save(self, prompt_for_confirmation=False, force_save=False):
        if self.editor.isModified():
            io = EditorIO(self.editor)
            return io.save_if_required(prompt_for_confirmation, force_save)
        else:
            return True

    def save_as(self):
        io = EditorIO(self.editor)
        new_filename = io.ask_for_filename()
        if new_filename:
            return io.write(save_as=new_filename), new_filename
        else:
            return False, None

    def set_editor_readonly(self, ro):
        self.editor.setReadOnly(ro)

    def set_status_message(self, msg):
        self.status.showMessage(msg)

    def replace_tabs_with_spaces(self):
        self.replace_text(TAB_CHAR, SPACE_CHAR * TAB_WIDTH)

    def replace_text(self, match_text, replace_text):
        if self.editor.selectedText() == '':
            self.editor.selectAll()
        new_text = self.editor.selectedText().replace(match_text, replace_text)
        self.editor.replaceSelectedText(new_text)

    def replace_spaces_with_tabs(self):
        self.replace_text(SPACE_CHAR * TAB_WIDTH, TAB_CHAR)

    def set_whitespace_visible(self):
        self.editor.setWhitespaceVisibility(CodeEditor.WsVisible)

    def set_whitespace_invisible(self):
        self.editor.setWhitespaceVisibility(CodeEditor.WsInvisible)

    def toggle_comment(self):
        self.code_commenter.toggle_comment()

    def _setup_editor(self, default_content, filename):
        editor = self.editor

        # Clear default QsciScintilla key bindings that we want to allow
        # to be users of this class
        self.clear_key_binding("Ctrl+/")

        # use tabs not spaces for indentation
        editor.setIndentationsUseTabs(False)
        editor.setTabWidth(TAB_WIDTH)

        # show current editing line but in a softer color
        editor.setCaretLineBackgroundColor(CURRENTLINE_BKGD_COLOR)
        editor.setCaretLineVisible(True)

        # set a margin large enough for sensible file sizes < 1000 lines
        # and the progress marker
        font_metrics = QFontMetrics(self.font())
        editor.setMarginWidth(1, font_metrics.averageCharWidth() * 3 + 20)

        # fill with content if supplied and set source filename
        if default_content is not None:
            editor.setText(default_content)
        if filename is not None:
            editor.setFileName(filename)
        # Default content does not count as a modification
        editor.setModified(False)

        editor.enableAutoCompletion(CodeEditor.AcsAll)

    def clear_key_binding(self, key_str):
        """Clear a keyboard shortcut bound to a Scintilla command"""
        self.editor.clearKeyBinding(key_str)