def box_rect(self, rect: QtCore.QRectF): self._box_rect = rect # Update the scene rect so that it matches how much space we # currently want for drawing everything. rect.setWidth(rect.width() - 1) self.setSceneRect(rect)
def get_header_rect(self): header_height = 1.4 * self.title_label.boundingRect().height() # 35 * (self.parent_node.title.count('\n')+1) header_rect = QRectF() header_rect.setTopLeft(QPointF(-self.width/2, -self.height/2)) header_rect.setWidth(self.width) header_rect.setHeight(header_height) return header_rect
def boundingRect(self): # remember: (0, 0) shall be the NI's center! rect = QRectF() w = self.layout.geometry().width() h = self.layout.geometry().height() rect.setLeft(-w / 2) rect.setTop(-h / 2) rect.setWidth(w) rect.setHeight(h) return rect
def get_header_rect(w, h, title_rect): """ :param w: width :param h: height """ header_height = 1.4 * title_rect.height( ) # 35 * (self.parent_node.title.count('\n')+1) header_rect = QRectF() header_rect.setTopLeft(QPointF(-w / 2, -h / 2)) header_rect.setWidth(w) header_rect.setHeight(header_height) return header_rect
def get_title_rect(self): title_rect_offset_factor = 0.56 header_rect = self.get_header_rect() rect = QRectF() rect.setTop(header_rect.top() + (header_rect.height() / 2) * (1 - title_rect_offset_factor)) rect.setLeft(header_rect.left() + 10) rect.setHeight(header_rect.height() * title_rect_offset_factor) w = header_rect.width() * title_rect_offset_factor title_width = self.display_name_FM.width( get_longest_line(self.parent_node.title)) rect.setWidth(w if w > title_width else title_width) return rect
def show_all(self): # trick: # if user zoom in or zoom out too much view exceeds matrix limit # so need to set view's matrix to initial matrix self.setMatrix(self.initial_matrix) items = self.get_visible_items() rect = QRectF() for i in items: rect = rect.united(i.boundingRect()) # it is not working properly without updating the rect # need to set new position and edit rect's size rect.setX(rect.x() - 1) rect.setY(rect.y() - 1) rect.setWidth(rect.width() + 1) rect.setHeight(rect.height() + 1) self.fitInView(rect, Qt.KeepAspectRatio)
def get_whole_scene_img(self): self.hide_proxies() img = QImage(self.sceneRect().width() / self.total_scale_div, self.sceneRect().height() / self.total_scale_div, QImage.Format_RGB32) img.fill(Qt.transparent) painter = QPainter(img) painter.setRenderHint(QPainter.Antialiasing) rect = QRectF() rect.setLeft(-self.viewport().pos().x()) rect.setTop(-self.viewport().pos().y()) rect.setWidth(img.rect().width()) rect.setHeight(img.rect().height()) # rect is right... but it only renders from the viewport's point down-and rightwards, not from topleft (0,0) ... self.render(painter, rect, rect.toRect()) self.show_proxies() return img
def paint(self, painter, option, widget=None): if Design.flow_theme == 'dark std': color = QColor( '#2E688C' ) if self.parent_port_instance.type_ == 'data' else QColor( '#3880ad') if option.state & QStyle.State_MouseOver: color = color.lighter() brush = QBrush(QColor(color)) painter.setBrush(brush) painter.setPen(Qt.NoPen) painter.drawEllipse( QRectF(self.padding, self.padding, self.painting_width, self.painting_height)) elif Design.flow_theme == 'dark tron': color = '' if self.parent_port_instance.type_ == 'exec': color = '#FFFFFF' elif self.parent_port_instance.type_ == 'data': color = self.parent_node_instance.parent_node.color pen = QPen(color) pen.setWidth(2) painter.setPen(pen) if len(self.parent_port_instance.connected_port_instances) > 0 or \ option.state & QStyle.State_MouseOver: # also fill when mouse hovers c = self.parent_node_instance.parent_node.color r = c.red() g = c.green() b = c.blue() brush = QBrush(QColor(r, g, b, 100)) painter.setBrush(brush) else: painter.setBrush(Qt.NoBrush) painter.drawEllipse( QRectF(self.padding, self.padding, self.painting_width, self.painting_height)) elif Design.flow_theme == 'ghostly' or Design.flow_theme == 'blender': color = '' if self.parent_port_instance.type_ == 'exec': color = '#FFFFFF' if len(self.parent_port_instance.connected_port_instances) > 0 or \ option.state & QStyle.State_MouseOver: # also fill when mouse hovers brush = QBrush(QColor(255, 255, 255, 100)) painter.setBrush(brush) else: painter.setBrush(Qt.NoBrush) elif self.parent_port_instance.type_ == 'data': color = self.parent_node_instance.parent_node.color if len(self.parent_port_instance.connected_port_instances) > 0 or \ option.state & QStyle.State_MouseOver: # also fill when mouse hovers c = self.parent_node_instance.parent_node.color r = c.red() g = c.green() b = c.blue() brush = QBrush(QColor(r, g, b, 100)) painter.setBrush(brush) else: painter.setBrush(Qt.NoBrush) pen = QPen(color) pen.setWidth(1) painter.setPen(pen) rect = QRectF() rect.moveCenter(QPointF(self.width / 2, self.height / 2)) rect.setWidth(self.painting_width) rect.setHeight(self.painting_height) painter.drawEllipse(QPointF(self.width / 2, self.height / 2), self.painting_width / 3, self.painting_height / 3)
class TextLineItem(QAbstractGraphicsShapeItem): """A one-line text item. Default origin point is at the left side of the baseline. This can change if setAlignMode is called. TextLineItem also supports drawing text background. Its brush can be set using setBackgroundBrush(). Text must not contain newline characters. """ def __init__(self, text=None, parent=None): super().__init__(parent) self._text = text or "" self._elided_text = text or "" self._elide_mode = Qt.ElideRight self._align_mode = Qt.AlignLeft self._max_width = None self._font = QFont() self._bounding_rect = QRectF() """Bounding and drawing rectangle. Determined automatically.""" self.background = QGraphicsRectItem(self) self.background.setPen(Qt.NoPen) self.background.setFlag(QGraphicsItem.ItemStacksBehindParent) self.adjust() def setText(self, text: str, /) -> None: if '\n' in text: raise ValueError("text must not contain newline characters") self.prepareGeometryChange() self._text = text self.adjust() def setElideMode(self, mode: int, /) -> None: """Elide mode specifies where the ellipsis should be located when the text is elided. Default value is Qt.ElideRight. """ self.prepareGeometryChange() self._elide_mode = mode self.adjust() def setAlignMode(self, mode: int, /) -> None: """Align mode specifies text alignment. Text alignment changes the origin point x position: - If mode is Qt.AlignLeft, the origin point is on the left of the baseline. - If mode is Qt.AlignHCenter, the origin point is in the center of the baseline. - If mode is Qt.AlignRight, the origin point is on the right of the baseline. Vertical alignment has no meaning for one line of text and should not be set. Default value is Qt.AlignLeft. """ self.prepareGeometryChange() self._align_mode = mode self.adjust() def setMaximumWidth(self, width, /): """Set the maximum width the text is allowed to be. `None` represents unlimited width.""" self.prepareGeometryChange() self._max_width = width self.adjust() def setFont(self, font: QFont, /) -> None: self.prepareGeometryChange() self._font = font self.adjust() def setBackgroundBrush(self, brush: QBrush, /): self.background.setBrush(brush) def text(self) -> str: return self._text def elidedText(self) -> str: return self._elided_text def elideMode(self) -> int: return self._elide_mode def alignMode(self) -> int: return self._align_mode def maximumWidth(self): """Maximum width the text is allowed to be. `None` represents unlimited width.""" return self._max_width def font(self) -> QFont: return self._font def backgroundBrush(self): return self.background.brush() def adjust(self): """Adjust the item's geometry in response to changes.""" metrics = QFontMetricsF(self.font()) # Get bounding rectangle for full text self._bounding_rect = metrics.boundingRect(self.text()) # Constrain by maximum width if self.maximumWidth() is not None: self._bounding_rect.setWidth(self.maximumWidth()) # Compute elided text self._elided_text = metrics.elidedText(self.text(), self.elideMode(), self.boundingRect().width()) # Get bounding rectangle for elided text self._bounding_rect = metrics.boundingRect(self.elidedText()) # It seems that for small characters like "..." the bounding rect returned is too small. Adjust it by a small # value. metrics_correction = px(1 / 72) self._bounding_rect.adjust(-metrics_correction, 0, metrics_correction, 0) # Move origin point according to the alignment if self.alignMode() & Qt.AlignLeft: self._bounding_rect.moveLeft(0) elif self.alignMode() & Qt.AlignRight: self._bounding_rect.moveRight(0) else: self._bounding_rect.moveLeft(-self._bounding_rect.width() / 2) # Set background rect self.background.setRect(self.boundingRect()) def boundingRect(self) -> QRectF: return self._bounding_rect def paint(self, painter: QPainter, option, widget=...) -> None: painter.setBrush(self.brush()) painter.setPen(self.pen()) painter.setFont(self.font()) painter.drawText(self.boundingRect(), self.alignMode(), self.elidedText())
def eventFilter(self, obj, event): if event.type() == QEvent.GraphicsSceneMousePress: if event.button() == Qt.MouseButton.LeftButton: self.mouse_pressed = True self.mouse_pressed_x, self.mouse_pressed_y = event.pos().x( ), event.pos().y() if self.draw_ellipse: ellipsis = QGraphicsEllipseItem(self.chart) ellipsis.setZValue(12) ellipsis.setBrush(QBrush(QColor(244, 67, 54, 50))) ellipsis.setPen(QPen(Qt.transparent)) self.ellipses.append(ellipsis) elif self.write_text: for t in self.texts: r = QRectF() r.setTopLeft(t.pos()) r.setWidth(t.boundingRect().width()) r.setHeight(t.boundingRect().height()) if r.contains(self.mouse_pressed_x, self.mouse_pressed_y): return True """ The user clicked over an area where there is no text. So we create one. """ text = QGraphicsTextItem(self.chart) text.setZValue(12) text.setPos( QPointF(self.mouse_pressed_x, self.mouse_pressed_y)) text.setPlainText("label") text.setAcceptHoverEvents(True) text.setTabChangesFocus(True) text.setFlags(QGraphicsTextItem.ItemIsMovable) text.installEventFilter(self.text_event_filter) self.texts.append(text) return True elif event.button() == Qt.MouseButton.RightButton: x, y = event.pos().x(), event.pos().y() for e in self.ellipses: if e.rect().contains(x, y): e.hide() self.ellipses.remove(e) for t in self.texts: r = QRectF() r.setTopLeft(t.pos()) r.setWidth(t.boundingRect().width()) r.setHeight(t.boundingRect().height()) if r.contains(x, y): t.hide() self.texts.remove(t) return True return QObject.eventFilter(self, obj, event) elif event.type() == QEvent.GraphicsSceneMouseRelease: self.mouse_pressed = False return True elif event.type() == QEvent.GraphicsSceneMouseMove: if self.mouse_pressed: if self.draw_ellipse: x, y = event.pos().x(), event.pos().y() width = x - self.mouse_pressed_x height = y - self.mouse_pressed_y self.ellipses[-1].setRect(self.mouse_pressed_x, self.mouse_pressed_y, width, height) return True return QObject.eventFilter(self, obj, event) return QObject.eventFilter(self, obj, event)