This commit is contained in:
2026-08-17 13:03:29 +02:00
parent 4591e6b7b0
commit a61c8e6003
6 changed files with 204 additions and 7 deletions

View File

@@ -0,0 +1,24 @@
from copy import deepcopy
from PySide6.QtGui import QUndoCommand
from bedit_core.models import ComponentID
from bedit_gui.models import GraphComponentLabel
class ChangeGraphComponentLabelCommand(QUndoCommand):
def __init__(self, document: object, graph_id: ComponentID, component_id: ComponentID, label: GraphComponentLabel, text: str) -> None:
super().__init__(text)
self.document = document
self.graph_id = graph_id
self.component_id = component_id
database = document._graph_database(False)
graph = database.graphs.get(graph_id) if database is not None else None
self.old_label = deepcopy(graph.component_labels.get(component_id)) if graph is not None and component_id in graph.component_labels else None
self.new_label = deepcopy(label)
def redo(self) -> None:
self.document._set_graph_component_label(self.graph_id, self.component_id, self.new_label)
def undo(self) -> None:
self.document._set_graph_component_label(self.graph_id, self.component_id, self.old_label)

View File

@@ -9,7 +9,7 @@ from PySide6.QtWidgets import QAbstractItemView, QDialog, QHeaderView, QMenu
from bedit_core.models import Component, ComponentID, ConnectionID, EquationImplementation, GraphImplementation, Port, PortID, Parameter, ParameterID from bedit_core.models import Component, ComponentID, ConnectionID, EquationImplementation, GraphImplementation, Port, PortID, Parameter, ParameterID
from bedit_core.models import Document as CoreDocument from bedit_core.models import Document as CoreDocument
from bedit_gui.documents import Document from bedit_gui.documents import Document
from bedit_gui.models import Graph, Icon from bedit_gui.models import Graph, GraphComponentLabel, Icon
from bedit_gui.views.dialogs.interface_editor_dialog import InterfaceEditorDialog from bedit_gui.views.dialogs.interface_editor_dialog import InterfaceEditorDialog
from bedit_gui.views.dialogs.param_editor_dialog import ParamEditorDialog from bedit_gui.views.dialogs.param_editor_dialog import ParamEditorDialog
from bedit_gui.views.icon_editor_window import IconEditorWindow from bedit_gui.views.icon_editor_window import IconEditorWindow
@@ -63,11 +63,13 @@ class DocumentTreeController(QObject):
document.model_changed.connect(self._on_document_changed) document.model_changed.connect(self._on_document_changed)
document.icon_changed.connect(self._on_icon_changed) document.icon_changed.connect(self._on_icon_changed)
document.graph_component_position_changed.connect(self._on_graph_component_position_changed) document.graph_component_position_changed.connect(self._on_graph_component_position_changed)
document.graph_component_label_changed.connect(self._on_graph_component_label_changed)
document.graph_connection_points_changed.connect(self._on_graph_connection_points_changed) document.graph_connection_points_changed.connect(self._on_graph_connection_points_changed)
document.equation_text_changed.connect(self._on_equation_text_changed) document.equation_text_changed.connect(self._on_equation_text_changed)
self.model.rename_document_requested.connect(self.document.rename) self.model.rename_document_requested.connect(self.document.rename)
self.model.rename_component_requested.connect(self.document.rename_component) self.model.rename_component_requested.connect(self.document.rename_component)
window.graph_editor.component_move_requested.connect(self.document.move_graph_component) window.graph_editor.component_move_requested.connect(self.document.move_graph_component)
window.graph_editor.component_label_move_requested.connect(self.document.move_graph_component_label)
window.graph_editor.component_context_menu_requested.connect(self._show_graph_component_context_menu) window.graph_editor.component_context_menu_requested.connect(self._show_graph_component_context_menu)
window.graph_editor.component_open_requested.connect(self._open_graph_component) window.graph_editor.component_open_requested.connect(self._open_graph_component)
window.graph_editor.connection_points_change_requested.connect(self.document.change_graph_connection_points) window.graph_editor.connection_points_change_requested.connect(self.document.change_graph_connection_points)
@@ -155,6 +157,11 @@ class DocumentTreeController(QObject):
if graph_component is not None and self.document.component_id(graph_component) == graph_id: if graph_component is not None and self.document.component_id(graph_component) == graph_id:
self.window.graph_editor.set_component_position(component_id, position) self.window.graph_editor.set_component_position(component_id, position)
def _on_graph_component_label_changed(self, graph_id: ComponentID, component_id: ComponentID, label: object) -> None:
graph_component = self.window.graph_editor.component()
if graph_component is not None and self.document.component_id(graph_component) == graph_id:
self.window.graph_editor.set_component_label(component_id, label if isinstance(label, GraphComponentLabel) else None)
def _on_graph_connection_points_changed(self, graph_id: ComponentID, connection_id: ConnectionID, points: list[tuple[int, int]] | None) -> None: def _on_graph_connection_points_changed(self, graph_id: ComponentID, connection_id: ConnectionID, points: list[tuple[int, int]] | None) -> None:
graph_component = self.window.graph_editor.component() graph_component = self.window.graph_editor.component()
if graph_component is not None and self.document.component_id(graph_component) == graph_id: if graph_component is not None and self.document.component_id(graph_component) == graph_id:
@@ -177,7 +184,7 @@ class DocumentTreeController(QObject):
def _show_graph_component_context_menu(self, component_id: ComponentID, global_position: QPoint) -> None: def _show_graph_component_context_menu(self, component_id: ComponentID, global_position: QPoint) -> None:
component = self._components.get(component_id) component = self._components.get(component_id)
if component is not None: if component is not None:
self._show_component_context_menu(component, global_position) self._show_component_context_menu(component, global_position, component_id)
def _open_graph_component(self, component_id: ComponentID) -> None: def _open_graph_component(self, component_id: ComponentID) -> None:
index = self.model.component_index(component_id) index = self.model.component_index(component_id)
@@ -185,11 +192,16 @@ class DocumentTreeController(QObject):
self.window.ui.documentTree.selectionModel().setCurrentIndex(index, QItemSelectionModel.SelectionFlag.ClearAndSelect | QItemSelectionModel.SelectionFlag.Rows) self.window.ui.documentTree.selectionModel().setCurrentIndex(index, QItemSelectionModel.SelectionFlag.ClearAndSelect | QItemSelectionModel.SelectionFlag.Rows)
self.window.ui.documentTree.scrollTo(index) self.window.ui.documentTree.scrollTo(index)
def _show_component_context_menu(self, component: Component, global_position: QPoint) -> None: def _show_component_context_menu(self, component: Component, global_position: QPoint, graph_component_id: ComponentID | None = None) -> None:
menu = QMenu(self.window.ui.documentTree) menu = QMenu(self.window.ui.documentTree)
edit_interface = menu.addAction("Edit Interface") edit_interface = menu.addAction("Edit Interface")
edit_params = menu.addAction("Edit Parameters") edit_params = menu.addAction("Edit Parameters")
edit_icon = menu.addAction("Edit Icon") edit_icon = menu.addAction("Edit Icon")
show_label = None
if graph_component_id is not None:
show_label = menu.addAction("Show Label")
show_label.setCheckable(True)
show_label.setChecked(self.window.graph_editor.component_label_visible(graph_component_id))
menu.addSeparator() menu.addSeparator()
add_graph_component = None add_graph_component = None
add_equation_component = None add_equation_component = None
@@ -205,6 +217,10 @@ class DocumentTreeController(QObject):
self._edit_params(component) self._edit_params(component)
elif selected is edit_icon: elif selected is edit_icon:
self._edit_icon(component) self._edit_icon(component)
elif show_label is not None and selected is show_label:
graph_component = self.window.graph_editor.component()
if graph_component is not None:
self.document.set_graph_component_label_visible(graph_component, graph_component_id, show_label.isChecked())
elif add_graph_component is not None and selected is add_graph_component: elif add_graph_component is not None and selected is add_graph_component:
self._add_graph_component(component) self._add_graph_component(component)
elif add_equation_component is not None and selected is add_equation_component: elif add_equation_component is not None and selected is add_equation_component:

