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()
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)
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())
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())
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())
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)
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")))
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())
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()) )
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"))
def resizeEvent(self, evt): """ Protected method to handle resize events. @param evt resize event (QResizeEvent) """ if self.__selection.isNull(): return r = QRect(self.__selection) r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect())) r.setBottomRight(self.__limitPointToRect(r.bottomRight(), self.rect())) if r.width() <= 1 or r.height() <= 1: # This just results in ugly drawing... self.__selection = QRect() else: self.__selection = self.__normalizeSelection(r)
def __updateHandles(self): """ Private method to update the handles. """ r = QRect(self.__selection) s2 = self.__handleSize // 2 self.__TLHandle.moveTopLeft(r.topLeft()) self.__TRHandle.moveTopRight(r.topRight()) self.__BLHandle.moveBottomLeft(r.bottomLeft()) self.__BRHandle.moveBottomRight(r.bottomRight()) self.__LHandle.moveTopLeft(QPoint(r.x(), r.y() + r.height() // 2 - s2)) self.__THandle.moveTopLeft(QPoint(r.x() + r.width() // 2 - s2, r.y())) self.__RHandle.moveTopRight( QPoint(r.right(), r.y() + r.height() // 2 - s2)) self.__BHandle.moveBottomLeft( QPoint(r.x() + r.width() // 2 - s2, r.bottom()))
def 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 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)
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)
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)
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)
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()
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)
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)
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
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()
def rect_to_points(r: QRect) -> Tuple[QPoint, QPoint]: lt, rb = r.topLeft(), r.bottomRight() return lt, rb
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)
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)
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))
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
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
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()
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()
def mouseMoveEvent(self, evt): """ Protected method to handle mouse movements. @param evt mouse move event (QMouseEvent) """ shouldShowHelp = not self.__helpTextRect.contains(evt.pos()) if shouldShowHelp != self.__showHelp: self.__showHelp = shouldShowHelp self.update() if self.__mouseDown: if self.__newSelection: p = evt.pos() r = self.rect() self.__selection = self.__normalizeSelection( QRect(self.__dragStartPoint, self.__limitPointToRect(p, r))) elif self.__mouseOverHandle is None: # moving the whole selection r = self.rect().normalized() s = self.__selectionBeforeDrag.normalized() p = s.topLeft() + evt.pos() - self.__dragStartPoint r.setBottomRight( r.bottomRight() - QPoint(s.width(), s.height()) + QPoint(1, 1)) if not r.isNull() and r.isValid(): self.__selection.moveTo(self.__limitPointToRect(p, r)) else: # dragging a handle r = QRect(self.__selectionBeforeDrag) offset = evt.pos() - self.__dragStartPoint if self.__mouseOverHandle in \ [self.__TLHandle, self.__THandle, self.__TRHandle]: r.setTop(r.top() + offset.y()) if self.__mouseOverHandle in \ [self.__TLHandle, self.__LHandle, self.__BLHandle]: r.setLeft(r.left() + offset.x()) if self.__mouseOverHandle in \ [self.__BLHandle, self.__BHandle, self.__BRHandle]: r.setBottom(r.bottom() + offset.y()) if self.__mouseOverHandle in \ [self.__TRHandle, self.__RHandle, self.__BRHandle]: r.setRight(r.right() + offset.x()) r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect())) r.setBottomRight( self.__limitPointToRect(r.bottomRight(), self.rect())) self.__selection = self.__normalizeSelection(r) self.update() else: if self.__selection.isNull(): return found = False for r in self.__handles: if r.contains(evt.pos()): self.__mouseOverHandle = r found = True break if not found: self.__mouseOverHandle = None if self.__selection.contains(evt.pos()): self.setCursor(Qt.OpenHandCursor) else: self.setCursor(Qt.CrossCursor) else: if self.__mouseOverHandle in [self.__TLHandle, self.__BRHandle]: self.setCursor(Qt.SizeFDiagCursor) elif self.__mouseOverHandle in [self.__TRHandle, self.__BLHandle]: self.setCursor(Qt.SizeBDiagCursor) elif self.__mouseOverHandle in [self.__LHandle, self.__RHandle]: self.setCursor(Qt.SizeHorCursor) elif self.__mouseOverHandle in [self.__THandle, self.__BHandle]: self.setCursor(Qt.SizeVerCursor)
def from_image_rect(self, rect: QRect) -> QRect: return QRect( self.from_image_coord(rect.topLeft()), self.from_image_coord(rect.bottomRight()) )
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)