Node
1# Node.py 2 3from PySide6.QtWidgets import QGraphicsItem, QGraphicsEllipseItem 4from PySide6.QtCore import QRectF, Qt, QPointF 5from PySide6.QtGui import QPainter, QPen, QBrush 6from Edge import Edge 7from NodeData import NodeData 8from NodeLayout import NodeLayout 9 10class Node(QGraphicsItem): 11 def __init__(self, node_data: NodeData): 12 super().__init__() 13 self.data = node_data 14 self.setFlag(QGraphicsItem.ItemIsMovable) 15 self.setFlag(QGraphicsItem.ItemIsSelectable) 16 self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) 17 self.rect = QRectF(0, 0, self.data.width, self.data.height) 18 self.resizeHandleSize = 10 19 self.resizing = False 20 self.resizeDirection = None 21 self.content = NodeLayout(self) 22 self.input_port = Port(self, QPointF(0, 25), "input") 23 self.output_port = Port(self, QPointF(self.rect.width(), 25), "output") 24 self.setPos(self.data.pos_x, self.data.pos_y) # Set initial position from NodeData 25 self.setAcceptHoverEvents(True) 26 self.hovered = False # Track hover state 27 28 def setWidth(self, width): 29 self.rect.setWidth(width) 30 self.output_port.setPos(width, 25) 31 self.prepareGeometryChange() 32 self.content.update_proxy_widget_geometry() # Ensure the content size is updated 33 self.data.width = width 34 35 def setHeight(self, height): 36 self.rect.setHeight(height) 37 self.prepareGeometryChange() 38 self.content.update_proxy_widget_geometry() # Ensure the content size is updated 39 self.data.height = height 40 41 def boundingRect(self): 42 return self.rect 43 44 def paint(self, painter, option, widget): 45 pen = QPen(Qt.black, 2) 46 if self.hovered: 47 pen.setColor(Qt.red) 48 painter.setPen(pen) 49 painter.drawRect(self.rect) 50 self.content.paint(painter, option, widget) # Delegate the painting to NodeLayout 51 52 def itemChange(self, change, value): 53 if change == QGraphicsItem.ItemPositionChange: 54 for port in [self.input_port, self.output_port]: 55 for edge in port.edges: 56 edge.update_position() 57 # Sync position with NodeData 58 self.data.pos_x = value.x() 59 self.data.pos_y = value.y() 60 return super().itemChange(change, value) 61 62 def mousePressEvent(self, event): 63 pos = event.pos() 64 if pos.x() >= self.rect.right() - self.resizeHandleSize and \ 65 pos.y() >= self.rect.bottom() - self.resizeHandleSize: 66 self.resizing = True 67 self.resizeDirection = "bottom_right" 68 self.setCursor(Qt.SizeFDiagCursor) 69 else: 70 self.resizing = False 71 super().mousePressEvent(event) 72 73 def mouseMoveEvent(self, event): 74 if self.resizing: 75 delta = event.pos() - event.lastPos() 76 if self.resizeDirection == "bottom_right": 77 self.setWidth(self.rect.width() + delta.x()) 78 self.setHeight(self.rect.height() + delta.y()) 79 else: 80 super().mouseMoveEvent(event) 81 82 def mouseReleaseEvent(self, event): 83 if self.resizing: 84 self.resizing = False 85 self.setCursor(Qt.ArrowCursor) 86 else: 87 super().mouseReleaseEvent(event) 88 89 def remove_node(self): 90 # Remove all edges connected to this node 91 for edge in self.input_port.edges[:]: 92 edge.remove() 93 for edge in self.output_port.edges[:]: 94 edge.remove() 95 96 # Update prevs and nexts of connected nodes 97 for prev_id in self.data.prevs: 98 prev_node = self.scene().get_node_by_id(prev_id) 99 if prev_node: 100 prev_node.data.nexts.remove(self.data.uniq_id) 101 102 for next_id in self.data.nexts: 103 next_node = self.scene().get_node_by_id(next_id) 104 if next_node: 105 next_node.data.prevs.remove(self.data.uniq_id) 106 107 # Finally, remove this node from the scene 108 self.scene().removeItem(self) 109 110 def hoverEnterEvent(self, event): 111 self.hovered = True 112 self.update() # Trigger a repaint 113 super().hoverEnterEvent(event) 114 115 def hoverLeaveEvent(self, event): 116 self.hovered = False 117 self.update() # Trigger a repaint 118 super().hoverLeaveEvent(event) 119 120class Port(QGraphicsEllipseItem): 121 def __init__(self, parent, position, port_type): 122 super().__init__(-5, -5, 10, 10, parent) 123 self.setBrush(Qt.black) 124 self.setFlag(QGraphicsItem.ItemIsMovable, False) 125 self.setPos(position) 126 self.port_type = port_type 127 self.edges = [] 128 129 def mousePressEvent(self, event): 130 if self.port_type == "output": 131 edge = Edge(self) 132 self.edges.append(edge) 133 self.scene().addItem(edge) 134 135 def mouseMoveEvent(self, event): 136 if self.edges: 137 self.edges[-1].update_position(event.scenePos()) 138 139 def mouseReleaseEvent(self, event): 140 if self.edges: 141 items = self.scene().items(event.scenePos()) 142 for item in items: 143 if isinstance(item, Port) and item != self: 144 if self.port_type == "output" and item.port_type == "input": 145 self.edges[-1].set_destination(item) 146 item.edges.append(self.edges[-1]) 147 break 148 else: 149 self.scene().removeItem(self.edges[-1]) 150 self.edges.pop()
class
Node(PySide6.QtWidgets.QGraphicsItem):
11class Node(QGraphicsItem): 12 def __init__(self, node_data: NodeData): 13 super().__init__() 14 self.data = node_data 15 self.setFlag(QGraphicsItem.ItemIsMovable) 16 self.setFlag(QGraphicsItem.ItemIsSelectable) 17 self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) 18 self.rect = QRectF(0, 0, self.data.width, self.data.height) 19 self.resizeHandleSize = 10 20 self.resizing = False 21 self.resizeDirection = None 22 self.content = NodeLayout(self) 23 self.input_port = Port(self, QPointF(0, 25), "input") 24 self.output_port = Port(self, QPointF(self.rect.width(), 25), "output") 25 self.setPos(self.data.pos_x, self.data.pos_y) # Set initial position from NodeData 26 self.setAcceptHoverEvents(True) 27 self.hovered = False # Track hover state 28 29 def setWidth(self, width): 30 self.rect.setWidth(width) 31 self.output_port.setPos(width, 25) 32 self.prepareGeometryChange() 33 self.content.update_proxy_widget_geometry() # Ensure the content size is updated 34 self.data.width = width 35 36 def setHeight(self, height): 37 self.rect.setHeight(height) 38 self.prepareGeometryChange() 39 self.content.update_proxy_widget_geometry() # Ensure the content size is updated 40 self.data.height = height 41 42 def boundingRect(self): 43 return self.rect 44 45 def paint(self, painter, option, widget): 46 pen = QPen(Qt.black, 2) 47 if self.hovered: 48 pen.setColor(Qt.red) 49 painter.setPen(pen) 50 painter.drawRect(self.rect) 51 self.content.paint(painter, option, widget) # Delegate the painting to NodeLayout 52 53 def itemChange(self, change, value): 54 if change == QGraphicsItem.ItemPositionChange: 55 for port in [self.input_port, self.output_port]: 56 for edge in port.edges: 57 edge.update_position() 58 # Sync position with NodeData 59 self.data.pos_x = value.x() 60 self.data.pos_y = value.y() 61 return super().itemChange(change, value) 62 63 def mousePressEvent(self, event): 64 pos = event.pos() 65 if pos.x() >= self.rect.right() - self.resizeHandleSize and \ 66 pos.y() >= self.rect.bottom() - self.resizeHandleSize: 67 self.resizing = True 68 self.resizeDirection = "bottom_right" 69 self.setCursor(Qt.SizeFDiagCursor) 70 else: 71 self.resizing = False 72 super().mousePressEvent(event) 73 74 def mouseMoveEvent(self, event): 75 if self.resizing: 76 delta = event.pos() - event.lastPos() 77 if self.resizeDirection == "bottom_right": 78 self.setWidth(self.rect.width() + delta.x()) 79 self.setHeight(self.rect.height() + delta.y()) 80 else: 81 super().mouseMoveEvent(event) 82 83 def mouseReleaseEvent(self, event): 84 if self.resizing: 85 self.resizing = False 86 self.setCursor(Qt.ArrowCursor) 87 else: 88 super().mouseReleaseEvent(event) 89 90 def remove_node(self): 91 # Remove all edges connected to this node 92 for edge in self.input_port.edges[:]: 93 edge.remove() 94 for edge in self.output_port.edges[:]: 95 edge.remove() 96 97 # Update prevs and nexts of connected nodes 98 for prev_id in self.data.prevs: 99 prev_node = self.scene().get_node_by_id(prev_id) 100 if prev_node: 101 prev_node.data.nexts.remove(self.data.uniq_id) 102 103 for next_id in self.data.nexts: 104 next_node = self.scene().get_node_by_id(next_id) 105 if next_node: 106 next_node.data.prevs.remove(self.data.uniq_id) 107 108 # Finally, remove this node from the scene 109 self.scene().removeItem(self) 110 111 def hoverEnterEvent(self, event): 112 self.hovered = True 113 self.update() # Trigger a repaint 114 super().hoverEnterEvent(event) 115 116 def hoverLeaveEvent(self, event): 117 self.hovered = False 118 self.update() # Trigger a repaint 119 super().hoverLeaveEvent(event)
QGraphicsItem(self, parent: Optional[PySide6.QtWidgets.QGraphicsItem] = None) -> None
Node(node_data: NodeData.NodeData)
12 def __init__(self, node_data: NodeData): 13 super().__init__() 14 self.data = node_data 15 self.setFlag(QGraphicsItem.ItemIsMovable) 16 self.setFlag(QGraphicsItem.ItemIsSelectable) 17 self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) 18 self.rect = QRectF(0, 0, self.data.width, self.data.height) 19 self.resizeHandleSize = 10 20 self.resizing = False 21 self.resizeDirection = None 22 self.content = NodeLayout(self) 23 self.input_port = Port(self, QPointF(0, 25), "input") 24 self.output_port = Port(self, QPointF(self.rect.width(), 25), "output") 25 self.setPos(self.data.pos_x, self.data.pos_y) # Set initial position from NodeData 26 self.setAcceptHoverEvents(True) 27 self.hovered = False # Track hover state
def
itemChange(self, change, value):
53 def itemChange(self, change, value): 54 if change == QGraphicsItem.ItemPositionChange: 55 for port in [self.input_port, self.output_port]: 56 for edge in port.edges: 57 edge.update_position() 58 # Sync position with NodeData 59 self.data.pos_x = value.x() 60 self.data.pos_y = value.y() 61 return super().itemChange(change, value)
def
mousePressEvent(self, event):
63 def mousePressEvent(self, event): 64 pos = event.pos() 65 if pos.x() >= self.rect.right() - self.resizeHandleSize and \ 66 pos.y() >= self.rect.bottom() - self.resizeHandleSize: 67 self.resizing = True 68 self.resizeDirection = "bottom_right" 69 self.setCursor(Qt.SizeFDiagCursor) 70 else: 71 self.resizing = False 72 super().mousePressEvent(event)
def
remove_node(self):
90 def remove_node(self): 91 # Remove all edges connected to this node 92 for edge in self.input_port.edges[:]: 93 edge.remove() 94 for edge in self.output_port.edges[:]: 95 edge.remove() 96 97 # Update prevs and nexts of connected nodes 98 for prev_id in self.data.prevs: 99 prev_node = self.scene().get_node_by_id(prev_id) 100 if prev_node: 101 prev_node.data.nexts.remove(self.data.uniq_id) 102 103 for next_id in self.data.nexts: 104 next_node = self.scene().get_node_by_id(next_id) 105 if next_node: 106 next_node.data.prevs.remove(self.data.uniq_id) 107 108 # Finally, remove this node from the scene 109 self.scene().removeItem(self)
Inherited Members
- PySide6.QtWidgets.QGraphicsItem
- acceptDrops
- acceptHoverEvents
- acceptTouchEvents
- acceptedMouseButtons
- addToIndex
- advance
- boundingRegion
- boundingRegionGranularity
- cacheMode
- childItems
- childrenBoundingRect
- clearFocus
- clipPath
- collidesWithItem
- collidesWithPath
- collidingItems
- commonAncestorItem
- contains
- contextMenuEvent
- cursor
- deviceTransform
- dragEnterEvent
- dragLeaveEvent
- dragMoveEvent
- dropEvent
- effectiveOpacity
- ensureVisible
- extension
- filtersChildEvents
- flags
- focusInEvent
- focusItem
- focusOutEvent
- focusProxy
- focusScopeItem
- grabKeyboard
- grabMouse
- graphicsEffect
- group
- handlesChildEvents
- hasCursor
- hasFocus
- hide
- hoverMoveEvent
- inputMethodEvent
- inputMethodHints
- inputMethodQuery
- installSceneEventFilter
- isActive
- isAncestorOf
- isBlockedByModalPanel
- isClipped
- isEnabled
- isObscured
- isObscuredBy
- isPanel
- isSelected
- isUnderMouse
- isVisible
- isVisibleTo
- isWidget
- isWindow
- itemTransform
- keyPressEvent
- keyReleaseEvent
- mapFromItem
- mapFromParent
- mapFromScene
- mapRectFromItem
- mapRectFromParent
- mapRectFromScene
- mapRectToItem
- mapRectToParent
- mapRectToScene
- mapToItem
- mapToParent
- mapToScene
- mouseDoubleClickEvent
- moveBy
- opacity
- opaqueArea
- panel
- panelModality
- parentItem
- parentObject
- parentWidget
- pos
- prepareGeometryChange
- removeFromIndex
- removeSceneEventFilter
- resetTransform
- rotation
- scale
- scene
- sceneBoundingRect
- sceneEvent
- sceneEventFilter
- scenePos
- sceneTransform
- scroll
- setAcceptDrops
- setAcceptHoverEvents
- setAcceptTouchEvents
- setAcceptedMouseButtons
- setActive
- setBoundingRegionGranularity
- setCacheMode
- setCursor
- setData
- setEnabled
- setFiltersChildEvents
- setFlag
- setFlags
- setFocus
- setFocusProxy
- setGraphicsEffect
- setGroup
- setHandlesChildEvents
- setInputMethodHints
- setOpacity
- setPanelModality
- setParentItem
- setPos
- setRotation
- setScale
- setSelected
- setToolTip
- setTransform
- setTransformOriginPoint
- setTransformations
- setVisible
- setX
- setY
- setZValue
- shape
- show
- stackBefore
- toGraphicsObject
- toolTip
- topLevelItem
- topLevelWidget
- transform
- transformOriginPoint
- transformations
- type
- ungrabKeyboard
- ungrabMouse
- unsetCursor
- update
- updateMicroFocus
- wheelEvent
- window
- x
- y
- zValue
- GraphicsItemFlag
- GraphicsItemChange
- CacheMode
- PanelModality
- Extension
- UserType
class
Port(PySide6.QtWidgets.QGraphicsEllipseItem):
121class Port(QGraphicsEllipseItem): 122 def __init__(self, parent, position, port_type): 123 super().__init__(-5, -5, 10, 10, parent) 124 self.setBrush(Qt.black) 125 self.setFlag(QGraphicsItem.ItemIsMovable, False) 126 self.setPos(position) 127 self.port_type = port_type 128 self.edges = [] 129 130 def mousePressEvent(self, event): 131 if self.port_type == "output": 132 edge = Edge(self) 133 self.edges.append(edge) 134 self.scene().addItem(edge) 135 136 def mouseMoveEvent(self, event): 137 if self.edges: 138 self.edges[-1].update_position(event.scenePos()) 139 140 def mouseReleaseEvent(self, event): 141 if self.edges: 142 items = self.scene().items(event.scenePos()) 143 for item in items: 144 if isinstance(item, Port) and item != self: 145 if self.port_type == "output" and item.port_type == "input": 146 self.edges[-1].set_destination(item) 147 item.edges.append(self.edges[-1]) 148 break 149 else: 150 self.scene().removeItem(self.edges[-1]) 151 self.edges.pop()
QGraphicsEllipseItem(self, parent: Optional[PySide6.QtWidgets.QGraphicsItem] = None) -> None QGraphicsEllipseItem(self, rect: Union[PySide6.QtCore.QRectF, PySide6.QtCore.QRect], parent: Optional[PySide6.QtWidgets.QGraphicsItem] = None) -> None QGraphicsEllipseItem(self, x: float, y: float, w: float, h: float, parent: Optional[PySide6.QtWidgets.QGraphicsItem] = None) -> None
def
mouseReleaseEvent(self, event):
140 def mouseReleaseEvent(self, event): 141 if self.edges: 142 items = self.scene().items(event.scenePos()) 143 for item in items: 144 if isinstance(item, Port) and item != self: 145 if self.port_type == "output" and item.port_type == "input": 146 self.edges[-1].set_destination(item) 147 item.edges.append(self.edges[-1]) 148 break 149 else: 150 self.scene().removeItem(self.edges[-1]) 151 self.edges.pop()
Inherited Members
- PySide6.QtWidgets.QGraphicsEllipseItem
- boundingRect
- contains
- extension
- isObscuredBy
- opaqueArea
- paint
- rect
- setRect
- setSpanAngle
- setStartAngle
- shape
- spanAngle
- startAngle
- type
- PySide6.QtWidgets.QAbstractGraphicsShapeItem
- brush
- pen
- setBrush
- setPen
- PySide6.QtWidgets.QGraphicsItem
- acceptDrops
- acceptHoverEvents
- acceptTouchEvents
- acceptedMouseButtons
- addToIndex
- advance
- boundingRegion
- boundingRegionGranularity
- cacheMode
- childItems
- childrenBoundingRect
- clearFocus
- clipPath
- collidesWithItem
- collidesWithPath
- collidingItems
- commonAncestorItem
- contextMenuEvent
- cursor
- data
- deviceTransform
- dragEnterEvent
- dragLeaveEvent
- dragMoveEvent
- dropEvent
- effectiveOpacity
- ensureVisible
- filtersChildEvents
- flags
- focusInEvent
- focusItem
- focusOutEvent
- focusProxy
- focusScopeItem
- grabKeyboard
- grabMouse
- graphicsEffect
- group
- handlesChildEvents
- hasCursor
- hasFocus
- hide
- hoverEnterEvent
- hoverLeaveEvent
- hoverMoveEvent
- inputMethodEvent
- inputMethodHints
- inputMethodQuery
- installSceneEventFilter
- isActive
- isAncestorOf
- isBlockedByModalPanel
- isClipped
- isEnabled
- isObscured
- isPanel
- isSelected
- isUnderMouse
- isVisible
- isVisibleTo
- isWidget
- isWindow
- itemChange
- itemTransform
- keyPressEvent
- keyReleaseEvent
- mapFromItem
- mapFromParent
- mapFromScene
- mapRectFromItem
- mapRectFromParent
- mapRectFromScene
- mapRectToItem
- mapRectToParent
- mapRectToScene
- mapToItem
- mapToParent
- mapToScene
- mouseDoubleClickEvent
- moveBy
- opacity
- panel
- panelModality
- parentItem
- parentObject
- parentWidget
- pos
- prepareGeometryChange
- removeFromIndex
- removeSceneEventFilter
- resetTransform
- rotation
- scale
- scene
- sceneBoundingRect
- sceneEvent
- sceneEventFilter
- scenePos
- sceneTransform
- scroll
- setAcceptDrops
- setAcceptHoverEvents
- setAcceptTouchEvents
- setAcceptedMouseButtons
- setActive
- setBoundingRegionGranularity
- setCacheMode
- setCursor
- setData
- setEnabled
- setFiltersChildEvents
- setFlag
- setFlags
- setFocus
- setFocusProxy
- setGraphicsEffect
- setGroup
- setHandlesChildEvents
- setInputMethodHints
- setOpacity
- setPanelModality
- setParentItem
- setPos
- setRotation
- setScale
- setSelected
- setToolTip
- setTransform
- setTransformOriginPoint
- setTransformations
- setVisible
- setX
- setY
- setZValue
- show
- stackBefore
- toGraphicsObject
- toolTip
- topLevelItem
- topLevelWidget
- transform
- transformOriginPoint
- transformations
- ungrabKeyboard
- ungrabMouse
- unsetCursor
- update
- updateMicroFocus
- wheelEvent
- window
- x
- y
- zValue
- GraphicsItemFlag
- GraphicsItemChange
- CacheMode
- PanelModality
- Extension
- UserType