Movable label for one component property — supports plain text and SVG modes. In SVG mode (a rendered LaTeX expression) the SVG is scaled to _LABEL_SVG_HEIGHT scene units tall; an optional prefix string is drawn as plain text immediately to the left. Freely draggable (no snap)
| 270 | |
| 271 | |
| 272 | class _PropertyLabel(QGraphicsItem): |
| 273 | """ |
| 274 | Movable label for one component property — supports plain text and SVG modes. |
| 275 | |
| 276 | In SVG mode (a rendered LaTeX expression) the SVG is scaled to |
| 277 | _LABEL_SVG_HEIGHT scene units tall; an optional prefix string is drawn |
| 278 | as plain text immediately to the left. |
| 279 | |
| 280 | Freely draggable (no snap) as a child of ComponentItem. |
| 281 | Counter-rotated by the parent so characters always stay upright. |
| 282 | """ |
| 283 | |
| 284 | def __init__(self, prop_key: str, parent: "ComponentItem"): |
| 285 | super().__init__(parent) |
| 286 | self.prop_key = prop_key |
| 287 | self._text: str = "" |
| 288 | self._svg_renderer: QSvgRenderer | None = None |
| 289 | self._svg_bytes: bytes = b"" # kept for SVG export |
| 290 | self._svg_rect: QRectF = QRectF() # scaled draw rect, centered at (0,0) |
| 291 | self._prefix: str = "" # plain text before the SVG |
| 292 | self._prefix_w: float = 0.0 # cached width of prefix string |
| 293 | self.setFlag(QGraphicsItem.ItemIsMovable) |
| 294 | self.setFlag(QGraphicsItem.ItemIsSelectable, False) |
| 295 | self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) |
| 296 | self.setAcceptedMouseButtons(Qt.LeftButton) |
| 297 | |
| 298 | def itemChange(self, change, value): |
| 299 | p = self.parentItem() |
| 300 | if p is not None: |
| 301 | if change == QGraphicsItem.ItemPositionChange: |
| 302 | p.prepareGeometryChange() |
| 303 | elif change == QGraphicsItem.ItemPositionHasChanged: |
| 304 | p.update() |
| 305 | return super().itemChange(change, value) |
| 306 | |
| 307 | def mousePressEvent(self, event): |
| 308 | p = self.parentItem() |
| 309 | if p is not None: |
| 310 | p._active_label_key = self.prop_key |
| 311 | p.setSelected(True) # so the leader shows as a selection cue |
| 312 | p.update() |
| 313 | super().mousePressEvent(event) |
| 314 | |
| 315 | def mouseReleaseEvent(self, event): |
| 316 | p = self.parentItem() |
| 317 | if p is not None: |
| 318 | p.update() |
| 319 | super().mouseReleaseEvent(event) |
| 320 | |
| 321 | # ── public setters ──────────────────────────────────────────────────────── |
| 322 | |
| 323 | def set_text(self, text: str) -> None: |
| 324 | self._text = text |
| 325 | self._svg_renderer = None |
| 326 | self._svg_bytes = b"" |
| 327 | self._svg_rect = QRectF() |
| 328 | self._prefix = "" |
| 329 | self._prefix_w = 0.0 |