def paintEvent(self, event): # Draw backgrounds according to css styleOpt = QStyleOption() styleOpt.initFrom(self) p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) self.style().drawPrimitive(QStyle.PE_Widget, styleOpt, p, self) if self.values == None or len(self.values) == 0: return # print(len(self.values)) r = self.rect() dx = r.width() / float(self.datapoints - 1) # Build a path from the readings path = QPainterPath() path.moveTo(r.bottomRight()) i = 0 for reading in reversed(self.values): pt = QPointF(r.width() - i*dx, (1.0 - reading) * r.height()) path.lineTo(pt) i = i + 1 path.lineTo(path.currentPosition().x(), r.height()) path.closeSubpath() # Use foreground color for graph gcolor = styleOpt.palette.color(QPalette.Text) p.setBrush(gcolor) p.setPen(gcolor) p.drawPath(path)
def paintEvent(self, event): rect = QRect(10, 20, 80, 60) path = QPainterPath() path.moveTo(20, 80) path.lineTo(20, 30) path.cubicTo(80, 0, 50, 50, 80, 80) startAngle = 30 * 16 arcLength = 120 * 16 painter = QPainter(self) painter.setPen(self.pen) painter.setBrush(self.brush) if self.antialiased: painter.setRenderHint(QPainter.Antialiasing) for x in range(0, self.width(), 100): for y in range(0, self.height(), 100): painter.save() painter.translate(x, y) if self.transformed: painter.translate(50, 50) painter.rotate(60.0) painter.scale(0.6, 0.9) painter.translate(-50, -50) if self.shape == RenderArea.Line: painter.drawLine(rect.bottomLeft(), rect.topRight()) elif self.shape == RenderArea.Points: painter.drawPoints(RenderArea.points) elif self.shape == RenderArea.Polyline: painter.drawPolyline(RenderArea.points) elif self.shape == RenderArea.Polygon: painter.drawPolygon(RenderArea.points) elif self.shape == RenderArea.Rect: painter.drawRect(rect) elif self.shape == RenderArea.RoundedRect: painter.drawRoundedRect(rect, 25, 25, Qt.RelativeSize) elif self.shape == RenderArea.Ellipse: painter.drawEllipse(rect) elif self.shape == RenderArea.Arc: painter.drawArc(rect, startAngle, arcLength) elif self.shape == RenderArea.Chord: painter.drawChord(rect, startAngle, arcLength) elif self.shape == RenderArea.Pie: painter.drawPie(rect, startAngle, arcLength) elif self.shape == RenderArea.Path: painter.drawPath(path) elif self.shape == RenderArea.Text: painter.drawText(rect, Qt.AlignCenter, "PyQt by\nRiverbank Computing") elif self.shape == RenderArea.Pixmap: painter.drawPixmap(10, 10, self.pixmap) painter.restore() painter.setPen(self.palette().dark().color()) painter.setBrush(Qt.NoBrush) painter.drawRect(QRect(0, 0, self.width() - 1, self.height() - 1))
def orbit(self): """Return a QPainterPath that shows the beam orbit.""" a, b = self.endpoints() path = QPainterPath() path.moveTo(*a) path.lineTo(*b) return path
def doHoneycomb(self, part_item, radius, bounds): """Summary Args: part_item (TYPE): Description radius (TYPE): Description bounds (TYPE): Description Returns: TYPE: Description """ doLattice = HoneycombDnaPart.latticeCoordToPositionXY doPosition = HoneycombDnaPart.positionToLatticeCoordRound isEven = HoneycombDnaPart.isEvenParity x_l, x_h, y_l, y_h = bounds dot_size, half_dot_size = self.dots sf = part_item.scale_factor points = self.points row_l, col_l = doPosition(radius, x_l, -y_l, False, False, scale_factor=sf) row_h, col_h = doPosition(radius, x_h, -y_h, True, True, scale_factor=sf) # print(row_l, row_h, col_l, col_h) path = QPainterPath() is_pen_down = False draw_lines = self.draw_lines for i in range(row_l, row_h): for j in range(col_l, col_h+1): x, y = doLattice(radius, i, j, scale_factor=sf) if draw_lines: if is_pen_down: path.lineTo(x, -y) else: is_pen_down = True path.moveTo(x, -y) """ +x is Left and +y is down origin of ellipse is Top Left corner so we subtract half in X and subtract in y """ pt = GridPoint(x - half_dot_size, -y - half_dot_size, dot_size, self) pt.setPen(getPenObj(Qt.blue, 1.0)) points.append(pt) is_pen_down = False # end for i # DO VERTICAL LINES if draw_lines: for j in range(col_l, col_h+1): # print("newcol") for i in range(row_l, row_h): x, y = doLattice(radius, i, j, scale_factor=sf) if is_pen_down and isEven(i, j): path.lineTo(x, -y) is_pen_down = False else: is_pen_down = True path.moveTo(x, -y) is_pen_down = False # end for j self.setPath(path)
def _addLinesToPainterPath( path: QPainterPath, p1: QPointF, p2: QPointF, p3: QPointF, p4: QPointF): path.moveTo(p1) path.lineTo(p2) path.moveTo(p3) path.lineTo(p4)
def lozengePath(x, y, size): halfSize = size / 2 path = QPainterPath() path.moveTo(x - halfSize, y) path.lineTo(x, y + halfSize) path.lineTo(x + halfSize, y) path.lineTo(x, y - halfSize) path.closeSubpath() return path
def set_shape(self, width, height): ''' Compute the polygon to fit in width, height ''' path = QPainterPath() path.addRoundedRect(0, 0, width, height, height / 2, height / 2) path.moveTo(min(width / 2, height / 2), 0) path.lineTo(min(width / 2, height / 2), height) path.moveTo(max(width / 2, width - height / 2), 0) path.lineTo(max(width / 2, width - height / 2), height) self.setPath(path) super(Start, self).set_shape(width, height)
def set_shape(self, width, height): ''' Compute the polygon to fit in width, height ''' path = QPainterPath() path.lineTo(width - 11, 0) path.lineTo(width, height / 2) path.lineTo(width - 11, height) path.lineTo(0, height) path.lineTo(0, 0) self.setPath(path) super(Output, self).set_shape(width, height)
def set_shape(self, width, height): ''' Compute the polygon to fit in width, height ''' path = QPainterPath() path.addRect(0, 0, width, height) path.moveTo(7, 0) path.lineTo(7, height) path.moveTo(width - 7, 0) path.lineTo(width - 7, height) self.setPath(path) super(ProcedureCall, self).set_shape(width, height)
def mousePressEvent(self, event): pos = self.magnetPos(event.localPos()) x, y = pos.x(), pos.y() path = QPainterPath() path.moveTo(x, y) path.lineTo(x + 1, y) path.lineTo(x + 1, y + 1) path.closeSubpath() text = "0" self._rulerObject = (path, text)
def set_shape(self, width, height): ''' Compute the polygon to fit in width, height ''' self.setPen(QPen(Qt.blue)) self.textbox_alignment = Qt.AlignLeft | Qt.AlignTop path = QPainterPath() path.moveTo(0, 0) path.lineTo(0, height) #path.moveTo(0, height / 2) #path.lineTo(width, height / 2) self.setPath(path) super(Input, self).set_shape(width, height)
def doSquare(self, part_item: GridNucleicAcidPartItemT, radius: float, bounds: RectT): """ Args: part_item: Description radius: Description bounds: Description """ doLattice = SquareDnaPart.latticeCoordToModelXY doPosition = SquareDnaPart.positionToLatticeCoordRound x_l, x_h, y_l, y_h = bounds dot_size, half_dot_size = self.dots sf = part_item.scale_factor points = self.points row_l, col_l = doPosition(radius, x_l, -y_l, scale_factor=sf) row_h, col_h = doPosition(radius, x_h, -y_h, scale_factor=sf) # print(row_l, row_h, col_l, col_h) path = QPainterPath() is_pen_down = False draw_lines = self.draw_lines for i in range(row_l, row_h + 1): for j in range(col_l, col_h + 1): x, y = doLattice(radius, i, j, scale_factor=sf) if draw_lines: if is_pen_down: path.lineTo(x, -y) else: is_pen_down = True path.moveTo(x, -y) """+x is Left and +y is down origin of ellipse is Top Left corner so we subtract half in X and subtract in y """ pt = GridPoint(x - half_dot_size, -y - half_dot_size, dot_size, self) pt.setPen(getPenObj(Qt.blue, 1.0)) points.append(pt) is_pen_down = False # pen up # DO VERTICAL LINES if draw_lines: for j in range(col_l, col_h + 1): for i in range(row_l, row_h + 1): x, y = doLattice(radius, i, j, scale_factor=sf) if is_pen_down: path.lineTo(x, -y) else: is_pen_down = True path.moveTo(x, -y) is_pen_down = False # pen up self.setPath(path)
def paint_to(self, painter): if len(self.points) > 1: painter.setPen(Qt.red) paint_path = QPainterPath() paint_path.moveTo(*self.points[0][0]) for pos, _ in self.points[1:]: paint_path.lineTo(*pos) painter.drawPath(paint_path) painter.setPen(Qt.green) for pos, _ in self.points: painter.drawPoint(*pos)
def _getRightTopCornerPath(self): width = self.width() borderRadius = self.borderRadius shadowMargin = self.shadowMargin shadowRadius = self.shadowRadius path = QPainterPath() path.moveTo(width - shadowRadius, 0) path.arcTo(width - 2 * shadowRadius, 0, 2 * shadowRadius, 2 * shadowRadius, 90, -90) path.lineTo(width - shadowMargin, shadowRadius) path.arcTo(width - shadowRadius - borderRadius, shadowMargin, 2 * borderRadius, 2 * borderRadius, 0, 90) path.lineTo(width - shadowRadius, 0) return path
def painterPath(self): i_g = self._item_group # the childrenBoundingRect is necessary to get this to work rect = self.mapRectFromItem(i_g, i_g.childrenBoundingRect()) radius = self._RADIUS path = QPainterPath() path.addRoundedRect(rect, radius, radius) path.moveTo(rect.right(),\ rect.center().y()) path.lineTo(rect.right() + radius / 2,\ rect.center().y()) return path
def _getLeftBottomCornerPath(self): height = self.height() borderRadius = self.borderRadius shadowMargin = self.shadowMargin shadowRadius = self.shadowRadius path = QPainterPath() path.moveTo(0, height - shadowRadius) path.arcTo(0, height - 2 * shadowRadius, 2 * shadowRadius, 2 * shadowRadius, 180, 90) path.lineTo(shadowRadius, height - shadowMargin) path.arcTo(shadowMargin, height - shadowRadius - borderRadius, 2 * borderRadius, 2 * borderRadius, 270, -90) path.lineTo(0, height - shadowRadius) return path
def _getRightBottomCornerPath(self): width = self.width() height = self.height() borderRadius = self.borderRadius shadowMargin = self.shadowMargin shadowRadius = self.shadowRadius path = QPainterPath() path.moveTo(width - shadowRadius, height) path.arcTo(width - 2 * shadowRadius, height - 2 * shadowRadius, 2 * shadowRadius, 2 * shadowRadius, 270, 90) path.lineTo(width - shadowMargin, height - shadowRadius) path.arcTo(width - shadowRadius - borderRadius, height - shadowRadius - borderRadius, 2 * borderRadius, 2 * borderRadius, 0, -90) path.lineTo(width - shadowRadius, height) return path
def outline(self): """Return a QPainterPath that outlines the element.""" r1, r2 = self.walls p0, p1 = self.endpoints() proj2D = self.plan.projection.dot vec0 = normalize(np.dot(rot90, proj2D(list(self.rotate[0](0, 0, 1))))) vec1 = normalize(np.dot(rot90, proj2D(list(self.rotate[1](0, 0, 1))))) path = QPainterPath() path.moveTo(*(p0 - r2*vec0)) path.lineTo(*(p1 - r2*vec1)) path.lineTo(*(p1 + r1*vec1)) path.lineTo(*(p0 + r1*vec0)) path.closeSubpath() return path
def _getLeftTopCornerPath(self): borderRadius = self.borderRadius shadowMargin = self.shadowMargin shadowRadius = self.shadowRadius path = QPainterPath() path.moveTo(self.shadowRadius, 0) path.arcTo(0, 0, 2 * shadowRadius, 2 * shadowRadius, 90, 90) path.lineTo(shadowMargin, shadowRadius) path.arcTo(shadowMargin, shadowMargin, 2 * borderRadius, 2 * borderRadius, 180, -90) path.lineTo(shadowRadius, 0) return path
def create_grid_lines(self): grid_line_width = self.settings.get_value('maps', 'grid_line_width') self.map_grid_path_item = QGraphicsPathItem() line_path = QPainterPath() for map_line in self.map_data.grid_lines: line_path.moveTo(map_line.x1, map_line.y1) line_path.lineTo(map_line.x2, map_line.y2) self.map_grid_path_item = QGraphicsPathItem(line_path) color = QColor().fromRgb(255, 255, 255, 25) self.map_grid_path_item.setPen( QPen( color, grid_line_width / self.scale_ratio ) )
def set_shape(self, width, height): ''' Define the symbol shape ''' circ = min(width, height) path = QPainterPath() path.addEllipse(0, 0, circ, circ) point1 = path.pointAtPercent(0.625) point2 = path.pointAtPercent(0.125) point3 = path.pointAtPercent(0.875) point4 = path.pointAtPercent(0.375) path.moveTo(point1) path.lineTo(point2) path.moveTo(point3) path.lineTo(point4) self.setPath(path) # call Join superclass, otherwise symbol will take Join shape super(Join, self).set_shape(circ, circ)
def reshape(self): ''' Update the connection or arrow shape ''' shape = QPainterPath() shape.moveTo(self.start_point) for point in self.middle_points: shape.lineTo(point) shape.lineTo(self.end_point) # If required draw an arrow head (e.g. in SDL NEXTSTATE and JOIN) if self.child.arrow_head: self.draw_arrow_head(shape, origin='head', kind=self.child.arrow_head) if self.child.arrow_tail: shape.moveTo(shape.pointAtPercent(0)) self.draw_arrow_head(shape, origin='tail', kind=self.child.arrow_head) self.setPath(shape)
def paint(self, painter): data = self.model.getStoredData() amplitude = self.height/2 painter.drawText(0, 0, self.text) path = QPainterPath() painter.translate(self.offset, 0) startYOffset = data[0]*amplitude painter.translate(0,-startYOffset) i = 1 for value in data[1:]: path.lineTo(i*SignalView.Grapher.xStep, -value*amplitude+startYOffset) i += 1 painter.drawPath(path) painter.translate(0,startYOffset) painter.translate(-self.offset, 0)
def drawGraph(self, data, points): xmin = data['xmin'] xmax = data['xmax'] ymin = data['ymin'] ymax = data['ymax'] xmarg = data['xmarg'] ymarg = data['xmarg'] xscale = data['xscale'] yscale = data['yscale'] scene = self.uiFunctionGraph.scene() func = QPainterPath(QPointF(xmarg, (points[0]['grade'] - ymin) * yscale + ymarg)) for point in points: func.lineTo((point['arg'] - xmin) * xscale + xmarg, (point['grade'] - ymin) * yscale + ymarg) scene.addPath(func)
def updatePath(self, margin=2): r, R, a, A = self.boundings() sgm = SegmentShapeEngine(r, a, R-r, A-a) pts = tuple(map(lambda p: (p[0], -p[1]), sgm.points_ra(margin))) (r, al), (_, aL), (R, AL), (_, Al) = sgm.points_RA(margin) p = QPainterPath() p.moveTo(*pts[0]) p.lineTo(*pts[1]) # p.lineTo(*pts[2]) p.arcTo(QRectF(-R, -R, 2*R, 2*R), aL, AL-aL) p.lineTo(*pts[3]) # p.lineTo(*pts[0]) p.arcTo(QRectF(-r, -r, 2*r, 2*r), Al, -(Al-al)) self._path = p self._text_rf = QRectF(*sgm.text_bbox_SCR())
def drawCellBackground(self, painter, rect): if self.shouldDrawMarkColor: markColor = self.glyph.markColor if markColor is not None: color = colorToQColor(markColor) color.setAlphaF(.7 * color.alphaF()) painter.fillRect(*(rect+(color,))) if self.shouldDrawHeader: if self.glyph.dirty: x, y, w, h = rect painter.fillRect(*(rect+(cellDirtyColor,))) path = QPainterPath() path.moveTo(x + w - 12, 0) path.lineTo(x + w, 0) path.lineTo(x + w, 12) path.closeSubpath() painter.fillPath(path, QColor(255, 0, 0, 170))
def arrow(x0, x1, arrow_size=0.3, arrow_angle=pi/5): dx, dy = x1 - x0 if dy**2 + dx**2 < arrow_size**2: return None path = QPainterPath() path.moveTo(*x0) path.lineTo(*x1) angle = atan2(dy, dx) p1 = x1 + [cos(angle + pi + arrow_angle) * arrow_size, sin(angle + pi + arrow_angle) * arrow_size] p2 = x1 + [cos(angle + pi - arrow_angle) * arrow_size, sin(angle + pi - arrow_angle) * arrow_size] path.addPolygon(QPolygonF([ QPointF(*x1), QPointF(*p1), QPointF(*p2), QPointF(*x1), ])) return path
def reshape(self): ''' Update the shape of the edge (redefined function) ''' path = QPainterPath() # If there is a starting point, draw a line to the first curve point if self.start_point: path.moveTo(self.source_connection.center) path.lineTo(self.bezier[0]) else: path.moveTo(self.source_connection.center) # Loop over the curve points: for group in self.bezier[1:]: path.cubicTo(*[point.center for point in group]) # If there is an ending point, draw a line to it if self.end_point: path.lineTo(self.end_connection.center) end_point = path.currentPosition() arrowhead = self.angle_arrow(path) path.lineTo(arrowhead[0]) path.moveTo(end_point) path.lineTo(arrowhead[1]) path.moveTo(end_point) try: # Add the transition label, if any (none for the START edge) font = QFont('arial', pointSize=8) metrics = QFontMetrics(font) label = self.edge.get('label', '') lines = label.split('\n') width = metrics.width(max(lines)) # longest line height = metrics.height() * len(lines) # lp is the position of the center of the text pos = self.mapFromScene(*self.edge['lp']) if not self.text_label: self.text_label = QGraphicsTextItem( self.edge.get('label', ''), parent=self) self.text_label.setX(pos.x() - width / 2) self.text_label.setY(pos.y() - height / 2) self.text_label.setFont(font) # Make horizontal center alignment, as dot does self.text_label.setTextWidth(self.text_label.boundingRect().width()) fmt = QTextBlockFormat() fmt.setAlignment(Qt.AlignHCenter) cursor = self.text_label.textCursor() cursor.select(QTextCursor.Document) cursor.mergeBlockFormat(fmt) cursor.clearSelection() self.text_label.setTextCursor(cursor) self.text_label.show() except KeyError: # no label pass self.setPath(path)
def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) self._optionsRects = {} w, h = self.width(), self.height() metrics = self.fontMetrics() hphp = 2 * _hPad painter.save() path = QPainterPath() path.addRoundedRect(.5, .5, w - 1, h - 1, 4, 4) painter.fillPath(path, QColor(250, 250, 250)) x = 0 linePath = QPainterPath() for text in self._options[:-1]: x += hphp + metrics.width(text) linePath.moveTo(x, 0) linePath.lineTo(x, h) pen = painter.pen() pen.setColor(QColor(218, 218, 218)) pen.setWidth(0) painter.setPen(pen) painter.drawPath(path) painter.setRenderHint(QPainter.Antialiasing, False) painter.drawPath(linePath) painter.restore() painter.translate(_hPad, _vPad + metrics.ascent()) left = 0 for index, text in enumerate(self._options): if index in self._selection: color = QColor(20, 146, 230) else: color = QColor(63, 63, 63) painter.setPen(color) painter.drawText(0, 0, text) textWidth = metrics.width(text) rectWidth = textWidth + hphp rect = (left, 0, rectWidth, h) self._optionsRects[index] = rect painter.translate(rectWidth, 0) left += rectWidth
def draw_path(self): plan = self.plan rect = plan.mapRectToScene(plan.viewport().rect()) rect.setWidth(10**floor(log10(rect.width()/2))) text = "{} m".format(round(rect.width())) tran = self.deviceTransform(plan.viewportTransform()).inverted()[0] width = tran.mapRect(QRectF( plan.mapFromScene(rect.topLeft()), plan.mapFromScene(rect.bottomRight()))).width() view = tran.mapRect(plan.viewport().rect()) x0 = QPointF(view.right() - view.width()/15, view.bottom() - view.height()/15) x1 = x0 - QPointF(width, 0) head = QPointF(0, 8) path = QPainterPath() path.moveTo(x0) path.lineTo(x1) path.moveTo(x0 + head) path.lineTo(x0 - head) path.moveTo(x1 + head) path.lineTo(x1 - head) # add label font = QFont(plan.font()) font.setPointSize(14) rect = QFontMetrics(font).boundingRect(text) size = tran.mapRect(QRectF(rect)).size() w, h = size.width(), size.height() offs = [-w/2, -h/2] path.addText((x0+x1)/2 + QPointF(*offs), font, text) return path
def handleShapeDescription(self, shape, list, textOnly=False): if (shape.type() != "KoSvgTextShapeID" and textOnly is True): return shapeDesc = {} shapeDesc["name"] = shape.name() rect = shape.boundingBox() listOfPoints = [rect.topLeft(), rect.topRight(), rect.bottomRight(), rect.bottomLeft()] shapeDoc = minidom.parseString(shape.toSvg()) docElem = shapeDoc.documentElement svgRegExp = re.compile('[MLCSQHVATmlzcqshva]\d+\.?\d* \d+\.?\d*') transform = docElem.getAttribute("transform") coord = [] adjust = QTransform() # TODO: If we get global transform api, use that instead of parsing manually. if "translate" in transform: transform = transform.replace('translate(', '') for c in transform[:-1].split(" "): coord.append(float(c)) if len(coord) < 2: coord.append(coord[0]) adjust = QTransform(1, 0, 0, 1, coord[0], coord[1]) if "matrix" in transform: transform = transform.replace('matrix(', '') for c in transform[:-1].split(" "): coord.append(float(c)) adjust = QTransform(coord[0], coord[1], coord[2], coord[3], coord[4], coord[5]) path = QPainterPath() if docElem.localName == "path": dVal = docElem.getAttribute("d") listOfSvgStrings = [" "] listOfSvgStrings = svgRegExp.findall(dVal) if listOfSvgStrings: listOfPoints = [] for l in listOfSvgStrings: line = l[1:] coordinates = line.split(" ") if len(coordinates) < 2: coordinates.append(coordinates[0]) x = float(coordinates[-2]) y = float(coordinates[-1]) offset = QPointF() if l.islower(): offset = listOfPoints[0] if l.lower().startswith("m"): path.moveTo(QPointF(x, y) + offset) elif l.lower().startswith("h"): y = listOfPoints[-1].y() path.lineTo(QPointF(x, y) + offset) elif l.lower().startswith("v"): x = listOfPoints[-1].x() path.lineTo(QPointF(x, y) + offset) elif l.lower().startswith("c"): path.cubicTo(coordinates[0], coordinates[1], coordinates[2], coordinates[3], x, y) else: path.lineTo(QPointF(x, y) + offset) path.setFillRule(Qt.WindingFill) for polygon in path.simplified().toSubpathPolygons(adjust): for point in polygon: listOfPoints.append(point) elif docElem.localName == "rect": listOfPoints = [] if (docElem.hasAttribute("x")): x = float(docElem.getAttribute("x")) else: x = 0 if (docElem.hasAttribute("y")): y = float(docElem.getAttribute("y")) else: y = 0 w = float(docElem.getAttribute("width")) h = float(docElem.getAttribute("height")) path.addRect(QRectF(x, y, w, h)) for point in path.toFillPolygon(adjust): listOfPoints.append(point) elif docElem.localName == "ellipse": listOfPoints = [] if (docElem.hasAttribute("cx")): x = float(docElem.getAttribute("cx")) else: x = 0 if (docElem.hasAttribute("cy")): y = float(docElem.getAttribute("cy")) else: y = 0 ry = float(docElem.getAttribute("ry")) rx = float(docElem.getAttribute("rx")) path.addEllipse(QPointF(x, y), rx, ry) for point in path.toFillPolygon(adjust): listOfPoints.append(point) elif docElem.localName == "text": # NOTE: This only works for horizontal preformated text. Vertical text needs a different # ordering of the rects, and wraparound should try to take the shape it is wrapped in. family = "sans-serif" if docElem.hasAttribute("font-family"): family = docElem.getAttribute("font-family") size = "11" if docElem.hasAttribute("font-size"): size = docElem.getAttribute("font-size") multilineText = True for el in docElem.childNodes: if el.nodeType == minidom.Node.TEXT_NODE: multilineText = False if multilineText: listOfPoints = [] listOfRects = [] # First we collect all the possible line-rects. for el in docElem.childNodes: if docElem.hasAttribute("font-family"): family = docElem.getAttribute("font-family") if docElem.hasAttribute("font-size"): size = docElem.getAttribute("font-size") fontsize = int(size) font = QFont(family, fontsize) string = el.toxml() string = re.sub("\<.*?\>", " ", string) string = string.replace(" ", " ") width = min(QFontMetrics(font).width(string.strip()), rect.width()) height = QFontMetrics(font).height() anchor = "start" if docElem.hasAttribute("text-anchor"): anchor = docElem.getAttribute("text-anchor") top = rect.top() if len(listOfRects)>0: top = listOfRects[-1].bottom() if anchor == "start": spanRect = QRectF(rect.left(), top, width, height) listOfRects.append(spanRect) elif anchor == "end": spanRect = QRectF(rect.right()-width, top, width, height) listOfRects.append(spanRect) else: # Middle spanRect = QRectF(rect.center().x()-(width*0.5), top, width, height) listOfRects.append(spanRect) # Now we have all the rects, we can check each and draw a # polygon around them. heightAdjust = (rect.height()-(listOfRects[-1].bottom()-rect.top()))/len(listOfRects) for i in range(len(listOfRects)): span = listOfRects[i] addtionalHeight = i*heightAdjust if i == 0: listOfPoints.append(span.topLeft()) listOfPoints.append(span.topRight()) else: if listOfRects[i-1].width()< span.width(): listOfPoints.append(QPointF(span.right(), span.top()+addtionalHeight)) listOfPoints.insert(0, QPointF(span.left(), span.top()+addtionalHeight)) else: bottom = listOfRects[i-1].bottom()+addtionalHeight-heightAdjust listOfPoints.append(QPointF(listOfRects[i-1].right(), bottom)) listOfPoints.insert(0, QPointF(listOfRects[i-1].left(), bottom)) listOfPoints.append(QPointF(span.right(), rect.bottom())) listOfPoints.insert(0, QPointF(span.left(), rect.bottom())) path = QPainterPath() path.moveTo(listOfPoints[0]) for p in range(1, len(listOfPoints)): path.lineTo(listOfPoints[p]) path.closeSubpath() listOfPoints = [] for point in path.toFillPolygon(adjust): listOfPoints.append(point) shapeDesc["boundingBox"] = listOfPoints if (shape.type() == "KoSvgTextShapeID" and textOnly is True): shapeDesc["text"] = shape.toSvg() list.append(shapeDesc)
def updateFloatPath(self, point=None): """ Draws a quad curve from the edge of the fromBase to the top or bottom of the toBase (q5), and finally to the center of the toBase (toBaseEndpoint). If floatPos!=None, this is a floatingXover and floatPos is the destination point (where the mouse is) while toHelix, toIndex are potentially None and represent the base at floatPos. Args: point (None, optional): Description """ node3 = self._node3 node5 = self._node5 bw = _BASE_WIDTH vhi5 = self._virtual_helix_item nucleicacid_part_item = vhi5.partItem() pt5 = vhi5.mapToItem(nucleicacid_part_item, *node5.floatPoint()) n5_is_forward = node5.is_forward # Enter/exit are relative to the direction that the path travels # overall. five_enter_pt = pt5 + QPointF(0 if n5_is_forward else 1, .5)*bw five_center_pt = pt5 + QPointF(.5, .5)*bw five_exit_pt = pt5 + QPointF(.5, 0 if n5_is_forward else 1)*bw vhi3 = node3.virtualHelixItem() if point: pt3 = point n3_is_forward = True same_strand = False same_parity = False three_enter_pt = three_center_pt = three_exit_pt = pt3 else: pt3 = vhi3.mapToItem(nucleicacid_part_item, *node3.point()) n3_is_forward = node3.is_forward same_strand = (n5_is_forward == n3_is_forward) and vhi3 == vhi5 same_parity = n5_is_forward == n3_is_forward three_enter_pt = pt3 + QPointF(.5, 0 if n3_is_forward else 1)*bw three_center_pt = pt3 + QPointF(.5, .5)*bw three_exit_pt = pt3 + QPointF(1 if n3_is_forward else 0, .5)*bw c1 = QPointF() # case 1: same strand if same_strand: dx = abs(three_enter_pt.x() - five_exit_pt.x()) c1.setX(0.5 * (five_exit_pt.x() + three_enter_pt.x())) if n5_is_forward: c1.setY(five_exit_pt.y() - _yScale * dx) else: c1.setY(five_exit_pt.y() + _yScale * dx) # case 2: same parity elif same_parity: dy = abs(three_enter_pt.y() - five_exit_pt.y()) c1.setX(five_exit_pt.x() + _xScale * dy) c1.setY(0.5 * (five_exit_pt.y() + three_enter_pt.y())) # case 3: different parity else: if n5_is_forward: c1.setX(five_exit_pt.x() - _xScale * abs(three_enter_pt.y() - five_exit_pt.y())) else: c1.setX(five_exit_pt.x() + _xScale * abs(three_enter_pt.y() - five_exit_pt.y())) c1.setY(0.5 * (five_exit_pt.y() + three_enter_pt.y())) # Construct painter path painterpath = QPainterPath() painterpath.moveTo(five_enter_pt) painterpath.lineTo(five_center_pt) painterpath.lineTo(five_exit_pt) painterpath.quadTo(c1, three_enter_pt) painterpath.lineTo(three_center_pt) painterpath.lineTo(three_exit_pt) self.setPath(painterpath) self._updateFloatPen()
def createSquareGrid(self, part_item: SliceNucleicAcidPartItemT, radius: float, bounds: RectT): """Instantiate an area of griditems arranged on a square lattice. Args: part_item: Description radius: Description bounds: Description """ doLattice = SquareDnaPart.latticeCoordToModelXY doPosition = SquareDnaPart.positionToLatticeCoordRound x_l, x_h, y_l, y_h = bounds x_l = x_l + SquareDnaPart.PAD_GRID_XL x_h = x_h + SquareDnaPart.PAD_GRID_XH y_h = y_h + SquareDnaPart.PAD_GRID_YL y_l = y_l + SquareDnaPart.PAD_GRID_YH dot_size, half_dot_size = self.dots sf = part_item.scale_factor points = self.points row_l, col_l = doPosition(radius, x_l, -y_l, scale_factor=sf) row_h, col_h = doPosition(radius, x_h, -y_h, scale_factor=sf) redo_neighbors = (row_l, col_l, row_h, col_h) != \ self.previous_grid_bounds or self.previous_grid_type != self.grid_type self.previous_grid_type = self.grid_type if redo_neighbors: neighbor_map = dict() path = QPainterPath() is_pen_down = False draw_lines = self.draw_lines for row in range(row_l, row_h + 1): for column in range(col_l, col_h + 1): x, y = doLattice(radius, row, column, scale_factor=sf) if draw_lines: if is_pen_down: path.lineTo(x, -y) else: is_pen_down = True path.moveTo(x, -y) """ +x is Left and +y is down origin of ellipse is Top Left corner so we subtract half in X and subtract in y """ pt = GridPoint(x - half_dot_size, -y - half_dot_size, dot_size, self, coord=(row, column)) if self._draw_gridpoint_coordinates: font = QFont(styles.THE_FONT) path.addText(x - 10, -y + 5, font, "%s,%s" % (-row, column)) pt.setPen( getPenObj(styles.GRAY_STROKE, styles.EMPTY_HELIX_STROKE_WIDTH)) # if x == 0 and y == 0: # pt.setBrush(getBrushObj(Qt.gray)) points.append(pt) self.points_dict[(-row, column)] = pt if redo_neighbors: self.previous_grid_bounds = (row_l, col_l, row_h, col_h) is_pen_down = False # pen up # DO VERTICAL LINES if draw_lines: for column in range(col_l, col_h + 1): for row in range(row_l, row_h + 1): x, y = doLattice(radius, row, column, scale_factor=sf) if is_pen_down: path.lineTo(x, -y) else: is_pen_down = True path.moveTo(x, -y) is_pen_down = False # pen up self._path.setPath(path)
def paintEvent(self, pe): p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) pen = QPen() pen.setWidth(1) pen.setColor(QColor(0x8c, 0xa3, 0xb0)) p.setPen(pen) p.setBrush(QColor(0xe4, 0xec, 0xf4)) rx = 6 space = self.space w = self.usable_width kw = self.key_w def drawRow(row, sx, sy, last_end=False): x = sx y = sy keys = row rw = w - sx i = 0 for k in keys: rect = QRectF(x, y, kw, kw) if i == len(keys) - 1 and last_end: rect.setWidth(rw) p.drawRoundedRect(rect, rx, rx) p.setPen(Qt.black) rect.adjust(5, 1, 0, 0) p.setFont(self.lowerFont) p.drawText( rect, Qt.AlignLeft | Qt.AlignBottom, self.regular_text(k)) p.setFont(self.upperFont) p.drawText( rect, Qt.AlignLeft | Qt.AlignTop, self.shift_text(k)) rw = rw - space - kw x = x + space + kw i = i + 1 p.setPen(pen) return (x, rw) x = .5 y = .5 keys = self.kb["keys"] ext_return = self.kb["extended_return"] first_key_w = 0 rows = 4 remaining_x = [0, 0, 0, 0] remaining_widths = [0, 0, 0, 0] for i in range(0, rows): if first_key_w > 0: first_key_w = first_key_w * 1.375 if self.kb == self.kb_105 and i == 3: first_key_w = kw * 1.275 rect = QRectF(x, y, first_key_w, kw) p.drawRoundedRect(rect, rx, rx) x = x + first_key_w + space else: first_key_w = kw x, rw = drawRow(keys[i], x, y, i == 1 and not ext_return) remaining_x[i] = x remaining_widths[i] = rw if i != 1 and i != 2: rect = QRectF(x, y, rw, kw) p.drawRoundedRect(rect, rx, rx) x = .5 y = y + space + kw if ext_return: rx = rx * 2 x1 = remaining_x[1] y1 = .5 + kw * 1 + space * 1 w1 = remaining_widths[1] x2 = remaining_x[2] y2 = .5 + kw * 2 + space * 2 # this is some serious crap... but it has to be so # maybe one day keyboards won't look like this... # one can only hope pp = QPainterPath() pp.moveTo(x1, y1 + rx) pp.arcTo(x1, y1, rx, rx, 180, -90) pp.lineTo(x1 + w1 - rx, y1) pp.arcTo(x1 + w1 - rx, y1, rx, rx, 90, -90) pp.lineTo(x1 + w1, y2 + kw - rx) pp.arcTo(x1 + w1 - rx, y2 + kw - rx, rx, rx, 0, -90) pp.lineTo(x2 + rx, y2 + kw) pp.arcTo(x2, y2 + kw - rx, rx, rx, -90, -90) pp.lineTo(x2, y1 + kw) pp.lineTo(x1 + rx, y1 + kw) pp.arcTo(x1, y1 + kw - rx, rx, rx, -90, -90) pp.closeSubpath() p.drawPath(pp) else: x = remaining_x[2] y = .5 + kw * 2 + space * 2 rect = QRectF(x, y, remaining_widths[2], kw) p.drawRoundedRect(rect, rx, rx) QWidget.paintEvent(self, pe)
from trufont.controls.statusBar import StatusBar from trufont.controls.tabWidget import TabWidget from trufont.controls.toolBar import ToolBar from trufont.objects import settings from trufont.objects.menu import Entries from trufont.tools import errorReports, platformSpecific from trufont.tools.uiMethods import deleteUISelection, removeUIGlyphElements from trufont.windows.fontFeaturesWindow import FontFeaturesWindow from trufont.windows.fontInfoWindow import FontInfoWindow from trufont.windows.groupsWindow import GroupsWindow from trufont.windows.kerningWindow import KerningWindow from trufont.windows.metricsWindow import MetricsWindow _path = QPainterPath() _path.moveTo(5, 8) _path.lineTo(23, 8) _path.lineTo(23, 10) _path.lineTo(5, 10) _path.closeSubpath() _path.moveTo(5, 13) _path.lineTo(23, 13) _path.lineTo(23, 15) _path.lineTo(5, 15) _path.closeSubpath() _path.moveTo(5, 18) _path.lineTo(23, 18) _path.lineTo(23, 20) _path.lineTo(5, 20) _path.closeSubpath()
def setupShapes(self): truck = QPainterPath() truck.setFillRule(Qt.WindingFill) truck.moveTo(0.0, 87.0) truck.lineTo(0.0, 60.0) truck.lineTo(10.0, 60.0) truck.lineTo(35.0, 35.0) truck.lineTo(100.0, 35.0) truck.lineTo(100.0, 87.0) truck.lineTo(0.0, 87.0) truck.moveTo(17.0, 60.0) truck.lineTo(55.0, 60.0) truck.lineTo(55.0, 40.0) truck.lineTo(37.0, 40.0) truck.lineTo(17.0, 60.0) truck.addEllipse(17.0, 75.0, 25.0, 25.0) truck.addEllipse(63.0, 75.0, 25.0, 25.0) clock = QPainterPath() clock.addEllipse(-50.0, -50.0, 100.0, 100.0) clock.addEllipse(-48.0, -48.0, 96.0, 96.0) clock.moveTo(0.0, 0.0) clock.lineTo(-2.0, -2.0) clock.lineTo(0.0, -42.0) clock.lineTo(2.0, -2.0) clock.lineTo(0.0, 0.0) clock.moveTo(0.0, 0.0) clock.lineTo(2.732, -0.732) clock.lineTo(24.495, 14.142) clock.lineTo(0.732, 2.732) clock.lineTo(0.0, 0.0) house = QPainterPath() house.moveTo(-45.0, -20.0) house.lineTo(0.0, -45.0) house.lineTo(45.0, -20.0) house.lineTo(45.0, 45.0) house.lineTo(-45.0, 45.0) house.lineTo(-45.0, -20.0) house.addRect(15.0, 5.0, 20.0, 35.0) house.addRect(-35.0, -15.0, 25.0, 25.0) text = QPainterPath() font = QFont() font.setPixelSize(50) fontBoundingRect = QFontMetrics(font).boundingRect("Qt") text.addText(-QPointF(fontBoundingRect.center()), font, "Qt") self.shapes = (clock, house, text, truck) self.shapeComboBox.activated.connect(self.shapeSelected)
def draw_photon(self, qp, start_x, start_y, up): wx = np.arange(0, 100.0, 0.1) wy = np.sin(wx * 3.14159 * 0.1) * 15 pen = QPen() pen.setWidth(2) if up == True: pen.setColor(QColor(0, 0, 255)) else: pen.setColor(QColor(0, 255, 0)) qp.setPen(pen) for i in range(1, len(wx)): qp.drawLine((int)(start_x - wy[i - 1]), (int)(start_y + wx[i - 1]), (int)(start_x - wy[i]), (int)(start_y + wx[i])) if up == True: path = QPainterPath() path.moveTo(start_x - 10, start_y) path.lineTo(start_x - 10, start_y) path.lineTo(start_x + 10, start_y) path.lineTo(start_x, start_y - 20) qp.fillPath(path, QBrush(QColor(0, 0, 255))) else: path = QPainterPath() path.moveTo(start_x - 10, start_y + 100.0) path.lineTo(start_x - 10, start_y + 100.0) path.lineTo(start_x + 10, start_y + 100.0) path.lineTo(start_x, start_y + 100.0 + 20) qp.setPen(Qt.NoPen) qp.fillPath(path, QBrush(QColor(0, 255, 0)))
from PyQt5.QtCore import QSize, Qt from PyQt5.QtGui import QColor, QPainter, QPainterPath from PyQt5.QtWidgets import (QHBoxLayout, QLabel, QSpinBox, QSizePolicy, QWidget) from simplefont.controls.pathButton import PathButton __all__ = ["StatusBar"] _minPath = QPainterPath() _minPath.moveTo(1, 6) _minPath.lineTo(11, 6) _plusPath = QPainterPath(_minPath) _plusPath.moveTo(6, 1) _plusPath.lineTo(6, 11) _minPath.translate(5, 7) _plusPath.translate(5, 7) def Button(): btn = PathButton() btn.setIsDownColor(QColor(210, 210, 210)) btn.setIsFlipped(True) btn.setSize(QSize(23, 25)) return btn class StatusBar(QWidget): """ Use the *sizeChanged* signal for size changes.
def getqgp(self): qpp = QPainterPath(self.points[0]) for p in self.points[1:]: qpp.lineTo(p) return QGraphicsPathItem(qpp)
def paintEvent(self, ev: QtGui.QPaintEvent): p = QPainter(self) option = QStyleOptionButton() option.initFrom(self) #background p.fillRect(0, 0, self.width(), self.height(), QColor('#131722')) #x-grid path = QPainterPath() x = self.moving.x() y = self.moving.y() path.moveTo(x + -4, 0 + y) path.lineTo(x + -4, 233 + +y) path.moveTo(x + 93, 0 + y) path.lineTo(x + 93, 233 + +y) path.moveTo(x + 190, 0 + y) path.lineTo(x + 190, 233 + +y) path.moveTo(x + 287, 0 + y) path.lineTo(x + 287, 233 + +y) path.moveTo(x + 384, 0 + y) path.lineTo(x + 384, 233 + +y) p.setPen(QColor('#363c4e')) p.drawPath(path) #y-grid path = QPainterPath() path.moveTo(x + 0, 2 + y) path.lineTo(x + 440, 2 + y) path.moveTo(x + 0, 40 + y) path.lineTo(x + 440, 40 + y) path.moveTo(x + 0, 77 + y) path.lineTo(x + 440, 77 + y) path.moveTo(x + 0, 114 + y) path.lineTo(x + 440, 114 + y) path.moveTo(x + 0, 152 + y) path.lineTo(x + 440, 152 + y) path.moveTo(x + 0, 189 + y) path.lineTo(x + 440, 189 + y) path.moveTo(x + 0, 226 + y) path.lineTo(x + 440, 226 + y) p.setPen(QColor('#363c4e')) p.drawPath(path) # candle p.fillRect(44, 40, 1, 0, QColor('#336854')) p.fillRect(34, 35, 1, 9, QColor('#336854')) p.fillRect(24, 12, 1, 37, QColor('#336854')) p.fillRect(15, 44, 1, 28, QColor('#336854')) p.fillRect(5, 68, 1, 23, QColor('#336854')) p.fillRect(-5, 12, 1, 102, QColor('#336854')) p.fillRect(41, 40, 7, 1, QColor('#53b987')) p.fillRect(31, 40, 7, 1, QColor('#53b987')) p.fillRect(21, 40, 7, 5, QColor('#53b987')) p.fillRect(12, 44, 7, 29, QColor('#53b987')) p.fillRect(2, 72, 7, 15, QColor('#53b987')) p.fillRect(-8, 86, 7, 29, QColor('#53b987')) if option.state & QStyle.State_MouseOver: self.setCursor(Qt.PointingHandCursor) # print(self.width(), self.height()) #price path = QPainterPath() path.moveTo(0, 40) path.lineTo(440, 40) pen = p.pen() pen.setStyle(Qt.DashDotLine) pen.setColor(QColor("#53b987")) p.setPen(pen) p.drawPath(path) #mouse path = QPainterPath() path.moveTo(0, self.pos.y()) path.lineTo(self.width(), self.pos.y()) path.moveTo(self.pos.x(), 0) path.lineTo(self.pos.x(), self.height()) p.setPen(Qt.red) p.drawPath(path)
class Drawer(QWidget): newPoint = pyqtSignal(QtCore.QPoint) def __init__(self, parent=None): QWidget.__init__(self, parent) self.path = QPainterPath() self.btn = QPushButton('classify', self) self.btn.clicked.connect(self.btn_event) self._left = False self.setStyleSheet("background-color:white;") self.img_data = None #print(dir(self.newPoint)) def btn_event(self): digit = load_and_predict.classify(self.img_data) buttonReply = QMessageBox.information( self, 'res', 'you are writing:{}'.format(digit), QMessageBox.Yes, QMessageBox.Yes) if buttonReply == QMessageBox.Yes: self.path = QPainterPath() self.update() def btnEvent2(self): print('hi') def paintEvent(self, event): p = QPen(QtCore.Qt.black) p.setWidth(20) painter = QPainter(self) painter.setPen(p) painter.drawPath(self.path) painter.end() def mousePressEvent(self, event): if event.button() == QtCore.Qt.LeftButton: self.path.moveTo(event.pos()) self._left = True pass elif event.button() == QtCore.Qt.RightButton: pass #print(dir(event)) self.update() def mouseMoveEvent(self, event): if self._left: self.path.lineTo(event.pos()) self.newPoint.emit(event.pos()) self.update() def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.LeftButton: px = self.grab() img = px.toImage() img = img.convertToFormat(QImage.Format_Grayscale8) file_name = 'tmp.jpg' img.save(file_name) cvMat = cv2.imread(file_name, -1) cvMat = 255 - cvMat self.img_data = cvMat self._left = False pass elif event.button() == QtCore.Qt.RightButton: self.path = QPainterPath() pass self.update() pass def sizeHint(self): return QtCore.QSize(300, 300)
from PyQt5.QtCore import pyqtSignal, QEvent, QRect, QSize, Qt from PyQt5.QtGui import QColor, QPainter, QPainterPath from PyQt5.QtWidgets import QSizePolicy, QToolTip, QWidget __all__ = ["TabWidget"] sidePadding = 9 spacing = 2 topPadding = bottomPadding = 5 crossMargin = sidePadding crossSize = 7 cross = QPainterPath() cross.moveTo(0.38, 0.38) cross.lineTo(9.63, 9.63) cross.moveTo(0.38, 9.63) cross.lineTo(9.63, 0.38) class TabWidget(QWidget): """ # TODO: RTL support? """ currentTabChanged = pyqtSignal(int) tabRemoved = pyqtSignal(int) def __init__(self, parent=None): super().__init__(parent) self.setMouseTracking(True) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
def paintEvent(self,event): #在窗口上绘图 painter=QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QPainter.TextAntialiasing) ##生成五角星的5个顶点的,假设原点在五角星中心 R=100.0 #半径 Pi=3.14159 #常数 deg=Pi*72.0/180 points=[QPoint(R,0), QPoint(R*math.cos(deg), -R*math.sin(deg)), QPoint(R*math.cos(2*deg), -R*math.sin(2*deg)), QPoint(R*math.cos(3*deg), -R*math.sin(3*deg)), QPoint(R*math.cos(4*deg), -R*math.sin(4*deg)) ] #元组数据 font=painter.font() font.setPointSize(14) font.setBold(False) painter.setFont(font) #设置画笔 pen=QPen() pen.setWidth(2) #线宽 pen.setColor(Qt.blue) #划线颜色 pen.setStyle(Qt.SolidLine) #线的类型,实线、虚线等 pen.setCapStyle(Qt.FlatCap) #线端点样式 pen.setJoinStyle(Qt.BevelJoin) #线的连接点样式 painter.setPen(pen) ##设置画刷 brush=QBrush() brush.setColor(Qt.yellow) #画刷颜色 brush.setStyle(Qt.SolidPattern) #填充样式 painter.setBrush(brush) ##设计绘制五角星的PainterPath,以便重复使用 starPath=QPainterPath() starPath.moveTo(points[0]) starPath.lineTo(points[2]) starPath.lineTo(points[4]) starPath.lineTo(points[1]) starPath.lineTo(points[3]) starPath.closeSubpath() #闭合路径,最后一个点与第一个点相连 starPath.addText(points[0],font,"0") #显示端点编号 starPath.addText(points[1],font,"1") starPath.addText(points[2],font,"2") starPath.addText(points[3],font,"3") starPath.addText(points[4],font,"4") ##绘图 painter.save() #保存坐标状态 painter.translate(100,120) painter.drawPath(starPath) #画星星 painter.drawText(0,0,"S1") painter.restore() #恢复坐标状态 painter.translate(300,120) #平移 painter.scale(0.8,0.8) #缩放 painter.rotate(90) #顺时针旋转 painter.drawPath(starPath) #画星星 painter.drawText(0,0,"S2") painter.resetTransform() #复位所有坐标变换 painter.translate(500,120) #平移 painter.rotate(-145) #逆时针旋转 painter.drawPath(starPath) #画星星 painter.drawText(0,0,"S3")
def createArrowBackground(self, transform): scaledRect = transform.mapRect( QRect(0, 0, self.logicalSize.width(), self.logicalSize.height())) image = QImage(scaledRect.width(), scaledRect.height(), QImage.Format_ARGB32_Premultiplied) image.fill(QColor(0, 0, 0, 0).rgba()) painter = QPainter(image) painter.setRenderHint(QPainter.SmoothPixmapTransform) painter.setRenderHint(QPainter.Antialiasing) painter.setPen(Qt.NoPen) if Colors.useEightBitPalette: painter.setPen(QColor(120, 120, 120)) if self.pressed: painter.setBrush(QColor(60, 60, 60)) elif self.highlighted: painter.setBrush(QColor(100, 100, 100)) else: painter.setBrush(QColor(80, 80, 80)) else: outlinebrush = QLinearGradient(0, 0, 0, scaledRect.height()) brush = QLinearGradient(0, 0, 0, scaledRect.height()) brush.setSpread(QLinearGradient.PadSpread) highlight = QColor(255, 255, 255, 70) shadow = QColor(0, 0, 0, 70) sunken = QColor(220, 220, 220, 30) normal1 = QColor(200, 170, 160, 50) normal2 = QColor(50, 10, 0, 50) if self.pressed: outlinebrush.setColorAt(0, shadow) outlinebrush.setColorAt(1, highlight) brush.setColorAt(0, sunken) painter.setPen(Qt.NoPen) else: outlinebrush.setColorAt(1, shadow) outlinebrush.setColorAt(0, highlight) brush.setColorAt(0, normal1) if not self.highlighted: brush.setColorAt(1, normal2) painter.setPen(QPen(outlinebrush, 1)) painter.setBrush(brush) painter.draw_rect(0, 0, scaledRect.width(), scaledRect.height()) xOff = scaledRect.width() / 2 yOff = scaledRect.height() / 2 sizex = 3.0 * transform.m11() sizey = 1.5 * transform.m22() if self.type == TextButton.UP: sizey *= -1 path = QPainterPath() path.moveTo(xOff, yOff + (5 * sizey)) path.lineTo(xOff - (4 * sizex), yOff - (3 * sizey)) path.lineTo(xOff + (4 * sizex), yOff - (3 * sizey)) path.lineTo(xOff, yOff + (5 * sizey)) painter.draw_path(path) return image
def createHoneycombGrid(self, part_item, radius, bounds): """Instantiate an area of griditems arranged on a honeycomb lattice. Args: part_item (TYPE): Description radius (TYPE): Description bounds (TYPE): Description Returns: TYPE: Description """ doLattice = HoneycombDnaPart.latticeCoordToModelXY doPosition = HoneycombDnaPart.positionModelToLatticeCoord isEven = HoneycombDnaPart.isEvenParity x_l, x_h, y_l, y_h = bounds x_l = x_l + HoneycombDnaPart.PAD_GRID_XL x_h = x_h + HoneycombDnaPart.PAD_GRID_XH y_h = y_h + HoneycombDnaPart.PAD_GRID_YL y_l = y_l + HoneycombDnaPart.PAD_GRID_YH dot_size, half_dot_size = self.dots sf = part_item.scale_factor points = self.points row_l, col_l = doPosition(radius, x_l, -y_l, scale_factor=sf) row_h, col_h = doPosition(radius, x_h, -y_h, scale_factor=sf) redo_neighbors = (row_l, col_l, row_h, col_h) != self.previous_grid_bounds or\ self.previous_grid_type != self.grid_type self.previous_grid_type = self.grid_type path = QPainterPath() is_pen_down = False draw_lines = self.draw_lines if redo_neighbors: self.points_dict = dict() for row in range(row_l, row_h): for column in range(col_l, col_h+1): x, y = doLattice(radius, row, column, scale_factor=sf) if draw_lines: if is_pen_down: path.lineTo(x, -y) else: is_pen_down = True path.moveTo(x, -y) """ +x is Left and +y is down origin of ellipse is Top Left corner so we subtract half in X and subtract in y """ pt = GridPoint(x - half_dot_size, -y - half_dot_size, dot_size, self, coord=(row, column)) if self._draw_gridpoint_coordinates: font = QFont(styles.THE_FONT, 6) path.addText(x - 5, -y + 4, font, "%s,%s" % (-row, column)) pt.setPen(getPenObj(styles.GRAY_STROKE, styles.EMPTY_HELIX_STROKE_WIDTH)) # if x == 0 and y == 0: # pt.setBrush(getBrushObj(Qt.gray)) points.append(pt) self.points_dict[(-row, column)] = pt if redo_neighbors: self.previous_grid_bounds = (row_l, col_l, row_h, col_h) is_pen_down = False if draw_lines: for column in range(col_l, col_h+1): for row in range(row_l, row_h): x, y = doLattice(radius, row, column, scale_factor=sf) if is_pen_down and isEven(row, column): path.lineTo(x, -y) is_pen_down = False else: is_pen_down = True path.moveTo(x, -y) is_pen_down = False # end for j self._path.setPath(path)
def point(self, x, y): path = QPainterPath() path.moveTo(x, y) path.lineTo(x + 0.1, y) self.renderPath(path)
def paintEvent(self, event): metrics = QFontMetrics(self.font) fw = metrics.width("0000000") fh = metrics.height() ascent = metrics.ascent() w, h = self.width(), self.height() painter = QPainter(self) painter.setFont(self.font) blackpen = QPen(Qt.black, 1) greypen = QPen(Qt.gray, 1) painter.setPen(blackpen) fill = QBrush(QColor(255, 255, 255)) painter.fillRect(QRect(fw, 0, w - fw - 1, h - fh), fill) if self.A.shape[1]: X, Y = numpy.moveaxis(self.A[:, -w // 2:], 2, 0) Ymin = min(0, Y.min()) Ymax = Y.max() maxticks = int((h - fh) / (1.5 * fh)) for k in count(0): if 2**k * maxticks >= Ymax: break ticks = Ymax / 2**k ticks = int(ticks + (-ticks) % 1) Ymax = ticks * 2**k Xmax = X.max() Xmin = Xmax - w / 2 for x in range(int(Xmin + (120 - Xmin) % 120), int(Xmax), 120): if x < 0: continue u = (w - fw) * (x - Xmin) / (Xmax - Xmin) + fw painter.setPen(greypen) painter.drawLine(u, 0, u, h - fh) painter.setPen(blackpen) sw = metrics.width(str(x)) if u - sw // 2 > fw and u + sw // 2 < w: painter.drawText(u - sw // 2, h, str(x)) for y in range(0, int(Ymax), 2**k): v = h - fh - (h - fh) * (y - Ymin) / (Ymax - Ymin) painter.setPen(greypen) painter.drawLine(fw, v, w, v) painter.setPen(blackpen) sw = metrics.width(str(y)) painter.drawText(fw - sw - 4, v + ascent / 3, str(y)) for pen, row in zip(self.pens, self.A): X, Y = row[-w // 2:].transpose() U = (w - fw) * (X - Xmin) / (Xmax - Xmin) + fw V = h - fh - (h - fh) * (Y - Ymin) / (Ymax - Ymin) painter.setPen(pen) path = QPainterPath() painter.setRenderHint(QPainter.Antialiasing) path.moveTo(U[0], V[0]) for x, y in zip(U[1:], V[1:]): path.lineTo(x, y) painter.drawPath(path) painter.setPen(blackpen) painter.drawRect(QRect(fw, 0, w - fw - 1, h - fh))
def line(self, x1, y1, x2, y2): path = QPainterPath() path.moveTo(x1, y1) path.lineTo(x2, y2) self.renderPath(path)
def _updatePath(self, strand5p: StrandT): """Draws a quad curve from the edge of the fromBase to the top or bottom of the toBase (q5), and finally to the center of the toBase (toBaseEndpoint). If floatPos!=None, this is a floatingXover and floatPos is the destination point (where the mouse is) while toHelix, toIndex are potentially None and represent the base at floatPos. Args: strand5p: Description """ group = self.group() self.tempReparent() node3 = self._node3 node5 = self._node5 bw = _BASE_WIDTH parent = self.partItem() vhi5 = self._virtual_helix_item pt5 = vhi5.mapToItem(parent, *node5.point()) n5_is_forward = node5.is_forward vhi3 = node3.virtualHelixItem() pt3 = vhi3.mapToItem(parent, *node3.point()) n3_is_forward = node3.is_forward same_strand = (n5_is_forward == n3_is_forward) and (vhi3 == vhi5) same_parity = n5_is_forward == n3_is_forward # Enter/exit are relative to the direction that the path travels # overall. five_enter_pt = pt5 + QPointF(0 if n5_is_forward else 1, .5) * bw five_center_pt = pt5 + QPointF(.5, .5) * bw # five_exit_pt = pt5 + QPointF(.85 if n5_is_forward else .15, 0 if n5_is_forward else 1)*bw five_exit_pt = pt5 + QPointF(.5 if n5_is_forward else .5, 0 if n5_is_forward else 1) * bw # three_enter_pt = pt3 + QPointF(.15 if n3_is_forward else .85, 0 if n3_is_forward else 1)*bw three_enter_pt = pt3 + QPointF(.5 if n3_is_forward else .5, 0 if n3_is_forward else 1) * bw three_center_pt = pt3 + QPointF(.5, .5) * bw three_exit_pt = pt3 + QPointF(1 if n3_is_forward else 0, .5) * bw c1 = QPointF() # case 1: same strand if same_strand: dx = abs(three_enter_pt.x() - five_exit_pt.x()) c1.setX(0.5 * (five_exit_pt.x() + three_enter_pt.x())) if n5_is_forward: c1.setY(five_exit_pt.y() - _Y_SCALE * dx) else: c1.setY(five_exit_pt.y() + _Y_SCALE * dx) # case 2: same parity elif same_parity: dy = abs(three_enter_pt.y() - five_exit_pt.y()) c1.setX(five_exit_pt.x() + _X_SCALE * dy) c1.setY(0.5 * (five_exit_pt.y() + three_enter_pt.y())) # case 3: different parity else: if n5_is_forward: c1.setX(five_exit_pt.x() - _X_SCALE * abs(three_enter_pt.y() - five_exit_pt.y())) else: c1.setX(five_exit_pt.x() + _X_SCALE * abs(three_enter_pt.y() - five_exit_pt.y())) c1.setY(0.5 * (five_exit_pt.y() + three_enter_pt.y())) # Construct painter path painterpath = QPainterPath() painterpath.moveTo(five_enter_pt) painterpath.lineTo(five_center_pt) painterpath.lineTo(five_exit_pt) # The xover5's non-crossing-over end (3') has a connection painterpath.quadTo(c1, three_enter_pt) painterpath.lineTo(three_center_pt) painterpath.lineTo(three_exit_pt) tempR = painterpath.boundingRect() tempR.adjust(-bw / 2, 0, bw, 0) self._click_area.setRect(tempR) self.setPath(painterpath) node3.updatePositionAndAppearance() node5.updatePositionAndAppearance() if group: group.addToGroup(self) self._updateColor(strand5p)
def doHoneycomb(self, part_item, radius, bounds): """Summary Args: part_item (TYPE): Description radius (TYPE): Description bounds (TYPE): Description Returns: TYPE: Description """ doLattice = HoneycombDnaPart.latticeCoordToPositionXY doPosition = HoneycombDnaPart.positionToLatticeCoordRound isEven = HoneycombDnaPart.isEvenParity x_l, x_h, y_l, y_h = bounds dot_size, half_dot_size = self.dots sf = part_item.scale_factor points = self.points row_l, col_l = doPosition(radius, x_l, -y_l, False, False, scale_factor=sf) row_h, col_h = doPosition(radius, x_h, -y_h, True, True, scale_factor=sf) # print(row_l, row_h, col_l, col_h) path = QPainterPath() is_pen_down = False draw_lines = self.draw_lines for i in range(row_l, row_h): for j in range(col_l, col_h + 1): x, y = doLattice(radius, i, j, scale_factor=sf) if draw_lines: if is_pen_down: path.lineTo(x, -y) else: is_pen_down = True path.moveTo(x, -y) """ +x is Left and +y is down origin of ellipse is Top Left corner so we subtract half in X and subtract in y """ pt = GridPoint(x - half_dot_size, -y - half_dot_size, dot_size, self) pt.setPen(getPenObj(Qt.blue, 1.0)) points.append(pt) is_pen_down = False # end for i # DO VERTICAL LINES if draw_lines: for j in range(col_l, col_h + 1): # print("newcol") for i in range(row_l, row_h): x, y = doLattice(radius, i, j, scale_factor=sf) if is_pen_down and isEven(i, j): path.lineTo(x, -y) is_pen_down = False else: is_pen_down = True path.moveTo(x, -y) is_pen_down = False # end for j self.setPath(path)
class PointerTrackGhost(QGraphicsPathItem): ''' A ghost for freehand drawing. Graphic between current PointerPosition and last PointerTrack path segment generated, which lags. Finally replaced by a path segment. Hidden when user not using freehand tool. Implementation: extend QGraphicsPathItem. Use a path of lines, one for each pointerTrack value. That is, there is no attempt here to make it minimal or smooth; that is what the rest of freehand is doing. I.E. this has about the same density as a bitmap of the pointerTrack. This presents a simplified API to FreehandTool, to reduce coupling between FreehandTool and Qt. ''' def __init__(self, **kwargs): super(PointerTrackGhost, self).__init__(**kwargs) self.start = None # cached start/end (don't get it from self.path) self.end = None self.path = QPainterPath( ) # working copy, frequently setPath() to self. self.hide() assert self.isVisible() == False, 'initial PointerTrackGhost is hidden' def showAt(self, initialPosition): ''' Resume using self, at given position, with length zero. ''' #print "showAt", initialPosition assert self.isVisible() == False, 'resumed PointerTrackGhost is hidden' self.start = initialPosition self.end = initialPosition self._replacePath() self.show() # assert path length is zero assert self.isVisible() == True def updateStart(self, pointSCS): ''' Shorten self by changing start, towards end. Called when freehand generator has traced an increment: determined one or more segments (lines and splines) that fit a prefix of self's path. Said segments are now displayed, thus remove the prefix of self's path that they represent. This implementation replaces working path with a single lineTo. (See below for work in progress, alternate implementation where we truncate a prefix of existing path.) Assert new start point is near self.end (so that result path is shorter.) ''' # not assert is visible, but might be assert isinstance(pointSCS, FreehandPoint) self.start = pointSCS self._replacePath() def _replacePath(self): ''' Completely abandon the working path and replace it with a new path, from cached start/end ''' self.path = QPainterPath() self.path.moveTo( self.start) # OLD self.floatSceneFromIntViewPoint(pointVCS)) self.path.lineTo(self.end) self.setPath(self.path) def updateEnd(self, point): ''' Update current path by appending lineTo new end point. ''' #print "updateEnd" assert isinstance(point, FreehandPoint) self.end = point self.path.lineTo(point) self.setPath(self.path) # hide() is inherited def floatSceneFromIntViewPoint(self, pointVCS): # !!! start point from FreehandTool is in View CS. pointViewInt = QPoint(pointVCS.x(), pointVCS.y()) pointSceneFloat = self.scene().views()[0].mapToScene(pointViewInt) return pointSceneFloat """
def refreshPath(self): """ Returns a QPainterPath object for the minor grid lines. The path also includes a border outline and a midline for dividing scaffold and staple bases. """ bw = _BASE_WIDTH bw2 = 2 * bw part = self.part() path = QPainterPath() sub_step_size = part.subStepSize() canvas_size = self._model_vh.getSize() # border path.addRect(0, 0, bw * canvas_size, 2 * bw) # minor tick marks for i in range(canvas_size): x = round(bw * i) if i % sub_step_size == 0: # path.moveTo(x - .5, 0) # path.lineTo(x - .5, bw2) # path.lineTo(x - .25, bw2) # path.lineTo(x - .25, 0) # path.lineTo(x, 0) # path.lineTo(x, bw2) # path.lineTo(x + .25, bw2) # path.lineTo(x + .25, 0) # path.lineTo(x + .5, 0) # path.lineTo(x + .5, bw2) # path.moveTo(x - .5, 0) # path.lineTo(x - .5, bw2) path.moveTo(x - .25, bw2) path.lineTo(x - .25, 0) path.lineTo(x, 0) path.lineTo(x, bw2) path.lineTo(x + .25, bw2) path.lineTo(x + .25, 0) # path.moveTo(x-.5, 0) # path.lineTo(x-.5, 2 * bw) # path.lineTo(x+.5, 2 * bw) # path.lineTo(x+.5, 0) else: path.moveTo(x, 0) path.lineTo(x, 2 * bw) # staple-scaffold divider path.moveTo(0, bw) path.lineTo(bw * canvas_size, bw) self.setPath(path)
def getLargerEdgePath(self): #Used to fill in the small areas on the edge #This makes it easier to select the edge yTranslation = 2 #Curve 1 beginPoint = QPointF(self.beginPoint.x(), self.beginPoint.y() + yTranslation) curvePoint1 = QPointF(self.curvePoint1.x() + 4, self.curvePoint1.y() + yTranslation) curvePoint2 = QPointF(self.curvePoint2.x() + 4, self.curvePoint2.y() + yTranslation) endPoint = QPointF(self.endPoint.x(), self.endPoint.y() + yTranslation) path = QPainterPath(beginPoint) point1 = QPointF(curvePoint1.x(), curvePoint1.y()) point2 = QPointF(curvePoint2.x(), curvePoint2.y()) path.cubicTo(point1, point2, endPoint) #Arrow arrowBeginPoint = QPointF(self.endPoint.x(), self.endPoint.y() + 4) path.lineTo(arrowBeginPoint) if self.endSide == 'right': path.lineTo(QPointF(self.endPoint.x() - 10, self.endPoint.y())) else: path.lineTo(QPointF(self.endPoint.x() + 10, self.endPoint.y())) path.lineTo(QPointF(self.endPoint.x(), self.endPoint.y() - 4)) path.lineTo(QPointF(self.endPoint.x(), self.endPoint.y() - 2)) #Curve 2 (back) endPoint = QPointF(self.beginPoint.x(), self.beginPoint.y() - yTranslation) curvePoint2 = QPointF(self.curvePoint1.x(), self.curvePoint1.y() - yTranslation) curvePoint1 = QPointF(self.curvePoint2.x(), self.curvePoint2.y() - yTranslation) beginPoint = QPointF(self.endPoint.x(), self.endPoint.y() - yTranslation) point1 = QPointF(curvePoint1.x(), curvePoint1.y()) point2 = QPointF(curvePoint2.x(), curvePoint2.y()) path.cubicTo(point1, point2, endPoint) if self.beginSide == 'right': path.lineTo( QPointF(self.beginPoint.x() - 10, self.beginPoint.y() - 2)) path.lineTo( QPointF(self.beginPoint.x() - 10, self.beginPoint.y() + 2)) else: path.lineTo( QPointF(self.beginPoint.x() + 10, self.beginPoint.y() - 2)) path.lineTo( QPointF(self.beginPoint.x() + 10, self.beginPoint.y() + 2)) path.lineTo(QPointF(self.beginPoint.x(), self.beginPoint.y() + 2)) return path
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
from PyQt5.QtCore import Qt from PyQt5.QtGui import QColor, QKeySequence, QPainterPath from PyQt5.QtWidgets import QApplication from trufont.drawingTools.baseTool import BaseTool import unicodedata _path = QPainterPath() _path.moveTo(5.29, 17.96) _path.lineTo(6.94, 17.96) _path.lineTo(7.36, 21.5) _path.lineTo(7.78, 21.95) _path.lineTo(12.4, 21.95) _path.lineTo(12.4, 6.35) _path.lineTo(11.86, 5.93) _path.lineTo(9.7, 5.78) _path.lineTo(9.7, 4.45) _path.lineTo(18.3, 4.45) _path.lineTo(18.3, 5.78) _path.lineTo(16.14, 5.93) _path.lineTo(15.6, 6.35) _path.lineTo(15.6, 21.95) _path.lineTo(20.22, 21.95) _path.lineTo(20.64, 21.5) _path.lineTo(21.06, 17.96) _path.lineTo(22.71, 17.96) _path.lineTo(22.71, 23.58) _path.lineTo(5.29, 23.58) _path.closeSubpath() def _isUnicodeChar(text):
def getEdgePath(self): yTranslation = 2 #Curve 1 beginPoint = QPointF(self.beginPoint.x(), self.beginPoint.y() + yTranslation) curvePoint1 = QPointF(self.curvePoint1.x(), self.curvePoint1.y() + yTranslation) curvePoint2 = QPointF(self.curvePoint2.x(), self.curvePoint2.y() + yTranslation) endPoint = QPointF(self.endPoint.x(), self.endPoint.y() + yTranslation) path = QPainterPath(beginPoint) point1 = QPointF(curvePoint1.x(), curvePoint1.y()) point2 = QPointF(curvePoint2.x(), curvePoint2.y()) path.cubicTo(point1, point2, endPoint) #Arrow arrowBeginPoint = QPointF(self.endPoint.x(), self.endPoint.y() + 4) path.lineTo(arrowBeginPoint) if self.endSide == 'right': path.lineTo(QPointF(self.endPoint.x() - 10, self.endPoint.y())) else: path.lineTo(QPointF(self.endPoint.x() + 10, self.endPoint.y())) path.lineTo(QPointF(self.endPoint.x(), self.endPoint.y() - 4)) path.lineTo(QPointF(self.endPoint.x(), self.endPoint.y() - 2)) #Curve 2 (back) endPoint = QPointF(self.beginPoint.x(), self.beginPoint.y() - yTranslation) curvePoint2 = QPointF(self.curvePoint1.x(), self.curvePoint1.y() - yTranslation) curvePoint1 = QPointF(self.curvePoint2.x(), self.curvePoint2.y() - yTranslation) beginPoint = QPointF(self.endPoint.x(), self.endPoint.y() - yTranslation) point1 = QPointF(curvePoint1.x(), curvePoint1.y()) point2 = QPointF(curvePoint2.x(), curvePoint2.y()) path.cubicTo(point1, point2, endPoint) if self.beginSide == 'right': path.lineTo( QPointF(self.beginPoint.x() - 10, self.beginPoint.y() - 2)) path.lineTo( QPointF(self.beginPoint.x() - 10, self.beginPoint.y() + 2)) else: path.lineTo( QPointF(self.beginPoint.x() + 10, self.beginPoint.y() - 2)) path.lineTo( QPointF(self.beginPoint.x() + 10, self.beginPoint.y() + 2)) path.lineTo(QPointF(self.beginPoint.x(), self.beginPoint.y() + 2)) return path
class SortingBox(QWidget): circle_count = square_count = triangle_count = 1 def __init__(self): super(SortingBox, self).__init__() self.circlePath = QPainterPath() self.squarePath = QPainterPath() self.trianglePath = QPainterPath() self.shapeItems = [] self.previousPosition = QPoint() self.setMouseTracking(True) self.setBackgroundRole(QPalette.Base) self.itemInMotion = None self.newCircleButton = self.createToolButton("New Circle", QIcon(':/images/circle.png'), self.createNewCircle) self.newSquareButton = self.createToolButton("New Square", QIcon(':/images/square.png'), self.createNewSquare) self.newTriangleButton = self.createToolButton("New Triangle", QIcon(':/images/triangle.png'), self.createNewTriangle) self.circlePath.addEllipse(0, 0, 100, 100) self.squarePath.addRect(0, 0, 100, 100) x = self.trianglePath.currentPosition().x() y = self.trianglePath.currentPosition().y() self.trianglePath.moveTo(x + 120 / 2, y) self.trianglePath.lineTo(0, 100) self.trianglePath.lineTo(120, 100) self.trianglePath.lineTo(x + 120 / 2, y) self.setWindowTitle("Tooltips") self.resize(500, 300) self.createShapeItem(self.circlePath, "Circle", self.initialItemPosition(self.circlePath), self.initialItemColor()) self.createShapeItem(self.squarePath, "Square", self.initialItemPosition(self.squarePath), self.initialItemColor()) self.createShapeItem(self.trianglePath, "Triangle", self.initialItemPosition(self.trianglePath), self.initialItemColor()) def event(self, event): if event.type() == QEvent.ToolTip: helpEvent = event index = self.itemAt(helpEvent.pos()) if index != -1: QToolTip.showText(helpEvent.globalPos(), self.shapeItems[index].toolTip()) else: QToolTip.hideText() event.ignore() return True return super(SortingBox, self).event(event) def resizeEvent(self, event): margin = self.style().pixelMetric(QStyle.PM_DefaultTopLevelMargin) x = self.width() - margin y = self.height() - margin y = self.updateButtonGeometry(self.newCircleButton, x, y) y = self.updateButtonGeometry(self.newSquareButton, x, y) self.updateButtonGeometry(self.newTriangleButton, x, y) def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) for shapeItem in self.shapeItems: painter.translate(shapeItem.position()) painter.setBrush(shapeItem.color()) painter.drawPath(shapeItem.path()) painter.translate(-shapeItem.position()) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: index = self.itemAt(event.pos()) if index != -1: self.itemInMotion = self.shapeItems[index] self.previousPosition = event.pos() value = self.shapeItems[index] del self.shapeItems[index] self.shapeItems.insert(len(self.shapeItems) - 1, value) self.update() def mouseMoveEvent(self, event): if (event.buttons() & Qt.LeftButton) and self.itemInMotion: self.moveItemTo(event.pos()) def mouseReleaseEvent(self, event): if (event.button() == Qt.LeftButton) and self.itemInMotion: self.moveItemTo(event.pos()) self.itemInMotion = None def createNewCircle(self): SortingBox.circle_count += 1 self.createShapeItem(self.circlePath, "Circle <%d>" % SortingBox.circle_count, self.randomItemPosition(), self.randomItemColor()) def createNewSquare(self): SortingBox.square_count += 1 self.createShapeItem(self.squarePath, "Square <%d>" % SortingBox.square_count, self.randomItemPosition(), self.randomItemColor()) def createNewTriangle(self): SortingBox.triangle_count += 1 self.createShapeItem(self.trianglePath, "Triangle <%d>" % SortingBox.triangle_count, self.randomItemPosition(), self.randomItemColor()) def itemAt(self, pos): for i in range(len(self.shapeItems) - 1, -1, -1): item = self.shapeItems[i] if item.path().contains(QPointF(pos - item.position())): return i return -1 def moveItemTo(self, pos): offset = pos - self.previousPosition self.itemInMotion.setPosition(self.itemInMotion.position() + offset) self.previousPosition = QPoint(pos) self.update() def updateButtonGeometry(self, button, x, y): size = button.sizeHint() button.setGeometry(x - size.width(), y - size.height(), size.width(), size.height()) return y - size.height() - self.style().pixelMetric(QStyle.PM_DefaultLayoutSpacing) def createShapeItem(self, path, toolTip, pos, color): shapeItem = ShapeItem() shapeItem.setPath(path) shapeItem.setToolTip(toolTip) shapeItem.setPosition(pos) shapeItem.setColor(color) self.shapeItems.append(shapeItem) self.update() def createToolButton(self, toolTip, icon, member): button = QToolButton(self) button.setToolTip(toolTip) button.setIcon(icon) button.setIconSize(QSize(32, 32)) button.clicked.connect(member) return button def initialItemPosition(self, path): y = (self.height() - path.controlPointRect().height()) / 2 if len(self.shapeItems) == 0: x = ((3 * self.width()) / 2 - path.controlPointRect().width()) / 2 else: x = (self.width() / len(self.shapeItems) - path.controlPointRect().width()) / 2 return QPoint(x, y) def randomItemPosition(self): x = random.randint(0, self.width() - 120) y = random.randint(0, self.height() - 120) return QPoint(x, y) def initialItemColor(self): hue = ((len(self.shapeItems) + 1) * 85) % 256 return QColor.fromHsv(hue, 255, 190) def randomItemColor(self): return QColor.fromHsv(random.randint(0, 256), 255, 190)
class PolygonWidget(QWidget): """PolygonWidget(QWidget) Provides a custom widget to display a polygon with properties and slots that can be used to customize its appearance. """ def __init__(self, parent=None): super(PolygonWidget, self).__init__(parent) self._sides = 5 self._innerRadius = 20 self._outerRadius = 50 self._angle = 0 self.createPath() self._innerColor = QColor(255, 255, 128) self._outerColor = QColor(255, 0, 128) self.createGradient() def paintEvent(self, event): painter = QPainter() painter.begin(self) painter.setRenderHint(QPainter.Antialiasing) painter.setBrush(QBrush(QColor(192, 192, 255))) painter.drawRect(event.rect()) painter.translate(self.width() / 2.0, self.height() / 2.0) painter.rotate(self._angle) painter.setBrush(QBrush(self.gradient)) painter.drawPath(self.path) painter.end() def sizeHint(self): return QSize(2 * self._outerRadius + 20, 2 * self._outerRadius + 20) def createPath(self): self.path = QPainterPath() angle = 2 * math.pi / self._sides self.path.moveTo(self._outerRadius, 0) for step in range(1, self._sides + 1): self.path.lineTo( self._innerRadius * math.cos((step - 0.5) * angle), self._innerRadius * math.sin((step - 0.5) * angle)) self.path.lineTo(self._outerRadius * math.cos(step * angle), self._outerRadius * math.sin(step * angle)) self.path.closeSubpath() def createGradient(self): center = QPointF(0, 0) self.gradient = QRadialGradient(center, self._outerRadius, center) self.gradient.setColorAt(0.5, QColor(self._innerColor)) self.gradient.setColorAt(1.0, QColor(self._outerColor)) # The angle property is implemented using the getAngle() and setAngle() # methods. def getAngle(self): return self._angle # The setAngle() setter method is also a slot. @pyqtSlot(int) def setAngle(self, angle): self._angle = min(max(0, angle), 360) self.update() angle = pyqtProperty(int, getAngle, setAngle) # The innerRadius property is implemented using the getInnerRadius() and # setInnerRadius() methods. def getInnerRadius(self): return self._innerRadius # The setInnerRadius() setter method is also a slot. @pyqtSlot(int) def setInnerRadius(self, radius): self._innerRadius = radius self.createPath() self.createGradient() self.update() innerRadius = pyqtProperty(int, getInnerRadius, setInnerRadius) # The outerRadius property is implemented using the getOuterRadius() and # setOuterRadius() methods. def getOuterRadius(self): return self._outerRadius # The setOuterRadius() setter method is also a slot. @pyqtSlot(int) def setOuterRadius(self, radius): self._outerRadius = radius self.createPath() self.createGradient() self.update() outerRadius = pyqtProperty(int, getOuterRadius, setOuterRadius) # The numberOfSides property is implemented using the getNumberOfSides() # and setNumberOfSides() methods. def getNumberOfSides(self): return self._sides # The setNumberOfSides() setter method is also a slot. @pyqtSlot(int) def setNumberOfSides(self, sides): self._sides = max(3, sides) self.createPath() self.update() numberOfSides = pyqtProperty(int, getNumberOfSides, setNumberOfSides) # The innerColor property is implemented using the getInnerColor() and # setInnerColor() methods. def getInnerColor(self): return self._innerColor def setInnerColor(self, color): self._innerColor = color self.createGradient() self.update() innerColor = pyqtProperty(QColor, getInnerColor, setInnerColor) # The outerColor property is implemented using the getOuterColor() and # setOuterColor() methods. def getOuterColor(self): return self._outerColor def setOuterColor(self, color): self._outerColor = color self.createGradient() self.update() outerColor = pyqtProperty(QColor, getOuterColor, setOuterColor)
from trufont.controls.glyphDialogs import AddComponentDialog, EditDialog from trufont.drawingTools.baseTool import BaseTool from trufont.tools import bezierMath, platformSpecific from trufont.tools.uiMethods import ( maybeProjectUISmoothPointOffcurve, moveUIGlyphElements, unselectUIGlyphElements, ) arrowKeys = (Qt.Key_Left, Qt.Key_Up, Qt.Key_Right, Qt.Key_Down) navKeys = (Qt.Key_Less, Qt.Key_Greater) _path = QPainterPath() _path.moveTo(15.33, 4.18) _path.lineTo(12.36, 11.2) _path.lineTo(8.37, 7.46) _path.lineTo(8.37, 23.87) _path.lineTo(20.85, 12.05) _path.lineTo(15.33, 12.05) _path.lineTo(18.17, 5.36) _path.closeSubpath() def _pointWithinThreshold(x, y, curve, eps): """ See whether *(x, y)* is within *eps* of *curve*. """ path = QPainterPath() path.addEllipse(x - eps, y - eps, 2 * eps, 2 * eps) curvePath = QPainterPath()
class StMoveGUI(QGraphicsLineItem, StMove): def __init__(self, shape): QGraphicsLineItem.__init__(self) StMove.__init__(self, shape) self.allwaysshow = False self.path = QPainterPath() self.setFlag(QGraphicsItem.ItemIsSelectable, False) self.pen = QPen(QColor(50, 100, 255), 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin) self.pen.setCosmetic(True) self.make_papath() def contains_point(self, point): """ StMove cannot be selected. Return maximal distance """ return float(0x7fffffff) def make_papath(self): """ To be called if a Shape shall be printed to the canvas @param canvas: The canvas to be printed in @param pospro: The color of the shape """ self.path = QPainterPath() if len(self.geos): start = self.geos.abs_el(0).get_start_end_points(True) self.path.moveTo(start.x, -start.y) drawHorLine = lambda caller, start, end: self.path.lineTo( end.x, -end.y) drawVerLine = lambda caller, start: None # Not used in 2D mode self.make_path(drawHorLine, drawVerLine) def setSelected(self, flag=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 will be triggered with each paint event. Possible to give options @param painter: Reference to std. painter @param option: Possible options here @param widget: The widget which is painted on. """ painter.setPen(self.pen) painter.drawPath(self.path) def boundingRect(self): """ Required method for painting. Inherited by Painterpath @return: Gives the Bounding Box """ return self.path.boundingRect()