Replace bgcolor of node elements with box containing Look
In the elements: Image, AdditionalComponent, Connector, and Cable.
This commit is contained in:
parent
251aab08ff
commit
bb39a12256
@ -43,9 +43,10 @@ class Look:
|
||||
fontsize: Optional[Points] = None
|
||||
|
||||
def _2dict(self) -> dict:
|
||||
"""Return dict of strings with color values translated to hex."""
|
||||
"""Return dict of non-None strings with color values translated to hex."""
|
||||
return {
|
||||
k:translate_color(v, "hex") if 'color' in k else str(v) for k,v in asdict(self).items()
|
||||
k:translate_color(v, "hex") if 'color' in k else str(v)
|
||||
for k,v in asdict(self).items() if v is not None
|
||||
}
|
||||
|
||||
def graph_args(self) -> dict:
|
||||
@ -111,13 +112,16 @@ class Image:
|
||||
width: Optional[Points] = None
|
||||
height: Optional[Points] = None
|
||||
fixedsize: Optional[bool] = None
|
||||
bgcolor: Optional[Color] = None
|
||||
box: Optional[Look] = None
|
||||
# Contents of the text cell <td> just below the image cell:
|
||||
caption: Optional[MultilineHypertext] = None
|
||||
# See also HTML doc at https://graphviz.org/doc/info/shapes.html#html
|
||||
|
||||
def __post_init__(self, gv_dir):
|
||||
|
||||
if isinstance(self.box, dict):
|
||||
self.box = Look(**self.box)
|
||||
|
||||
if self.fixedsize is None:
|
||||
# Default True if any dimension specified unless self.scale also is specified.
|
||||
self.fixedsize = (self.width or self.height) and self.scale is None
|
||||
@ -150,7 +154,11 @@ class AdditionalComponent:
|
||||
qty: float = 1
|
||||
unit: Optional[str] = None
|
||||
qty_multiplier: Union[ConnectorMultiplier, CableMultiplier, None] = None
|
||||
bgcolor: Optional[Color] = None
|
||||
box: Optional[Look] = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if isinstance(self.box, dict):
|
||||
self.box = Look(**self.box)
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
@ -160,8 +168,8 @@ class AdditionalComponent:
|
||||
@dataclass
|
||||
class Connector:
|
||||
name: Designator
|
||||
bgcolor: Optional[Color] = None
|
||||
bgcolor_title: Optional[Color] = None
|
||||
box: Optional[Look] = None
|
||||
title: Optional[Look] = None
|
||||
manufacturer: Optional[MultilineHypertext] = None
|
||||
mpn: Optional[MultilineHypertext] = None
|
||||
supplier: Optional[MultilineHypertext] = None
|
||||
@ -188,6 +196,10 @@ class Connector:
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
|
||||
if isinstance(self.box, dict):
|
||||
self.box = Look(**self.box)
|
||||
if isinstance(self.title, dict):
|
||||
self.title = Look(**self.title)
|
||||
if isinstance(self.image, dict):
|
||||
self.image = Image(**self.image)
|
||||
|
||||
@ -246,8 +258,8 @@ class Connector:
|
||||
@dataclass
|
||||
class Cable:
|
||||
name: Designator
|
||||
bgcolor: Optional[Color] = None
|
||||
bgcolor_title: Optional[Color] = None
|
||||
box: Optional[Look] = None
|
||||
title: Optional[Look] = None
|
||||
manufacturer: Union[MultilineHypertext, List[MultilineHypertext], None] = None
|
||||
mpn: Union[MultilineHypertext, List[MultilineHypertext], None] = None
|
||||
supplier: Union[MultilineHypertext, List[MultilineHypertext], None] = None
|
||||
@ -276,6 +288,10 @@ class Cable:
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
|
||||
if isinstance(self.box, dict):
|
||||
self.box = Look(**self.box)
|
||||
if isinstance(self.title, dict):
|
||||
self.title = Look(**self.title)
|
||||
if isinstance(self.image, dict):
|
||||
self.image = Image(**self.image)
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ from wireviz import wv_colors, __version__, APP_NAME, APP_URL
|
||||
from wireviz.DataClasses import Metadata, Options, Tweak, Connector, Cable
|
||||
from wireviz.wv_colors import get_color_hex, translate_color
|
||||
from wireviz.wv_gv_html import nested_html_table, \
|
||||
html_bgcolor_attr, html_bgcolor, html_colorbar, \
|
||||
html_cell, html_colorbar, \
|
||||
html_image, html_caption, remove_links, html_line_breaks
|
||||
from wireviz.wv_bom import pn_info_string, component_table_entry, \
|
||||
get_additional_component_table, bom_list, generate_bom, \
|
||||
@ -124,7 +124,7 @@ class Harness:
|
||||
|
||||
html = []
|
||||
|
||||
rows = [[f'{html_bgcolor(connector.bgcolor_title)}{remove_links(connector.name)}'
|
||||
rows = [[html_cell(connector.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)),
|
||||
@ -139,7 +139,7 @@ class Harness:
|
||||
[html_caption(connector.image)]]
|
||||
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)))
|
||||
html.extend(nested_html_table(rows, connector.box))
|
||||
|
||||
if connector.style != 'simple':
|
||||
pinhtml = []
|
||||
@ -210,7 +210,7 @@ class Harness:
|
||||
elif cable.gauge_unit.upper() == 'AWG':
|
||||
awg_fmt = f' ({mm2_equiv(cable.gauge)} mm\u00B2)'
|
||||
|
||||
rows = [[f'{html_bgcolor(cable.bgcolor_title)}{remove_links(cable.name)}'
|
||||
rows = [[html_cell(cable.title, remove_links(cable.name))
|
||||
if cable.show_name else None],
|
||||
[pn_info_string(HEADER_PN, None,
|
||||
remove_links(cable.pn)) if not isinstance(cable.pn, list) else None,
|
||||
@ -233,7 +233,7 @@ class Harness:
|
||||
|
||||
rows.extend(get_additional_component_table(self, cable))
|
||||
rows.append([html_line_breaks(cable.notes)])
|
||||
html.extend(nested_html_table(rows, html_bgcolor_attr(cable.bgcolor)))
|
||||
html.extend(nested_html_table(rows, cable.box))
|
||||
|
||||
wirehtml = []
|
||||
wirehtml.append('<table border="0" cellspacing="0" cellborder="0">') # conductor table
|
||||
|
||||
@ -4,9 +4,9 @@ from dataclasses import asdict
|
||||
from itertools import groupby
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from wireviz.DataClasses import AdditionalComponent, Cable, Connector
|
||||
from wireviz.DataClasses import AdditionalComponent, Cable, Connector, Look
|
||||
from wireviz.wv_colors import Color, translate_color
|
||||
from wireviz.wv_gv_html import html_bgcolor_attr, html_line_breaks
|
||||
from wireviz.wv_gv_html import font_tag, html_line_breaks, table_attr
|
||||
from wireviz.wv_helper import clean_whitespace
|
||||
|
||||
BOM_COLUMNS_ALWAYS = ('id', 'description', 'qty', 'unit', 'designators')
|
||||
@ -35,7 +35,7 @@ def get_additional_component_table(harness: "Harness", component: Union[Connecto
|
||||
common_args = {
|
||||
'qty': part.qty * component.get_qty_multiplier(part.qty_multiplier),
|
||||
'unit': part.unit,
|
||||
'bgcolor': part.bgcolor,
|
||||
'box': part.box,
|
||||
}
|
||||
if harness.options.mini_bom_mode:
|
||||
id = get_bom_index(harness.bom(), bom_entry_key({**asdict(part), 'description': part.description}))
|
||||
@ -158,7 +158,7 @@ def component_table_entry(
|
||||
type: str,
|
||||
qty: Union[int, float],
|
||||
unit: Optional[str] = None,
|
||||
bgcolor: Optional[Color] = None,
|
||||
box: Optional[Look] = None,
|
||||
pn: Optional[str] = None,
|
||||
manufacturer: Optional[str] = None,
|
||||
mpn: Optional[str] = None,
|
||||
@ -178,8 +178,8 @@ def component_table_entry(
|
||||
+ (', '.join([pn for pn in part_number_list if pn])))
|
||||
# format the above output as left aligned text in a single visible cell
|
||||
# indent is set to two to match the indent in the generated html table
|
||||
return f'''<table border="0" cellspacing="0" cellpadding="3" cellborder="1"{html_bgcolor_attr(bgcolor)}><tr>
|
||||
<td align="left" balign="left">{html_line_breaks(output)}</td>
|
||||
return f'''<table border="0" cellspacing="0" cellpadding="3" cellborder="1"{table_attr(box)}><tr>
|
||||
<td align="left" balign="left">{font_tag(box, html_line_breaks(output))}</td>
|
||||
</tr></table>'''
|
||||
|
||||
def pn_info_string(header: str, name: Optional[str], number: Optional[str]) -> Optional[str]:
|
||||
|
||||
@ -1,18 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import List, Optional, Union
|
||||
import re
|
||||
|
||||
from wireviz.DataClasses import Image, Look
|
||||
from wireviz.wv_colors import Color, translate_color
|
||||
from wireviz.wv_helper import remove_links
|
||||
|
||||
def nested_html_table(rows: List[Union[str, List[Optional[str]], None]], table_attrs: str = '') -> str:
|
||||
# input: list, each item may be scalar or list
|
||||
GvHtml = str # Graphviz HTML-like label string
|
||||
GvHtmlX = str # Graphviz HTML-like label string possibly including a leading <tdX> tag
|
||||
GvHtmlAttr = str # Attributes part of Graphviz HTML-like tag (including a leading space)
|
||||
|
||||
def nested_html_table(rows: List[Union[GvHtml, List[Optional[GvHtmlX]], None]], look: Optional[Look]) -> GvHtml:
|
||||
# input: list, each item may be scalar or list, and look with optional table look attributes
|
||||
# output: a parent table with one child table per parent item that is list, and one cell per parent item that is scalar
|
||||
# purpose: create the appearance of one table, where cell widths are independent between rows
|
||||
# attributes in any leading <tdX> inside a list are injected into to the preceeding <td> tag
|
||||
html = []
|
||||
html.append(f'<table border="0" cellspacing="0" cellpadding="0"{table_attrs or ""}>')
|
||||
attr = font_attr(look)
|
||||
font = f'<font{attr}>' if attr else ''
|
||||
html.append(f'{font}<table border="0" cellspacing="0" cellpadding="0"{table_attr(look)}>')
|
||||
for row in rows:
|
||||
if isinstance(row, List):
|
||||
if len(row) > 0 and any(row):
|
||||
@ -28,23 +34,36 @@ def nested_html_table(rows: List[Union[str, List[Optional[str]], None]], table_a
|
||||
html.append(' <tr><td>')
|
||||
html.append(f' {row}')
|
||||
html.append(' </td></tr>')
|
||||
html.append('</table>')
|
||||
html.append(f'</table>{"</font>" if font else ""}')
|
||||
return html
|
||||
|
||||
def html_bgcolor_attr(color: Color) -> str:
|
||||
"""Return attributes for bgcolor or '' if no color."""
|
||||
return f' bgcolor="{translate_color(color, "HEX")}"' if color else ''
|
||||
def table_attr(look: Optional[Look]) -> GvHtmlAttr:
|
||||
"""Return table tag attributes containing all non-empty table option values."""
|
||||
return '' if not look else ''.join({
|
||||
f' {k}="{v}"' for k,v in look._2dict().items() if v and 'font' not in k})
|
||||
|
||||
def html_bgcolor(color: Color, _extra_attr: str = '') -> str:
|
||||
"""Return <td> attributes prefix for bgcolor or '' if no color."""
|
||||
return f'<tdX{html_bgcolor_attr(color)}{_extra_attr}>' if color else ''
|
||||
def font_attr(look: Optional[Look]) -> GvHtmlAttr:
|
||||
"""Return font tag attributes containing all non-empty font option values."""
|
||||
attr = {k:v for k,v in look._2dict().items() if v and 'font' in k} if look else {}
|
||||
return ((f' color="{attr["fontcolor"]}"' if attr.get('fontcolor') else '')
|
||||
+ (f' face="{attr["fontname"]}"' if attr.get('fontname') else '')
|
||||
+ (f' point-size="{attr["fontsize"]}"' if attr.get('fontsize') else ''))
|
||||
|
||||
def html_colorbar(color: Color) -> str:
|
||||
"""Return <tdX> attributes prefix for bgcolor and minimum width or None if no color."""
|
||||
return html_bgcolor(color, ' width="4"') if color else None
|
||||
def font_tag(look: Optional[Look], text: GvHtml) -> GvHtml:
|
||||
"""Return text in Graphviz HTML font tag with all non-empty font option values."""
|
||||
attr = font_attr(look)
|
||||
return f'<font{attr}>{text}</font>' if attr and text > '' else text
|
||||
|
||||
def html_image(image):
|
||||
from wireviz.DataClasses import Image
|
||||
def html_cell(look: Optional[Look], text: GvHtml = '', attr: GvHtmlAttr = '') -> GvHtmlX:
|
||||
"""Return cell to be included in the rows list for nested_html_table()."""
|
||||
return f'<tdX{attr}{table_attr(look)}>{font_tag(look, text)}'
|
||||
|
||||
def html_colorbar(color: Optional[Color]) -> Optional[GvHtmlX]:
|
||||
"""Return colored cell to be included in the rows list for nested_html_table() or None if no color."""
|
||||
return html_cell(Look(bgcolor=color), attr=' width="4"') if color else None
|
||||
|
||||
def html_image(image: Optional[Image]) -> Optional[GvHtmlX]:
|
||||
"""Return image cell to be included in the rows list for nested_html_table() or None if no image."""
|
||||
if not image:
|
||||
return None
|
||||
# The leading attributes belong to the preceeding tag. See where used below.
|
||||
@ -57,16 +76,14 @@ def html_image(image):
|
||||
<td{html}</td>
|
||||
</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 ''}{table_attr(image.box)}{html}'''
|
||||
|
||||
def html_caption(image):
|
||||
from wireviz.DataClasses import Image
|
||||
return (f'<tdX sides="BLR"{html_bgcolor_attr(image.bgcolor)}>{html_line_breaks(image.caption)}'
|
||||
if image and image.caption else None)
|
||||
def html_caption(image: Optional[Image]) -> Optional[GvHtmlX]:
|
||||
"""Return image caption cell to be included just after the image cell or None if no caption."""
|
||||
return html_cell(image.box, html_line_breaks(image.caption), ' sides="BLR"') if image and image.caption else None
|
||||
|
||||
def html_size_attr(image):
|
||||
from wireviz.DataClasses import Image
|
||||
# Return Graphviz HTML attributes to specify minimum or fixed size of a TABLE or TD object
|
||||
def html_size_attr(image: Optional[Image]) -> GvHtmlAttr:
|
||||
"""Return Graphviz HTML attributes to specify minimum or fixed size of a TABLE or TD object."""
|
||||
return ((f' width="{image.width}"' if image.width else '')
|
||||
+ (f' height="{image.height}"' if image.height else '')
|
||||
+ ( ' fixedsize="true"' if image.fixedsize else '')) if image else ''
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user