Added array ports and junctions
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from PySide6.QtCore import QPointF
|
||||
from PySide6.QtGui import QUndoCommand
|
||||
|
||||
from bedit.core.model import Annotation, Component, Connection, Port
|
||||
from bedit.core.model import Annotation, Component, Connection, Junction, Port
|
||||
|
||||
|
||||
class AddComponentCommand(QUndoCommand):
|
||||
@@ -76,6 +76,32 @@ class AddConnectionCommand(QUndoCommand):
|
||||
self.controller._remove_connection(self.owner_id, self.connection.id)
|
||||
|
||||
|
||||
class SplitConnectionCommand(QUndoCommand):
|
||||
def __init__(
|
||||
self,
|
||||
controller,
|
||||
owner_id: str,
|
||||
original: Connection,
|
||||
junction: Junction,
|
||||
first: Connection,
|
||||
second: Connection,
|
||||
) -> None:
|
||||
super().__init__("Add connection junction")
|
||||
self.controller, self.owner_id = controller, owner_id
|
||||
self.original, self.junction = original, junction
|
||||
self.first, self.second = first, second
|
||||
|
||||
def redo(self) -> None:
|
||||
self.controller._split_connection(
|
||||
self.owner_id, self.original.id, self.junction, self.first, self.second
|
||||
)
|
||||
|
||||
def undo(self) -> None:
|
||||
self.controller._restore_split_connection(
|
||||
self.owner_id, self.original, self.junction.id, self.first.id, self.second.id
|
||||
)
|
||||
|
||||
|
||||
class AddAnnotationCommand(QUndoCommand):
|
||||
def __init__(self, controller, owner_id: str, annotation: Annotation) -> None:
|
||||
super().__init__(f"Draw {annotation.kind}")
|
||||
|
||||
@@ -23,6 +23,7 @@ from bedit.gui.controllers.commands import (
|
||||
RenameInterfacePortCommand,
|
||||
ReplaceSourceCommand,
|
||||
RotateComponentsCommand,
|
||||
SplitConnectionCommand,
|
||||
)
|
||||
from bedit.core.model import (
|
||||
Annotation,
|
||||
@@ -31,6 +32,7 @@ from bedit.core.model import (
|
||||
Endpoint,
|
||||
GraphDocument,
|
||||
Icon,
|
||||
Junction,
|
||||
Parameter,
|
||||
Port,
|
||||
clone_component,
|
||||
@@ -228,6 +230,20 @@ class DocumentController(QObject):
|
||||
MoveComponentCommand(self, self.active_component_id, component_id, old, new)
|
||||
)
|
||||
|
||||
def move_junction(self, junction_id: str, old: QPointF, new: QPointF) -> None:
|
||||
if old != new and self.active_component_id is not None:
|
||||
self.undo_stack.push(
|
||||
EditGraphItemCommand(
|
||||
self,
|
||||
self.active_component_id,
|
||||
"junction_geometry",
|
||||
junction_id,
|
||||
{"x": old.x(), "y": old.y()},
|
||||
{"x": new.x(), "y": new.y()},
|
||||
"Move connection junction",
|
||||
)
|
||||
)
|
||||
|
||||
def rotate_components(self, component_ids: set[str]) -> None:
|
||||
if self.active_component is None or self.active_component_id is None:
|
||||
return
|
||||
@@ -254,6 +270,14 @@ class DocumentController(QObject):
|
||||
raise ValueError("A connection endpoint no longer exists")
|
||||
if not PortTypeRegistry.compatible(source_port.type, target_port.type):
|
||||
raise ValueError(f"Cannot connect {source_port.type!r} to {target_port.type!r}")
|
||||
if not self.endpoint_accepts_connection(source, "source"):
|
||||
raise ValueError(
|
||||
f"Port {source_port.name!r} already has a connection; enable multiple connections first"
|
||||
)
|
||||
if not self.endpoint_accepts_connection(target, "target"):
|
||||
raise ValueError(
|
||||
f"Port {target_port.name!r} already has a connection; enable multiple connections first"
|
||||
)
|
||||
connection = Connection(
|
||||
str(uuid4()),
|
||||
source,
|
||||
@@ -265,6 +289,53 @@ class DocumentController(QObject):
|
||||
self.undo_stack.push(AddConnectionCommand(self, self.active_component_id, connection))
|
||||
return connection.id
|
||||
|
||||
def split_connection(
|
||||
self,
|
||||
connection_id: str,
|
||||
position: QPointF,
|
||||
first_waypoints: list[QPointF],
|
||||
second_waypoints: list[QPointF],
|
||||
) -> str:
|
||||
if self.active_component_id is None:
|
||||
raise ValueError("There is no active graph")
|
||||
original = self.active_graph.connections.get(connection_id)
|
||||
if original is None:
|
||||
raise ValueError("The connection no longer exists")
|
||||
port_type = self.connection_port_type(original)
|
||||
junction = Junction(str(uuid4()), position.x(), position.y(), port_type)
|
||||
first_properties = deepcopy(original.properties)
|
||||
first_properties["waypoints"] = [
|
||||
{"x": point.x(), "y": point.y()} for point in first_waypoints
|
||||
]
|
||||
second_properties = {
|
||||
"waypoints": [{"x": point.x(), "y": point.y()} for point in second_waypoints]
|
||||
}
|
||||
first = Connection(
|
||||
str(uuid4()),
|
||||
original.source,
|
||||
Endpoint(junction=junction.id),
|
||||
original.name,
|
||||
first_properties,
|
||||
)
|
||||
second = Connection(
|
||||
str(uuid4()),
|
||||
Endpoint(junction=junction.id),
|
||||
original.target,
|
||||
"",
|
||||
second_properties,
|
||||
)
|
||||
self.undo_stack.push(
|
||||
SplitConnectionCommand(
|
||||
self,
|
||||
self.active_component_id,
|
||||
original,
|
||||
junction,
|
||||
first,
|
||||
second,
|
||||
)
|
||||
)
|
||||
return junction.id
|
||||
|
||||
def add_annotation(
|
||||
self,
|
||||
kind: str,
|
||||
@@ -405,6 +476,16 @@ class DocumentController(QObject):
|
||||
owner = self.active_component
|
||||
if owner is None:
|
||||
return None
|
||||
if endpoint.junction is not None:
|
||||
junction = owner.graph.junctions.get(endpoint.junction)
|
||||
if junction is None:
|
||||
return None
|
||||
return Port(
|
||||
junction.id,
|
||||
"Junction",
|
||||
type=junction.type,
|
||||
allows_multiple_connections=role == "source",
|
||||
)
|
||||
if endpoint.interface is not None:
|
||||
ports = owner.inputs if role == "source" else owner.outputs
|
||||
else:
|
||||
@@ -420,6 +501,17 @@ class DocumentController(QObject):
|
||||
port = self._port_for_endpoint(connection.source, "source")
|
||||
return port.type if port is not None else "signal"
|
||||
|
||||
def endpoint_accepts_connection(self, endpoint: Endpoint, role: str) -> bool:
|
||||
port = self._port_for_endpoint(endpoint, role)
|
||||
if port is None:
|
||||
return False
|
||||
if role == "source" or port.allows_multiple_connections:
|
||||
return True
|
||||
return not any(
|
||||
endpoint == (connection.source if role == "source" else connection.target)
|
||||
for connection in self.active_graph.connections.values()
|
||||
)
|
||||
|
||||
def add_interface_port(self, direction: str, position: QPointF) -> str:
|
||||
component = self.active_component
|
||||
if component is None or component.implementation_kind != "graph":
|
||||
@@ -526,6 +618,12 @@ class DocumentController(QObject):
|
||||
},
|
||||
}
|
||||
if old != new:
|
||||
candidate = deepcopy(self.document)
|
||||
candidate_component = candidate.find_component(component.id)
|
||||
candidate_component.inputs = deepcopy(inputs)
|
||||
candidate_component.outputs = deepcopy(outputs)
|
||||
candidate_component.source = deepcopy(new["source"])
|
||||
candidate.validate()
|
||||
self.undo_stack.push(EditTextDefinitionCommand(self, component.id, old, new))
|
||||
|
||||
def edit_component_appearance(
|
||||
@@ -849,6 +947,36 @@ class DocumentController(QObject):
|
||||
self.connectionAdded.emit(connection.id)
|
||||
self.documentReset.emit()
|
||||
|
||||
def _split_connection(
|
||||
self,
|
||||
owner_id: str,
|
||||
original_id: str,
|
||||
junction: Junction,
|
||||
first: Connection,
|
||||
second: Connection,
|
||||
) -> None:
|
||||
graph = self._graph_for(owner_id)
|
||||
graph.connections.pop(original_id, None)
|
||||
graph.junctions[junction.id] = junction
|
||||
graph.connections[first.id] = first
|
||||
graph.connections[second.id] = second
|
||||
self.documentReset.emit()
|
||||
|
||||
def _restore_split_connection(
|
||||
self,
|
||||
owner_id: str,
|
||||
original: Connection,
|
||||
junction_id: str,
|
||||
first_id: str,
|
||||
second_id: str,
|
||||
) -> None:
|
||||
graph = self._graph_for(owner_id)
|
||||
graph.connections.pop(first_id, None)
|
||||
graph.connections.pop(second_id, None)
|
||||
graph.junctions.pop(junction_id, None)
|
||||
graph.connections[original.id] = original
|
||||
self.documentReset.emit()
|
||||
|
||||
def _remove_connection(self, owner_id: str, connection_id: str) -> None:
|
||||
self._graph_for(owner_id).connections.pop(connection_id, None)
|
||||
if owner_id == self.active_component_id:
|
||||
@@ -871,7 +999,11 @@ class DocumentController(QObject):
|
||||
self, owner_id: str, item_kind: str, item_id: str, values: dict
|
||||
) -> None:
|
||||
graph = self._graph_for(owner_id)
|
||||
if item_kind == "connection_data":
|
||||
if item_kind == "junction_geometry":
|
||||
item = graph.junctions.get(item_id)
|
||||
if item is not None:
|
||||
item.x, item.y = float(values["x"]), float(values["y"])
|
||||
elif item_kind == "connection_data":
|
||||
item = graph.connections.get(item_id)
|
||||
if item is not None:
|
||||
item.name = values["name"]
|
||||
|
||||
Reference in New Issue
Block a user