Beispiel #1
0
    def paintEvent(self, e):

        painter = QPainter(self)

        draw_rect = e.rect()

        # SLIDER---------------------------------------------------------------------

        # BAR --------

        painter.setPen(self._bgColor.lighter(200))

        painter.drawRect(draw_rect.adjusted(0, 0, -1, -1))

        painter.fillRect(draw_rect.adjusted(1, 1, -1, -1), self._bgColor)

        # THUMB --------

        painter.setPen(self._thumbColor.lighter())

        painter.drawRect(self._thumbRect.adjusted(0, 0, -1, -1))

        painter.fillRect(self._thumbRect.adjusted(1, 1, -1, -1),
                         self._thumbColor)

        # VALUE LABEL --------

        value_text = str(self._value)

        value_label_size = QSize(self._fontMetrics.width(value_text),
                                 self._fontMetrics.height())

        value_indicator_rect = QRect(self._thumbRect.right() + 2,
                                     self._thumbRect.top(),
                                     value_label_size.width() + 10,
                                     self._thumbRect.height())

        if value_indicator_rect.right() > draw_rect.right():
            value_indicator_rect.setRect(
                self._thumbRect.left() - value_indicator_rect.width() - 1,
                value_indicator_rect.top(), value_indicator_rect.width(),
                value_indicator_rect.height())

        painter.setPen(self._indicatorColor.lighter())

        painter.drawRect(value_indicator_rect.adjusted(0, 0, -1, -1))

        painter.fillRect(value_indicator_rect.adjusted(1, 1, -1, -1),
                         self._indicatorColor)

        painter.setPen(Qt.white)

        painter.drawText(
            value_indicator_rect.left() + value_indicator_rect.width() / 2 -
            value_label_size.width() / 2,
            value_indicator_rect.top() + value_indicator_rect.height() / 2 +
            value_label_size.height() / 3, value_text)
Beispiel #2
0
    def paintEvent(self, e):

        p = QPainter(self)

        cell_rect = QRect()

        ramp_count = len(self._ramps)

        col_count = self._ramps[0].color_count

        index = 0
        ramp_index = 0

        for ramp in self._ramps:

            for i in range(0, col_count):
                cell_rect.setRect(i * (self._cellSize + 1),
                                  (index // ramp_count) * (self._cellSize + 1),
                                  self._cellSize, self._cellSize)
                p.fillRect(cell_rect, ramp.color_at(col_count - 1 - i))

                index += 1

            ramp_index += 1

        pen = QPen()

        pen.setWidth(self._cellIndicatorSize)
        pen.setJoinStyle(Qt.MiterJoin)

        border_adjust = self._cellIndicatorSize / 2

        # PAINT SELECTED CELL A

        pen.setColor(self._primaryIndicatorColor)
        p.setPen(pen)

        cell_rect = self._cell_rect(self._selectedCellA2.index)

        p.drawRect(cell_rect.adjusted(border_adjust,
                                      border_adjust,
                                      -border_adjust,
                                      -border_adjust))

        # PAINT SELECTED CELL B

        pen.setColor(self._secondaryIndicatorColor)
        p.setPen(pen)

        cell_rect = self._cell_rect(self._selectedCellB2.index)

        p.drawRect(cell_rect.adjusted(border_adjust,
                                      border_adjust,
                                      -border_adjust,
                                      -border_adjust))
Beispiel #3
0
    def draw(self, painter):

        width = self._list.width()

        draw_rect = QRect(0, self._top, width, self._height)

        if not self._hovered:

            if not self._selected:

                back_color = self._backColor
                border_color = self._borderColor

            else:

                back_color = self._backColorSelected
                border_color = self._borderColorSelected

        else:

            if not self._selected:

                back_color = self._backColor.lighter(120)
                border_color = self._borderColor.lighter(120)

            else:

                back_color = self._backColorSelected.lighter(120)
                border_color = self._borderColorSelected.lighter(120)

        painter.setPen(border_color)
        painter.drawRect(draw_rect.adjusted(0, 0, -2, -2))
        painter.fillRect(draw_rect.adjusted(1, 1, -2, -2), back_color)

        self.draw_content(painter, draw_rect)
Beispiel #4
0
    def paint(self, painter, option, index):
        extra = index.data(Qt.UserRole + 1)

        if not extra:
            return QStyledItemDelegate.paint(self, painter, option, index)
        else:
            if option.state & QStyle.State_Selected:
                painter.fillRect(option.rect,
                                 option.palette.color(QPalette.Highlight))

            title = index.data()
            painter.drawText(option.rect.adjusted(2, 1, 0, 0), Qt.AlignLeft,
                             title)

            fm = QFontMetrics(option.font)
            w = fm.width(title)
            r = QRect(option.rect)
            r.setLeft(r.left() + w)
            painter.save()
            if option.state & QStyle.State_Selected:
                painter.setPen(Qt.white)
            else:
                painter.setPen(Qt.gray)
            painter.drawText(r.adjusted(2, 1, 0, 0), Qt.AlignLeft,
                             " - {}".format(extra))
            painter.restore()
Beispiel #5
0
 def paintEvent(self, event):
     print('hujFrame PaintEvent()', event.rect())
     painter = QPainter()
     rect = painter.viewport()
     print('hujFrame painter.viewport()', event.rect())
     painter.begin(self)
     painter.save()
     font = painter.font()
     font.setPixelSize(56)
     painter.setFont(font)
     # painter.translate(100, 100)
     rectangle = QRect(160, 160, 100, 50)
     boundingRect = painter.drawText(rectangle, 0, self.tr("Hello"))
     pen = painter.pen()
     pen.setStyle(Qt.DotLine)
     painter.setPen(pen)
     painter.drawRect(
         boundingRect.adjusted(0, 0, -pen.width(), -pen.width()))
     pen.setStyle(Qt.DashLine)
     painter.setPen(pen)
     painter.drawRect(rectangle.adjusted(0, 0, -pen.width(), -pen.width()))
     painter.restore()
     painter.end()
     del painter
     super(hujFrame, self).paintEvent(event)
Beispiel #6
0
    def paintEvent(self, e: QPaintEvent):
        super().paintEvent(e)
        painter = QtGui.QPainter(self)
        pen = QtGui.QPen()
        brush = QtGui.QBrush()
        brush.setStyle(Qt.SolidPattern)

        font = QtGui.QFont()
        font.setFamily('Montserrat')
        self.text_template_to_rect = {}

        for template_id, text in self.parent.render_options.items():
            text_template = self.parent.meme_template[template_id]
            pen.setColor(QtGui.QColor(text_template.text_color))
            painter.setPen(pen)

            keyframe = text_template.keyframes.interpolate(
                self.selected_frame_ind)
            font.setPixelSize(keyframe.text_size)
            painter.setFont(font)

            margin = 10
            x, y, width, height = text_template.get_text_bounding_box(
                center_position=keyframe.position,
                font_size=keyframe.text_size,
                text=text)
            text_rect = QRect(x, y, width, height)
            self.text_template_to_rect[template_id] = text_rect

            background_rect = None
            if text_template.background_color is not None:
                background_rect = text_rect.adjusted(-margin, -margin, margin,
                                                     margin)
                painter.fillRect(background_rect,
                                 QColor(text_template.background_color))
            if template_id == self.parent.selected_text_template.id:
                rubber_rect = background_rect if background_rect is not None else text_rect
                self.rubberBand.setGeometry(rubber_rect)

            if text_template.stroke_width:
                painter.setRenderHint(QPainter.Antialiasing, True)
                brush.setColor(QColor(text_template.text_color))
                painter.setBrush(brush)

                pen.setColor(QColor(text_template.stroke_color))
                pen.setWidth(text_template.stroke_width * 2)
                painter.setPen(pen)

                path = QPainterPath()
                path.addText(text_rect.bottomLeft(), font, text)
                painter.strokePath(path, pen)
                painter.fillPath(path, brush)

            else:
                painter.drawText(text_rect, Qt.AlignHCenter | Qt.AlignVCenter,
                                 text)

        painter.end()
Beispiel #7
0
    def paintEvent(self, e):

        p = QPainter(self)

        current_frame_index = self._sprite.current_animation.current_frame_index

        frame_list = self._sprite.current_animation.frames

        frame_size = self._frameSize
        frame_padding = self._framePadding
        half_padding = frame_padding // 2
        two_padding = frame_padding * 2

        if self._horizontalShift != 0:
            p.translate(-self._horizontalShift, 0)

        for frameIndex, frame in enumerate(frame_list):

            surfaces = frame.surfaces

            frame_rect = QRect(
                frame_padding + frameIndex * frame_size +
                two_padding * frameIndex, frame_padding, frame_size,
                frame_size)

            if current_frame_index == frameIndex:
                p.setPen(self._pen)

                p.drawRect(
                    frame_rect.adjusted(-half_padding, -half_padding,
                                        half_padding, half_padding))

                p.setPen(Qt.black)

                p.drawRect(frame_rect.adjusted(-1, -1, 0, 0))

            p.drawTiledPixmap(frame_rect, self._checkerTile)

            for surface in surfaces:
                p.drawImage(frame_rect, surface.image, surface.image.rect())

            p.setPen(Qt.black)
            p.drawText(frame_rect.left() + two_padding,
                       frame_rect.top() + two_padding * 2, str(frameIndex + 1))
Beispiel #8
0
    def do_layout(self, rect: QRect, test_only: bool):
        left, top, right, bottom = self.getContentsMargins()
        effective_rect = rect.adjusted(+left, +top, -right, -bottom)
        x = effective_rect.x()
        y = effective_rect.y()
        line_height = 0
        max_line_width = 0
        curr_line_width = 0
        num_of_lines = 0
        for item in self._items:
            widget = item.widget()
            space_x = self._horizontal_spacing
            if space_x == -1:
                space_x = widget.style().layoutSpacing(QSizePolicy.PushButton,
                                                       QSizePolicy.PushButton,
                                                       Qt.Horizontal)
            space_y = self._vertical_spacing
            if space_y == -1:
                space_y = widget.style().layoutSpacing(QSizePolicy.PushButton,
                                                       QSizePolicy.PushButton,
                                                       Qt.Vertical)
            next_x = x + item.sizeHint().width() + space_x

            if next_x - space_x > effective_rect.right() and line_height > 0:
                x = effective_rect.x()
                y = y + line_height + space_y
                next_x = x + item.sizeHint().width() + space_x
                line_height = 0
                max_line_width = max(curr_line_width, max_line_width)
                curr_line_width = 0
                num_of_lines += 1

            if not test_only:
                item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
            curr_line_width += item.sizeHint().width()
            x = next_x
            line_height = max(line_height, item.sizeHint().height())
        max_line_width = max(curr_line_width, max_line_width)
        if not test_only and rect.width() != 0:
            x_offset = ((rect.width() - left - right) - max_line_width -
                        (self.get_horizontal_spacing() *
                         (len(self._items) - 1))) / 2
            y_offset = ((rect.height() - top - bottom) -
                        (num_of_lines *
                         (line_height + self.get_vertical_spacing()) -
                         self.get_vertical_spacing())) / 2
            for item in self._items:
                widget = item.widget()
                x = widget.x() + x_offset
                y = widget.y() + y_offset
                item.setGeometry(QRect(QPoint(int(x), int(y)),
                                       item.sizeHint()))
        return y + line_height - rect.y() + bottom
    def mouseMoveEvent(self, event):
        p = event.pos()
        r = QRect()

        if self.vSplitRect.contains(p):
            self.mouseHoverState = MOUSE_HOVER.HOVER_VSPLIT
        elif self.hSplitRect.contains(p):
            self.mouseHoverState = MOUSE_HOVER.HOVER_HSPLIT
        elif self.closeRect.contains(p):
            self.mouseHoverState = MOUSE_HOVER.HOVER_CLOSE
        elif self.floatRect.contains(p):
            self.mouseHoverState = MOUSE_HOVER.HOVER_FLOAT
        else:
            self.mouseHoverState = MOUSE_HOVER.HOVER_NONE

        self.repaint(r.adjusted(-1, -1, 1, 1))
Beispiel #10
0
 def computeSize(self):
     """Compute and set the total size of the layout.
     
     In most cases the implementation of this method is sufficient: it
     computes the bounding rectangle of all Pages and adds the margin.
     
     True is returned if the total size has changed.
     
     """
     r = QRect()
     for page in self:
         r |= page.rect()
     m = self.margin
     size = r.adjusted(-m, -m, m, m).size()
     changed = self.size() != size
     self.setSize(size)
     return changed
Beispiel #11
0
 def computeSize(self):
     """Compute and set the total size of the layout.
     
     In most cases the implementation of this method is sufficient: it
     computes the bounding rectangle of all Pages and adds the margin.
     
     True is returned if the total size has changed.
     
     """
     r = QRect()
     for page in self:
         r |= page.rect()
     m = self.margin
     size = r.adjusted(-m, -m, m, m).size()
     changed = self.size() != size
     self.setSize(size)
     return changed
Beispiel #12
0
    def paintSection(self, painter: QPainter, rect: QRect, logical_index: int):
        bg = self.model().headerData(logical_index, Qt.Horizontal,
                                     Qt.BackgroundColorRole)
        cm = self.model().headerData(logical_index, Qt.Horizontal,
                                     ColorMarkRole)

        painter.save()
        super().paintSection(painter, rect, logical_index)
        painter.restore()

        if bg is not None and bg.isValid():
            bg.setAlpha(100)
            painter.fillRect(rect, bg)

        if cm is not None and cm.isValid():
            painter.fillRect(
                rect.adjusted(0, 0, 0, -int(7 * rect.height() / 8)), cm)
    def mouseMoveEvent(self, ev: QtGui.QMouseEvent) -> None:
        ev.accept()
        if self._current_item_index == -1:
            return

        current_seed_item = self._circle_seed_items[
            self._current_item_index]  # type: CircleSeedItem
        if current_seed_item.change_able:
            if self._resize_handel_pressed:
                rect = QRect(current_seed_item.rect().topLeft(),
                             QPoint(ev.pos() + self._mouse_press_offset))
                current_seed_item.radius = min(rect.width(), rect.height(), 8)
            else:
                rect = current_seed_item.rect()
                rect.moveTopLeft(ev.pos() - self._mouse_press_offset)
                rect = rect.adjusted(0, 0, 1, 1)
                current_seed_item.center_pos = rect.center()
        self.update()
Beispiel #14
0
    def doLayout(self, rect: QRect, testOnly: bool):
        left, top, right, bottom = self.getContentsMargins()
        actual_rect: QRect = rect.adjusted(left, top, -right, -bottom)

        horizontal: int = actual_rect.x()
        vertical: int = actual_rect.y()
        line_height: int = 0

        for item in self.items:

            widget = item.widget()
            horizontal_space = self.horizontalSpacing()
            vertical_space = self.verticalSpacing()

            if horizontal_space == -1:
                horizontal_space = widget.style().layoutSpacing(
                    QSizePolicy.PushButton, QSizePolicy.PushButton,
                    Qt.Horizontal)
            if vertical_space == -1:
                vertical_space = widget.style().layoutSpacing(
                    QSizePolicy.PushButton, QSizePolicy.PushButton,
                    Qt.Vertical)

            next_horizontal: int = horizontal + item.sizeHint().width(
            ) + horizontal_space
            if next_horizontal - horizontal_space > actual_rect.right(
            ) and line_height > 0:
                horizontal = actual_rect.x()
                vertical = vertical + line_height + vertical_space
                next_horizontal = horizontal + item.sizeHint().width(
                ) + horizontal_space
                line_height = 0

            if not testOnly:
                item.setGeometry(
                    QRect(QPoint(horizontal, vertical), item.sizeHint()))

            horizontal = next_horizontal
            line_height = max(line_height, item.sizeHint().height())

        return vertical + line_height - rect.y() + bottom
Beispiel #15
0
    def _do_layout(self, full_rect: QRect, dry_run: bool = False) -> int:
        left, top, right, bottom = self.getContentsMargins()
        rect = full_rect.adjusted(left, top, -right, -bottom)
        x = rect.x()
        y = rect.y()
        space_x = self._h_spacing
        space_y = self._v_spacing
        line_height = 0
        for item in self._items:
            next_x = x + item.sizeHint().width() + space_x
            if next_x - space_x > rect.right() and line_height > 0:
                x = rect.x()
                y += line_height + space_y
                next_x = x + item.sizeHint().width() + space_x
                line_height = 0

            if not dry_run:
                item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))

            x = next_x
            line_height = max(line_height, item.sizeHint().height())
        return y + line_height - rect.y() + bottom
Beispiel #16
0
    def paint(self, painter, option, index):
        extra = index.data(Qt.UserRole + 1)
        if not extra:
            return QStyledItemDelegate.paint(self, painter, option, index)

        else:
            if option.state & QStyle.State_Selected:
                painter.fillRect(option.rect, option.palette.color(QPalette.Highlight))

            title = index.data()
            extra = " - {}".format(extra)
            painter.drawText(option.rect.adjusted(2, 1, 0, 0), Qt.AlignLeft, title)

            fm = QFontMetrics(option.font)
            w = fm.width(title)
            r = QRect(option.rect)
            r.setLeft(r.left() + w)
            painter.save()
            if option.state & QStyle.State_Selected:
                painter.setPen(Qt.white)
            else:
                painter.setPen(Qt.gray)
            painter.drawText(r.adjusted(2, 1, 0, 0), Qt.AlignLeft, extra)
            painter.restore()
