From ee859c4311a78e7dd67c25172fb7afa07aeec4d6 Mon Sep 17 00:00:00 2001 From: Joppe Blondel Date: Mon, 20 Jul 2026 12:45:47 +0200 Subject: [PATCH] Added new connection styles --- BEdit/AGENTS.md | 6 + BEdit/README.md | 4 +- BEdit/src/bedit/gui/controllers/document.py | 34 +++- .../src/bedit/gui/generated/ui_main_window.py | 46 ++++- .../bedit/gui/graphics/connection_styles.py | 25 +++ BEdit/src/bedit/gui/graphics/workspace.py | 184 +++++++++++++++++- BEdit/src/bedit/gui/main_window.py | 61 +++++- BEdit/test.bedit.json | 162 --------------- BEdit/ui/main_window.ui | 8 +- 9 files changed, 348 insertions(+), 182 deletions(-) create mode 100644 BEdit/src/bedit/gui/graphics/connection_styles.py delete mode 100644 BEdit/test.bedit.json diff --git a/BEdit/AGENTS.md b/BEdit/AGENTS.md index 8b41c1d..322e6d0 100644 --- a/BEdit/AGENTS.md +++ b/BEdit/AGENTS.md @@ -60,6 +60,12 @@ Keep the root of `src/bedit` minimal. New UI modules should go into the relevant - Port removal or reorientation must be rejected when it would invalidate an existing connection. - Connections reference port IDs, never port names. +- Graph interaction has separate Pointer and Connect modes. Connections store a + `properties.routing` value (`direct`, `angled`, or `spline`); angled routes + store absolute scene points in `properties.waypoints`. +- Connection appearance is configured per port type in + `gui/graphics/connection_styles.py`, including color, width, pen style, and + source/target arrowheads. Do not scatter those constants through painters. - Icon editing uses a fixed 128×128 coordinate space. - The visible/selectable component hitbox is calculated from vector elements, not from the complete 128×128 icon canvas. diff --git a/BEdit/README.md b/BEdit/README.md index ef2c599..1262b35 100644 --- a/BEdit/README.md +++ b/BEdit/README.md @@ -110,7 +110,9 @@ BEdit document used as a copy source. The built-in example defines A, B, and C. - Components, interface terminals, and connections are selectable. Use a rubber band or Ctrl-click for multiple selection, Delete to remove items, and the standard Cut/Copy/Paste shortcuts to duplicate selected component groups. -- Click an output port and then an input port to create a connection. +- Switch the graph header to **Connect**, choose Direct, Angled, or Spline, then + click an output and input. Angled connections accept intermediate corner + clicks; right-click cancels an unfinished connection. - Double-click a graph component to open its owned subgraph; use **Up** to return. - Graph components show **Pointer**, **Input**, and **Output** tools. Select an interface tool and click the canvas to add a visible internal terminal and a diff --git a/BEdit/src/bedit/gui/controllers/document.py b/BEdit/src/bedit/gui/controllers/document.py index a588dc0..1abc7c2 100644 --- a/BEdit/src/bedit/gui/controllers/document.py +++ b/BEdit/src/bedit/gui/controllers/document.py @@ -225,7 +225,14 @@ class DocumentController(QObject): RotateComponentsCommand(self, self.active_component_id, rotations) ) - def connect(self, source: Endpoint, target: Endpoint) -> str: + def connect( + self, + source: Endpoint, + target: Endpoint, + *, + routing: str = "spline", + waypoints: list[QPointF] | None = None, + ) -> str: if self.active_component_id is None: raise ValueError("There is no active graph") source_port = self._port_for_endpoint(source, "source") @@ -236,7 +243,19 @@ class DocumentController(QObject): raise ValueError( f"Cannot connect {source_port.type!r} to {target_port.type!r}" ) - connection = Connection(str(uuid4()), source, target) + if routing not in {"direct", "angled", "spline"}: + raise ValueError(f"Unknown connection routing: {routing}") + connection = Connection( + str(uuid4()), + source, + target, + properties={ + "routing": routing, + "waypoints": [ + {"x": point.x(), "y": point.y()} for point in (waypoints or []) + ], + }, + ) self.undo_stack.push( AddConnectionCommand(self, self.active_component_id, connection) ) @@ -255,6 +274,10 @@ class DocumentController(QObject): ports = component.outputs if role == "source" else component.inputs return next((port for port in ports if port.id == (endpoint.interface or endpoint.port)), None) + def connection_port_type(self, connection: Connection) -> str: + port = self._port_for_endpoint(connection.source, "source") + return port.type if port is not None else "signal" + def add_interface_port(self, direction: str, position: QPointF) -> str: component = self.active_component if component is None or component.implementation_kind != "graph": @@ -489,10 +512,17 @@ class DocumentController(QObject): for source in source_connections: if source.source.block not in id_map or source.target.block not in id_map: continue + properties = deepcopy(source.properties) + for point in properties.get("waypoints", []): + if isinstance(point, dict): + point["x"] = float(point.get("x", 0)) + offset.x() + point["y"] = float(point.get("y", 0)) + offset.y() connection = Connection( id=str(uuid4()), source=Endpoint(block=id_map[source.source.block], port=source.source.port), target=Endpoint(block=id_map[source.target.block], port=source.target.port), + name=source.name, + properties=properties, ) connections[connection.id] = connection if blocks: diff --git a/BEdit/src/bedit/gui/generated/ui_main_window.py b/BEdit/src/bedit/gui/generated/ui_main_window.py index cd1895b..73f09c7 100644 --- a/BEdit/src/bedit/gui/generated/ui_main_window.py +++ b/BEdit/src/bedit/gui/generated/ui_main_window.py @@ -182,6 +182,12 @@ class Ui_MainWindow(object): self.workspaceHeaderLayout.addWidget(self.navigateUpButton) + self.navigateDownButton = QToolButton(self.workspaceHeader) + self.navigateDownButton.setObjectName(u"navigateDownButton") + self.navigateDownButton.setEnabled(False) + + self.workspaceHeaderLayout.addWidget(self.navigateDownButton) + self.graphBreadcrumbLabel = QLabel(self.workspaceHeader) self.graphBreadcrumbLabel.setObjectName(u"graphBreadcrumbLabel") @@ -206,10 +212,39 @@ class Ui_MainWindow(object): self.pointerToolButton.setObjectName(u"pointerToolButton") self.pointerToolButton.setCheckable(True) self.pointerToolButton.setChecked(True) - self.pointerToolButton.setAutoExclusive(True) self.workspaceHeaderLayout.addWidget(self.pointerToolButton) + self.connectToolButton = QToolButton(self.workspaceHeader) + self.connectToolButton.setObjectName(u"connectToolButton") + self.connectToolButton.setCheckable(True) + + self.workspaceHeaderLayout.addWidget(self.connectToolButton) + + self.routingLabel = QLabel(self.workspaceHeader) + self.routingLabel.setObjectName(u"routingLabel") + + self.workspaceHeaderLayout.addWidget(self.routingLabel) + + self.directRoutingButton = QToolButton(self.workspaceHeader) + self.directRoutingButton.setObjectName(u"directRoutingButton") + self.directRoutingButton.setCheckable(True) + + self.workspaceHeaderLayout.addWidget(self.directRoutingButton) + + self.angledRoutingButton = QToolButton(self.workspaceHeader) + self.angledRoutingButton.setObjectName(u"angledRoutingButton") + self.angledRoutingButton.setCheckable(True) + + self.workspaceHeaderLayout.addWidget(self.angledRoutingButton) + + self.splineRoutingButton = QToolButton(self.workspaceHeader) + self.splineRoutingButton.setObjectName(u"splineRoutingButton") + self.splineRoutingButton.setCheckable(True) + self.splineRoutingButton.setChecked(True) + + self.workspaceHeaderLayout.addWidget(self.splineRoutingButton) + self.workspaceEditorLayout.addWidget(self.workspaceHeader) @@ -437,11 +472,20 @@ class Ui_MainWindow(object): self.navigateUpButton.setText(QCoreApplication.translate("MainWindow", u"Up", None)) #if QT_CONFIG(tooltip) self.navigateUpButton.setToolTip(QCoreApplication.translate("MainWindow", u"Open the containing graph", None)) +#endif // QT_CONFIG(tooltip) + self.navigateDownButton.setText(QCoreApplication.translate("MainWindow", u"Down", None)) +#if QT_CONFIG(tooltip) + self.navigateDownButton.setToolTip(QCoreApplication.translate("MainWindow", u"Open the selected block", None)) #endif // QT_CONFIG(tooltip) self.graphBreadcrumbLabel.setText(QCoreApplication.translate("MainWindow", u"Untitled", None)) self.workspaceModeLabel.setText(QCoreApplication.translate("MainWindow", u"Graph", None)) self.applyJsonButton.setText(QCoreApplication.translate("MainWindow", u"Apply JSON", None)) self.pointerToolButton.setText(QCoreApplication.translate("MainWindow", u"Pointer", None)) + self.connectToolButton.setText(QCoreApplication.translate("MainWindow", u"Connect", None)) + self.routingLabel.setText(QCoreApplication.translate("MainWindow", u"Line:", None)) + self.directRoutingButton.setText(QCoreApplication.translate("MainWindow", u"Direct", None)) + self.angledRoutingButton.setText(QCoreApplication.translate("MainWindow", u"Angled", None)) + self.splineRoutingButton.setText(QCoreApplication.translate("MainWindow", u"Spline", None)) self.jsonEditor.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Component JSON", None)) self.emptyWorkspaceLabel.setText(QCoreApplication.translate("MainWindow", u"No document open", None)) self.menuFile.setTitle(QCoreApplication.translate("MainWindow", u"&File", None)) diff --git a/BEdit/src/bedit/gui/graphics/connection_styles.py b/BEdit/src/bedit/gui/graphics/connection_styles.py new file mode 100644 index 0000000..1a16d11 --- /dev/null +++ b/BEdit/src/bedit/gui/graphics/connection_styles.py @@ -0,0 +1,25 @@ +from dataclasses import dataclass + +from PySide6.QtCore import Qt + + +@dataclass(frozen=True) +class ConnectionStyle: + color: str = "#285f9e" + selected_color: str = "#f59e0b" + width: float = 2.5 + selected_width: float = 4.0 + line_style: Qt.PenStyle = Qt.PenStyle.SolidLine + arrow_at_source: bool = False + arrow_at_target: bool = True + arrow_size: float = 10.0 + + +# This is the intentional code-level styling point for every port/connection type. +CONNECTION_STYLES: dict[str, ConnectionStyle] = { + "signal": ConnectionStyle(), +} + + +def connection_style(port_type: str) -> ConnectionStyle: + return CONNECTION_STYLES.get(port_type, ConnectionStyle()) diff --git a/BEdit/src/bedit/gui/graphics/workspace.py b/BEdit/src/bedit/gui/graphics/workspace.py index 398e377..eb0cf8e 100644 --- a/BEdit/src/bedit/gui/graphics/workspace.py +++ b/BEdit/src/bedit/gui/graphics/workspace.py @@ -10,6 +10,7 @@ from PySide6.QtGui import ( QPainter, QPainterPath, QPen, + QPolygonF, QTransform, ) from PySide6.QtWidgets import ( @@ -32,6 +33,7 @@ from bedit.core.model import Component, Connection, Endpoint, Port from bedit.gui.controllers.document import DocumentController from bedit.gui.models.library_tree import COMPONENT_MIME_TYPE from bedit.gui.graphics.icon_renderer import icon_bounds, paint_icon +from bedit.gui.graphics.connection_styles import ConnectionStyle, connection_style from bedit.gui.preferences import application_settings @@ -235,10 +237,20 @@ class InterfaceTerminalItem(QGraphicsObject): class ConnectionGraphicsItem(QGraphicsPathItem): - def __init__(self, connection_id: str, name: str = "") -> None: + def __init__( + self, + connection_id: str, + name: str = "", + style: ConnectionStyle | None = None, + ) -> None: super().__init__() self.connection_id = connection_id self.name = name + self.style = style or ConnectionStyle() + self.start = QPointF() + self.end = QPointF() + self.start_direction = QPointF(1, 0) + self.end_direction = QPointF(1, 0) self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable) self._update_pen() self.setZValue(-1) @@ -262,11 +274,40 @@ class ConnectionGraphicsItem(QGraphicsPathItem): def _update_pen(self) -> None: self.setPen( QPen( - QColor("#f59e0b") if self.isSelected() else QColor("#285f9e"), - 4.0 if self.isSelected() else 2.5, + QColor(self.style.selected_color if self.isSelected() else self.style.color), + self.style.selected_width if self.isSelected() else self.style.width, + self.style.line_style, ) ) + def set_connection_path( + self, + path: QPainterPath, + points: list[QPointF], + ) -> None: + self.setPath(path) + self.start, self.end = points[0], points[-1] + if len(points) > 1: + self.start_direction = points[1] - points[0] + self.end_direction = points[-1] - points[-2] + + @staticmethod + def _arrow(end: QPointF, direction: QPointF, size: float) -> QPolygonF: + length = max(0.001, (direction.x() ** 2 + direction.y() ** 2) ** 0.5) + unit = QPointF(direction.x() / length, direction.y() / length) + normal = QPointF(-unit.y(), unit.x()) + base = end - unit * size + return QPolygonF([end, base + normal * size * 0.45, base - normal * size * 0.45]) + + def paint(self, painter: QPainter, option, widget=None) -> None: + super().paint(painter, option, widget) + painter.setPen(Qt.PenStyle.NoPen) + painter.setBrush(self.pen().color()) + if self.style.arrow_at_target: + painter.drawPolygon(self._arrow(self.end, self.end_direction, self.style.arrow_size)) + if self.style.arrow_at_source: + painter.drawPolygon(self._arrow(self.start, -self.start_direction, self.style.arrow_size)) + class GraphScene(QGraphicsScene): componentOptionsRequested = Signal(str) @@ -282,6 +323,10 @@ class GraphScene(QGraphicsScene): self.output_items: dict[str, InterfaceTerminalItem] = {} self.connection_items: dict[str, ConnectionGraphicsItem] = {} self.pending_source: ConnectionPortItem | None = None + self.pending_waypoints: list[QPointF] = [] + self.pending_preview: QGraphicsPathItem | None = None + self.interaction_mode = "pointer" + self.connection_routing = "spline" self.setSceneRect(-2000, -2000, 4000, 4000) controller.documentReset.connect(self.rebuild) @@ -297,6 +342,8 @@ class GraphScene(QGraphicsScene): self.output_items.clear() self.connection_items.clear() self.pending_source = None + self.pending_waypoints.clear() + self.pending_preview = None owner = self.controller.active_component if owner is None or owner.implementation_kind != "graph": return @@ -316,7 +363,11 @@ class GraphScene(QGraphicsScene): item.setPos(component.x, component.y) self.component_items[component.id] = item for connection in owner.graph.connections.values(): - item = ConnectionGraphicsItem(connection.id, connection.name) + item = ConnectionGraphicsItem( + connection.id, + connection.name, + connection_style(self.controller.connection_port_type(connection)), + ) self.addItem(item) self.connection_items[connection.id] = item self.update_connection(connection.id) @@ -367,34 +418,115 @@ class GraphScene(QGraphicsScene): if source is None or target is None: return start, end = source.scenePos(), target.scenePos() - distance = max(50.0, abs(end.x() - start.x()) * 0.5) + routing = str(connection.properties.get("routing", "spline")) + waypoints = [ + QPointF(float(point["x"]), float(point["y"])) + for point in connection.properties.get("waypoints", []) + if isinstance(point, dict) and "x" in point and "y" in point + ] + path, direction_points = self._route_path(start, end, routing, waypoints) + graphics.set_connection_path(path, direction_points) + + @staticmethod + def _route_path( + start: QPointF, + end: QPointF, + routing: str, + waypoints: list[QPointF] | None = None, + ) -> tuple[QPainterPath, list[QPointF]]: + waypoints = waypoints or [] path = QPainterPath(start) - path.cubicTo(start + QPointF(distance, 0), end - QPointF(distance, 0), end) - graphics.setPath(path) + if routing == "angled": + points = [start, *waypoints, end] + for point in points[1:]: + path.lineTo(point) + return path, points + if routing == "direct": + path.lineTo(end) + return path, [start, end] + distance = max(50.0, abs(end.x() - start.x()) * 0.5) + first_control = start + QPointF(distance, 0) + second_control = end - QPointF(distance, 0) + path.cubicTo(first_control, second_control, end) + return path, [start, first_control, second_control, end] + + def set_interaction_mode(self, mode: str) -> None: + self.interaction_mode = mode + if mode != "connect": + self._clear_pending_source() + + def set_connection_routing(self, routing: str) -> None: + self.connection_routing = routing + self._clear_pending_source() def mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None: # noqa: N802 + if self.interaction_mode != "connect": + self._clear_pending_source() + super().mousePressEvent(event) + return + if event.button() == Qt.MouseButton.RightButton: + self._clear_pending_source() + event.accept() + return item = self.itemAt(event.scenePos(), QTransform()) if isinstance(item, ConnectionPortItem): if item.role == "source": self._clear_pending_source() self.pending_source = item + self.pending_waypoints = [] item.setBrush(QColor("#f5b642")) + self._create_preview() elif self.pending_source is not None: if self.pending_source.endpoint != item.endpoint: try: - self.controller.connect(self.pending_source.endpoint, item.endpoint) + self.controller.connect( + self.pending_source.endpoint, + item.endpoint, + routing=self.connection_routing, + waypoints=self.pending_waypoints, + ) except ValueError as error: QToolTip.showText(event.screenPos(), str(error)) self._clear_pending_source() event.accept() return - self._clear_pending_source() - super().mousePressEvent(event) + if self.pending_source is not None and self.connection_routing == "angled": + self.pending_waypoints.append(_snapped(event.scenePos())) + self._update_preview(event.scenePos()) + event.accept() + + def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None: # noqa: N802 + if self.interaction_mode == "connect" and self.pending_source is not None: + self._update_preview(event.scenePos()) + event.accept() + return + super().mouseMoveEvent(event) + + def _create_preview(self) -> None: + self.pending_preview = QGraphicsPathItem() + self.pending_preview.setPen(QPen(QColor("#64748b"), 1.5, Qt.PenStyle.DashLine)) + self.pending_preview.setZValue(-0.5) + self.addItem(self.pending_preview) + + def _update_preview(self, cursor: QPointF) -> None: + if self.pending_source is None or self.pending_preview is None: + return + path, _points = self._route_path( + self.pending_source.scenePos(), + cursor, + self.connection_routing, + self.pending_waypoints, + ) + self.pending_preview.setPath(path) def _clear_pending_source(self) -> None: if self.pending_source is not None: self.pending_source.setBrush(QColor("#ffffff")) + if self.pending_preview is not None: + self.removeItem(self.pending_preview) self.pending_source = None + self.pending_waypoints.clear() + self.pending_preview = None class GraphWorkspaceView(QGraphicsView): @@ -411,6 +543,7 @@ class GraphWorkspaceView(QGraphicsView): self.tool_mode = "pointer" self.paste_count = 0 self.setAcceptDrops(True) + self.setMouseTracking(True) self.setRenderHint(QPainter.RenderHint.Antialiasing) self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) self.setBackgroundBrush(QColor("#f7f7f7")) @@ -505,6 +638,29 @@ class GraphWorkspaceView(QGraphicsView): and any(isinstance(item, ComponentGraphicsItem) for item in scene.selectedItems()) ) + def has_single_selected_component(self) -> bool: + scene = self.scene() + return bool( + scene + and sum( + isinstance(item, ComponentGraphicsItem) for item in scene.selectedItems() + ) + == 1 + ) + + def open_selected_component(self) -> bool: + if self.controller is None or self.scene() is None: + return False + selected = [ + item + for item in self.scene().selectedItems() + if isinstance(item, ComponentGraphicsItem) + ] + if len(selected) != 1: + return False + self.controller.activate_component(selected[0].component_id) + return True + def rotate_selected(self) -> None: if self.controller is None or self.scene() is None: return @@ -578,6 +734,14 @@ class GraphWorkspaceView(QGraphicsView): if mode == "pointer" else QGraphicsView.DragMode.NoDrag ) + scene = self.scene() + if isinstance(scene, GraphScene): + scene.set_interaction_mode(mode) + + def set_connection_routing(self, routing: str) -> None: + scene = self.scene() + if isinstance(scene, GraphScene): + scene.set_connection_routing(routing) def mousePressEvent(self, event: QMouseEvent) -> None: # noqa: N802 super().mousePressEvent(event) diff --git a/BEdit/src/bedit/gui/main_window.py b/BEdit/src/bedit/gui/main_window.py index e136a2e..a843e3c 100644 --- a/BEdit/src/bedit/gui/main_window.py +++ b/BEdit/src/bedit/gui/main_window.py @@ -4,7 +4,7 @@ from pathlib import Path from PySide6.QtCore import Qt, Slot from PySide6.QtGui import QCloseEvent -from PySide6.QtWidgets import QFileDialog, QMainWindow, QMenu, QMessageBox +from PySide6.QtWidgets import QButtonGroup, QFileDialog, QMainWindow, QMenu, QMessageBox from bedit.core.model import Component, Port from bedit.core.serializer import JsonDocumentSerializer @@ -93,8 +93,31 @@ class MainWindow(QMainWindow): self.ui.graphView.selectionAvailabilityChanged.connect( lambda _available: self._update_edit_actions() ) + self.mode_button_group = QButtonGroup(self) + self.mode_button_group.setExclusive(True) + self.mode_button_group.addButton(self.ui.pointerToolButton) + self.mode_button_group.addButton(self.ui.connectToolButton) + self.routing_button_group = QButtonGroup(self) + self.routing_button_group.setExclusive(True) + for button in ( + self.ui.directRoutingButton, + self.ui.angledRoutingButton, + self.ui.splineRoutingButton, + ): + self.routing_button_group.addButton(button) self.ui.navigateUpButton.clicked.connect(self.navigate_up) + self.ui.navigateDownButton.clicked.connect(self.navigate_down) self.ui.pointerToolButton.clicked.connect(lambda: self.set_graph_tool("pointer")) + self.ui.connectToolButton.clicked.connect(lambda: self.set_graph_tool("connect")) + self.ui.directRoutingButton.clicked.connect( + lambda: self.set_connection_routing("direct") + ) + self.ui.angledRoutingButton.clicked.connect( + lambda: self.set_connection_routing("angled") + ) + self.ui.splineRoutingButton.clicked.connect( + lambda: self.set_connection_routing("spline") + ) self.ui.applyJsonButton.clicked.connect(self.apply_json) self.document_controller.activeGraphChanged.connect(self._active_graph_changed) @@ -173,7 +196,7 @@ class MainWindow(QMainWindow): self.ui.workspaceModeLabel.setText("") self.ui.workspaceStack.setCurrentWidget(self.ui.emptyPage) self.ui.applyJsonButton.setVisible(False) - self.ui.pointerToolButton.setVisible(False) + self._set_graph_controls_visible(False) self._update_edit_actions() return self.ui.graphBreadcrumbLabel.setText(" › ".join(self.document_controller.breadcrumb())) @@ -184,7 +207,7 @@ class MainWindow(QMainWindow): self.ui.workspaceModeLabel.setText("Graph" if is_graph else "Text") self.ui.workspaceStack.setCurrentWidget(self.ui.graphPage if is_graph else self.ui.jsonPage) self.ui.applyJsonButton.setVisible(not is_graph) - self.ui.pointerToolButton.setVisible(is_graph) + self._set_graph_controls_visible(is_graph) if is_graph: self.set_graph_tool("pointer") else: @@ -202,15 +225,43 @@ class MainWindow(QMainWindow): ) self.ui.actionSelectAll.setEnabled(is_graph) self.ui.actionPaste.setEnabled(is_graph) + self.ui.navigateDownButton.setEnabled( + is_graph and self.ui.graphView.has_single_selected_component() + ) @Slot() def navigate_up(self) -> None: if self._resolve_source_edits(): self.document_controller.navigate_up() + @Slot() + def navigate_down(self) -> None: + if self._resolve_source_edits(): + self.ui.graphView.open_selected_component() + + def _set_graph_controls_visible(self, visible: bool) -> None: + for widget in ( + self.ui.pointerToolButton, + self.ui.connectToolButton, + self.ui.routingLabel, + self.ui.directRoutingButton, + self.ui.angledRoutingButton, + self.ui.splineRoutingButton, + ): + widget.setVisible(visible) + def set_graph_tool(self, mode: str) -> None: - self.ui.graphView.set_tool_mode("pointer") - self.ui.pointerToolButton.setChecked(True) + self.ui.graphView.set_tool_mode(mode) + (self.ui.pointerToolButton if mode == "pointer" else self.ui.connectToolButton).setChecked(True) + + def set_connection_routing(self, routing: str) -> None: + self.ui.graphView.set_connection_routing(routing) + buttons = { + "direct": self.ui.directRoutingButton, + "angled": self.ui.angledRoutingButton, + "spline": self.ui.splineRoutingButton, + } + buttons[routing].setChecked(True) def _load_source_json(self) -> None: component = self.document_controller.active_component diff --git a/BEdit/test.bedit.json b/BEdit/test.bedit.json deleted file mode 100644 index 4f2e98f..0000000 --- a/BEdit/test.bedit.json +++ /dev/null @@ -1,162 +0,0 @@ -{ - "format": "bedit-document", - "version": 1, - "metadata": { - "name": "Untitled" - }, - "roots": [ - { - "id": "5ee742db-b25c-4d86-b4ca-cc0e61c4002a", - "name": "New Graph Block 1", - "position": { - "x": 0.0, - "y": 0.0 - }, - "rotation": 0.0, - "interface": { - "inputs": [], - "outputs": [] - }, - "icon": { - "shape": "rectangle", - "fill": "#f4f4f4", - "border": "#303030", - "text": "Graph", - "size": { - "width": 128.0, - "height": 128.0 - }, - "elements": [ - { - "type": "rectangle", - "x": 1.0, - "y": 1.0, - "width": 126.0, - "height": 126.0, - "fill": "#f4f4f4", - "stroke": "#303030", - "lineWidth": 1.5, - "lineStyle": "solid", - "cornerRadius": 5.0 - }, - { - "type": "text", - "x": 8.0, - "y": 8.0, - "width": 112.0, - "height": 112.0, - "text": "Graph", - "color": "#202020", - "fontSize": 12.0 - } - ] - }, - "properties": {}, - "library": { - "showSubtree": true - }, - "implementation": { - "kind": "graph", - "graph": { - "blocks": [ - { - "id": "89944479-e73e-446a-8d58-ebf35ac4144b", - "name": "New Graph Block 1", - "position": { - "x": 0.0, - "y": -64.0 - }, - "rotation": 0.0, - "interface": { - "inputs": [ - { - "id": "port-e5cb81a5", - "name": "Port 1", - "position": { - "x": 0.0, - "y": 0.0 - }, - "properties": { - "iconPosition": { - "x": 32.0, - "y": 64.0 - } - }, - "type": "signal" - } - ], - "outputs": [ - { - "id": "port-eb0034af", - "name": "Port 2", - "position": { - "x": 0.0, - "y": 0.0 - }, - "properties": { - "iconPosition": { - "x": 96.0, - "y": 64.0 - } - }, - "type": "signal" - } - ] - }, - "icon": { - "shape": "rectangle", - "fill": "#f4f4f4", - "border": "#303030", - "text": "Graph", - "size": { - "width": 128.0, - "height": 128.0 - }, - "elements": [ - { - "type": "rectangle", - "x": 32.0, - "y": 32.0, - "width": 64.0, - "height": 64.0, - "fill": "#f4f4f4", - "stroke": "#303030", - "lineWidth": 1.5, - "lineStyle": "solid", - "cornerRadius": 5.0 - }, - { - "type": "text", - "x": 40.0, - "y": 40.0, - "width": 48.0, - "height": 48.0, - "text": "Graph", - "color": "#303030", - "fontSize": 12.0, - "lineStyle": "solid", - "lineWidth": 1.5, - "stroke": "#303030", - "fill": "#ffffff" - } - ] - }, - "properties": {}, - "library": { - "showSubtree": true - }, - "implementation": { - "kind": "graph", - "graph": { - "blocks": [], - "connections": [] - } - } - } - ], - "connections": [] - } - } - } - ] -} diff --git a/BEdit/ui/main_window.ui b/BEdit/ui/main_window.ui index 6add917..af6d04a 100644 --- a/BEdit/ui/main_window.ui +++ b/BEdit/ui/main_window.ui @@ -144,11 +144,17 @@ 6 2 UpOpen the containing graph + DownOpen the selected blockfalse Untitled Graph Qt::Orientation::Horizontal4020 Apply JSONfalse - Pointertruetruetrue + Pointertruetrue + Connecttrue + Line: + Directtrue + Angledtrue + Splinetruetrue