def plotOutline(self, vertexs): scene = self.view.getScene() polygon = QPolygonF() polygon.clear() for point in vertexs: polygon.append(QPointF(point[0] * consts.DPM_X, point[1] * consts.DPM_Y)) scene.addPolygon(polygon, QColor(0,0,128))
def SetPoly(self, pos: QPointF): x, y = pos.x(), pos.y() if self.m_Item: self.removeItem(self.m_Item) poly = QPolygonF() poly.clear() poly.append(QPointF(x, y)) poly.append(QPointF(x + 100, y)) poly.append(QPointF(x + 200, y - 100)) poly.append(QPointF(x - 100, y - 100)) bursh = QBrush(QColor(123, 123, 123, 80)) pen = QPen(QtCore.Qt.red) self.m_Item = self.addPolygon(poly, pen, bursh)
class Arrow(QGraphicsLineItem): def __init__(self, startItem, endItem, parent=None, scene=None): super(Arrow, self).__init__(parent) self.arrowHead = QPolygonF() self.myStartItem = startItem self.myEndItem = endItem self.setFlag(QGraphicsItem.ItemIsSelectable, True) self.myColor = Qt.black self.setPen(QPen(self.myColor, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) def setColor(self, color): self.myColor = color def startItem(self): return self.myStartItem def endItem(self): return self.myEndItem def boundingRect(self): extra = (self.pen().width() + 20) / 2.0 p1 = self.line().p1() p2 = self.line().p2() return QRectF(p1, QSizeF(p2.x() - p1.x(), p2.y() - p1.y())).normalized().adjusted(-extra, -extra, extra, extra) def shape(self): path = super(Arrow, self).shape() path.addPolygon(self.arrowHead) return path def updatePosition(self): line = QLineF(self.mapFromItem(self.myStartItem, 0, 0), self.mapFromItem(self.myEndItem, 0, 0)) self.setLine(line) def paint(self, painter, option, widget=None): if (self.myStartItem.collidesWithItem(self.myEndItem)): return myStartItem = self.myStartItem myEndItem = self.myEndItem myColor = self.myColor myPen = self.pen() myPen.setColor(self.myColor) arrowSize = 20.0 painter.setPen(myPen) painter.setBrush(self.myColor) centerLine = QLineF(myStartItem.pos(), myEndItem.pos()) endPolygon = myEndItem.polygon() p1 = endPolygon.first() + myEndItem.pos() intersectPoint = QPointF() for i in endPolygon: p2 = i + myEndItem.pos() polyLine = QLineF(p1, p2) intersectType = polyLine.intersect(centerLine, intersectPoint) if intersectType == QLineF.BoundedIntersection: break p1 = p2 self.setLine(QLineF(intersectPoint, myStartItem.pos())) line = self.line() angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (math.pi * 2.0) - angle arrowP1 = line.p1() + QPointF(math.sin(angle + math.pi / 3.0) * arrowSize, math.cos(angle + math.pi / 3) * arrowSize) arrowP2 = line.p1() + QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrowSize, math.cos(angle + math.pi - math.pi / 3.0) * arrowSize) self.arrowHead.clear() for point in [line.p1(), arrowP1, arrowP2]: self.arrowHead.append(point) painter.drawLine(line) painter.drawPolygon(self.arrowHead) if self.isSelected(): painter.setPen(QPen(myColor, 1, Qt.DashLine)) myLine = QLineF(line) myLine.translate(0, 4.0) painter.drawLine(myLine) myLine.translate(0,-8.0) painter.drawLine(myLine)
class Arrow(QGraphicsLineItem): def __init__(self, start_item, end_item, parent=None): super(Arrow, self).__init__(parent) self.arrowHead = QPolygonF() self.my_start_item = start_item self.my_end_item = end_item self.setFlag(QGraphicsItem.ItemIsSelectable, True) self.my_color = Qt.black self.setPen(QPen(self.my_color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) def set_color(self, color): self.my_color = color def start_item(self): return self.my_start_item def end_item(self): return self.my_end_item def boundingRect(self): extra = (self.pen().width() + 20) / 2.0 p1 = self.line().p1() p2 = self.line().p2() return QRectF(p1, QSizeF(p2.x() - p1.x(), p2.y() - p1.y())).normalized().adjusted(-extra, -extra, extra, extra) def shape(self): path = super(Arrow, self).shape() path.addPolygon(self.arrowHead) return path def update_position(self): line = QLineF(self.mapFromItem(self.my_start_item, 0, 0), self.mapFromItem(self.my_end_item, 0, 0)) self.setLine(line) def paint(self, painter, option, widget=None): if self.my_start_item.collidesWithItem(self.my_end_item): return my_start_item = self.my_start_item my_end_item = self.my_end_item my_color = self.my_color my_pen = self.pen() my_pen.setColor(self.my_color) arrow_size = 20.0 painter.setPen(my_pen) painter.setBrush(my_color) center_line = QLineF(my_start_item.pos(), my_end_item.pos()) end_polygon = my_end_item.polygon p1 = end_polygon.first() + my_end_item.pos() intersect_point = QPointF() for i in end_polygon: p2 = i + my_end_item.pos() poly_line = QLineF(p1, p2) intersect_type = poly_line.intersect(center_line, intersect_point) if intersect_type == QLineF.BoundedIntersection: break p1 = p2 self.setLine(QLineF(intersect_point, my_start_item.pos())) line = self.line() angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (math.pi * 2) - angle arrow_p1 = line.p1() + QPointF(math.sin(angle + math.pi / 3.0) * arrow_size, math.cos(angle + math.pi / 3) * arrow_size) arrow_p2 = line.p1() + QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrow_size, math.cos(angle + math.pi - math.pi / 3.0) * arrow_size) self.arrowHead.clear() for point in [line.p1(), arrow_p1, arrow_p2]: self.arrowHead.append(point) painter.drawLine(line) painter.drawPolygon(self.arrowHead) if self.isSelected(): painter.setPen(QPen(my_color, 1, Qt.DashLine)) my_line = QLineF(line) my_line.translate(0, 4.0) painter.drawLine(my_line) my_line.translate(0, -8.0) painter.drawLine(my_line)
class MovableArrow(QGraphicsLineItem): def __init__(self, parent=None): super(MovableArrow, self).__init__(parent) self.setZValue(1000) self.arrowHead = QPolygonF() self.begin = np.array([0.0, 0.0]) self.end =np.array([10.0, 10.0]) self.myColor = Qt.black self.setPen(QPen(self.myColor, 5)) self.arrowSize = 5 self.setOpacity(0.4) self.isMousePressed = False self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemSendsGeometryChanges) self.angleFixedFlag = False self.objectName = None def boundingRect(self): extra = (self.pen().width() + 20) / 2.0 size = QSizeF( 1.3*(self.line().p1().x() - self.line().p2().x()), 1.3*(self.line().p1().y() - self.line().p2().y()) ) return QRectF(self.line().p2(), size).normalized().adjusted(-extra, -extra, extra, extra) def shape(self): path = super(MovableArrow, self).shape() path.addPolygon(self.arrowHead) return path def setColor(self, colorArray): self.myColor = QColor(*colorArray) def updatePosition(self): line = QLineF(QPointF(*self.end), QPointF(*self.begin)) self.setLine(line) self.shape() def paint(self, painter, option, widget=None): self.updatePosition() myPen = self.pen() myPen.setColor(self.myColor) painter.setPen(myPen) # painter.setBrush(self.myColor) try: angle = np.arccos(self.line().dx() / self.line().length()) except ZeroDivisionError: angle = 0.0 if self.line().dy() >= 0: angle = (np.pi * 2) - angle; l = self.line().length()*0.1 arrowP0 = self.line().p1() - QPointF(self.line().dx()/l, self.line().dy()/l) arrowP1 = self.line().p1() + QPointF(np.sin(angle + np.pi / 6) * self.arrowSize, np.cos(angle + np.pi / 6) * self.arrowSize) arrowP2 = self.line().p1() + QPointF(np.sin(angle + np.pi - np.pi / 6) * self.arrowSize, np.cos(angle + np.pi - np.pi / 6) * self.arrowSize) self.arrowHead.clear(); self.arrowHead.append(arrowP0) self.arrowHead.append(arrowP1) self.arrowHead.append(arrowP2) # painter.drawConvexPolygon(self.arrowHead) arrow = QPainterPath() arrow.addPolygon(self.arrowHead) painter.fillPath(arrow, QBrush(self.myColor)) painter.drawLine(self.line()) self.shape() def mousePressEvent(self, event): self.isMousePressed = True self.mousePressedPos = event.scenePos() self.end_old = self.end.copy() super(MovableArrow, self).mousePressEvent(event) def mouseMoveEvent(self, event): mouseCursorPos = event.scenePos() #mouseCursorPos = event.Pos() if self.isMousePressed: x = mouseCursorPos.x() - self.mousePressedPos.x() y = mouseCursorPos.y() - self.mousePressedPos.y() delta = np.array([x,y]) # angle = ang(self.begin, self.end+delta) if self.angleFixedFlag == False: self.end[:] = self.end_old + delta else: T = self.end_old-self.begin delta = delta self.end[:] = self.begin+((T)/np.linalg.norm(T))*np.linalg.norm(delta) self.updatePosition() #super(MovableArrow, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): self.isMousePressed = False super(MovableArrow, self).mouseReleaseEvent(event) def getVector(self): return self.end-self.begin def setObjectName(self,name): self.objectName = name def objectName(self): return self.objectName
class Arrow(QGraphicsLineItem): def __init__(self, startp=Point(), endp=None, length=60.0, angle=50.0, color=QtCore.Qt.red, pencolor=QtCore.Qt.green, startarrow=True): """ Initialisation of the class. """ self.sc = None super(Arrow, self).__init__() self.startp = QtCore.QPointF(startp.x, -startp.y) self.endp = endp self.length = length self.angle = angle self.startarrow = startarrow self.allwaysshow = False self.arrowHead = QPolygonF() self.setFlag(QGraphicsItem.ItemIsSelectable, False) self.myColor = color self.pen = QPen(pencolor, 1, QtCore.Qt.SolidLine) self.pen.setCosmetic(True) self.arrowSize = 8.0 def contains_point(self, point): """ Arrows cannot be selected. Return maximal distance """ return float(0x7fffffff) def setSelected(self, flag=True, blockSignals=True): """ Override inherited function to turn off selection of Arrows. @param flag: The flag to enable or disable Selection """ if self.allwaysshow: pass elif flag is True: self.show() else: self.hide() def setallwaysshow(self, flag=False): """ If the directions shall be allwaysshown the parameter will be set and all paths will be shown. @param flag: The flag to enable or disable Selection """ self.allwaysshow = flag if flag is True: self.show() elif flag is True and self.isSelected(): self.show() else: self.hide() def paint(self, painter, option, widget=None): """ Method for painting the arrow. """ demat = painter.deviceTransform() self.sc = demat.m11() if self.endp is None: dx = cos(self.angle) * self.length / self.sc dy = sin(self.angle) * self.length / self.sc endp = QtCore.QPointF(self.startp.x() - dx, self.startp.y() + dy) else: endp = QtCore.QPointF(self.endp.x, -self.endp.y) arrowSize = self.arrowSize / self.sc painter.setPen(self.pen) painter.setBrush(self.myColor) self.setLine(QtCore.QLineF(endp, self.startp)) line = self.line() if line.length() != 0: angle = acos(line.dx() / line.length()) if line.dy() >= 0: angle = (pi * 2.0) - angle if self.startarrow: arrowP1 = line.p2() - QtCore.QPointF(sin(angle + pi / 3.0) * arrowSize, cos(angle + pi / 3.0) * arrowSize) arrowP2 = line.p2() - QtCore.QPointF(sin(angle + pi - pi / 3.0) * arrowSize, cos(angle + pi - pi / 3.0) * arrowSize) self.arrowHead.clear() for Point in [line.p2(), arrowP1, arrowP2]: self.arrowHead.append(Point) else: arrowP1 = line.p1() + QtCore.QPointF(sin(angle + pi / 3.0) * arrowSize, cos(angle + pi / 3.0) * arrowSize) arrowP2 = line.p1() + QtCore.QPointF(sin(angle + pi - pi / 3.0) * arrowSize, cos(angle + pi - pi / 3.0) * arrowSize) self.arrowHead.clear() for Point in [line.p1(), arrowP1, arrowP2]: self.arrowHead.append(Point) painter.drawLine(line) painter.drawPolygon(self.arrowHead) def boundingRect(self): """ Override inherited function to enlarge selection of Arrow to include all @param flag: The flag to enable or disable Selection """ if not self.sc: # since this function is called before paint; and scale is unknown return QtCore.QRectF(self.startp.x(), self.startp.y(), 1e-9, 1e-9) arrowSize = self.arrowSize / self.sc extra = arrowSize # self.pen.width() + if self.endp is None: dx = cos(self.angle) * self.length / self.sc dy = sin(self.angle) * self.length / self.sc endp = QtCore.QPointF(self.startp.x() - dx, self.startp.y() + dy) else: endp = QtCore.QPointF(self.endp.x, -self.endp.y) brect = QtCore.QRectF(self.startp, QtCore.QSizeF(endp.x()-self.startp.x(), endp.y()-self.startp.y())).normalized().adjusted(-extra, -extra, extra, extra) return brect
class ArrowItem(QGraphicsLineItem): def __init__(self, *args, has_head=True, has_tail=False, **kwargs): super().__init__(*args, **kwargs) self.setFlag(QGraphicsItem.ItemIsSelectable, True) self.setFlag(QGraphicsItem.ItemIsMovable, True) self.setPen(QPen(Qt.black, 10, Qt.SolidLine)) self._has_head = has_head self._has_tail = has_tail self._arrow_head = QPolygonF() self._arrow_tail = QPolygonF() def hasTail(self): return self._has_tail def setTail(self, visible: bool): if self._has_tail != visible: self._has_tail = visible self.update() def hasHead(self): return self._has_head def setHead(self, visible: bool): if self._has_head != visible: self._has_head = visible self.update() def getAngle(self): dx, dy = self.line().dx(), self.line().dy() return math.pi - math.atan(dx / dy) if dy != 0 else math.copysign(math.pi / 2, dx) def shape(self): path = QPainterPath() stroker = QPainterPathStroker() path.moveTo(self.line().p1()) path.lineTo(self.line().p2()) path.addPolygon(self._arrow_head) path.addPolygon(self._arrow_tail) stroker.setWidth(self.pen().width()) return stroker.createStroke(path) def boundingRect(self) -> QRectF: return self.shape().boundingRect() def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, widget: Optional[QWidget] = None) -> None: painter.setRenderHint(QPainter.Antialiasing) pen = self.pen() brush = QBrush() if self.isSelected(): color = QColor(255, 0, 0) pen.setColor(color) else: color = pen.color() painter.setPen(pen) brush.setColor(color) brush.setStyle(Qt.SolidPattern) painter.setBrush(brush) painter.drawLine(self.line()) angle = self.getAngle() if self.line().dy() >= 0.: angle += math.pi size = self.pen().width() * 2.5 if self._has_tail or self._has_head: painter.setPen(QPen(color, self.pen().width(), Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) if self._has_tail: a = angle + math.pi + math.pi * .1 b = angle + math.pi - math.pi * .1 p0 = self.line().p1() + QPointF(math.sin(angle) * self.pen().width(), -math.cos(angle) * self.pen().width()) p1 = p0 + QPointF(math.sin(a) * size, -math.cos(a) * size) p2 = p0 + QPointF(math.sin(b) * size, -math.cos(b) * size) self._arrow_tail.clear() self._arrow_tail << p0 << p1 << p2 painter.drawPolygon(self._arrow_tail) if self._has_head: a = angle + math.pi * .1 b = angle - math.pi * .1 p0 = self.line().p2() - QPointF(math.sin(angle) * self.pen().width(), -math.cos(angle) * self.pen().width()) p1 = p0 + QPointF(math.sin(a) * size, -math.cos(a) * size) p2 = p0 + QPointF(math.sin(b) * size, -math.cos(b) * size) self._arrow_head.clear() self._arrow_head << p0 << p1 << p2 painter.drawPolygon(self._arrow_head) def __str__(self): return 'Arrow' if self.hasHead() or self.hasTail() else 'Line'
class Arrow(QGraphicsLineItem): def __init__(self, startp=Point(), endp=None, length=60.0, angle=50.0, color=QtCore.Qt.red, pencolor=QtCore.Qt.green, startarrow=True): """ Initialisation of the class. """ self.sc = None super(Arrow, self).__init__() self.startp = QtCore.QPointF(startp.x, -startp.y) self.endp = endp self.length = length self.angle = angle self.startarrow = startarrow self.allwaysshow = False self.arrowHead = QPolygonF() self.setFlag(QGraphicsItem.ItemIsSelectable, False) self.myColor = color self.pen = QPen(pencolor, 1, QtCore.Qt.SolidLine) self.pen.setCosmetic(True) self.arrowSize = 8.0 def contains_point(self, point): """ Arrows cannot be selected. Return maximal distance """ return float(0x7fffffff) def setSelected(self, flag=True, blockSignals=True): """ Override inherited function to turn off selection of Arrows. @param flag: The flag to enable or disable Selection """ if self.allwaysshow: pass elif flag is True: self.show() else: self.hide() def setallwaysshow(self, flag=False): """ If the directions shall be allwaysshown the parameter will be set and all paths will be shown. @param flag: The flag to enable or disable Selection """ self.allwaysshow = flag if flag is True: self.show() elif flag is True and self.isSelected(): self.show() else: self.hide() def paint(self, painter, option, widget=None): """ Method for painting the arrow. """ demat = painter.deviceTransform() self.sc = demat.m11() if self.endp is None: dx = cos(self.angle) * self.length / self.sc dy = sin(self.angle) * self.length / self.sc endp = QtCore.QPointF(self.startp.x() - dx, self.startp.y() + dy) else: endp = QtCore.QPointF(self.endp.x, -self.endp.y) arrowSize = self.arrowSize / self.sc painter.setPen(self.pen) painter.setBrush(self.myColor) self.setLine(QtCore.QLineF(endp, self.startp)) line = self.line() if line.length() != 0: angle = acos(line.dx() / line.length()) if line.dy() >= 0: angle = (pi * 2.0) - angle if self.startarrow: arrowP1 = line.p2() - QtCore.QPointF( sin(angle + pi / 3.0) * arrowSize, cos(angle + pi / 3.0) * arrowSize) arrowP2 = line.p2() - QtCore.QPointF( sin(angle + pi - pi / 3.0) * arrowSize, cos(angle + pi - pi / 3.0) * arrowSize) self.arrowHead.clear() for Point in [line.p2(), arrowP1, arrowP2]: self.arrowHead.append(Point) else: arrowP1 = line.p1() + QtCore.QPointF( sin(angle + pi / 3.0) * arrowSize, cos(angle + pi / 3.0) * arrowSize) arrowP2 = line.p1() + QtCore.QPointF( sin(angle + pi - pi / 3.0) * arrowSize, cos(angle + pi - pi / 3.0) * arrowSize) self.arrowHead.clear() for Point in [line.p1(), arrowP1, arrowP2]: self.arrowHead.append(Point) painter.drawLine(line) painter.drawPolygon(self.arrowHead) def boundingRect(self): """ Override inherited function to enlarge selection of Arrow to include all @param flag: The flag to enable or disable Selection """ if not self.sc: # since this function is called before paint; and scale is unknown return QtCore.QRectF(self.startp.x(), self.startp.y(), 1e-9, 1e-9) arrowSize = self.arrowSize / self.sc extra = arrowSize # self.pen.width() + if self.endp is None: dx = cos(self.angle) * self.length / self.sc dy = sin(self.angle) * self.length / self.sc endp = QtCore.QPointF(self.startp.x() - dx, self.startp.y() + dy) else: endp = QtCore.QPointF(self.endp.x, -self.endp.y) brect = QtCore.QRectF( self.startp, QtCore.QSizeF(endp.x() - self.startp.x(), endp.y() - self.startp.y())).normalized().adjusted( -extra, -extra, extra, extra) return brect
class ContOverlay(AbstractOverlay): '''Definie contour item ''' def __init__(self, widget): super().__init__(widget) self.freehandDone = None # fill dummydata self.contour = QPolygonF() self.contour.append(QPointF(23, 24)) self.contour.append(QPointF(50, 50)) self.contour.append(QPointF(21, 76)) self.freeHandPath = QPolygonF() self.curmouspos = QPoint() def handleEvent(self, event) -> bool: trf = self.invertedTransform() processed = False if event.type() == QEvent.MouseButtonPress: self.freeHandPath.clear() trfmpos = trf.map(event.pos()) self.freeHandPath.append(trfmpos) processed = True elif event.type( ) == QEvent.MouseMove and event.buttons() & Qt.LeftButton: trfmpos = trf.map(event.pos()) self.freeHandPath.append(trfmpos) processed = True elif event.type() == QEvent.MouseMove: # mouse move without button pressed self.curmouspos = event.pos() self.widget.update() elif event.type() == QEvent.MouseButtonRelease: processed = True if self.freehandDone: self.freehandDone(event.pos()) if processed: self.widget.update() return processed def render(self, painter): if self.active: trf = self.transform() painter.setPen(QPen(Qt.white, 5)) cont = trf.map(self.contour) painter.drawPolygon(cont) if len(self.freeHandPath) > 0: pen = QPen(QColor(255, 255, 255, 180), 22) pen.setCapStyle(Qt.RoundCap) pen.setJoinStyle(Qt.RoundJoin) painter.setPen(pen) fh = trf.map(self.freeHandPath) painter.drawPolyline(fh) else: # zeichnen einer kreis, zur suggestion painter.setPen(QPen(Qt.black, 1)) painter.drawEllipse(self.curmouspos, 11, 11) def enter(self): self.freeHandPath.clear() self.active = True self.widget.update() def leave(self): self.freeHandPath.clear() self.active = False self.widget.update()
def paintEvent(self, event): page_bottom = self.edit.viewport().height() font_metrics = QFontMetrics(self.edit.document().defaultFont()) current_block = self.edit.document().findBlock( self.edit.textCursor().position()) pattern = self.pat if self.edit.lang == "python" else self.patNotPython painter = QPainter(self) background = resources.CUSTOM_SCHEME.get('sidebar-background', resources.COLOR_SCHEME['sidebar-background']) foreground = resources.CUSTOM_SCHEME.get('sidebar-foreground', resources.COLOR_SCHEME['sidebar-foreground']) pep8color = resources.CUSTOM_SCHEME.get('pep8-underline', resources.COLOR_SCHEME['pep8-underline']) errorcolor = resources.CUSTOM_SCHEME.get('error-underline', resources.COLOR_SCHEME['error-underline']) migrationcolor = resources.CUSTOM_SCHEME.get('migration-underline', resources.COLOR_SCHEME['migration-underline']) painter.fillRect(self.rect(), QColor(background)) block = self.edit.firstVisibleBlock() viewport_offset = self.edit.contentOffset() line_count = block.blockNumber() painter.setFont(self.edit.document().defaultFont()) while block.isValid(): line_count += 1 # The top left position of the block in the document position = self.edit.blockBoundingGeometry(block).topLeft() + \ viewport_offset # Check if the position of the block is outside of the visible area if position.y() > page_bottom: break # Set the Painter Pen depending on special lines error = False if settings.CHECK_STYLE and \ ((line_count - 1) in self._pep8Lines): painter.setPen(QColor(pep8color)) font = painter.font() font.setItalic(True) font.setUnderline(True) painter.setFont(font) error = True elif settings.FIND_ERRORS and \ ((line_count - 1) in self._errorsLines): painter.setPen(QColor(errorcolor)) font = painter.font() font.setItalic(True) font.setUnderline(True) painter.setFont(font) error = True elif settings.SHOW_MIGRATION_TIPS and \ ((line_count - 1) in self._migrationLines): painter.setPen(QColor(migrationcolor)) font = painter.font() font.setItalic(True) font.setUnderline(True) painter.setFont(font) error = True else: painter.setPen(QColor(foreground)) # We want the line number for the selected line to be bold. bold = False if block == current_block: bold = True font = painter.font() font.setBold(True) painter.setFont(font) # Draw the line number right justified at the y position of the # line. 3 is a magic padding number. drawText(x, y, text). if block.isVisible(): painter.drawText(self.width() - self.foldArea - font_metrics.width(str(line_count)) - 3, round(position.y()) + font_metrics.ascent() + font_metrics.descent() - 1, str(line_count)) # Remove the bold style if it was set previously. if bold: font = painter.font() font.setBold(False) painter.setFont(font) if error: font = painter.font() font.setItalic(False) font.setUnderline(False) painter.setFont(font) block = block.next() self.highest_line = line_count #Code Folding xofs = self.width() - self.foldArea painter.fillRect(xofs, 0, self.foldArea, self.height(), QColor(resources.CUSTOM_SCHEME.get('fold-area', resources.COLOR_SCHEME['fold-area']))) if self.foldArea != self.rightArrowIcon.width(): polygon = QPolygonF() self.rightArrowIcon = QPixmap(self.foldArea, self.foldArea) self.rightArrowIcon.fill(Qt.transparent) self.downArrowIcon = QPixmap(self.foldArea, self.foldArea) self.downArrowIcon.fill(Qt.transparent) polygon.append(QPointF(self.foldArea * 0.4, self.foldArea * 0.25)) polygon.append(QPointF(self.foldArea * 0.4, self.foldArea * 0.75)) polygon.append(QPointF(self.foldArea * 0.8, self.foldArea * 0.5)) iconPainter = QPainter(self.rightArrowIcon) iconPainter.setRenderHint(QPainter.Antialiasing) iconPainter.setPen(Qt.NoPen) iconPainter.setBrush(QColor( resources.CUSTOM_SCHEME.get('fold-arrow', resources.COLOR_SCHEME['fold-arrow']))) iconPainter.drawPolygon(polygon) polygon.clear() polygon.append(QPointF(self.foldArea * 0.25, self.foldArea * 0.4)) polygon.append(QPointF(self.foldArea * 0.75, self.foldArea * 0.4)) polygon.append(QPointF(self.foldArea * 0.5, self.foldArea * 0.8)) iconPainter = QPainter(self.downArrowIcon) iconPainter.setRenderHint(QPainter.Antialiasing) iconPainter.setPen(Qt.NoPen) iconPainter.setBrush(QColor( resources.CUSTOM_SCHEME.get('fold-arrow', resources.COLOR_SCHEME['fold-arrow']))) iconPainter.drawPolygon(polygon) block = self.edit.firstVisibleBlock() while block.isValid(): position = self.edit.blockBoundingGeometry( block).topLeft() + viewport_offset #Check if the position of the block is outside of the visible area if position.y() > page_bottom: break if pattern.match(block.text()) and block.isVisible(): if block.blockNumber() in self._foldedBlocks: painter.drawPixmap(xofs, round(position.y()), self.rightArrowIcon) else: painter.drawPixmap(xofs, round(position.y()), self.downArrowIcon) #Add Bookmarks and Breakpoint elif block.blockNumber() in self._breakpoints: linear_gradient = QLinearGradient( xofs, round(position.y()), xofs + self.foldArea, round(position.y()) + self.foldArea) linear_gradient.setColorAt(0, QColor(255, 11, 11)) linear_gradient.setColorAt(1, QColor(147, 9, 9)) painter.setRenderHints(QPainter.Antialiasing, True) painter.setPen(Qt.NoPen) painter.setBrush(QBrush(linear_gradient)) painter.drawEllipse( xofs + 1, round(position.y()) + 6, self.foldArea - 1, self.foldArea - 1) elif block.blockNumber() in self._bookmarks: linear_gradient = QLinearGradient( xofs, round(position.y()), xofs + self.foldArea, round(position.y()) + self.foldArea) linear_gradient.setColorAt(0, QColor(13, 62, 243)) linear_gradient.setColorAt(1, QColor(5, 27, 106)) painter.setRenderHints(QPainter.Antialiasing, True) painter.setPen(Qt.NoPen) painter.setBrush(QBrush(linear_gradient)) painter.drawRoundedRect( xofs + 1, round(position.y()) + 6, self.foldArea - 2, self.foldArea - 1, 3, 3) block = block.next()# block = next(block) painter.end() super(SidebarWidget, self).paintEvent(event)
def paintEvent(self, event): page_bottom = self.edit.viewport().height() font_metrics = QFontMetrics(self.edit.document().defaultFont()) current_block = self.edit.document().findBlock( self.edit.textCursor().position()) pattern = self.pat if self.edit.lang == "python" else self.patNotPython painter = QPainter(self) background = resources.CUSTOM_SCHEME.get( 'sidebar-background', resources.COLOR_SCHEME['sidebar-background']) foreground = resources.CUSTOM_SCHEME.get( 'sidebar-foreground', resources.COLOR_SCHEME['sidebar-foreground']) background_selected = resources.CUSTOM_SCHEME.get( 'sidebar-selected-background', resources.COLOR_SCHEME['sidebar-selected-background']) foreground_selected = resources.CUSTOM_SCHEME.get( 'sidebar-selected-foreground', resources.COLOR_SCHEME['sidebar-selected-foreground']) painter.fillRect(self.rect(), QColor(background)) block = self.edit.firstVisibleBlock() viewport_offset = self.edit.contentOffset() line_count = block.blockNumber() painter.setFont(self.edit.document().defaultFont()) xofs = self.width() - self.foldArea painter.fillRect( xofs, 0, self.foldArea, self.height(), QColor( resources.CUSTOM_SCHEME.get( 'fold-area', resources.COLOR_SCHEME['fold-area']))) while block.isValid(): line_count += 1 # The top left position of the block in the document position = self.edit.blockBoundingGeometry(block).topLeft() + \ viewport_offset # Check if the position of the block is outside of the visible area if position.y() > page_bottom: break # Set the Painter Pen depending on special lines painter.setPen(QColor(foreground)) error = False checkers = self._neditable.sorted_checkers for items in checkers: checker, color, _ = items if (line_count - 1) in checker.checks: painter.setPen(QColor(color)) font = painter.font() font.setItalic(True) font.setUnderline(True) painter.setFont(font) error = True break # We want the line number for the selected line to be bold. bold = False if block == current_block: painter.fillRect( 0, round(position.y()) + font_metrics.descent(), self.width(), font_metrics.ascent() + font_metrics.descent(), QColor(background_selected)) bold = True font = painter.font() font.setBold(True) if not error: painter.setPen(QColor(foreground_selected)) painter.setFont(font) # Draw the line number right justified at the y position of the # line. 3 is a magic padding number. drawText(x, y, text). if block.isVisible(): painter.drawText( self.width() - self.foldArea - font_metrics.width(str(line_count)) - 3, round(position.y()) + font_metrics.ascent() + font_metrics.descent() - 1, str(line_count)) # Remove the bold style if it was set previously. if bold: font = painter.font() font.setBold(False) painter.setFont(font) if error: font = painter.font() font.setItalic(False) font.setUnderline(False) painter.setFont(font) block = block.next() self.highest_line = line_count #Code Folding if self.foldArea != self.rightArrowIcon.width(): polygon = QPolygonF() self.rightArrowIcon = QPixmap(self.foldArea, self.foldArea) self.rightArrowIcon.fill(Qt.transparent) self.downArrowIcon = QPixmap(self.foldArea, self.foldArea) self.downArrowIcon.fill(Qt.transparent) polygon.append(QPointF(self.foldArea * 0.4, self.foldArea * 0.25)) polygon.append(QPointF(self.foldArea * 0.4, self.foldArea * 0.75)) polygon.append(QPointF(self.foldArea * 0.8, self.foldArea * 0.5)) iconPainter = QPainter(self.rightArrowIcon) iconPainter.setRenderHint(QPainter.Antialiasing) iconPainter.setPen(Qt.NoPen) iconPainter.setBrush( QColor( resources.CUSTOM_SCHEME.get( 'fold-arrow', resources.COLOR_SCHEME['fold-arrow']))) iconPainter.drawPolygon(polygon) polygon.clear() polygon.append(QPointF(self.foldArea * 0.25, self.foldArea * 0.4)) polygon.append(QPointF(self.foldArea * 0.75, self.foldArea * 0.4)) polygon.append(QPointF(self.foldArea * 0.5, self.foldArea * 0.8)) iconPainter = QPainter(self.downArrowIcon) iconPainter.setRenderHint(QPainter.Antialiasing) iconPainter.setPen(Qt.NoPen) iconPainter.setBrush( QColor( resources.CUSTOM_SCHEME.get( 'fold-arrow', resources.COLOR_SCHEME['fold-arrow']))) iconPainter.drawPolygon(polygon) self.calculate_docstring_block_fold() block = self.edit.firstVisibleBlock() while block.isValid(): position = self.edit.blockBoundingGeometry( block).topLeft() + viewport_offset #Check if the position of the block is outside of the visible area if position.y() > page_bottom: break if pattern.match(block.text()) and block.isVisible(): can_fold = True if self.patComment.match(block.text()) and \ (block.blockNumber() in self._endDocstringBlocks): can_fold = False if can_fold: if block.blockNumber() in self.foldedBlocks: painter.drawPixmap(xofs, round(position.y()), self.rightArrowIcon) else: painter.drawPixmap(xofs, round(position.y()), self.downArrowIcon) #Add Bookmarks and Breakpoint if block.blockNumber() in self.breakpoints: linear_gradient = QLinearGradient( xofs, round(position.y()), xofs + self.foldArea, round(position.y()) + self.foldArea) linear_gradient.setColorAt(0, QColor(255, 11, 11)) linear_gradient.setColorAt(1, QColor(147, 9, 9)) painter.setRenderHints(QPainter.Antialiasing, True) painter.setPen(Qt.NoPen) painter.setBrush(QBrush(linear_gradient)) painter.drawEllipse(xofs + 1, round(position.y()) + 6, self.foldArea - 1, self.foldArea - 1) elif block.blockNumber() in self.bookmarks: linear_gradient = QLinearGradient( xofs, round(position.y()), xofs + self.foldArea, round(position.y()) + self.foldArea) linear_gradient.setColorAt(0, QColor(13, 62, 243)) linear_gradient.setColorAt(1, QColor(5, 27, 106)) painter.setRenderHints(QPainter.Antialiasing, True) painter.setPen(Qt.NoPen) painter.setBrush(QBrush(linear_gradient)) painter.drawRoundedRect(xofs + 1, round(position.y()) + 6, self.foldArea - 2, self.foldArea - 1, 3, 3) block = block.next() painter.end() super(SidebarWidget, self).paintEvent(event)
class Arrow(QGraphicsItemGroup): def __init__(self, start): super().__init__() self.fromItem = start self.startPoint = None self.toItem = None self.endPoint = None self.setFlag(QGraphicsItem.ItemIsSelectable) self.color = Qt.black self.pen = QPen(self.color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) self.arrowHead = QPolygonF() self.lines = [] self.qLines = [] #experimental self.setFlag(QGraphicsItem.ItemIsMovable) """ We need to reimplement this function because the arrow is larger than the bounding rectangle of the QGraphicsLineItem. The graphics scene uses the bounding rectangle to know which regions of the scene to update """ def boundingRect(self): extra = (self.pen.width() + 20) / 2.0 #rect = QRectF(self.line().p1(), QSizeF(self.line().p2().x() - self.line().p1().x(), # self.line().p2().y() - self.line().p1().y())) rect = self.calcRect() #return self.arrowHead.boundingRect() return rect.normalized().adjusted(-extra, -extra, extra, extra) """ The shape function returns a QPainterPath that is the exact shape of the item. The QGraphicsLineItem::shape() returns a path with a line drawn with the current pen, so we only need to add the arrow head. This function is used to check for collisions and selections with the mouse. """ def shape(self): #path = super().shape() path = QPainterPath() #path.addRect(self.calcRect()) path.addPolygon(self.arrowHead) return path #redraw, due to moving an object def recalcUpdate(self): if self.fromItem is None or self.toItem is None: return coordinates = QLineF( self.fromItem.getLinePoint(self.toItem.center())[1], self.toItem.getLinePoint(self.fromItem.center())[1]) #self.setLine(coordinates) """ is called, when one of the items is moved. it recalculates the lines """ def move(self): self.startPoint = GeoHelper.movePoint( self.posFromItem, self.fromItem.getPositionalRect().topLeft(), self.startPoint) self.endPoint = GeoHelper.movePoint( self.posToItem, self.toItem.getPositionalRect().topLeft(), self.endPoint) g = Geometry() self.lines = g.rectToRect(self.startPoint, self.fromItem.getPositionalRect(), self.endPoint, self.toItem.getPositionalRect()) self.posToItem = self.toItem.getPositionalRect().topLeft() self.posFromItem = self.fromItem.getPositionalRect().topLeft() self.update(self.boundingRect()) def drawLine(self, point, item): if item is not None: self.setItem2(item, point) else: self.setPoint2(point) self.update(self.boundingRect()) #trigger paint to update/ redraw #self.setLine(self.lines[-1]) #super().update(self.boundingRect()) def setPoint2(self, point): if self.startPoint is None: s1, self.startPoint = self.fromItem.getNearestPoint(point) g = Geometry() self.lines = g.rectToPoint(self.startPoint, self.fromItem.getPositionalRect(), point) """ saves second rectangle/Item and end point of a connection params ------ end: RoundedRect second rectangle/ toItem pos: QPointF position of mouse """ def setItem2(self, end, pos): #save endPoint s2, self.endPoint = end.getNearestPoint(pos) #save endItem self.toItem = end #save position (for moving) self.posToItem = self.toItem.getPositionalRect().topLeft() self.posFromItem = self.fromItem.getPositionalRect().topLeft() g = Geometry() self.lines = g.rectToRect(self.startPoint, self.fromItem.getPositionalRect(), self.endPoint, end.getPositionalRect()) print("a:", self.lines) def connect(self, end): self.toItem = end self.toItem.addInput(self) self.fromItem.addOutput(self) def calcRect(self): minX = self.lines[0].p1().x() minY = self.lines[0].p1().y() maxX = self.lines[0].p1().x() maxY = self.lines[0].p1().y() for l in self.lines: minX = min(minX, l.p1().x()) minY = min(minY, l.p1().y()) maxX = max(maxX, l.p1().x()) maxY = max(maxY, l.p1().y()) minX = min(minX, l.p2().x()) minY = min(minY, l.p2().y()) maxX = max(maxX, l.p2().x()) maxY = max(maxY, l.p2().y()) return QRectF(QPointF(minX, minY), QPointF(maxX, maxY)) def addOrAppend(self, i, line): if len(self.lines) > i: self.lines[i] = line else: self.lines.append(line) def resetLines(self, pen): for l in self.qLines: self.scene().removeItem(l) self.qLines = [] for l in self.lines: #line = QGraphicsLineItem(l, self) line = LineItem(l, self) line.setPen(pen) #line.setFlag(QGraphicsItem.ItemIsSelectable) self.qLines.append(line) def paint(self, painter, option, widget=None): arrowSize = 10 if self.isSelected(): pen = QPen(Qt.red, 1) color = Qt.red else: pen = self.pen color = self.color painter.setPen(pen) painter.setBrush(color) #calculate line #coordinates = QLineF(self.fromItem.getLinePoint(self.toItem.center()), # self.toItem.getLinePoint(self.fromItem.center())) #self.setLine(coordinates) #calculate points of arrow line = self.lines[-1] angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (math.pi * 2) - angle p1 = line.p2() - QPointF( math.sin(angle + math.pi / 3) * arrowSize, math.cos(angle + math.pi / 3) * arrowSize) p2 = line.p2() - QPointF( math.sin(angle + math.pi - math.pi / 3) * arrowSize, math.cos(angle + math.pi - math.pi / 3) * arrowSize) self.arrowHead.clear() self.arrowHead.append(line.p2()) self.arrowHead.append(p1) self.arrowHead.append(p2) painter.drawPolygon(self.arrowHead) self.resetLines(pen)
class Arrow(QGraphicsLineItem): def __init__( self, start_item: DiagramItem, end_item: DiagramItem, parent: QGraphicsItem = None, scene: QGraphicsScene = None, ): super(Arrow, self).__init__() self.start_item = start_item self.end_item = end_item self.arrow_head = QPolygonF() # Could be used later to support coloring. self.color = Qt.black self.setFlag(QGraphicsItem.ItemIsSelectable, True) self.setPen( QPen(self.color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) def get_start_item(self) -> DiagramItem: return self.start_item def get_end_item(self) -> DiagramItem: return self.end_item def boundingRect(self) -> QRectF: extra = (self.pen().width() + 20) / 2.0 p1 = self.line().p1() p2 = self.line().p2() return (QRectF(p1, QSizeF(p2.x() - p1.x(), p2.y() - p1.y())).normalized().adjusted( -extra, -extra, extra, extra)) def shape(self): path = super(Arrow, self).shape() path.addPolygon(self.arrow_head) return path def updatePosition(self): line = QLineF(self.mapFromItem(self.start_item, 0, 0), self.mapFromItem(self.end_item, 0, 0)) self.setLine(line) def paint(self, painter, option, widget=None): if self.start_item.collidesWithItem(self.end_item): return start_item = self.start_item end_item = self.end_item color = self.color pen = self.pen() pen.setColor(color) arrow_size = 10.0 painter.setPen(pen) painter.setBrush(color) center_line = QLineF(start_item.pos(), end_item.pos()) end_polygon = end_item.polygon p1 = end_polygon.first() + end_item.pos() intersect_point = QPointF() for i in end_polygon: p2 = i + end_item.pos() poly_line = QLineF(p1, p2) intersect_type = poly_line.intersect(center_line, intersect_point) if intersect_type == QLineF.BoundedIntersection: break p1 = p2 self.setLine(QLineF(intersect_point, start_item.pos())) line = self.line() angle = math.acos(line.dx() / max(1, line.length())) if line.dy() >= 0: angle = (math.pi * 2.0) - angle arrow_p1 = (line.p1() + QPointF( math.sin(angle + math.pi / 3.0) * arrow_size, math.cos(angle + math.pi / 3.0) * arrow_size, )) arrow_p2 = (line.p1() + QPointF( math.sin(angle + math.pi - math.pi / 3.0) * arrow_size, math.cos(angle + math.pi - math.pi / 3.0) * arrow_size, )) self.arrow_head.clear() for point in [line.p1(), arrow_p1, arrow_p2]: self.arrow_head.append(point) painter.drawLine(line) painter.drawPolygon(self.arrow_head) if self.isSelected(): painter.setPen(QPen(color, 1, Qt.DashLine)) line = QLineF(line) line.translate(0, 4.0) painter.drawLine(line) line.translate(0, -8.0) painter.drawLine(line)
class Link(QGraphicsLineItem): """! Link between Ports """ def __init__(self, from_port, to_port): """! @brief Link between two Ports (of different Nodes) @param from_port <OutputPort>: origin port @param to_port <InputPort>: destination port """ super().__init__() self.setFlag(QGraphicsItem.ItemIsSelectable) self.head = None self.tail = None self.selection_offset = 8 self.arrow_size = 10 self.selection_polygon = None self.from_port = from_port self.to_port = to_port self.arrow_head = QPolygonF() self.update_nodes() self.pen = QPen(Qt.black, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) self.dashed_pen = QPen(Qt.black, 1, Qt.DashLine) self.brush = QBrush(Qt.black) def save(self): return '|'.join( map(str, [ self.from_port.parentItem().index(), self.from_port.index(), self.to_port.parentItem().index(), self.to_port.index() ])) def update_polygon(self): angle = self.line().angle() * math.pi / 180 dx = self.selection_offset * math.sin(angle) dy = self.selection_offset * math.cos(angle) offset1 = QPointF(dx, dy) offset2 = QPointF(-dx, -dy) if self.head is None and self.tail is None: self.selection_polygon = QPolygonF([ self.line().p1() + offset1, self.line().p1() + offset2, self.line().p2() + offset2, self.line().p2() + offset1 ]) elif self.tail is None: head_angle = self.head.angle() * math.pi / 180 head_dx = self.selection_offset * math.sin(head_angle) head_dy = self.selection_offset * math.cos(head_angle) head_offset1 = QPointF(head_dx, head_dy) head_offset2 = QPointF(-head_dx, -head_dy) self.selection_polygon = QPolygonF([ self.line().p1() + offset1, self.head.p1() + head_offset1, self.head.p1() + head_offset2, self.line().p1() + offset2, self.line().p2() + offset2, self.line().p2() + offset1 ]) elif self.head is None: tail_angle = self.tail.angle() * math.pi / 180 tail_dx = self.selection_offset * math.sin(tail_angle) tail_dy = self.selection_offset * math.cos(tail_angle) tail_offset1 = QPointF(tail_dx, tail_dy) tail_offset2 = QPointF(-tail_dx, -tail_dy) self.selection_polygon = QPolygonF([ self.line().p1() + offset1, self.line().p1() + offset2, self.line().p2() + offset2, self.tail.p2() + tail_offset2, self.tail.p2() + tail_offset1, self.line().p2() + offset1 ]) else: head_angle = self.head.angle() * math.pi / 180 head_dx = self.selection_offset * math.sin(head_angle) head_dy = self.selection_offset * math.cos(head_angle) head_offset1 = QPointF(head_dx, head_dy) head_offset2 = QPointF(-head_dx, -head_dy) tail_angle = self.tail.angle() * math.pi / 180 tail_dx = self.selection_offset * math.sin(tail_angle) tail_dy = self.selection_offset * math.cos(tail_angle) tail_offset1 = QPointF(tail_dx, tail_dy) tail_offset2 = QPointF(-tail_dx, -tail_dy) self.selection_polygon = QPolygonF([ self.line().p1() + offset1, self.head.p1() + head_offset1, self.head.p1() + head_offset2, self.line().p1() + offset2, self.line().p2() + offset2, self.tail.p2() + tail_offset2, self.tail.p2() + tail_offset1, self.line().p2() + offset1 ]) def boundingRect(self): return self.selection_polygon.boundingRect() def shape(self): path = QPainterPath() path.addPolygon(self.selection_polygon) return path def paint(self, painter, options, widget=None): painter.setPen(self.pen) if self.head is not None: painter.drawLine(self.head) if self.tail is not None: painter.drawLine(self.tail) painter.drawLine(self.line()) if self.isSelected(): painter.setPen(self.dashed_pen) painter.drawPolygon(self.selection_polygon) # draw the arrow tip if self.tail is not None: tail_line = self.tail else: tail_line = self.line() intersection_point = QPointF(0, 0) for line in self.to_port.lines(): line = QLineF(self.mapFromScene(line.p1()), self.mapFromScene(line.p2())) intersection_type = tail_line.intersect(line, intersection_point) if intersection_type == QLineF.BoundedIntersection: break angle = math.acos(tail_line.dx() / tail_line.length()) if tail_line.dy() >= 0: angle = (math.pi * 2) - angle arrow_p1 = intersection_point - QPointF( math.sin(angle + math.pi / 3) * self.arrow_size, math.cos(angle + math.pi / 3) * self.arrow_size) arrow_p2 = intersection_point - QPointF( math.sin(angle + math.pi - math.pi / 3) * self.arrow_size, math.cos(angle + math.pi - math.pi / 3) * self.arrow_size) self.arrow_head.clear() for p in [intersection_point, arrow_p1, arrow_p2]: self.arrow_head.append(p) path = QPainterPath() path.addPolygon(self.arrow_head) painter.fillPath(path, self.brush) def update_nodes(self): p1 = self.from_port.rect().center() p2 = self.to_port.rect().center() p1 = self.from_port.parentItem().mapToScene(p1) p2 = self.to_port.parentItem().mapToScene(p2) line = QLineF(p1, p2) self.setLine(line) self.update_polygon() box1 = self.from_port.parentItem().mapRectToScene( self.from_port.parentItem().box.rect()) if box1.intersects(self.boundingRect()): p3 = box1.bottomRight() + QPointF(0, Port.WIDTH / 2) self.head = QLineF(p1, p3) line = QLineF(p3, p2) else: self.head = None box2 = self.to_port.parentItem().mapRectToScene( self.to_port.parentItem().box.rect()) if box2.intersects(self.boundingRect()): p4 = box2.topLeft() + QPointF(-Port.WIDTH / 2, 0) self.tail = QLineF(p4, p2) line = QLineF(line.p1(), p4) else: self.tail = None self.setLine(line) self.update_polygon() self.update() def remove(self): self.from_port.disconnect(self.to_port) self.to_port.disconnect() self.from_port.parentItem().remove_link(self) self.to_port.parentItem().remove_link(self) self.to_port.parentItem().reconfigure()
class MovableArrow(QGraphicsLineItem): def __init__(self, parent=None): super(MovableArrow, self).__init__(parent) self.setZValue(1000) self.arrowHead = QPolygonF() self.begin = np.array([0.0, 0.0]) self.end = np.array([10.0, 10.0]) self.myColor = Qt.black self.setPen(QPen(self.myColor, 5)) self.arrowSize = 5 self.setOpacity(0.4) self.isMousePressed = False self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemSendsGeometryChanges) self.angleFixedFlag = False self.objectName = None def boundingRect(self): extra = (self.pen().width() + 20) / 2.0 size = QSizeF(1.3 * (self.line().p1().x() - self.line().p2().x()), 1.3 * (self.line().p1().y() - self.line().p2().y())) return QRectF(self.line().p2(), size).normalized().adjusted(-extra, -extra, extra, extra) def shape(self): path = super(MovableArrow, self).shape() path.addPolygon(self.arrowHead) return path def setColor(self, colorArray): self.myColor = QColor(*colorArray) def updatePosition(self): line = QLineF(QPointF(*self.end), QPointF(*self.begin)) self.setLine(line) self.shape() def paint(self, painter, option, widget=None): self.updatePosition() myPen = self.pen() myPen.setColor(self.myColor) painter.setPen(myPen) # painter.setBrush(self.myColor) try: angle = np.arccos(self.line().dx() / self.line().length()) except ZeroDivisionError: angle = 0.0 if self.line().dy() >= 0: angle = (np.pi * 2) - angle l = self.line().length() * 0.1 arrowP0 = self.line().p1() - QPointF(self.line().dx() / l, self.line().dy() / l) arrowP1 = self.line().p1() + QPointF( np.sin(angle + np.pi / 6) * self.arrowSize, np.cos(angle + np.pi / 6) * self.arrowSize) arrowP2 = self.line().p1() + QPointF( np.sin(angle + np.pi - np.pi / 6) * self.arrowSize, np.cos(angle + np.pi - np.pi / 6) * self.arrowSize) self.arrowHead.clear() self.arrowHead.append(arrowP0) self.arrowHead.append(arrowP1) self.arrowHead.append(arrowP2) # painter.drawConvexPolygon(self.arrowHead) arrow = QPainterPath() arrow.addPolygon(self.arrowHead) painter.fillPath(arrow, QBrush(self.myColor)) painter.drawLine(self.line()) self.shape() def mousePressEvent(self, event): self.isMousePressed = True self.mousePressedPos = event.scenePos() self.end_old = self.end.copy() super(MovableArrow, self).mousePressEvent(event) def mouseMoveEvent(self, event): mouseCursorPos = event.scenePos() #mouseCursorPos = event.Pos() if self.isMousePressed: x = mouseCursorPos.x() - self.mousePressedPos.x() y = mouseCursorPos.y() - self.mousePressedPos.y() delta = np.array([x, y]) # angle = ang(self.begin, self.end+delta) if self.angleFixedFlag == False: self.end[:] = self.end_old + delta else: T = self.end_old - self.begin delta = delta self.end[:] = self.begin + ( (T) / np.linalg.norm(T)) * np.linalg.norm(delta) self.updatePosition() #super(MovableArrow, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): self.isMousePressed = False super(MovableArrow, self).mouseReleaseEvent(event) def getVector(self): return self.end - self.begin def setObjectName(self, name): self.objectName = name def objectName(self): return self.objectName
class Edge(QGraphicsLineItem): """ Implements an Edge to two nodes """ def __init__(self, start, dst, offset, color=Qt.black): """ Constructor for a conjunction. It generates all necessary variables and calls the draw function It adds also the parent arrow from the source to the conjunction rectangle :param start: Starting object of the arrow :param dst: End object of the arrow :param offset: left/right offset for the starting arrow :param color: Color of the arrow """ super().__init__() self.arrowHead = QPolygonF() self.start = start self.dst = dst self.offset = offset self.setFlag(QGraphicsItem.ItemIsSelectable, True) self.setPen(QPen(color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.updatePosition() def boundingRect(self): """ New calculation of the bounding rect, because the arrow is not only a line :return: new bounding rectangle """ extra = (self.pen().width() + 20) / 2.0 return QRectF(self.line().p1(), QSizeF(self.line().p2().x() - self.line().p1().x(), self.line().p2().y() - self.line().p1().y())).normalized().adjusted( -extra, -extra, extra, extra) def shape(self): """ Calculation of the shape of the arrow :return: shape of the arrow """ path = QGraphicsLineItem.shape(self) path.addPolygon(self.arrowHead) return path def updatePosition(self): """ Updates the position of the arrow """ line = QLineF(self.mapFromItem(self.start, 0, 0), self.mapFromItem(self.dst, 0, 0)) self.setLine(line) def paint(self, painter, options, widget=None): """ Painter implementation for the arrow. First it draws the line and then the triangle on the end :param painter: The painter, which draws the node :param options: options for the paint job :param widget: widget of the Item """ if self.start.collidesWithItem(self.dst): return myPen = self.pen() arrowSize = 10 painter.setPen(myPen) painter.setBrush(myPen.color()) """ Calculation for the line """ centerLine = QLineF(QPointF(self.start.x() + self.start.boundingRect().center().x() + self.offset, self.start.y() + self.start.boundingRect().bottom()), QPointF(self.dst.x() + self.dst.boundingRect().center().x(), self.dst.y())) endPolygon = self.dst.mapFromItem(self.dst, self.dst.boundingRect()) p1 = endPolygon.first() + self.dst.pos() p2 = None intersectPoint = QPointF() for i in endPolygon: p2 = i + self.dst.pos() polyLine = QLineF(p1, p2) intersectType = polyLine.intersect(centerLine, intersectPoint) if intersectType == QLineF.BoundedIntersection: break p1 = p2 self.setLine(QLineF(intersectPoint, QPointF(self.start.x() + self.start.boundingRect().center().x() + self.offset, self.start.y() + self.start.boundingRect().bottom()))) """ Calculation for the arrow It calculates an left and an right part of the arrow """ angle = math.atan2(-self.line().dy(), self.line().dx()) arrowP1 = self.line().p1() + QPointF(math.sin(angle + math.pi / 3) * arrowSize, math.cos(angle + math.pi / 3) * arrowSize) arrowP2 = self.line().p1() + QPointF(math.sin(angle + math.pi - math.pi / 3) * arrowSize, math.cos(angle + math.pi - math.pi / 3) * arrowSize) self.arrowHead.clear() self.arrowHead << self.line().p1() << arrowP1 << arrowP2 painter.drawLine(self.line()) painter.drawPolygon(self.arrowHead) if self.isSelected(): painter.setPen(QPen(Qt.black, 1, Qt.DashLine)) myLine = self.line() myLine.translate(0, 4.0) painter.drawLine(myLine) myLine.translate(0, -8.0) painter.drawLine(myLine) def selectChildren(self): """ Select all children of the destination """ self.dst.selectChildren()