This commit is contained in:
Daniel Rojas 2021-10-18 17:23:15 +02:00 committed by KV
parent f46bce6867
commit d65222953e
3 changed files with 130 additions and 108 deletions

View File

@ -138,9 +138,10 @@ class AdditionalComponent:
@dataclass @dataclass
class Component(): class Component:
pass pass
@dataclass @dataclass
class Connector(Component): class Connector(Component):
name: Designator name: Designator

View File

@ -4,7 +4,7 @@ import re
from itertools import zip_longest from itertools import zip_longest
from typing import List, Optional, Union from typing import List, Optional, Union
from wireviz.DataClasses import Cable, Color, Connector, Component, Options from wireviz.DataClasses import Cable, Color, Component, Connector, Options
from wireviz.wv_colors import get_color_hex, translate_color from wireviz.wv_colors import get_color_hex, translate_color
from wireviz.wv_helper import pn_info_string, remove_links from wireviz.wv_helper import pn_info_string, remove_links
from wireviz.wv_table_util import * # TODO: explicitly import each needed tag later from wireviz.wv_table_util import * # TODO: explicitly import each needed tag later
@ -14,7 +14,9 @@ HEADER_MPN = "MPN"
HEADER_SPN = "SPN" HEADER_SPN = "SPN"
def gv_node_component(component: Component, harness_options: Options, pad=None) -> Table: def gv_node_component(
component: Component, harness_options: Options, pad=None
) -> Table:
# If no wires connected (except maybe loop wires)? # If no wires connected (except maybe loop wires)?
if isinstance(component, Connector): if isinstance(component, Connector):
if not (component.ports_left or component.ports_right): if not (component.ports_left or component.ports_right):
@ -23,14 +25,14 @@ def gv_node_component(component: Component, harness_options: Options, pad=None)
# generate all rows to be shown in the node # generate all rows to be shown in the node
if component.show_name: if component.show_name:
str_name = f"{remove_links(component.name)}" str_name = f"{remove_links(component.name)}"
row_name = [colored_cell(str_name, component.bgcolor_title)] line_name = colored_cell(str_name, component.bgcolor_title)
else: else:
row_name = [] line_name = None
row_pn = par_number_cell_list(component) line_pn = part_number_str_list(component)
if isinstance(component, Connector): if isinstance(component, Connector):
row_info = [ line_info = [
html_line_breaks(component.type), html_line_breaks(component.type),
html_line_breaks(component.subtype), html_line_breaks(component.subtype),
f"{component.pincount}-pin" if component.show_pincount else None, f"{component.pincount}-pin" if component.show_pincount else None,
@ -38,22 +40,23 @@ def gv_node_component(component: Component, harness_options: Options, pad=None)
colorbar_cell(component.color), colorbar_cell(component.color),
] ]
elif isinstance(component, Cable): elif isinstance(component, Cable):
row_info = [ line_info = [
html_line_breaks(component.type), html_line_breaks(component.type),
f"{component.wirecount}x" if component.show_wirecount else None, f"{component.wirecount}x" if component.show_wirecount else None,
f"{component.gauge_str}" if component.gauge else None, f"{component.gauge_str}" if component.gauge else None,
"+ S" if component.shield else None, "+ S" if component.shield else None,
f"{component.length} {component.length_unit}" if component.length > 0 else None, f"{component.length} {component.length_unit}"
if component.length > 0
else None,
translate_color(component.color, harness_options.color_mode), translate_color(component.color, harness_options.color_mode),
colorbar_cell(component.color), colorbar_cell(component.color),
] ]
row_image, row_image_caption = image_and_caption_cells(component) line_image, line_image_caption = image_and_caption_cells(component)
# row_additional_component_table = get_additional_component_table(self, connector)
row_additional_component_table = None
row_notes = [html_line_breaks(component.notes)]
# line_additional_component_table = get_additional_component_table(self, connector)
line_additional_component_table = None
line_notes = [html_line_breaks(component.notes)]
if isinstance(component, Connector): if isinstance(component, Connector):
# pin table # pin table
@ -77,24 +80,26 @@ def gv_node_component(component: Component, harness_options: Options, pad=None)
"cellpadding": 3, "cellpadding": 3,
"cellborder": 1, "cellborder": 1,
} }
row_ports = str(Table(pin_rows, attribs=table_attribs)) line_ports = Table(pin_rows, attribs=table_attribs)
else: else:
row_ports = None line_ports = None
elif isinstance(component, Cable): elif isinstance(component, Cable):
row_ports = str(gv_conductor_table(component, harness_options, pad)) line_ports = gv_conductor_table(component, harness_options, pad)
rows = [ lines = [
row_name, line_name,
row_pn, line_pn,
row_info, line_info,
row_ports, line_ports,
row_image, line_image,
row_image_caption, line_image_caption,
row_additional_component_table, line_additional_component_table,
row_notes, line_notes,
] ]
tbl = nested_table(rows) cell_lists = [make_list_of_cells(line) for line in lines]
tbl = nested_table(cell_lists)
if component.bgcolor: if component.bgcolor:
tbl.attribs["bgcolor"] = translate_color(component.bgcolor, "HEX") tbl.attribs["bgcolor"] = translate_color(component.bgcolor, "HEX")
@ -108,10 +113,64 @@ def gv_node_component(component: Component, harness_options: Options, pad=None)
harness_options.bgcolor_cable, "HEX" harness_options.bgcolor_cable, "HEX"
) )
return tbl
def nested_table(cell_lists: List[Td]) -> Table:
outer_table_attribs = {
"border": 0,
"cellspacing": 0,
"cellpadding": 0,
}
inner_table_attribs = {
"border": 0,
"cellspacing": 0,
"cellpadding": 3,
"cellborder": 1,
}
rows = []
for lst in cell_lists:
if len(lst) == 0:
continue # no cells in list
cells = [item for item in lst if item.contents is not None]
if len(cells) == 0:
continue # no cells in list that are not None
if (
len(cells) == 1
and isinstance(cells[0].contents, Table)
and not "!" in cells[0].contents.attribs.get("id", "")
):
# cell content is already a table, no need to re-wrap it;
# unless explicitly asked to by a "!" in the ID field
# as used by image_and_caption_cells()
inner_table = cells[0].contents
else:
# nest cell content inside a table
inner_table = Table(Tr(cells), attribs=inner_table_attribs)
rows.append(Tr(Td(inner_table)))
if len(rows) == 0: # create dummy row to avoid GraphViz errors due to empty <table>
rows = Tr(Td(""))
tbl = Table(rows, attribs=outer_table_attribs)
return tbl return tbl
def make_list_of_cells(inp) -> List[Td]:
# inp may be List,
if isinstance(inp, List):
# ensure all list items are Td
list_out = [item if isinstance(item, Td) else Td(item) for item in inp]
return list_out
else:
if inp is None:
return []
if isinstance(inp, Td):
return [inp]
else:
return [Td(inp)]
def gv_pin_row(pin_index, pin_name, pin_label, pin_color, connector): def gv_pin_row(pin_index, pin_name, pin_label, pin_color, connector):
cell_pin_left = Td(pin_name, attribs={"port": f"p{pin_index+1}l"}) cell_pin_left = Td(pin_name, attribs={"port": f"p{pin_index+1}l"})
cell_pin_label = Td(pin_label, empty_is_none=True) cell_pin_label = Td(pin_label, empty_is_none=True)
@ -236,98 +295,58 @@ def colorbar_cell(color) -> Td:
# image_table = Table(Tr(Td(image_tag, attribs=html_size_attr_dict(image))), attribs={"border": 0, "cellspacing": 0, "cellborder": 0}) # image_table = Table(Tr(Td(image_tag, attribs=html_size_attr_dict(image))), attribs={"border": 0, "cellspacing": 0, "cellborder": 0})
# return image_table # return image_table
def image_and_caption_cells(component):
if component.image:
# outer_cell_attribs = {}
# outer_cell_attribs["balign"] = "left"
# outer_cell_attribs["bgcolor"] = translate_color(
# component.image.bgcolor, "HEX"
# )
# if component.image.caption:
# outer_cell_attribs["sides"] = "TLR"
image_tag = Img(attribs={"scale": component.image.scale, "src": component.image.src}) def image_and_caption_cells(component: Component) -> (Td, Td):
cell_attribs = html_size_attr_dict(component.image) if not component.image:
image_cell = Td(image_tag, attribs=cell_attribs)
image_row = Tr(image_cell)
image_table_attribs = {
"border": 0,
"cellspacing": 0,
"cellpadding": 0,
"cellborder": 1,
}
image_table = Table(image_row, attribs=image_table_attribs)
outer_cell = Td(image_table)
# return:
row_image = outer_cell
if component.image.caption:
row_caption_attribs = {"balign": "left", "sides": "BLR", "id": "td_caption"}
row_image_caption = Td(
html_caption_new(component.image),
attribs=row_caption_attribs,
)
else:
row_image_caption = None
return (row_image, row_image_caption)
else:
return (None, None) return (None, None)
image_tag = Img(
attribs={"scale": component.image.scale, "src": component.image.src}
)
image_cell_inner = Td(image_tag, flat=True)
if component.image.fixedsize:
# further nest the image in a table with width/height/fixedsize parameters, and place that table in a cell
inner_cell_attribs = html_size_attr_dict(component.image)
image_cell_inner.attribs = Attribs(inner_cell_attribs)
image_cell = Td(
Table(
Tr(image_cell_inner),
attribs={"border": 0, "cellspacing": 0, "cellborder": 0, "id": "!"},
)
)
else:
image_cell = image_cell_inner
def par_number_cell_list(component) -> List[Td]: outer_cell_attribs = {}
outer_cell_attribs["balign"] = "left"
if component.image.bgcolor:
outer_cell_attribs["bgcolor"] = translate_color(component.image.bgcolor, "HEX")
if component.image.caption:
outer_cell_attribs["sides"] = "TLR"
image_cell.attribs = Attribs(outer_cell_attribs)
if component.image.caption:
caption_cell_attribs = {"balign": "left", "sides": "BLR", "id": "td_caption"}
caption_cell = Td(
html_caption_new(component.image), attribs=caption_cell_attribs
)
else:
caption_cell = None
return (image_cell, caption_cell)
def part_number_str_list(component: Component) -> List[str]:
cell_contents = [ cell_contents = [
pn_info_string(HEADER_PN, None, component.pn), pn_info_string(HEADER_PN, None, component.pn),
pn_info_string(HEADER_MPN, component.manufacturer, component.mpn), pn_info_string(HEADER_MPN, component.manufacturer, component.mpn),
pn_info_string(HEADER_SPN, component.supplier, component.spn), pn_info_string(HEADER_SPN, component.supplier, component.spn),
] ]
if any(cell_contents): if any(cell_contents):
return [Td(html_line_breaks(cell)) for cell in cell_contents] return [html_line_breaks(cell) for cell in cell_contents]
else: else:
return None return None
def nested_table(rows_in: List[Tr]) -> Table:
outer_rows = []
for row in rows_in:
if isinstance(row, List) and len(row) > 0 and any(row):
# row is a nested list
# remove rows which are none
row_no_empty = [cell for cell in row if cell is not None]
# if row item is Td, append directly; else convert to Td
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))
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:
if isinstance(row, Iterable) and not any(row):
continue
# row is a single item
# if item is Td, append directly; else convert to Td
cell = row if isinstance(row, Td) else Td(row)
outer_rows.append(Tr(cell))
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 html_image(image): # def html_image(image):
# from wireviz.DataClasses import Image # from wireviz.DataClasses import Image
# if not image: # if not image:
@ -345,8 +364,6 @@ def nested_table(rows_in: List[Tr]) -> Table:
# return f"""<tdX{' sides="TLR"' if image.caption else ''}{html_bgcolor_attr(image.bgcolor)}{html}""" # return f"""<tdX{' sides="TLR"' if image.caption else ''}{html_bgcolor_attr(image.bgcolor)}{html}"""
def html_caption_new(image): def html_caption_new(image):
from wireviz.DataClasses import Image from wireviz.DataClasses import Image

View File

@ -71,6 +71,9 @@ class Tag:
return self.indent_lines(str(self.contents)) return self.indent_lines(str(self.contents))
def __repr__(self): def __repr__(self):
# if self.flat:
# import pudb; pudb.set_trace()
separator = "" if self.auto_flat else "\n" separator = "" if self.auto_flat else "\n"
if self.contents is None and self.empty_is_none: if self.contents is None and self.empty_is_none:
return "" return ""
@ -80,7 +83,8 @@ class Tag:
f"{self.get_contents()}", f"{self.get_contents()}",
f"</{self.tagname}>", f"</{self.tagname}>",
] ]
return separator.join(html) html_joined = separator.join(html)
return html_joined
@dataclass @dataclass