Source code for node_editor.node_graphics_node

# -*- coding: utf-8 -*-
"""
A module containing Graphics representation of :class:`~node_editor.node_node.Node`
"""
from qtpy.QtWidgets import QGraphicsItem, QWidget, QGraphicsTextItem
from qtpy.QtGui import QFont, QColor, QPen, QBrush, QPainterPath
from qtpy.QtCore import Qt, QRectF


[docs]class QDMGraphicsNode(QGraphicsItem): """Class describing Graphics representation of :class:`~node_editor.node_node.Node`""" def __init__(self, node:'Node', parent:QWidget=None): """ :param node: reference to :class:`~node_editor.node_node.Node` :type node: :class:`~nodeeditor.node_node.Node` :param parent: parent widget :type parent: QWidget :Instance Attributes: - **node** - reference to :class:`~node_editor.node_node.Node` """ super().__init__(parent) self.node = node # init our flags self.hovered = False self._was_moved = False self._last_selected_state = False self.initSizes() self.initAssets() self.initUI() @property def content(self): """Reference to `Node Content`""" return self.node.content if self.node else None @property def title(self): """title of this `Node` :getter: current Graphics Node title :setter: stores and make visible the new title :type: str """ return self._title @title.setter def title(self, value): self._title = value self.title_item.setPlainText(self._title)
[docs] def initUI(self): """Set up this ``QGraphicsItem``""" self.setFlag(QGraphicsItem.ItemIsSelectable) self.setFlag(QGraphicsItem.ItemIsMovable) self.setAcceptHoverEvents(True) # init title self.initTitle() self.title = self.node.title self.initContent()
[docs] def initSizes(self): """Set up internal attributes like `width`, `height`, etc.""" self.edge_roundness = 10.0 self.edge_padding = 10.0 self.title_height = 24.0 self.title_horizontal_padding = 4.0 self.title_vertical_padding = 4.0 self.width = 250 + 2 * self.edge_padding self.height = 280 + self.title_height + 2*self.title_vertical_padding+2*self.edge_padding
[docs] def initAssets(self): """Initialize ``QObjects`` like ``QColor``, ``QPen`` and ``QBrush``""" self._title_color = Qt.white self._title_font = QFont("Ubuntu", 10) self._color = QColor("#7F000000") self._color_selected = QColor("#FFFFA637") self._color_hovered = QColor("#FF37A6FF") self._pen_default = QPen(self._color) self._pen_default.setWidthF(2.0) self._pen_selected = QPen(self._color_selected) self._pen_selected.setWidthF(2.0) self._pen_hovered = QPen(self._color_hovered) self._pen_hovered.setWidthF(3.0) self._brush_title = QBrush(QColor("#FF313131")) self._brush_background = QBrush(QColor("#E3212121"))
[docs] def onSelected(self): """Our event handling when the node was selected""" self.node.scene.grScene.itemSelected.emit()
[docs] def doSelect(self, new_state=True): """Safe version of selecting the `Graphics Node`. Takes care about the selection state flag used internally :param new_state: ``True`` to select, ``False`` to deselect :type new_state: ``bool`` """ self.setSelected(new_state) self._last_selected_state = new_state if new_state: self.onSelected()
[docs] def mouseMoveEvent(self, event): """Overridden event to detect that we moved with this `Node`""" super().mouseMoveEvent(event) # optimize me! just update the selected nodes for node in self.scene().scene.nodes: if node.grNode.isSelected(): node.updateConnectedEdges() self._was_moved = True
[docs] def mouseReleaseEvent(self, event): """Overriden event to handle when we moved, selected or deselected this `Node`""" super().mouseReleaseEvent(event) # handle when grNode moved if self._was_moved: self._was_moved = False self.node.scene.history.storeHistory("Node moved", setModified=True) self.node.scene.resetLastSelectedStates() self.doSelect() # also trigger itemSelected when node was moved # we need to store the last selected state, because moving does also select the nodes self.node.scene._last_selected_items = self.node.scene.getSelectedItems() # now we want to skip storing selection return # handle when grNode was clicked on if self._last_selected_state != self.isSelected() or self.node.scene._last_selected_items != self.node.scene.getSelectedItems(): self.node.scene.resetLastSelectedStates() self._last_selected_state = self.isSelected() self.onSelected()
[docs] def mouseDoubleClickEvent(self, event): """Overriden event for doubleclick. Resend to `Node::onDoubleClicked`""" self.node.onDoubleClicked(event)
[docs] def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: """Handle hover effect""" self.hovered = True self.update()
[docs] def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: """Handle hover effect""" self.hovered = False self.update()
[docs] def boundingRect(self) -> QRectF: """Defining Qt' bounding rectangle""" return QRectF( 0, 0, self.width, self.height ).normalized()
[docs] def initTitle(self): """Set up the title Graphics representation: font, color, position, etc.""" self.title_item = QGraphicsTextItem(self) self.title_item.node = self.node self.title_item.setDefaultTextColor(self._title_color) self.title_item.setFont(self._title_font) self.title_item.setPos(self.title_horizontal_padding, 0) self.title_item.setTextWidth( self.width - 2 * self.title_horizontal_padding )
[docs] def initContent(self): """Set up the `grContent` - ``QGraphicsProxyWidget`` to have a container for `Graphics Content`""" if self.content is not None: self.content.setGeometry(self.edge_padding, self.title_height + self.edge_padding, self.width - 2 * self.edge_padding, self.height - 2 * self.edge_padding - self.title_height) # get the QGraphicsProxyWidget when inserted into the grScene self.grContent = self.node.scene.grScene.addWidget(self.content) self.grContent.node = self.node self.grContent.setParentItem(self)
[docs] def paint(self, painter, QStyleOptionGraphicsItem, widget=None): """Painting the rounded rectanglar `Node`""" # title path_title = QPainterPath() path_title.setFillRule(Qt.WindingFill) path_title.addRoundedRect(0, 0, self.width, self.title_height, self.edge_roundness, self.edge_roundness) path_title.addRect(0, self.title_height - self.edge_roundness, self.edge_roundness, self.edge_roundness) path_title.addRect(self.width - self.edge_roundness, self.title_height - self.edge_roundness, self.edge_roundness, self.edge_roundness) painter.setPen(Qt.NoPen) painter.setBrush(self._brush_title) painter.drawPath(path_title.simplified()) # content path_content = QPainterPath() path_content.setFillRule(Qt.WindingFill) path_content.addRoundedRect(0, self.title_height, self.width, self.height - self.title_height, self.edge_roundness, self.edge_roundness) path_content.addRect(0, self.title_height, self.edge_roundness, self.edge_roundness) path_content.addRect(self.width - self.edge_roundness, self.title_height, self.edge_roundness, self.edge_roundness) painter.setPen(Qt.NoPen) painter.setBrush(self._brush_background) painter.drawPath(path_content.simplified()) # outline path_outline = QPainterPath() path_outline.addRoundedRect(-1, -1, self.width+2, self.height+2, self.edge_roundness, self.edge_roundness) painter.setBrush(Qt.NoBrush) if self.hovered: painter.setPen(self._pen_hovered) painter.drawPath(path_outline.simplified()) painter.setPen(self._pen_default) painter.drawPath(path_outline.simplified()) else: painter.setPen(self._pen_default if not self.isSelected() else self._pen_selected) painter.drawPath(path_outline.simplified())