def paintEvent(self, event): # this puts the line numbers in the margin painter = QPainter(self) painter.fillRect(event.rect(), self.background) block = self.parent.firstVisibleBlock() font = self.parent.font() while block.isValid(): block_num = block.blockNumber() block_top = self.parent.blockBoundingGeometry(block).translated( self.parent.contentOffset()).top() # if the block is not visible stop wasting time if not block.isVisible() or block_top >= event.rect().bottom(): break if block_num == self.parent.textCursor().blockNumber(): font.setBold(True) painter.setFont(font) painter.setPen(self.highlight_color) background = self.highlight_background else: font.setBold(False) painter.setFont(font) painter.setPen(self.color) background = self.background text_rec = QRect(0, block_top, self.width(), self.parent.fontMetrics().height()) painter.fillRect(text_rec, background) painter.drawText(text_rec, Qt.AlignRight, str(block_num + 1)) block = block.next() painter.end() QWidget.paintEvent(self, event)
def paintEvent(self, event): self.makeCurrent() gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) gl.glUseProgram(self.shaders_program) gl.glUniform1i(self.colormap_location, 0) gl.glActiveTexture(gl.GL_TEXTURE0 + 0) gl.glBindTexture(gl.GL_TEXTURE_1D, self.colormap_id) gl.glBegin(gl.GL_QUAD_STRIP) bar_start = -1 + self.text_height / self.height() * 2 bar_height = (1 - 2 * self.text_height / self.height()) * 2 steps = 40 for i in range(steps + 1): y = i * (1 / steps) # gl.glColor(y, 0, 0) gl.glVertex(-0.5, (bar_height * y + bar_start), y) gl.glVertex(0.5, (bar_height * y + bar_start), y) gl.glEnd() p = QPainter(self) p.drawText((self.width() - self.vmax_width) / 2, self.text_ascent, self.vmax_str) p.drawText((self.width() - self.vmin_width) / 2, self.height() - self.text_height + self.text_ascent, self.vmin_str) p.end()
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): """Renders the delegate using the given painter and style option for the item specified by index. :param painter: A QPainter object to draw :param option: Options to describe what should be drawn :param index: _description_ """ if not index.isValid(): return # Initialize the style options. This is not very Pythonic as it uses C++ # references under the hood so opt is affected by the second call opt = QStyleOptionViewItem(option) self.initStyleOption(opt, index) # Standard setup, paint, restore operation painter.save() try: painter.setClipRect(opt.rect) foreground_colour, background_colour = index.data(Qt.ForegroundRole), index.data(Qt.BackgroundRole) if foreground_colour is not None: painter.setPen(foreground_colour) if background_colour is not None: painter.fillRect(option.rect, background_colour) padding = self._padding opt.rect = option.rect.adjusted(padding, padding, -padding, -padding) painter.drawText(opt.rect, int(Qt.AlignLeft | Qt.AlignVCenter), opt.fontMetrics.elidedText(opt.text, Qt.ElideRight, opt.rect.width())) finally: painter.restore()
def paintEvent(self, event): super().paintEvent(event) painter = QPainter(self) font_metrics = painter.fontMetrics() text_layout = QTextLayout(self._text, painter.font()) text_layout.beginLayout() y = 0 while True: line = text_layout.createLine() if not line.isValid(): break line.setLineWidth(self.width()) nextLineY = y + font_metrics.lineSpacing() if self.height() >= nextLineY + font_metrics.lineSpacing(): line.draw(painter, QPoint(0, y)) y = nextLineY else: lastLine = self._text[line.textStart():] elidedLastLine = font_metrics.elidedText( lastLine, Qt.ElideRight, self.width()) painter.drawText(QPoint(0, y + font_metrics.ascent()), elidedLastLine) line = text_layout.createLine() break text_layout.endLayout()
def paintEvent(self, event: QtGui.QPaintEvent): border_distance = 5 rect = self.rect() mid = rect.y() + rect.height() / 2 line_begin = QPointF(rect.height() + 10 + self.text_size.width(), mid) line_end = QPointF(rect.width() + rect.x() - 5, mid) triangle = QPolygonF() side_length = rect.height() - 2 * border_distance triangle_height = side_length * sqrt(3) / 2 start_point = QPointF(rect.x() + border_distance, rect.y() + border_distance) if self.isChecked(): triangle.append(start_point) triangle.append(start_point + QPointF(0, side_length)) triangle.append(start_point + QPointF(triangle_height, side_length / 2)) else: triangle.append(start_point) triangle.append(start_point + QPointF(side_length, 0)) triangle.append(start_point + QPointF(side_length / 2, triangle_height)) painter = QPainter(self) painter.setBrush(Qt.black) top = rect.height() - (self.text_size.height() / 2) painter.drawText(rect.height() + 5, top, self.info_text) painter.drawPolygon(triangle, Qt.WindingFill) painter.drawLine(QLineF(line_begin, line_end))
def draw_model_name(painter: QPainter, geom: NodeGeometry, state: NodeState, model: NodeDataModel, node_style: NodeStyle): """ Draw model name Parameters ---------- painter : QPainter geom : NodeGeometry state : NodeState model : NodeDataModel """ if not model.caption_visible: return name = model.caption f = painter.font() f.setBold(True) metrics = QFontMetrics(f) rect = metrics.boundingRect(name) position = QPointF((geom.width - rect.width()) / 2.0, (geom.spacing + geom.entry_height) / 3.0) painter.setFont(f) painter.setPen(node_style.font_color) painter.drawText(position, name) f.setBold(False) painter.setFont(f)
def draw_entry_labels(painter: QPainter, geom: NodeGeometry, state: NodeState, model: NodeDataModel, node_style: NodeStyle): """ Draw entry labels Parameters ---------- painter : QPainter geom : NodeGeometry state : NodeState model : NodeDataModel node_style : NodeStyle """ metrics = painter.fontMetrics() for port in state.ports: scene_pos = port.scene_position if not port.connections: painter.setPen(node_style.font_color_faded) else: painter.setPen(node_style.font_color) display_text = port.display_text rect = metrics.boundingRect(display_text) scene_pos.setY(scene_pos.y() + rect.height() / 4.0) if port.port_type == PortType.input: scene_pos.setX(5.0) elif port.port_type == PortType.output: scene_pos.setX(geom.width - 5.0 - rect.width()) painter.drawText(scene_pos, display_text)
def findAscent(self, font): dummy = "E" white = QColor(Qt.white) fm = self.fontmetrics(font) pm = QPixmap(fm.width(dummy), fm.height()) pm.fill(white) p = QPainter(pm) p.setFont(font) p.drawText(0, 0, pm.width(), pm.height(), 0, dummy) p.end() img = pm.toImage() w = pm.width() linebytes = w * 4 for row in range(img.height()): if PYSIDE2: line = bytes(img.scanLine(row)) else: line = img.scanLine(row).asstring(linebytes) for col in range(w): color = struct.unpack("I", line[col * 4:(col + 1) * 4])[0] if color != white.rgb(): return fm.ascent() - row + 1 return fm.ascent()
def paintEvent(self, event): tic = time.perf_counter() painter = QPainter(self) rect = event.rect() painter.drawImage(rect, self.image, rect) painter.setPen(QColor.fromRgb(255, 0, 0)) #painter.drawPoints(self.clicks) if self.drawBoxes: self.drawBoxes(painter) # Draw the center mark painter.setPen(QColor.fromRgb(255, 0, 0)) painter.drawLine(self.center.x() - 20, self.center.y(), self.center.x() + 20, self.center.y()) painter.drawLine(self.center.x(), self.center.y() - 20, self.center.x(), self.center.y() + 20) # Draw the scale bar if self.scaleBar: painter.setPen(QColor.fromRgb(40, 40, 40)) painter.setFont(QFont("Arial", 30)) scaleRect = QRect(10, 420, 200, 30) painter.drawText(scaleRect, Qt.AlignCenter, "10 nm") pen = painter.pen() pen.setWidth(5) painter.setPen(pen) painter.drawLine(10, 460, 210, 460) toc = time.perf_counter()
def draw_validation_rect(painter: QPainter, geom: NodeGeometry, model: NodeDataModel, graphics_object: NodeGraphicsObject, node_style: NodeStyle): """ Draw validation rect Parameters ---------- painter : QPainter geom : NodeGeometry model : NodeDataModel graphics_object : NodeGraphicsObject node_style : NodeStyle """ model_validation_state = model.validation_state() if model_validation_state == NodeValidationState.valid: return color = (node_style.selected_boundary_color if graphics_object.isSelected() else node_style.normal_boundary_color) if geom.hovered: p = QPen(color, node_style.hovered_pen_width) else: p = QPen(color, node_style.pen_width) painter.setPen(p) # Drawing the validation message background if model_validation_state == NodeValidationState.error: painter.setBrush(node_style.error_color) else: painter.setBrush(node_style.warning_color) radius = 3.0 diam = node_style.connection_point_diameter boundary = QRectF( -diam, -diam + geom.height - geom.validation_height, 2.0 * diam + geom.width, 2.0 * diam + geom.validation_height, ) painter.drawRoundedRect(boundary, radius, radius) painter.setBrush(Qt.gray) # Drawing the validation message itself error_msg = model.validation_message() f = painter.font() metrics = QFontMetrics(f) rect = metrics.boundingRect(error_msg) position = QPointF( (geom.width - rect.width()) / 2.0, geom.height - (geom.validation_height - diam) / 2.0 ) painter.setFont(f) painter.setPen(node_style.font_color) painter.drawText(position, error_msg)
def paintEvent(self, event): """Override Qt method. Painting line number area """ painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) # This is needed to make that the font size of line numbers # be the same as the text one when zooming # See Issue 2296 and 4811 font = self.editor.font() font_height = self.editor.fontMetrics().height() active_block = self.editor.textCursor().block() active_line_number = active_block.blockNumber() + 1 def draw_pixmap(ytop, pixmap): if not QT55_VERSION: pixmap_height = pixmap.height() else: # scale pixmap height to device independent pixels pixmap_height = pixmap.height() / pixmap.devicePixelRatio() painter.drawPixmap(0, ytop + (font_height-pixmap_height) / 2, pixmap) for top, line_number, block in self.editor.visible_blocks: if self._margin: if line_number == active_line_number: font.setWeight(font.Bold) painter.setFont(font) painter.setPen(self.editor.normal_color) else: font.setWeight(font.Normal) painter.setFont(font) painter.setPen(self.linenumbers_color) painter.drawText(0, top, self.width(), font_height, Qt.AlignRight | Qt.AlignBottom, to_text_string(line_number)) data = block.userData() if self._markers_margin and data: if data.code_analysis: for source, code, severity, message in data.code_analysis: error = severity == DiagnosticSeverity.ERROR if error: break if error: draw_pixmap(top, self.error_pixmap) else: draw_pixmap(top, self.warning_pixmap) if data.todo: draw_pixmap(top, self.todo_pixmap) if data.breakpoint: if data.breakpoint_condition is None: draw_pixmap(top, self.bp_pixmap) else: draw_pixmap(top, self.bpc_pixmap)
def paintEvent(self, evt): painter = QPainter(self) if self.color is not None: painter.setPen(QPen(self.color)) painter.rotate(self.angle) transform = painter.transform().inverted()[0] rct = transform.mapRect(self.rect()) painter.drawText(rct, self.alignment(), self.text())
def paintEvent(self, event): super(DetailedProgress, self).paintEvent(event) if not self._current_progress: return painter = QPainter(self) width = self.width() height = self.height() aspect_ratio = float(width) / height nr_realizations = max([iens for iens, _, _ in self._current_progress]) + 1 fm_size = max( [len(progress) for _, progress, _ in self._current_progress]) self.grid_height = math.ceil(math.sqrt(nr_realizations / aspect_ratio)) self.grid_width = math.ceil(self.grid_height * aspect_ratio) sub_grid_size = math.ceil(math.sqrt(fm_size)) cell_height = height / self.grid_height cell_width = width / self.grid_width foreground_image = QImage(self.grid_width * sub_grid_size, self.grid_height * sub_grid_size, QImage.Format_ARGB32) foreground_image.fill(QColor(0, 0, 0, 0)) for index, (iens, progress, _) in enumerate(self._current_progress): y = int(iens / self.grid_width) x = int(iens - (y * self.grid_width)) self.draw_window(x * sub_grid_size, y * sub_grid_size, progress, foreground_image) painter.drawImage(self.contentsRect(), foreground_image) for index, (iens, progress, state) in enumerate(self._current_progress): y = int(iens / self.grid_width) x = int(iens - (y * self.grid_width)) painter.setPen(QColor(80, 80, 80)) painter.drawText(int(x * cell_width), int(y * cell_height), int(cell_width), int(cell_height), int(Qt.AlignHCenter | Qt.AlignVCenter), str(iens)) if iens == self.selected_realization: pen = QPen(QColor(240, 240, 240)) elif (self.has_realization_failed(progress)): pen = QPen(QColor(*self.state_colors['Failure'])) elif (state == JobStatusType.JOB_QUEUE_RUNNING): pen = QPen(QColor(*self.state_colors['Running'])) else: pen = QPen(QColor(80, 80, 80)) thickness = 4 pen.setWidth(thickness) painter.setPen(pen) painter.drawRect( int(x * cell_width) + (thickness // 2), int(y * cell_height) + (thickness // 2), int(cell_width) - (thickness - 1), int(cell_height) - (thickness - 1))
def add_char_pixmap(pixmap, char, size=14, weight=QFont.Bold): if len(char) > 1: raise ValueError("Only one char is allowed") painter = QPainter(pixmap) painter.setFont(QFont("Times", size, weight)) painter.setPen(QColor(255, 0, 0)) w, h = pixmap.width(), pixmap.height() p = QPoint(w - size, h - 2) painter.drawText(p, char)
def paintEvent(self, event): """Override Qt method. Painting line number area """ painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) # This is needed to make that the font size of line numbers # be the same as the text one when zooming # See Issue 2296 if sys.platform == 'darwin': font = self.editor.font() else: font = painter.font() font_height = self.editor.fontMetrics().height() active_block = self.editor.textCursor().block() active_line_number = active_block.blockNumber() + 1 def draw_pixmap(ytop, pixmap): painter.drawPixmap(0, ytop + (font_height-pixmap.height()) / 2, pixmap) for top, line_number, block in self.editor.visible_blocks: if self._margin: if line_number == active_line_number: font.setWeight(font.Bold) painter.setFont(font) painter.setPen(self.editor.normal_color) else: font.setWeight(font.Normal) painter.setFont(font) painter.setPen(self.linenumbers_color) painter.drawText(0, top, self.width(), font_height, Qt.AlignRight | Qt.AlignBottom, to_text_string(line_number)) data = block.userData() if self._markers_margin and data: if data.code_analysis: for _message, error in data.code_analysis: if error: break if error: draw_pixmap(top, self.error_pixmap) else: draw_pixmap(top, self.warning_pixmap) if data.todo: draw_pixmap(top, self.todo_pixmap) if data.breakpoint: if data.breakpoint_condition is None: draw_pixmap(top, self.bp_pixmap) else: draw_pixmap(top, self.bpc_pixmap)
def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex) -> None: viewOption = QStyleOptionViewItem(option) self.initStyleOption(viewOption, index) QStyledItemDelegate.paint(self, painter, viewOption, index) item = index.model().data(index, Qt.UserRole) if isinstance(item, QVariant): return value = item['value'] type = item['type'] if type == 'checkbox': # 数据转换 value = True if value == 1 else 0 # 绘制单选框 checkBoxStyle = QStyleOptionButton() checkBoxStyle.state = QStyle.State_On if value else QStyle.State_Off checkBoxStyle.state |= QStyle.State_Enabled # 计算位置 size = item['size'] rect = calculate_middle_rect(option.rect, size, size) checkBoxStyle.rect = rect checkBox = QCheckBox() QApplication.style().drawPrimitive(QStyle.PE_IndicatorCheckBox, checkBoxStyle, painter, checkBox) if type == 'tag': painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHints(QPainter.SmoothPixmapTransform) path = QPainterPath() # 绘制文本 self.font = ResourceLoader().qt_font_text_tag text_color = item['text_color'] border_color = item['border_color'] text = value padding_v = 2 padding_h = 4 border_radius = 2 border_width = 1 painter.setFont(item['font']) painter.setPen(text_color) fm = QFontMetrics(painter.font()) w = fm.width(text) h = fm.height() # 计算位置 rect = calculate_middle_rect(option.rect, w + padding_h * 2, h + padding_v * 2) rectf = QRectF(rect.x(), rect.y(), rect.width(), rect.height()) painter.drawText( QRect(rectf.x() + padding_h, rectf.y() + padding_v, w, h), Qt.TextWordWrap, text) # 绘制边框 path.addRoundedRect(rectf, border_radius, border_radius) painter.strokePath(path, QPen(border_color, border_width))
def paintEvent(self, event: QPaintEvent): rect = event.rect() painter = QPainter(self) painter.save() if self.isChecked(): lock = lock_close else: lock = lock_open painter.setFont(QFont("Symbola")) painter.drawText(rect.bottomLeft() + QPoint(0, -2), lock) painter.restore()
def paintEvent(self, event: QtGui.QPaintEvent): painter = QPainter(self) color = painter.pen().color() painter.save() rect = self.rect() top = int(rect.height() - (self.text_size.height() / 2)) painter.drawText(rect.height() + 5, top, self.info_text) if self.isChecked(): icon = qta.icon("fa5s.caret-right", color=color) else: icon = qta.icon("fa5s.caret-down", color=color) icon.paint(painter, QRect(0, -self.height() / 4, self.height(), self.height())) painter.restore()
def drawText(self, p: QPainter, innerRect: QRectF, innerRadius: float, value: float): if not self.m_format: return f = QFont(self.font()) f.setPixelSize(10) fm = QFontMetricsF(f) maxWidth = fm.width(self.valueToText(self.m_max)) delta = innerRadius / maxWidth fontSize = f.pixelSize() * delta * 0.75 f.setPixelSize(int(fontSize)) p.setFont(f) textRect = QRectF(innerRect) p.setPen(self.palette().text().color()) p.drawText(textRect, Qt.AlignCenter, self.valueToText(value))
def linenumberarea_paint_event(self, event): """ Paint the line number area. """ if self._linenumber_enabled: painter = QPainter(self.linenumberarea) painter.fillRect( event.rect(), self._highlighter.get_sideareas_color(), ) block = self.firstVisibleBlock() block_number = block.blockNumber() top = round( self.blockBoundingGeometry(block).translated( self.contentOffset()).top()) bottom = top + round(self.blockBoundingRect(block).height()) font = self.font() active_block = self.textCursor().block() active_line_number = active_block.blockNumber() + 1 while block.isValid() and top <= event.rect().bottom(): if block.isVisible() and bottom >= event.rect().top(): number = block_number + 1 if number == active_line_number: font.setWeight(font.Bold) painter.setFont(font) painter.setPen( self._highlighter.get_foreground_color()) else: font.setWeight(font.Normal) painter.setFont(font) painter.setPen(QColor(Qt.darkGray)) right_padding = self.linenumberarea._right_padding painter.drawText( 0, top, self.linenumberarea.width() - right_padding, self.fontMetrics().height(), Qt.AlignRight, str(number), ) block = block.next() top = bottom bottom = top + round(self.blockBoundingRect(block).height()) block_number += 1
def paintEvent(self, event): """ Override from QWidget, needed to get stylesheets working :param event: paint event """ # _log.debug("Tab: paint event.") opt = QStyleOption() opt.initFrom(self) painter = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self) if CONFIG.debug_layout: painter.setPen(QPen(Qt.red, 1.0)) painter.drawRect(self.rect().adjusted(0, 0, -1, -1)) painter.setPen(QPen(Qt.black, 1.0)) painter.drawText(QPointF(5, 12), str(self))
def paintEvent(self, event): bw = float(self._border_width) br = self._border_radius val = self.value() if self.orientation() == Qt.Horizontal: w = QStyle.sliderPositionFromValue(self.minimum(), self.maximum(), val, self.width()) h = self.height() rect = QRectF(bw / 2, bw / 2, w - bw, h - bw) else: w = self.width() h = self.height() - QStyle.sliderPositionFromValue( self.minimum(), self.maximum(), val, self.height()) rect = QRectF(bw / 2, h - bw / 2, w - bw, self.height() - bw) p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) # draw the load meter value bar p.setPen(Qt.transparent) p.setBrush(self.gradient) p.drawRoundedRect(rect, br, br) # draw the border p.setBrush(Qt.transparent) border_pen = QPen() border_pen.setWidth(bw) border_pen.setColor(self._border_color) p.setPen(border_pen) rect = QRectF(bw / 2, bw / 2, self.width() - bw, self.height() - bw) p.drawRoundedRect(rect, br, br) # draw the load percentage text p.setPen(self._text_color) if self.orientation() == Qt.Vertical: p.rotate(-90) p.drawText(-self.height(), 0, self.height(), self.width(), Qt.AlignCenter, self.text()) else: p.drawText(0, 0, self.width(), self.height(), Qt.AlignCenter, self.text())
def render(self): rect = QRect(QPoint(), self.geometry().size()) self.m_backingStore.resize(rect.size()) self.m_backingStore.beginPaint(QRegion(rect)) device = self.m_backingStore.paintDevice() p = QPainter(device) p.drawImage(0, 0, self.m_image) font = QFont() font.setPixelSize(32) p.setFont(font) p.drawText(rect, 0, self.m_text) self.m_backingStore.endPaint() self.m_backingStore.flush(QRegion(rect))
def get_font_array(sz, chars=DEFAULT_CHARS): from qtpy.QtGui import QFont, QPainter, QColor font = QFont() font.setFixedPitch(True) font.setPixelSize(int(sz)) font.setStyleStrategy(QFont.NoAntialias) dummy = QImage(10, 10, QImage.Format_ARGB32) pnt = QPainter(dummy) pnt.setFont(font) metric = pnt.fontMetrics() rct = metric.boundingRect(chars) pnt.end() h = rct.height() w = rct.width() img = QImage(w, h, QImage.Format_ARGB32) paint = QPainter() paint.begin(img) paint.setFont(font) paint.setBrush(QColor(255, 255, 255)) paint.setPen(QColor(255, 255, 255)) paint.drawRect(0, 0, w + 1, h + 1) paint.setPen(QColor(0, 0, 0)) paint.setBrush(QColor(0, 0, 0)) paint.drawText(0, paint.fontMetrics().ascent(), chars) paint.end() try: try: # PyQt4 (at least until Qt 4.8) data = img.bits().asstring(img.numBytes()) except AttributeError: if PYSIDE2: # PySide2 data = bytes(img.bits()) else: # PyQt5 data = img.bits().asstring(img.byteCount()) except SystemError: # PyQt4 (4.11.3) and PyQt5 (5.3.2) on Python 3 return npy = np.frombuffer(data, np.uint8) npy.shape = img.height(), int(img.bytesPerLine() / 4), 4 return npy[:, :, 0]
def paint(self, painter: QPainter, style: QStyleOptionViewItem, model: QModelIndex): if model.data() not in image_dict: image_dict[model.data()] = create_colormap_image( model.data(), self.color_dict) rect = QRect(style.rect.x(), style.rect.y() + 2, style.rect.width() - 150, style.rect.height() - 4) painter.drawImage(rect, image_dict[model.data()]) rect2 = QRect(style.rect.x() + style.rect.width() - 140, style.rect.y() + 2, 140, style.rect.height() - 4) painter.drawText(rect2, Qt.AlignLeft, model.data()) if int(style.state & QStyle.State_HasFocus): painter.save() pen = QPen() pen.setWidth(5) painter.setPen(pen) painter.drawRect(rect) painter.restore()
def paintEvent(self, event): if self.elideMode == 0: # if not set then behave as a normal label QLabel.paintEvent(self, event) else: QFrame.paintEvent(self, event) painter = QPainter(self) painter.setFont(self.font()) # gets the spacing between lines lineSpacing = self.fontMetrics().lineSpacing() y = 0 textLayout = QTextLayout(self.text(), self.font()) textLayout.beginLayout() # loops til the end of line while True: # create a line line = textLayout.createLine() if line.isValid() != True: break self.lines += 1 # set limit of line width line.setLineWidth(self.width()) # calculate position of next line nextLineY = y + lineSpacing if self.height() >= nextLineY + lineSpacing: line.draw(painter, QPoint(0, y)) y = nextLineY else: # regenerate each line so that they do not overflow the width of widget lastLine = self.text()[line.textStart():len(self.text())] elidedLastLine = self.fontMetrics().elidedText( lastLine, Qt.ElideRight, self.width()) painter.drawText( QPoint(0, y + self.fontMetrics().ascent()), elidedLastLine) line = textLayout.createLine() break textLayout.endLayout()
def paintEvent(self, event: QtGui.QPaintEvent): bar_width = 30 if self.image is None: return rect = self.rect() number_of_marks = self.number_of_marks(rect.height()) image_rect = QRect(rect.topLeft(), QSize(bar_width, rect.size().height())) painter = QPainter(self) old_font = painter.font() new_font = painter.font() new_font.setPointSizeF(new_font.pointSizeF() / 1.1) painter.setFont(new_font) painter.drawImage(image_rect, self.image) if self.range[1] == self.range[0]: painter.drawText(bar_width + 5, 20, f"{self.range[1]}") painter.drawText(bar_width + 5, rect.size().height(), f"{self.range[1]}") painter.setFont(old_font) return start_prop = 1 - (self.round_range[0] - self.range[0]) / (self.range[1] - self.range[0]) end_prop = 1 - (self.round_range[1] - self.range[0]) / (self.range[1] - self.range[0]) for pos, val in zip( np.linspace(10 + end_prop * rect.size().height(), start_prop * rect.size().height(), number_of_marks), np.linspace(self.round_range[1], self.round_range[0], number_of_marks, dtype=np.uint32), ): painter.drawText(bar_width + 5, int(pos), f"{val}") painter.setFont(old_font)
def graph2icon(g: Graph, width: int, node_mode: bool, show_label: bool, monochrome: bool, *, except_node: Optional[int] = None, engine: str = "", pos: Optional[_Pos] = None) -> QIcon: """Draw a generalized chain graph.""" if engine: pos = engine_picker(g, engine, node_mode) if pos is None: raise ValueError("no engine selected") if not pos: pixmap = QPixmap(width, width) pixmap.fill(Qt.transparent) return QIcon(pixmap) width_bound = -float('inf') for x, y in pos.values(): if abs(x) > width_bound: width_bound = x if abs(y) > width_bound: width_bound = y width_bound *= 2.5 image = QImage(QSize(int(width_bound), int(width_bound)), QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) painter = QPainter(image) painter.translate(image.width() / 2, image.height() / 2) pen = QPen() r = int(width_bound / 50) pen.setWidth(r) painter.setPen(pen) _font.setPixelSize(r * 6) painter.setFont(_font) # Draw edges if node_mode: for l1, l2 in g.edges: if except_node in {l1, l2}: pen.setColor(Qt.gray) else: pen.setColor(Qt.black) painter.setPen(pen) painter.drawLine(QPointF(pos[l1][0], -pos[l1][1]), QPointF(pos[l2][0], -pos[l2][1])) else: color = color_qt('dark-gray') if monochrome else LINK_COLOR color.setAlpha(150) painter.setBrush(QBrush(color)) for link in g.vertices: if link == except_node: pen.setColor(Qt.gray) else: pen.setColor(Qt.black) painter.setPen(pen) painter.drawPolygon(*convex_hull([(pos[n][0], -pos[n][1]) for n, edge in edges_view(g) if link in edge], as_qpoint=True)) # Draw vertices for k, (x, y) in pos.items(): if node_mode: color = color_num(len(list(g.neighbors(k))) - 1) if k == except_node: color.setAlpha(150) else: if monochrome: color = Qt.black elif except_node in dict(edges_view(g))[k]: color = color_qt('green') else: color = color_qt('blue') pen.setColor(color) painter.setPen(pen) painter.setBrush(QBrush(color)) point = QPointF(x, -y) painter.drawEllipse(point, r, r) if show_label: pen.setColor(Qt.darkMagenta) painter.setPen(pen) painter.drawText(point, str(k)) painter.end() return QIcon(QPixmap.fromImage(image).scaledToWidth(width))
class BaseCanvas(QWidget, metaclass=QABCMeta): """The subclass can draw a blank canvas more easier.""" @abstractmethod def __init__(self, parent: QWidget): """Set the parameters for drawing.""" super(BaseCanvas, self).__init__(parent) self.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.setFocusPolicy(Qt.StrongFocus) self.setMouseTracking(True) self.painter = QPainter() # Origin coordinate self.ox = self.width() / 2 self.oy = self.height() / 2 # Canvas zoom rate self.zoom = 1. # Joint size self.joint_size = 5 # Canvas line width self.link_width = 3 self.path_width = 3 # Font size self.font_size = 15 # Show point mark or dimension self.show_ticks = _TickMark.SHOW self.show_point_mark = True self.show_dimension = True # Path track self.path = _PathOption() # Path solving self.ranges: Dict[str, QRectF] = {} self.target_path: Dict[int, Sequence[_Coord]] = {} self.show_target_path = False # Background self.background = QImage() self.background_opacity = 1. self.background_scale = 1. self.background_offset = QPointF(0, 0) # Monochrome mode self.monochrome = False # Grab mode self.__grab_mode = False def switch_grab(self) -> None: """Start grab mode.""" self.__grab_mode = not self.__grab_mode @staticmethod def zoom_factor(width: int, height: int, x_right: float, x_left: float, y_top: float, y_bottom: float) -> float: """Calculate the zoom factor.""" x_diff = x_left - x_right y_diff = y_top - y_bottom x_diff = x_diff if x_diff else 1. y_diff = y_diff if y_diff else 1. if width / x_diff < height / y_diff: return width / x_diff else: return height / y_diff @abstractmethod def paintEvent(self, event: QPaintEvent) -> None: """Using a QPainter under 'self', so just change QPen or QBrush before painting. """ if not self.__grab_mode: self.painter.begin(self) self.painter.fillRect(event.rect(), QBrush(Qt.white)) # Translation self.painter.translate(self.ox, self.oy) # Background if not self.background.isNull(): rect = self.background.rect() self.painter.setOpacity(self.background_opacity) self.painter.drawImage( QRectF( self.background_offset * self.zoom, QSizeF(rect.width(), rect.height()) * self.background_scale * self.zoom), self.background, QRectF(rect)) self.painter.setOpacity(1) # Show frame pen = QPen(Qt.blue) pen.setWidth(1) self.painter.setPen(pen) self.painter.setFont(QFont("Arial", self.font_size)) # Draw origin lines if self.show_ticks not in {_TickMark.SHOW, _TickMark.SHOW_NUM}: return pen.setColor(Qt.gray) self.painter.setPen(pen) x_l = -self.ox x_r = self.width() - self.ox self.painter.drawLine(QPointF(x_l, 0), QPointF(x_r, 0)) y_t = self.height() - self.oy y_b = -self.oy self.painter.drawLine(QPointF(0, y_b), QPointF(0, y_t)) def indexing(v: float) -> int: """Draw tick.""" return int(v / self.zoom - v / self.zoom % 5) # Draw tick for x in range(indexing(x_l), indexing(x_r) + 1, 5): if x == 0: continue is_ten = x % 10 == 0 end = QPointF(x * self.zoom, -10 if is_ten else -5) self.painter.drawLine(QPointF(x, 0) * self.zoom, end) if self.show_ticks == _TickMark.SHOW_NUM and is_ten: self.painter.drawText(end + QPointF(0, 3), f"{x}") for y in range(indexing(y_b), indexing(y_t) + 1, 5): if y == 0: continue is_ten = y % 10 == 0 end = QPointF(10 if is_ten else 5, y * self.zoom) self.painter.drawLine(QPointF(0, y) * self.zoom, end) if self.show_ticks == _TickMark.SHOW_NUM and is_ten: self.painter.drawText(end + QPointF(3, 0), f"{-y}") # Please to call the "end" method when ending paint event. def draw_circle(self, p: QPointF, r: float) -> None: """Draw circle.""" self.painter.drawEllipse(p, r, r) def draw_point(self, i: int, cx: float, cy: float, fixed: bool, color: Optional[Tuple[int, int, int]], mul: int = 1) -> None: """Draw a joint.""" if self.monochrome or color is None: color = Qt.black else: color = QColor(*color) pen = QPen(color) pen.setWidth(2) self.painter.setPen(pen) x = cx * self.zoom y = cy * -self.zoom if fixed: # Draw a triangle below self.painter.drawPolygon( QPointF(x, y), QPointF(x - self.joint_size, y + 2 * self.joint_size), QPointF(x + self.joint_size, y + 2 * self.joint_size)) r = self.joint_size for _ in range(1 if mul < 1 else mul): self.draw_circle(QPointF(x, y), r) r += 5 if not self.show_point_mark: return pen.setColor(Qt.darkGray) pen.setWidth(2) self.painter.setPen(pen) text = f"[Point{i}]" if self.show_dimension: text += f":({cx:.02f}, {cy:.02f})" self.painter.drawText(QPointF(x, y) + QPointF(6, -6), text) def draw_ranges(self) -> None: """Draw rectangle ranges.""" pen = QPen() pen.setWidth(5) for i, (tag, rect) in enumerate(self.ranges.items()): range_color = QColor(color_num(i + 1)) range_color.setAlpha(30) self.painter.setBrush(range_color) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) cx = rect.x() * self.zoom cy = rect.y() * -self.zoom if rect.width(): self.painter.drawRect( QRectF(QPointF(cx, cy), QSizeF(rect.width(), rect.height()) * self.zoom)) else: self.draw_circle(QPointF(cx, cy), 3) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) self.painter.drawText(QPointF(cx, cy) + QPointF(6, -6), tag) self.painter.setBrush(Qt.NoBrush) def draw_target_path(self) -> None: """Draw solving path.""" pen = QPen() pen.setWidth(self.path_width) for i, n in enumerate(sorted(self.target_path)): path = self.target_path[n] if self.monochrome: line, dot = target_path_style(0) else: line, dot = target_path_style(i + 1) pen.setColor(line) self.painter.setPen(pen) if len(path) == 1: x, y = path[0] p = QPointF(x, -y) * self.zoom self.painter.drawText(p + QPointF(6, -6), f"P{n}") pen.setColor(dot) self.painter.setPen(pen) self.draw_circle(p, self.joint_size) else: painter_path = QPainterPath() for j, (x, y) in enumerate(path): p = QPointF(x, -y) * self.zoom self.draw_circle(p, self.joint_size) if j == 0: self.painter.drawText(p + QPointF(6, -6), f"P{n}") painter_path.moveTo(p) else: x2, y2 = path[j - 1] self.__draw_arrow(x, -y, x2, -y2, zoom=True) painter_path.lineTo(p) pen.setColor(line) self.painter.setPen(pen) self.painter.drawPath(painter_path) for x, y in path: pen.setColor(dot) self.painter.setPen(pen) self.draw_circle( QPointF(x, -y) * self.zoom, self.joint_size) self.painter.setBrush(Qt.NoBrush) def __draw_arrow(self, x1: float, y1: float, x2: float, y2: float, *, zoom: bool = False, text: str = '') -> None: """Front point -> Back point""" if zoom: x1 *= self.zoom y1 *= self.zoom x2 *= self.zoom y2 *= self.zoom a = atan2(y2 - y1, x2 - x1) x1 = (x1 + x2) / 2 - 7.5 * cos(a) y1 = (y1 + y2) / 2 - 7.5 * sin(a) first_point = QPointF(x1, y1) self.painter.drawLine( first_point, QPointF(x1 + 15 * cos(a + radians(20)), y1 + 15 * sin(a + radians(20)))) self.painter.drawLine( first_point, QPointF(x1 + 15 * cos(a - radians(20)), y1 + 15 * sin(a - radians(20)))) if not text: return # Font font = self.painter.font() font_copy = QFont(font) font.setBold(True) font.setPointSize(font.pointSize() + 8) self.painter.setFont(font) # Color pen = self.painter.pen() color = pen.color() pen.setColor(color.darker()) self.painter.setPen(pen) self.painter.drawText(first_point, text) pen.setColor(color) self.painter.setPen(pen) self.painter.setFont(font_copy) def draw_curve(self, path: Sequence[_Coord]) -> None: """Draw path as curve.""" if len(set(path)) < 2: return painter_path = QPainterPath() error = False for i, (x, y) in enumerate(path): if isnan(x): error = True self.painter.drawPath(painter_path) painter_path = QPainterPath() else: p = QPointF(x, -y) * self.zoom if i == 0: painter_path.moveTo(p) self.draw_circle(p, 2) continue if error: painter_path.moveTo(p) error = False else: painter_path.lineTo(p) self.painter.drawPath(painter_path) def draw_dot(self, path: Sequence[_Coord]) -> None: """Draw path as dots.""" if len(set(path)) < 2: return for i, (x, y) in enumerate(path): if isnan(x): continue p = QPointF(x, -y) * self.zoom if i == 0: self.draw_circle(p, 2) else: self.painter.drawPoint(p) def solution_polygon( self, func: str, args: Sequence[str], target: str, pos: Sequence[VPoint]) -> Tuple[List[QPointF], QColor]: """Get solution polygon.""" if func == 'PLLP': color = QColor(121, 171, 252) params = [args[0], args[-1]] elif func == 'PLAP': color = QColor(249, 84, 216) params = [args[0]] else: if func == 'PLPP': color = QColor(94, 255, 185) else: # PXY color = QColor(249, 175, 27) params = [args[0]] params.append(target) tmp_list = [] for name in params: try: index = int(name.replace('P', '')) except ValueError: continue else: vpoint = pos[index] tmp_list.append(QPointF(vpoint.cx, -vpoint.cy) * self.zoom) return tmp_list, color def draw_solution(self, func: str, args: Sequence[str], target: str, pos: Sequence[VPoint]) -> None: """Draw the solution triangle.""" points, color = self.solution_polygon(func, args, target, pos) color.setAlpha(150) pen = QPen(color) pen.setWidth(self.joint_size) self.painter.setPen(pen) def draw_arrow(index: int, text: str) -> None: """Draw arrow.""" self.__draw_arrow(points[-1].x(), points[-1].y(), points[index].x(), points[index].y(), text=text) draw_arrow(0, args[1]) if func == 'PLLP': draw_arrow(1, args[2]) color.setAlpha(30) self.painter.setBrush(QBrush(color)) self.painter.drawPolygon(QPolygonF(points)) self.painter.setBrush(Qt.NoBrush) @Slot(int) def set_show_ticks(self, show: int): """Set the appearance of tick mark.""" self.show_ticks = _TickMark(show + 1) self.update() @Slot(bool) def set_monochrome_mode(self, monochrome: bool) -> None: """Set monochrome mode.""" self.monochrome = monochrome self.update()
def paintEvent(self, event): """Override Qt method. Painting line number area """ painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) # This is needed to make that the font size of line numbers # be the same as the text one when zooming # See Issue 2296 and 4811 font = self.editor.font() font_height = self.editor.fontMetrics().height() active_block = self.editor.textCursor().block() active_line_number = active_block.blockNumber() + 1 def draw_pixmap(xleft, ytop, pixmap): if not QT55_VERSION: pixmap_height = pixmap.height() else: # scale pixmap height to device independent pixels pixmap_height = pixmap.height() / pixmap.devicePixelRatio() painter.drawPixmap(xleft, ytop + (font_height - pixmap_height) / 2, pixmap) for top, line_number, block in self.editor.visible_blocks: if self._margin: if line_number == active_line_number: font.setWeight(font.Bold) painter.setFont(font) painter.setPen(self.editor.normal_color) else: font.setWeight(font.Normal) painter.setFont(font) painter.setPen(self.linenumbers_color) painter.drawText(0, top, self.width(), font_height, Qt.AlignRight | Qt.AlignBottom, to_text_string(line_number)) size = self.get_markers_margin() - 2 icon_size = QSize(size, size) data = block.userData() if self._markers_margin and data: if data.code_analysis: errors = 0 warnings = 0 infos = 0 hints = 0 for _, _, sev, _ in data.code_analysis: errors += sev == DiagnosticSeverity.ERROR warnings += sev == DiagnosticSeverity.WARNING infos += sev == DiagnosticSeverity.INFORMATION hints += sev == DiagnosticSeverity.HINT if errors: draw_pixmap(1, top, self.error_icon.pixmap(icon_size)) elif warnings: draw_pixmap(1, top, self.warning_icon.pixmap(icon_size)) elif infos: draw_pixmap(1, top, self.info_icon.pixmap(icon_size)) elif hints: draw_pixmap(1, top, self.hint_icon.pixmap(icon_size)) if data.todo: draw_pixmap(1, top, self.todo_icon.pixmap(icon_size))