diff --git a/pySimBlocks/gui/blocks/operators/product.py b/pySimBlocks/gui/blocks/operators/product.py index 995e2e0..2326feb 100644 --- a/pySimBlocks/gui/blocks/operators/product.py +++ b/pySimBlocks/gui/blocks/operators/product.py @@ -91,7 +91,7 @@ def resolve_port_group( instance: "BlockInstance" ) -> list["PortInstance"]: - if direction == port_meta.name == "input": + if direction == "input" and port_meta.name == "in": operations_str = instance.parameters.get("operations", "") ports = [] for i, op in enumerate(operations_str): diff --git a/pySimBlocks/gui/graphics/block_item.py b/pySimBlocks/gui/graphics/block_item.py index 6aa6972..4f358c0 100644 --- a/pySimBlocks/gui/graphics/block_item.py +++ b/pySimBlocks/gui/graphics/block_item.py @@ -72,7 +72,6 @@ def __init__(self, # Ports self.port_items: list[PortItem] = [] - self.instance.resolve_ports() for port in self.instance.ports: item = PortItem(port, self) self.port_items.append(item) @@ -89,16 +88,23 @@ def get_port_item(self, name:str) -> PortItem | None: # -------------------------------------------------------------- def refresh_ports(self): - for item in self.port_items: - self.scene().removeItem(item) - self.port_items.clear() - self.instance.resolve_ports() + for item in list(self.port_items): + if item.instance not in self.instance.ports: + self.scene().removeItem(item) + self.port_items.remove(item) - for port in self.instance.ports: - self.port_items.append(PortItem(port, self)) + displayed_ports = {item.instance for item in self.port_items} + for port in self.instance.ports: + if port not in displayed_ports: + item = PortItem(port, self) + self.port_items.append(item) + self._layout_ports() + for item in self.port_items: + item.update_display_as() + self.view.on_block_moved(self) # -------------------------------------------------------------- def toggle_orientation(self): diff --git a/pySimBlocks/gui/graphics/port_item.py b/pySimBlocks/gui/graphics/port_item.py index 2ba761c..9941401 100644 --- a/pySimBlocks/gui/graphics/port_item.py +++ b/pySimBlocks/gui/graphics/port_item.py @@ -80,6 +80,10 @@ def update_label_position(self): self.y() - label_rect.height() / 2, ) + # -------------------------------------------------------------- + def update_display_as(self): + self.label.setPlainText(self.instance.display_as) + # -------------------------------------------------------------- def connection_anchor(self) -> QPointF: if self.is_input: diff --git a/pySimBlocks/gui/model/block_instance.py b/pySimBlocks/gui/model/block_instance.py index d10116a..6514063 100644 --- a/pySimBlocks/gui/model/block_instance.py +++ b/pySimBlocks/gui/model/block_instance.py @@ -74,70 +74,41 @@ def update_params(self, params: dict[str, Any]): self.parameters[k] = v def resolve_ports(self) -> None: - self.ports = self.meta.build_ports(self) - def active_parameters(self): + new_ports = self.meta.build_ports(self) + + if not self.ports: + self.ports = new_ports + return + + old_inputs = [p for p in self.ports if p.direction == "input"] + old_outputs = [p for p in self.ports if p.direction == "output"] + + updated_ports = [] + + for np in new_ports: + if np.direction == "input": + if old_inputs: + p = old_inputs.pop(0) + p.name = np.name + p.display_as = np.display_as + updated_ports.append(p) + else: + updated_ports.append(np) + else: + if old_outputs: + p = old_outputs.pop(0) + p.name = np.name + p.display_as = np.display_as + updated_ports.append(p) + else: + updated_ports.append(np) + + self.ports = updated_ports + + def active_parameters(self) -> dict[str, Any]: return { k: v for k, v in self.parameters.items() if self.meta.is_parameter_active(k, self.parameters) } - - """ - ports: List[PortInstance] = [] - - for direction in ("input", "output"): - for pmeta in self.meta.ports[f"{direction}s"]: - ports.extend(self._resolve_port_group(pmeta, direction)) - self.ports = ports - - def _resolve_port_group(self, pmeta: Dict[str, Dict[str, Any]], direction: Literal['input', 'output']) -> list[PortInstance]: - if not pmeta["dynamic"]: - return [PortInstance(pmeta["pattern"], direction, self, pmeta)] - - source = pmeta["source"] - pattern = pmeta["pattern"] - - if source["type"] == "parameter": - value = self.parameters.get(source["parameter"]) - - if value is None and "fallback" in pmeta: - value = self.parameters.get( - pmeta["fallback"]["parameter"], - pmeta["fallback"]["default"], - ) - return self._expand_ports(pattern, value, direction, pmeta) - - return [] - - def _expand_ports(self, - pattern: str, - value: Sized, - direction: Literal['input', 'output'], - meta: Dict[str, Dict[str, str]] - ) -> list[PortInstance]: - - ports: List[PortInstance] = [] - operation: str = meta["source"].get("operation", "") - - if operation == "len": - for i in range(1, len(value) + 1): - ports.append(PortInstance(pattern.format(val=i), direction, self, meta)) - - elif operation == "len + 1": - for i in range(1, len(value) + 2): - ports.append(PortInstance(pattern.format(val=i), direction, self, meta)) - - elif operation == "keys": - if value: - for key in value: - ports.append( - PortInstance(pattern.format(val=key), direction, self, meta) - ) - - elif operation == "value": - for i in range(1, int(value) + 1): - ports.append(PortInstance(pattern.format(val=i), direction, self, meta)) - - return ports - """ diff --git a/pySimBlocks/gui/project_controller.py b/pySimBlocks/gui/project_controller.py index e9ed2d2..60455a3 100644 --- a/pySimBlocks/gui/project_controller.py +++ b/pySimBlocks/gui/project_controller.py @@ -30,6 +30,7 @@ ConnectionInstance, PortInstance, ProjectState, + port_instance, ) from pySimBlocks.gui.widgets.diagram_view import DiagramView from pySimBlocks.gui.blocks.block_meta import BlockMeta @@ -74,7 +75,7 @@ def _add_block(self, block_instance: BlockInstance, block_layout: dict | None = None) -> BlockInstance: self.make_dirty() block_instance.name = self.make_unique_name(block_instance.name) - + block_instance.resolve_ports() self.project_state.add_block(block_instance) self.view.add_block(block_instance, block_layout) @@ -109,13 +110,15 @@ def rename_block(self, block_instance: BlockInstance, new_name: str): # ------------------------------------------------------------------ def update_block_param(self, block_instance: BlockInstance, params: dict[str, Any]): - old_params = copy.deepcopy(block_instance.parameters) + self.rename_block(block_instance, params.pop("name", block_instance.name)) - block_instance.update_params(params) - if old_params == block_instance.parameters: + if params == block_instance.parameters: return + block_instance.update_params(params) + block_instance.resolve_ports() + self._remove_connection_if_port_disapear(block_instance) self.view.refresh_block_port(block_instance) self.make_dirty() @@ -199,6 +202,17 @@ def add_connection(self, self.view.add_connection(connection_instance, points) self.make_dirty() + # ------------------------------------------------------------------ + + def _remove_connection_if_port_disapear(self, block_instance: BlockInstance) -> None: + + for connection in self.project_state.get_connections_of_block(block_instance): + + src_exists = connection.src_port in connection.src_block().ports + dst_exists = connection.dst_port in connection.dst_block().ports + if not (src_exists and dst_exists): + self.remove_connection(connection) + # ------------------------------------------------------------------ def remove_connection(self, connection: ConnectionInstance):