pluto_hdl_adi/docs/extensions/adi_hdl_render.py

231 lines
6.6 KiB
Python
Raw Normal View History

import os.path
from lxml import etree
font_size = 16
margin = 18
line_length = 16
text_vertical_margin = 8
color_main = '#0067b9'
color_bg1 = '#c4e5ff'
color_bg2 = '#ebf6ff'
stroke_width = 3
class hdl_component():
@staticmethod
def get_name(lib_name):
return f"{lib_name.replace('/','-')}.svg"
@staticmethod
def render(env, lib_name, item):
#ports, bus_interface
dest_dir = os.path.join(env.srcdir, '_build/managed')
dest_file = os.path.join(dest_dir, hdl_component.get_name(lib_name))
def make_style(parent):
style = etree.SubElement(parent, 'style').text = """
a {
text-decoration: none;
}
"""
def make_gradient(parent):
defs = etree.SubElement(parent, 'defs')
gradient = etree.SubElement(defs, 'linearGradient', attrib={
'id':'ip_background',
'x1':'0', 'x2':'1', 'y1':'0', 'y2':'1'
})
etree.SubElement(gradient, 'stop', attrib={'offset':'0%', 'stop-color':color_bg1})
etree.SubElement(gradient, 'stop', attrib={'offset':'100%', 'stop-color':color_bg2})
def symbol_bus(parent):
rect_height = font_size
one_fifth_x = line_length/5
one_fifth_y = rect_height/5
x = 0; y = 0
pattern = [[0,1,0,1,0],[0,0,0,0,0],[0,1,0,1,0],[0,0,0,0,0],[0,1,0,1,0]]
etree.SubElement(parent, "rect", attrib={
'x':'0', 'y':'0',
'width':str(line_length), 'height':str(font_size),
'fill':color_bg1,
})
for i in pattern:
for j in i:
if j:
etree.SubElement(parent, "rect", attrib={
'x':str(x), 'y':str(y),
'width':str(one_fifth_x), 'height':str(one_fifth_y),
'fill':color_main,
})
x = x+one_fifth_x
x = 0
y = y+one_fifth_y
def symbol_port(parent):
etree.SubElement(parent, "line", attrib={
'stroke':'black',
'stroke-width':str(stroke_width),
'x1':'0', 'y1':str(font_size/2),
'x2':str(line_length), 'y2':str(font_size/2)
})
def create_text(items, side):
y_pos = margin*4
if side == 'out':
text_anchor = 'end'
x_pos = margin*4 + aux_width
line_x1 = x_pos+(margin)
line_x2 = x_pos+(margin+line_length)
x_pos_group = x_pos+margin
scale_group = 'scale(1,1)'
else:
text_anchor = 'start'
x_pos = margin*3
line_x1 = x_pos-(margin+line_length)
line_x2 = x_pos-(margin)
x_pos_group = x_pos-margin
scale_group = 'scale(-1,1)'
for elem in items:
if elem[1] == 'bus':
link_anchor = f"#bus-interface-{elem[0]}"
else:
link_anchor = "#ports"
link = etree.SubElement(root, "a", attrib={
'href':link_anchor,
})
etree.SubElement(link, "text", attrib={
'style':f"font: {font_size}px sans-serif",
'text-anchor':text_anchor,
'dominant-baseline':'middle',
'x':str(x_pos), 'y':str(y_pos)
}).text = elem[0]
group = etree.SubElement(root, "g", attrib={
'transform':f"translate({x_pos_group},{y_pos-font_size/2}) {scale_group}"}
)
if elem[1] == 'bus':
symbol_bus(group)
else:
symbol_port(group)
y_pos += font_size+text_vertical_margin
ins = []
outs = []
for key in item['bus_interface']:
if item['bus_interface'][key]['role'] == 'master':
outs.append((key, 'bus'))
else:
ins.append((key, 'bus'))
for key in item['ports']:
if item['ports'][key]['direction'] == 'out':
outs.append((key, 'port'))
else:
ins.append((key, 'port'))
max_len_in = 0
for elem in ins:
max_len_in = len(elem[0]) if len(elem[0]) > max_len_in else max_len_in
max_len_out = 0
for elem in outs:
max_len_out = len(elem[0]) if len(elem[0]) > max_len_out else max_len_out
aux_width = (max_len_in+max_len_out)*font_size*.6
num_outs = len(outs)
num_ins = len(ins)
max_num = max(num_outs, num_ins)
root = etree.Element('svg', xmlns="http://www.w3.org/2000/svg")
make_style(root)
make_gradient(root)
ip_width = aux_width + margin*3
ip_height = max_num*(font_size+text_vertical_margin) + margin*2
etree.SubElement(root, "rect", attrib={
'x':str(margin*2), 'y':str(margin*2),
'width':str(ip_width), 'height':str(ip_height),
'rx':str(margin),
'fill':'url(#ip_background)'
})
create_text(ins,'in')
create_text(outs,'out')
viewbox_x = margin*7 + aux_width
viewbox_y = margin*7 + max_num*(font_size+text_vertical_margin)
root.set('viewBox', f"0 0 {viewbox_x} {viewbox_y}")
root.set('width', str(viewbox_x))
root.set('height', str(viewbox_y))
etree.SubElement(root, "rect", attrib={
'x':str(margin*2), 'y':str(margin*2),
'width':str(ip_width), 'height':str(ip_height),
'rx':str(margin),
'fill':'none',
'stroke':color_main,
'stroke-width':str(stroke_width)
})
ipname_y = viewbox_y-font_size-margin
ipname_x = viewbox_x/2
etree.SubElement(root, "text", attrib={
'style':f"font: {font_size}px sans-serif",
'fill': color_main,
'text-anchor':'middle',
'dominant-baseline':'middle',
'x':str(ipname_x), 'y':str(ipname_y)
}).text = lib_name[lib_name.rfind('/')+1:]
tree = etree.ElementTree(root)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
tree.write(dest_file)
@staticmethod
def render_placeholder(lib_name):
root = etree.Element('svg', xmlns="http://www.w3.org/2000/svg")
def text_element(text, fs, x, y, font='sans-serif'):
etree.SubElement(root, "text", attrib={
'style':f"font: {font_size*fs}px {font}",
'fill': '#666',
'text-anchor':'middle',
'dominant-baseline':'middle',
'x':str(x), 'y':str(y)
}).text = text
ip_width = font_size*30
ip_height = font_size*15
etree.SubElement(root, "rect", attrib={
'x':str(margin*2), 'y':str(margin*2),
'width':str(ip_width), 'height':str(ip_height),
'rx':str(margin),
'stroke':'#666',
'fill':'none',
'stroke-width':str(stroke_width),
'stroke-dasharray':'8 16',
'stroke-linecap':'round'
})
viewbox_x = ip_width + 4*margin
viewbox_y = ip_height + 4*margin
root.set('viewBox', f"0 0 {viewbox_x} {viewbox_y}")
root.set('width', str(viewbox_x))
root.set('height', str(viewbox_y))
text_y = viewbox_y/2.5
text_x = viewbox_x/2
text_element("🧐", 4, text_x, text_y-text_vertical_margin*2)
text_element(f"{lib_name[lib_name.rfind('/')+1:]} IP-XACT not found.",
1, text_x, text_y+font_size*2+text_vertical_margin)
text_element("Generate it and the documentation:",
.75, text_x, text_y+font_size*3+text_vertical_margin*2.5)
text_element(f"(cd {lib_name}; make)",
.75, text_x, text_y+font_size*4+text_vertical_margin*3, 'monospace')
text_element("(cd docs; make html)",
.75, text_x, text_y+font_size*5+text_vertical_margin*3.5, 'monospace')
tree = etree.ElementTree(root)
return etree.tostring(tree, encoding="utf-8", method="xml").decode("utf-8")