Esempio n. 1
0
 def paintSection(self, painter: QPainter, rect: QRect, index):
     print(index, rect)
     super(SectionHeaderView, self).paintSection(painter, rect, index)
     painter.save()
     painter.drawLine(rect.topLeft().x() - 1, rect.topLeft().y(),
                      rect.bottomLeft().x() - 1, rect.bottomLeft().y())
     painter.drawLine(rect.topRight().x(), rect.topRight().y(),
                      rect.bottomRight().x(), rect.bottomRight().y())
     painter.restore()
Esempio n. 2
0
 def updateWindowSize(self):
     """
     拉伸窗口过程中,根据记录的坐标更新窗口大小
     :return:
     """
     windowRect = QRect(self.m_windowRectBeforeStretch.x(),
                        self.m_windowRectBeforeStretch.y(),
                        self.m_windowRectBeforeStretch.width(),
                        self.m_windowRectBeforeStretch.height())
     delValue_X = self.m_startPoint.x() - self.m_endPoint.x()
     delValue_Y = self.m_startPoint.y() - self.m_endPoint.y()
     if self.m_stretchRectState == LEFT_BORDER:
         topLeftPoint = windowRect.topLeft()
         topLeftPoint.setX(topLeftPoint.x() - delValue_X)
         windowRect.setTopLeft(topLeftPoint)
     elif self.m_stretchRectState == RIGHT_BORDER:
         bottomRightPoint = windowRect.bottomRight()
         bottomRightPoint.setX(bottomRightPoint.x() - delValue_X)
         windowRect.setBottomRight(bottomRightPoint)
     elif self.m_stretchRectState == TOP_BORDER:
         topLeftPoint = windowRect.topLeft()
         topLeftPoint.setY(topLeftPoint.y() - delValue_Y)
         windowRect.setTopLeft(topLeftPoint)
     elif self.m_stretchRectState == BOTTOM_BORDER:
         bottomRightPoint = windowRect.bottomRight()
         bottomRightPoint.setY(bottomRightPoint.y() - delValue_Y)
         windowRect.setBottomRight(bottomRightPoint)
     elif self.m_stretchRectState == LEFT_TOP_RECT:
         topLeftPoint = windowRect.topLeft()
         topLeftPoint.setX(topLeftPoint.x() - delValue_X)
         topLeftPoint.setY(topLeftPoint.y() - delValue_Y)
         windowRect.setTopLeft(topLeftPoint)
     elif self.m_stretchRectState == RIGHT_TOP_RECT:
         topRightPoint = windowRect.topRight()
         topRightPoint.setX(topRightPoint.x() - delValue_X)
         topRightPoint.setY(topRightPoint.y() - delValue_Y)
         windowRect.setTopRight(topRightPoint)
     elif self.m_stretchRectState == RIGHT_BOTTOM_RECT:
         bottomRightPoint = windowRect.bottomRight()
         bottomRightPoint.setX(bottomRightPoint.x() - delValue_X)
         bottomRightPoint.setY(bottomRightPoint.y() - delValue_Y)
         windowRect.setBottomRight(bottomRightPoint)
     elif self.m_stretchRectState == LEFT_BOTTOM_RECT:
         bottomLeftPoint = windowRect.bottomLeft()
         bottomLeftPoint.setX(bottomLeftPoint.x() - delValue_X)
         bottomLeftPoint.setY(bottomLeftPoint.y() - delValue_Y)
         windowRect.setBottomLeft(bottomLeftPoint)
     # 避免宽或高为零窗口显示有误,这里给窗口设置最小拉伸高度、宽度
     if windowRect.width() < self.m_windowMinWidth:
         windowRect.setLeft(self.geometry().left())
         windowRect.setWidth(self.m_windowMinWidth)
     if windowRect.height() < self.m_windowMinHeight:
         windowRect.setTop(self.geometry().top())
         windowRect.setHeight(self.m_windowMinHeight)
     self.setGeometry(windowRect)
Esempio n. 3
0
 def paintBorders(self, painter: QPainter, rect: QRect) -> None:
     if self.quirk_mode:
         painter.setPen(self.quirkPen)
         painter.drawLine(rect.topLeft(), rect.topRight())
     painter.setPen(self.midPen)
     painter.drawLine(rect.topLeft(), rect.bottomLeft())
     if (
         self.container_horizontal_scrollbar_visible is None
         or not self.container_horizontal_scrollbar_visible
     ):
         painter.drawLine(rect.bottomLeft(), rect.bottomRight())
     if (
         self.container_vertical_scrollbar_visible is None
         or not self.container_vertical_scrollbar_visible
     ):
         painter.drawLine(rect.topRight(), rect.bottomRight())
Esempio n. 4
0
    def paintEvent(self, QPaintEvent):
        p = QPainter(self)
        p.setPen(self.pen)
        p.setBrush(self.brush)

        rect = QRect(40, 70, 100, 100)

        p.drawLine(rect.topLeft(), rect.bottomRight())
Esempio n. 5
0
class ImageLabel(QLabel):
    shot = pyqtSignal(QRect)

    def __init__(self, w=640, h=480):
        super(ImageLabel, self).__init__()
        self.setFixedSize(w, h)
        self.setStyleSheet("QLabel{background:black}")
        self._drawing = False
        self._image = None
        self._shot_rect = QRect()
        self._start_pos = None
        self._end_pos = None

    def set_image(self, name):
        self._image = QImage()
        self._image.load(name)
        self.update()

    def mousePressEvent(self, ev: QMouseEvent) -> None:
        if ev.button() == Qt.LeftButton:
            self._drawing = True
            self._start_pos = ev.pos()

    def mouseMoveEvent(self, ev: QMouseEvent) -> None:
        if self._drawing:
            self._end_pos = ev.pos()
            self._shot_rect = QRect(self._start_pos, self._end_pos)
            self.update()

    def mouseReleaseEvent(self, ev: QMouseEvent) -> None:
        if ev.button() == Qt.LeftButton:
            self.shot.emit(self._shot_rect)
            self._drawing = False
            self._shot_rect.setWidth(0)
            self._shot_rect.setHeight(0)

    def paintEvent(self, a0: QPaintEvent) -> None:
        painter = QPainter(self)
        if self._image is not None:
            pixmap = QPixmap.fromImage(self._image)
            painter.drawPixmap(0, 0, self._image.width(), self._image.height(),
                               pixmap)
        if self._drawing:
            painter.setPen(QPen(Qt.red, 4, Qt.SolidLine, Qt.FlatCap))
            painter.drawRect(self._shot_rect)
            painter.setPen(QPen(Qt.red, 2, Qt.SolidLine, Qt.FlatCap))
            painter.drawLine(self._shot_rect.topLeft(),
                             self._shot_rect.bottomRight())
            painter.drawLine(self._shot_rect.topRight(),
                             self._shot_rect.bottomLeft())
Esempio n. 6
0
    def clear(self, color=None):
        if color is None:
            self.__painter.setBackground(QColor(255, 255, 255))
        else:
            self.__painter.setBackground(self.__convert_color(color))

        rect = self.__painter.viewport()

        if self.__zoom_set or self.__delta_set:
            transform, invertible = self.__painter.worldTransform().inverted()
            rect = QRect(transform.map(rect.topLeft()),
                         transform.map(rect.bottomRight()))

        self.__painter.eraseRect(rect)
Esempio n. 7
0
    def _drawAutoencoder(self, painter: QPainter, rect: QRect) -> None:
        """Draw a given portion of this widget.

        Parameters
        ----------
        painter:
        rect:
        """
        pen = QPen(Qt.red)
        penWidth = 1
        pen.setWidth(penWidth)
        painter.setPen(pen)

        painter.drawLine(rect.topLeft(), rect.bottomRight())

        path = QPainterPath()
        path.moveTo(rect.topLeft())
        centerRect = QRectF(rect.left() + (rect.width() *.3),
                            rect.top() + (rect.height() *.4),
                            rect.width() *.2, rect.height() *.2)
        # path.lineTo(rect.left() + (rect.width() / 2),
        #             rect.top() + (rect.height() / 2))
        path.arcTo(centerRect, 45, -90)
        path.lineTo(rect.bottomLeft())
        path.lineTo(rect.topLeft())
        path.closeSubpath()
        painter.fillPath(path, QBrush(QColor("blue")))

        path = QPainterPath()
        path.moveTo(rect.topRight())
        path.lineTo(rect.left() + (rect.width() / 2),
                    rect.top() + (rect.height() / 2))
        path.lineTo(rect.bottomRight())
        path.lineTo(rect.bottomRight())
        path.closeSubpath()
        painter.fillPath(path, QBrush(QColor("blue")))
Esempio n. 8
0
def verticalGradientHelper(p: QPainter, spanRect: QRect, rect: QRect):
    highlight = HIGHLIGHT_COLOR
    shadow = SHADOW_COLOR
    grad = QLinearGradient(spanRect.topRight(), spanRect.topLeft())
    grad.setColorAt(0, highlight.lighter(117))
    grad.setColorAt(1, shadow.darker(109))
    p.fillRect(rect, grad)

    light = QColor(255, 255, 255, 80)
    p.setPen(light)
    p.drawLine(rect.topRight() - QPoint(1, 0),
               rect.bottomRight() - QPoint(1, 0))
    dark = QColor(0, 0, 0, 90)
    p.setPen(dark)
    p.drawLine(rect.topLeft(), rect.bottomLeft())
Esempio n. 9
0
    def to_image_rect(self, rect: QRect) -> QRect:
        rect = QRect(rect)
        if rect.top() > rect.bottom():
            _top, _bottom = rect.top(), rect.bottom()
            rect.setBottom(_top), rect.setTop(_bottom)

        if rect.left() > rect.right():
            _left, _right = rect.left(), rect.right()
            rect.setLeft(_right)
            rect.setRight(_left)

        return QRect(
            self.to_image_coord(rect.topLeft()),
            self.to_image_coord(rect.bottomRight())
        )
Esempio n. 10
0
    def paintEvent(self, QPaintEvent):
        p = QPainter(self)
        p.setPen(self.pen)
        p.setBrush(self.brush)

        rect = QRect(50, 100, 300, 200)
        points = [
            QPoint(150, 100),
            QPoint(300, 150),
            QPoint(350, 250),
            QPoint(100, 300)
        ]
        startAngle = 30 * 16
        spanAngle = 120 * 16

        path = QPainterPath()
        path.addRect(150, 150, 100, 100)
        path.moveTo(100, 100)
        path.cubicTo(300, 100, 200, 200, 300, 300)
        path.cubicTo(100, 300, 200, 200, 100, 100)

        if self.shape == "Line":
            p.drawLine(rect.topLeft(), rect.bottomRight())
        elif self.shape == "Rectangle":
            p.drawRect(rect)
        elif self.shape == 'Rounded Rectangle':
            p.drawRoundedRect(rect, 25, 25, Qt.RelativeSize)
        elif self.shape == "Ellipse":
            p.drawEllipse(rect)
        elif self.shape == "Polygon":
            p.drawPolygon(QPolygon(points), Qt.WindingFill)
        elif self.shape == "Polyline":
            p.drawPolyline(QPolygon(points))
        elif self.shape == "Points":
            p.drawPoints(QPolygon(points))
        elif self.shape == "Pie":
            p.drawPie(rect, startAngle, spanAngle)
        elif self.shape == "Arc":
            p.drawArc(rect, startAngle, spanAngle)
        elif self.shape == "Chord":
            p.drawChord(rect, startAngle, spanAngle)
        elif self.shape == "Path":
            p.drawPath(path)
        elif self.shape == "Text":
            p.drawText(rect, Qt.AlignCenter, "Hello Qt!")
        elif self.shape == "Pixmap":
            p.drawPixmap(150, 150, QPixmap("images/qt-logo.png"))
Esempio n. 11
0
 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)
Esempio n. 12
0
    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)
Esempio n. 13
0
 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()))
Esempio n. 14
0
    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()))
Esempio n. 15
0
    def drawThumnail(self, cellNum, pic, thumb : PhotoNode, cell : Rectangle, painter : QPainter):
        rect = QRect(cell.x, cell.y, cell.width, cell.height)
        bLeft = rect.bottomLeft()

        # draw name
        fontHeight = 20
        font = painter.font()
        font.setPixelSize(fontHeight)
        textTopRight = QPoint(bLeft.x(), bLeft.y() - fontHeight)
        textRect = QRect(textTopRight, rect.bottomRight())
        thumbName = thumb.name
        painter.drawText(textRect, Qt.AlignHCenter, thumbName)
        #painter.drawRect(rect)

        # draw thumb
        imageRect = QRect(rect.topLeft(), textRect.topRight())
        imageCenter = imageRect.center()
        imageX = int(imageCenter.x() - pic.width() / 2)
        imageY = int(imageCenter.y() - pic.height() / 2)
        imageOrigin = QPoint(imageX, imageY)
        painter.drawPixmap(imageOrigin, pic)
Esempio n. 16
0
    def drawThumnail(self, cellNum, pic, thumb: PhotoNode, cell: Rectangle,
                     painter: QPainter):
        rect = QRect(cell.x, cell.y, cell.width, cell.height)
        bLeft = rect.bottomLeft()

        # draw name
        fontHeight = 20
        font = painter.font()
        font.setPixelSize(fontHeight)
        textTopRight = QPoint(bLeft.x(), bLeft.y() - fontHeight)
        textRect = QRect(textTopRight, rect.bottomRight())
        thumbName = thumb.name
        painter.drawText(textRect, Qt.AlignHCenter, thumbName)
        #painter.drawRect(rect)

        # draw thumb
        imageRect = QRect(rect.topLeft(), textRect.topRight())
        imageCenter = imageRect.center()
        imageX = int(imageCenter.x() - pic.width() / 2)
        imageY = int(imageCenter.y() - pic.height() / 2)
        imageOrigin = QPoint(imageX, imageY)
        painter.drawPixmap(imageOrigin, pic)
    def _paintImage(self, painter: QPainter, index: int, image: Image,
                    rect: QRect) -> None:
        super()._paintImage(painter, index, image, rect)

        # draw specific decorations
        if self.invalid(index):
            painter.setPen(self._redPen)
            painter.drawLine(rect.topLeft(), rect.bottomRight())
            painter.drawLine(rect.topRight(), rect.bottomLeft())

        # add the age label
        age = self.age(index)
        ageText = "None" if age is None else f"{age}"
        pen = self._bluePen if age is None else self._greenPen
        painter.setPen(pen)
        # print(Qt.AlignHCenter | Qt.AlignBottom, type(Qt.AlignHCenter | Qt.AlignBottom), ageText, type(ageText))
        painter.drawText(rect, Qt.AlignHCenter | Qt.AlignBottom, ageText)

        dataset = image.dataset
        metaText = "No Meta" if dataset is None else dataset
        pen = self._redPen if dataset is None else self._greenPen
        painter.setPen(pen)
        painter.drawText(rect, Qt.AlignHCenter | Qt.AlignTop, metaText)