Beispiel #17
0
class PuzzleWidget(QWidget):

    puzzleCompleted = pyqtSignal()

    def __init__(self, parent=None):
        super(PuzzleWidget, self).__init__(parent)

        self.piecePixmaps = []
        self.pieceRects = []
        self.pieceLocations = []
        self.highlightedRect = QRect()
        self.inPlace = 0

        self.setAcceptDrops(True)
        self.setMinimumSize(400, 400)
        self.setMaximumSize(400, 400)

    def clear(self):
        self.pieceLocations = []
        self.piecePixmaps = []
        self.pieceRects = []
        self.highlightedRect = QRect()
        self.inPlace = 0
        self.update()

    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat('image/x-puzzle-piece'):
            event.accept()
        else:
            event.ignore()

    def dragLeaveEvent(self, event):
        updateRect = self.highlightedRect
        self.highlightedRect = QRect()
        self.update(updateRect)
        event.accept()

    def dragMoveEvent(self, event):
        updateRect = self.highlightedRect.united(self.targetSquare(
            event.pos()))

        if event.mimeData().hasFormat(
                'image/x-puzzle-piece') and self.findPiece(
                    self.targetSquare(event.pos())) == -1:
            self.highlightedRect = self.targetSquare(event.pos())
            event.setDropAction(Qt.MoveAction)
            event.accept()
        else:
            self.highlightedRect = QRect()
            event.ignore()

        self.update(updateRect)

    def dropEvent(self, event):
        if event.mimeData().hasFormat(
                'image/x-puzzle-piece') and self.findPiece(
                    self.targetSquare(event.pos())) == -1:
            pieceData = event.mimeData().data('image/x-puzzle-piece')
            dataStream = QDataStream(pieceData, QIODevice.ReadOnly)
            square = self.targetSquare(event.pos())
            pixmap = QPixmap()
            location = QPoint()
            dataStream >> pixmap >> location

            self.pieceLocations.append(location)
            self.piecePixmaps.append(pixmap)
            self.pieceRects.append(square)

            self.hightlightedRect = QRect()
            self.update(square)

            event.setDropAction(Qt.MoveAction)
            event.accept()

            if location == QPoint(square.x() / 80, square.y() / 80):
                self.inPlace += 1
                if self.inPlace == 25:
                    self.puzzleCompleted.emit()
        else:
            self.highlightedRect = QRect()
            event.ignore()

    def findPiece(self, pieceRect):
        try:
            return self.pieceRects.index(pieceRect)
        except ValueError:
            return -1

    def mousePressEvent(self, event):
        square = self.targetSquare(event.pos())
        found = self.findPiece(square)

        if found == -1:
            return

        location = self.pieceLocations[found]
        pixmap = self.piecePixmaps[found]
        del self.pieceLocations[found]
        del self.piecePixmaps[found]
        del self.pieceRects[found]

        if location == QPoint(square.x() / 80, square.y() / 80):
            self.inPlace -= 1

        self.update(square)

        itemData = QByteArray()
        dataStream = QDataStream(itemData, QIODevice.WriteOnly)

        dataStream << pixmap << location

        mimeData = QMimeData()
        mimeData.setData('image/x-puzzle-piece', itemData)

        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(event.pos() - square.topLeft())
        drag.setPixmap(pixmap)

        if drag.exec_(Qt.MoveAction) != Qt.MoveAction:
            self.pieceLocations.insert(found, location)
            self.piecePixmaps.insert(found, pixmap)
            self.pieceRects.insert(found, square)
            self.update(self.targetSquare(event.pos()))

            if location == QPoint(square.x() / 80, square.y() / 80):
                self.inPlace += 1

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

        if self.highlightedRect.isValid():
            painter.setBrush(QColor("#ffcccc"))
            painter.setPen(Qt.NoPen)
            painter.drawRect(self.highlightedRect.adjusted(0, 0, -1, -1))

        for rect, pixmap in zip(self.pieceRects, self.piecePixmaps):
            painter.drawPixmap(rect, pixmap)

        painter.end()

    def targetSquare(self, position):
        return QRect(position.x() // 80 * 80, position.y() // 80 * 80, 80, 80)
class PanelTopLeftCorner(QWidget):
    def __init__(self, parent):
        super(QWidget, self).__init__(parent)

        self.menuRect = QRect(4, 4, 14, 14)
        self.hovered = False
        self.panelMenu = QMenu() if 0 else None

        self.setMouseTracking(True)
        self.setAttribute(Qt.WA_Hover)
        self.installEventFilter(self)

    def minimumSizeHint(self):
        return QSize(22, 22)

    def sizeHint(self):
        return self.minimumSizeHint()

    def paintEvent(self, event):
        painter = QPainter(self)
        palette = self.palette()
        midColor = palette.mid().color()
        highlight = palette.highlight().color()

        # background
        painter.fillRect(self.rect(), midColor.lighter())

        # menu rect
        color = highlight if self.hovered else midColor
        painter.setPen(color)
        painter.setBrush(palette.light())
        painter.drawRect(self.menuRect)
        if color == highlight:
            painter.setBrush(highlight)
            painter.drawRect(self.menuRect.adjusted(2, 2, -2, -2))

    def mouseMoveEvent(self, event):
        self.hovered = self.menuRect.contains(event.pos())
        self.repaint(self.menuRect.adjusted(-1, -1, -1, -1))

    def mousePressEvent(self, event):
        mouseClickPos = event.pos()
        if self.menuRect.contains(mouseClickPos):
            self.panelMenu.exec_(self.mapToGlobal(mouseClickPos))

    def eventFilter(self, obj, event):
        if event.type() == QEvent.HoverLeave:
            self.hovered = False
            self.repaint(self.rect())
            return True
        return False

    def createMenu(self, items):
        self.panelMenu = QMenu(self)
        for item in items:
            self.panelMenu.addAction(item)

        self.panelMenu.addSeparator()
        self.panelMenu.addAction('Close Tab')
        self.panelMenu.aboutToHide.connect(lambda: self.menuAboutToHide())

        return self.panelMenu

    def contextMenuEvent(self, event):
        pos = event.pos()
        if self.panelMenu and self.menuRect.contains(pos):
            self.panelMenu.exec_(self.mapToGlobal(pos))
            event.accept()

    def menuAboutToHide(self):
        self.hovered = False
        self.repaint(self.menuRect.adjusted(-1, -1, 1, 1))
Beispiel #19
0
class corkDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        QStyledItemDelegate.__init__(self, parent)
        self.factor = settings.corkSizeFactor / 100.
        self.lastPos = None
        self.editing = None
        self.margin = 5

        self.bgColors = {}

    def newStyle(self):
        return settings.corkStyle == "new"

    def setCorkSizeFactor(self, v):
        self.factor = v / 100.

    def sizeHint(self, option, index):
        if self.newStyle():
            defaultSize = QSize(300, 210)
        else:
            defaultSize = QSize(300, 200)
        return defaultSize * self.factor

    def editorEvent(self, event, model, option, index):
        # We catch the mouse position in the widget to know which part to edit
        if type(event) == QMouseEvent:
            self.lastPos = event.pos()  # - option.rect.topLeft()
        return QStyledItemDelegate.editorEvent(self, event, model, option,
                                               index)

    def createEditor(self, parent, option, index):
        # When the user performs a global search and selects an Outline result (title or summary), the
        # associated chapter is selected in cork view, triggering a call to this method with the results
        # list widget set in self.sender(). In this case we store the searched column so we know which
        # editor should be created.
        searchedColumn = None
        if self.sender() is not None and self.sender().objectName(
        ) == 'result' and self.sender().currentItem():
            searchedColumn = self.sender().currentItem().data(
                Qt.UserRole).column()

        self.updateRects(option, index)

        bgColor = self.bgColors.get(index, "white")

        if searchedColumn == Outline.summarySentence or (
                self.lastPos is not None
                and self.mainLineRect.contains(self.lastPos)):
            # One line summary
            self.editing = Outline.summarySentence
            edt = QLineEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrame(False)
            f = QFont(option.font)
            if self.newStyle():
                f.setBold(True)
            else:
                f.setItalic(True)
                edt.setAlignment(Qt.AlignCenter)
            edt.setPlaceholderText(self.tr("One line summary"))
            edt.setFont(f)
            edt.setStyleSheet("background: {}; color: black;".format(bgColor))
            return edt

        elif searchedColumn == Outline.title or (self.lastPos is not None
                                                 and self.titleRect.contains(
                                                     self.lastPos)):
            # Title
            self.editing = Outline.title
            edt = QLineEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrame(False)
            f = QFont(option.font)
            if self.newStyle():
                f.setPointSize(f.pointSize() + 4)
            else:
                edt.setAlignment(Qt.AlignCenter)
            f.setBold(True)
            edt.setFont(f)
            edt.setStyleSheet("background: {}; color: black;".format(bgColor))
            # edt.setGeometry(self.titleRect)
            return edt

        else:  # self.mainTextRect.contains(self.lastPos):
            # Summary
            self.editing = Outline.summaryFull
            edt = QPlainTextEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrameShape(QFrame.NoFrame)
            try:
                # QPlainTextEdit.setPlaceholderText was introduced in Qt 5.3
                edt.setPlaceholderText(self.tr("Full summary"))
            except AttributeError:
                pass
            edt.setStyleSheet("background: {}; color: black;".format(bgColor))
            return edt

    def updateEditorGeometry(self, editor, option, index):

        if self.editing == Outline.summarySentence:
            # One line summary
            editor.setGeometry(self.mainLineRect)

        elif self.editing == Outline.title:
            # Title
            editor.setGeometry(self.titleRect)

        elif self.editing == Outline.summaryFull:
            # Summary
            editor.setGeometry(self.mainTextRect)

    def setEditorData(self, editor, index):
        item = index.internalPointer()

        if self.editing == Outline.summarySentence:
            # One line summary
            editor.setText(item.data(Outline.summarySentence))

        elif self.editing == Outline.title:
            # Title
            editor.setText(index.data())

        elif self.editing == Outline.summaryFull:
            # Summary
            editor.setPlainText(item.data(Outline.summaryFull))

    def setModelData(self, editor, model, index):

        if self.editing == Outline.summarySentence:
            # One line summary
            model.setData(index.sibling(index.row(), Outline.summarySentence),
                          editor.text())

        elif self.editing == Outline.title:
            # Title
            model.setData(index, editor.text(), Outline.title)

        elif self.editing == Outline.summaryFull:
            # Summary
            model.setData(index.sibling(index.row(), Outline.summaryFull),
                          editor.toPlainText())

    def updateRects(self, option, index):
        if self.newStyle():
            self.updateRects_v2(option, index)
        else:
            self.updateRects_v1(option, index)

    def updateRects_v2(self, option, index):
        margin = self.margin * 2
        iconSize = max(24 * self.factor, 18)
        item = index.internalPointer()
        fm = QFontMetrics(option.font)
        h = fm.lineSpacing()

        self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin)

        top = 15 * self.factor
        self.topRect = QRect(self.itemRect)
        self.topRect.setHeight(top)

        self.cardRect = QRect(self.itemRect.topLeft() + QPoint(0, top),
                              self.itemRect.bottomRight())
        self.iconRect = QRect(self.cardRect.topLeft() + QPoint(margin, margin),
                              QSize(iconSize, iconSize))
        self.labelRect = QRect(
            self.cardRect.topRight() - QPoint(margin + self.factor * 18, 1),
            self.cardRect.topRight() +
            QPoint(-margin - self.factor * 4, self.factor * 24))
        self.titleRect = QRect(
            self.iconRect.topRight() + QPoint(margin, 0),
            self.labelRect.bottomLeft() - QPoint(margin, margin))
        self.titleRect.setBottom(self.iconRect.bottom())
        self.mainRect = QRect(
            self.iconRect.bottomLeft() + QPoint(0, margin),
            self.cardRect.bottomRight() - QPoint(margin, 2 * margin))
        self.mainRect.setLeft(self.titleRect.left())
        self.mainLineRect = QRect(self.mainRect.topLeft(),
                                  self.mainRect.topRight() + QPoint(0, h))
        self.mainTextRect = QRect(
            self.mainLineRect.bottomLeft() + QPoint(0, margin),
            self.mainRect.bottomRight())
        if not item.data(Outline.summarySentence):
            self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())

    def updateRects_v1(self, option, index):
        margin = self.margin
        iconSize = max(16 * self.factor, 12)
        item = index.internalPointer()
        self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin)
        self.iconRect = QRect(self.itemRect.topLeft() + QPoint(margin, margin),
                              QSize(iconSize, iconSize))
        self.labelRect = QRect(
            self.itemRect.topRight() - QPoint(iconSize + margin, 0),
            self.itemRect.topRight() + QPoint(0, iconSize + 2 * margin))
        self.titleRect = QRect(
            self.iconRect.topRight() + QPoint(margin, 0),
            self.labelRect.bottomLeft() - QPoint(margin, margin))
        self.bottomRect = QRect(
            QPoint(self.itemRect.x(),
                   self.iconRect.bottom() + margin),
            QPoint(self.itemRect.right(), self.itemRect.bottom()))
        self.topRect = QRect(self.itemRect.topLeft(),
                             self.bottomRect.topRight())
        self.mainRect = self.bottomRect.adjusted(margin, margin, -margin,
                                                 -margin)
        self.mainLineRect = QRect(
            self.mainRect.topLeft(),
            self.mainRect.topRight() + QPoint(0, iconSize))
        self.mainTextRect = QRect(
            self.mainLineRect.bottomLeft() + QPoint(0, margin),
            self.mainRect.bottomRight())
        if not item.data(Outline.summarySentence):
            self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())
        if item.data(Outline.label) in ["", "0", 0]:
            self.titleRect.setBottomRight(self.labelRect.bottomRight() -
                                          QPoint(self.margin, self.margin))

    def paint(self, p, option, index):
        if self.newStyle():
            self.paint_v2(p, option, index)
        else:
            self.paint_v1(p, option, index)

    def paint_v2(self, p, option, index):
        # QStyledItemDelegate.paint(self, p, option, index)
        if not index.isValid():
            return

        item = index.internalPointer()
        self.updateRects(option, index)
        colors = outlineItemColors(item)

        style = qApp.style()

        def _rotate(angle, rect=self.mainRect):
            p.translate(rect.center())
            p.rotate(angle)
            p.translate(-rect.center())

        def drawRect(r):
            p.save()
            p.setBrush(Qt.gray)
            p.drawRect(r)
            p.restore()

        # Draw background
        cg = QPalette.ColorGroup(QPalette.Normal if option.state
                                 & QStyle.State_Enabled else QPalette.Disabled)
        if cg == QPalette.Normal and not option.state & QStyle.State_Active:
            cg = QPalette.Inactive

            # Selection
        if option.state & QStyle.State_Selected:
            p.save()
            p.setBrush(option.palette.brush(cg, QPalette.Highlight))
            p.setPen(Qt.NoPen)
            #p.drawRoundedRect(option.rect, 12, 12)
            p.drawRect(option.rect)
            p.restore()

            # Background
        p.save()
        if settings.viewSettings["Cork"]["Background"] != "Nothing":
            c = colors[settings.viewSettings["Cork"]["Background"]]
            if c == QColor(Qt.transparent):
                c = QColor(Qt.white)
            col = mixColors(c, QColor(Qt.white), .2)
            backgroundColor = col
            p.setBrush(col)
        else:
            p.setBrush(Qt.white)
            backgroundColor = QColor(Qt.white)

            # Cache background color
        self.bgColors[index] = backgroundColor.name()

        p.setPen(Qt.NoPen)
        p.drawRect(self.cardRect)
        if item.isFolder():
            itemPoly = QPolygonF([
                self.topRect.topLeft(),
                self.topRect.topLeft() + QPoint(self.topRect.width() * .35, 0),
                self.cardRect.topLeft() +
                QPoint(self.topRect.width() * .45, 0),
                self.cardRect.topRight(),
                self.cardRect.bottomRight(),
                self.cardRect.bottomLeft()
            ])
            p.drawPolygon(itemPoly)
        p.restore()

        # Label color
        if settings.viewSettings["Cork"]["Corner"] != "Nothing":
            p.save()
            color = colors[settings.viewSettings["Cork"]["Corner"]]
            p.setPen(Qt.NoPen)
            p.setBrush(color)
            p.drawRect(self.labelRect)
            w = self.labelRect.width()
            poly = QPolygonF([
                self.labelRect.bottomLeft() + QPointF(0, 1),
                self.labelRect.bottomLeft() + QPointF(0, w / 2),
                self.labelRect.bottomLeft() + QPointF(w / 2, 1),
                self.labelRect.bottomRight() + QPointF(1, w / 2),
                self.labelRect.bottomRight() + QPointF(1, 1),
            ])

            p.drawPolygon(poly)
            p.restore()

        if settings.viewSettings["Cork"]["Corner"] == "Nothing" or \
           color == Qt.transparent:
            # No corner, so title can be full width
            self.titleRect.setRight(self.mainRect.right())

        # Draw the icon
        iconRect = self.iconRect
        mode = QIcon.Normal
        if not option.state & style.State_Enabled:
            mode = QIcon.Disabled
        elif option.state & style.State_Selected:
            mode = QIcon.Selected
        # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode)
        icon = index.data(Qt.DecorationRole).pixmap(iconRect.size())
        if settings.viewSettings["Cork"]["Icon"] != "Nothing":
            color = colors[settings.viewSettings["Cork"]["Icon"]]
            colorifyPixmap(icon, color)
        QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode)

        # Draw title
        p.save()
        text = index.data()

        if text:
            p.setPen(Qt.black)
            textColor = QColor(Qt.black)
            if settings.viewSettings["Cork"]["Text"] != "Nothing":
                col = colors[settings.viewSettings["Cork"]["Text"]]
                if col == Qt.transparent:
                    col = Qt.black

                # If title setting is compile, we have to hack the color
                # Or we won't see anything in some themes
                if settings.viewSettings["Cork"]["Text"] == "Compile":
                    if item.compile() in [0, "0"]:
                        col = mixColors(QColor(Qt.black), backgroundColor)
                    else:
                        col = Qt.black
                textColor = col
                p.setPen(col)
            f = QFont(option.font)
            f.setPointSize(f.pointSize() + 4)
            f.setBold(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(text, Qt.ElideRight,
                                       self.titleRect.width())
            p.drawText(self.titleRect, Qt.AlignLeft | Qt.AlignVCenter,
                       elidedText)
        p.restore()

        # One line summary background
        lineSummary = item.data(Outline.summarySentence)
        fullSummary = item.data(Outline.summaryFull)

        # Border
        if settings.viewSettings["Cork"]["Border"] != "Nothing":
            p.save()
            p.setBrush(Qt.NoBrush)
            pen = p.pen()
            pen.setWidth(2)
            col = colors[settings.viewSettings["Cork"]["Border"]]
            pen.setColor(col)
            p.setPen(pen)
            if item.isFolder():
                p.drawPolygon(itemPoly)
            else:
                p.drawRect(self.cardRect)
            p.restore()

        # Draw status
        status = item.data(Outline.status)
        if status:
            it = mainWindow().mdlStatus.item(int(status), 0)
            if it != None:
                p.save()
                p.setClipRegion(QRegion(self.cardRect))
                f = p.font()
                f.setPointSize(f.pointSize() + 12)
                f.setBold(True)
                p.setFont(f)
                p.setPen(QColor(Qt.red).lighter(170))
                _rotate(-35, rect=self.cardRect)
                p.drawText(self.cardRect, Qt.AlignCenter, it.text())
                p.restore()

                # Draw Summary
                # One line
        if lineSummary:
            p.save()
            f = QFont(option.font)
            f.setBold(True)
            p.setFont(f)
            p.setPen(textColor)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(lineSummary, Qt.ElideRight,
                                       self.mainLineRect.width())
            p.drawText(self.mainLineRect, Qt.AlignLeft | Qt.AlignVCenter,
                       elidedText)
            p.restore()

            # Full summary
        if fullSummary:
            p.save()
            p.setFont(option.font)
            p.setPen(textColor)
            p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)
            p.restore()

    def paint_v1(self, p, option, index):
        # QStyledItemDelegate.paint(self, p, option, index)
        if not index.isValid():
            return

        item = index.internalPointer()
        self.updateRects(option, index)
        colors = outlineItemColors(item)

        style = qApp.style()

        def _rotate(angle):
            p.translate(self.mainRect.center())
            p.rotate(angle)
            p.translate(-self.mainRect.center())

        # Draw background
        cg = QPalette.ColorGroup(QPalette.Normal if option.state
                                 & QStyle.State_Enabled else QPalette.Disabled)
        if cg == QPalette.Normal and not option.state & QStyle.State_Active:
            cg = QPalette.Inactive

            # Selection
        if option.state & QStyle.State_Selected:
            p.save()
            p.setBrush(option.palette.brush(cg, QPalette.Highlight))
            p.setPen(Qt.NoPen)
            p.drawRoundedRect(option.rect, 12, 12)
            p.restore()

            # Stack
        if item.isFolder() and item.childCount() > 0:
            p.save()
            p.setBrush(Qt.white)
            for i in reversed(range(3)):
                p.drawRoundedRect(
                    self.itemRect.adjusted(2 * i, 2 * i, -2 * i, 2 * i), 10,
                    10)

            p.restore()

            # Background
        itemRect = self.itemRect
        p.save()
        if settings.viewSettings["Cork"]["Background"] != "Nothing":
            c = colors[settings.viewSettings["Cork"]["Background"]]
            col = mixColors(c, QColor(Qt.white), .2)
            p.setBrush(col)
        else:
            p.setBrush(Qt.white)
        pen = p.pen()
        pen.setWidth(2)
        p.setPen(pen)
        p.drawRoundedRect(itemRect, 10, 10)
        p.restore()

        # Title bar
        topRect = self.topRect
        p.save()
        if item.isFolder():
            color = QColor(Qt.darkGreen)
        else:
            color = QColor(Qt.blue).lighter(175)
        p.setPen(Qt.NoPen)
        p.setBrush(color)
        p.setClipRegion(QRegion(topRect))
        p.drawRoundedRect(itemRect, 10, 10)
        # p.drawRect(topRect)
        p.restore()

        # Label color
        if settings.viewSettings["Cork"]["Corner"] != "Nothing":
            p.save()
            color = colors[settings.viewSettings["Cork"]["Corner"]]
            p.setPen(Qt.NoPen)
            p.setBrush(color)
            p.setClipRegion(QRegion(self.labelRect))
            p.drawRoundedRect(itemRect, 10, 10)
            # p.drawRect(topRect)
            p.restore()
            if color != Qt.transparent:
                p.drawLine(self.labelRect.topLeft(),
                           self.labelRect.bottomLeft())

            # One line summary background
        lineSummary = item.data(Outline.summarySentence)
        fullSummary = item.data(Outline.summaryFull)
        if lineSummary or not fullSummary:
            m = self.margin
            r = self.mainLineRect.adjusted(-m, -m, m, m / 2)
            p.save()
            p.setPen(Qt.NoPen)
            p.setBrush(QColor("#EEE"))
            p.drawRect(r)
            p.restore()

            # Border
        p.save()
        p.setBrush(Qt.NoBrush)
        pen = p.pen()
        pen.setWidth(2)
        if settings.viewSettings["Cork"]["Border"] != "Nothing":
            col = colors[settings.viewSettings["Cork"]["Border"]]
            if col == Qt.transparent:
                col = Qt.black
            pen.setColor(col)
        p.setPen(pen)
        p.drawRoundedRect(itemRect, 10, 10)
        p.restore()

        # Draw the icon
        iconRect = self.iconRect
        mode = QIcon.Normal
        if not option.state & style.State_Enabled:
            mode = QIcon.Disabled
        elif option.state & style.State_Selected:
            mode = QIcon.Selected
        # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode)
        icon = index.data(Qt.DecorationRole).pixmap(iconRect.size())
        if settings.viewSettings["Cork"]["Icon"] != "Nothing":
            color = colors[settings.viewSettings["Cork"]["Icon"]]
            colorifyPixmap(icon, color)
        QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode)

        # Draw title
        p.save()
        text = index.data()
        titleRect = self.titleRect
        if text:
            if settings.viewSettings["Cork"]["Text"] != "Nothing":
                col = colors[settings.viewSettings["Cork"]["Text"]]
                if col == Qt.transparent:
                    col = Qt.black
                p.setPen(col)
            f = QFont(option.font)
            # f.setPointSize(f.pointSize() + 1)
            f.setBold(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(text, Qt.ElideRight, titleRect.width())
            p.drawText(titleRect, Qt.AlignCenter, elidedText)
        p.restore()

        # Draw the line
        bottomRect = self.bottomRect
        p.save()
        # p.drawLine(itemRect.x(), iconRect.bottom() + margin,
        # itemRect.right(), iconRect.bottom() + margin)
        p.drawLine(bottomRect.topLeft(), bottomRect.topRight())
        p.restore()

        # Lines
        if True:
            p.save()
            p.setPen(QColor("#EEE"))
            fm = QFontMetrics(option.font)
            h = fm.lineSpacing()
            l = self.mainTextRect.topLeft() + QPoint(0, h)
            while self.mainTextRect.contains(l):
                p.drawLine(l, QPoint(self.mainTextRect.right(), l.y()))
                l.setY(l.y() + h)
            p.restore()

        # Draw status
        mainRect = self.mainRect
        status = item.data(Outline.status)
        if status:
            it = mainWindow().mdlStatus.item(int(status), 0)
            if it != None:
                p.save()
                p.setClipRegion(QRegion(mainRect))
                f = p.font()
                f.setPointSize(f.pointSize() + 12)
                f.setBold(True)
                p.setFont(f)
                p.setPen(QColor(Qt.red).lighter(175))
                _rotate(-35)
                p.drawText(mainRect, Qt.AlignCenter, it.text())
                p.restore()

                # Draw Summary
                # One line
        if lineSummary:
            p.save()
            f = QFont(option.font)
            f.setItalic(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(lineSummary, Qt.ElideRight,
                                       self.mainLineRect.width())
            p.drawText(self.mainLineRect, Qt.AlignCenter, elidedText)
            p.restore()

            # Full summary
        if fullSummary:
            p.setFont(option.font)
            p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)
Beispiel #20
0
class SlippyMap(QObject):

    updated = pyqtSignal(QRect)

    def __init__(self, parent=None):
        super(SlippyMap, self).__init__(parent)

        self._offset = QPoint()
        self._tilesRect = QRect()
        self._tilePixmaps = {} # Point(x, y) to QPixmap mapping
        self._manager = QNetworkAccessManager()
        self._url = QUrl()
        # public vars
        self.width = 400
        self.height = 300
        self.zoom = 15
        self.latitude = 59.9138204
        self.longitude = 10.7387413

        self._emptyTile = QPixmap(TDIM, TDIM)
        self._emptyTile.fill(Qt.lightGray)

        cache = QNetworkDiskCache()
        cache.setCacheDirectory(
            QStandardPaths.writableLocation(QStandardPaths.CacheLocation))
        self._manager.setCache(cache)
        self._manager.finished.connect(self.handleNetworkData)

    def invalidate(self):
        if self.width <= 0 or self.height <= 0:
            return

        ct = tileForCoordinate(self.latitude, self.longitude, self.zoom)
        tx = ct.x()
        ty = ct.y()

        # top-left corner of the center tile
        xp = int(self.width / 2 - (tx - math.floor(tx)) * TDIM)
        yp = int(self.height / 2 - (ty - math.floor(ty)) * TDIM)

        # first tile vertical and horizontal
        xa = (xp + TDIM - 1) / TDIM
        ya = (yp + TDIM - 1) / TDIM
        xs = int(tx) - xa
        ys = int(ty) - ya

        # offset for top-left tile
        self._offset = QPoint(xp - xa * TDIM, yp - ya * TDIM)

        # last tile vertical and horizontal
        xe = int(tx) + (self.width - xp - 1) / TDIM
        ye = int(ty) + (self.height - yp - 1) / TDIM

        # build a rect
        self._tilesRect = QRect(xs, ys, xe - xs + 1, ye - ys + 1)

        if self._url.isEmpty():
            self.download()

        self.updated.emit(QRect(0, 0, self.width, self.height))

    def render(self, p, rect):
        for x in range(self._tilesRect.width()):
            for y in range(self._tilesRect.height()):
                tp = Point(x + self._tilesRect.left(), y + self._tilesRect.top())
                box = self.tileRect(tp)
                if rect.intersects(box):
                    p.drawPixmap(box, self._tilePixmaps.get(tp, self._emptyTile))
   
    def pan(self, delta):
        dx = QPointF(delta) / float(TDIM)
        center = tileForCoordinate(self.latitude, self.longitude, self.zoom) - dx
        self.latitude = latitudeFromTile(center.y(), self.zoom)
        self.longitude = longitudeFromTile(center.x(), self.zoom)
        self.invalidate()

    # slots
    def handleNetworkData(self, reply):
        img = QImage()
        tp = Point(reply.request().attribute(QNetworkRequest.User))
        url = reply.url()
        if not reply.error():
            if img.load(reply, None):
                self._tilePixmaps[tp] = QPixmap.fromImage(img)
        reply.deleteLater()
        self.updated.emit(self.tileRect(tp))

        # purge unused tiles
        bound = self._tilesRect.adjusted(-2, -2, 2, 2)
        for tp in list(self._tilePixmaps.keys()):
            if not bound.contains(tp):
                del self._tilePixmaps[tp]
        self.download()

    def download(self):
        grab = None
        for x in range(self._tilesRect.width()):
            for y in range(self._tilesRect.height()):
                tp = Point(self._tilesRect.topLeft() + QPoint(x, y))
                if tp not in self._tilePixmaps:
                    grab = QPoint(tp)
                    break

        if grab is None:
            self._url = QUrl()
            return

        path = 'http://tile.openstreetmap.org/%d/%d/%d.png' % (self.zoom, grab.x(), grab.y())
        self._url = QUrl(path)
        request = QNetworkRequest()
        request.setUrl(self._url)
        request.setRawHeader(b'User-Agent', b'Nokia (PyQt) Graphics Dojo 1.0')
        request.setAttribute(QNetworkRequest.User, grab)
        self._manager.get(request)

    def tileRect(self, tp):
        t = tp - self._tilesRect.topLeft()
        x = t.x() * TDIM + self._offset.x()
        y = t.y() * TDIM + self._offset.y()

        return QRect(x, y, TDIM, TDIM)
Beispiel #21
0
	def paintMarkedRegions(self, evt):
		"""Draw the marked region indicators."""
		
		def f2px(frameNumber):
			"""Convert frame number to pixel coordinates."""
			return round(frameNumber / self.totalRecordedFrames * (self.uiMarkedRegionVisualization.width()-1))
		
		if not self.totalRecordedFrames:
			return
		
		p = QPainter(self.uiMarkedRegionVisualization)
		
		#This causes borders to get merged and generally mis-drawn.
		#Could otherwise be used to simplify math when calculating rect position.
		#p.setCompositionMode(QPainter.CompositionMode_DestinationOver)
		
		#This causes graphics glitches in 5.7 upon redraw.
		#Could otherwise be used to simplify math when calculating rect position.
		#p.scale(1,-1)
		#p.translate(0, -evt.rect().height()+1)
		
		#Draw the tracks of marked regions.
		trackOffset = -1
		for track in reversed(self._tracks):
			for region in track:
				regionRect = QRect(
					f2px(region['mark start']),
					trackOffset + self.saveRegionBorder,
					f2px(region['mark end'] - region['mark start']),
					self.saveRegionMarkerHeight,
				)
				
				if region['saved'] < 1: #Draw coloured, unsaved marked region.
					p.setPen(hsva(
						region['hue'],
						{-1:150, 0:230, 1:255}[region['highlight']],
						{-1:160, 0:190, 1:100}[region['highlight']],
					))
					p.setBrush(QBrush(hsva(
						region['hue'], 
						{-1:0, 0:153, 1:255}[region['highlight']], 
						{-1:0, 0:230, 1:255}[region['highlight']],
					)))
					p.setClipRect(regionRect.adjusted(regionRect.width() * region['saved'],0, 0,0))
					p.drawRect(regionRect)
				
				if region['saved'] > 0: #Draw green, saved marked region.
					p.setPen(hsva(
						120, #green
						{-1:150, 0:230, 1:255}[region['highlight']],
						{-1:160, 0:190, 1:100}[region['highlight']],
					))
					p.setBrush(QBrush(hsva(
						120, 
						{-1:0, 0:153, 1:255}[region['highlight']], 
						{-1:0, 0:230, 1:255}[region['highlight']],
					)))
					p.setClipRect(regionRect.adjusted(0,0, -regionRect.width() * (1-region['saved']),0))
					p.drawRect(regionRect)
			
			trackOffset += self.saveRegionMarkerOffset
Beispiel #22
0
class PuzzleWidget(QWidget):

    puzzleCompleted = pyqtSignal()

    def __init__(self, parent=None):
        super(PuzzleWidget, self).__init__(parent)

        self.piecePixmaps = []
        self.pieceRects = []
        self.pieceLocations = []
        self.highlightedRect = QRect()
        self.inPlace = 0

        self.setAcceptDrops(True)
        self.setMinimumSize(400, 400)
        self.setMaximumSize(400, 400)

    def clear(self):
        self.pieceLocations = []
        self.piecePixmaps = []
        self.pieceRects = []
        self.highlightedRect = QRect()
        self.inPlace = 0
        self.update()

    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat('image/x-puzzle-piece'):
            event.accept()
        else:
            event.ignore()

    def dragLeaveEvent(self, event):
        updateRect = self.highlightedRect
        self.highlightedRect = QRect()
        self.update(updateRect)
        event.accept()

    def dragMoveEvent(self, event):
        updateRect = self.highlightedRect.united(self.targetSquare(event.pos()))

        if event.mimeData().hasFormat('image/x-puzzle-piece') and self.findPiece(self.targetSquare(event.pos())) == -1:
            self.highlightedRect = self.targetSquare(event.pos())
            event.setDropAction(Qt.MoveAction)
            event.accept()
        else:
            self.highlightedRect = QRect()
            event.ignore()

        self.update(updateRect)

    def dropEvent(self, event):
        if event.mimeData().hasFormat('image/x-puzzle-piece') and self.findPiece(self.targetSquare(event.pos())) == -1:
            pieceData = event.mimeData().data('image/x-puzzle-piece')
            dataStream = QDataStream(pieceData, QIODevice.ReadOnly)
            square = self.targetSquare(event.pos())
            pixmap = QPixmap()
            location = QPoint()
            dataStream >> pixmap >> location

            self.pieceLocations.append(location)
            self.piecePixmaps.append(pixmap)
            self.pieceRects.append(square)

            self.hightlightedRect = QRect()
            self.update(square)

            event.setDropAction(Qt.MoveAction)
            event.accept()

            if location == QPoint(square.x() / 80, square.y() / 80):
                self.inPlace += 1
                if self.inPlace == 25:
                    self.puzzleCompleted.emit()
        else:
            self.highlightedRect = QRect()
            event.ignore()

    def findPiece(self, pieceRect):
        try:
            return self.pieceRects.index(pieceRect)
        except ValueError:
            return -1

    def mousePressEvent(self, event):
        square = self.targetSquare(event.pos())
        found = self.findPiece(square)

        if found == -1:
            return

        location = self.pieceLocations[found]
        pixmap = self.piecePixmaps[found]
        del self.pieceLocations[found]
        del self.piecePixmaps[found]
        del self.pieceRects[found]

        if location == QPoint(square.x() / 80, square.y() / 80):
            self.inPlace -= 1

        self.update(square)

        itemData = QByteArray()
        dataStream = QDataStream(itemData, QIODevice.WriteOnly)

        dataStream << pixmap << location

        mimeData = QMimeData()
        mimeData.setData('image/x-puzzle-piece', itemData)

        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(event.pos() - square.topLeft())
        drag.setPixmap(pixmap)

        if drag.exec_(Qt.MoveAction) != Qt.MoveAction:
            self.pieceLocations.insert(found, location)
            self.piecePixmaps.insert(found, pixmap)
            self.pieceRects.insert(found, square)
            self.update(self.targetSquare(event.pos()))

            if location == QPoint(square.x() / 80, square.y() / 80):
                self.inPlace += 1

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

        if self.highlightedRect.isValid():
            painter.setBrush(QColor("#ffcccc"))
            painter.setPen(Qt.NoPen)
            painter.drawRect(self.highlightedRect.adjusted(0, 0, -1, -1))

        for rect, pixmap in zip(self.pieceRects, self.piecePixmaps):
            painter.drawPixmap(rect, pixmap)

        painter.end()

    def targetSquare(self, position):
        return QRect(position.x() // 80 * 80, position.y() // 80 * 80, 80, 80)
class SnapshotFreehandGrabber(QWidget):
    """
    Class implementing a grabber widget for a freehand snapshot region.
    
    @signal grabbed(QPixmap) emitted after the region was grabbed
    """
    grabbed = pyqtSignal(QPixmap)
    
    def __init__(self):
        """
        Constructor
        """
        super(SnapshotFreehandGrabber, self).__init__(
            None,
            Qt.X11BypassWindowManagerHint | Qt.WindowStaysOnTopHint |
            Qt.FramelessWindowHint | Qt.Tool)
        
        self.__selection = QPolygon()
        self.__mouseDown = False
        self.__newSelection = False
        self.__handleSize = 10
        self.__showHelp = True
        self.__grabbing = False
        self.__dragStartPoint = QPoint()
        self.__selectionBeforeDrag = QPolygon()
        self.__locale = QLocale()
        
        self.__helpTextRect = QRect()
        self.__helpText = self.tr(
            "Select a region using the mouse. To take the snapshot,"
            " press the Enter key or double click. Press Esc to quit.")
        
        self.__pixmap = QPixmap()
        self.__pBefore = QPoint()
        
        self.setMouseTracking(True)
        
        QTimer.singleShot(200, self.__initialize)
    
    def __initialize(self):
        """
        Private slot to initialize the rest of the widget.
        """
        self.__desktop = QApplication.desktop()
        x = self.__desktop.x()
        y = self.__desktop.y()
        if qVersion() >= "5.0.0":
            self.__pixmap = QApplication.screens()[0].grabWindow(
                self.__desktop.winId(), x, y,
                self.__desktop.width(), self.__desktop.height())
        else:
            self.__pixmap = QPixmap.grabWindow(
                self.__desktop.winId(), x, y,
                self.__desktop.width(), self.__desktop.height())
        self.resize(self.__pixmap.size())
        self.move(x, y)
        self.setCursor(Qt.CrossCursor)
        self.show()

        self.grabMouse()
        self.grabKeyboard()
        self.activateWindow()
    
    def paintEvent(self, evt):
        """
        Protected method handling paint events.
        
        @param evt paint event (QPaintEvent)
        """
        if self.__grabbing:     # grabWindow() should just get the background
            return
        
        painter = QPainter(self)
        pal = QPalette(QToolTip.palette())
        font = QToolTip.font()
        
        handleColor = pal.color(QPalette.Active, QPalette.Highlight)
        handleColor.setAlpha(160)
        overlayColor = QColor(0, 0, 0, 160)
        textColor = pal.color(QPalette.Active, QPalette.Text)
        textBackgroundColor = pal.color(QPalette.Active, QPalette.Base)
        painter.drawPixmap(0, 0, self.__pixmap)
        painter.setFont(font)
        
        pol = QPolygon(self.__selection)
        if not self.__selection.boundingRect().isNull():
            # Draw outline around selection.
            # Important: the 1px-wide outline is *also* part of the
            # captured free-region
            pen = QPen(handleColor, 1, Qt.SolidLine, Qt.SquareCap,
                       Qt.BevelJoin)
            painter.setPen(pen)
            painter.drawPolygon(pol)
            
            # Draw the grey area around the selection.
            grey = QRegion(self.rect())
            grey = grey - QRegion(pol)
            painter.setClipRegion(grey)
            painter.setPen(Qt.NoPen)
            painter.setBrush(overlayColor)
            painter.drawRect(self.rect())
            painter.setClipRect(self.rect())
            drawPolygon(painter, pol, handleColor)
        
        if self.__showHelp:
            painter.setPen(textColor)
            painter.setBrush(textBackgroundColor)
            self.__helpTextRect = painter.boundingRect(
                self.rect().adjusted(2, 2, -2, -2),
                Qt.TextWordWrap, self.__helpText).translated(
                -self.__desktop.x(), -self.__desktop.y())
            self.__helpTextRect.adjust(-2, -2, 4, 2)
            drawPolygon(painter, self.__helpTextRect, textColor,
                        textBackgroundColor)
            painter.drawText(
                self.__helpTextRect.adjusted(3, 3, -3, -3),
                Qt.TextWordWrap, self.__helpText)
        
        if self.__selection.isEmpty():
            return
        
        # The grabbed region is everything which is covered by the drawn
        # rectangles (border included). This means that there is no 0px
        # selection, since a 0px wide rectangle will always be drawn as a line.
        boundingRect = self.__selection.boundingRect()
        txt = "{0}, {1} ({2} x {3})".format(
            self.__locale.toString(boundingRect.x()),
            self.__locale.toString(boundingRect.y()),
            self.__locale.toString(boundingRect.width()),
            self.__locale.toString(boundingRect.height())
        )
        textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt)
        boundingRect = textRect.adjusted(-4, 0, 0, 0)
        
        polBoundingRect = pol.boundingRect()
        if (textRect.width() <
            polBoundingRect.width() - 2 * self.__handleSize) and \
           (textRect.height() <
            polBoundingRect.height() - 2 * self.__handleSize) and \
           polBoundingRect.width() > 100 and \
           polBoundingRect.height() > 100:
            # center, unsuitable for small selections
            boundingRect.moveCenter(polBoundingRect.center())
            textRect.moveCenter(polBoundingRect.center())
        elif polBoundingRect.y() - 3 > textRect.height() and \
                polBoundingRect.x() + textRect.width() < self.rect().width():
            # on top, left aligned
            boundingRect.moveBottomLeft(
                QPoint(polBoundingRect.x(), polBoundingRect.y() - 3))
            textRect.moveBottomLeft(
                QPoint(polBoundingRect.x() + 2, polBoundingRect.y() - 3))
        elif polBoundingRect.x() - 3 > textRect.width():
            # left, top aligned
            boundingRect.moveTopRight(
                QPoint(polBoundingRect.x() - 3, polBoundingRect.y()))
            textRect.moveTopRight(
                QPoint(polBoundingRect.x() - 5, polBoundingRect.y()))
        elif (polBoundingRect.bottom() + 3 + textRect.height() <
              self.rect().bottom()) and \
                polBoundingRect.right() > textRect.width():
            # at bottom, right aligned
            boundingRect.moveTopRight(
                QPoint(polBoundingRect.right(), polBoundingRect.bottom() + 3))
            textRect.moveTopRight(
                QPoint(polBoundingRect.right() - 2,
                       polBoundingRect.bottom() + 3))
        elif polBoundingRect.right() + textRect.width() + 3 < \
                self.rect().width():
            # right, bottom aligned
            boundingRect.moveBottomLeft(
                QPoint(polBoundingRect.right() + 3, polBoundingRect.bottom()))
            textRect.moveBottomLeft(
                QPoint(polBoundingRect.right() + 5, polBoundingRect.bottom()))
        
        # If the above didn't catch it, you are running on a very
        # tiny screen...
        drawPolygon(painter, boundingRect, textColor, textBackgroundColor)
        painter.drawText(textRect, Qt.AlignHCenter, txt)
        
        if (polBoundingRect.height() > self.__handleSize * 2 and
            polBoundingRect.width() > self.__handleSize * 2) or \
           not self.__mouseDown:
            painter.setBrush(Qt.transparent)
            painter.setClipRegion(QRegion(pol))
            painter.drawPolygon(QPolygon(self.rect()))
    
    def mousePressEvent(self, evt):
        """
        Protected method to handle mouse button presses.
        
        @param evt mouse press event (QMouseEvent)
        """
        self.__pBefore = evt.pos()
        
        self.__showHelp = not self.__helpTextRect.contains(evt.pos())
        if evt.button() == Qt.LeftButton:
            self.__mouseDown = True
            self.__dragStartPoint = evt.pos()
            self.__selectionBeforeDrag = QPolygon(self.__selection)
            if not self.__selection.containsPoint(evt.pos(), Qt.WindingFill):
                self.__newSelection = True
                self.__selection = QPolygon()
            else:
                self.setCursor(Qt.ClosedHandCursor)
        elif evt.button() == Qt.RightButton:
            self.__newSelection = False
            self.__selection = QPolygon()
            self.setCursor(Qt.CrossCursor)
        self.update()
    
    def mouseMoveEvent(self, evt):
        """
        Protected method to handle mouse movements.
        
        @param evt mouse move event (QMouseEvent)
        """
        shouldShowHelp = not self.__helpTextRect.contains(evt.pos())
        if shouldShowHelp != self.__showHelp:
            self.__showHelp = shouldShowHelp
            self.update()
        
        if self.__mouseDown:
            if self.__newSelection:
                p = evt.pos()
                self.__selection.append(p)
            else:
                # moving the whole selection
                p = evt.pos() - self.__pBefore  # Offset
                self.__pBefore = evt.pos()  # save position for next iteration
                self.__selection.translate(p)
            
            self.update()
        else:
            if self.__selection.boundingRect().isEmpty():
                return
            
            if self.__selection.containsPoint(evt.pos(), Qt.WindingFill):
                self.setCursor(Qt.OpenHandCursor)
            else:
                self.setCursor(Qt.CrossCursor)
    
    def mouseReleaseEvent(self, evt):
        """
        Protected method to handle mouse button releases.
        
        @param evt mouse release event (QMouseEvent)
        """
        self.__mouseDown = False
        self.__newSelection = False
        if self.__selection.containsPoint(evt.pos(), Qt.WindingFill):
            self.setCursor(Qt.OpenHandCursor)
        self.update()
    
    def mouseDoubleClickEvent(self, evt):
        """
        Protected method to handle mouse double clicks.
        
        @param evt mouse double click event (QMouseEvent)
        """
        self.__grabRegion()
    
    def keyPressEvent(self, evt):
        """
        Protected method to handle key presses.
        
        @param evt key press event (QKeyEvent)
        """
        if evt.key() == Qt.Key_Escape:
            self.grabbed.emit(QPixmap())
        elif evt.key() in [Qt.Key_Enter, Qt.Key_Return]:
            self.__grabRegion()
        else:
            evt.ignore()
    
    def __grabRegion(self):
        """
        Private method to grab the selected region (i.e. do the snapshot).
        """
        pol = QPolygon(self.__selection)
        if not pol.isEmpty():
            self.__grabbing = True
            
            xOffset = self.__pixmap.rect().x() - pol.boundingRect().x()
            yOffset = self.__pixmap.rect().y() - pol.boundingRect().y()
            translatedPol = pol.translated(xOffset, yOffset)
            
            pixmap2 = QPixmap(pol.boundingRect().size())
            pixmap2.fill(Qt.transparent)
            
            pt = QPainter()
            pt.begin(pixmap2)
            if pt.paintEngine().hasFeature(QPaintEngine.PorterDuff):
                pt.setRenderHints(
                    QPainter.Antialiasing |
                    QPainter.HighQualityAntialiasing |
                    QPainter.SmoothPixmapTransform,
                    True)
                pt.setBrush(Qt.black)
                pt.setPen(QPen(QBrush(Qt.black), 0.5))
                pt.drawPolygon(translatedPol)
                pt.setCompositionMode(QPainter.CompositionMode_SourceIn)
            else:
                pt.setClipRegion(QRegion(translatedPol))
                pt.setCompositionMode(QPainter.CompositionMode_Source)
            
            pt.drawPixmap(pixmap2.rect(), self.__pixmap, pol.boundingRect())
            pt.end()
            
            self.grabbed.emit(pixmap2)
Beispiel #24
0
class PuzzleShow(QWidget):

    '''
    拼图的合成区
    '''

    puzzleCompleted = pyqtSignal()
    dropCompleted = pyqtSignal()

    def __init__(self, imageSize):
        super().__init__()
        self.imageSize = imageSize
        # 载入图片的大小

        self.inPlace = 0
        # 位置摆放正确的拼图数量

        self.piecePixmaps = []
        # 存储从拼图展示区拖到拼图合成区的拼图

        self.pieceRects = []
        # 存储拼图放到拼图合成区的目标矩形

        self.pieceLocations = []
        # 存储从拼图展示区拖到拼图合成区的拼图的位置

        self.highlightedRect = QRect()
        # 拼图放到拼图合成区的目标矩形,以高亮形式出现

        self.initUi()

    def initUi(self):
        self.setAcceptDrops(True)
        self.setMaximumSize(self.imageSize, self.imageSize)
        self.setMinimumSize(self.imageSize, self.imageSize)

    def dragEnterEvent(self, event):
        """
        鼠标移入准备拖动
        """
        if event.mimeData().hasFormat("image/x-puzzle-xdbcb8"):
            event.accept()
        else:
            event.ignore()
        # 鼠标移入准备拖动,因为你放置的拼图不一定合适,需要再次调整放置

    def dragLeaveEvent(self, event):
        """
        鼠标移开小窗口
        """
        updateRect = self.highlightedRect
        self.highlightedRect = QRect()
        self.update(updateRect)
        event.accept()
        # 避免多了一个高亮的矩形出来

    def dragMoveEvent(self, event):
        """
        拖动
        """
        updateRect = self.highlightedRect.united(self.targetSquare(event.pos()))
        # 两个矩形的拼接

        if event.mimeData().hasFormat("image/x-puzzle-xdbcb8") and self.findPiece(self.targetSquare(event.pos())) == -1:
            self.highlightedRect = self.targetSquare(event.pos())
            # 若我们拖动时符合要求的,我们将取得一个矩形,这个矩形就是我们可以放置在拼图合成区的目标矩形,并将其赋值给self.highlightedRect
            event.setDropAction(Qt.MoveAction)
            event.accept()
        else:
            self.highlightedRect = QRect()
            event.ignore()

        self.update(updateRect)

    def dropEvent(self, event):
        """
        拖动结束,图片落下
        """
        if event.mimeData().hasFormat("image/x-puzzle-xdbcb8") and self.findPiece(self.targetSquare(event.pos())) == -1:
            # 要是我们拖动的符合要求以及没有在存储目标矩形的列表中找到的话
            pieceData = event.mimeData().data("image/x-puzzle-xdbcb8")
            dataStream = QDataStream(pieceData, QIODevice.ReadOnly)
            square = self.targetSquare(event.pos())
            pixmap = QPixmap()
            location = QPoint()
            dataStream >> pixmap >> location

            self.pieceLocations.append(location)
            self.piecePixmaps.append(pixmap)
            self.pieceRects.append(square)
            # 把拖动拼图的位置、图片、以及目标矩形分别存入self.pieceLocations、self.piecePixmaps、self.pieceRects

            self.highlightedRect = QRect()
            self.update(square)
            # 必须要有这句话,否则,哼哼!
    
            event.setDropAction(Qt.MoveAction)
            event.accept()

            if location == QPoint(square.x()/self.pieceSize(), square.y()/self.pieceSize()):
                self.inPlace += 1
                # 要是我们放置的拼图位置和正确的拼图位置是一样的,self.inPlace += 1。
                if self.inPlace == 25:
                    self.puzzleCompleted.emit()
                    # 要是正确位置的拼图达到25个,发射puzzleCompleted信号。

        else:
            self.highlightedRect = QRect()
            event.ignore()

    def mousePressEvent(self, event):
        """
        鼠标按下事件(QWidget中是没有self.setDragEnabled(True)这个属性的。故我们重写了mousePressEvent方法)
        """
        square = self.targetSquare(event.pos())
        found = self.findPiece(square)
        if found == -1:
            return
        # 先看看鼠标点击的地方有没有我们的目标矩形,没有的话直接return,有的话返回相关的索引
        location = self.pieceLocations[found]
        pixmap = self.piecePixmaps[found]
        del self.pieceLocations[found]
        del self.piecePixmaps[found]
        del self.pieceRects[found]
    
        if location == QPoint(square.x()/self.pieceSize(), square.y()/self.pieceSize()):
            self.inPlace -= 1
        # 得到位置信息、拼图信息,并把它们从相关的列表中删除,当然拼图正确的总数也要减1
        self.update(square)
    
        itemData = QByteArray()
        dataStream = QDataStream(itemData, QIODevice.WriteOnly)
    
        dataStream << pixmap << location
        # 相关的变量放入数据流中。
    
        mimeData = QMimeData()
        mimeData.setData("image/x-puzzle-xdbcb8", itemData)
    
        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(event.pos() - square.topLeft())
        drag.setPixmap(pixmap)
        # 新建一个QDrag对象,该对象中设置mimeData,HotSpot和图片信息
    
        if drag.exec(Qt.MoveAction) != Qt.MoveAction:
            self.pieceLocations.insert(found, location)
            self.piecePixmaps.insert(found, pixmap)
            self.pieceRects.insert(found, square)
            self.update(self.targetSquare(event.pos()))
    
            if location == QPoint(square.x()/self.pieceSize(), square.y()/self.pieceSize()):
                self.inPlace += 1
                # 正确的拼图数也要加上1

        # 要是drag不是拖动,那么我们给self.pieceLocations、self.piecePixmaps、self.pieceRects
        # 按照之前找到的索引增加位置、图片和目标矩形信息,相当于把之前删除掉的又加上

    def paintEvent(self, event):
        """
        绘画事件
        """
        painter = QPainter()
        painter.begin(self)
        painter.fillRect(event.rect(), Qt.white)
        if self.highlightedRect.isValid():
            painter.setBrush(QColor("#E6E6FA"))
            painter.setPen(Qt.NoPen)
            painter.drawRect(self.highlightedRect.adjusted(0, 0, -1, -1))
            # 首先绘制目标矩形
    
        for i in range(len(self.pieceRects)):
            painter.drawPixmap(self.pieceRects[i], self.piecePixmaps[i])
        painter.end()
        # 到目前矩形后,要画出来,所以就重写绘图事件

    def targetSquare(self, position):
        """
        拼图放下的矩形位置
        """
        x = position.x()//self.pieceSize() * self.pieceSize()
        y = position.y()//self.pieceSize() * self.pieceSize()
        return QRect(x, y, self.pieceSize(), self.pieceSize())
        # x、y表示的是拼图放下具体矩形位置的x、y坐标,矩形的大小是拼图的大小

    def findPiece(self, piece_Rect):
        """
        找到拼图
        """
        try:
            return self.pieceRects.index(piece_Rect)
        except ValueError:
            return -1
        # 找一找拼图合成区中的单个拼图的矩形是否已经在pieceRects列表中,有的话返回索引,没有的话返回-1。
    
    def pieceSize(self):
        """
        单个拼图的大小
        """
        return int(self.imageSize // 5)

    def clear(self):
        """
        相关数据清空。这个我们在游戏初始化的时候会用到
        """
        self.piecePixmaps.clear()
        self.pieceRects = []
        self.pieceLocations = []
        self.highlightedRect = QRect()
        self.inPlace = 0
        self.update()
class PanelTopRightCorner(QWidget):
    def __init__(self, parent):
        super(QWidget, self).__init__(parent)

        self.vSplitRect = QRect()
        self.hSplitRect = QRect()
        self.floatRect = QRect()
        self.closeRect = QRect()

        self.closeClicked = pyqtSignal()
        self.floatClicked = pyqtSignal()
        self.splitClicked = pyqtSignal()

        self.mouseHoverState = MOUSE_HOVER.HOVER_NONE
        self.mouseClickPos = QPoint()
        self.setMouseTracking(True)
        self.setAttribute(Qt.WA_Hover)
        self.installEventFilter(self)

    def minimumSizeHint(self):
        w = 4
        w += self.vSplitRect.width() + 6
        w += self.hSplitRect.width() + 6
        w += self.floatRect.width() + 6
        w += self.closeRect.width() + 6
        s = QSize(w, 22)
        return s

    def sizeHint(self):
        return self.minimumSizeHint()

    def mouseMoveEvent(self, event):
        p = event.pos()
        r = QRect()

        if self.vSplitRect.contains(p):
            self.mouseHoverState = MOUSE_HOVER.HOVER_VSPLIT
        elif self.hSplitRect.contains(p):
            self.mouseHoverState = MOUSE_HOVER.HOVER_HSPLIT
        elif self.closeRect.contains(p):
            self.mouseHoverState = MOUSE_HOVER.HOVER_CLOSE
        elif self.floatRect.contains(p):
            self.mouseHoverState = MOUSE_HOVER.HOVER_FLOAT
        else:
            self.mouseHoverState = MOUSE_HOVER.HOVER_NONE

        self.repaint(r.adjusted(-1, -1, 1, 1))

    def mousePressEvent(self, event):
        self.mouseClickPos = event.pos()
        if self.closeRect.contains(self.mouseClickPos):
            self.closeClicked.emit()
        elif self.floatRect.contains(self.mouseClickPos):
            self.floatClicked.emit()
        elif self.vSplitRect.contains(self.mouseClickPos):
            self.splitClicked.emit(Qt.Vertical)
        elif self.hSplitRect.contains(self.mouseClickPos):
            self.splitClicked.emit(Qt.Horizontal)
            self.mouseHoverState = MOUSE_HOVER.HOVER_NONE

    def paintEvent(self, event):
        painter = QPainter(self)
        palette = self.palette()
        midColor = palette.mid().color()
        highlight = palette.highlight().color()

        # background
        painter.fillRect(self.rect(), midColor.lighter())

        # float rect
        color = highlight if self.mouseHoverState == MOUSE_HOVER.HOVER_FLOAT else midColor
        painter.setPen(color)
        painter.setBrush(palette.light())
        painter.drawRect(self.floatRect)
        painter.setBrush(highlight if color == highlight else midColor)
        painter.drawRect(self.floatRect.adjusted(4, 2, -2, -4))

        # hsplit rect
        color = highlight if self.mouseHoverState == MOUSE_HOVER.HOVER_HSPLIT else midColor
        painter.setPen(color)
        painter.setBrush(palette.light())
        painter.drawRect(self.hSplitRect)
        painter.setBrush(highlight if color == highlight else midColor)
        painter.drawRect(self.hSplitRect.adjusted(2, 2, -6, -2))

        # float rect
        color = highlight if self.mouseHoverState == MOUSE_HOVER.HOVER_VSPLIT else midColor
        painter.setPen(color)
        painter.setBrush(palette.light())
        painter.drawRect(self.vSplitRect)
        painter.setBrush(highlight if color == highlight else midColor)
        painter.drawRect(self.vSplitRect.adjusted(2, 2, -2, -6))

        # float rect
        color = highlight if self.mouseHoverState == MOUSE_HOVER.HOVER_CLOSE else midColor
        painter.setPen(color)
        painter.setBrush(palette.light())
        painter.drawRect(self.closeRect)
        painter.translate(self.closeRect.topLeft())
        painter.setPen(QPen(color, 1.5))
        painter.drawLine(QPoint(4, 4), QPoint(9, 9))
        painter.drawLine(QPoint(4, 9), QPoint(9, 4))
        painter.resetTransform()

    def resizeEvent(self, event):
        w = self.width()
        self.hSplitRect = QRect(w-72, 4, 12, 12)
        self.vSplitRect = QRect(w-54, 4, 12, 12)
        self.floatRect = QRect(w-36, 4, 12, 12)
        self.closeRect = QRect(w-18, 4, 12, 12)

    def eventFilter(self, obj, event):
        if event.type() == QEvent.HoverLeave:
            self.mouseHoverState = MOUSE_HOVER.HOVER_NONE
            self.repaint(self.rect())
            return True
        return False
Beispiel #26
0
class corkDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        QStyledItemDelegate.__init__(self, parent)
        self.factor = settings.corkSizeFactor / 100.
        self.defaultSize = QSize(300, 200)
        self.lastPos = None
        self.editing = None
        self.margin = 5

    def setCorkSizeFactor(self, v):
        self.factor = v / 100.

    def sizeHint(self, option, index):
        return self.defaultSize * self.factor

    def editorEvent(self, event, model, option, index):
        # We catch the mouse position in the widget to know which part to edit
        if type(event) == QMouseEvent:
            self.lastPos = event.pos()  # - option.rect.topLeft()
        return QStyledItemDelegate.editorEvent(self, event, model, option,
                                               index)

    def createEditor(self, parent, option, index):
        self.updateRects(option, index)

        if self.mainLineRect.contains(self.lastPos):
            # One line summary
            self.editing = Outline.summarySentence
            edt = QLineEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrame(False)
            edt.setAlignment(Qt.AlignCenter)
            edt.setPlaceholderText(self.tr("One line summary"))
            f = QFont(option.font)
            f.setItalic(True)
            edt.setFont(f)
            return edt

        elif self.titleRect.contains(self.lastPos):
            # Title
            self.editing = Outline.title
            edt = QLineEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrame(False)
            f = QFont(option.font)
            # f.setPointSize(f.pointSize() + 1)
            f.setBold(True)
            edt.setFont(f)
            edt.setAlignment(Qt.AlignCenter)
            # edt.setGeometry(self.titleRect)
            return edt

        else:  # self.mainTextRect.contains(self.lastPos):
            # Summary
            self.editing = Outline.summaryFull
            edt = QPlainTextEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrameShape(QFrame.NoFrame)
            try:
                # QPlainTextEdit.setPlaceholderText was introduced in Qt 5.3
                edt.setPlaceholderText(self.tr("Full summary"))
            except AttributeError:
                pass
            return edt

    def updateEditorGeometry(self, editor, option, index):

        if self.editing == Outline.summarySentence:
            # One line summary
            editor.setGeometry(self.mainLineRect)

        elif self.editing == Outline.title:
            # Title
            editor.setGeometry(self.titleRect)

        elif self.editing == Outline.summaryFull:
            # Summary
            editor.setGeometry(self.mainTextRect)

    def setEditorData(self, editor, index):
        item = index.internalPointer()

        if self.editing == Outline.summarySentence:
            # One line summary
            editor.setText(item.data(Outline.summarySentence.value))

        elif self.editing == Outline.title:
            # Title
            editor.setText(index.data())

        elif self.editing == Outline.summaryFull:
            # Summary
            editor.setPlainText(item.data(Outline.summaryFull.value))

    def setModelData(self, editor, model, index):

        if self.editing == Outline.summarySentence:
            # One line summary
            model.setData(
                index.sibling(index.row(), Outline.summarySentence.value),
                editor.text())

        elif self.editing == Outline.title:
            # Title
            model.setData(index, editor.text(), Outline.title.value)

        elif self.editing == Outline.summaryFull:
            # Summary
            model.setData(
                index.sibling(index.row(), Outline.summaryFull.value),
                editor.toPlainText())

    def updateRects(self, option, index):
        margin = self.margin
        iconSize = max(16 * self.factor, 12)
        item = index.internalPointer()
        self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin)
        self.iconRect = QRect(self.itemRect.topLeft() + QPoint(margin, margin),
                              QSize(iconSize, iconSize))
        self.labelRect = QRect(
            self.itemRect.topRight() - QPoint(iconSize + margin, 0),
            self.itemRect.topRight() + QPoint(0, iconSize + 2 * margin))
        self.titleRect = QRect(
            self.iconRect.topRight() + QPoint(margin, 0),
            self.labelRect.bottomLeft() - QPoint(margin, margin))
        self.bottomRect = QRect(
            QPoint(self.itemRect.x(),
                   self.iconRect.bottom() + margin),
            QPoint(self.itemRect.right(), self.itemRect.bottom()))
        self.topRect = QRect(self.itemRect.topLeft(),
                             self.bottomRect.topRight())
        self.mainRect = self.bottomRect.adjusted(margin, margin, -margin,
                                                 -margin)
        self.mainLineRect = QRect(
            self.mainRect.topLeft(),
            self.mainRect.topRight() + QPoint(0, iconSize))
        self.mainTextRect = QRect(
            self.mainLineRect.bottomLeft() + QPoint(0, margin),
            self.mainRect.bottomRight())
        if not item.data(Outline.summarySentence.value):
            self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())
        if item.data(Outline.label.value) in ["", "0", 0]:
            self.titleRect.setBottomRight(self.labelRect.bottomRight() -
                                          QPoint(self.margin, self.margin))

    def paint(self, p, option, index):
        # QStyledItemDelegate.paint(self, p, option, index)
        if not index.isValid():
            return

        item = index.internalPointer()
        self.updateRects(option, index)
        colors = outlineItemColors(item)

        style = qApp.style()

        def _rotate(angle):
            p.translate(self.mainRect.center())
            p.rotate(angle)
            p.translate(-self.mainRect.center())

        # Draw background
        cg = QPalette.ColorGroup(QPalette.Normal if option.state
                                 & QStyle.State_Enabled else QPalette.Disabled)
        if cg == QPalette.Normal and not option.state & QStyle.State_Active:
            cg = QPalette.Inactive

            # Selection
        if option.state & QStyle.State_Selected:
            p.save()
            p.setBrush(option.palette.brush(cg, QPalette.Highlight))
            p.setPen(Qt.NoPen)
            p.drawRoundedRect(option.rect, 12, 12)
            p.restore()

            # Stack
        if item.isFolder() and item.childCount() > 0:
            p.save()
            p.setBrush(Qt.white)
            for i in reversed(range(3)):
                p.drawRoundedRect(
                    self.itemRect.adjusted(2 * i, 2 * i, -2 * i, 2 * i), 10,
                    10)

            p.restore()

            # Background
        itemRect = self.itemRect
        p.save()
        if settings.viewSettings["Cork"]["Background"] != "Nothing":
            c = colors[settings.viewSettings["Cork"]["Background"]]
            col = mixColors(c, QColor(Qt.white), .2)
            p.setBrush(col)
        else:
            p.setBrush(Qt.white)
        pen = p.pen()
        pen.setWidth(2)
        p.setPen(pen)
        p.drawRoundedRect(itemRect, 10, 10)
        p.restore()

        # Title bar
        topRect = self.topRect
        p.save()
        if item.isFolder():
            color = QColor(Qt.darkGreen)
        else:
            color = QColor(Qt.blue).lighter(175)
        p.setPen(Qt.NoPen)
        p.setBrush(color)
        p.setClipRegion(QRegion(topRect))
        p.drawRoundedRect(itemRect, 10, 10)
        # p.drawRect(topRect)
        p.restore()

        # Label color
        if settings.viewSettings["Cork"]["Corner"] != "Nothing":
            p.save()
            color = colors[settings.viewSettings["Cork"]["Corner"]]
            p.setPen(Qt.NoPen)
            p.setBrush(color)
            p.setClipRegion(QRegion(self.labelRect))
            p.drawRoundedRect(itemRect, 10, 10)
            # p.drawRect(topRect)
            p.restore()
            if color != Qt.transparent:
                p.drawLine(self.labelRect.topLeft(),
                           self.labelRect.bottomLeft())

            # One line summary background
        lineSummary = item.data(Outline.summarySentence.value)
        fullSummary = item.data(Outline.summaryFull.value)
        if lineSummary or not fullSummary:
            m = self.margin
            r = self.mainLineRect.adjusted(-m, -m, m, m / 2)
            p.save()
            p.setPen(Qt.NoPen)
            p.setBrush(QColor("#EEE"))
            p.drawRect(r)
            p.restore()

            # Border
        p.save()
        p.setBrush(Qt.NoBrush)
        pen = p.pen()
        pen.setWidth(2)
        if settings.viewSettings["Cork"]["Border"] != "Nothing":
            col = colors[settings.viewSettings["Cork"]["Border"]]
            if col == Qt.transparent:
                col = Qt.black
            pen.setColor(col)
        p.setPen(pen)
        p.drawRoundedRect(itemRect, 10, 10)
        p.restore()

        # Draw the icon
        iconRect = self.iconRect
        mode = QIcon.Normal
        if not option.state & style.State_Enabled:
            mode = QIcon.Disabled
        elif option.state & style.State_Selected:
            mode = QIcon.Selected
        # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode)
        icon = index.data(Qt.DecorationRole).pixmap(iconRect.size())
        if settings.viewSettings["Cork"]["Icon"] != "Nothing":
            color = colors[settings.viewSettings["Cork"]["Icon"]]
            colorifyPixmap(icon, color)
        QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode)

        # Draw title
        p.save()
        text = index.data()
        titleRect = self.titleRect
        if text:
            if settings.viewSettings["Cork"]["Text"] != "Nothing":
                col = colors[settings.viewSettings["Cork"]["Text"]]
                if col == Qt.transparent:
                    col = Qt.black
                p.setPen(col)
            f = QFont(option.font)
            # f.setPointSize(f.pointSize() + 1)
            f.setBold(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(text, Qt.ElideRight, titleRect.width())
            p.drawText(titleRect, Qt.AlignCenter, elidedText)
        p.restore()

        # Draw the line
        bottomRect = self.bottomRect
        p.save()
        # p.drawLine(itemRect.x(), iconRect.bottom() + margin,
        # itemRect.right(), iconRect.bottom() + margin)
        p.drawLine(bottomRect.topLeft(), bottomRect.topRight())
        p.restore()

        # Lines
        if True:
            p.save()
            p.setPen(QColor("#EEE"))
            fm = QFontMetrics(option.font)
            h = fm.lineSpacing()
            l = self.mainTextRect.topLeft() + QPoint(0, h)
            while self.mainTextRect.contains(l):
                p.drawLine(l, QPoint(self.mainTextRect.right(), l.y()))
                l.setY(l.y() + h)
            p.restore()

        # Draw status
        mainRect = self.mainRect
        status = item.data(Outline.status.value)
        if status:
            it = mainWindow().mdlStatus.item(int(status), 0)
            if it != None:
                p.save()
                p.setClipRegion(QRegion(mainRect))
                f = p.font()
                f.setPointSize(f.pointSize() + 12)
                f.setBold(True)
                p.setFont(f)
                p.setPen(QColor(Qt.red).lighter(175))
                _rotate(-35)
                p.drawText(mainRect, Qt.AlignCenter, it.text())
                p.restore()

                # Draw Summary
                # One line
        if lineSummary:
            p.save()
            f = QFont(option.font)
            f.setItalic(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(lineSummary, Qt.ElideRight,
                                       self.mainLineRect.width())
            p.drawText(self.mainLineRect, Qt.AlignCenter, elidedText)
            p.restore()

            # Full summary
        if fullSummary:
            p.setFont(option.font)
            p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)
Beispiel #27
0
class corkDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        QStyledItemDelegate.__init__(self, parent)
        self.factor = settings.corkSizeFactor / 100.
        self.defaultSize = QSize(300, 200)
        self.lastPos = None
        self.editing = None
        self.margin = 5

    def setCorkSizeFactor(self, v):
        self.factor = v / 100.

    def sizeHint(self, option, index):
        return self.defaultSize * self.factor

    def editorEvent(self, event, model, option, index):
        # We catch the mouse position in the widget to know which part to edit
        if type(event) == QMouseEvent:
            self.lastPos = event.pos()  # - option.rect.topLeft()
        return QStyledItemDelegate.editorEvent(self, event, model, option, index)

    def createEditor(self, parent, option, index):
        self.updateRects(option, index)

        if self.mainLineRect.contains(self.lastPos):
            # One line summary
            self.editing = Outline.summarySentance
            edt = QLineEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrame(False)
            edt.setAlignment(Qt.AlignCenter)
            edt.setPlaceholderText(self.tr("One line summary"))
            f = QFont(option.font)
            f.setItalic(True)
            edt.setFont(f)
            return edt

        elif self.titleRect.contains(self.lastPos):
            # Title
            self.editing = Outline.title
            edt = QLineEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrame(False)
            f = QFont(option.font)
            # f.setPointSize(f.pointSize() + 1)
            f.setBold(True)
            edt.setFont(f)
            edt.setAlignment(Qt.AlignCenter)
            # edt.setGeometry(self.titleRect)
            return edt

        else:  # self.mainTextRect.contains(self.lastPos):
            # Summary
            self.editing = Outline.summaryFull
            edt = QPlainTextEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrameShape(QFrame.NoFrame)
            edt.setPlaceholderText(self.tr("Full summary"))
            return edt

    def updateEditorGeometry(self, editor, option, index):

        if self.editing == Outline.summarySentance:
            # One line summary
            editor.setGeometry(self.mainLineRect)

        elif self.editing == Outline.title:
            # Title
            editor.setGeometry(self.titleRect)

        elif self.editing == Outline.summaryFull:
            # Summary
            editor.setGeometry(self.mainTextRect)

    def setEditorData(self, editor, index):
        item = index.internalPointer()

        if self.editing == Outline.summarySentance:
            # One line summary
            editor.setText(item.data(Outline.summarySentance.value))

        elif self.editing == Outline.title:
            # Title
            editor.setText(index.data())

        elif self.editing == Outline.summaryFull:
            # Summary
            editor.setPlainText(item.data(Outline.summaryFull.value))

    def setModelData(self, editor, model, index):

        if self.editing == Outline.summarySentance:
            # One line summary
            model.setData(index.sibling(index.row(), Outline.summarySentance.value), editor.text())

        elif self.editing == Outline.title:
            # Title
            model.setData(index, editor.text(), Outline.title.value)

        elif self.editing == Outline.summaryFull:
            # Summary
            model.setData(index.sibling(index.row(), Outline.summaryFull.value), editor.toPlainText())

    def updateRects(self, option, index):
        margin = self.margin
        iconSize = max(16 * self.factor, 12)
        item = index.internalPointer()
        self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin)
        self.iconRect = QRect(self.itemRect.topLeft() + QPoint(margin, margin), QSize(iconSize, iconSize))
        self.labelRect = QRect(self.itemRect.topRight() - QPoint(iconSize + margin, 0),
                               self.itemRect.topRight() + QPoint(0, iconSize + 2 * margin))
        self.titleRect = QRect(self.iconRect.topRight() + QPoint(margin, 0),
                               self.labelRect.bottomLeft() - QPoint(margin, margin))
        self.bottomRect = QRect(QPoint(self.itemRect.x(), self.iconRect.bottom() + margin),
                                QPoint(self.itemRect.right(), self.itemRect.bottom()))
        self.topRect = QRect(self.itemRect.topLeft(), self.bottomRect.topRight())
        self.mainRect = self.bottomRect.adjusted(margin, margin, -margin, -margin)
        self.mainLineRect = QRect(self.mainRect.topLeft(),
                                  self.mainRect.topRight() + QPoint(0, iconSize))
        self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin),
                                  self.mainRect.bottomRight())
        if not item.data(Outline.summarySentance.value):
            self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())
        if item.data(Outline.label.value) in ["", "0"]:
            self.titleRect.setBottomRight(self.labelRect.bottomRight() - QPoint(self.margin, self.margin))

    def paint(self, p, option, index):
        # QStyledItemDelegate.paint(self, p, option, index)
        if not index.isValid():
            return

        item = index.internalPointer()
        self.updateRects(option, index)
        colors = outlineItemColors(item)

        style = qApp.style()

        def _rotate(angle):
            p.translate(self.mainRect.center())
            p.rotate(angle)
            p.translate(-self.mainRect.center())

        # Draw background
        cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled)
        if cg == QPalette.Normal and not option.state & QStyle.State_Active:
            cg = QPalette.Inactive

            # Selection
        if option.state & QStyle.State_Selected:
            p.save()
            p.setBrush(option.palette.brush(cg, QPalette.Highlight))
            p.setPen(Qt.NoPen)
            p.drawRoundedRect(option.rect, 12, 12)
            p.restore()

            # Stack
        if item.isFolder() and item.childCount() > 0:
            p.save()
            p.setBrush(Qt.white)
            for i in reversed(range(3)):
                p.drawRoundedRect(self.itemRect.adjusted(2 * i, 2 * i, -2 * i, 2 * i), 10, 10)

            p.restore()

            # Background
        itemRect = self.itemRect
        p.save()
        if settings.viewSettings["Cork"]["Background"] != "Nothing":
            c = colors[settings.viewSettings["Cork"]["Background"]]
            col = mixColors(c, QColor(Qt.white), .2)
            p.setBrush(col)
        else:
            p.setBrush(Qt.white)
        pen = p.pen()
        pen.setWidth(2)
        p.setPen(pen)
        p.drawRoundedRect(itemRect, 10, 10)
        p.restore()

        # Title bar
        topRect = self.topRect
        p.save()
        if item.isFolder():
            color = QColor(Qt.darkGreen)
        else:
            color = QColor(Qt.blue).lighter(175)
        p.setPen(Qt.NoPen)
        p.setBrush(color)
        p.setClipRegion(QRegion(topRect))
        p.drawRoundedRect(itemRect, 10, 10)
        # p.drawRect(topRect)
        p.restore()

        # Label color
        if settings.viewSettings["Cork"]["Corner"] != "Nothing":
            p.save()
            color = colors[settings.viewSettings["Cork"]["Corner"]]
            p.setPen(Qt.NoPen)
            p.setBrush(color)
            p.setClipRegion(QRegion(self.labelRect))
            p.drawRoundedRect(itemRect, 10, 10)
            # p.drawRect(topRect)
            p.restore()
            p.drawLine(self.labelRect.topLeft(), self.labelRect.bottomLeft())

            # One line summary background
        lineSummary = item.data(Outline.summarySentance.value)
        fullSummary = item.data(Outline.summaryFull.value)
        if lineSummary or not fullSummary:
            m = self.margin
            r = self.mainLineRect.adjusted(-m, -m, m, m / 2)
            p.save()
            p.setPen(Qt.NoPen)
            p.setBrush(QColor("#EEE"))
            p.drawRect(r)
            p.restore()

            # Border
        p.save()
        p.setBrush(Qt.NoBrush)
        pen = p.pen()
        pen.setWidth(2)
        if settings.viewSettings["Cork"]["Border"] != "Nothing":
            col = colors[settings.viewSettings["Cork"]["Border"]]
            if col == Qt.transparent:
                col = Qt.black
            pen.setColor(col)
        p.setPen(pen)
        p.drawRoundedRect(itemRect, 10, 10)
        p.restore()

        # Draw the icon
        iconRect = self.iconRect
        mode = QIcon.Normal
        if not option.state & style.State_Enabled:
            mode = QIcon.Disabled
        elif option.state & style.State_Selected:
            mode = QIcon.Selected
        # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode)
        icon = index.data(Qt.DecorationRole).pixmap(iconRect.size())
        if settings.viewSettings["Cork"]["Icon"] != "Nothing":
            color = colors[settings.viewSettings["Cork"]["Icon"]]
            colorifyPixmap(icon, color)
        QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode)

        # Draw title
        p.save()
        text = index.data()
        titleRect = self.titleRect
        if text:
            if settings.viewSettings["Cork"]["Text"] != "Nothing":
                col = colors[settings.viewSettings["Cork"]["Text"]]
                if col == Qt.transparent:
                    col = Qt.black
                p.setPen(col)
            f = QFont(option.font)
            # f.setPointSize(f.pointSize() + 1)
            f.setBold(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(text, Qt.ElideRight, titleRect.width())
            p.drawText(titleRect, Qt.AlignCenter, elidedText)
        p.restore()

        # Draw the line
        bottomRect = self.bottomRect
        p.save()
        # p.drawLine(itemRect.x(), iconRect.bottom() + margin,
        # itemRect.right(), iconRect.bottom() + margin)
        p.drawLine(bottomRect.topLeft(), bottomRect.topRight())
        p.restore()

        # Lines
        if True:
            p.save()
            p.setPen(QColor("#EEE"))
            fm = QFontMetrics(option.font)
            h = fm.lineSpacing()
            l = self.mainTextRect.topLeft() + QPoint(0, h)
            while self.mainTextRect.contains(l):
                p.drawLine(l, QPoint(self.mainTextRect.right(), l.y()))
                l.setY(l.y() + h)
            p.restore()

        # Draw status
        mainRect = self.mainRect
        status = item.data(Outline.status.value)
        if status:
            it = mainWindow().mdlStatus.item(int(status), 0)
            if it != None:
                p.save()
                p.setClipRegion(QRegion(mainRect))
                f = p.font()
                f.setPointSize(f.pointSize() + 12)
                f.setBold(True)
                p.setFont(f)
                p.setPen(QColor(Qt.red).lighter(175))
                _rotate(-35)
                p.drawText(mainRect, Qt.AlignCenter, it.text())
                p.restore()

                # Draw Summary
                # One line
        if lineSummary:
            p.save()
            f = QFont(option.font)
            f.setItalic(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width())
            p.drawText(self.mainLineRect, Qt.AlignCenter, elidedText)
            p.restore()

            # Full summary
        if fullSummary:
            p.setFont(option.font)
            p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)
