WIP
This commit is contained in:
parent
82b5cb710f
commit
f7359ff9b1
@ -33,6 +33,9 @@ from wireviz.wv_bom import (
|
||||
)
|
||||
from wireviz.wv_colors import get_color_hex, translate_color
|
||||
from wireviz.wv_gv_html import (
|
||||
gv_connector_loops,
|
||||
gv_node_connector,
|
||||
gv_pin,
|
||||
html_bgcolor,
|
||||
html_bgcolor_attr,
|
||||
html_caption,
|
||||
@ -174,102 +177,21 @@ class Harness:
|
||||
dot.attr("edge", style="bold", fontname=self.options.fontname)
|
||||
|
||||
for connector in self.connectors.values():
|
||||
|
||||
# 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.
|
||||
|
||||
html = []
|
||||
# fmt: off
|
||||
rows = [[f'{html_bgcolor(connector.bgcolor_title)}{remove_links(connector.name)}'
|
||||
if connector.show_name else None],
|
||||
[pn_info_string(HEADER_PN, None, remove_links(connector.pn)),
|
||||
html_line_breaks(pn_info_string(HEADER_MPN, connector.manufacturer, connector.mpn)),
|
||||
html_line_breaks(pn_info_string(HEADER_SPN, connector.supplier, connector.spn))],
|
||||
[html_line_breaks(connector.type),
|
||||
html_line_breaks(connector.subtype),
|
||||
f'{connector.pincount}-pin' if connector.show_pincount else None,
|
||||
translate_color(connector.color, self.options.color_mode) if connector.color else None,
|
||||
html_colorbar(connector.color)],
|
||||
'<!-- connector table -->' if connector.style != 'simple' else None,
|
||||
[html_image(connector.image)],
|
||||
[html_caption(connector.image)]]
|
||||
# fmt: on
|
||||
|
||||
rows.extend(get_additional_component_table(self, connector))
|
||||
rows.append([html_line_breaks(connector.notes)])
|
||||
html.extend(nested_html_table(rows, html_bgcolor_attr(connector.bgcolor)))
|
||||
|
||||
if connector.style != "simple":
|
||||
pinhtml = []
|
||||
pinhtml.append(
|
||||
'<table border="0" cellspacing="0" cellpadding="3" cellborder="1">'
|
||||
)
|
||||
|
||||
for pinindex, (pinname, pinlabel, pincolor) in enumerate(
|
||||
zip_longest(
|
||||
connector.pins, connector.pinlabels, connector.pincolors
|
||||
)
|
||||
):
|
||||
if (
|
||||
connector.hide_disconnected_pins
|
||||
and not connector.visible_pins.get(pinname, False)
|
||||
):
|
||||
continue
|
||||
|
||||
pinhtml.append(" <tr>")
|
||||
if connector.ports_left:
|
||||
pinhtml.append(f' <td port="p{pinindex+1}l">{pinname}</td>')
|
||||
if pinlabel:
|
||||
pinhtml.append(f" <td>{pinlabel}</td>")
|
||||
if connector.pincolors:
|
||||
if pincolor in wv_colors._color_hex.keys():
|
||||
# fmt: off
|
||||
pinhtml.append(f' <td sides="tbl">{translate_color(pincolor, self.options.color_mode)}</td>')
|
||||
pinhtml.append( ' <td sides="tbr">')
|
||||
pinhtml.append( ' <table border="0" cellborder="1"><tr>')
|
||||
pinhtml.append(f' <td bgcolor="{wv_colors.translate_color(pincolor, "HEX")}" width="8" height="8" fixedsize="true"></td>')
|
||||
pinhtml.append( ' </tr></table>')
|
||||
pinhtml.append( ' </td>')
|
||||
# fmt: on
|
||||
else:
|
||||
pinhtml.append(' <td colspan="2"></td>')
|
||||
|
||||
if connector.ports_right:
|
||||
pinhtml.append(f' <td port="p{pinindex+1}r">{pinname}</td>')
|
||||
pinhtml.append(" </tr>")
|
||||
|
||||
pinhtml.append(" </table>")
|
||||
|
||||
html = [
|
||||
row.replace("<!-- connector table -->", "\n".join(pinhtml))
|
||||
for row in html
|
||||
]
|
||||
|
||||
html = "\n".join(html)
|
||||
gv_html = gv_node_connector(connector, self.options)
|
||||
_default_fillcolor = translate_color(self.options.bgcolor_connector, "HEX")
|
||||
dot.node(
|
||||
connector.name,
|
||||
label=f"<\n{html}\n>",
|
||||
label=f"<\n{gv_html}\n>",
|
||||
shape="box",
|
||||
style="filled",
|
||||
fillcolor=translate_color(self.options.bgcolor_connector, "HEX"),
|
||||
fillcolor=_default_fillcolor,
|
||||
)
|
||||
|
||||
if len(connector.loops) > 0:
|
||||
dot.attr("edge", color="#000000:#ffffff:#000000")
|
||||
if connector.ports_left:
|
||||
loop_side = "l"
|
||||
loop_dir = "w"
|
||||
elif connector.ports_right:
|
||||
loop_side = "r"
|
||||
loop_dir = "e"
|
||||
else:
|
||||
raise Exception("No side for loops")
|
||||
for loop in connector.loops:
|
||||
dot.edge(
|
||||
f"{connector.name}:p{loop[0]}{loop_side}:{loop_dir}",
|
||||
f"{connector.name}:p{loop[1]}{loop_side}:{loop_dir}",
|
||||
)
|
||||
loops = gv_connector_loops(connector)
|
||||
for head, tail in loops:
|
||||
dot.edge(head, tail)
|
||||
|
||||
# determine if there are double- or triple-colored wires in the harness;
|
||||
# if so, pad single-color wires to make all wires of equal thickness
|
||||
|
||||
@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
from wireviz.DataClasses import AdditionalComponent, Cable, Color, Connector
|
||||
from wireviz.wv_colors import translate_color
|
||||
from wireviz.wv_gv_html import html_bgcolor_attr, html_line_breaks
|
||||
from wireviz.wv_helper import clean_whitespace
|
||||
from wireviz.wv_helper import clean_whitespace, pn_info_string
|
||||
|
||||
BOM_COLUMNS_ALWAYS = ("id", "description", "qty", "unit", "designators")
|
||||
BOM_COLUMNS_OPTIONAL = ("pn", "manufacturer", "mpn", "supplier", "spn")
|
||||
@ -263,17 +263,6 @@ def component_table_entry(
|
||||
</tr></table>"""
|
||||
|
||||
|
||||
def pn_info_string(
|
||||
header: str, name: Optional[str], number: Optional[str]
|
||||
) -> Optional[str]:
|
||||
"""Return the company name and/or the part number in one single string or None otherwise."""
|
||||
number = str(number).strip() if number is not None else ""
|
||||
if name or number:
|
||||
return f'{name if name else header}{": " + number if number else ""}'
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def index_if_list(value: Any, index: int) -> Any:
|
||||
"""Return the value indexed if it is a list, or simply the value otherwise."""
|
||||
return value[index] if isinstance(value, list) else value
|
||||
|
||||
@ -178,8 +178,10 @@ def get_color_translation(translate: Dict[Color, str], input: Colors) -> List[st
|
||||
|
||||
|
||||
def translate_color(input: Colors, color_mode: ColorMode) -> str:
|
||||
if input == "" or input is None:
|
||||
if input == "":
|
||||
return ""
|
||||
if input is None:
|
||||
return None
|
||||
upper = color_mode.isupper()
|
||||
if not (color_mode.isupper() or color_mode.islower()):
|
||||
raise Exception("Unknown color mode capitalization")
|
||||
|
||||
@ -1,11 +1,155 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
from itertools import zip_longest
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from wireviz.DataClasses import Color
|
||||
from wireviz.DataClasses import Color, Connector, Options
|
||||
from wireviz.wv_colors import translate_color
|
||||
from wireviz.wv_helper import 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
|
||||
|
||||
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:
|
||||
# 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
|
||||
|
||||
html = []
|
||||
if connector.show_name:
|
||||
row_name = [
|
||||
f"{html_bgcolor(connector.bgcolor_title)}" f"{remove_links(connector.name)}"
|
||||
]
|
||||
else:
|
||||
row_name = []
|
||||
|
||||
row_pn = [
|
||||
pn_info_string(HEADER_PN, None, connector.pn),
|
||||
pn_info_string(HEADER_MPN, connector.manufacturer, connector.mpn),
|
||||
pn_info_string(HEADER_SPN, connector.supplier, connector.spn),
|
||||
]
|
||||
row_pn = [html_line_breaks(cell) for cell in row_pn]
|
||||
|
||||
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),
|
||||
]
|
||||
|
||||
if connector.style != "simple":
|
||||
row_connector_table = "<!-- connector table -->"
|
||||
else:
|
||||
row_connector_table = None
|
||||
|
||||
row_image = [html_image(connector.image)]
|
||||
row_image_caption = [html_caption(connector.image)]
|
||||
row_notes = [html_line_breaks(connector.notes)]
|
||||
# row_additional_component_table = get_additional_component_table(self, connector)
|
||||
row_additional_component_table = None
|
||||
|
||||
rows = [
|
||||
row_name,
|
||||
row_pn,
|
||||
row_info,
|
||||
row_connector_table,
|
||||
row_image,
|
||||
row_image_caption,
|
||||
row_additional_component_table,
|
||||
row_notes,
|
||||
]
|
||||
|
||||
html.extend(nested_html_table(rows, html_bgcolor_attr(connector.bgcolor)))
|
||||
|
||||
if connector.style != "simple":
|
||||
pinhtml = []
|
||||
# fmt: off
|
||||
# pinhtml.append('<table border="0" cellspacing="0" cellpadding="3" cellborder="1">')
|
||||
# fmt: on
|
||||
|
||||
pin_tuples = zip_longest(
|
||||
connector.pins,
|
||||
connector.pinlabels,
|
||||
connector.pincolors,
|
||||
)
|
||||
|
||||
contents = []
|
||||
for pinindex, (pinname, pinlabel, pincolor) in enumerate(pin_tuples):
|
||||
if connector.hide_disconnected_pins and not connector.visible_pins.get(
|
||||
pinname, False
|
||||
):
|
||||
continue
|
||||
|
||||
contents.append(gv_pin(pinindex, pinname, pinlabel, pincolor, connector))
|
||||
|
||||
table_attribs = {
|
||||
"border": 0,
|
||||
"cellspacing": 0,
|
||||
"cellpadding": 3,
|
||||
"cellborder": 1,
|
||||
}
|
||||
pinhtml.append(str(Table(contents, attribs=Attribs(table_attribs))))
|
||||
|
||||
pin_html_joined = "\n".join(pinhtml)
|
||||
|
||||
html = [
|
||||
row.replace("<!-- connector table -->", pin_html_joined) for row in html
|
||||
]
|
||||
|
||||
html = "\n".join(html)
|
||||
|
||||
return html
|
||||
|
||||
|
||||
def gv_pin(pinindex, pinname, pinlabel, pincolor, connector):
|
||||
pinhtml = []
|
||||
pinhtml.append(" <tr>")
|
||||
if connector.ports_left:
|
||||
pinhtml.append(f' <td port="p{pinindex+1}l">{pinname}</td>')
|
||||
if pinlabel:
|
||||
pinhtml.append(f" <td>{pinlabel}</td>")
|
||||
if connector.pincolors:
|
||||
if pincolor in wv_colors._color_hex.keys():
|
||||
# fmt: off
|
||||
pinhtml.append(f' <td sides="tbl">{translate_color(pincolor, harness_options.color_mode)}</td>')
|
||||
pinhtml.append( ' <td sides="tbr">')
|
||||
pinhtml.append( ' <table border="0" cellborder="1"><tr>')
|
||||
pinhtml.append(f' <td bgcolor="{wv_colors.translate_color(pincolor, "HEX")}" width="8" height="8" fixedsize="true"></td>')
|
||||
pinhtml.append( ' </tr></table>')
|
||||
pinhtml.append( ' </td>')
|
||||
# fmt: on
|
||||
else:
|
||||
pinhtml.append(' <td colspan="2"></td>')
|
||||
|
||||
if connector.ports_right:
|
||||
pinhtml.append(f' <td port="p{pinindex+1}r">{pinname}</td>')
|
||||
pinhtml.append(" </tr>")
|
||||
|
||||
pinhtml = "\n".join(pinhtml)
|
||||
|
||||
return pinhtml
|
||||
|
||||
|
||||
def gv_connector_loops(connector: Connector) -> List:
|
||||
loop_edges = []
|
||||
if connector.ports_left:
|
||||
loop_side = "l"
|
||||
loop_dir = "w"
|
||||
elif connector.ports_right:
|
||||
loop_side = "r"
|
||||
loop_dir = "e"
|
||||
else:
|
||||
raise Exception("No side for loops")
|
||||
for loop in connector.loops:
|
||||
head = f"{connector.name}:p{loop[0]}{loop_side}:{loop_dir}"
|
||||
tail = f"{connector.name}:p{loop[1]}{loop_side}:{loop_dir}"
|
||||
loop_edges.append((head, tail))
|
||||
return loop_edges
|
||||
|
||||
|
||||
def nested_html_table(
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
awg_equiv_table = {
|
||||
"0.09": "28",
|
||||
@ -176,3 +176,14 @@ def smart_file_resolve(filename: str, possible_paths: (str, List[str])) -> Path:
|
||||
f"{filename} was not found in any of the following locations: \n"
|
||||
+ "\n".join([str(x) for x in possible_paths])
|
||||
)
|
||||
|
||||
|
||||
def pn_info_string(
|
||||
header: str, name: Optional[str], number: Optional[str]
|
||||
) -> Optional[str]:
|
||||
"""Return the company name and/or the part number in one single string or None otherwise."""
|
||||
number = str(number).strip() if number is not None else ""
|
||||
if name or number:
|
||||
return f'{name if name else header}{": " + number if number else ""}'
|
||||
else:
|
||||
return None
|
||||
|
||||
104
src/wireviz/wv_table_util.py
Normal file
104
src/wireviz/wv_table_util.py
Normal file
@ -0,0 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, List, Optional
|
||||
from collections.abc import Iterable
|
||||
|
||||
|
||||
class Attribs(Dict):
|
||||
def __repr__(self):
|
||||
if len(self) == 0:
|
||||
return ""
|
||||
|
||||
html = []
|
||||
for k, v in self.items():
|
||||
if v is not None:
|
||||
html.append(f' {k}="{v}"')
|
||||
else:
|
||||
html.append(f" {k}")
|
||||
return "".join(html)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Tag:
|
||||
contents: str
|
||||
attribs: Attribs = field(default_factory=Attribs)
|
||||
one_line: bool = False
|
||||
|
||||
@property
|
||||
def tagname(self):
|
||||
return type(self).__name__.lower()
|
||||
|
||||
def get_contents(self):
|
||||
if isinstance(self.contents, Iterable):
|
||||
return "\n".join([str(c) for c in self.contents])
|
||||
else:
|
||||
return str(self.contents)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
separator = "" if self.one_line else "\n"
|
||||
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} />"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Br(TagSingleton):
|
||||
pass
|
||||
|
||||
|
||||
class Td(Tag):
|
||||
pass
|
||||
# contents: str = ""
|
||||
#
|
||||
# def __init__(self, contents, *args, **kwargs):
|
||||
# self.contents = contents
|
||||
# super().__init__(*args, **kwargs)
|
||||
#
|
||||
# def __repr__(self):
|
||||
# html = [
|
||||
# f"<td{self.attribs}>",
|
||||
# self.contents,
|
||||
# f"</td>",
|
||||
# ]
|
||||
# return "\n".join(html)
|
||||
|
||||
|
||||
class Tr(Tag):
|
||||
pass
|
||||
# cells: List[Cell] = field(default_factory=list)
|
||||
#
|
||||
# def __init__(self, cells, *args, **kwargs):
|
||||
# self.cells = cells
|
||||
# super().__init__(*args, **kwargs)
|
||||
#
|
||||
# def __repr__(self):
|
||||
# html = [
|
||||
# f"<tr{self.attribs}>",
|
||||
# "\n".join([str(c) for c in self.cells]),
|
||||
# f"</tr>",
|
||||
# ]
|
||||
# return "\n".join(html)
|
||||
|
||||
|
||||
class Table(Tag):
|
||||
pass
|
||||
# rows: List[Row] = field(default_factory=list)
|
||||
#
|
||||
# def __repr__(self):
|
||||
# html = [
|
||||
# f"<table{self.attribs}>",
|
||||
# "\n".join([str(r) for r in self.rows]),
|
||||
# "</table>",
|
||||
# ]
|
||||
# return "\n".join(html)
|
||||
Loading…
x
Reference in New Issue
Block a user