diff --git a/src/wireviz/Harness.py b/src/wireviz/Harness.py index 5f1230c..956efe6 100644 --- a/src/wireviz/Harness.py +++ b/src/wireviz/Harness.py @@ -34,8 +34,8 @@ 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_node_cable, + gv_node_connector, html_bgcolor, html_bgcolor_attr, html_caption, diff --git a/src/wireviz/wv_gv_html.py b/src/wireviz/wv_gv_html.py index 98acc6e..36de073 100644 --- a/src/wireviz/wv_gv_html.py +++ b/src/wireviz/wv_gv_html.py @@ -5,7 +5,7 @@ from itertools import zip_longest from typing import List, Optional, Union from wireviz.DataClasses import Cable, Color, Connector, Options -from wireviz.wv_colors import translate_color, get_color_hex +from wireviz.wv_colors import get_color_hex, translate_color from wireviz.wv_helper import pn_info_string, remove_links from wireviz.wv_table_util import * # TODO: explicitly import each needed tag later @@ -90,9 +90,9 @@ def gv_node_connector(connector: Connector, harness_options: Options) -> Table: 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"}, 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) + 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_right = Td(pin_name, attribs={"port": f"p{pin_index+1}r"}) cells = [ cell_pin_left if connector.ports_left else None, @@ -203,8 +203,9 @@ def gv_conductor_table(cable, harness_options, pad) -> Table: return tbl + def gv_wire_cell(index, color, pad) -> Td: - bgcolors = ['#000000'] + get_color_hex(color, pad=pad) + ['#000000'] + bgcolors = ["#000000"] + get_color_hex(color, pad=pad) + ["#000000"] wire_inner_rows = [] for j, bgcolor in enumerate(bgcolors[::-1]): wire_inner_cell_attribs = { @@ -215,7 +216,7 @@ def gv_wire_cell(index, color, pad) -> Td: "bgcolor": bgcolor if bgcolor != "" else "BK", } wire_inner_rows.append(Tr(Td("", attribs=wire_inner_cell_attribs))) - wire_inner_table_attribs = {"cellspacing":0, "cellborder":0, "border":0} + wire_inner_table_attribs = {"cellspacing": 0, "cellborder": 0, "border": 0} wire_inner_table = Table(wire_inner_rows, wire_inner_table_attribs) wire_outer_cell_attribs = { "colspan": 3, @@ -229,7 +230,6 @@ def gv_wire_cell(index, color, pad) -> Td: return wire_outer_cell - def colored_cell(contents, bgcolor) -> Td: if bgcolor: attribs = {"bgcolor": translate_color(bgcolor, "HEX")} @@ -267,7 +267,6 @@ def image_and_caption_cells(component): Td( html_caption_new(component.image), attribs=row_caption_attribs, - flat=True, ) ] else: @@ -301,7 +300,7 @@ def nested_table(rows_in: List[Tr]): inner_cells.append(cell) else: inner_cell_attribs = {"balign": "left"} - inner_cells.append(Td(cell, attribs=inner_cell_attribs, flat=True)) + inner_cells.append(Td(cell, attribs=inner_cell_attribs)) inner_table_attribs = { "border": 0, diff --git a/src/wireviz/wv_table_util.py b/src/wireviz/wv_table_util.py index b5a36e6..a071f17 100644 --- a/src/wireviz/wv_table_util.py +++ b/src/wireviz/wv_table_util.py @@ -4,6 +4,8 @@ from collections.abc import Iterable from dataclasses import dataclass, field from typing import Dict, List, Optional +indent_count = 1 + class Attribs(Dict): def __repr__(self): @@ -42,23 +44,40 @@ class Tag: def tagname(self): return type(self).__name__.lower() + @property + def auto_flat(self): + if self.flat: # force flat + return True + if not _is_iterable_not_str(self.contents): # catch str, int, float, ... + if not isinstance(self.contents, Tag): # avoid recursion + return not "\n" in str(self.contents) # flatten if single line + + def indent_lines(self, lines): + if self.auto_flat: + return lines + else: + indenter = " " * indent_count + return "\n".join(f"{indenter}{line}" for line in lines.split("\n")) + def get_contents(self): - 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]) + separator = "" if self.auto_flat else "\n" + if _is_iterable_not_str(self.contents): + return separator.join( + [self.indent_lines(str(c)) for c in self.contents if c is not None] + ) elif self.contents is None: return "" - else: - return str(self.contents) + else: # str, int, float, etc. + return self.indent_lines(str(self.contents)) def __repr__(self): - separator = "" if self.flat else "\n" + separator = "" if self.auto_flat else "\n" if self.contents is None and self.empty_is_none: return "" else: html = [ f"<{self.tagname}{str(self.attribs)}>", - self.get_contents(), + f"{self.get_contents()}", f"{self.tagname}>", ] return separator.join(html) @@ -70,6 +89,11 @@ class TagSingleton(Tag): return f"<{self.tagname}{str(self.attribs)} />" +def _is_iterable_not_str(inp): + # str is iterable, but should be treated as not iterable + return isinstance(inp, Iterable) and not isinstance(inp, str) + + @dataclass class Br(TagSingleton): pass @@ -77,46 +101,11 @@ class Br(TagSingleton): class Td(Tag): pass - # contents: str = "" - # - # def __init__(self, contents, *args, **kwargs): - # self.contents = contents - # super().__init__(*args, **kwargs) - # - # def __repr__(self): - # html = [ - # f"