Esempio n. 18
0
    def paintEvent(self, paint_event):
        super().paintEvent(paint_event)
        widget_rect = self.rect()
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.fillRect(widget_rect, self.background_color)

        if self.mouse_over:
            indicator_rect = QRect(
                widget_rect.width() + self.indicator_pos - 6,
                (widget_rect.height() - 6) // 2, 6, 9)
            triangle_path = QPainterPath(indicator_rect.topRight())
            triangle_path.lineTo(indicator_rect.bottomRight())
            mid_left = indicator_rect.bottomLeft()
            mid_left.setY(mid_left.y() - indicator_rect.height() // 2)
            triangle_path.lineTo(mid_left)
            triangle_path.lineTo(indicator_rect.topRight())

            painter.fillPath(triangle_path, self.indicator_background)

        if self.pixmap:
            pixmap_rect = QRect(self.spacing, (widget_rect.height() - 20) // 2,
                                20, 20)
            painter.drawPixmap(pixmap_rect, self.pixmap, self.pixmap.rect())
            # painter.drawRect(pixmap_rect)
        else:
            pixmap_rect = QRect(0, 0, 0, 0)

        text_rect = QRect(pixmap_rect.right() + self.spacing, 0, 0,
                          widget_rect.height())
        text_rect.setWidth(widget_rect.width() - text_rect.left())
        # painter.drawRect(text_rect)

        text = self.fm.elidedText(self.text, Qt.ElideRight, text_rect.width())
        painter.setFont(self.font)
        painter.drawText(text_rect, Qt.AlignVCenter | Qt.AlignLeft, text)
Esempio n. 19
0
class Window(QWidget):
    def __init__(self):

        QWidget.__init__(self)
        self.largest_rect = QRect(50, 50, 400, 400)

        self.clip_rect = QRect(50, 50, 400, 400)
        self.dragging = None
        self.drag_offset = QPoint()
        self.handle_offsets = (QPoint(8, 8), QPoint(-1, 8), QPoint(8, -1),
                               QPoint(-1, -1))

        self.path = QPainterPath()
        self.path.moveTo(100, 250)
        font = QFont()
        font.setPixelSize(80)
        self.path.addText(100, 300, font, "Clipping")

        self.polygon = QPolygon([
            QPoint(250, 100),
            QPoint(400, 250),
            QPoint(250, 400),
            QPoint(100, 250),
            QPoint(250, 100)
        ])

    def paintEvent(self, event):

        painter = QPainter()
        painter.begin(self)
        painter.fillRect(event.rect(), QBrush(Qt.white))
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setPen(QPen(QBrush(Qt.red), 1, Qt.DashLine))
        painter.drawRect(self.largest_rect)
        painter.setPen(QPen(Qt.black))
        painter.drawRect(self.clip_rect)
        for i in range(4):
            painter.drawRect(self.corner(i))

        painter.setClipRect(self.clip_rect)
        painter.drawPolyline(self.polygon)
        painter.setBrush(QBrush(Qt.blue))
        painter.drawPath(self.path)
        painter.end()

    def corner(self, number):

        if number == 0:
            return QRect(self.clip_rect.topLeft() - self.handle_offsets[0],
                         QSize(8, 8))
        elif number == 1:
            return QRect(self.clip_rect.topRight() - self.handle_offsets[1],
                         QSize(8, 8))
        elif number == 2:
            return QRect(self.clip_rect.bottomLeft() - self.handle_offsets[2],
                         QSize(8, 8))
        elif number == 3:
            return QRect(self.clip_rect.bottomRight() - self.handle_offsets[3],
                         QSize(8, 8))

    def mousePressEvent(self, event):

        for i in range(4):
            rect = self.corner(i)
            if rect.contains(event.pos()):
                self.dragging = i
                self.drag_offset = rect.topLeft() - event.pos()
                break
        else:
            self.dragging = None

    def mouseMoveEvent(self, event):

        if self.dragging is None:
            return

        left = self.largest_rect.left()
        right = self.largest_rect.right()
        top = self.largest_rect.top()
        bottom = self.largest_rect.bottom()

        point = event.pos() + self.drag_offset + self.handle_offsets[
            self.dragging]
        point.setX(max(left, min(point.x(), right)))
        point.setY(max(top, min(point.y(), bottom)))

        if self.dragging == 0:
            self.clip_rect.setTopLeft(point)
        elif self.dragging == 1:
            self.clip_rect.setTopRight(point)
        elif self.dragging == 2:
            self.clip_rect.setBottomLeft(point)
        elif self.dragging == 3:
            self.clip_rect.setBottomRight(point)

        self.update()

    def mouseReleaseEvent(self, event):

        self.dragging = None

    def sizeHint(self):
        return QSize(500, 500)
Esempio n. 20
0
    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)
Esempio n. 21
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)
    def paint(self, painter, option, index):

        if (index.isValid() == False):
            return
        painter.save()
        painter.setOpacity(0.6)
        if (option.state & QStyle.State_Selected):
            painter.fillRect(option.rect, option.palette.highlight())
        if (option.state & QStyle.State_MouseOver):
            painter.setOpacity(0.25)
            painter.fillRect(option.rect, option.palette.highlight())
        painter.setOpacity(1.0)
        painter.setFont(option.font)
        metrics = QFontMetrics(option.font)
        regular = QFont(option.font)
        italics = QFont(option.font)
        italics.setItalic(True)
        icon = QIcon(index.data(CPE.IMAGE))
        rect = option.rect
        margin = 4
        decoratonSize = QSize(option.decorationSize)
        imageSize = icon.actualSize(option.decorationSize)
        leftSideThumbnail = (decoratonSize.width() - imageSize.width()) / 2
        if (rect.width() < decoratonSize.width()):
            leftSideThumbnail = max(0, (rect.width() - imageSize.width()) / 2)
        topSizeThumbnail = (
            (rect.height() - imageSize.height()) / 2) + rect.top()
        painter.drawImage(
            QRect(leftSideThumbnail, topSizeThumbnail, imageSize.width(),
                  imageSize.height()),
            icon.pixmap(imageSize).toImage())

        labelWidth = rect.width() - decoratonSize.width() - (margin * 3)

        if (decoratonSize.width() + (margin * 2) < rect.width()):

            textRect = QRect(decoratonSize.width() + margin,
                             margin + rect.top(), labelWidth, metrics.height())
            textTitle = metrics.elidedText(
                str(index.row() + 1) + ". " + index.data(CPE.TITLE),
                Qt.ElideRight, labelWidth)
            painter.drawText(textRect, Qt.TextWordWrap, textTitle)

            if rect.height() / (metrics.lineSpacing() +
                                margin) > 5 or index.data(
                                    CPE.KEYWORDS) is not None:
                painter.setOpacity(0.6)
                textRect = QRect(textRect.left(),
                                 textRect.bottom() + margin, labelWidth,
                                 metrics.height())
                if textRect.bottom() < rect.bottom():
                    textKeyWords = index.data(CPE.KEYWORDS)
                    if textKeyWords == None:
                        textKeyWords = i18n("No keywords")
                        painter.setOpacity(0.3)
                        painter.setFont(italics)
                    textKeyWords = metrics.elidedText(textKeyWords,
                                                      Qt.ElideRight,
                                                      labelWidth)
                    painter.drawText(textRect, Qt.TextWordWrap, textKeyWords)

            painter.setFont(regular)

            if rect.height() / (metrics.lineSpacing() + margin) > 3:
                painter.setOpacity(0.6)
                textRect = QRect(textRect.left(),
                                 textRect.bottom() + margin, labelWidth,
                                 metrics.height())
                if textRect.bottom() + metrics.height() < rect.bottom():
                    textLastEdit = index.data(CPE.LASTEDIT)
                    if textLastEdit is None:
                        textLastEdit = i18n("No last edit timestamp")
                    if index.data(CPE.EDITOR) is not None:
                        textLastEdit += " - " + index.data(CPE.EDITOR)
                    if (index.data(CPE.LASTEDIT) is None) and (index.data(
                            CPE.EDITOR) is None):
                        painter.setOpacity(0.3)
                        painter.setFont(italics)
                    textLastEdit = metrics.elidedText(textLastEdit,
                                                      Qt.ElideRight,
                                                      labelWidth)
                    painter.drawText(textRect, Qt.TextWordWrap, textLastEdit)

            painter.setFont(regular)

            descRect = QRect(textRect.left(),
                             textRect.bottom() + margin, labelWidth,
                             (rect.bottom() - margin) -
                             (textRect.bottom() + margin))
            if textRect.bottom() + metrics.height() < rect.bottom():
                textRect.setBottom(textRect.bottom() + (margin / 2))
                textRect.setLeft(textRect.left() - (margin / 2))
                painter.setOpacity(0.4)
                painter.drawLine(textRect.bottomLeft(), textRect.bottomRight())
                painter.setOpacity(1.0)
                textDescription = index.data(CPE.DESCRIPTION)
                if textDescription is None:
                    textDescription = i18n("No description")
                    painter.setOpacity(0.3)
                    painter.setFont(italics)
                linesTotal = floor(descRect.height() / metrics.lineSpacing())
                if linesTotal == 1:
                    textDescription = metrics.elidedText(
                        textDescription, Qt.ElideRight, labelWidth)
                    painter.drawText(descRect, Qt.TextWordWrap,
                                     textDescription)
                else:
                    descRect.setHeight(linesTotal * metrics.lineSpacing())
                    totalDescHeight = metrics.boundingRect(
                        descRect, Qt.TextWordWrap, textDescription).height()
                    if totalDescHeight > descRect.height():
                        if totalDescHeight - metrics.lineSpacing(
                        ) > descRect.height():
                            painter.setOpacity(0.5)
                            painter.drawText(descRect, Qt.TextWordWrap,
                                             textDescription)
                            descRect.setHeight(
                                (linesTotal - 1) * metrics.lineSpacing())
                            painter.drawText(descRect, Qt.TextWordWrap,
                                             textDescription)
                            descRect.setHeight(
                                (linesTotal - 2) * metrics.lineSpacing())
                            painter.drawText(descRect, Qt.TextWordWrap,
                                             textDescription)
                        else:
                            painter.setOpacity(0.75)
                            painter.drawText(descRect, Qt.TextWordWrap,
                                             textDescription)
                            descRect.setHeight(
                                (linesTotal - 1) * metrics.lineSpacing())
                            painter.drawText(descRect, Qt.TextWordWrap,
                                             textDescription)
                    else:
                        painter.drawText(descRect, Qt.TextWordWrap,
                                         textDescription)

            painter.setFont(regular)

        painter.restore()
Esempio n. 23
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)
Esempio n. 24
0
    def paintGraph(self, graph, painter):
        brush = QBrush(Qt.SolidPattern)
        pen = QPen()
        brush.setColor(Qt.white)

        for i, edge in enumerate(graph.edges):
            if ("color" in edge.kwargs.keys()):
                pen.setColor(QColor(edge.kwargs["color"]))
            else:
                pen.setColor(QColor("black"))

            if ("width" in edge.kwargs.keys()):
                pen.setWidth(int(edge.kwargs["width"]))
            else:
                pen.setWidth(1)

            painter.setPen(pen)
            painter.setBrush(brush)
            if (edge.source.parent_graph != graph and not self.show_subgraphs):
                gspos = edge.source.parent_graph.global_pos
            else:
                gspos = edge.source.global_pos

            if (edge.dest.parent_graph != graph and not self.show_subgraphs):
                gspos = edge.dest.parent_graph.global_pos
            else:
                gdpos = edge.dest.global_pos

            nb_next = 0
            for j in range(i, len(graph.edges)):
                if (graph.edges[j].source == edge.source
                        and graph.edges[j].dest == edge.dest):
                    nb_next += 1

            offset = [0, 0]
            if (nb_next % 2 == 1):
                offset[0] = 20 * (nb_next / 2)
            else:
                offset[0] = -20 * (nb_next / 2)

            path = QPainterPath()
            path.moveTo(gspos[0], gspos[1])
            path.cubicTo(gspos[0], gspos[1],
                         offset[0] + (gspos[0] + gdpos[0]) / 2,
                         (gspos[1] + gdpos[1]) / 2, gdpos[0], gdpos[1])
            painter.strokePath(path, pen)
            """
            painter.drawLine(gspos[0],gspos[1],
            gdpos[0],
            gdpos[1])
            """

        if (self.show_subgraphs):
            for node in graph.nodes:
                if type(node) == Graph:
                    subgraph = node
                    self.paintSubgraph(subgraph, painter, pen, brush)

        # TODO : add more painting parameters
        for node in graph.nodes:
            if type(node) != Graph:
                if ("color" in node.kwargs.keys()):
                    pen.setColor(QColor(node.kwargs["color"]))
                else:
                    pen.setColor(QColor("black"))

                if ("fillcolor" in node.kwargs.keys()):
                    if (":" in node.kwargs["fillcolor"]):
                        gradient = QLinearGradient(
                            node.pos[0] - node.size[0] / 2, node.pos[1],
                            node.pos[0] + node.size[0] / 2, node.pos[1])
                        c = node.kwargs["fillcolor"].split(":")
                        for i, col in enumerate(c):
                            stop = i / (len(c) - 1)
                            gradient.setColorAt(stop, QColor(col))

                        brush = QBrush(gradient)
                    else:
                        brush = QBrush(QColor(node.kwargs["fillcolor"]))
                else:
                    brush = QBrush(QColor("white"))

                if ("width" in node.kwargs.keys()):
                    pen.setWidth(int(node.kwargs["width"]))
                else:
                    pen.setWidth(1)

                gpos = node.global_pos

                painter.setPen(pen)
                painter.setBrush(brush)
                if ("shape" in node.kwargs.keys()):
                    if (node.kwargs["shape"] == "box"):
                        painter.drawRect(gpos[0] - node.size[0] / 2,
                                         gpos[1] - node.size[1] / 2,
                                         node.size[0], node.size[1])

                    elif (node.kwargs["shape"] == "circle"):
                        painter.drawEllipse(gpos[0] - node.size[0] / 2,
                                            gpos[1] - node.size[1] / 2,
                                            node.size[0], node.size[1])
                    elif (node.kwargs["shape"] == "triangle"):
                        rect = QRect(gpos[0] - node.size[0] / 2,
                                     gpos[1] - 2 * node.size[1] / 3,
                                     node.size[0], node.size[1])

                        path = QPainterPath()
                        path.moveTo(rect.left() + (rect.width() / 2),
                                    rect.top())
                        path.lineTo(rect.bottomLeft())
                        path.lineTo(rect.bottomRight())
                        path.lineTo(rect.left() + (rect.width() / 2),
                                    rect.top())

                        painter.fillPath(path, brush)
                        painter.drawPath(path)
                    elif (node.kwargs["shape"] == "polygon"):
                        rect = QRect(gpos[0] - node.size[0] / 2,
                                     gpos[1] - node.size[1] / 2, node.size[0],
                                     node.size[1])

                        path = QPainterPath()
                        path.moveTo(rect.left() + (rect.width() / 4),
                                    rect.top())
                        path.lineTo(rect.left() + 3 * rect.width() / 4,
                                    rect.top())
                        path.lineTo(rect.left() + rect.width(),
                                    rect.top() + rect.height() / 2)
                        path.lineTo(rect.left() + 3 * rect.width() / 4,
                                    rect.top() + rect.height())
                        path.lineTo(rect.left() + rect.width() / 4,
                                    rect.top() + rect.height())
                        path.lineTo(rect.left(),
                                    rect.top() + rect.height() / 2)
                        path.lineTo(rect.left() + (rect.width() / 4),
                                    rect.top())

                        painter.fillPath(path, brush)
                        painter.drawPath(path)
                    elif (node.kwargs["shape"] == "diamond"):
                        rect = QRect(gpos[0] - node.size[0] / 2,
                                     gpos[1] - node.size[1] / 2, node.size[0],
                                     node.size[1])

                        path = QPainterPath()
                        path.moveTo(rect.left() + (rect.width() / 2),
                                    rect.top())
                        path.lineTo(rect.left() + rect.width(),
                                    rect.top() + rect.height() / 2)
                        path.lineTo(rect.left() + rect.width() / 2,
                                    rect.top() + rect.height())
                        path.lineTo(rect.left(),
                                    rect.top() + rect.height() / 2)
                        path.lineTo(rect.left() + (rect.width() / 2),
                                    rect.top())

                        painter.fillPath(path, brush)
                        painter.drawPath(path)

                    # Image as a node, this implementation checks to see if a
                    # file path was provided in the shape parameter
                    if (os.path.isfile(node.kwargs["shape"])):
                        img_path = node.kwargs["shape"]
                        painter.drawImage(
                            QRect(gpos[0] - node.size[0] / 2,
                                  gpos[1] - node.size[1] / 2, node.size[0],
                                  node.size[1]), QImage(img_path))
                else:
                    painter.drawEllipse(gpos[0] - node.size[0] / 2,
                                        gpos[1] - node.size[1] / 2,
                                        node.size[0], node.size[1])

                if ("label" in node.kwargs.keys()):
                    painter.drawText(gpos[0] - node.size[0] / 2,
                                     gpos[1] - node.size[1] / 2, node.size[0],
                                     node.size[1],
                                     Qt.AlignCenter | Qt.AlignTop,
                                     node.kwargs["label"])
            else:
                if (self.show_subgraphs):
                    self.paintGraph(subgraph, painter)
                else:
                    subgraph = node
                    self.paintSubgraph(subgraph, painter, pen, brush)
