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 data(unknown):
rect
resizeHandleSize
resizing
resizeDirection
content
input_port
output_port
hovered
def setWidth(self, width):
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
def setHeight(self, height):
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
def boundingRect(self):
42    def boundingRect(self):
43        return self.rect
def paint(self, painter, option, widget):
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
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 mouseMoveEvent(self, event):
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)
def mouseReleaseEvent(self, event):
83    def mouseReleaseEvent(self, event):
84        if self.resizing:
85            self.resizing = False
86            self.setCursor(Qt.ArrowCursor)
87        else:
88            super().mouseReleaseEvent(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)
def hoverEnterEvent(self, event):
111    def hoverEnterEvent(self, event):
112        self.hovered = True
113        self.update()  # Trigger a repaint
114        super().hoverEnterEvent(event)
def hoverLeaveEvent(self, event):
116    def hoverLeaveEvent(self, event):
117        self.hovered = False
118        self.update()  # Trigger a repaint
119        super().hoverLeaveEvent(event)
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

Port(parent, position, port_type)
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 = []
port_type
edges
def mousePressEvent(self, event):
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)
def mouseMoveEvent(self, event):
136    def mouseMoveEvent(self, event):
137        if self.edges:
138            self.edges[-1].update_position(event.scenePos())
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