diff --git a/capellambse_context_diagrams/collectors/default.py b/capellambse_context_diagrams/collectors/default.py index 0964e81..0c1c1b8 100644 --- a/capellambse_context_diagrams/collectors/default.py +++ b/capellambse_context_diagrams/collectors/default.py @@ -69,11 +69,7 @@ def process_context(self): box.children = [self.centerbox] del self.data.children[0] - stack_heights: dict[str, float | int] = { - "input": -makers.NEIGHBOR_VMARGIN, - "output": -makers.NEIGHBOR_VMARGIN, - } - self._process_ports(stack_heights) + self._process_ports() if self.diagram._display_parent_relation and self.diagram.target.owner: current = self.diagram.target.owner @@ -102,9 +98,6 @@ def process_context(self): ) generic.move_edges(owner_boxes, self.exchanges.values(), self.data) - self.centerbox.height = max( - self.centerbox.height, *stack_heights.values() - ) if self.diagram._hide_direct_children: self.centerbox.children = [] hidden = set(edge.id for edge in self.centerbox.edges) @@ -210,32 +203,46 @@ def _process_exchanges( except AttributeError: continue - for p in inc + out: + if not self.diagram._display_unused_ports: + ports = [ + p + for p in inc + out + if (inc_c.get(p.uuid) or out_c.get(p.uuid)) + ] + else: + ports = inc + out + + self.centerbox.height = max( + self.centerbox.height, + (makers.PORT_SIZE + 2 * makers.PORT_PADDING) * (len(ports) + 1), + ) + for p in ports: port = makers.make_port(p.uuid) if self.diagram._display_port_labels: port.labels = makers.make_label(p.name) + label_height = sum(label.height for label in port.labels) + self.centerbox.height += label_height self.centerbox.ports.append(port) self.centerbox.layoutOptions["portLabels.placement"] = "OUTSIDE" - return (inc + out), ex_datas + return ports, ex_datas - def _process_ports(self, stack_heights: dict[str, float | int]) -> None: + def _process_ports(self) -> None: ports, ex_datas = self._process_exchanges() - for owner, local_ports, side in port_context_collector( - ex_datas, ports - ): + for owner, local_ports in port_context_collector(ex_datas, ports): _, label_height = helpers.get_text_extent(owner.name) height = max( label_height + 2 * makers.LABEL_VPAD, - makers.PORT_PADDING - + (makers.PORT_SIZE + makers.PORT_PADDING) * len(local_ports), + (makers.PORT_SIZE + 2 * makers.PORT_PADDING) + * (len(local_ports) + 1), ) local_port_objs = [] for j in local_ports: port = makers.make_port(j.uuid) if self.diagram._display_port_labels: port.labels = makers.make_label(j.name) + height += sum(label.height for label in port.labels) local_port_objs.append(port) if box := self.global_boxes.get(owner.uuid): # type: ignore[assignment] @@ -264,8 +271,6 @@ def _process_ports(self, stack_heights: dict[str, float | int]) -> None: current = self._make_owner_box(self.diagram, current) self.common_owners.add(current.uuid) - stack_heights[side] += makers.NEIGHBOR_VMARGIN + height - def _make_box( self, obj: t.Any, @@ -401,8 +406,6 @@ class ContextInfo(t.NamedTuple): This list only contains ports that at least one of the exchanges passed into ``collect_exchanges`` sees. """ - side: t.Literal["input", "output"] - """Whether this is an input or output to the element of interest.""" def port_context_collector( @@ -428,7 +431,6 @@ def port_context_collector( """ ctx: dict[str, ContextInfo] = {} - side: t.Literal["input", "output"] for exd in exchange_datas: try: source, target = generic.collect_exchange_endpoints(exd) @@ -437,10 +439,8 @@ def port_context_collector( if source in local_ports: port = target - side = "output" elif target in local_ports: port = source - side = "input" else: continue @@ -449,7 +449,7 @@ def port_context_collector( except AttributeError: continue - info = ContextInfo(owner, [], side) + info = ContextInfo(owner, []) info = ctx.setdefault(owner.uuid, info) if port not in info.ports: info.ports.append(port) diff --git a/capellambse_context_diagrams/context.py b/capellambse_context_diagrams/context.py index ff18998..2e143da 100644 --- a/capellambse_context_diagrams/context.py +++ b/capellambse_context_diagrams/context.py @@ -251,6 +251,7 @@ class ContextDiagram(m.AbstractDiagram): [`PORT_LABEL_POSITION`][capellambse_context_diagrams.context._elkjs.PORT_LABEL_POSITION]. * hide_direct_children - Hide direct children of the object of interest. + * display_unused_ports - Display ports that are not connected to an edge. """ _display_symbols_as_boxes: bool @@ -261,6 +262,7 @@ class ContextDiagram(m.AbstractDiagram): _display_port_labels: bool _port_label_position: str _transparent_background: bool + _display_unused_ports: bool def __init__( self, @@ -288,6 +290,7 @@ def __init__( "display_port_labels": False, "port_label_position": _elkjs.PORT_LABEL_POSITION.OUTSIDE.name, "transparent_background": False, + "display_unused_ports": False, } | default_render_parameters if standard_filter := STANDARD_FILTERS.get(class_):