View File

@@ -15,13 +15,14 @@ from bedit_gui.commands.equation_text_command import ChangeEquationTextCommand
from bedit_gui.commands.graph_position_command import MoveGraphComponentCommand from bedit_gui.commands.graph_position_command import MoveGraphComponentCommand
from bedit_gui.commands.graph_connection_points_command import ChangeGraphConnectionPointsCommand from bedit_gui.commands.graph_connection_points_command import ChangeGraphConnectionPointsCommand
from bedit_gui.commands.graph_connection_command import AddGraphConnectionCommand, DeleteGraphConnectionCommand from bedit_gui.commands.graph_connection_command import AddGraphConnectionCommand, DeleteGraphConnectionCommand
from bedit_gui.commands.graph_label_command import ChangeGraphComponentLabelCommand
from bedit_gui.commands.port_commands import AddPortCommand, ChangePortCommand, RemovePortCommand from bedit_gui.commands.port_commands import AddPortCommand, ChangePortCommand, RemovePortCommand
from bedit_gui.commands.param_commands import AddParamCommand, ChangeParamCommand, RemoveParamCommand from bedit_gui.commands.param_commands import AddParamCommand, ChangeParamCommand, RemoveParamCommand
from bedit_gui.commands.rename_component_command import RenameComponentCommand from bedit_gui.commands.rename_component_command import RenameComponentCommand
from bedit_gui.commands.rename_document_command import RenameDocumentCommand from bedit_gui.commands.rename_document_command import RenameDocumentCommand
from bedit_gui.commands.simulation_database_command import ChangeSimulationDatabaseCommand from bedit_gui.commands.simulation_database_command import ChangeSimulationDatabaseCommand
from bedit_gui.commands.component_command import AddEmptyEquationComponent, AddEmptyGraphComponent, DeleteComponent, PasteComponents from bedit_gui.commands.component_command import AddEmptyEquationComponent, AddEmptyGraphComponent, DeleteComponent, PasteComponents
from bedit_gui.models import Graph, GraphConnection, GraphDatabase, Icon, IconDatabase, Simulation, SimulationDatabase from bedit_gui.models import Graph, GraphComponentLabel, GraphConnection, GraphDatabase, Icon, IconDatabase, Simulation, SimulationDatabase
from bedit_gui.services import document_files from bedit_gui.services import document_files
@@ -35,6 +36,7 @@ class Document(QObject):
equation_text_changed = Signal(object, str) equation_text_changed = Signal(object, str)
simulation_database_changed = Signal(object) simulation_database_changed = Signal(object)
graph_component_position_changed = Signal(object, object, object) graph_component_position_changed = Signal(object, object, object)
graph_component_label_changed = Signal(object, object, object)
graph_connection_points_changed = Signal(object, object, object) graph_connection_points_changed = Signal(object, object, object)
def __init__(self, parent: QObject | None = None) -> None: def __init__(self, parent: QObject | None = None) -> None:
@@ -157,6 +159,36 @@ class Document(QObject):
graph.component_positions[component_id] = position graph.component_positions[component_id] = position
self.graph_component_position_changed.emit(graph_id, component_id, position) self.graph_component_position_changed.emit(graph_id, component_id, position)
def move_graph_component_label(self, graph_component: Component, component_id: ComponentID, relative_position: tuple[int, int]) -> None:
graph_id = self.component_id(graph_component)
database = self._graph_database(False)
graph = database.graphs.get(graph_id) if database is not None else None
current = deepcopy(graph.component_labels.get(component_id)) if graph is not None and component_id in graph.component_labels else GraphComponentLabel()
if current.relative_position != relative_position:
current.relative_position = relative_position
self.undo_stack.push(ChangeGraphComponentLabelCommand(self, graph_id, component_id, current, "Move component label"))
def set_graph_component_label_visible(self, graph_component: Component, component_id: ComponentID, visible: bool) -> None:
graph_id = self.component_id(graph_component)
database = self._graph_database(False)
graph = database.graphs.get(graph_id) if database is not None else None
current = deepcopy(graph.component_labels.get(component_id)) if graph is not None and component_id in graph.component_labels else GraphComponentLabel()
if current.visible != visible:
current.visible = visible
self.undo_stack.push(ChangeGraphComponentLabelCommand(self, graph_id, component_id, current, "Show component label" if visible else "Hide component label"))
def _set_graph_component_label(self, graph_id: ComponentID, component_id: ComponentID, label: GraphComponentLabel | None) -> None:
if label is None:
database = self._graph_database(False)
graph = database.graphs.get(graph_id) if database is not None else None
if graph is not None:
graph.component_labels.pop(component_id, None)
else:
database = self._graph_database(True)
graph = database.graphs.setdefault(graph_id, Graph())
graph.component_labels[component_id] = deepcopy(label)
self.graph_component_label_changed.emit(graph_id, component_id, deepcopy(label))
def _graph_database(self, create: bool) -> GraphDatabase | None: def _graph_database(self, create: bool) -> GraphDatabase | None:
metadata = self.model.metadata metadata = self.model.metadata
value = metadata.get("graph_database") if metadata is not None else None value = metadata.get("graph_database") if metadata is not None else None

