"""PortItem: a clickable, relation-colored connection anchor on a node.""" from __future__ import annotations from PyQt6.QtCore import QPointF, QRectF, Qt from PyQt6.QtGui import QBrush, QColor, QPen from PyQt6.QtWidgets import QGraphicsItem from ..model.port import Port PORT_RADIUS = 6.0 class PortItem(QGraphicsItem): """Rendered anchor for a single :class:`Port`, child of its NodeItem.""" def __init__(self, node_item, port: Port) -> None: super().__init__(node_item) self.node_item = node_item self.port = port self.setAcceptHoverEvents(True) self.setZValue(2) self._hover = False # Visual affordance flags set by the scene during an edge drag. self.compatible_hint = False self.setToolTip(f"{port.name} ({port.relation})") self.update_position() # -- geometry --------------------------------------------------------- def update_position(self) -> None: n = self.node_item.node lx, ly = self.port.local_point(n.width, n.height) self.setPos(lx, ly) def boundingRect(self) -> QRectF: r = PORT_RADIUS + 3 return QRectF(-r, -r, 2 * r, 2 * r) def scene_center(self) -> QPointF: return self.mapToScene(QPointF(0, 0)) def relation_color(self) -> QColor: reg = self.node_item.scene_relations() return QColor(reg.color(self.port.relation)) if reg else QColor("#888") # -- interaction ------------------------------------------------------ def hoverEnterEvent(self, event): self._hover = True self.update() super().hoverEnterEvent(event) def hoverLeaveEvent(self, event): self._hover = False self.update() super().hoverLeaveEvent(event) def set_compatible_hint(self, value: bool) -> None: if self.compatible_hint != value: self.compatible_hint = value self.update() # -- painting --------------------------------------------------------- def paint(self, painter, option, widget=None): color = self.relation_color() r = PORT_RADIUS if self._hover or self.compatible_hint: r = PORT_RADIUS + 2 painter.setRenderHint(painter.RenderHint.Antialiasing, True) pen = QPen(color.darker(140), 1.5) if self.compatible_hint: pen = QPen(QColor("#000000"), 2) painter.setPen(pen) fill = color.lighter(120) if self._hover else color painter.setBrush(QBrush(fill)) painter.drawEllipse(QPointF(0, 0), r, r)