class SlippyMap(QObject):

    updated = pyqtSignal(QRect)

    def __init__(self, parent=None):
        super(SlippyMap, self).__init__(parent)

        self._offset = QPoint()
        self._tilesRect = QRect()
        self._tilePixmaps = {}  # Point(x, y) to QPixmap mapping
        self._manager = QNetworkAccessManager()
        self._url = QUrl()
        # public vars
        self.width = 400
        self.height = 300
        self.zoom = 15
        self.latitude = 59.9138204
        self.longitude = 10.7387413

        self._emptyTile = QPixmap(TDIM, TDIM)
        self._emptyTile.fill(Qt.lightGray)

        cache = QNetworkDiskCache()
        cache.setCacheDirectory(
            QStandardPaths.writableLocation(QStandardPaths.CacheLocation))
        self._manager.setCache(cache)
        self._manager.finished.connect(self.handleNetworkData)

    def invalidate(self):
        if self.width <= 0 or self.height <= 0:
            return

        ct = tileForCoordinate(self.latitude, self.longitude, self.zoom)
        tx = ct.x()
        ty = ct.y()

        # top-left corner of the center tile
        xp = int(self.width / 2 - (tx - math.floor(tx)) * TDIM)
        yp = int(self.height / 2 - (ty - math.floor(ty)) * TDIM)

        # first tile vertical and horizontal
        xa = (xp + TDIM - 1) / TDIM
        ya = (yp + TDIM - 1) / TDIM
        xs = int(tx) - xa
        ys = int(ty) - ya

        # offset for top-left tile
        self._offset = QPoint(xp - xa * TDIM, yp - ya * TDIM)

        # last tile vertical and horizontal
        xe = int(tx) + (self.width - xp - 1) / TDIM
        ye = int(ty) + (self.height - yp - 1) / TDIM

        # build a rect
        self._tilesRect = QRect(xs, ys, xe - xs + 1, ye - ys + 1)

        if self._url.isEmpty():
            self.download()

        self.updated.emit(QRect(0, 0, self.width, self.height))

    def render(self, p, rect):
        for x in range(self._tilesRect.width()):
            for y in range(self._tilesRect.height()):
                tp = Point(x + self._tilesRect.left(),
                           y + self._tilesRect.top())
                box = self.tileRect(tp)
                if rect.intersects(box):
                    p.drawPixmap(box,
                                 self._tilePixmaps.get(tp, self._emptyTile))

    def pan(self, delta):
        dx = QPointF(delta) / float(TDIM)
        center = tileForCoordinate(self.latitude, self.longitude,
                                   self.zoom) - dx
        self.latitude = latitudeFromTile(center.y(), self.zoom)
        self.longitude = longitudeFromTile(center.x(), self.zoom)
        self.invalidate()

    # slots
    def handleNetworkData(self, reply):
        img = QImage()
        tp = Point(reply.request().attribute(QNetworkRequest.User))
        url = reply.url()
        if not reply.error():
            if img.load(reply, None):
                self._tilePixmaps[tp] = QPixmap.fromImage(img)
        reply.deleteLater()
        self.updated.emit(self.tileRect(tp))

        # purge unused tiles
        bound = self._tilesRect.adjusted(-2, -2, 2, 2)
        for tp in list(self._tilePixmaps.keys()):
            if not bound.contains(tp):
                del self._tilePixmaps[tp]
        self.download()

    def download(self):
        grab = None
        for x in range(self._tilesRect.width()):
            for y in range(self._tilesRect.height()):
                tp = Point(self._tilesRect.topLeft() + QPoint(x, y))
                if tp not in self._tilePixmaps:
                    grab = QPoint(tp)
                    break

        if grab is None:
            self._url = QUrl()
            return

        path = 'http://tile.openstreetmap.org/%d/%d/%d.png' % (
            self.zoom, grab.x(), grab.y())
        self._url = QUrl(path)
        request = QNetworkRequest()
        request.setUrl(self._url)
        request.setRawHeader(b'User-Agent', b'Nokia (PyQt) Graphics Dojo 1.0')
        request.setAttribute(QNetworkRequest.User, grab)
        self._manager.get(request)

    def tileRect(self, tp):
        t = tp - self._tilesRect.topLeft()
        x = t.x() * TDIM + self._offset.x()
        y = t.y() * TDIM + self._offset.y()

        return QRect(x, y, TDIM, TDIM)