View File

@@ -134,23 +134,39 @@ class GraphConnection:
def to_data(self) -> dict[str, Any]: def to_data(self) -> dict[str, Any]:
return {"points": [list(point) for point in self.points]} return {"points": [list(point) for point in self.points]}
@dataclass
class GraphComponentLabel:
relative_position: tuple[int, int] = (0, 8)
visible: bool = True
@classmethod
def from_data(cls, data: Mapping[str, Any]) -> GraphComponentLabel:
position = data.get("relative_position", [0, 8])
return cls(relative_position=(int(position[0]), int(position[1])), visible=bool(data.get("visible", True)))
def to_data(self) -> dict[str, Any]:
return {"relative_position": list(self.relative_position), "visible": self.visible}
@dataclass @dataclass
class Graph: class Graph:
shapes: dict[ShapeID, Shape] = field(default_factory=dict) shapes: dict[ShapeID, Shape] = field(default_factory=dict)
component_positions: dict[ComponentID, tuple[int, int]] = field(default_factory=dict) component_positions: dict[ComponentID, tuple[int, int]] = field(default_factory=dict)
connections: dict[ConnectionID, GraphConnection] = field(default_factory=dict) connections: dict[ConnectionID, GraphConnection] = field(default_factory=dict)
component_labels: dict[ComponentID, GraphComponentLabel] = field(default_factory=dict)
@classmethod @classmethod
def from_data(cls, data: Mapping[str, Any]) -> Graph: def from_data(cls, data: Mapping[str, Any]) -> Graph:
shapes = {ShapeID(key): Shape.from_data(value) for key, value in data.get("shapes", {}).items()} shapes = {ShapeID(key): Shape.from_data(value) for key, value in data.get("shapes", {}).items()}
component_positions = {ComponentID(key): (int(value[0]), int(value[1])) for key, value in data.get("component_positions", {}).items()} component_positions = {ComponentID(key): (int(value[0]), int(value[1])) for key, value in data.get("component_positions", {}).items()}
component_labels = {ComponentID(key): GraphComponentLabel.from_data(value) for key, value in data.get("component_labels", {}).items()}
connections = {ConnectionID(key): GraphConnection.from_data(value) for key, value in data.get("connections", {}).items()} connections = {ConnectionID(key): GraphConnection.from_data(value) for key, value in data.get("connections", {}).items()}
return cls(shapes=shapes, component_positions=component_positions, connections=connections) return cls(shapes=shapes, component_positions=component_positions, component_labels=component_labels, connections=connections)
def to_data(self) -> dict[str, Any]: def to_data(self) -> dict[str, Any]:
return { return {
"shapes": {str(key): shape.to_data() for key, shape in self.shapes.items()}, "shapes": {str(key): shape.to_data() for key, shape in self.shapes.items()},
"component_positions": {str(key): list(position) for key, position in self.component_positions.items()}, "component_positions": {str(key): list(position) for key, position in self.component_positions.items()},
"component_labels": {str(key): label.to_data() for key, label in self.component_labels.items()},
"connections": {str(key): connection.to_data() for key, connection in self.connections.items()}, "connections": {str(key): connection.to_data() for key, connection in self.connections.items()},
} }

