Further refactor connector node generation
This commit is contained in:
parent
77080c90a2
commit
738012911d
@ -178,13 +178,11 @@ class Harness:
|
||||
for connector in self.connectors.values():
|
||||
# generate connector node
|
||||
gv_html = gv_node_connector(connector, self.options)
|
||||
_default_fillcolor = translate_color(self.options.bgcolor_connector, "HEX")
|
||||
dot.node(
|
||||
connector.name,
|
||||
label=f"<\n{gv_html}\n>",
|
||||
shape="box",
|
||||
style="filled",
|
||||
fillcolor=_default_fillcolor,
|
||||
)
|
||||
# generate edges for connector loops
|
||||
if len(connector.loops) > 0:
|
||||
|
||||
@ -13,17 +13,22 @@ HEADER_PN = "P/N"
|
||||
HEADER_MPN = "MPN"
|
||||
HEADER_SPN = "SPN"
|
||||
|
||||
# TODO: remove harness argument; only used by get_additional_component_table()
|
||||
def gv_node_connector(connector: Connector, harness_options: Options) -> str:
|
||||
|
||||
def gv_node_connector(connector: Connector, harness_options: Options) -> Table:
|
||||
# If no wires connected (except maybe loop wires)?
|
||||
if not (connector.ports_left or connector.ports_right):
|
||||
connector.ports_left = True # Use left side pins by default
|
||||
|
||||
# generate all rows to be shown in the node
|
||||
if connector.show_name:
|
||||
row_name = [
|
||||
f"{html_bgcolor(connector.bgcolor_title)}{remove_links(connector.name)}"
|
||||
]
|
||||
str_name = [f"{remove_links(connector.name)}"]
|
||||
if connector.bgcolor_title:
|
||||
row_name_attribs = {
|
||||
"bgcolor": translate_color(connector.bgcolor_title, "HEX")
|
||||
}
|
||||
row_name = [Td(str_name, attribs=row_name_attribs)]
|
||||
else:
|
||||
row_name = [str_name]
|
||||
else:
|
||||
row_name = []
|
||||
|
||||
@ -34,16 +39,47 @@ def gv_node_connector(connector: Connector, harness_options: Options) -> str:
|
||||
]
|
||||
row_pn = [html_line_breaks(cell) for cell in row_pn]
|
||||
|
||||
if connector.color:
|
||||
colorbar_attribs = {
|
||||
"bgcolor": translate_color(connector.color, "HEX"),
|
||||
"width": 4,
|
||||
}
|
||||
colorbar_cell = Td("", attribs=colorbar_attribs)
|
||||
else:
|
||||
colorbar_cell = None
|
||||
|
||||
row_info = [
|
||||
html_line_breaks(connector.type),
|
||||
html_line_breaks(connector.subtype),
|
||||
f"{connector.pincount}-pin" if connector.show_pincount else None,
|
||||
translate_color(connector.color, harness_options.color_mode),
|
||||
html_colorbar(connector.color),
|
||||
colorbar_cell,
|
||||
]
|
||||
|
||||
row_image = [html_image(connector.image)]
|
||||
row_image_caption = [html_caption(connector.image)]
|
||||
# <tdX{' sides="TLR"' if image.caption else ''}
|
||||
# <tdX sides="BLR"{html_bgcolor_attr(image.bgcolor)}>
|
||||
# {html_size_attr(image)}
|
||||
if connector.image and connector.image.caption:
|
||||
# import pudb; pudb.set_trace()
|
||||
row_image_attribs = html_size_attr_dict(connector.image)
|
||||
row_image_attribs["balign"] = "left"
|
||||
row_image_attribs["sides"] = "TLR"
|
||||
if connector.image.bgcolor:
|
||||
row_image_attribs["bgcolor"] = translate_color(
|
||||
connector.image.bgcolor, "HEX"
|
||||
)
|
||||
row_caption_attribs = {"balign": "left", "sides": "BLR"}
|
||||
row_image = [Td(html_image_new(connector.image), attribs=row_image_attribs)]
|
||||
row_image_caption = [
|
||||
Td(
|
||||
html_caption_new(connector.image),
|
||||
attribs=row_caption_attribs,
|
||||
flat=True,
|
||||
)
|
||||
]
|
||||
else:
|
||||
row_image = []
|
||||
row_image_caption = []
|
||||
row_notes = [html_line_breaks(connector.notes)]
|
||||
# row_additional_component_table = get_additional_component_table(self, connector)
|
||||
row_additional_component_table = None
|
||||
@ -62,9 +98,12 @@ def gv_node_connector(connector: Connector, harness_options: Options) -> str:
|
||||
gv_pin_row(pinindex, pinname, pinlabel, pincolor, connector)
|
||||
)
|
||||
|
||||
table_attribs = Attribs(
|
||||
{"border": 0, "cellspacing": 0, "cellpadding": 3, "cellborder": 1}
|
||||
)
|
||||
table_attribs = {
|
||||
"border": 0,
|
||||
"cellspacing": 0,
|
||||
"cellpadding": 3,
|
||||
"cellborder": 1,
|
||||
}
|
||||
row_connector_table = str(Table(pin_rows, attribs=table_attribs))
|
||||
else:
|
||||
row_connector_table = None
|
||||
@ -80,19 +119,20 @@ def gv_node_connector(connector: Connector, harness_options: Options) -> str:
|
||||
row_notes,
|
||||
]
|
||||
|
||||
html = "\n".join(nested_html_table(rows, html_bgcolor_attr(connector.bgcolor)))
|
||||
tbl = nested_table(rows)
|
||||
|
||||
return html
|
||||
if connector.bgcolor:
|
||||
tbl.attribs["bgcolor"] = translate_color(connector.bgcolor, "HEX")
|
||||
elif harness_options.bgcolor_connector:
|
||||
tbl.attribs["bgcolor"] = translate_color(harness_options.bgcolor_connector, "HEX")
|
||||
|
||||
return tbl
|
||||
|
||||
|
||||
def gv_pin_row(pin_index, pin_name, pin_label, pin_color, connector):
|
||||
cell_pin_left = Td(
|
||||
pin_name, attribs=Attribs({"port": f"p{pin_index+1}l"}), flat=True
|
||||
)
|
||||
cell_pin_label = Td(pin_label, flat=True)
|
||||
cell_pin_right = Td(
|
||||
pin_name, attribs=Attribs({"port": f"p{pin_index+1}r"}), flat=True
|
||||
)
|
||||
cell_pin_left = Td(pin_name, attribs={"port": f"p{pin_index+1}l"}, flat=True)
|
||||
cell_pin_label = Td(pin_label, flat=True, empty_is_none=True)
|
||||
cell_pin_right = Td(pin_name, attribs={"port": f"p{pin_index+1}r"}, flat=True)
|
||||
|
||||
cells = [
|
||||
cell_pin_left if connector.ports_left else None,
|
||||
@ -119,6 +159,39 @@ def gv_connector_loops(connector: Connector) -> List:
|
||||
return loop_edges
|
||||
|
||||
|
||||
def nested_table(rows_in: List[Tr]):
|
||||
outer_rows = []
|
||||
for row in rows_in:
|
||||
if isinstance(row, List) and len(row) > 0 and any(row):
|
||||
# remove rows which are none
|
||||
row_no_empty = [cell for cell in row if cell is not None]
|
||||
inner_cells = []
|
||||
for cell in row_no_empty:
|
||||
if isinstance(cell, Td):
|
||||
inner_cells.append(cell)
|
||||
else:
|
||||
inner_cell_attribs = {"balign": "left"}
|
||||
inner_cells.append(Td(cell, attribs=inner_cell_attribs, flat=True))
|
||||
|
||||
inner_table_attribs = {
|
||||
"border": 0,
|
||||
"cellspacing": 0,
|
||||
"cellpadding": 3,
|
||||
"cellborder": 1,
|
||||
}
|
||||
if len(inner_cells) > 0:
|
||||
inner_table = Table(Tr(inner_cells), attribs=inner_table_attribs)
|
||||
outer_rows.append(Tr(Td(inner_table)))
|
||||
elif row is not None and any(row):
|
||||
outer_rows.append(Tr(Td(row)))
|
||||
if len(outer_rows) == 0:
|
||||
outer_rows = Tr(Td("")) # Generate empty cell to avoid GraphViz errors
|
||||
outer_table_attribs = {"border": 0, "cellspacing": 0, "cellpadding": 0}
|
||||
outer_table = Table(outer_rows, attribs=outer_table_attribs)
|
||||
|
||||
return outer_table
|
||||
|
||||
|
||||
def nested_html_table(
|
||||
rows: List[Union[str, List[Optional[str]], None]], table_attrs: str = ""
|
||||
) -> str:
|
||||
@ -193,6 +266,24 @@ def html_image(image):
|
||||
return f"""<tdX{' sides="TLR"' if image.caption else ''}{html_bgcolor_attr(image.bgcolor)}{html}"""
|
||||
|
||||
|
||||
def html_image_new(image):
|
||||
from wireviz.DataClasses import Image
|
||||
|
||||
if not image:
|
||||
return None
|
||||
# The leading attributes belong to the preceeding tag. See where used below.
|
||||
html = f'<img scale="{image.scale}" src="{image.src}"/>'
|
||||
if image.fixedsize:
|
||||
# Close the preceeding tag and enclose the image cell in a table without
|
||||
# borders to avoid narrow borders when the fixed width < the node width.
|
||||
html = f"""
|
||||
<table border="0" cellspacing="0" cellborder="0"><tr>
|
||||
<td>{html}</td>
|
||||
</tr></table>
|
||||
"""
|
||||
return f"{html_bgcolor_attr(image.bgcolor)}{html}"
|
||||
|
||||
|
||||
def html_caption(image):
|
||||
from wireviz.DataClasses import Image
|
||||
|
||||
@ -203,6 +294,12 @@ def html_caption(image):
|
||||
)
|
||||
|
||||
|
||||
def html_caption_new(image):
|
||||
from wireviz.DataClasses import Image
|
||||
|
||||
return f"{html_line_breaks(image.caption)}" if image and image.caption else None
|
||||
|
||||
|
||||
def html_size_attr(image):
|
||||
from wireviz.DataClasses import Image
|
||||
|
||||
@ -218,5 +315,20 @@ def html_size_attr(image):
|
||||
)
|
||||
|
||||
|
||||
def html_size_attr_dict(image):
|
||||
# Return Graphviz HTML attributes to specify minimum or fixed size of a TABLE or TD object
|
||||
from wireviz.DataClasses import Image
|
||||
|
||||
attr_dict = {}
|
||||
if image:
|
||||
if image.width:
|
||||
attr_dict["width"] = image.width
|
||||
if image.height:
|
||||
attr_dict["height"] = image.height
|
||||
if image.fixedsize:
|
||||
attr_dict["fixedsize"] = "true"
|
||||
return attr_dict
|
||||
|
||||
|
||||
def html_line_breaks(inp):
|
||||
return remove_links(inp).replace("\n", "<br />") if isinstance(inp, str) else inp
|
||||
|
||||
@ -24,13 +24,25 @@ class Tag:
|
||||
contents: str
|
||||
attribs: Attribs = field(default_factory=Attribs)
|
||||
flat: bool = False
|
||||
empty_is_none: bool = False
|
||||
|
||||
def __post_init__(self):
|
||||
if self.attribs is None:
|
||||
self.attribs = Attribs({})
|
||||
elif isinstance(self.attribs, Dict):
|
||||
self.attribs = Attribs(self.attribs)
|
||||
elif not isinstance(self.attribs, Attribs):
|
||||
raise Exception(
|
||||
"Tag.attribs must be of type None, Dict, or Attribs, "
|
||||
f"but type {type(self.attribs).__name__} was given instead:\n"
|
||||
f"{self.attribs}"
|
||||
)
|
||||
|
||||
@property
|
||||
def tagname(self):
|
||||
return type(self).__name__.lower()
|
||||
|
||||
def get_contents(self):
|
||||
# import pudb; pudb.set_trace()
|
||||
separator = "" if self.flat else "\n"
|
||||
if isinstance(self.contents, Iterable) and not isinstance(self.contents, str):
|
||||
return separator.join([str(c) for c in self.contents if c is not None])
|
||||
@ -41,18 +53,21 @@ class Tag:
|
||||
|
||||
def __repr__(self):
|
||||
separator = "" if self.flat else "\n"
|
||||
html = [
|
||||
f"<{self.tagname}{str(self.attribs)}>",
|
||||
self.get_contents(),
|
||||
f"</{self.tagname}>",
|
||||
]
|
||||
return separator.join(html)
|
||||
if self.contents is None and self.empty_is_none:
|
||||
return ""
|
||||
else:
|
||||
html = [
|
||||
f"<{self.tagname}{str(self.attribs)}>",
|
||||
self.get_contents(),
|
||||
f"</{self.tagname}>",
|
||||
]
|
||||
return separator.join(html)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TagSingleton(Tag):
|
||||
def __repr__(self):
|
||||
return f"<{self.tagname}{self.attribs} />"
|
||||
return f"<{self.tagname}{str(self.attribs)} />"
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user