Beispiel #29
0
class corkDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        QStyledItemDelegate.__init__(self, parent)
        self.factor = settings.corkSizeFactor / 100.
        self.lastPos = None
        self.editing = None
        self.margin = 5

        self.bgColors = {}

    def newStyle(self):
        return settings.corkStyle == "new"

    def setCorkSizeFactor(self, v):
        self.factor = v / 100.

    def sizeHint(self, option, index):
        if self.newStyle():
            defaultSize = QSize(300, 210)
        else:
            defaultSize = QSize(300, 200)
        return defaultSize * self.factor

    def editorEvent(self, event, model, option, index):
        # We catch the mouse position in the widget to know which part to edit
        if type(event) == QMouseEvent:
            self.lastPos = event.pos()  # - option.rect.topLeft()
        return QStyledItemDelegate.editorEvent(self, event, model, option, index)

    def createEditor(self, parent, option, index):
        self.updateRects(option, index)

        bgColor = self.bgColors.get(index, "white")

        if self.mainLineRect.contains(self.lastPos):
            # One line summary
            self.editing = Outline.summarySentence
            edt = QLineEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrame(False)
            f = QFont(option.font)
            if self.newStyle():
                f.setBold(True)
            else:
                f.setItalic(True)
                edt.setAlignment(Qt.AlignCenter)
            edt.setPlaceholderText(self.tr("One line summary"))
            edt.setFont(f)
            edt.setStyleSheet("background: {}; color: black;".format(bgColor))
            return edt

        elif self.titleRect.contains(self.lastPos):
            # Title
            self.editing = Outline.title
            edt = QLineEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrame(False)
            f = QFont(option.font)
            if self.newStyle():
                f.setPointSize(f.pointSize() + 4)
            else:
                edt.setAlignment(Qt.AlignCenter)
            f.setBold(True)
            edt.setFont(f)
            edt.setStyleSheet("background: {}; color: black;".format(bgColor))
            # edt.setGeometry(self.titleRect)
            return edt

        else:  # self.mainTextRect.contains(self.lastPos):
            # Summary
            self.editing = Outline.summaryFull
            edt = QPlainTextEdit(parent)
            edt.setFocusPolicy(Qt.StrongFocus)
            edt.setFrameShape(QFrame.NoFrame)
            try:
                # QPlainTextEdit.setPlaceholderText was introduced in Qt 5.3
                edt.setPlaceholderText(self.tr("Full summary"))
            except AttributeError:
                pass
            edt.setStyleSheet("background: {}; color: black;".format(bgColor))
            return edt

    def updateEditorGeometry(self, editor, option, index):

        if self.editing == Outline.summarySentence:
            # One line summary
            editor.setGeometry(self.mainLineRect)

        elif self.editing == Outline.title:
            # Title
            editor.setGeometry(self.titleRect)

        elif self.editing == Outline.summaryFull:
            # Summary
            editor.setGeometry(self.mainTextRect)

    def setEditorData(self, editor, index):
        item = index.internalPointer()

        if self.editing == Outline.summarySentence:
            # One line summary
            editor.setText(item.data(Outline.summarySentence))

        elif self.editing == Outline.title:
            # Title
            editor.setText(index.data())

        elif self.editing == Outline.summaryFull:
            # Summary
            editor.setPlainText(item.data(Outline.summaryFull))

    def setModelData(self, editor, model, index):

        if self.editing == Outline.summarySentence:
            # One line summary
            model.setData(index.sibling(index.row(), Outline.summarySentence), editor.text())

        elif self.editing == Outline.title:
            # Title
            model.setData(index, editor.text(), Outline.title)

        elif self.editing == Outline.summaryFull:
            # Summary
            model.setData(index.sibling(index.row(), Outline.summaryFull), editor.toPlainText())

    def updateRects(self, option, index):
        if self.newStyle():
            self.updateRects_v2(option, index)
        else:
            self.updateRects_v1(option, index)

    def updateRects_v2(self, option, index):
        margin = self.margin * 2
        iconSize = max(24 * self.factor, 18)
        item = index.internalPointer()
        fm = QFontMetrics(option.font)
        h = fm.lineSpacing()

        self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin)

        top = 15 * self.factor
        self.topRect = QRect(self.itemRect)
        self.topRect.setHeight(top)

        self.cardRect = QRect(self.itemRect.topLeft() + QPoint(0, top),
                         self.itemRect.bottomRight())
        self.iconRect = QRect(self.cardRect.topLeft() + QPoint(margin, margin),
                              QSize(iconSize, iconSize))
        self.labelRect = QRect(self.cardRect.topRight() - QPoint(margin + self.factor * 18, 1),
                               self.cardRect.topRight() + QPoint(- margin - self.factor * 4, self.factor * 24))
        self.titleRect = QRect(self.iconRect.topRight() + QPoint(margin, 0),
                               self.labelRect.bottomLeft() - QPoint(margin, margin))
        self.titleRect.setBottom(self.iconRect.bottom())
        self.mainRect = QRect(self.iconRect.bottomLeft() + QPoint(0, margin),
                              self.cardRect.bottomRight() - QPoint(margin, 2*margin))
        self.mainRect.setLeft(self.titleRect.left())
        self.mainLineRect = QRect(self.mainRect.topLeft(),
                                  self.mainRect.topRight() + QPoint(0, h))
        self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin),
                                  self.mainRect.bottomRight())
        if not item.data(Outline.summarySentence):
            self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())

    def updateRects_v1(self, option, index):
        margin = self.margin
        iconSize = max(16 * self.factor, 12)
        item = index.internalPointer()
        self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin)
        self.iconRect = QRect(self.itemRect.topLeft() + QPoint(margin, margin), QSize(iconSize, iconSize))
        self.labelRect = QRect(self.itemRect.topRight() - QPoint(iconSize + margin, 0),
                               self.itemRect.topRight() + QPoint(0, iconSize + 2 * margin))
        self.titleRect = QRect(self.iconRect.topRight() + QPoint(margin, 0),
                               self.labelRect.bottomLeft() - QPoint(margin, margin))
        self.bottomRect = QRect(QPoint(self.itemRect.x(), self.iconRect.bottom() + margin),
                                QPoint(self.itemRect.right(), self.itemRect.bottom()))
        self.topRect = QRect(self.itemRect.topLeft(), self.bottomRect.topRight())
        self.mainRect = self.bottomRect.adjusted(margin, margin, -margin, -margin)
        self.mainLineRect = QRect(self.mainRect.topLeft(),
                                  self.mainRect.topRight() + QPoint(0, iconSize))
        self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin),
                                  self.mainRect.bottomRight())
        if not item.data(Outline.summarySentence):
            self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())
        if item.data(Outline.label) in ["", "0", 0]:
            self.titleRect.setBottomRight(self.labelRect.bottomRight() - QPoint(self.margin, self.margin))

    def paint(self, p, option, index):
        if self.newStyle():
            self.paint_v2(p, option, index)
        else:
            self.paint_v1(p, option, index)

    def paint_v2(self, p, option, index):
        # QStyledItemDelegate.paint(self, p, option, index)
        if not index.isValid():
            return

        item = index.internalPointer()
        self.updateRects(option, index)
        colors = outlineItemColors(item)

        style = qApp.style()

        def _rotate(angle, rect=self.mainRect):
            p.translate(rect.center())
            p.rotate(angle)
            p.translate(-rect.center())

        def drawRect(r):
            p.save()
            p.setBrush(Qt.gray)
            p.drawRect(r)
            p.restore()

        # Draw background
        cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled)
        if cg == QPalette.Normal and not option.state & QStyle.State_Active:
            cg = QPalette.Inactive

            # Selection
        if option.state & QStyle.State_Selected:
            p.save()
            p.setBrush(option.palette.brush(cg, QPalette.Highlight))
            p.setPen(Qt.NoPen)
            #p.drawRoundedRect(option.rect, 12, 12)
            p.drawRect(option.rect)
            p.restore()

            # Background
        p.save()
        if settings.viewSettings["Cork"]["Background"] != "Nothing":
            c = colors[settings.viewSettings["Cork"]["Background"]]
            if c == QColor(Qt.transparent):
                c = QColor(Qt.white)
            col = mixColors(c, QColor(Qt.white), .2)
            backgroundColor = col
            p.setBrush(col)
        else:
            p.setBrush(Qt.white)
            backgroundColor = QColor(Qt.white)

            # Cache background color
        self.bgColors[index] = backgroundColor.name()

        p.setPen(Qt.NoPen)
        p.drawRect(self.cardRect)
        if item.isFolder():
            itemPoly = QPolygonF([
                self.topRect.topLeft(),
                self.topRect.topLeft() + QPoint(self.topRect.width() * .35, 0),
                self.cardRect.topLeft() + QPoint(self.topRect.width() * .45, 0),
                self.cardRect.topRight(),
                self.cardRect.bottomRight(),
                self.cardRect.bottomLeft()
            ])
            p.drawPolygon(itemPoly)
        p.restore()

        # Label color
        if settings.viewSettings["Cork"]["Corner"] != "Nothing":
            p.save()
            color = colors[settings.viewSettings["Cork"]["Corner"]]
            p.setPen(Qt.NoPen)
            p.setBrush(color)
            p.drawRect(self.labelRect)
            w = self.labelRect.width()
            poly = QPolygonF([
                self.labelRect.bottomLeft() + QPointF(0, 1),
                self.labelRect.bottomLeft() + QPointF(0, w / 2),
                self.labelRect.bottomLeft() + QPointF(w / 2, 1),
                self.labelRect.bottomRight() + QPointF(1, w / 2),
                self.labelRect.bottomRight() + QPointF(1, 1),
            ])

            p.drawPolygon(poly)
            p.restore()

        if settings.viewSettings["Cork"]["Corner"] == "Nothing" or \
           color == Qt.transparent:
            # No corner, so title can be full width
            self.titleRect.setRight(self.mainRect.right())

        # Draw the icon
        iconRect = self.iconRect
        mode = QIcon.Normal
        if not option.state & style.State_Enabled:
            mode = QIcon.Disabled
        elif option.state & style.State_Selected:
            mode = QIcon.Selected
        # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode)
        icon = index.data(Qt.DecorationRole).pixmap(iconRect.size())
        if settings.viewSettings["Cork"]["Icon"] != "Nothing":
            color = colors[settings.viewSettings["Cork"]["Icon"]]
            colorifyPixmap(icon, color)
        QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode)

        # Draw title
        p.save()
        text = index.data()

        if text:
            p.setPen(Qt.black)
            textColor = QColor(Qt.black)
            if settings.viewSettings["Cork"]["Text"] != "Nothing":
                col = colors[settings.viewSettings["Cork"]["Text"]]
                if col == Qt.transparent:
                    col = Qt.black

                # If title setting is compile, we have to hack the color
                # Or we won't see anything in some themes
                if settings.viewSettings["Cork"]["Text"] == "Compile":
                    if item.compile() in [0, "0"]:
                        col = mixColors(QColor(Qt.black), backgroundColor)
                    else:
                        col = Qt.black
                textColor = col
                p.setPen(col)
            f = QFont(option.font)
            f.setPointSize(f.pointSize() + 4)
            f.setBold(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(text, Qt.ElideRight, self.titleRect.width())
            p.drawText(self.titleRect, Qt.AlignLeft | Qt.AlignVCenter, elidedText)
        p.restore()

            # One line summary background
        lineSummary = item.data(Outline.summarySentence)
        fullSummary = item.data(Outline.summaryFull)

            # Border
        if settings.viewSettings["Cork"]["Border"] != "Nothing":
            p.save()
            p.setBrush(Qt.NoBrush)
            pen = p.pen()
            pen.setWidth(2)
            col = colors[settings.viewSettings["Cork"]["Border"]]
            pen.setColor(col)
            p.setPen(pen)
            if item.isFolder():
                p.drawPolygon(itemPoly)
            else:
                p.drawRect(self.cardRect)
            p.restore()

        # Draw status
        status = item.data(Outline.status)
        if status:
            it = mainWindow().mdlStatus.item(int(status), 0)
            if it != None:
                p.save()
                p.setClipRegion(QRegion(self.cardRect))
                f = p.font()
                f.setPointSize(f.pointSize() + 12)
                f.setBold(True)
                p.setFont(f)
                p.setPen(QColor(Qt.red).lighter(170))
                _rotate(-35, rect=self.cardRect)
                p.drawText(self.cardRect, Qt.AlignCenter, it.text())
                p.restore()

                # Draw Summary
                # One line
        if lineSummary:
            p.save()
            f = QFont(option.font)
            f.setBold(True)
            p.setFont(f)
            p.setPen(textColor)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width())
            p.drawText(self.mainLineRect, Qt.AlignLeft | Qt.AlignVCenter, elidedText)
            p.restore()

            # Full summary
        if fullSummary:
            p.save()
            p.setFont(option.font)
            p.setPen(textColor)
            p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)
            p.restore()

    def paint_v1(self, p, option, index):
        # QStyledItemDelegate.paint(self, p, option, index)
        if not index.isValid():
            return

        item = index.internalPointer()
        self.updateRects(option, index)
        colors = outlineItemColors(item)

        style = qApp.style()

        def _rotate(angle):
            p.translate(self.mainRect.center())
            p.rotate(angle)
            p.translate(-self.mainRect.center())

        # Draw background
        cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled)
        if cg == QPalette.Normal and not option.state & QStyle.State_Active:
            cg = QPalette.Inactive

            # Selection
        if option.state & QStyle.State_Selected:
            p.save()
            p.setBrush(option.palette.brush(cg, QPalette.Highlight))
            p.setPen(Qt.NoPen)
            p.drawRoundedRect(option.rect, 12, 12)
            p.restore()

            # Stack
        if item.isFolder() and item.childCount() > 0:
            p.save()
            p.setBrush(Qt.white)
            for i in reversed(range(3)):
                p.drawRoundedRect(self.itemRect.adjusted(2 * i, 2 * i, -2 * i, 2 * i), 10, 10)

            p.restore()

            # Background
        itemRect = self.itemRect
        p.save()
        if settings.viewSettings["Cork"]["Background"] != "Nothing":
            c = colors[settings.viewSettings["Cork"]["Background"]]
            col = mixColors(c, QColor(Qt.white), .2)
            p.setBrush(col)
        else:
            p.setBrush(Qt.white)
        pen = p.pen()
        pen.setWidth(2)
        p.setPen(pen)
        p.drawRoundedRect(itemRect, 10, 10)
        p.restore()

        # Title bar
        topRect = self.topRect
        p.save()
        if item.isFolder():
            color = QColor(Qt.darkGreen)
        else:
            color = QColor(Qt.blue).lighter(175)
        p.setPen(Qt.NoPen)
        p.setBrush(color)
        p.setClipRegion(QRegion(topRect))
        p.drawRoundedRect(itemRect, 10, 10)
        # p.drawRect(topRect)
        p.restore()

        # Label color
        if settings.viewSettings["Cork"]["Corner"] != "Nothing":
            p.save()
            color = colors[settings.viewSettings["Cork"]["Corner"]]
            p.setPen(Qt.NoPen)
            p.setBrush(color)
            p.setClipRegion(QRegion(self.labelRect))
            p.drawRoundedRect(itemRect, 10, 10)
            # p.drawRect(topRect)
            p.restore()
            if color != Qt.transparent:
                p.drawLine(self.labelRect.topLeft(), self.labelRect.bottomLeft())

            # One line summary background
        lineSummary = item.data(Outline.summarySentence)
        fullSummary = item.data(Outline.summaryFull)
        if lineSummary or not fullSummary:
            m = self.margin
            r = self.mainLineRect.adjusted(-m, -m, m, m / 2)
            p.save()
            p.setPen(Qt.NoPen)
            p.setBrush(QColor("#EEE"))
            p.drawRect(r)
            p.restore()

            # Border
        p.save()
        p.setBrush(Qt.NoBrush)
        pen = p.pen()
        pen.setWidth(2)
        if settings.viewSettings["Cork"]["Border"] != "Nothing":
            col = colors[settings.viewSettings["Cork"]["Border"]]
            if col == Qt.transparent:
                col = Qt.black
            pen.setColor(col)
        p.setPen(pen)
        p.drawRoundedRect(itemRect, 10, 10)
        p.restore()

        # Draw the icon
        iconRect = self.iconRect
        mode = QIcon.Normal
        if not option.state & style.State_Enabled:
            mode = QIcon.Disabled
        elif option.state & style.State_Selected:
            mode = QIcon.Selected
        # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode)
        icon = index.data(Qt.DecorationRole).pixmap(iconRect.size())
        if settings.viewSettings["Cork"]["Icon"] != "Nothing":
            color = colors[settings.viewSettings["Cork"]["Icon"]]
            colorifyPixmap(icon, color)
        QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode)

        # Draw title
        p.save()
        text = index.data()
        titleRect = self.titleRect
        if text:
            if settings.viewSettings["Cork"]["Text"] != "Nothing":
                col = colors[settings.viewSettings["Cork"]["Text"]]
                if col == Qt.transparent:
                    col = Qt.black
                p.setPen(col)
            f = QFont(option.font)
            # f.setPointSize(f.pointSize() + 1)
            f.setBold(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(text, Qt.ElideRight, titleRect.width())
            p.drawText(titleRect, Qt.AlignCenter, elidedText)
        p.restore()

        # Draw the line
        bottomRect = self.bottomRect
        p.save()
        # p.drawLine(itemRect.x(), iconRect.bottom() + margin,
        # itemRect.right(), iconRect.bottom() + margin)
        p.drawLine(bottomRect.topLeft(), bottomRect.topRight())
        p.restore()

        # Lines
        if True:
            p.save()
            p.setPen(QColor("#EEE"))
            fm = QFontMetrics(option.font)
            h = fm.lineSpacing()
            l = self.mainTextRect.topLeft() + QPoint(0, h)
            while self.mainTextRect.contains(l):
                p.drawLine(l, QPoint(self.mainTextRect.right(), l.y()))
                l.setY(l.y() + h)
            p.restore()

        # Draw status
        mainRect = self.mainRect
        status = item.data(Outline.status)
        if status:
            it = mainWindow().mdlStatus.item(int(status), 0)
            if it != None:
                p.save()
                p.setClipRegion(QRegion(mainRect))
                f = p.font()
                f.setPointSize(f.pointSize() + 12)
                f.setBold(True)
                p.setFont(f)
                p.setPen(QColor(Qt.red).lighter(175))
                _rotate(-35)
                p.drawText(mainRect, Qt.AlignCenter, it.text())
                p.restore()

                # Draw Summary
                # One line
        if lineSummary:
            p.save()
            f = QFont(option.font)
            f.setItalic(True)
            p.setFont(f)
            fm = QFontMetrics(f)
            elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width())
            p.drawText(self.mainLineRect, Qt.AlignCenter, elidedText)
            p.restore()

            # Full summary
        if fullSummary:
            p.setFont(option.font)
            p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)