Esempio n. 25
0
class IconEditorGrid(QWidget):
    """
    Class implementing the icon editor grid.
    
    @signal canRedoChanged(bool) emitted after the redo status has changed
    @signal canUndoChanged(bool) emitted after the undo status has changed
    @signal clipboardImageAvailable(bool) emitted to signal the availability
        of an image to be pasted
    @signal colorChanged(QColor) emitted after the drawing color was changed
    @signal imageChanged(bool) emitted after the image was modified
    @signal positionChanged(int, int) emitted after the cursor poition was
        changed
    @signal previewChanged(QPixmap) emitted to signal a new preview pixmap
    @signal selectionAvailable(bool) emitted to signal a change of the
        selection
    @signal sizeChanged(int, int) emitted after the size has been changed
    @signal zoomChanged(int) emitted to signal a change of the zoom value
    """
    canRedoChanged = pyqtSignal(bool)
    canUndoChanged = pyqtSignal(bool)
    clipboardImageAvailable = pyqtSignal(bool)
    colorChanged = pyqtSignal(QColor)
    imageChanged = pyqtSignal(bool)
    positionChanged = pyqtSignal(int, int)
    previewChanged = pyqtSignal(QPixmap)
    selectionAvailable = pyqtSignal(bool)
    sizeChanged = pyqtSignal(int, int)
    zoomChanged = pyqtSignal(int)

    Pencil = 1
    Rubber = 2
    Line = 3
    Rectangle = 4
    FilledRectangle = 5
    Circle = 6
    FilledCircle = 7
    Ellipse = 8
    FilledEllipse = 9
    Fill = 10
    ColorPicker = 11

    RectangleSelection = 20
    CircleSelection = 21

    MarkColor = QColor(255, 255, 255, 255)
    NoMarkColor = QColor(0, 0, 0, 0)

    ZoomMinimum = 100
    ZoomMaximum = 10000
    ZoomStep = 100
    ZoomDefault = 1200
    ZoomPercent = True

    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super(IconEditorGrid, self).__init__(parent)

        self.setAttribute(Qt.WA_StaticContents)
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        self.__curColor = Qt.black
        self.__zoom = 12
        self.__curTool = self.Pencil
        self.__startPos = QPoint()
        self.__endPos = QPoint()
        self.__dirty = False
        self.__selecting = False
        self.__selRect = QRect()
        self.__isPasting = False
        self.__clipboardSize = QSize()
        self.__pasteRect = QRect()

        self.__undoStack = QUndoStack(self)
        self.__currentUndoCmd = None

        self.__image = QImage(32, 32, QImage.Format_ARGB32)
        self.__image.fill(qRgba(0, 0, 0, 0))
        self.__markImage = QImage(self.__image)
        self.__markImage.fill(self.NoMarkColor.rgba())

        self.__compositingMode = QPainter.CompositionMode_SourceOver
        self.__lastPos = (-1, -1)

        self.__gridEnabled = True
        self.__selectionAvailable = False

        self.__initCursors()
        self.__initUndoTexts()

        self.setMouseTracking(True)

        self.__undoStack.canRedoChanged.connect(self.canRedoChanged)
        self.__undoStack.canUndoChanged.connect(self.canUndoChanged)
        self.__undoStack.cleanChanged.connect(self.__cleanChanged)

        self.imageChanged.connect(self.__updatePreviewPixmap)
        QApplication.clipboard().dataChanged.connect(self.__checkClipboard)

        self.__checkClipboard()

    def __initCursors(self):
        """
        Private method to initialize the various cursors.
        """
        self.__normalCursor = QCursor(Qt.ArrowCursor)

        pix = QPixmap(":colorpicker-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__colorPickerCursor = QCursor(pix, 1, 21)

        pix = QPixmap(":paintbrush-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__paintCursor = QCursor(pix, 0, 19)

        pix = QPixmap(":fill-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__fillCursor = QCursor(pix, 3, 20)

        pix = QPixmap(":aim-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__aimCursor = QCursor(pix, 10, 10)

        pix = QPixmap(":eraser-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__rubberCursor = QCursor(pix, 1, 16)

    def __initUndoTexts(self):
        """
        Private method to initialize texts to be associated with undo commands
        for the various drawing tools.
        """
        self.__undoTexts = {
            self.Pencil: self.tr("Set Pixel"),
            self.Rubber: self.tr("Erase Pixel"),
            self.Line: self.tr("Draw Line"),
            self.Rectangle: self.tr("Draw Rectangle"),
            self.FilledRectangle: self.tr("Draw Filled Rectangle"),
            self.Circle: self.tr("Draw Circle"),
            self.FilledCircle: self.tr("Draw Filled Circle"),
            self.Ellipse: self.tr("Draw Ellipse"),
            self.FilledEllipse: self.tr("Draw Filled Ellipse"),
            self.Fill: self.tr("Fill Region"),
        }

    def isDirty(self):
        """
        Public method to check the dirty status.
        
        @return flag indicating a modified status (boolean)
        """
        return self.__dirty

    def setDirty(self, dirty, setCleanState=False):
        """
        Public slot to set the dirty flag.
        
        @param dirty flag indicating the new modification status (boolean)
        @param setCleanState flag indicating to set the undo stack to clean
            (boolean)
        """
        self.__dirty = dirty
        self.imageChanged.emit(dirty)

        if not dirty and setCleanState:
            self.__undoStack.setClean()

    def sizeHint(self):
        """
        Public method to report the size hint.
        
        @return size hint (QSize)
        """
        size = self.__zoom * self.__image.size()
        if self.__zoom >= 3 and self.__gridEnabled:
            size += QSize(1, 1)
        return size

    def setPenColor(self, newColor):
        """
        Public method to set the drawing color.
        
        @param newColor reference to the new color (QColor)
        """
        self.__curColor = QColor(newColor)
        self.colorChanged.emit(QColor(newColor))

    def penColor(self):
        """
        Public method to get the current drawing color.
        
        @return current drawing color (QColor)
        """
        return QColor(self.__curColor)

    def setCompositingMode(self, mode):
        """
        Public method to set the compositing mode.
        
        @param mode compositing mode to set (QPainter.CompositionMode)
        """
        self.__compositingMode = mode

    def compositingMode(self):
        """
        Public method to get the compositing mode.
        
        @return compositing mode (QPainter.CompositionMode)
        """
        return self.__compositingMode

    def setTool(self, tool):
        """
        Public method to set the current drawing tool.
        
        @param tool drawing tool to be used
            (IconEditorGrid.Pencil ... IconEditorGrid.CircleSelection)
        """
        self.__curTool = tool
        self.__lastPos = (-1, -1)

        if self.__curTool in [self.RectangleSelection, self.CircleSelection]:
            self.__selecting = True
        else:
            self.__selecting = False

        if self.__curTool in [
                self.RectangleSelection, self.CircleSelection, self.Line,
                self.Rectangle, self.FilledRectangle, self.Circle,
                self.FilledCircle, self.Ellipse, self.FilledEllipse
        ]:
            self.setCursor(self.__aimCursor)
        elif self.__curTool == self.Fill:
            self.setCursor(self.__fillCursor)
        elif self.__curTool == self.ColorPicker:
            self.setCursor(self.__colorPickerCursor)
        elif self.__curTool == self.Pencil:
            self.setCursor(self.__paintCursor)
        elif self.__curTool == self.Rubber:
            self.setCursor(self.__rubberCursor)
        else:
            self.setCursor(self.__normalCursor)

    def tool(self):
        """
        Public method to get the current drawing tool.
        
        @return current drawing tool
            (IconEditorGrid.Pencil ... IconEditorGrid.CircleSelection)
        """
        return self.__curTool

    def setIconImage(self, newImage, undoRedo=False, clearUndo=False):
        """
        Public method to set a new icon image.
        
        @param newImage reference to the new image (QImage)
        @keyparam undoRedo flag indicating an undo or redo operation (boolean)
        @keyparam clearUndo flag indicating to clear the undo stack (boolean)
        """
        if newImage != self.__image:
            self.__image = newImage.convertToFormat(QImage.Format_ARGB32)
            self.update()
            self.updateGeometry()
            self.resize(self.sizeHint())

            self.__markImage = QImage(self.__image)
            self.__markImage.fill(self.NoMarkColor.rgba())

            if undoRedo:
                self.setDirty(not self.__undoStack.isClean())
            else:
                self.setDirty(False)

            if clearUndo:
                self.__undoStack.clear()

            self.sizeChanged.emit(*self.iconSize())

    def iconImage(self):
        """
        Public method to get a copy of the icon image.
        
        @return copy of the icon image (QImage)
        """
        return QImage(self.__image)

    def iconSize(self):
        """
        Public method to get the size of the icon.
        
        @return width and height of the image as a tuple (integer, integer)
        """
        return self.__image.width(), self.__image.height()

    def setZoomFactor(self, newZoom):
        """
        Public method to set the zoom factor in percent.
        
        @param newZoom zoom factor (integer >= 100)
        """
        newZoom = max(100, newZoom)  # must not be less than 100
        if newZoom != self.__zoom:
            self.__zoom = newZoom // 100
            self.update()
            self.updateGeometry()
            self.resize(self.sizeHint())
            self.zoomChanged.emit(int(self.__zoom * 100))

    def zoomFactor(self):
        """
        Public method to get the current zoom factor in percent.
        
        @return zoom factor (integer)
        """
        return self.__zoom * 100

    def setGridEnabled(self, enable):
        """
        Public method to enable the display of grid lines.
        
        @param enable enabled status of the grid lines (boolean)
        """
        if enable != self.__gridEnabled:
            self.__gridEnabled = enable
            self.update()

    def isGridEnabled(self):
        """
        Public method to get the grid lines status.
        
        @return enabled status of the grid lines (boolean)
        """
        return self.__gridEnabled

    def paintEvent(self, evt):
        """
        Protected method called to repaint some of the widget.
        
        @param evt reference to the paint event object (QPaintEvent)
        """
        painter = QPainter(self)

        if self.__zoom >= 3 and self.__gridEnabled:
            painter.setPen(self.palette().windowText().color())
            i = 0
            while i <= self.__image.width():
                painter.drawLine(self.__zoom * i, 0, self.__zoom * i,
                                 self.__zoom * self.__image.height())
                i += 1
            j = 0
            while j <= self.__image.height():
                painter.drawLine(0, self.__zoom * j,
                                 self.__zoom * self.__image.width(),
                                 self.__zoom * j)
                j += 1

        col = QColor("#aaa")
        painter.setPen(Qt.DashLine)
        for i in range(0, self.__image.width()):
            for j in range(0, self.__image.height()):
                rect = self.__pixelRect(i, j)
                if evt.region().intersects(rect):
                    color = QColor.fromRgba(self.__image.pixel(i, j))
                    painter.fillRect(rect, QBrush(Qt.white))
                    painter.fillRect(QRect(rect.topLeft(), rect.center()), col)
                    painter.fillRect(QRect(rect.center(), rect.bottomRight()),
                                     col)
                    painter.fillRect(rect, QBrush(color))

                    if self.__isMarked(i, j):
                        painter.drawRect(rect.adjusted(0, 0, -1, -1))

        painter.end()

    def __pixelRect(self, i, j):
        """
        Private method to determine the rectangle for a given pixel coordinate.
        
        @param i x-coordinate of the pixel in the image (integer)
        @param j y-coordinate of the pixel in the image (integer)
        @return rectangle for the given pixel coordinates (QRect)
        """
        if self.__zoom >= 3 and self.__gridEnabled:
            return QRect(self.__zoom * i + 1, self.__zoom * j + 1,
                         self.__zoom - 1, self.__zoom - 1)
        else:
            return QRect(self.__zoom * i, self.__zoom * j, self.__zoom,
                         self.__zoom)

    def mousePressEvent(self, evt):
        """
        Protected method to handle mouse button press events.
        
        @param evt reference to the mouse event object (QMouseEvent)
        """
        if evt.button() == Qt.LeftButton:
            if self.__isPasting:
                self.__isPasting = False
                self.editPaste(True)
                self.__markImage.fill(self.NoMarkColor.rgba())
                self.update(self.__pasteRect)
                self.__pasteRect = QRect()
                return

            if self.__curTool == self.Pencil:
                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
                                      self.__image)
                self.__setImagePixel(evt.pos(), True)
                self.setDirty(True)
                self.__undoStack.push(cmd)
                self.__currentUndoCmd = cmd
            elif self.__curTool == self.Rubber:
                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
                                      self.__image)
                self.__setImagePixel(evt.pos(), False)
                self.setDirty(True)
                self.__undoStack.push(cmd)
                self.__currentUndoCmd = cmd
            elif self.__curTool == self.Fill:
                i, j = self.__imageCoordinates(evt.pos())
                col = QColor()
                col.setRgba(self.__image.pixel(i, j))
                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
                                      self.__image)
                self.__drawFlood(i, j, col)
                self.setDirty(True)
                self.__undoStack.push(cmd)
                cmd.setAfterImage(self.__image)
            elif self.__curTool == self.ColorPicker:
                i, j = self.__imageCoordinates(evt.pos())
                col = QColor()
                col.setRgba(self.__image.pixel(i, j))
                self.setPenColor(col)
            else:
                self.__unMark()
                self.__startPos = evt.pos()
                self.__endPos = evt.pos()

    def mouseMoveEvent(self, evt):
        """
        Protected method to handle mouse move events.
        
        @param evt reference to the mouse event object (QMouseEvent)
        """
        self.positionChanged.emit(*self.__imageCoordinates(evt.pos()))

        if self.__isPasting and not (evt.buttons() & Qt.LeftButton):
            self.__drawPasteRect(evt.pos())
            return

        if evt.buttons() & Qt.LeftButton:
            if self.__curTool == self.Pencil:
                self.__setImagePixel(evt.pos(), True)
                self.setDirty(True)
            elif self.__curTool == self.Rubber:
                self.__setImagePixel(evt.pos(), False)
                self.setDirty(True)
            elif self.__curTool in [self.Fill, self.ColorPicker]:
                pass  # do nothing
            else:
                self.__drawTool(evt.pos(), True)

    def mouseReleaseEvent(self, evt):
        """
        Protected method to handle mouse button release events.
        
        @param evt reference to the mouse event object (QMouseEvent)
        """
        if evt.button() == Qt.LeftButton:
            if self.__curTool in [self.Pencil, self.Rubber]:
                if self.__currentUndoCmd:
                    self.__currentUndoCmd.setAfterImage(self.__image)
                    self.__currentUndoCmd = None

            if self.__curTool not in [
                    self.Pencil, self.Rubber, self.Fill, self.ColorPicker,
                    self.RectangleSelection, self.CircleSelection
            ]:
                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
                                      self.__image)
                if self.__drawTool(evt.pos(), False):
                    self.__undoStack.push(cmd)
                    cmd.setAfterImage(self.__image)
                    self.setDirty(True)

    def __setImagePixel(self, pos, opaque):
        """
        Private slot to set or erase a pixel.
        
        @param pos position of the pixel in the widget (QPoint)
        @param opaque flag indicating a set operation (boolean)
        """
        i, j = self.__imageCoordinates(pos)

        if self.__image.rect().contains(i, j) and (i, j) != self.__lastPos:
            if opaque:
                painter = QPainter(self.__image)
                painter.setPen(self.penColor())
                painter.setCompositionMode(self.__compositingMode)
                painter.drawPoint(i, j)
            else:
                self.__image.setPixel(i, j, qRgba(0, 0, 0, 0))
            self.__lastPos = (i, j)

            self.update(self.__pixelRect(i, j))

    def __imageCoordinates(self, pos):
        """
        Private method to convert from widget to image coordinates.
        
        @param pos widget coordinate (QPoint)
        @return tuple with the image coordinates (tuple of two integers)
        """
        i = pos.x() // self.__zoom
        j = pos.y() // self.__zoom
        return i, j

    def __drawPasteRect(self, pos):
        """
        Private slot to draw a rectangle for signaling a paste operation.
        
        @param pos widget position of the paste rectangle (QPoint)
        """
        self.__markImage.fill(self.NoMarkColor.rgba())
        if self.__pasteRect.isValid():
            self.__updateImageRect(
                self.__pasteRect.topLeft(),
                self.__pasteRect.bottomRight() + QPoint(1, 1))

        x, y = self.__imageCoordinates(pos)
        isize = self.__image.size()
        if x + self.__clipboardSize.width() <= isize.width():
            sx = self.__clipboardSize.width()
        else:
            sx = isize.width() - x
        if y + self.__clipboardSize.height() <= isize.height():
            sy = self.__clipboardSize.height()
        else:
            sy = isize.height() - y

        self.__pasteRect = QRect(QPoint(x, y), QSize(sx - 1, sy - 1))

        painter = QPainter(self.__markImage)
        painter.setPen(self.MarkColor)
        painter.drawRect(self.__pasteRect)
        painter.end()

        self.__updateImageRect(self.__pasteRect.topLeft(),
                               self.__pasteRect.bottomRight() + QPoint(1, 1))

    def __drawTool(self, pos, mark):
        """
        Private method to perform a draw operation depending of the current
        tool.
        
        @param pos widget coordinate to perform the draw operation at (QPoint)
        @param mark flag indicating a mark operation (boolean)
        @return flag indicating a successful draw (boolean)
        """
        self.__unMark()

        if mark:
            self.__endPos = QPoint(pos)
            drawColor = self.MarkColor
            img = self.__markImage
        else:
            drawColor = self.penColor()
            img = self.__image

        start = QPoint(*self.__imageCoordinates(self.__startPos))
        end = QPoint(*self.__imageCoordinates(pos))

        painter = QPainter(img)
        painter.setPen(drawColor)
        painter.setCompositionMode(self.__compositingMode)

        if self.__curTool == self.Line:
            painter.drawLine(start, end)

        elif self.__curTool in [
                self.Rectangle, self.FilledRectangle, self.RectangleSelection
        ]:
            left = min(start.x(), end.x())
            top = min(start.y(), end.y())
            right = max(start.x(), end.x())
            bottom = max(start.y(), end.y())
            if self.__curTool == self.RectangleSelection:
                painter.setBrush(QBrush(drawColor))
            if self.__curTool == self.FilledRectangle:
                for y in range(top, bottom + 1):
                    painter.drawLine(left, y, right, y)
            else:
                painter.drawRect(left, top, right - left, bottom - top)
            if self.__selecting:
                self.__selRect = QRect(left, top, right - left + 1,
                                       bottom - top + 1)
                self.__selectionAvailable = True
                self.selectionAvailable.emit(True)

        elif self.__curTool in [
                self.Circle, self.FilledCircle, self.CircleSelection
        ]:
            r = max(abs(start.x() - end.x()), abs(start.y() - end.y()))
            if self.__curTool in [self.FilledCircle, self.CircleSelection]:
                painter.setBrush(QBrush(drawColor))
            painter.drawEllipse(start, r, r)
            if self.__selecting:
                self.__selRect = QRect(start.x() - r,
                                       start.y() - r, 2 * r + 1, 2 * r + 1)
                self.__selectionAvailable = True
                self.selectionAvailable.emit(True)

        elif self.__curTool in [self.Ellipse, self.FilledEllipse]:
            r1 = abs(start.x() - end.x())
            r2 = abs(start.y() - end.y())
            if r1 == 0 or r2 == 0:
                return False
            if self.__curTool == self.FilledEllipse:
                painter.setBrush(QBrush(drawColor))
            painter.drawEllipse(start, r1, r2)

        painter.end()

        if self.__curTool in [
                self.Circle, self.FilledCircle, self.Ellipse,
                self.FilledEllipse
        ]:
            self.update()
        else:
            self.__updateRect(self.__startPos, pos)

        return True

    def __drawFlood(self, i, j, oldColor, doUpdate=True):
        """
        Private method to perform a flood fill operation.
        
        @param i x-value in image coordinates (integer)
        @param j y-value in image coordinates (integer)
        @param oldColor reference to the color at position i, j (QColor)
        @param doUpdate flag indicating an update is requested (boolean)
            (used for speed optimizations)
        """
        if not self.__image.rect().contains(i, j) or \
           self.__image.pixel(i, j) != oldColor.rgba() or \
           self.__image.pixel(i, j) == self.penColor().rgba():
            return

        self.__image.setPixel(i, j, self.penColor().rgba())

        self.__drawFlood(i, j - 1, oldColor, False)
        self.__drawFlood(i, j + 1, oldColor, False)
        self.__drawFlood(i - 1, j, oldColor, False)
        self.__drawFlood(i + 1, j, oldColor, False)

        if doUpdate:
            self.update()

    def __updateRect(self, pos1, pos2):
        """
        Private slot to update parts of the widget.
        
        @param pos1 top, left position for the update in widget coordinates
            (QPoint)
        @param pos2 bottom, right position for the update in widget
            coordinates (QPoint)
        """
        self.__updateImageRect(QPoint(*self.__imageCoordinates(pos1)),
                               QPoint(*self.__imageCoordinates(pos2)))

    def __updateImageRect(self, ipos1, ipos2):
        """
        Private slot to update parts of the widget.
        
        @param ipos1 top, left position for the update in image coordinates
            (QPoint)
        @param ipos2 bottom, right position for the update in image
            coordinates (QPoint)
        """
        r1 = self.__pixelRect(ipos1.x(), ipos1.y())
        r2 = self.__pixelRect(ipos2.x(), ipos2.y())

        left = min(r1.x(), r2.x())
        top = min(r1.y(), r2.y())
        right = max(r1.x() + r1.width(), r2.x() + r2.width())
        bottom = max(r1.y() + r1.height(), r2.y() + r2.height())
        self.update(left, top, right - left + 1, bottom - top + 1)

    def __unMark(self):
        """
        Private slot to remove the mark indicator.
        """
        self.__markImage.fill(self.NoMarkColor.rgba())
        if self.__curTool in [
                self.Circle, self.FilledCircle, self.Ellipse,
                self.FilledEllipse, self.CircleSelection
        ]:
            self.update()
        else:
            self.__updateRect(self.__startPos, self.__endPos)

        if self.__selecting:
            self.__selRect = QRect()
            self.__selectionAvailable = False
            self.selectionAvailable.emit(False)

    def __isMarked(self, i, j):
        """
        Private method to check, if a pixel is marked.
        
        @param i x-value in image coordinates (integer)
        @param j y-value in image coordinates (integer)
        @return flag indicating a marked pixel (boolean)
        """
        return self.__markImage.pixel(i, j) == self.MarkColor.rgba()

    def __updatePreviewPixmap(self):
        """
        Private slot to generate and signal an updated preview pixmap.
        """
        p = QPixmap.fromImage(self.__image)
        self.previewChanged.emit(p)

    def previewPixmap(self):
        """
        Public method to generate a preview pixmap.
        
        @return preview pixmap (QPixmap)
        """
        p = QPixmap.fromImage(self.__image)
        return p

    def __checkClipboard(self):
        """
        Private slot to check, if the clipboard contains a valid image, and
        signal the result.
        """
        ok = self.__clipboardImage()[1]
        self.__clipboardImageAvailable = ok
        self.clipboardImageAvailable.emit(ok)

    def canPaste(self):
        """
        Public slot to check the availability of the paste operation.
        
        @return flag indicating availability of paste (boolean)
        """
        return self.__clipboardImageAvailable

    def __clipboardImage(self):
        """
        Private method to get an image from the clipboard.
        
        @return tuple with the image (QImage) and a flag indicating a
            valid image (boolean)
        """
        img = QApplication.clipboard().image()
        ok = not img.isNull()
        if ok:
            img = img.convertToFormat(QImage.Format_ARGB32)

        return img, ok

    def __getSelectionImage(self, cut):
        """
        Private method to get an image from the selection.
        
        @param cut flag indicating to cut the selection (boolean)
        @return image of the selection (QImage)
        """
        if cut:
            cmd = IconEditCommand(self, self.tr("Cut Selection"), self.__image)

        img = QImage(self.__selRect.size(), QImage.Format_ARGB32)
        img.fill(qRgba(0, 0, 0, 0))
        for i in range(0, self.__selRect.width()):
            for j in range(0, self.__selRect.height()):
                if self.__image.rect().contains(self.__selRect.x() + i,
                                                self.__selRect.y() + j):
                    if self.__isMarked(self.__selRect.x() + i,
                                       self.__selRect.y() + j):
                        img.setPixel(
                            i, j,
                            self.__image.pixel(self.__selRect.x() + i,
                                               self.__selRect.y() + j))
                        if cut:
                            self.__image.setPixel(self.__selRect.x() + i,
                                                  self.__selRect.y() + j,
                                                  qRgba(0, 0, 0, 0))

        if cut:
            self.__undoStack.push(cmd)
            cmd.setAfterImage(self.__image)

        self.__unMark()

        if cut:
            self.update(self.__selRect)

        return img

    def editCopy(self):
        """
        Public slot to copy the selection.
        """
        if self.__selRect.isValid():
            img = self.__getSelectionImage(False)
            QApplication.clipboard().setImage(img)

    def editCut(self):
        """
        Public slot to cut the selection.
        """
        if self.__selRect.isValid():
            img = self.__getSelectionImage(True)
            QApplication.clipboard().setImage(img)

    @pyqtSlot()
    def editPaste(self, pasting=False):
        """
        Public slot to paste an image from the clipboard.
        
        @param pasting flag indicating part two of the paste operation
            (boolean)
        """
        img, ok = self.__clipboardImage()
        if ok:
            if img.width() > self.__image.width() or \
                    img.height() > self.__image.height():
                res = E5MessageBox.yesNo(
                    self, self.tr("Paste"),
                    self.tr("""<p>The clipboard image is larger than the"""
                            """ current image.<br/>Paste as new image?</p>"""))
                if res:
                    self.editPasteAsNew()
                return
            elif not pasting:
                self.__isPasting = True
                self.__clipboardSize = img.size()
            else:
                cmd = IconEditCommand(self, self.tr("Paste Clipboard"),
                                      self.__image)
                self.__markImage.fill(self.NoMarkColor.rgba())
                painter = QPainter(self.__image)
                painter.setPen(self.penColor())
                painter.setCompositionMode(self.__compositingMode)
                painter.drawImage(self.__pasteRect.x(), self.__pasteRect.y(),
                                  img, 0, 0,
                                  self.__pasteRect.width() + 1,
                                  self.__pasteRect.height() + 1)

                self.__undoStack.push(cmd)
                cmd.setAfterImage(self.__image)

                self.__updateImageRect(
                    self.__pasteRect.topLeft(),
                    self.__pasteRect.bottomRight() + QPoint(1, 1))
        else:
            E5MessageBox.warning(
                self, self.tr("Pasting Image"),
                self.tr("""Invalid image data in clipboard."""))

    def editPasteAsNew(self):
        """
        Public slot to paste the clipboard as a new image.
        """
        img, ok = self.__clipboardImage()
        if ok:
            cmd = IconEditCommand(self,
                                  self.tr("Paste Clipboard as New Image"),
                                  self.__image)
            self.setIconImage(img)
            self.setDirty(True)
            self.__undoStack.push(cmd)
            cmd.setAfterImage(self.__image)

    def editSelectAll(self):
        """
        Public slot to select the complete image.
        """
        self.__unMark()

        self.__startPos = QPoint(0, 0)
        self.__endPos = QPoint(self.rect().bottomRight())
        self.__markImage.fill(self.MarkColor.rgba())
        self.__selRect = self.__image.rect()
        self.__selectionAvailable = True
        self.selectionAvailable.emit(True)

        self.update()

    def editClear(self):
        """
        Public slot to clear the image.
        """
        self.__unMark()

        cmd = IconEditCommand(self, self.tr("Clear Image"), self.__image)
        self.__image.fill(qRgba(0, 0, 0, 0))
        self.update()
        self.setDirty(True)
        self.__undoStack.push(cmd)
        cmd.setAfterImage(self.__image)

    def editResize(self):
        """
        Public slot to resize the image.
        """
        from .IconSizeDialog import IconSizeDialog
        dlg = IconSizeDialog(self.__image.width(), self.__image.height())
        res = dlg.exec_()
        if res == QDialog.Accepted:
            newWidth, newHeight = dlg.getData()
            if newWidth != self.__image.width() or \
                    newHeight != self.__image.height():
                cmd = IconEditCommand(self, self.tr("Resize Image"),
                                      self.__image)
                img = self.__image.scaled(newWidth, newHeight,
                                          Qt.IgnoreAspectRatio,
                                          Qt.SmoothTransformation)
                self.setIconImage(img)
                self.setDirty(True)
                self.__undoStack.push(cmd)
                cmd.setAfterImage(self.__image)

    def editNew(self):
        """
        Public slot to generate a new, empty image.
        """
        from .IconSizeDialog import IconSizeDialog
        dlg = IconSizeDialog(self.__image.width(), self.__image.height())
        res = dlg.exec_()
        if res == QDialog.Accepted:
            width, height = dlg.getData()
            img = QImage(width, height, QImage.Format_ARGB32)
            img.fill(qRgba(0, 0, 0, 0))
            self.setIconImage(img)

    def grayScale(self):
        """
        Public slot to convert the image to gray preserving transparency.
        """
        cmd = IconEditCommand(self, self.tr("Convert to Grayscale"),
                              self.__image)
        for x in range(self.__image.width()):
            for y in range(self.__image.height()):
                col = self.__image.pixel(x, y)
                if col != qRgba(0, 0, 0, 0):
                    gray = qGray(col)
                    self.__image.setPixel(x, y,
                                          qRgba(gray, gray, gray, qAlpha(col)))
        self.update()
        self.setDirty(True)
        self.__undoStack.push(cmd)
        cmd.setAfterImage(self.__image)

    def editUndo(self):
        """
        Public slot to perform an undo operation.
        """
        if self.__undoStack.canUndo():
            self.__undoStack.undo()

    def editRedo(self):
        """
        Public slot to perform a redo operation.
        """
        if self.__undoStack.canRedo():
            self.__undoStack.redo()

    def canUndo(self):
        """
        Public method to return the undo status.
        
        @return flag indicating the availability of undo (boolean)
        """
        return self.__undoStack.canUndo()

    def canRedo(self):
        """
        Public method to return the redo status.
        
        @return flag indicating the availability of redo (boolean)
        """
        return self.__undoStack.canRedo()

    def __cleanChanged(self, clean):
        """
        Private slot to handle the undo stack clean state change.
        
        @param clean flag indicating the clean state (boolean)
        """
        self.setDirty(not clean)

    def shutdown(self):
        """
        Public slot to perform some shutdown actions.
        """
        self.__undoStack.canRedoChanged.disconnect(self.canRedoChanged)
        self.__undoStack.canUndoChanged.disconnect(self.canUndoChanged)
        self.__undoStack.cleanChanged.disconnect(self.__cleanChanged)

    def isSelectionAvailable(self):
        """
        Public method to check the availability of a selection.
        
        @return flag indicating the availability of a selection (boolean)
        """
        return self.__selectionAvailable
Esempio n. 26
0
    def paintEvent(self, e):
        self.painter.begin(self)

        # 绘制图片内容
        self.painter.drawPixmap(self.rect(), self.pixmap,
                                self.pmapShowAreaRect)

        # 绘制图片区域预览
        self.painter.setPen(QColor(0, 0, 0))
        scale = min(self.width() / self.pixmap.width() / 5,
                    self.height() / self.pixmap.height() / 5)
        self.pmapPreRect = QRect(0, 0,
                                 self.pixmap.width() * scale,
                                 self.pixmap.height() * scale)
        margin = int(min(self.width(), self.height()) / 16)
        self.pmapPreRect.moveTopRight(QPoint(self.width() - margin, margin))
        self.painter.drawRect(self.pmapPreRect)

        # 绘制图片展示区域预览
        self.painter.setPen(QColor(255, 0, 0))
        pmapprerect = self.pmapPreRect.getRect()
        pmapshowarearect = self.pmapShowAreaRect.getRect()
        x = pmapprerect[0] + self.pmapPreRect.width(
        ) * pmapshowarearect[0] / self.pixmap.width()
        y = pmapprerect[1] + self.pmapPreRect.height(
        ) * pmapshowarearect[1] / self.pixmap.height()
        w = scale * self.pmapShowAreaRect.width()
        h = scale * self.pmapShowAreaRect.height()
        self.pmapShowAreaPreRect = QRect(x, y, w, h)
        self.painter.drawRect(self.pmapShowAreaPreRect)

        self.dragAreaRect = QRect(
            self.pmapPreRect.x() - self.pmapShowAreaPreRect.width(),
            self.pmapPreRect.y() - self.pmapShowAreaPreRect.height(),
            self.pmapShowAreaPreRect.width() + self.pmapPreRect.width(),
            self.pmapShowAreaPreRect.height() + self.pmapPreRect.height())

        # 绘制缩放中心点标线
        self.painter.setPen(QColor(255, 0, 0))
        self.painter.drawLine(self.width() / 3,
                              self.height() / 2,
                              self.width() / 3 * 2,
                              self.height() / 2)
        self.painter.drawLine(self.width() / 2,
                              self.height() / 3,
                              self.width() / 2,
                              self.height() / 3 * 2)

        # 绘制鼠标位置标线
        if self.labeling:
            self.painter.setPen(QColor(0, 0, 0))
            self.painter.drawLine(self.mousex, 0, self.mousex, self.height())
            self.painter.drawLine(0, self.mousey, self.width(), self.mousey)

        # 绘制正在编辑中的label位置
        if self.templabel:
            for i in range(int(len(self.templabel) / 2)):
                imagex, imagey = self.templabel[0 +
                                                2 * i], self.templabel[1 +
                                                                       2 * i]
                if self.pmapShowAreaRect.contains(imagex, imagey):
                    widgetx, widgety = self.imageXY2WidgetXY(imagex, imagey)
                    self.painter.setPen(QPen(Qt.red, 5))
                    self.painter.drawPoint(widgetx, widgety)

                    pen = QPen(Qt.black, 2, Qt.SolidLine)
                    pen.setStyle(Qt.DashDotDotLine)
                    self.painter.setPen(pen)
                    self.painter.drawLine(widgetx, 0, widgetx, self.height())
                    self.painter.drawLine(0, widgety, self.width(), widgety)

        # 绘制已标记内容
        self.deleteRects.clear()
        self.textRects.clear()

        self.painter.setPen(QColor(168, 34, 3))
        self.painter.setFont(QFont('Decorative', 12))
        metrics = self.painter.fontMetrics()
        deleteRectWidth, deleteRectHeight = metrics.height(
        ) * 1.2, metrics.height() * 1.2

        separatorheight = margin / 10

        pmapprerect = self.pmapPreRect.getRect()
        topRightx, topRighty = self.width(
        ) - margin, pmapprerect[1] + pmapprerect[3] + margin / 4
        for i in range(len(self.labels)):
            label = self.labels[i]
            # 绘制文字展示信息
            text = label[4]
            deleteRect = QRect(
                topRightx - deleteRectWidth,
                topRighty + (deleteRectHeight + separatorheight) * i,
                deleteRectWidth, deleteRectHeight)
            self.painter.drawRect(deleteRect)
            self.painter.drawLine(deleteRect.topLeft(),
                                  deleteRect.bottomRight())
            self.painter.drawLine(deleteRect.topRight(),
                                  deleteRect.bottomLeft())
            self.deleteRects.append(deleteRect)

            deleterect = deleteRect.getRect()
            textWidth, textHeight = metrics.width(text), metrics.height()
            textRect = QRect(deleterect[0] - textWidth - metrics.height(),
                             deleterect[1], textWidth + metrics.height(),
                             deleterect[3])
            self.painter.drawRect(textRect)
            self.painter.drawText(textRect, Qt.AlignCenter, text)
            self.textRects.append(textRect)
            # 在图片上绘制标签矩形框
            labelPixmapX, labelPixmapY, labelPixmapWidth, labelPixmapHeight = label[:
                                                                                    4]
            labelPixmapRect = QRect(labelPixmapX, labelPixmapY,
                                    labelPixmapWidth, labelPixmapHeight)
            intersectedRect = self.pmapShowAreaRect.intersected(
                labelPixmapRect)
            if intersectedRect:
                pixmapTopLeftPoint, pixmapBottomRightPoint = intersectedRect.topLeft(
                ), intersectedRect.bottomRight()
                widgetTopLeftPointX, widgetTopLeftPointY = self.imageXY2WidgetXY(
                    pixmapTopLeftPoint.x(), pixmapTopLeftPoint.y())
                widgetTopLeftPoint = QPoint(widgetTopLeftPointX,
                                            widgetTopLeftPointY)
                widgetBottomRightPointX, widgetBottomRightPointY = self.imageXY2WidgetXY(
                    pixmapBottomRightPoint.x(), pixmapBottomRightPoint.y())
                widgetBottomRightPoint = QPoint(widgetBottomRightPointX,
                                                widgetBottomRightPointY)
                labelRect = QRect(widgetTopLeftPoint, widgetBottomRightPoint)
                self.painter.drawRect(labelRect)
                # 绘制标签名
                labelrect = labelRect.getRect()
                textRect1 = QRect(labelrect[0], labelrect[1] - textHeight,
                                  textWidth, textHeight)
                # self.painter.drawRect(textRect1)
                self.painter.drawText(textRect1, Qt.AlignCenter, text)

        self.painter.end()
Esempio n. 27
0
def rect_to_points(r: QRect) -> Tuple[QPoint, QPoint]:
    lt, rb = r.topLeft(), r.bottomRight()
    return lt, rb
Esempio n. 28
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)
Esempio n. 29
0
    def paint(self, painter, option, index):
        dlg = index.model().data(index, Qt.DisplayRole)
        painter.setRenderHint(QPainter.Antialiasing)
        color = QColor(Qt.white)
        if option.state & QStyle.State_MouseOver:
            color = QColor(variables.HIGHLIGHT_COLOR)
            painter.setPen(QPen(color))
            painter.setBrush(QBrush(color))
            painter.drawRect(option.rect)
        painter.setPen(Qt.black)
        painter.setBrush(Qt.NoBrush)
        painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())
        doc = QTextDocument(dlg.ip)
        doc.setDocumentMargin(0)
        doc.setDefaultFont(variables.font)
        textrect = QRect(option.rect)
        textrect = textrect.marginsRemoved(variables.IP_PADDING)
        textrect.setHeight(int(doc.size().height()))
        textrect.setWidth(int(doc.size().width()))
        offset = textrect.marginsAdded(variables.IP_PADDING).height()
        painter.setPen(Qt.black)
        painter.setFont(variables.font)
        painter.translate(textrect.x(), textrect.y())
        textrectf = QRectF(textrect)
        textrectf.moveTo(0, 0)
        doc.drawContents(painter, textrectf)
        painter.translate(-textrect.x(), -textrect.y())
        string = ""
        if dlg.user == variables.USER_ME:
            string += "You: "
        print(dlg.msg)
        string += dlg.msg
        fm = QFontMetrics(variables.font_small)
        textrect = QRect(option.rect)
        textrect.moveTop(textrect.y() + offset)
        textrect = textrect.marginsRemoved(variables.MSG_PADDING)
        textrect.setHeight(fm.lineSpacing())
        spainter = QStylePainter(painter.device(), QWidget())
        spainter.setRenderHint(QPainter.Antialiasing)
        if fm.horizontalAdvance(string) > textrect.width():
            fade = QLinearGradient(variables.MSG_PADDING.left() + textrect.width()* 0.9, 0, variables.MSG_PADDING.left() + textrect.width(), 0)
            fade.setSpread(QGradient.PadSpread)
            fade.setColorAt(0, Qt.darkGray)
            fade.setColorAt(1, color)
            pal = QPalette()
            pal.setBrush(QPalette.Text, QBrush(fade))
            spainter.setFont(variables.font_small)
            spainter.drawItemText(textrect, Qt.TextSingleLine, pal, True, string, QPalette.Text)
        else:
            spainter.setPen(Qt.darkGray)
            spainter.setFont(variables.font_small)
            spainter.drawText(textrect, Qt.TextSingleLine, string)
        p1 = textrect.bottomRight() + QPoint(36, -int(textrect.height() / 2))
        if dlg.status == variables.STATUS_UNREAD:
            spainter.setPen(Qt.NoPen)
            spainter.setBrush(QColor(variables.STATUS_COLOR))
            spainter.drawEllipse(p1, 7, 7)
        elif dlg.status == variables.STATUS_UNDELIVERED:
            pen = QPen(QColor(variables.STATUS_COLOR))
            pen.setWidth(2)
            spainter.setPen(pen)
            spainter.setBrush(Qt.NoBrush)
            spainter.drawEllipse(p1, 7, 7)
            spainter.drawLine(p1, p1 + QPoint(0, -5))
            spainter.drawLine(p1, p1 + QPoint(3, 0))
        elif dlg.status == variables.STATUS_NEW:
            pen = QPen(QColor(variables.STATUS_NEW_COLOR))
            pen.setWidth(5)
            spainter.setPen(pen)
            spainter.setBrush(Qt.NoBrush)
            spainter.drawEllipse(p1, 7, 7)
        #painter.translate(-textrect.x(), -textrect.y())

        '''doc = QTextDocument(str)
Esempio n. 30
0
    def drawMagnifier(self):
        # First, calculate the magnifier position due to the mouse position
        watchAreaWidth = 16
        watchAreaHeight = 16
        watchAreaPixmap = QPixmap()

        cursor_pos = self.mousePoint

        watchArea = QRect(
            QPoint(cursor_pos.x() - watchAreaWidth / 2,
                   cursor_pos.y() - watchAreaHeight / 2),
            QPoint(cursor_pos.x() + watchAreaWidth / 2,
                   cursor_pos.y() + watchAreaHeight / 2))
        if watchArea.left() < 0:
            watchArea.moveLeft(0)
            watchArea.moveRight(watchAreaWidth)
        if self.mousePoint.x() + watchAreaWidth / 2 >= self.screenPixel.width(
        ):
            watchArea.moveRight(self.screenPixel.width() - 1)
            watchArea.moveLeft(watchArea.right() - watchAreaWidth)
        if self.mousePoint.y() - watchAreaHeight / 2 < 0:
            watchArea.moveTop(0)
            watchArea.moveBottom(watchAreaHeight)
        if self.mousePoint.y(
        ) + watchAreaHeight / 2 >= self.screenPixel.height():
            watchArea.moveBottom(self.screenPixel.height() - 1)
            watchArea.moveTop(watchArea.bottom() - watchAreaHeight)

        # tricks to solve the hidpi impact on QCursor.pos()
        watchArea.setTopLeft(
            QPoint(watchArea.topLeft().x() * self.scale,
                   watchArea.topLeft().y() * self.scale))
        watchArea.setBottomRight(
            QPoint(watchArea.bottomRight().x() * self.scale,
                   watchArea.bottomRight().y() * self.scale))
        watchAreaPixmap = self.screenPixel.copy(watchArea)

        # second, calculate the magnifier area
        magnifierAreaWidth = watchAreaWidth * 10
        magnifierAreaHeight = watchAreaHeight * 10
        fontAreaHeight = 40

        cursorSize = 24
        magnifierArea = QRectF(
            QPoint(QCursor.pos().x() + cursorSize,
                   QCursor.pos().y() + cursorSize),
            QPoint(QCursor.pos().x() + cursorSize + magnifierAreaWidth,
                   QCursor.pos().y() + cursorSize + magnifierAreaHeight))
        if magnifierArea.right() >= self.screenPixel.width():
            magnifierArea.moveLeft(QCursor.pos().x() - magnifierAreaWidth -
                                   cursorSize / 2)
        if magnifierArea.bottom() + fontAreaHeight >= self.screenPixel.height(
        ):
            magnifierArea.moveTop(QCursor.pos().y() - magnifierAreaHeight -
                                  cursorSize / 2 - fontAreaHeight)

        # third, draw the watch area to magnifier area
        watchAreaScaled = watchAreaPixmap.scaled(
            QSize(magnifierAreaWidth * self.scale,
                  magnifierAreaHeight * self.scale))
        magnifierPixmap = self.graphicsScene.addPixmap(watchAreaScaled)
        magnifierPixmap.setOffset(magnifierArea.topLeft())

        # then draw lines and text
        self.graphicsScene.addRect(QRectF(magnifierArea),
                                   QPen(QColor(255, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.center().x(), magnifierArea.top()),
                   QPointF(magnifierArea.center().x(),
                           magnifierArea.bottom())),
            QPen(QColor(0, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.left(),
                           magnifierArea.center().y()),
                   QPointF(magnifierArea.right(),
                           magnifierArea.center().y())),
            QPen(QColor(0, 255, 255), 2))

        # get the rgb of mouse point
        pointRgb = QColor(self.screenPixel.toImage().pixel(self.mousePoint))

        # draw information
        self.graphicsScene.addRect(
            QRectF(
                magnifierArea.bottomLeft(),
                magnifierArea.bottomRight() + QPoint(0, fontAreaHeight + 30)),
            Qt.black, QBrush(Qt.black))
        rgbInfo = self.graphicsScene.addSimpleText(
            ' Rgb: ({0}, {1}, {2})'.format(pointRgb.red(), pointRgb.green(),
                                           pointRgb.blue()))
        rgbInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 5))
        rgbInfo.setPen(QPen(QColor(255, 255, 255), 2))

        rect = self.selectedArea.normalized()
        sizeInfo = self.graphicsScene.addSimpleText(' Size: {0} x {1}'.format(
            rect.width() * self.scale,
            rect.height() * self.scale))
        sizeInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 15) +
                        QPoint(0, fontAreaHeight / 2))
        sizeInfo.setPen(QPen(QColor(255, 255, 255), 2))
Esempio n. 31
0
class Screenshot(QGraphicsView):
    """ Main Class """

    screen_shot_grabed = pyqtSignal(QImage)
    widget_closed = pyqtSignal()

    def __init__(self, flags=constant.DEFAULT, parent=None):
        """
        flags: binary flags. see the flags in the constant.py
        """
        super().__init__(parent)

        # Init
        self.penColorNow = QColor(PENCOLOR)
        self.penSizeNow = PENSIZE
        self.fontNow = QFont('Sans')
        self.clipboard = QApplication.clipboard()

        self.drawListResult = [
        ]  # draw list that sure to be drew, [action, coord]
        self.drawListProcess = None  # the process to the result
        self.selectedArea = QRect(
        )  # a QRect instance which stands for the selected area
        self.selectedAreaRaw = QRect()
        self.mousePosition = MousePosition.OUTSIDE_AREA  # mouse position
        self.screenPixel = None
        self.textRect = None

        self.mousePressed = False
        self.action = ACTION_SELECT
        self.mousePoint = self.cursor().pos()

        self.startX, self.startY = 0, 0  # the point where you start
        self.endX, self.endY = 0, 0  # the point where you end
        self.pointPath = QPainterPath(
        )  # the point mouse passes, used by draw free line
        self.itemsToRemove = [
        ]  # the items that should not draw on screenshot picture
        self.textPosition = None

        # result
        self.target_img = None

        # Init window
        self.getscreenshot()
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)

        self.setMouseTracking(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setContentsMargins(0, 0, 0, 0)
        self.setStyleSheet("QGraphicsView { border-style: none; }")

        self.tooBar = MyToolBar(flags, self)
        self.tooBar.trigger.connect(self.changeAction)

        self.penSetBar = None
        if flags & constant.RECT or flags & constant.ELLIPSE or flags & constant.LINE or flags & constant.FREEPEN \
                or flags & constant.ARROW or flags & constant.TEXT:
            self.penSetBar = PenSetWidget(self)
            self.penSetBar.penSizeTrigger.connect(self.changePenSize)
            self.penSetBar.penColorTrigger.connect(self.changePenColor)
            self.penSetBar.fontChangeTrigger.connect(self.changeFont)

        self.textInput = TextInput(self)
        self.textInput.inputChanged.connect(self.textChange)
        self.textInput.cancelPressed.connect(self.cancelInput)
        self.textInput.okPressed.connect(self.okInput)

        self.graphicsScene = QGraphicsScene(0, 0, self.screenPixel.width(),
                                            self.screenPixel.height())

        self.show()
        self.setScene(self.graphicsScene)
        self.windowHandle().setScreen(QGuiApplication.screenAt(QCursor.pos()))
        self.scale = self.get_scale()
        # self.setFixedSize(self.screenPixel.width(), self.screenPixel.height())
        self.setGeometry(QGuiApplication.screenAt(QCursor.pos()).geometry())
        self.showFullScreen()
        self.redraw()

        QShortcut(QKeySequence('ctrl+s'),
                  self).activated.connect(self.saveScreenshot)
        QShortcut(QKeySequence('esc'), self).activated.connect(self.close)

    @staticmethod
    def take_screenshot(flags):
        loop = QEventLoop()
        screen_shot = Screenshot(flags)
        screen_shot.show()
        screen_shot.widget_closed.connect(loop.quit)

        loop.exec()
        img = screen_shot.target_img
        return img

    def getscreenshot(self):
        screen = QGuiApplication.screenAt(QCursor.pos())
        self.screenPixel = screen.grabWindow(0)

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if event.button() != Qt.LeftButton:
            return

        if self.action is None:
            self.action = ACTION_SELECT

        self.startX, self.startY = event.x(), event.y()

        if self.action == ACTION_SELECT:
            if self.mousePosition == MousePosition.OUTSIDE_AREA:
                self.mousePressed = True
                self.selectedArea = QRect()
                self.selectedArea.setTopLeft(QPoint(event.x(), event.y()))
                self.selectedArea.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            elif self.mousePosition == MousePosition.INSIDE_AREA:
                self.mousePressed = True
            else:
                pass
        elif self.action == ACTION_MOVE_SELECTED:
            if self.mousePosition == MousePosition.OUTSIDE_AREA:
                self.action = ACTION_SELECT
                self.selectedArea = QRect()
                self.selectedArea.setTopLeft(QPoint(event.x(), event.y()))
                self.selectedArea.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            self.mousePressed = True
        elif self.action in DRAW_ACTION:
            self.mousePressed = True
            if self.action == ACTION_FREEPEN:
                self.pointPath = QPainterPath()
                self.pointPath.moveTo(QPoint(event.x(), event.y()))
            elif self.action == ACTION_TEXT:
                if self.textPosition is None:
                    self.textPosition = QPoint(event.x(), event.y())
                    self.textRect = None
                    self.redraw()

    def mouseMoveEvent(self, event: QMouseEvent):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        self.mousePoint = QPoint(event.globalPos().x(), event.globalPos().y())

        if self.action is None:
            self.action = ACTION_SELECT

        if not self.mousePressed:
            point = QPoint(event.x(), event.y())
            self.detectMousePosition(point)
            self.setCursorStyle()
            self.redraw()
        else:
            self.endX, self.endY = event.x(), event.y()

            # if self.mousePosition != OUTSIDE_AREA:
            #    self.action = ACTION_MOVE_SELECTED

            if self.action == ACTION_SELECT:
                self.selectedArea.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            elif self.action == ACTION_MOVE_SELECTED:
                self.selectedArea = QRect(self.selectedAreaRaw)

                if self.mousePosition == MousePosition.INSIDE_AREA:
                    moveToX = event.x() - self.startX + self.selectedArea.left(
                    )
                    moveToY = event.y() - self.startY + self.selectedArea.top()
                    if 0 <= moveToX <= self.screenPixel.width(
                    ) - 1 - self.selectedArea.width():
                        self.selectedArea.moveLeft(moveToX)
                    if 0 <= moveToY <= self.screenPixel.height(
                    ) - 1 - self.selectedArea.height():
                        self.selectedArea.moveTop(moveToY)
                    self.selectedArea = self.selectedArea.normalized()
                    self.selectedAreaRaw = QRect(self.selectedArea)
                    self.startX, self.startY = event.x(), event.y()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_LEFT_SIDE:
                    moveToX = event.x() - self.startX + self.selectedArea.left(
                    )
                    if moveToX <= self.selectedArea.right():
                        self.selectedArea.setLeft(moveToX)
                        self.selectedArea = self.selectedArea.normalized()
                        self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE:
                    moveToX = event.x(
                    ) - self.startX + self.selectedArea.right()
                    self.selectedArea.setRight(moveToX)
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_UP_SIDE:
                    moveToY = event.y() - self.startY + self.selectedArea.top()
                    self.selectedArea.setTop(moveToY)
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_DOWN_SIDE:
                    moveToY = event.y(
                    ) - self.startY + self.selectedArea.bottom()
                    self.selectedArea.setBottom(moveToY)
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER:
                    moveToX = event.x() - self.startX + self.selectedArea.left(
                    )
                    moveToY = event.y() - self.startY + self.selectedArea.top()
                    self.selectedArea.setTopLeft(QPoint(moveToX, moveToY))
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER:
                    moveToX = event.x(
                    ) - self.startX + self.selectedArea.right()
                    moveToY = event.y(
                    ) - self.startY + self.selectedArea.bottom()
                    self.selectedArea.setBottomRight(QPoint(moveToX, moveToY))
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER:
                    moveToX = event.x(
                    ) - self.startX + self.selectedArea.right()
                    moveToY = event.y() - self.startY + self.selectedArea.top()
                    self.selectedArea.setTopRight(QPoint(moveToX, moveToY))
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER:
                    moveToX = event.x() - self.startX + self.selectedArea.left(
                    )
                    moveToY = event.y(
                    ) - self.startY + self.selectedArea.bottom()
                    self.selectedArea.setBottomLeft(QPoint(moveToX, moveToY))
                    self.redraw()
                else:
                    pass
            elif self.action == ACTION_RECT:
                self.drawRect(self.startX, self.startY, event.x(), event.y(),
                              False)
                self.redraw()
                pass
            elif self.action == ACTION_ELLIPSE:
                self.drawEllipse(self.startX, self.startY, event.x(),
                                 event.y(), False)
                self.redraw()
            elif self.action == ACTION_ARROW:
                self.drawArrow(self.startX, self.startY, event.x(), event.y(),
                               False)
                self.redraw()
            elif self.action == ACTION_LINE:
                self.drawLine(self.startX, self.startY, event.x(), event.y(),
                              False)
                self.redraw()
            elif self.action == ACTION_FREEPEN:
                y1, y2 = event.x(), event.y()
                rect = self.selectedArea.normalized()
                if y1 <= rect.left():
                    y1 = rect.left()
                elif y1 >= rect.right():
                    y1 = rect.right()

                if y2 <= rect.top():
                    y2 = rect.top()
                elif y2 >= rect.bottom():
                    y2 = rect.bottom()

                self.pointPath.lineTo(y1, y2)
                self.drawFreeLine(self.pointPath, False)
                self.redraw()

    def mouseReleaseEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if event.button() != Qt.LeftButton:
            return

        if self.mousePressed:
            self.mousePressed = False
            self.endX, self.endY = event.x(), event.y()

            if self.action == ACTION_SELECT:
                self.selectedArea.setBottomRight(QPoint(event.x(), event.y()))
                self.selectedAreaRaw = QRect(self.selectedArea)
                self.action = ACTION_MOVE_SELECTED
                self.redraw()
            elif self.action == ACTION_MOVE_SELECTED:
                self.selectedAreaRaw = QRect(self.selectedArea)
                self.redraw()
                # self.action = None
            elif self.action == ACTION_RECT:
                self.drawRect(self.startX, self.startY, event.x(), event.y(),
                              True)
                self.redraw()
            elif self.action == ACTION_ELLIPSE:
                self.drawEllipse(self.startX, self.startY, event.x(),
                                 event.y(), True)
                self.redraw()
            elif self.action == ACTION_ARROW:
                self.drawArrow(self.startX, self.startY, event.x(), event.y(),
                               True)
                self.redraw()
            elif self.action == ACTION_LINE:
                self.drawLine(self.startX, self.startY, event.x(), event.y(),
                              True)
                self.redraw()
            elif self.action == ACTION_FREEPEN:
                self.drawFreeLine(self.pointPath, True)
                self.redraw()

    def detectMousePosition(self, point):
        """
        :type point: QPoint
        :param point: the mouse position you want to check
        :return:
        """
        if self.selectedArea == QRect():
            self.mousePosition = MousePosition.OUTSIDE_AREA
            return

        if self.selectedArea.left() - ERRORRANGE <= point.x(
        ) <= self.selectedArea.left() and (self.selectedArea.top() - ERRORRANGE
                                           <= point.y() <=
                                           self.selectedArea.top()):
            self.mousePosition = MousePosition.ON_THE_TOP_LEFT_CORNER
        elif self.selectedArea.right() <= point.x() <= self.selectedArea.right(
        ) + ERRORRANGE and (self.selectedArea.top() - ERRORRANGE <= point.y()
                            <= self.selectedArea.top()):
            self.mousePosition = MousePosition.ON_THE_TOP_RIGHT_CORNER
        elif self.selectedArea.left() - ERRORRANGE <= point.x(
        ) <= self.selectedArea.left() and (
                self.selectedArea.bottom() <= point.y() <=
                self.selectedArea.bottom() + ERRORRANGE):
            self.mousePosition = MousePosition.ON_THE_BOTTOM_LEFT_CORNER
        elif self.selectedArea.right() <= point.x() <= self.selectedArea.right(
        ) + ERRORRANGE and (self.selectedArea.bottom() <= point.y() <=
                            self.selectedArea.bottom() + ERRORRANGE):
            self.mousePosition = MousePosition.ON_THE_BOTTOM_RIGHT_CORNER
        elif -ERRORRANGE <= point.x() - self.selectedArea.left() <= 0 and (
                self.selectedArea.topLeft().y() < point.y() <
                self.selectedArea.bottomLeft().y()):
            self.mousePosition = MousePosition.ON_THE_LEFT_SIDE
        elif 0 <= point.x() - self.selectedArea.right() <= ERRORRANGE and (
                self.selectedArea.topRight().y() < point.y() <
                self.selectedArea.bottomRight().y()):
            self.mousePosition = MousePosition.ON_THE_RIGHT_SIDE
        elif -ERRORRANGE <= point.y() - self.selectedArea.top() <= 0 and (
                self.selectedArea.topLeft().x() < point.x() <
                self.selectedArea.topRight().x()):
            self.mousePosition = MousePosition.ON_THE_UP_SIDE
        elif 0 <= point.y() - self.selectedArea.bottom() <= ERRORRANGE and (
                self.selectedArea.bottomLeft().x() < point.x() <
                self.selectedArea.bottomRight().x()):
            self.mousePosition = MousePosition.ON_THE_DOWN_SIDE
        elif not self.selectedArea.contains(point):
            self.mousePosition = MousePosition.OUTSIDE_AREA
        else:
            self.mousePosition = MousePosition.INSIDE_AREA

    def setCursorStyle(self):
        if self.action in DRAW_ACTION:
            self.setCursor(Qt.CrossCursor)
            return

        if self.mousePosition == MousePosition.ON_THE_LEFT_SIDE or \
                        self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE:

            self.setCursor(Qt.SizeHorCursor)
        elif self.mousePosition == MousePosition.ON_THE_UP_SIDE or \
                        self.mousePosition == MousePosition.ON_THE_DOWN_SIDE:

            self.setCursor(Qt.SizeVerCursor)
        elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER or \
                        self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER:

            self.setCursor(Qt.SizeFDiagCursor)
        elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER or \
                        self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER:

            self.setCursor(Qt.SizeBDiagCursor)
        elif self.mousePosition == MousePosition.OUTSIDE_AREA:
            self.setCursor(Qt.ArrowCursor)
        elif self.mousePosition == MousePosition.INSIDE_AREA:
            self.setCursor(Qt.OpenHandCursor)
        else:
            self.setCursor(Qt.ArrowCursor)
            pass

    def drawMagnifier(self):
        # First, calculate the magnifier position due to the mouse position
        watchAreaWidth = 16
        watchAreaHeight = 16
        watchAreaPixmap = QPixmap()

        cursor_pos = self.mousePoint

        watchArea = QRect(
            QPoint(cursor_pos.x() - watchAreaWidth / 2,
                   cursor_pos.y() - watchAreaHeight / 2),
            QPoint(cursor_pos.x() + watchAreaWidth / 2,
                   cursor_pos.y() + watchAreaHeight / 2))
        if watchArea.left() < 0:
            watchArea.moveLeft(0)
            watchArea.moveRight(watchAreaWidth)
        if self.mousePoint.x() + watchAreaWidth / 2 >= self.screenPixel.width(
        ):
            watchArea.moveRight(self.screenPixel.width() - 1)
            watchArea.moveLeft(watchArea.right() - watchAreaWidth)
        if self.mousePoint.y() - watchAreaHeight / 2 < 0:
            watchArea.moveTop(0)
            watchArea.moveBottom(watchAreaHeight)
        if self.mousePoint.y(
        ) + watchAreaHeight / 2 >= self.screenPixel.height():
            watchArea.moveBottom(self.screenPixel.height() - 1)
            watchArea.moveTop(watchArea.bottom() - watchAreaHeight)

        # tricks to solve the hidpi impact on QCursor.pos()
        watchArea.setTopLeft(
            QPoint(watchArea.topLeft().x() * self.scale,
                   watchArea.topLeft().y() * self.scale))
        watchArea.setBottomRight(
            QPoint(watchArea.bottomRight().x() * self.scale,
                   watchArea.bottomRight().y() * self.scale))
        watchAreaPixmap = self.screenPixel.copy(watchArea)

        # second, calculate the magnifier area
        magnifierAreaWidth = watchAreaWidth * 10
        magnifierAreaHeight = watchAreaHeight * 10
        fontAreaHeight = 40

        cursorSize = 24
        magnifierArea = QRectF(
            QPoint(QCursor.pos().x() + cursorSize,
                   QCursor.pos().y() + cursorSize),
            QPoint(QCursor.pos().x() + cursorSize + magnifierAreaWidth,
                   QCursor.pos().y() + cursorSize + magnifierAreaHeight))
        if magnifierArea.right() >= self.screenPixel.width():
            magnifierArea.moveLeft(QCursor.pos().x() - magnifierAreaWidth -
                                   cursorSize / 2)
        if magnifierArea.bottom() + fontAreaHeight >= self.screenPixel.height(
        ):
            magnifierArea.moveTop(QCursor.pos().y() - magnifierAreaHeight -
                                  cursorSize / 2 - fontAreaHeight)

        # third, draw the watch area to magnifier area
        watchAreaScaled = watchAreaPixmap.scaled(
            QSize(magnifierAreaWidth * self.scale,
                  magnifierAreaHeight * self.scale))
        magnifierPixmap = self.graphicsScene.addPixmap(watchAreaScaled)
        magnifierPixmap.setOffset(magnifierArea.topLeft())

        # then draw lines and text
        self.graphicsScene.addRect(QRectF(magnifierArea),
                                   QPen(QColor(255, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.center().x(), magnifierArea.top()),
                   QPointF(magnifierArea.center().x(),
                           magnifierArea.bottom())),
            QPen(QColor(0, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.left(),
                           magnifierArea.center().y()),
                   QPointF(magnifierArea.right(),
                           magnifierArea.center().y())),
            QPen(QColor(0, 255, 255), 2))

        # get the rgb of mouse point
        pointRgb = QColor(self.screenPixel.toImage().pixel(self.mousePoint))

        # draw information
        self.graphicsScene.addRect(
            QRectF(
                magnifierArea.bottomLeft(),
                magnifierArea.bottomRight() + QPoint(0, fontAreaHeight + 30)),
            Qt.black, QBrush(Qt.black))
        rgbInfo = self.graphicsScene.addSimpleText(
            ' Rgb: ({0}, {1}, {2})'.format(pointRgb.red(), pointRgb.green(),
                                           pointRgb.blue()))
        rgbInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 5))
        rgbInfo.setPen(QPen(QColor(255, 255, 255), 2))

        rect = self.selectedArea.normalized()
        sizeInfo = self.graphicsScene.addSimpleText(' Size: {0} x {1}'.format(
            rect.width() * self.scale,
            rect.height() * self.scale))
        sizeInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 15) +
                        QPoint(0, fontAreaHeight / 2))
        sizeInfo.setPen(QPen(QColor(255, 255, 255), 2))

    def get_scale(self):
        return self.devicePixelRatio()

    def saveScreenshot(self,
                       clipboard=False,
                       fileName='screenshot.png',
                       picType='png'):
        fullWindow = QRect(0, 0, self.width() - 1, self.height() - 1)
        selected = QRect(self.selectedArea)
        if selected.left() < 0:
            selected.setLeft(0)
        if selected.right() >= self.width():
            selected.setRight(self.width() - 1)
        if selected.top() < 0:
            selected.setTop(0)
        if selected.bottom() >= self.height():
            selected.setBottom(self.height() - 1)

        source = (fullWindow & selected)
        source.setTopLeft(
            QPoint(source.topLeft().x() * self.scale,
                   source.topLeft().y() * self.scale))
        source.setBottomRight(
            QPoint(source.bottomRight().x() * self.scale,
                   source.bottomRight().y() * self.scale))
        image = self.screenPixel.copy(source)
        image.setDevicePixelRatio(1)

        if clipboard:
            QGuiApplication.clipboard().setImage(QImage(image),
                                                 QClipboard.Clipboard)
        else:
            image.save(fileName, picType, 10)
        self.target_img = image
        self.screen_shot_grabed.emit(QImage(image))

    def redraw(self):
        self.graphicsScene.clear()

        # draw screenshot
        self.graphicsScene.addPixmap(self.screenPixel)

        # prepare for drawing selected area
        rect = QRectF(self.selectedArea)
        rect = rect.normalized()

        topLeftPoint = rect.topLeft()
        topRightPoint = rect.topRight()
        bottomLeftPoint = rect.bottomLeft()
        bottomRightPoint = rect.bottomRight()
        topMiddlePoint = (topLeftPoint + topRightPoint) / 2
        leftMiddlePoint = (topLeftPoint + bottomLeftPoint) / 2
        bottomMiddlePoint = (bottomLeftPoint + bottomRightPoint) / 2
        rightMiddlePoint = (topRightPoint + bottomRightPoint) / 2

        # draw the picture mask
        mask = QColor(0, 0, 0, 155)

        if self.selectedArea == QRect():
            self.graphicsScene.addRect(0, 0, self.screenPixel.width(),
                                       self.screenPixel.height(),
                                       QPen(Qt.NoPen), mask)
        else:
            self.graphicsScene.addRect(0, 0, self.screenPixel.width(),
                                       topRightPoint.y(), QPen(Qt.NoPen), mask)
            self.graphicsScene.addRect(0, topLeftPoint.y(), topLeftPoint.x(),
                                       rect.height(), QPen(Qt.NoPen), mask)
            self.graphicsScene.addRect(
                topRightPoint.x(), topRightPoint.y(),
                self.screenPixel.width() - topRightPoint.x(), rect.height(),
                QPen(Qt.NoPen), mask)
            self.graphicsScene.addRect(
                0, bottomLeftPoint.y(), self.screenPixel.width(),
                self.screenPixel.height() - bottomLeftPoint.y(),
                QPen(Qt.NoPen), mask)

        # draw the toolBar
        if self.action != ACTION_SELECT:
            spacing = 5
            # show the toolbar first, then move it to the correct position
            # because the width of it may be wrong if this is the first time it shows
            self.tooBar.show()

            dest = QPointF(rect.bottomRight() -
                           QPointF(self.tooBar.width(), 0) -
                           QPointF(spacing, -spacing))
            if dest.x() < spacing:
                dest.setX(spacing)
            pen_set_bar_height = self.penSetBar.height(
            ) if self.penSetBar is not None else 0
            if dest.y() + self.tooBar.height(
            ) + pen_set_bar_height >= self.height():
                if rect.top() - self.tooBar.height(
                ) - pen_set_bar_height < spacing:
                    dest.setY(rect.top() + spacing)
                else:
                    dest.setY(rect.top() - self.tooBar.height() -
                              pen_set_bar_height - spacing)

            self.tooBar.move(dest.toPoint())

            if self.penSetBar is not None:
                self.penSetBar.show()
                self.penSetBar.move(dest.toPoint() +
                                    QPoint(0,
                                           self.tooBar.height() + spacing))

                if self.action == ACTION_TEXT:
                    self.penSetBar.showFontWidget()
                else:
                    self.penSetBar.showPenWidget()
        else:
            self.tooBar.hide()

            if self.penSetBar is not None:
                self.penSetBar.hide()

        # draw the list
        for step in self.drawListResult:
            self.drawOneStep(step)

        if self.drawListProcess is not None:
            self.drawOneStep(self.drawListProcess)
            if self.action != ACTION_TEXT:
                self.drawListProcess = None

        if self.selectedArea != QRect():
            self.itemsToRemove = []

            # draw the selected rectangle
            pen = QPen(QColor(0, 255, 255), 2)
            self.itemsToRemove.append(self.graphicsScene.addRect(rect, pen))

            # draw the drag point
            radius = QPoint(3, 3)
            brush = QBrush(QColor(0, 255, 255))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(topLeftPoint - radius, topLeftPoint + radius), pen,
                    brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(topMiddlePoint - radius, topMiddlePoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(topRightPoint - radius, topRightPoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(leftMiddlePoint - radius, leftMiddlePoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(rightMiddlePoint - radius,
                           rightMiddlePoint + radius), pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(bottomLeftPoint - radius, bottomLeftPoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(bottomMiddlePoint - radius,
                           bottomMiddlePoint + radius), pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(bottomRightPoint - radius,
                           bottomRightPoint + radius), pen, brush))

        # draw the textedit
        if self.textPosition is not None:
            textSpacing = 50
            position = QPoint()
            if self.textPosition.x() + self.textInput.width(
            ) >= self.screenPixel.width():
                position.setX(self.textPosition.x() - self.textInput.width())
            else:
                position.setX(self.textPosition.x())

            if self.textRect is not None:
                if self.textPosition.y() + self.textInput.height(
                ) + self.textRect.height() >= self.screenPixel.height():
                    position.setY(self.textPosition.y() -
                                  self.textInput.height() -
                                  self.textRect.height())
                else:
                    position.setY(self.textPosition.y() +
                                  self.textRect.height())
            else:
                if self.textPosition.y() + self.textInput.height(
                ) >= self.screenPixel.height():
                    position.setY(self.textPosition.y() -
                                  self.textInput.height())
                else:
                    position.setY(self.textPosition.y())

            self.textInput.move(position)
            self.textInput.show()
            # self.textInput.getFocus()

        # draw the magnifier
        if self.action == ACTION_SELECT:
            self.drawMagnifier()
            if self.mousePressed:
                self.drawSizeInfo()

        if self.action == ACTION_MOVE_SELECTED:
            self.drawSizeInfo()

    # deal with every step in drawList
    def drawOneStep(self, step):
        """
        :type step: tuple
        """
        if step[0] == ACTION_RECT:
            self.graphicsScene.addRect(
                QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_ELLIPSE:
            self.graphicsScene.addEllipse(
                QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_ARROW:
            arrow = QPolygonF()

            linex = float(step[1] - step[3])
            liney = float(step[2] - step[4])
            line = sqrt(pow(linex, 2) + pow(liney, 2))

            # in case to divided by 0
            if line == 0:
                return

            sinAngel = liney / line
            cosAngel = linex / line

            # sideLength is the length of bottom side of the body of an arrow
            # arrowSize is the size of the head of an arrow, left and right
            # sides' size is arrowSize, and the bottom side's size is arrowSize / 2
            sideLength = step[5].width()
            arrowSize = 8
            bottomSize = arrowSize / 2

            tmpPoint = QPointF(step[3] + arrowSize * sideLength * cosAngel,
                               step[4] + arrowSize * sideLength * sinAngel)

            point1 = QPointF(step[1] + sideLength * sinAngel,
                             step[2] - sideLength * cosAngel)
            point2 = QPointF(step[1] - sideLength * sinAngel,
                             step[2] + sideLength * cosAngel)
            point3 = QPointF(tmpPoint.x() - sideLength * sinAngel,
                             tmpPoint.y() + sideLength * cosAngel)
            point4 = QPointF(tmpPoint.x() - bottomSize * sideLength * sinAngel,
                             tmpPoint.y() + bottomSize * sideLength * cosAngel)
            point5 = QPointF(step[3], step[4])
            point6 = QPointF(tmpPoint.x() + bottomSize * sideLength * sinAngel,
                             tmpPoint.y() - bottomSize * sideLength * cosAngel)
            point7 = QPointF(tmpPoint.x() + sideLength * sinAngel,
                             tmpPoint.y() - sideLength * cosAngel)

            arrow.append(point1)
            arrow.append(point2)
            arrow.append(point3)
            arrow.append(point4)
            arrow.append(point5)
            arrow.append(point6)
            arrow.append(point7)
            arrow.append(point1)

            self.graphicsScene.addPolygon(arrow, step[5], step[6])
        elif step[0] == ACTION_LINE:
            self.graphicsScene.addLine(
                QLineF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_FREEPEN:
            self.graphicsScene.addPath(step[1], step[2])
        elif step[0] == ACTION_TEXT:
            textAdd = self.graphicsScene.addSimpleText(step[1], step[2])
            textAdd.setPos(step[3])
            textAdd.setBrush(QBrush(step[4]))
            self.textRect = textAdd.boundingRect()

    # draw the size information on the top left corner
    def drawSizeInfo(self):
        sizeInfoAreaWidth = 200
        sizeInfoAreaHeight = 30
        spacing = 5
        rect = self.selectedArea.normalized()
        sizeInfoArea = QRect(rect.left(),
                             rect.top() - spacing - sizeInfoAreaHeight,
                             sizeInfoAreaWidth, sizeInfoAreaHeight)

        if sizeInfoArea.top() < 0:
            sizeInfoArea.moveTopLeft(rect.topLeft() + QPoint(spacing, spacing))
        if sizeInfoArea.right() >= self.screenPixel.width():
            sizeInfoArea.moveTopLeft(rect.topLeft() -
                                     QPoint(spacing, spacing) -
                                     QPoint(sizeInfoAreaWidth, 0))
        if sizeInfoArea.left() < spacing:
            sizeInfoArea.moveLeft(spacing)
        if sizeInfoArea.top() < spacing:
            sizeInfoArea.moveTop(spacing)

        self.itemsToRemove.append(
            self.graphicsScene.addRect(QRectF(sizeInfoArea), Qt.white,
                                       QBrush(Qt.black)))

        sizeInfo = self.graphicsScene.addSimpleText('  {0} x {1}'.format(
            rect.width() * self.scale,
            rect.height() * self.scale))
        sizeInfo.setPos(sizeInfoArea.topLeft() + QPoint(0, 2))
        sizeInfo.setPen(QPen(QColor(255, 255, 255), 2))
        self.itemsToRemove.append(sizeInfo)

    def drawRect(self, x1, x2, y1, y2, result):
        rect = self.selectedArea.normalized()
        tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized()
        resultRect = rect & tmpRect
        tmp = [
            ACTION_RECT,
            resultRect.topLeft().x(),
            resultRect.topLeft().y(),
            resultRect.bottomRight().x(),
            resultRect.bottomRight().y(),
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawEllipse(self, x1, x2, y1, y2, result):
        rect = self.selectedArea.normalized()
        tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized()
        resultRect = rect & tmpRect
        tmp = [
            ACTION_ELLIPSE,
            resultRect.topLeft().x(),
            resultRect.topLeft().y(),
            resultRect.bottomRight().x(),
            resultRect.bottomRight().y(),
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawArrow(self, x1, x2, y1, y2, result):
        rect = self.selectedArea.normalized()
        if y1 <= rect.left():
            y1 = rect.left()
        elif y1 >= rect.right():
            y1 = rect.right()

        if y2 <= rect.top():
            y2 = rect.top()
        elif y2 >= rect.bottom():
            y2 = rect.bottom()

        tmp = [
            ACTION_ARROW, x1, x2, y1, y2,
            QPen(QColor(self.penColorNow), int(self.penSizeNow)),
            QBrush(QColor(self.penColorNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawLine(self, x1, x2, y1, y2, result):
        rect = self.selectedArea.normalized()
        if y1 <= rect.left():
            y1 = rect.left()
        elif y1 >= rect.right():
            y1 = rect.right()

        if y2 <= rect.top():
            y2 = rect.top()
        elif y2 >= rect.bottom():
            y2 = rect.bottom()

        tmp = [
            ACTION_LINE, x1, x2, y1, y2,
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawFreeLine(self, pointPath, result):
        tmp = [
            ACTION_FREEPEN,
            QPainterPath(pointPath),
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def textChange(self):
        if self.textPosition is None:
            return
        self.text = self.textInput.getText()
        self.drawListProcess = [
            ACTION_TEXT,
            str(self.text),
            QFont(self.fontNow),
            QPoint(self.textPosition),
            QColor(self.penColorNow)
        ]
        self.redraw()

    def undoOperation(self):
        if len(self.drawListResult) == 0:
            self.action = ACTION_SELECT
            self.selectedArea = QRect()
            self.selectedAreaRaw = QRect()
            self.tooBar.hide()
            if self.penSetBar is not None:
                self.penSetBar.hide()
        else:
            self.drawListResult.pop()
        self.redraw()

    def saveOperation(self):
        filename = QFileDialog.getSaveFileName(self, 'Save file',
                                               './screenshot.png',
                                               '*.png;;*.jpg')
        if len(filename[0]) == 0:
            return
        else:
            self.saveScreenshot(False, filename[0], filename[1][2:])
            self.close()

    def close(self):
        self.widget_closed.emit()
        super().close()
        self.tooBar.close()
        if self.penSetBar is not None:
            self.penSetBar.close()

    def saveToClipboard(self):
        QApplication.clipboard().setText('Test in save function')

        self.saveScreenshot(True)
        self.close()

    # slots
    def changeAction(self, nextAction):
        QApplication.clipboard().setText('Test in changeAction function')

        if nextAction == ACTION_UNDO:
            self.undoOperation()
        elif nextAction == ACTION_SAVE:
            self.saveOperation()
        elif nextAction == ACTION_CANCEL:
            self.close()
        elif nextAction == ACTION_SURE:
            self.saveToClipboard()

        else:
            self.action = nextAction

        self.setFocus()

    def changePenSize(self, nextPenSize):
        self.penSizeNow = nextPenSize

    def changePenColor(self, nextPenColor):
        self.penColorNow = nextPenColor

    def cancelInput(self):
        self.drawListProcess = None
        self.textPosition = None
        self.textRect = None
        self.textInput.hide()
        self.textInput.clearText()
        self.redraw()

    def okInput(self):
        self.text = self.textInput.getText()
        self.drawListResult.append([
            ACTION_TEXT,
            str(self.text),
            QFont(self.fontNow),
            QPoint(self.textPosition),
            QColor(self.penColorNow)
        ])
        self.textPosition = None
        self.textRect = None
        self.textInput.hide()
        self.textInput.clearText()
        self.redraw()

    def changeFont(self, font):
        self.fontNow = font
Esempio n. 32
0
class IconEditorGrid(QWidget):
    """
    Class implementing the icon editor grid.
    
    @signal canRedoChanged(bool) emitted after the redo status has changed
    @signal canUndoChanged(bool) emitted after the undo status has changed
    @signal clipboardImageAvailable(bool) emitted to signal the availability
        of an image to be pasted
    @signal colorChanged(QColor) emitted after the drawing color was changed
    @signal imageChanged(bool) emitted after the image was modified
    @signal positionChanged(int, int) emitted after the cursor poition was
        changed
    @signal previewChanged(QPixmap) emitted to signal a new preview pixmap
    @signal selectionAvailable(bool) emitted to signal a change of the
        selection
    @signal sizeChanged(int, int) emitted after the size has been changed
    @signal zoomChanged(int) emitted to signal a change of the zoom value
    """
    canRedoChanged = pyqtSignal(bool)
    canUndoChanged = pyqtSignal(bool)
    clipboardImageAvailable = pyqtSignal(bool)
    colorChanged = pyqtSignal(QColor)
    imageChanged = pyqtSignal(bool)
    positionChanged = pyqtSignal(int, int)
    previewChanged = pyqtSignal(QPixmap)
    selectionAvailable = pyqtSignal(bool)
    sizeChanged = pyqtSignal(int, int)
    zoomChanged = pyqtSignal(int)
    
    Pencil = 1
    Rubber = 2
    Line = 3
    Rectangle = 4
    FilledRectangle = 5
    Circle = 6
    FilledCircle = 7
    Ellipse = 8
    FilledEllipse = 9
    Fill = 10
    ColorPicker = 11
    
    RectangleSelection = 20
    CircleSelection = 21
    
    MarkColor = QColor(255, 255, 255, 255)
    NoMarkColor = QColor(0, 0, 0, 0)
    
    ZoomMinimum = 100
    ZoomMaximum = 10000
    ZoomStep = 100
    ZoomDefault = 1200
    ZoomPercent = True
    
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super(IconEditorGrid, self).__init__(parent)
        
        self.setAttribute(Qt.WA_StaticContents)
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        
        self.__curColor = Qt.black
        self.__zoom = 12
        self.__curTool = self.Pencil
        self.__startPos = QPoint()
        self.__endPos = QPoint()
        self.__dirty = False
        self.__selecting = False
        self.__selRect = QRect()
        self.__isPasting = False
        self.__clipboardSize = QSize()
        self.__pasteRect = QRect()
        
        self.__undoStack = QUndoStack(self)
        self.__currentUndoCmd = None
        
        self.__image = QImage(32, 32, QImage.Format_ARGB32)
        self.__image.fill(qRgba(0, 0, 0, 0))
        self.__markImage = QImage(self.__image)
        self.__markImage.fill(self.NoMarkColor.rgba())
        
        self.__compositingMode = QPainter.CompositionMode_SourceOver
        self.__lastPos = (-1, -1)
        
        self.__gridEnabled = True
        self.__selectionAvailable = False
        
        self.__initCursors()
        self.__initUndoTexts()
        
        self.setMouseTracking(True)
        
        self.__undoStack.canRedoChanged.connect(self.canRedoChanged)
        self.__undoStack.canUndoChanged.connect(self.canUndoChanged)
        self.__undoStack.cleanChanged.connect(self.__cleanChanged)
        
        self.imageChanged.connect(self.__updatePreviewPixmap)
        QApplication.clipboard().dataChanged.connect(self.__checkClipboard)
        
        self.__checkClipboard()
    
    def __initCursors(self):
        """
        Private method to initialize the various cursors.
        """
        self.__normalCursor = QCursor(Qt.ArrowCursor)
        
        pix = QPixmap(":colorpicker-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__colorPickerCursor = QCursor(pix, 1, 21)
        
        pix = QPixmap(":paintbrush-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__paintCursor = QCursor(pix, 0, 19)
        
        pix = QPixmap(":fill-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__fillCursor = QCursor(pix, 3, 20)
        
        pix = QPixmap(":aim-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__aimCursor = QCursor(pix, 10, 10)
        
        pix = QPixmap(":eraser-cursor.xpm")
        mask = pix.createHeuristicMask()
        pix.setMask(mask)
        self.__rubberCursor = QCursor(pix, 1, 16)
    
    def __initUndoTexts(self):
        """
        Private method to initialize texts to be associated with undo commands
        for the various drawing tools.
        """
        self.__undoTexts = {
            self.Pencil: self.tr("Set Pixel"),
            self.Rubber: self.tr("Erase Pixel"),
            self.Line: self.tr("Draw Line"),
            self.Rectangle: self.tr("Draw Rectangle"),
            self.FilledRectangle: self.tr("Draw Filled Rectangle"),
            self.Circle: self.tr("Draw Circle"),
            self.FilledCircle: self.tr("Draw Filled Circle"),
            self.Ellipse: self.tr("Draw Ellipse"),
            self.FilledEllipse: self.tr("Draw Filled Ellipse"),
            self.Fill: self.tr("Fill Region"),
        }
    
    def isDirty(self):
        """
        Public method to check the dirty status.
        
        @return flag indicating a modified status (boolean)
        """
        return self.__dirty
    
    def setDirty(self, dirty, setCleanState=False):
        """
        Public slot to set the dirty flag.
        
        @param dirty flag indicating the new modification status (boolean)
        @param setCleanState flag indicating to set the undo stack to clean
            (boolean)
        """
        self.__dirty = dirty
        self.imageChanged.emit(dirty)
        
        if not dirty and setCleanState:
            self.__undoStack.setClean()
    
    def sizeHint(self):
        """
        Public method to report the size hint.
        
        @return size hint (QSize)
        """
        size = self.__zoom * self.__image.size()
        if self.__zoom >= 3 and self.__gridEnabled:
            size += QSize(1, 1)
        return size
    
    def setPenColor(self, newColor):
        """
        Public method to set the drawing color.
        
        @param newColor reference to the new color (QColor)
        """
        self.__curColor = QColor(newColor)
        self.colorChanged.emit(QColor(newColor))
    
    def penColor(self):
        """
        Public method to get the current drawing color.
        
        @return current drawing color (QColor)
        """
        return QColor(self.__curColor)
    
    def setCompositingMode(self, mode):
        """
        Public method to set the compositing mode.
        
        @param mode compositing mode to set (QPainter.CompositionMode)
        """
        self.__compositingMode = mode
    
    def compositingMode(self):
        """
        Public method to get the compositing mode.
        
        @return compositing mode (QPainter.CompositionMode)
        """
        return self.__compositingMode
    
    def setTool(self, tool):
        """
        Public method to set the current drawing tool.
        
        @param tool drawing tool to be used
            (IconEditorGrid.Pencil ... IconEditorGrid.CircleSelection)
        """
        self.__curTool = tool
        self.__lastPos = (-1, -1)
        
        if self.__curTool in [self.RectangleSelection, self.CircleSelection]:
            self.__selecting = True
        else:
            self.__selecting = False
        
        if self.__curTool in [self.RectangleSelection, self.CircleSelection,
                              self.Line, self.Rectangle, self.FilledRectangle,
                              self.Circle, self.FilledCircle,
                              self.Ellipse, self.FilledEllipse]:
            self.setCursor(self.__aimCursor)
        elif self.__curTool == self.Fill:
            self.setCursor(self.__fillCursor)
        elif self.__curTool == self.ColorPicker:
            self.setCursor(self.__colorPickerCursor)
        elif self.__curTool == self.Pencil:
            self.setCursor(self.__paintCursor)
        elif self.__curTool == self.Rubber:
            self.setCursor(self.__rubberCursor)
        else:
            self.setCursor(self.__normalCursor)
    
    def tool(self):
        """
        Public method to get the current drawing tool.
        
        @return current drawing tool
            (IconEditorGrid.Pencil ... IconEditorGrid.CircleSelection)
        """
        return self.__curTool
    
    def setIconImage(self, newImage, undoRedo=False, clearUndo=False):
        """
        Public method to set a new icon image.
        
        @param newImage reference to the new image (QImage)
        @keyparam undoRedo flag indicating an undo or redo operation (boolean)
        @keyparam clearUndo flag indicating to clear the undo stack (boolean)
        """
        if newImage != self.__image:
            self.__image = newImage.convertToFormat(QImage.Format_ARGB32)
            self.update()
            self.updateGeometry()
            self.resize(self.sizeHint())
            
            self.__markImage = QImage(self.__image)
            self.__markImage.fill(self.NoMarkColor.rgba())
            
            if undoRedo:
                self.setDirty(not self.__undoStack.isClean())
            else:
                self.setDirty(False)
            
            if clearUndo:
                self.__undoStack.clear()
            
            self.sizeChanged.emit(*self.iconSize())
    
    def iconImage(self):
        """
        Public method to get a copy of the icon image.
        
        @return copy of the icon image (QImage)
        """
        return QImage(self.__image)
    
    def iconSize(self):
        """
        Public method to get the size of the icon.
        
        @return width and height of the image as a tuple (integer, integer)
        """
        return self.__image.width(), self.__image.height()
    
    def setZoomFactor(self, newZoom):
        """
        Public method to set the zoom factor in percent.
        
        @param newZoom zoom factor (integer >= 100)
        """
        newZoom = max(100, newZoom)   # must not be less than 100
        if newZoom != self.__zoom:
            self.__zoom = newZoom // 100
            self.update()
            self.updateGeometry()
            self.resize(self.sizeHint())
            self.zoomChanged.emit(int(self.__zoom * 100))
    
    def zoomFactor(self):
        """
        Public method to get the current zoom factor in percent.
        
        @return zoom factor (integer)
        """
        return self.__zoom * 100
    
    def setGridEnabled(self, enable):
        """
        Public method to enable the display of grid lines.
        
        @param enable enabled status of the grid lines (boolean)
        """
        if enable != self.__gridEnabled:
            self.__gridEnabled = enable
            self.update()
    
    def isGridEnabled(self):
        """
        Public method to get the grid lines status.
        
        @return enabled status of the grid lines (boolean)
        """
        return self.__gridEnabled
    
    def paintEvent(self, evt):
        """
        Protected method called to repaint some of the widget.
        
        @param evt reference to the paint event object (QPaintEvent)
        """
        painter = QPainter(self)
        
        if self.__zoom >= 3 and self.__gridEnabled:
            painter.setPen(self.palette().windowText().color())
            i = 0
            while i <= self.__image.width():
                painter.drawLine(
                    self.__zoom * i, 0,
                    self.__zoom * i, self.__zoom * self.__image.height())
                i += 1
            j = 0
            while j <= self.__image.height():
                painter.drawLine(
                    0, self.__zoom * j,
                    self.__zoom * self.__image.width(), self.__zoom * j)
                j += 1
        
        col = QColor("#aaa")
        painter.setPen(Qt.DashLine)
        for i in range(0, self.__image.width()):
            for j in range(0, self.__image.height()):
                rect = self.__pixelRect(i, j)
                if evt.region().intersects(rect):
                    color = QColor.fromRgba(self.__image.pixel(i, j))
                    painter.fillRect(rect, QBrush(Qt.white))
                    painter.fillRect(QRect(rect.topLeft(), rect.center()), col)
                    painter.fillRect(QRect(rect.center(), rect.bottomRight()),
                                     col)
                    painter.fillRect(rect, QBrush(color))
                
                    if self.__isMarked(i, j):
                        painter.drawRect(rect.adjusted(0, 0, -1, -1))
        
        painter.end()
    
    def __pixelRect(self, i, j):
        """
        Private method to determine the rectangle for a given pixel coordinate.
        
        @param i x-coordinate of the pixel in the image (integer)
        @param j y-coordinate of the pixel in the image (integer)
        @return rectangle for the given pixel coordinates (QRect)
        """
        if self.__zoom >= 3 and self.__gridEnabled:
            return QRect(self.__zoom * i + 1, self.__zoom * j + 1,
                         self.__zoom - 1, self.__zoom - 1)
        else:
            return QRect(self.__zoom * i, self.__zoom * j,
                         self.__zoom, self.__zoom)
    
    def mousePressEvent(self, evt):
        """
        Protected method to handle mouse button press events.
        
        @param evt reference to the mouse event object (QMouseEvent)
        """
        if evt.button() == Qt.LeftButton:
            if self.__isPasting:
                self.__isPasting = False
                self.editPaste(True)
                self.__markImage.fill(self.NoMarkColor.rgba())
                self.update(self.__pasteRect)
                self.__pasteRect = QRect()
                return
            
            if self.__curTool == self.Pencil:
                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
                                      self.__image)
                self.__setImagePixel(evt.pos(), True)
                self.setDirty(True)
                self.__undoStack.push(cmd)
                self.__currentUndoCmd = cmd
            elif self.__curTool == self.Rubber:
                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
                                      self.__image)
                self.__setImagePixel(evt.pos(), False)
                self.setDirty(True)
                self.__undoStack.push(cmd)
                self.__currentUndoCmd = cmd
            elif self.__curTool == self.Fill:
                i, j = self.__imageCoordinates(evt.pos())
                col = QColor()
                col.setRgba(self.__image.pixel(i, j))
                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
                                      self.__image)
                self.__drawFlood(i, j, col)
                self.setDirty(True)
                self.__undoStack.push(cmd)
                cmd.setAfterImage(self.__image)
            elif self.__curTool == self.ColorPicker:
                i, j = self.__imageCoordinates(evt.pos())
                col = QColor()
                col.setRgba(self.__image.pixel(i, j))
                self.setPenColor(col)
            else:
                self.__unMark()
                self.__startPos = evt.pos()
                self.__endPos = evt.pos()
    
    def mouseMoveEvent(self, evt):
        """
        Protected method to handle mouse move events.
        
        @param evt reference to the mouse event object (QMouseEvent)
        """
        self.positionChanged.emit(*self.__imageCoordinates(evt.pos()))
        
        if self.__isPasting and not (evt.buttons() & Qt.LeftButton):
            self.__drawPasteRect(evt.pos())
            return
        
        if evt.buttons() & Qt.LeftButton:
            if self.__curTool == self.Pencil:
                self.__setImagePixel(evt.pos(), True)
                self.setDirty(True)
            elif self.__curTool == self.Rubber:
                self.__setImagePixel(evt.pos(), False)
                self.setDirty(True)
            elif self.__curTool in [self.Fill, self.ColorPicker]:
                pass    # do nothing
            else:
                self.__drawTool(evt.pos(), True)
    
    def mouseReleaseEvent(self, evt):
        """
        Protected method to handle mouse button release events.
        
        @param evt reference to the mouse event object (QMouseEvent)
        """
        if evt.button() == Qt.LeftButton:
            if self.__curTool in [self.Pencil, self.Rubber]:
                if self.__currentUndoCmd:
                    self.__currentUndoCmd.setAfterImage(self.__image)
                    self.__currentUndoCmd = None
            
            if self.__curTool not in [self.Pencil, self.Rubber,
                                      self.Fill, self.ColorPicker,
                                      self.RectangleSelection,
                                      self.CircleSelection]:
                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
                                      self.__image)
                if self.__drawTool(evt.pos(), False):
                    self.__undoStack.push(cmd)
                    cmd.setAfterImage(self.__image)
                    self.setDirty(True)
    
    def __setImagePixel(self, pos, opaque):
        """
        Private slot to set or erase a pixel.
        
        @param pos position of the pixel in the widget (QPoint)
        @param opaque flag indicating a set operation (boolean)
        """
        i, j = self.__imageCoordinates(pos)
        
        if self.__image.rect().contains(i, j) and (i, j) != self.__lastPos:
            if opaque:
                painter = QPainter(self.__image)
                painter.setPen(self.penColor())
                painter.setCompositionMode(self.__compositingMode)
                painter.drawPoint(i, j)
            else:
                self.__image.setPixel(i, j, qRgba(0, 0, 0, 0))
            self.__lastPos = (i, j)
        
            self.update(self.__pixelRect(i, j))
    
    def __imageCoordinates(self, pos):
        """
        Private method to convert from widget to image coordinates.
        
        @param pos widget coordinate (QPoint)
        @return tuple with the image coordinates (tuple of two integers)
        """
        i = pos.x() // self.__zoom
        j = pos.y() // self.__zoom
        return i, j
    
    def __drawPasteRect(self, pos):
        """
        Private slot to draw a rectangle for signaling a paste operation.
        
        @param pos widget position of the paste rectangle (QPoint)
        """
        self.__markImage.fill(self.NoMarkColor.rgba())
        if self.__pasteRect.isValid():
            self.__updateImageRect(
                self.__pasteRect.topLeft(),
                self.__pasteRect.bottomRight() + QPoint(1, 1))
        
        x, y = self.__imageCoordinates(pos)
        isize = self.__image.size()
        if x + self.__clipboardSize.width() <= isize.width():
            sx = self.__clipboardSize.width()
        else:
            sx = isize.width() - x
        if y + self.__clipboardSize.height() <= isize.height():
            sy = self.__clipboardSize.height()
        else:
            sy = isize.height() - y
        
        self.__pasteRect = QRect(QPoint(x, y), QSize(sx - 1, sy - 1))
        
        painter = QPainter(self.__markImage)
        painter.setPen(self.MarkColor)
        painter.drawRect(self.__pasteRect)
        painter.end()
        
        self.__updateImageRect(self.__pasteRect.topLeft(),
                               self.__pasteRect.bottomRight() + QPoint(1, 1))
    
    def __drawTool(self, pos, mark):
        """
        Private method to perform a draw operation depending of the current
        tool.
        
        @param pos widget coordinate to perform the draw operation at (QPoint)
        @param mark flag indicating a mark operation (boolean)
        @return flag indicating a successful draw (boolean)
        """
        self.__unMark()
        
        if mark:
            self.__endPos = QPoint(pos)
            drawColor = self.MarkColor
            img = self.__markImage
        else:
            drawColor = self.penColor()
            img = self.__image
        
        start = QPoint(*self.__imageCoordinates(self.__startPos))
        end = QPoint(*self.__imageCoordinates(pos))
        
        painter = QPainter(img)
        painter.setPen(drawColor)
        painter.setCompositionMode(self.__compositingMode)
        
        if self.__curTool == self.Line:
            painter.drawLine(start, end)
        
        elif self.__curTool in [self.Rectangle, self.FilledRectangle,
                                self.RectangleSelection]:
            left = min(start.x(), end.x())
            top = min(start.y(), end.y())
            right = max(start.x(), end.x())
            bottom = max(start.y(), end.y())
            if self.__curTool == self.RectangleSelection:
                painter.setBrush(QBrush(drawColor))
            if self.__curTool == self.FilledRectangle:
                for y in range(top, bottom + 1):
                    painter.drawLine(left, y, right, y)
            else:
                painter.drawRect(left, top, right - left, bottom - top)
            if self.__selecting:
                self.__selRect = QRect(
                    left, top, right - left + 1, bottom - top + 1)
                self.__selectionAvailable = True
                self.selectionAvailable.emit(True)
        
        elif self.__curTool in [self.Circle, self.FilledCircle,
                                self.CircleSelection]:
            r = max(abs(start.x() - end.x()), abs(start.y() - end.y()))
            if self.__curTool in [self.FilledCircle, self.CircleSelection]:
                painter.setBrush(QBrush(drawColor))
            painter.drawEllipse(start, r, r)
            if self.__selecting:
                self.__selRect = QRect(start.x() - r, start.y() - r,
                                       2 * r + 1, 2 * r + 1)
                self.__selectionAvailable = True
                self.selectionAvailable.emit(True)
        
        elif self.__curTool in [self.Ellipse, self.FilledEllipse]:
            r1 = abs(start.x() - end.x())
            r2 = abs(start.y() - end.y())
            if r1 == 0 or r2 == 0:
                return False
            if self.__curTool == self.FilledEllipse:
                painter.setBrush(QBrush(drawColor))
            painter.drawEllipse(start, r1, r2)
        
        painter.end()
        
        if self.__curTool in [self.Circle, self.FilledCircle,
                              self.Ellipse, self.FilledEllipse]:
            self.update()
        else:
            self.__updateRect(self.__startPos, pos)
        
        return True
    
    def __drawFlood(self, i, j, oldColor, doUpdate=True):
        """
        Private method to perform a flood fill operation.
        
        @param i x-value in image coordinates (integer)
        @param j y-value in image coordinates (integer)
        @param oldColor reference to the color at position i, j (QColor)
        @param doUpdate flag indicating an update is requested (boolean)
            (used for speed optimizations)
        """
        if not self.__image.rect().contains(i, j) or \
           self.__image.pixel(i, j) != oldColor.rgba() or \
           self.__image.pixel(i, j) == self.penColor().rgba():
            return
        
        self.__image.setPixel(i, j, self.penColor().rgba())
        
        self.__drawFlood(i, j - 1, oldColor, False)
        self.__drawFlood(i, j + 1, oldColor, False)
        self.__drawFlood(i - 1, j, oldColor, False)
        self.__drawFlood(i + 1, j, oldColor, False)
        
        if doUpdate:
            self.update()
    
    def __updateRect(self, pos1, pos2):
        """
        Private slot to update parts of the widget.
        
        @param pos1 top, left position for the update in widget coordinates
            (QPoint)
        @param pos2 bottom, right position for the update in widget
            coordinates (QPoint)
        """
        self.__updateImageRect(QPoint(*self.__imageCoordinates(pos1)),
                               QPoint(*self.__imageCoordinates(pos2)))
    
    def __updateImageRect(self, ipos1, ipos2):
        """
        Private slot to update parts of the widget.
        
        @param ipos1 top, left position for the update in image coordinates
            (QPoint)
        @param ipos2 bottom, right position for the update in image
            coordinates (QPoint)
        """
        r1 = self.__pixelRect(ipos1.x(), ipos1.y())
        r2 = self.__pixelRect(ipos2.x(), ipos2.y())
        
        left = min(r1.x(), r2.x())
        top = min(r1.y(), r2.y())
        right = max(r1.x() + r1.width(), r2.x() + r2.width())
        bottom = max(r1.y() + r1.height(), r2.y() + r2.height())
        self.update(left, top, right - left + 1, bottom - top + 1)
    
    def __unMark(self):
        """
        Private slot to remove the mark indicator.
        """
        self.__markImage.fill(self.NoMarkColor.rgba())
        if self.__curTool in [self.Circle, self.FilledCircle,
                              self.Ellipse, self.FilledEllipse,
                              self.CircleSelection]:
            self.update()
        else:
            self.__updateRect(self.__startPos, self.__endPos)
        
        if self.__selecting:
            self.__selRect = QRect()
            self.__selectionAvailable = False
            self.selectionAvailable.emit(False)
    
    def __isMarked(self, i, j):
        """
        Private method to check, if a pixel is marked.
        
        @param i x-value in image coordinates (integer)
        @param j y-value in image coordinates (integer)
        @return flag indicating a marked pixel (boolean)
        """
        return self.__markImage.pixel(i, j) == self.MarkColor.rgba()
    
    def __updatePreviewPixmap(self):
        """
        Private slot to generate and signal an updated preview pixmap.
        """
        p = QPixmap.fromImage(self.__image)
        self.previewChanged.emit(p)
    
    def previewPixmap(self):
        """
        Public method to generate a preview pixmap.
        
        @return preview pixmap (QPixmap)
        """
        p = QPixmap.fromImage(self.__image)
        return p
    
    def __checkClipboard(self):
        """
        Private slot to check, if the clipboard contains a valid image, and
        signal the result.
        """
        ok = self.__clipboardImage()[1]
        self.__clipboardImageAvailable = ok
        self.clipboardImageAvailable.emit(ok)
    
    def canPaste(self):
        """
        Public slot to check the availability of the paste operation.
        
        @return flag indicating availability of paste (boolean)
        """
        return self.__clipboardImageAvailable
    
    def __clipboardImage(self):
        """
        Private method to get an image from the clipboard.
        
        @return tuple with the image (QImage) and a flag indicating a
            valid image (boolean)
        """
        img = QApplication.clipboard().image()
        ok = not img.isNull()
        if ok:
            img = img.convertToFormat(QImage.Format_ARGB32)
        
        return img, ok
    
    def __getSelectionImage(self, cut):
        """
        Private method to get an image from the selection.
        
        @param cut flag indicating to cut the selection (boolean)
        @return image of the selection (QImage)
        """
        if cut:
            cmd = IconEditCommand(self, self.tr("Cut Selection"),
                                  self.__image)
        
        img = QImage(self.__selRect.size(), QImage.Format_ARGB32)
        img.fill(qRgba(0, 0, 0, 0))
        for i in range(0, self.__selRect.width()):
            for j in range(0, self.__selRect.height()):
                if self.__image.rect().contains(self.__selRect.x() + i,
                                                self.__selRect.y() + j):
                    if self.__isMarked(
                            self.__selRect.x() + i, self.__selRect.y() + j):
                        img.setPixel(i, j, self.__image.pixel(
                            self.__selRect.x() + i, self.__selRect.y() + j))
                        if cut:
                            self.__image.setPixel(self.__selRect.x() + i,
                                                  self.__selRect.y() + j,
                                                  qRgba(0, 0, 0, 0))
        
        if cut:
            self.__undoStack.push(cmd)
            cmd.setAfterImage(self.__image)
        
        self.__unMark()
        
        if cut:
            self.update(self.__selRect)
        
        return img
    
    def editCopy(self):
        """
        Public slot to copy the selection.
        """
        if self.__selRect.isValid():
            img = self.__getSelectionImage(False)
            QApplication.clipboard().setImage(img)
    
    def editCut(self):
        """
        Public slot to cut the selection.
        """
        if self.__selRect.isValid():
            img = self.__getSelectionImage(True)
            QApplication.clipboard().setImage(img)
    
    @pyqtSlot()
    def editPaste(self, pasting=False):
        """
        Public slot to paste an image from the clipboard.
        
        @param pasting flag indicating part two of the paste operation
            (boolean)
        """
        img, ok = self.__clipboardImage()
        if ok:
            if img.width() > self.__image.width() or \
                    img.height() > self.__image.height():
                res = E5MessageBox.yesNo(
                    self,
                    self.tr("Paste"),
                    self.tr(
                        """<p>The clipboard image is larger than the"""
                        """ current image.<br/>Paste as new image?</p>"""))
                if res:
                    self.editPasteAsNew()
                return
            elif not pasting:
                self.__isPasting = True
                self.__clipboardSize = img.size()
            else:
                cmd = IconEditCommand(self, self.tr("Paste Clipboard"),
                                      self.__image)
                self.__markImage.fill(self.NoMarkColor.rgba())
                painter = QPainter(self.__image)
                painter.setPen(self.penColor())
                painter.setCompositionMode(self.__compositingMode)
                painter.drawImage(
                    self.__pasteRect.x(), self.__pasteRect.y(), img, 0, 0,
                    self.__pasteRect.width() + 1,
                    self.__pasteRect.height() + 1)
                
                self.__undoStack.push(cmd)
                cmd.setAfterImage(self.__image)
                
                self.__updateImageRect(
                    self.__pasteRect.topLeft(),
                    self.__pasteRect.bottomRight() + QPoint(1, 1))
        else:
            E5MessageBox.warning(
                self,
                self.tr("Pasting Image"),
                self.tr("""Invalid image data in clipboard."""))
    
    def editPasteAsNew(self):
        """
        Public slot to paste the clipboard as a new image.
        """
        img, ok = self.__clipboardImage()
        if ok:
            cmd = IconEditCommand(
                self, self.tr("Paste Clipboard as New Image"),
                self.__image)
            self.setIconImage(img)
            self.setDirty(True)
            self.__undoStack.push(cmd)
            cmd.setAfterImage(self.__image)
    
    def editSelectAll(self):
        """
        Public slot to select the complete image.
        """
        self.__unMark()
        
        self.__startPos = QPoint(0, 0)
        self.__endPos = QPoint(self.rect().bottomRight())
        self.__markImage.fill(self.MarkColor.rgba())
        self.__selRect = self.__image.rect()
        self.__selectionAvailable = True
        self.selectionAvailable.emit(True)
        
        self.update()
    
    def editClear(self):
        """
        Public slot to clear the image.
        """
        self.__unMark()
        
        cmd = IconEditCommand(self, self.tr("Clear Image"), self.__image)
        self.__image.fill(qRgba(0, 0, 0, 0))
        self.update()
        self.setDirty(True)
        self.__undoStack.push(cmd)
        cmd.setAfterImage(self.__image)
    
    def editResize(self):
        """
        Public slot to resize the image.
        """
        from .IconSizeDialog import IconSizeDialog
        dlg = IconSizeDialog(self.__image.width(), self.__image.height())
        res = dlg.exec_()
        if res == QDialog.Accepted:
            newWidth, newHeight = dlg.getData()
            if newWidth != self.__image.width() or \
                    newHeight != self.__image.height():
                cmd = IconEditCommand(self, self.tr("Resize Image"),
                                      self.__image)
                img = self.__image.scaled(
                    newWidth, newHeight, Qt.IgnoreAspectRatio,
                    Qt.SmoothTransformation)
                self.setIconImage(img)
                self.setDirty(True)
                self.__undoStack.push(cmd)
                cmd.setAfterImage(self.__image)
    
    def editNew(self):
        """
        Public slot to generate a new, empty image.
        """
        from .IconSizeDialog import IconSizeDialog
        dlg = IconSizeDialog(self.__image.width(), self.__image.height())
        res = dlg.exec_()
        if res == QDialog.Accepted:
            width, height = dlg.getData()
            img = QImage(width, height, QImage.Format_ARGB32)
            img.fill(qRgba(0, 0, 0, 0))
            self.setIconImage(img)
    
    def grayScale(self):
        """
        Public slot to convert the image to gray preserving transparency.
        """
        cmd = IconEditCommand(self, self.tr("Convert to Grayscale"),
                              self.__image)
        for x in range(self.__image.width()):
            for y in range(self.__image.height()):
                col = self.__image.pixel(x, y)
                if col != qRgba(0, 0, 0, 0):
                    gray = qGray(col)
                    self.__image.setPixel(
                        x, y, qRgba(gray, gray, gray, qAlpha(col)))
        self.update()
        self.setDirty(True)
        self.__undoStack.push(cmd)
        cmd.setAfterImage(self.__image)

    def editUndo(self):
        """
        Public slot to perform an undo operation.
        """
        if self.__undoStack.canUndo():
            self.__undoStack.undo()
    
    def editRedo(self):
        """
        Public slot to perform a redo operation.
        """
        if self.__undoStack.canRedo():
            self.__undoStack.redo()
    
    def canUndo(self):
        """
        Public method to return the undo status.
        
        @return flag indicating the availability of undo (boolean)
        """
        return self.__undoStack.canUndo()
    
    def canRedo(self):
        """
        Public method to return the redo status.
        
        @return flag indicating the availability of redo (boolean)
        """
        return self.__undoStack.canRedo()
    
    def __cleanChanged(self, clean):
        """
        Private slot to handle the undo stack clean state change.
        
        @param clean flag indicating the clean state (boolean)
        """
        self.setDirty(not clean)
    
    def shutdown(self):
        """
        Public slot to perform some shutdown actions.
        """
        self.__undoStack.canRedoChanged.disconnect(self.canRedoChanged)
        self.__undoStack.canUndoChanged.disconnect(self.canUndoChanged)
        self.__undoStack.cleanChanged.disconnect(self.__cleanChanged)
    
    def isSelectionAvailable(self):
        """
        Public method to check the availability of a selection.
        
        @return flag indicating the availability of a selection (boolean)
        """
        return self.__selectionAvailable
Esempio n. 33
0
    def paint(self, painter, option, index):
        painter.setRenderHint(QPainter.Antialiasing)
        provider_ui_item = index.data(Qt.UserRole)

        painter.save()
        painter.translate(self._padding + option.rect.x(),
                          self._padding + option.rect.y())

        w = h = (self._radius - self._padding) * 2
        body_rect = QRect(0, 0, w, h)

        if provider_ui_item.colorful_svg:
            svg_renderer = QSvgRenderer(QUrl(provider_ui_item.colorful_svg).toString())
            svg_renderer.render(painter, QRectF(body_rect))
        else:
            # draw rounded rect
            painter.save()
            text_color = option.palette.color(QPalette.Text)
            if text_color.lightness() > 150:
                non_text_color = text_color.darker(140)
            else:
                non_text_color = text_color.lighter(150)
            non_text_color.setAlpha(100)
            pen = painter.pen()
            pen.setColor(non_text_color)
            painter.setPen(pen)
            painter.drawRoundedRect(body_rect, w//2, h//2)
            painter.restore()

            painter.save()
            font = painter.font()
            resize_font(font, -3)
            painter.setFont(font)
            text_option = QTextOption()
            text_option.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)
            text_option.setAlignment(Qt.AlignCenter)

            text_rect = QRectF(self.__text_rect_x, self.__text_rect_x,
                               self.__text_rect_width, self.__text_rect_width)
            painter.drawText(QRectF(text_rect), provider_ui_item.text, text_option)
            painter.restore()

        # TODO: use library.check_flags instead of provider.check_flags
        provider = provider_ui_item.provider
        if self._library.check_flags(
                provider.identifier, ModelType.none, PF.current_user):
            if provider.has_current_user():
                painter.save()
                bottom_right = body_rect.bottomRight()
                status_radius = self._radius // 5
                x = bottom_right.x() - status_radius * 2
                y = bottom_right.y() - status_radius * 2
                status_rect = QRect(QPoint(x, y), bottom_right)
                pen = painter.pen()
                pen.setWidth(2)
                pen.setColor(QGuiApplication.palette().color(QPalette.Window))
                painter.setPen(pen)
                painter.setBrush(QColor(SOLARIZED_COLORS['blue']))
                painter.drawRoundedRect(status_rect, status_radius, status_radius)
                painter.restore()

        painter.restore()
Esempio n. 34
0
    def __paintEventNoStyle(self):
        p = QPainter(self)
        opt = QStyleOptionToolButton()
        self.initStyleOption(opt)

        fm = QFontMetrics(opt.font)
        palette = opt.palette

        # highlight brush is used as the background for the icon and background
        # when the tab is expanded and as mouse hover color (lighter).
        brush_highlight = palette.highlight()
        foregroundrole = QPalette.ButtonText
        if opt.state & QStyle.State_Sunken:
            # State 'down' pressed during a mouse press (slightly darker).
            background_brush = brush_darker(brush_highlight, 110)
            foregroundrole = QPalette.HighlightedText
        elif opt.state & QStyle.State_MouseOver:
            background_brush = brush_darker(brush_highlight, 95)
            foregroundrole = QPalette.HighlightedText
        elif opt.state & QStyle.State_On:
            background_brush = brush_highlight
            foregroundrole = QPalette.HighlightedText
        else:
            # The default button brush.
            background_brush = palette.button()

        rect = opt.rect

        icon_area_rect = QRect(rect)
        icon_area_rect.setRight(int(icon_area_rect.height() * 1.26))

        text_rect = QRect(rect)
        text_rect.setLeft(icon_area_rect.right() + 10)

        # Background  (TODO: Should the tab button have native
        # toolbutton shape, drawn using PE_PanelButtonTool or even
        # QToolBox tab shape)

        # Default outline pen
        pen = QPen(palette.color(QPalette.Mid))

        p.save()
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(background_brush))
        p.drawRect(rect)

        # Draw the background behind the icon if the background_brush
        # is different.
        if not opt.state & QStyle.State_On:
            p.setBrush(brush_highlight)
            p.drawRect(icon_area_rect)
            # Line between the icon and text
            p.setPen(pen)
            p.drawLine(icon_area_rect.topRight(), icon_area_rect.bottomRight())

        if opt.state & QStyle.State_HasFocus:
            # Set the focus frame pen and draw the border
            pen = QPen(QColor(FOCUS_OUTLINE_COLOR))
            p.setPen(pen)
            p.setBrush(Qt.NoBrush)
            # Adjust for pen
            rect = rect.adjusted(0, 0, -1, -1)
            p.drawRect(rect)

        else:
            p.setPen(pen)
            # Draw the top/bottom border
            if self.position == QStyleOptionToolBox.OnlyOneTab or \
                    self.position == QStyleOptionToolBox.Beginning or \
                    self.selected & \
                        QStyleOptionToolBox.PreviousIsSelected:

                p.drawLine(rect.topLeft(), rect.topRight())

            p.drawLine(rect.bottomLeft(), rect.bottomRight())

        p.restore()

        p.save()
        text = fm.elidedText(opt.text, Qt.ElideRight, text_rect.width())
        p.setPen(QPen(palette.color(foregroundrole)))
        p.setFont(opt.font)

        p.drawText(text_rect,
                   int(Qt.AlignVCenter | Qt.AlignLeft) | \
                   int(Qt.TextSingleLine),
                   text)

        if not opt.icon.isNull():
            if opt.state & QStyle.State_Enabled:
                mode = QIcon.Normal
            else:
                mode = QIcon.Disabled
            if opt.state & QStyle.State_On:
                state = QIcon.On
            else:
                state = QIcon.Off
            icon_area_rect = icon_area_rect
            icon_rect = QRect(QPoint(0, 0), opt.iconSize)
            icon_rect.moveCenter(icon_area_rect.center())
            opt.icon.paint(p, icon_rect, Qt.AlignCenter, mode, state)
        p.restore()
Esempio n. 35
0
 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)
Esempio n. 36
0
 def from_image_rect(self, rect: QRect) -> QRect:
     return QRect(
         self.from_image_coord(rect.topLeft()),
         self.from_image_coord(rect.bottomRight())
     )
Esempio n. 37
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)