labels
This commit is contained in:
@@ -23,6 +23,7 @@ from PySide6.QtWidgets import (
|
||||
QGraphicsScene,
|
||||
QGraphicsSceneContextMenuEvent,
|
||||
QGraphicsSceneMouseEvent,
|
||||
QGraphicsSimpleTextItem,
|
||||
QGraphicsView,
|
||||
QApplication,
|
||||
QMenu,
|
||||
@@ -78,6 +79,48 @@ class ConnectionPortItem(QGraphicsEllipseItem):
|
||||
self.setToolTip(label)
|
||||
|
||||
|
||||
class NameLabelItem(QGraphicsSimpleTextItem):
|
||||
"""Movable italic name label whose position is stored by its owner."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
text: str,
|
||||
owner_kind: str,
|
||||
owner_id: str,
|
||||
controller: DocumentController,
|
||||
parent: QGraphicsItem | None = None,
|
||||
) -> None:
|
||||
super().__init__(text, parent)
|
||||
self.owner_kind = owner_kind
|
||||
self.owner_id = owner_id
|
||||
self.controller = controller
|
||||
font = self.font()
|
||||
font.setItalic(True)
|
||||
self.setFont(font)
|
||||
self.setBrush(QColor("#303030"))
|
||||
self.setCursor(Qt.CursorShape.SizeAllCursor)
|
||||
self.drag_offset = QPointF()
|
||||
|
||||
def mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None: # noqa: N802
|
||||
parent = self.parentItem()
|
||||
point = parent.mapFromScene(event.scenePos()) if parent else event.scenePos()
|
||||
self.drag_offset = self.pos() - point
|
||||
event.accept()
|
||||
|
||||
def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None: # noqa: N802
|
||||
parent = self.parentItem()
|
||||
point = parent.mapFromScene(event.scenePos()) if parent else event.scenePos()
|
||||
self.setPos(_snapped(point + self.drag_offset))
|
||||
event.accept()
|
||||
|
||||
def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent) -> None: # noqa: N802
|
||||
if self.owner_kind == "component":
|
||||
self.controller.move_component_name_label(self.owner_id, self.pos())
|
||||
else:
|
||||
self.controller.move_connection_name_label(self.owner_id, self.pos())
|
||||
event.accept()
|
||||
|
||||
|
||||
class ComponentGraphicsItem(QGraphicsObject):
|
||||
WIDTH = 128.0
|
||||
HEIGHT = 128.0
|
||||
@@ -98,6 +141,31 @@ class ComponentGraphicsItem(QGraphicsObject):
|
||||
self.output_ports = self._create_ports(component.outputs, "source", self.WIDTH)
|
||||
self.setTransformOriginPoint(self.hitbox.center())
|
||||
self.setRotation(component.rotation)
|
||||
self.name_label: NameLabelItem | None = None
|
||||
self.sync_name_label(component)
|
||||
|
||||
def sync_name_label(self, component: Component) -> None:
|
||||
if component.properties.get("showName", False):
|
||||
if self.name_label is None:
|
||||
self.name_label = NameLabelItem(
|
||||
component.name, "component", component.id, self.controller, self
|
||||
)
|
||||
self.name_label.setText(component.name)
|
||||
position = component.properties.get("nameLabelPosition")
|
||||
if isinstance(position, dict):
|
||||
self.name_label.setPos(float(position["x"]), float(position["y"]))
|
||||
else:
|
||||
bounds = self.name_label.boundingRect()
|
||||
self.name_label.setPos(
|
||||
self.hitbox.center().x() - bounds.width() / 2,
|
||||
self.hitbox.bottom() + 6,
|
||||
)
|
||||
self.name_label.setRotation(-component.rotation)
|
||||
elif self.name_label is not None:
|
||||
if self.name_label.scene() is not None:
|
||||
self.name_label.setParentItem(None)
|
||||
self.name_label.scene().removeItem(self.name_label)
|
||||
self.name_label = None
|
||||
|
||||
def _create_ports(self, ports, role: str, x: float) -> dict[str, ConnectionPortItem]:
|
||||
result = {}
|
||||
@@ -255,13 +323,14 @@ class InterfaceTerminalItem(QGraphicsObject):
|
||||
class ConnectionGraphicsItem(QGraphicsPathItem):
|
||||
def __init__(
|
||||
self,
|
||||
connection_id: str,
|
||||
name: str = "",
|
||||
connection: Connection,
|
||||
controller: DocumentController,
|
||||
style: ConnectionStyle | None = None,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.connection_id = connection_id
|
||||
self.name = name
|
||||
self.connection_id = connection.id
|
||||
self.name = connection.name
|
||||
self.controller = controller
|
||||
self.style = style or ConnectionStyle()
|
||||
self.start = QPointF()
|
||||
self.end = QPointF()
|
||||
@@ -270,8 +339,34 @@ class ConnectionGraphicsItem(QGraphicsPathItem):
|
||||
self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable)
|
||||
self._update_pen()
|
||||
self.setZValue(0)
|
||||
self.setToolTip(name or "Connection")
|
||||
self.setToolTip(connection.name or "Connection")
|
||||
self.handles: list[WaypointHandle] = []
|
||||
self.name_label: NameLabelItem | None = None
|
||||
self.sync_name_label(connection)
|
||||
|
||||
def sync_name_label(self, connection: Connection) -> None:
|
||||
visible = bool(connection.properties.get("showName", False))
|
||||
if not visible:
|
||||
if self.name_label is not None and self.name_label.scene() is not None:
|
||||
self.name_label.setParentItem(None)
|
||||
self.name_label.scene().removeItem(self.name_label)
|
||||
self.name_label = None
|
||||
return
|
||||
if self.name_label is None:
|
||||
self.name_label = NameLabelItem(
|
||||
connection.name, "connection", connection.id, self.controller, self
|
||||
)
|
||||
self.name_label.setText(connection.name)
|
||||
position = connection.properties.get("nameLabelPosition")
|
||||
if isinstance(position, dict):
|
||||
self.name_label.setPos(float(position["x"]), float(position["y"]))
|
||||
elif not self.path().isEmpty():
|
||||
bounds = self.path().boundingRect()
|
||||
label_bounds = self.name_label.boundingRect()
|
||||
self.name_label.setPos(
|
||||
bounds.center().x() - label_bounds.width() / 2,
|
||||
bounds.bottom() + 6,
|
||||
)
|
||||
|
||||
def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None: # noqa: N802
|
||||
if not self.isSelected():
|
||||
@@ -318,6 +413,10 @@ class ConnectionGraphicsItem(QGraphicsPathItem):
|
||||
if len(points) > 1:
|
||||
self.start_direction = points[1] - points[0]
|
||||
self.end_direction = points[-1] - points[-2]
|
||||
if self.name_label is not None:
|
||||
connection = self.controller.active_graph.connections.get(self.connection_id)
|
||||
if connection is not None:
|
||||
self.sync_name_label(connection)
|
||||
|
||||
def set_waypoints(self, points: list[QPointF]) -> None:
|
||||
for handle in self.handles:
|
||||
@@ -713,6 +812,7 @@ class GraphScene(QGraphicsScene):
|
||||
controller.activeGraphChanged.connect(self.rebuild)
|
||||
controller.componentMoved.connect(self.set_component_position)
|
||||
controller.componentRotated.connect(self.set_component_rotation)
|
||||
controller.componentPropertiesChanged.connect(self.refresh_component_properties)
|
||||
controller.graphItemChanged.connect(self.refresh_graph_item)
|
||||
self.rebuild()
|
||||
|
||||
@@ -746,8 +846,8 @@ class GraphScene(QGraphicsScene):
|
||||
self.component_items[component.id] = item
|
||||
for connection in owner.graph.connections.values():
|
||||
item = ConnectionGraphicsItem(
|
||||
connection.id,
|
||||
connection.name,
|
||||
connection,
|
||||
self.controller,
|
||||
connection_style(self.controller.connection_port_type(connection)),
|
||||
)
|
||||
self.addItem(item)
|
||||
@@ -774,10 +874,22 @@ class GraphScene(QGraphicsScene):
|
||||
item = self.component_items.get(component_id)
|
||||
if item is not None:
|
||||
item.setRotation(rotation)
|
||||
if item.name_label is not None:
|
||||
item.name_label.setRotation(-rotation)
|
||||
self.update_connections_for_block(component_id)
|
||||
|
||||
def refresh_component_properties(self, component_id: str) -> None:
|
||||
component = (
|
||||
self.controller.document.find_component(component_id)
|
||||
if self.controller.document
|
||||
else None
|
||||
)
|
||||
item = self.component_items.get(component_id)
|
||||
if component is not None and item is not None:
|
||||
item.sync_name_label(component)
|
||||
|
||||
def refresh_graph_item(self, item_kind: str, item_id: str) -> None:
|
||||
if item_kind == "connection":
|
||||
if item_kind in {"connection", "connection_data"}:
|
||||
self.update_connection(item_id)
|
||||
return
|
||||
annotation = self.controller.active_graph.annotations.get(item_id)
|
||||
@@ -908,6 +1020,7 @@ class GraphScene(QGraphicsScene):
|
||||
start, end = geometry
|
||||
path, direction_points = self._route_path(start, end, waypoints)
|
||||
graphics.set_connection_path(path, direction_points)
|
||||
graphics.sync_name_label(connection)
|
||||
graphics.set_waypoints(waypoints)
|
||||
|
||||
def update_annotation(self, annotation_id: str) -> None:
|
||||
|
||||
Reference in New Issue
Block a user