Beispiel #30
0
class SnapshotRegionGrabber(QWidget):
    """
    Class implementing a grabber widget for a rectangular snapshot region.
    
    @signal grabbed(QPixmap) emitted after the region was grabbed
    """
    grabbed = pyqtSignal(QPixmap)
    
    StrokeMask = 0
    FillMask = 1
    
    Rectangle = 0
    Ellipse = 1
    
    def __init__(self, mode=Rectangle):
        """
        Constructor
        
        @param mode region grabber mode (SnapshotRegionGrabber.Rectangle or
            SnapshotRegionGrabber.Ellipse)
        """
        super(SnapshotRegionGrabber, self).__init__(
            None,
            Qt.X11BypassWindowManagerHint | Qt.WindowStaysOnTopHint |
            Qt.FramelessWindowHint | Qt.Tool)
        
        assert mode in [SnapshotRegionGrabber.Rectangle,
                        SnapshotRegionGrabber.Ellipse]
        self.__mode = mode
        
        self.__selection = QRect()
        self.__mouseDown = False
        self.__newSelection = False
        self.__handleSize = 10
        self.__mouseOverHandle = None
        self.__showHelp = True
        self.__grabbing = False
        self.__dragStartPoint = QPoint()
        self.__selectionBeforeDrag = QRect()
        
        # naming conventions for handles
        # T top, B bottom, R Right, L left
        # 2 letters: a corner
        # 1 letter: the handle on the middle of the corresponding side
        self.__TLHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__TRHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__BLHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__BRHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__LHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__THandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__RHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__BHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__handles = [self.__TLHandle, self.__TRHandle, self.__BLHandle,
                          self.__BRHandle, self.__LHandle, self.__THandle,
                          self.__RHandle, self.__BHandle]
        self.__helpTextRect = QRect()
        self.__helpText = self.tr(
            "Select a region using the mouse. To take the snapshot, press"
            " the Enter key or double click. Press Esc to quit.")
        
        self.__pixmap = QPixmap()
        
        self.setMouseTracking(True)
        
        QTimer.singleShot(200, self.__initialize)
    
    def __initialize(self):
        """
        Private slot to initialize the rest of the widget.
        """
        self.__desktop = QApplication.desktop()
        x = self.__desktop.x()
        y = self.__desktop.y()
        if qVersion() >= "5.0.0":
            self.__pixmap = QApplication.screens()[0].grabWindow(
                self.__desktop.winId(), x, y,
                self.__desktop.width(), self.__desktop.height())
        else:
            self.__pixmap = QPixmap.grabWindow(
                self.__desktop.winId(), x, y,
                self.__desktop.width(), self.__desktop.height())
        self.resize(self.__pixmap.size())
        self.move(x, y)
        self.setCursor(Qt.CrossCursor)
        self.show()

        self.grabMouse()
        self.grabKeyboard()
    
    def paintEvent(self, evt):
        """
        Protected method handling paint events.
        
        @param evt paint event (QPaintEvent)
        """
        if self.__grabbing:     # grabWindow() should just get the background
            return
        
        painter = QPainter(self)
        pal = QPalette(QToolTip.palette())
        font = QToolTip.font()
        
        handleColor = pal.color(QPalette.Active, QPalette.Highlight)
        handleColor.setAlpha(160)
        overlayColor = QColor(0, 0, 0, 160)
        textColor = pal.color(QPalette.Active, QPalette.Text)
        textBackgroundColor = pal.color(QPalette.Active, QPalette.Base)
        painter.drawPixmap(0, 0, self.__pixmap)
        painter.setFont(font)
        
        r = QRect(self.__selection)
        if not self.__selection.isNull():
            grey = QRegion(self.rect())
            if self.__mode == SnapshotRegionGrabber.Ellipse:
                reg = QRegion(r, QRegion.Ellipse)
            else:
                reg = QRegion(r)
            grey = grey.subtracted(reg)
            painter.setClipRegion(grey)
            painter.setPen(Qt.NoPen)
            painter.setBrush(overlayColor)
            painter.drawRect(self.rect())
            painter.setClipRect(self.rect())
            drawRect(painter, r, handleColor)
        
        if self.__showHelp:
            painter.setPen(textColor)
            painter.setBrush(textBackgroundColor)
            self.__helpTextRect = painter.boundingRect(
                self.rect().adjusted(2, 2, -2, -2),
                Qt.TextWordWrap, self.__helpText).translated(
                -self.__desktop.x(), -self.__desktop.y())
            self.__helpTextRect.adjust(-2, -2, 4, 2)
            drawRect(painter, self.__helpTextRect, textColor,
                     textBackgroundColor)
            painter.drawText(
                self.__helpTextRect.adjusted(3, 3, -3, -3),
                Qt.TextWordWrap, self.__helpText)
        
        if self.__selection.isNull():
            return
        
        # The grabbed region is everything which is covered by the drawn
        # rectangles (border included). This means that there is no 0px
        # selection, since a 0px wide rectangle will always be drawn as a line.
        txt = "{0:n}, {1:n} ({2:n} x {3:n})".format(
            self.__selection.x(), self.__selection.y(),
            self.__selection.width(), self.__selection.height())
        textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt)
        boundingRect = textRect.adjusted(-4, 0, 0, 0)
        
        if textRect.width() < r.width() - 2 * self.__handleSize and \
           textRect.height() < r.height() - 2 * self.__handleSize and \
           r.width() > 100 and \
           r.height() > 100:
            # center, unsuitable for small selections
            boundingRect.moveCenter(r.center())
            textRect.moveCenter(r.center())
        elif r.y() - 3 > textRect.height() and \
                r.x() + textRect.width() < self.rect().width():
            # on top, left aligned
            boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3))
            textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3))
        elif r.x() - 3 > textRect.width():
            # left, top aligned
            boundingRect.moveTopRight(QPoint(r.x() - 3, r.y()))
            textRect.moveTopRight(QPoint(r.x() - 5, r.y()))
        elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \
                r.right() > textRect.width():
            # at bottom, right aligned
            boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3))
            textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3))
        elif r.right() + textRect.width() + 3 < self.rect().width():
            # right, bottom aligned
            boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom()))
            textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom()))
        
        # If the above didn't catch it, you are running on a very
        # tiny screen...
        drawRect(painter, boundingRect, textColor, textBackgroundColor)
        painter.drawText(textRect, Qt.AlignHCenter, txt)
        
        if (r.height() > self.__handleSize * 2 and
            r.width() > self.__handleSize * 2) or \
           not self.__mouseDown:
            self.__updateHandles()
            painter.setPen(Qt.NoPen)
            painter.setBrush(handleColor)
            painter.setClipRegion(
                self.__handleMask(SnapshotRegionGrabber.StrokeMask))
            painter.drawRect(self.rect())
            handleColor.setAlpha(60)
            painter.setBrush(handleColor)
            painter.setClipRegion(
                self.__handleMask(SnapshotRegionGrabber.FillMask))
            painter.drawRect(self.rect())
    
    def resizeEvent(self, evt):
        """
        Protected method to handle resize events.
        
        @param evt resize event (QResizeEvent)
        """
        if self.__selection.isNull():
            return
        
        r = QRect(self.__selection)
        r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect()))
        r.setBottomRight(self.__limitPointToRect(r.bottomRight(), self.rect()))
        if r.width() <= 1 or r.height() <= 1:
            # This just results in ugly drawing...
            self.__selection = QRect()
        else:
            self.__selection = self.__normalizeSelection(r)
    
    def mousePressEvent(self, evt):
        """
        Protected method to handle mouse button presses.
        
        @param evt mouse press event (QMouseEvent)
        """
        self.__showHelp = not self.__helpTextRect.contains(evt.pos())
        if evt.button() == Qt.LeftButton:
            self.__mouseDown = True
            self.__dragStartPoint = evt.pos()
            self.__selectionBeforeDrag = QRect(self.__selection)
            if not self.__selection.contains(evt.pos()):
                self.__newSelection = True
                self.__selection = QRect()
            else:
                self.setCursor(Qt.ClosedHandCursor)
        elif evt.button() == Qt.RightButton:
            self.__newSelection = False
            self.__selection = QRect()
            self.setCursor(Qt.CrossCursor)
        self.update()
    
    def mouseMoveEvent(self, evt):
        """
        Protected method to handle mouse movements.
        
        @param evt mouse move event (QMouseEvent)
        """
        shouldShowHelp = not self.__helpTextRect.contains(evt.pos())
        if shouldShowHelp != self.__showHelp:
            self.__showHelp = shouldShowHelp
            self.update()
        
        if self.__mouseDown:
            if self.__newSelection:
                p = evt.pos()
                r = self.rect()
                self.__selection = self.__normalizeSelection(
                    QRect(self.__dragStartPoint,
                          self.__limitPointToRect(p, r)))
            elif self.__mouseOverHandle is None:
                # moving the whole selection
                r = self.rect().normalized()
                s = self.__selectionBeforeDrag.normalized()
                p = s.topLeft() + evt.pos() - self.__dragStartPoint
                r.setBottomRight(
                    r.bottomRight() - QPoint(s.width(), s.height()) +
                    QPoint(1, 1))
                if not r.isNull() and r.isValid():
                    self.__selection.moveTo(self.__limitPointToRect(p, r))
            else:
                # dragging a handle
                r = QRect(self.__selectionBeforeDrag)
                offset = evt.pos() - self.__dragStartPoint
                
                if self.__mouseOverHandle in \
                   [self.__TLHandle, self.__THandle, self.__TRHandle]:
                    r.setTop(r.top() + offset.y())
                
                if self.__mouseOverHandle in \
                   [self.__TLHandle, self.__LHandle, self.__BLHandle]:
                    r.setLeft(r.left() + offset.x())
                
                if self.__mouseOverHandle in \
                   [self.__BLHandle, self.__BHandle, self.__BRHandle]:
                    r.setBottom(r.bottom() + offset.y())
                
                if self.__mouseOverHandle in \
                   [self.__TRHandle, self.__RHandle, self.__BRHandle]:
                    r.setRight(r.right() + offset.x())
                
                r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect()))
                r.setBottomRight(
                    self.__limitPointToRect(r.bottomRight(), self.rect()))
                self.__selection = self.__normalizeSelection(r)
            
            self.update()
        else:
            if self.__selection.isNull():
                return
            
            found = False
            for r in self.__handles:
                if r.contains(evt.pos()):
                    self.__mouseOverHandle = r
                    found = True
                    break
            
            if not found:
                self.__mouseOverHandle = None
                if self.__selection.contains(evt.pos()):
                    self.setCursor(Qt.OpenHandCursor)
                else:
                    self.setCursor(Qt.CrossCursor)
            else:
                if self.__mouseOverHandle in [self.__TLHandle,
                                              self.__BRHandle]:
                    self.setCursor(Qt.SizeFDiagCursor)
                elif self.__mouseOverHandle in [self.__TRHandle,
                                                self.__BLHandle]:
                    self.setCursor(Qt.SizeBDiagCursor)
                elif self.__mouseOverHandle in [self.__LHandle,
                                                self.__RHandle]:
                    self.setCursor(Qt.SizeHorCursor)
                elif self.__mouseOverHandle in [self.__THandle,
                                                self.__BHandle]:
                    self.setCursor(Qt.SizeVerCursor)
    
    def mouseReleaseEvent(self, evt):
        """
        Protected method to handle mouse button releases.
        
        @param evt mouse release event (QMouseEvent)
        """
        self.__mouseDown = False
        self.__newSelection = False
        if self.__mouseOverHandle is None and \
           self.__selection.contains(evt.pos()):
            self.setCursor(Qt.OpenHandCursor)
        self.update()
    
    def mouseDoubleClickEvent(self, evt):
        """
        Protected method to handle mouse double clicks.
        
        @param evt mouse double click event (QMouseEvent)
        """
        self.__grabRect()
    
    def keyPressEvent(self, evt):
        """
        Protected method to handle key presses.
        
        @param evt key press event (QKeyEvent)
        """
        if evt.key() == Qt.Key_Escape:
            self.grabbed.emit(QPixmap())
        elif evt.key() in [Qt.Key_Enter, Qt.Key_Return]:
            self.__grabRect()
        else:
            evt.ignore()
    
    def __updateHandles(self):
        """
        Private method to update the handles.
        """
        r = QRect(self.__selection)
        s2 = self.__handleSize // 2
        
        self.__TLHandle.moveTopLeft(r.topLeft())
        self.__TRHandle.moveTopRight(r.topRight())
        self.__BLHandle.moveBottomLeft(r.bottomLeft())
        self.__BRHandle.moveBottomRight(r.bottomRight())
        
        self.__LHandle.moveTopLeft(QPoint(r.x(), r.y() + r.height() // 2 - s2))
        self.__THandle.moveTopLeft(QPoint(r.x() + r.width() // 2 - s2, r.y()))
        self.__RHandle.moveTopRight(
            QPoint(r.right(), r.y() + r.height() // 2 - s2))
        self.__BHandle.moveBottomLeft(
            QPoint(r.x() + r.width() // 2 - s2, r.bottom()))
    
    def __handleMask(self, maskType):
        """
        Private method to calculate the handle mask.
        
        @param maskType type of the mask to be used
            (SnapshotRegionGrabber.FillMask or
            SnapshotRegionGrabber.StrokeMask)
        @return calculated mask (QRegion)
        """
        mask = QRegion()
        for rect in self.__handles:
            if maskType == SnapshotRegionGrabber.StrokeMask:
                r = QRegion(rect)
                mask += r.subtracted(QRegion(rect.adjusted(1, 1, -1, -1)))
            else:
                mask += QRegion(rect.adjusted(1, 1, -1, -1))
        return mask
    
    def __limitPointToRect(self, point, rect):
        """
        Private method to limit the given point to the given rectangle.
        
        @param point point to be limited (QPoint)
        @param rect rectangle the point shall be limited to (QRect)
        @return limited point (QPoint)
        """
        q = QPoint()
        if point.x() < rect.x():
            q.setX(rect.x())
        elif point.x() < rect.right():
            q.setX(point.x())
        else:
            q.setX(rect.right())
        if point.y() < rect.y():
            q.setY(rect.y())
        elif point.y() < rect.bottom():
            q.setY(point.y())
        else:
            q.setY(rect.bottom())
        return q
    
    def __normalizeSelection(self, sel):
        """
        Private method to normalize the given selection.
        
        @param sel selection to be normalized (QRect)
        @return normalized selection (QRect)
        """
        rect = QRect(sel)
        if rect.width() <= 0:
            left = rect.left()
            width = rect.width()
            rect.setLeft(left + width - 1)
            rect.setRight(left)
        if rect.height() <= 0:
            top = rect.top()
            height = rect.height()
            rect.setTop(top + height - 1)
            rect.setBottom(top)
        return rect
    
    def __grabRect(self):
        """
        Private method to grab the selected rectangle (i.e. do the snapshot).
        """
        if self.__mode == SnapshotRegionGrabber.Ellipse:
            ell = QRegion(self.__selection, QRegion.Ellipse)
            if not ell.isEmpty():
                self.__grabbing = True
                
                xOffset = self.__pixmap.rect().x() - ell.boundingRect().x()
                yOffset = self.__pixmap.rect().y() - ell.boundingRect().y()
                translatedEll = ell.translated(xOffset, yOffset)
                
                pixmap2 = QPixmap(ell.boundingRect().size())
                pixmap2.fill(Qt.transparent)
                
                pt = QPainter()
                pt.begin(pixmap2)
                if pt.paintEngine().hasFeature(QPaintEngine.PorterDuff):
                    pt.setRenderHints(
                        QPainter.Antialiasing |
                        QPainter.HighQualityAntialiasing |
                        QPainter.SmoothPixmapTransform,
                        True)
                    pt.setBrush(Qt.black)
                    pt.setPen(QPen(QBrush(Qt.black), 0.5))
                    pt.drawEllipse(translatedEll.boundingRect())
                    pt.setCompositionMode(QPainter.CompositionMode_SourceIn)
                else:
                    pt.setClipRegion(translatedEll)
                    pt.setCompositionMode(QPainter.CompositionMode_Source)
                
                pt.drawPixmap(pixmap2.rect(), self.__pixmap,
                              ell.boundingRect())
                pt.end()
                
                self.grabbed.emit(pixmap2)
        else:
            r = QRect(self.__selection)
            if not r.isNull() and r.isValid():
                self.__grabbing = True
                self.grabbed.emit(self.__pixmap.copy(r))
Beispiel #31
0
class Slider(QWidget):
    valueChanged = pyqtSignal(int)

    def __init__(self, min_value, max_value, step=None):

        super(Slider, self).__init__()

        if step is None:
            step = 1

        self._value = 0
        self._minValue = min_value
        self._maxValue = max_value
        self._step = step
        self._thumbWidth = 20
        self._thumbRect = QRect()
        self._slidingAreaRect = QRect()

        self._bgColor = QColor(20, 20, 20)
        self._indicatorColor = QColor(30, 108, 125)
        self._thumbColor = QColor(42, 157, 182)

        self._sliding = False

        self._fontMetrics = QFontMetrics(self.font())

        self._update_thumb()

    def value(self):

        return self._value

    def set_value(self, v):

        v = max(self._minValue, min(v, self._maxValue))

        if v != self._value:

            if self._step == 1:

                self._value = int(round(v))

            elif self._step > 1:

                self._value = int(round(utils.snap(v, self._step)))

        self.valueChanged.emit(self._value)

        self._update_thumb()

    def max_value(self):

        return self._maxValue

    def set_max_value(self, v):

        if v < self._minValue:
            v = self._minValue

        self._maxValue = v

    def min_value(self):

        return self._minValue

    def set_min_value(self, v):

        if v > self._maxValue:
            v = self._maxValue

        self._minValue = v

    def step(self):

        return self._step

    def set_step(self, v):

        self._step = v

    def set_thumb_size(self, size):

        self._thumbWidth = size

    def _get_value_from_position(self, pos):

        pos -= self._thumbWidth / 2

        width = self.width()

        size = width - self._thumbWidth

        if pos > size:
            return self._maxValue

        if pos < 0:
            return self._minValue

        percent = pos / size

        return self._minValue + round(
            (self._maxValue - self._minValue) * percent)

    def _update_thumb(self):

        size = self.width() - self._thumbWidth

        height = self.height()

        pos = round(
            max(
                0,
                min(
                    size * ((self._value - self._minValue) /
                            (self._maxValue - self._minValue)), size)))

        self._thumbRect.setRect(pos, 0, self._thumbWidth, height)

        self.update()

    def sizeHint(self):

        return QSize(200, 25)

    def resizeEvent(self, e):

        self._update_thumb()

    def mousePressEvent(self, e):

        self._sliding = True

        self.set_value(self._get_value_from_position(e.pos()))

    def mouseReleaseEvent(self, e):

        if self._sliding:
            self._sliding = False
            self.update()

    def mouseMoveEvent(self, e):

        if self._sliding:
            mouse_pos = e.pos().x()

            self.set_value(self._get_value_from_position(mouse_pos))

    def wheelEvent(self, e):

        self.set_value(self._value +
                       utils.sign(e.angleDelta().y() > 0) * self._step)

    def paintEvent(self, e):

        painter = QPainter(self)

        draw_rect = e.rect()

        # SLIDER---------------------------------------------------------------------

        # BAR --------

        painter.setPen(self._bgColor.lighter(200))

        painter.drawRect(draw_rect.adjusted(0, 0, -1, -1))

        painter.fillRect(draw_rect.adjusted(1, 1, -1, -1), self._bgColor)

        # THUMB --------

        painter.setPen(self._thumbColor.lighter())

        painter.drawRect(self._thumbRect.adjusted(0, 0, -1, -1))

        painter.fillRect(self._thumbRect.adjusted(1, 1, -1, -1),
                         self._thumbColor)

        # VALUE LABEL --------

        value_text = str(self._value)

        value_label_size = QSize(self._fontMetrics.width(value_text),
                                 self._fontMetrics.height())

        value_indicator_rect = QRect(self._thumbRect.right() + 2,
                                     self._thumbRect.top(),
                                     value_label_size.width() + 10,
                                     self._thumbRect.height())

        if value_indicator_rect.right() > draw_rect.right():
            value_indicator_rect.setRect(
                self._thumbRect.left() - value_indicator_rect.width() - 1,
                value_indicator_rect.top(), value_indicator_rect.width(),
                value_indicator_rect.height())

        painter.setPen(self._indicatorColor.lighter())

        painter.drawRect(value_indicator_rect.adjusted(0, 0, -1, -1))

        painter.fillRect(value_indicator_rect.adjusted(1, 1, -1, -1),
                         self._indicatorColor)

        painter.setPen(Qt.white)

        painter.drawText(
            value_indicator_rect.left() + value_indicator_rect.width() / 2 -
            value_label_size.width() / 2,
            value_indicator_rect.top() + value_indicator_rect.height() / 2 +
            value_label_size.height() / 3, value_text)
class SnapshotRegionGrabber(QWidget):
    """
    Class implementing a grabber widget for a rectangular snapshot region.
    
    @signal grabbed(QPixmap) emitted after the region was grabbed
    """
    grabbed = pyqtSignal(QPixmap)

    StrokeMask = 0
    FillMask = 1

    Rectangle = 0
    Ellipse = 1

    def __init__(self, mode=Rectangle):
        """
        Constructor
        
        @param mode region grabber mode (SnapshotRegionGrabber.Rectangle or
            SnapshotRegionGrabber.Ellipse)
        """
        super(SnapshotRegionGrabber, self).__init__(
            None, Qt.X11BypassWindowManagerHint | Qt.WindowStaysOnTopHint
            | Qt.FramelessWindowHint | Qt.Tool)

        assert mode in [
            SnapshotRegionGrabber.Rectangle, SnapshotRegionGrabber.Ellipse
        ]
        self.__mode = mode

        self.__selection = QRect()
        self.__mouseDown = False
        self.__newSelection = False
        self.__handleSize = 10
        self.__mouseOverHandle = None
        self.__showHelp = True
        self.__grabbing = False
        self.__dragStartPoint = QPoint()
        self.__selectionBeforeDrag = QRect()
        self.__locale = QLocale()

        # naming conventions for handles
        # T top, B bottom, R Right, L left
        # 2 letters: a corner
        # 1 letter: the handle on the middle of the corresponding side
        self.__TLHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__TRHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__BLHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__BRHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__LHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__THandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__RHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__BHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
        self.__handles = [
            self.__TLHandle, self.__TRHandle, self.__BLHandle, self.__BRHandle,
            self.__LHandle, self.__THandle, self.__RHandle, self.__BHandle
        ]
        self.__helpTextRect = QRect()
        self.__helpText = self.tr(
            "Select a region using the mouse. To take the snapshot, press"
            " the Enter key or double click. Press Esc to quit.")

        self.__pixmap = QPixmap()

        self.setMouseTracking(True)

        QTimer.singleShot(200, self.__initialize)

    def __initialize(self):
        """
        Private slot to initialize the rest of the widget.
        """
        self.__desktop = QApplication.desktop()
        x = self.__desktop.x()
        y = self.__desktop.y()
        if qVersion() >= "5.0.0":
            self.__pixmap = QApplication.screens()[0].grabWindow(
                self.__desktop.winId(), x, y, self.__desktop.width(),
                self.__desktop.height())
        else:
            self.__pixmap = QPixmap.grabWindow(self.__desktop.winId(), x, y,
                                               self.__desktop.width(),
                                               self.__desktop.height())
        self.resize(self.__pixmap.size())
        self.move(x, y)
        self.setCursor(Qt.CrossCursor)
        self.show()

        self.grabMouse()
        self.grabKeyboard()
        self.activateWindow()

    def paintEvent(self, evt):
        """
        Protected method handling paint events.
        
        @param evt paint event (QPaintEvent)
        """
        if self.__grabbing:  # grabWindow() should just get the background
            return

        painter = QPainter(self)
        pal = QPalette(QToolTip.palette())
        font = QToolTip.font()

        handleColor = pal.color(QPalette.Active, QPalette.Highlight)
        handleColor.setAlpha(160)
        overlayColor = QColor(0, 0, 0, 160)
        textColor = pal.color(QPalette.Active, QPalette.Text)
        textBackgroundColor = pal.color(QPalette.Active, QPalette.Base)
        painter.drawPixmap(0, 0, self.__pixmap)
        painter.setFont(font)

        r = QRect(self.__selection)
        if not self.__selection.isNull():
            grey = QRegion(self.rect())
            if self.__mode == SnapshotRegionGrabber.Ellipse:
                reg = QRegion(r, QRegion.Ellipse)
            else:
                reg = QRegion(r)
            grey = grey.subtracted(reg)
            painter.setClipRegion(grey)
            painter.setPen(Qt.NoPen)
            painter.setBrush(overlayColor)
            painter.drawRect(self.rect())
            painter.setClipRect(self.rect())
            drawRect(painter, r, handleColor)

        if self.__showHelp:
            painter.setPen(textColor)
            painter.setBrush(textBackgroundColor)
            self.__helpTextRect = painter.boundingRect(
                self.rect().adjusted(2, 2, -2, -2), Qt.TextWordWrap,
                self.__helpText).translated(-self.__desktop.x(),
                                            -self.__desktop.y())
            self.__helpTextRect.adjust(-2, -2, 4, 2)
            drawRect(painter, self.__helpTextRect, textColor,
                     textBackgroundColor)
            painter.drawText(self.__helpTextRect.adjusted(3, 3, -3, -3),
                             Qt.TextWordWrap, self.__helpText)

        if self.__selection.isNull():
            return

        # The grabbed region is everything which is covered by the drawn
        # rectangles (border included). This means that there is no 0px
        # selection, since a 0px wide rectangle will always be drawn as a line.
        txt = "{0}, {1} ({2} x {3})".format(
            self.__locale.toString(self.__selection.x()),
            self.__locale.toString(self.__selection.y()),
            self.__locale.toString(self.__selection.width()),
            self.__locale.toString(self.__selection.height()))
        textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt)
        boundingRect = textRect.adjusted(-4, 0, 0, 0)

        if textRect.width() < r.width() - 2 * self.__handleSize and \
           textRect.height() < r.height() - 2 * self.__handleSize and \
           r.width() > 100 and \
           r.height() > 100:
            # center, unsuitable for small selections
            boundingRect.moveCenter(r.center())
            textRect.moveCenter(r.center())
        elif r.y() - 3 > textRect.height() and \
                r.x() + textRect.width() < self.rect().width():
            # on top, left aligned
            boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3))
            textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3))
        elif r.x() - 3 > textRect.width():
            # left, top aligned
            boundingRect.moveTopRight(QPoint(r.x() - 3, r.y()))
            textRect.moveTopRight(QPoint(r.x() - 5, r.y()))
        elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \
                r.right() > textRect.width():
            # at bottom, right aligned
            boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3))
            textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3))
        elif r.right() + textRect.width() + 3 < self.rect().width():
            # right, bottom aligned
            boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom()))
            textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom()))

        # If the above didn't catch it, you are running on a very
        # tiny screen...
        drawRect(painter, boundingRect, textColor, textBackgroundColor)
        painter.drawText(textRect, Qt.AlignHCenter, txt)

        if (r.height() > self.__handleSize * 2 and
            r.width() > self.__handleSize * 2) or \
           not self.__mouseDown:
            self.__updateHandles()
            painter.setPen(Qt.NoPen)
            painter.setBrush(handleColor)
            painter.setClipRegion(
                self.__handleMask(SnapshotRegionGrabber.StrokeMask))
            painter.drawRect(self.rect())
            handleColor.setAlpha(60)
            painter.setBrush(handleColor)
            painter.setClipRegion(
                self.__handleMask(SnapshotRegionGrabber.FillMask))
            painter.drawRect(self.rect())

    def resizeEvent(self, evt):
        """
        Protected method to handle resize events.
        
        @param evt resize event (QResizeEvent)
        """
        if self.__selection.isNull():
            return

        r = QRect(self.__selection)
        r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect()))
        r.setBottomRight(self.__limitPointToRect(r.bottomRight(), self.rect()))
        if r.width() <= 1 or r.height() <= 1:
            # This just results in ugly drawing...
            self.__selection = QRect()
        else:
            self.__selection = self.__normalizeSelection(r)

    def mousePressEvent(self, evt):
        """
        Protected method to handle mouse button presses.
        
        @param evt mouse press event (QMouseEvent)
        """
        self.__showHelp = not self.__helpTextRect.contains(evt.pos())
        if evt.button() == Qt.LeftButton:
            self.__mouseDown = True
            self.__dragStartPoint = evt.pos()
            self.__selectionBeforeDrag = QRect(self.__selection)
            if not self.__selection.contains(evt.pos()):
                self.__newSelection = True
                self.__selection = QRect()
            else:
                self.setCursor(Qt.ClosedHandCursor)
        elif evt.button() == Qt.RightButton:
            self.__newSelection = False
            self.__selection = QRect()
            self.setCursor(Qt.CrossCursor)
        self.update()

    def mouseMoveEvent(self, evt):
        """
        Protected method to handle mouse movements.
        
        @param evt mouse move event (QMouseEvent)
        """
        shouldShowHelp = not self.__helpTextRect.contains(evt.pos())
        if shouldShowHelp != self.__showHelp:
            self.__showHelp = shouldShowHelp
            self.update()

        if self.__mouseDown:
            if self.__newSelection:
                p = evt.pos()
                r = self.rect()
                self.__selection = self.__normalizeSelection(
                    QRect(self.__dragStartPoint, self.__limitPointToRect(p,
                                                                         r)))
            elif self.__mouseOverHandle is None:
                # moving the whole selection
                r = self.rect().normalized()
                s = self.__selectionBeforeDrag.normalized()
                p = s.topLeft() + evt.pos() - self.__dragStartPoint
                r.setBottomRight(r.bottomRight() -
                                 QPoint(s.width(), s.height()) + QPoint(1, 1))
                if not r.isNull() and r.isValid():
                    self.__selection.moveTo(self.__limitPointToRect(p, r))
            else:
                # dragging a handle
                r = QRect(self.__selectionBeforeDrag)
                offset = evt.pos() - self.__dragStartPoint

                if self.__mouseOverHandle in \
                   [self.__TLHandle, self.__THandle, self.__TRHandle]:
                    r.setTop(r.top() + offset.y())

                if self.__mouseOverHandle in \
                   [self.__TLHandle, self.__LHandle, self.__BLHandle]:
                    r.setLeft(r.left() + offset.x())

                if self.__mouseOverHandle in \
                   [self.__BLHandle, self.__BHandle, self.__BRHandle]:
                    r.setBottom(r.bottom() + offset.y())

                if self.__mouseOverHandle in \
                   [self.__TRHandle, self.__RHandle, self.__BRHandle]:
                    r.setRight(r.right() + offset.x())

                r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect()))
                r.setBottomRight(
                    self.__limitPointToRect(r.bottomRight(), self.rect()))
                self.__selection = self.__normalizeSelection(r)

            self.update()
        else:
            if self.__selection.isNull():
                return

            found = False
            for r in self.__handles:
                if r.contains(evt.pos()):
                    self.__mouseOverHandle = r
                    found = True
                    break

            if not found:
                self.__mouseOverHandle = None
                if self.__selection.contains(evt.pos()):
                    self.setCursor(Qt.OpenHandCursor)
                else:
                    self.setCursor(Qt.CrossCursor)
            else:
                if self.__mouseOverHandle in [
                        self.__TLHandle, self.__BRHandle
                ]:
                    self.setCursor(Qt.SizeFDiagCursor)
                elif self.__mouseOverHandle in [
                        self.__TRHandle, self.__BLHandle
                ]:
                    self.setCursor(Qt.SizeBDiagCursor)
                elif self.__mouseOverHandle in [
                        self.__LHandle, self.__RHandle
                ]:
                    self.setCursor(Qt.SizeHorCursor)
                elif self.__mouseOverHandle in [
                        self.__THandle, self.__BHandle
                ]:
                    self.setCursor(Qt.SizeVerCursor)

    def mouseReleaseEvent(self, evt):
        """
        Protected method to handle mouse button releases.
        
        @param evt mouse release event (QMouseEvent)
        """
        self.__mouseDown = False
        self.__newSelection = False
        if self.__mouseOverHandle is None and \
           self.__selection.contains(evt.pos()):
            self.setCursor(Qt.OpenHandCursor)
        self.update()

    def mouseDoubleClickEvent(self, evt):
        """
        Protected method to handle mouse double clicks.
        
        @param evt mouse double click event (QMouseEvent)
        """
        self.__grabRect()

    def keyPressEvent(self, evt):
        """
        Protected method to handle key presses.
        
        @param evt key press event (QKeyEvent)
        """
        if evt.key() == Qt.Key_Escape:
            self.grabbed.emit(QPixmap())
        elif evt.key() in [Qt.Key_Enter, Qt.Key_Return]:
            self.__grabRect()
        else:
            evt.ignore()

    def __updateHandles(self):
        """
        Private method to update the handles.
        """
        r = QRect(self.__selection)
        s2 = self.__handleSize // 2

        self.__TLHandle.moveTopLeft(r.topLeft())
        self.__TRHandle.moveTopRight(r.topRight())
        self.__BLHandle.moveBottomLeft(r.bottomLeft())
        self.__BRHandle.moveBottomRight(r.bottomRight())

        self.__LHandle.moveTopLeft(QPoint(r.x(), r.y() + r.height() // 2 - s2))
        self.__THandle.moveTopLeft(QPoint(r.x() + r.width() // 2 - s2, r.y()))
        self.__RHandle.moveTopRight(
            QPoint(r.right(),
                   r.y() + r.height() // 2 - s2))
        self.__BHandle.moveBottomLeft(
            QPoint(r.x() + r.width() // 2 - s2, r.bottom()))

    def __handleMask(self, maskType):
        """
        Private method to calculate the handle mask.
        
        @param maskType type of the mask to be used
            (SnapshotRegionGrabber.FillMask or
            SnapshotRegionGrabber.StrokeMask)
        @return calculated mask (QRegion)
        """
        mask = QRegion()
        for rect in self.__handles:
            if maskType == SnapshotRegionGrabber.StrokeMask:
                r = QRegion(rect)
                mask += r.subtracted(QRegion(rect.adjusted(1, 1, -1, -1)))
            else:
                mask += QRegion(rect.adjusted(1, 1, -1, -1))
        return mask

    def __limitPointToRect(self, point, rect):
        """
        Private method to limit the given point to the given rectangle.
        
        @param point point to be limited (QPoint)
        @param rect rectangle the point shall be limited to (QRect)
        @return limited point (QPoint)
        """
        q = QPoint()
        if point.x() < rect.x():
            q.setX(rect.x())
        elif point.x() < rect.right():
            q.setX(point.x())
        else:
            q.setX(rect.right())
        if point.y() < rect.y():
            q.setY(rect.y())
        elif point.y() < rect.bottom():
            q.setY(point.y())
        else:
            q.setY(rect.bottom())
        return q

    def __normalizeSelection(self, sel):
        """
        Private method to normalize the given selection.
        
        @param sel selection to be normalized (QRect)
        @return normalized selection (QRect)
        """
        rect = QRect(sel)
        if rect.width() <= 0:
            left = rect.left()
            width = rect.width()
            rect.setLeft(left + width - 1)
            rect.setRight(left)
        if rect.height() <= 0:
            top = rect.top()
            height = rect.height()
            rect.setTop(top + height - 1)
            rect.setBottom(top)
        return rect

    def __grabRect(self):
        """
        Private method to grab the selected rectangle (i.e. do the snapshot).
        """
        if self.__mode == SnapshotRegionGrabber.Ellipse:
            ell = QRegion(self.__selection, QRegion.Ellipse)
            if not ell.isEmpty():
                self.__grabbing = True

                xOffset = self.__pixmap.rect().x() - ell.boundingRect().x()
                yOffset = self.__pixmap.rect().y() - ell.boundingRect().y()
                translatedEll = ell.translated(xOffset, yOffset)

                pixmap2 = QPixmap(ell.boundingRect().size())
                pixmap2.fill(Qt.transparent)

                pt = QPainter()
                pt.begin(pixmap2)
                if pt.paintEngine().hasFeature(QPaintEngine.PorterDuff):
                    pt.setRenderHints(
                        QPainter.Antialiasing
                        | QPainter.HighQualityAntialiasing
                        | QPainter.SmoothPixmapTransform, True)
                    pt.setBrush(Qt.black)
                    pt.setPen(QPen(QBrush(Qt.black), 0.5))
                    pt.drawEllipse(translatedEll.boundingRect())
                    pt.setCompositionMode(QPainter.CompositionMode_SourceIn)
                else:
                    pt.setClipRegion(translatedEll)
                    pt.setCompositionMode(QPainter.CompositionMode_Source)

                pt.drawPixmap(pixmap2.rect(), self.__pixmap,
                              ell.boundingRect())
                pt.end()

                self.grabbed.emit(pixmap2)
        else:
            r = QRect(self.__selection)
            if not r.isNull() and r.isValid():
                self.__grabbing = True
                self.grabbed.emit(self.__pixmap.copy(r))
Beispiel #33
0
class SlippyMap(QObject):
    def __init__(self, parent: QObject = None) -> None:
        super().__init__(parent)

        self.width: int = 400
        self.height: int = 300
        self.zoom: int = 15
        self.latitude: float = 59.9138204
        self.longitude: float = 10.7387413

        self.m_offset = QPoint()
        self.m_tilesRect = QRect()

        self.m_emptyTile = QPixmap(tdim, tdim)
        self.m_emptyTile.fill(Qt.lightGray)

        self.m_tilePixmaps: typing.Dict[QPointH, QPixmap] = dict()
        self.m_manager = QNetworkAccessManager()
        self.m_url = QUrl()

        cache = QNetworkDiskCache()
        cache.setCacheDirectory(
            QStandardPaths.writableLocation(QStandardPaths.CacheLocation)
        )
        self.m_manager.setCache(cache)
        self.m_manager.finished.connect(self.handleNetworkData)

    def invalidate(self) -> None:
        if self.width <= 0 or self.height <= 0:
            return

        ct = tileForCoordinate(self.latitude, self.longitude, self.zoom)
        tx = ct.x()
        ty = ct.y()

        # top-left corner of the center tile
        xp = self.width / 2 - (tx - math.floor(tx)) * tdim
        yp = self.height / 2 - (ty - math.floor(ty)) * tdim

        xa = (xp + tdim - 1) / tdim
        ya = (yp + tdim - 1) / tdim
        xs = int(tx) - xa
        ys = int(ty) - ya

        # offset for top-left tile
        self.m_offset = QPoint(xp - xa * tdim, yp - ya * tdim)

        # last tile vertical and horizontal
        xe = int(tx) + (self.width - xp - 1) / tdim
        ye = int(ty) + (self.height - yp - 1) / tdim

        # build a rect
        self.m_tilesRect = QRect(xs, ys, xe - xs + 1, ye - ys + 1)

        if self.m_url.isEmpty():
            self.download()

        self.updated.emit(QRect(0, 0, self.width, self.height))

    def render(self, painter: QPainter, rect: QRect) -> None:
        for x in range(self.m_tilesRect.width() + 1):
            for y in range(self.m_tilesRect.height() + 1):
                tp = QPoint(x + self.m_tilesRect.left(), y + self.m_tilesRect.top())
                box = self.tileRect(tp)
                if rect.intersects(box):
                    painter.drawPixmap(
                        box, self.m_tilePixmaps.get(QPointH(tp), self.m_emptyTile)
                    )

    def pan(self, delta: QPoint) -> None:
        dx = QPointF(delta) / float(tdim)
        center = tileForCoordinate(self.latitude, self.longitude, self.zoom) - dx
        self.latitude = latitudeFromTile(center.y(), self.zoom)
        self.longitude = longitudeFromTile(center.x(), self.zoom)
        self.invalidate()

    updated = pyqtSignal(QRect)

    @pyqtSlot(QNetworkReply)
    def handleNetworkData(self, reply: QNetworkReply) -> None:
        img = QImage()
        tp = reply.request().attribute(QNetworkRequest.User)
        if not reply.error():
            if not img.load(reply, ""):
                img = QImage()
        reply.deleteLater()
        self.m_tilePixmaps[QPointH(tp)] = (
            self.m_emptyTile if img.isNull() else QPixmap.fromImage(img)
        )
        self.updated.emit(self.tileRect(tp))

        # purge unused spaces
        bound = self.m_tilesRect.adjusted(-2, -2, 2, 2)
        self.m_tilePixmaps = {
            tp: pixmap
            for tp, pixmap in self.m_tilePixmaps.items()
            if bound.contains(tp)
        }

        self.download()

    @pyqtSlot()
    def download(self):
        grab = QPoint(0, 0)
        for x in range(self.m_tilesRect.width() + 1):
            for y in range(self.m_tilesRect.height() + 1):
                tp = self.m_tilesRect.topLeft() + QPoint(x, y)
                if QPointH(tp) not in self.m_tilePixmaps:
                    grab = tp
                    break

        if grab == QPoint(0, 0):
            self.m_url = QUrl()
            return
        path = "http://tile.openstreetmap.org/%d/%d/%d.png"
        self.m_url = QUrl(path % (self.zoom, grab.x(), grab.y()))
        request = QNetworkRequest()
        request.setUrl(self.m_url)
        request.setRawHeader(b"User-Agent", b"The Qt Company (Qt) Graphics Dojo 1.0")
        request.setAttribute(QNetworkRequest.User, grab)
        self.m_manager.get(request)

    def tileRect(self, tp: QPoint):
        t = tp - self.m_tilesRect.topLeft()
        x = t.x() * tdim + self.m_offset.x()
        y = t.y() * tdim + self.m_offset.y()
        return QRect(x, y, tdim, tdim)