View File

@@ -6,10 +6,10 @@ from math import hypot
from PySide6.QtCore import QEvent, QObject, QPointF, QRectF, QSize, QTimer, Qt, Signal from PySide6.QtCore import QEvent, QObject, QPointF, QRectF, QSize, QTimer, Qt, Signal
from PySide6.QtGui import QActionGroup, QBrush, QColor, QCursor, QKeySequence, QMouseEvent, QPainter, QPainterPath, QPen, QShortcut, QWheelEvent from PySide6.QtGui import QActionGroup, QBrush, QColor, QCursor, QKeySequence, QMouseEvent, QPainter, QPainterPath, QPen, QShortcut, QWheelEvent
from PySide6.QtWidgets import QGraphicsEllipseItem, QGraphicsItem, QGraphicsPathItem, QGraphicsPixmapItem, QGraphicsScene, QGraphicsSceneMouseEvent, QGraphicsView, QMenu, QWidget from PySide6.QtWidgets import QGraphicsEllipseItem, QGraphicsItem, QGraphicsPathItem, QGraphicsPixmapItem, QGraphicsScene, QGraphicsSceneMouseEvent, QGraphicsTextItem, QGraphicsView, QMenu, QWidget
from bedit_core.models import BondCausality, BondConnection, BondPort, Component, ComponentID, Connection, ConnectionID, GraphImplementation, Port, PortID, SignalConnection, SignalDirection, SignalPort from bedit_core.models import BondCausality, BondConnection, BondPort, Component, ComponentID, Connection, ConnectionID, GraphImplementation, Port, PortID, SignalConnection, SignalDirection, SignalPort
from bedit_gui.models import Graph, GraphConnection, Icon from bedit_gui.models import Graph, GraphComponentLabel, GraphConnection, Icon
from bedit_gui.ui.generated.ui_graph_editor_widget import Ui_graphEditorWidget from bedit_gui.ui.generated.ui_graph_editor_widget import Ui_graphEditorWidget
from bedit_gui.utils.icon import get_pixmap_bounding_box, render_icon from bedit_gui.utils.icon import get_pixmap_bounding_box, render_icon
@@ -20,6 +20,7 @@ MAX_ZOOM = 4.0
ZOOM_STEP = 1.15 ZOOM_STEP = 1.15
ZOOM_TO_FIT_PADDING = 32.0 ZOOM_TO_FIT_PADDING = 32.0
COMPONENT_ICON_SIZE = QSize(128, 128) COMPONENT_ICON_SIZE = QSize(128, 128)
COMPONENT_LABEL_FONT_SIZE = 24.0
FALLBACK_COMPONENT_SPACING = 128 FALLBACK_COMPONENT_SPACING = 128
CONNECTION_WIDTH = 4.0 CONNECTION_WIDTH = 4.0
CONNECTION_BOUNDING_BOX_SPACING = 16.0 CONNECTION_BOUNDING_BOX_SPACING = 16.0
@@ -184,6 +185,58 @@ class GraphComponentItem(QGraphicsPixmapItem):
event.accept() event.accept()
class GraphComponentLabelItem(QGraphicsTextItem):
def __init__(self, component_id: ComponentID, text: str, label: GraphComponentLabel, component_item: GraphComponentItem, editor: GraphEditorWidget) -> None:
super().__init__(text, component_item)
self.component_id = component_id
self.editor = editor
self._dragging = False
self._drag_start = label.relative_position
font = self.font()
font.setItalic(True)
font.setPointSizeF(COMPONENT_LABEL_FONT_SIZE)
self.setFont(font)
self.setDefaultTextColor(QColor("#202020"))
self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable)
self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable, editor.mode is GraphEditorMode.NORMAL)
self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemSendsGeometryChanges)
self.set_relative_position(label.relative_position)
def relative_position(self) -> tuple[int, int]:
component_bounds = self.editor._component_bounds[self.component_id]
return round(self.pos().x() + self.boundingRect().width() / 2), round(self.pos().y() - component_bounds.bottom())
def set_relative_position(self, position: tuple[int, int]) -> None:
component_bounds = self.editor._component_bounds[self.component_id]
self.setPos(position[0] - self.boundingRect().width() / 2, component_bounds.bottom() + position[1])
def itemChange(self, change: QGraphicsItem.GraphicsItemChange, value: object) -> object:
if change == QGraphicsItem.GraphicsItemChange.ItemPositionChange and self._dragging and isinstance(value, QPointF):
component_bounds = self.editor._component_bounds[self.component_id]
size = self.editor.snap_to_grid_size
relative_x = value.x() + self.boundingRect().width() / 2
relative_y = value.y() - component_bounds.bottom()
value = QPointF(round(relative_x / size) * size - self.boundingRect().width() / 2, component_bounds.bottom() + round(relative_y / size) * size)
return super().itemChange(change, value)
def mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None:
self._drag_start = self.relative_position()
self._dragging = True
super().mousePressEvent(event)
def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent) -> None:
super().mouseReleaseEvent(event)
self._dragging = False
position = self.relative_position()
self.set_relative_position(position)
if position != self._drag_start:
self.editor.finish_component_label_move(self.component_id, position)
def contextMenuEvent(self, event) -> None:
self.editor.component_context_menu_requested.emit(self.component_id, event.screenPos())
event.accept()
class GraphConnectionPointItem(QGraphicsEllipseItem): class GraphConnectionPointItem(QGraphicsEllipseItem):
def __init__(self, connection_id: ConnectionID, index: int, position: tuple[int, int], editor: GraphEditorWidget) -> None: def __init__(self, connection_id: ConnectionID, index: int, position: tuple[int, int], editor: GraphEditorWidget) -> None:
radius = CONNECTION_WIDTH radius = CONNECTION_WIDTH
@@ -234,6 +287,7 @@ class GraphEditorWidget(QWidget):
component_move_requested = Signal(object, object, object) component_move_requested = Signal(object, object, object)
component_context_menu_requested = Signal(object, object) component_context_menu_requested = Signal(object, object)
component_open_requested = Signal(object) component_open_requested = Signal(object)
component_label_move_requested = Signal(object, object, object)
connection_points_change_requested = Signal(object, object, object, str) connection_points_change_requested = Signal(object, object, object, str)
connection_add_requested = Signal(object, object) connection_add_requested = Signal(object, object)
connections_delete_requested = Signal(object, object) connections_delete_requested = Signal(object, object)
@@ -251,6 +305,7 @@ class GraphEditorWidget(QWidget):
self._connection_preview: QGraphicsPathItem | None = None self._connection_preview: QGraphicsPathItem | None = None
self._component_items: dict[ComponentID, GraphComponentItem] = {} self._component_items: dict[ComponentID, GraphComponentItem] = {}
self._component_bounds: dict[ComponentID, QRectF] = {} self._component_bounds: dict[ComponentID, QRectF] = {}
self._component_label_items: dict[ComponentID, GraphComponentLabelItem] = {}
self._connection_items: dict[ConnectionID, GraphConnectionItem] = {} self._connection_items: dict[ConnectionID, GraphConnectionItem] = {}
self._connection_point_items: dict[ConnectionID, list[GraphConnectionPointItem]] = {} self._connection_point_items: dict[ConnectionID, list[GraphConnectionPointItem]] = {}
self.set_snap_to_grid_size(snap_to_grid_size) self.set_snap_to_grid_size(snap_to_grid_size)
@@ -310,6 +365,7 @@ class GraphEditorWidget(QWidget):
self._icons = icons or {} self._icons = icons or {}
self._component_items = {} self._component_items = {}
self._component_bounds = {} self._component_bounds = {}
self._component_label_items = {}
self._connection_items = {} self._connection_items = {}
self._connection_point_items = {} self._connection_point_items = {}
self.scene.clear() self.scene.clear()
@@ -331,6 +387,11 @@ class GraphEditorWidget(QWidget):
self._component_bounds[component_id] = bounds.translated(-pixmap.width() / 2, -pixmap.height() / 2) self._component_bounds[component_id] = bounds.translated(-pixmap.width() / 2, -pixmap.height() / 2)
self.scene.addItem(item) self.scene.addItem(item)
for component_id, child in component.implementation.graph.components.items():
label = graph.component_labels.get(component_id, GraphComponentLabel())
if label.visible:
self._create_component_label_item(component_id, child.name, label)
for connection_id, connection in component.implementation.graph.connections.items(): for connection_id, connection in component.implementation.graph.connections.items():
if not isinstance(connection, (SignalConnection, BondConnection)): if not isinstance(connection, (SignalConnection, BondConnection)):
continue continue
@@ -459,6 +520,31 @@ class GraphEditorWidget(QWidget):
if self._component is not None: if self._component is not None:
self.component_move_requested.emit(self._component, component_id, position) self.component_move_requested.emit(self._component, component_id, position)
def finish_component_label_move(self, component_id: ComponentID, relative_position: tuple[int, int]) -> None:
if self._component is not None:
self.component_label_move_requested.emit(self._component, component_id, relative_position)
def component_label_visible(self, component_id: ComponentID) -> bool:
return self._graph.component_labels.get(component_id, GraphComponentLabel()).visible
def set_component_label(self, component_id: ComponentID, label: GraphComponentLabel | None) -> None:
if label is None:
self._graph.component_labels.pop(component_id, None)
label = GraphComponentLabel()
else:
self._graph.component_labels[component_id] = label
item = self._component_label_items.pop(component_id, None)
if item is not None:
item.setParentItem(None)
self.scene.removeItem(item)
component = self._component
if component is not None and label.visible and component_id in component.implementation.graph.components:
self._create_component_label_item(component_id, component.implementation.graph.components[component_id].name, label)
def _create_component_label_item(self, component_id: ComponentID, text: str, label: GraphComponentLabel) -> None:
item = GraphComponentLabelItem(component_id, text, label, self._component_items[component_id], self)
self._component_label_items[component_id] = item
def set_component_position(self, component_id: ComponentID, position: tuple[int, int] | None) -> None: def set_component_position(self, component_id: ComponentID, position: tuple[int, int] | None) -> None:
item = self._component_items.get(component_id) item = self._component_items.get(component_id)
if item is None: if item is None:

View File

@@ -628,6 +628,29 @@
384 384
] ]
}, },
"component_labels": {
"43b3aee6-0b38-429b-9c6d-d38fc097297f": {
"relative_position": [
68,
-68
],
"visible": true
},
"9ee2f42b-5ed1-446d-8790-c2a1df6b61d3": {
"relative_position": [
0,
8
],
"visible": false
},
"9f392c28-6bef-4b10-9305-93e250747007": {
"relative_position": [
0,
8
],
"visible": false
}
},
"connections": { "connections": {
"7e293c73-1e07-4d4c-b750-6f43870c71c4": { "7e293c73-1e07-4d4c-b750-6f43870c71c4": {
"points": [ "points": [