Skip to content

Commit ee2aeb5

Browse files
committed
Add fabrication layer support
Issue #76
1 parent 1668fdc commit ee2aeb5

File tree

8 files changed

+204
-39
lines changed

8 files changed

+204
-39
lines changed

InteractiveHtmlBom/core/config.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
from wx import FileConfig
77

8+
from .. import dialog
9+
810

911
class Config:
1012
# Helper constants
@@ -18,14 +20,16 @@ class Config:
1820
]
1921
default_checkboxes = ['Sourced', 'Placed']
2022
html_config_fields = [
21-
'dark_mode', 'show_silkscreen', 'highlight_pin1', 'redraw_on_drag',
22-
'board_rotation', 'checkboxes', 'bom_view', 'layer_view', 'extra_fields'
23+
'dark_mode', 'show_fabrication', 'show_silkscreen', 'highlight_pin1',
24+
'redraw_on_drag', 'board_rotation', 'checkboxes', 'bom_view',
25+
'layer_view', 'extra_fields'
2326
]
2427

2528
# Defaults
2629

2730
# HTML section
2831
dark_mode = False
32+
show_fabrication = False
2933
show_silkscreen = True
3034
highlight_pin1 = False
3135
redraw_on_drag = True
@@ -65,6 +69,8 @@ def __init__(self):
6569

6670
f.SetPath('/html_defaults')
6771
self.dark_mode = f.ReadBool('dark_mode', self.dark_mode)
72+
self.show_fabrication = f.ReadBool(
73+
'show_fabrication', self.show_fabrication)
6874
self.show_silkscreen = f.ReadBool(
6975
'show_silkscreen', self.show_silkscreen)
7076
self.highlight_pin1 = f.ReadBool('highlight_pin1', self.highlight_pin1)
@@ -108,6 +114,7 @@ def save(self):
108114

109115
f.SetPath('/html_defaults')
110116
f.WriteBool('dark_mode', self.dark_mode)
117+
f.WriteBool('show_fabrication', self.show_fabrication)
111118
f.WriteBool('show_silkscreen', self.show_silkscreen)
112119
f.WriteBool('highlight_pin1', self.highlight_pin1)
113120
f.WriteBool('redraw_on_drag', self.redraw_on_drag)
@@ -145,6 +152,7 @@ def set_from_dialog(self, dlg):
145152
# type: (dialog.settings_dialog.SettingsDialogPanel) -> None
146153
# Html
147154
self.dark_mode = dlg.html.darkModeCheckbox.IsChecked()
155+
self.show_fabrication = dlg.html.showFabricationCheckbox.IsChecked()
148156
self.show_silkscreen = dlg.html.showSilkscreenCheckbox.IsChecked()
149157
self.highlight_pin1 = dlg.html.highlightPin1Checkbox.IsChecked()
150158
self.redraw_on_drag = dlg.html.continuousRedrawCheckbox.IsChecked()
@@ -183,6 +191,7 @@ def transfer_to_dialog(self, dlg):
183191
# type: (dialog.settings_dialog.SettingsDialogPanel) -> None
184192
# Html
185193
dlg.html.darkModeCheckbox.Value = self.dark_mode
194+
dlg.html.showFabricationCheckbox.Value = self.show_fabrication
186195
dlg.html.showSilkscreenCheckbox.Value = self.show_silkscreen
187196
dlg.html.highlightPin1Checkbox.Value = self.highlight_pin1
188197
dlg.html.continuousRedrawCheckbox.value = self.redraw_on_drag
@@ -235,6 +244,9 @@ def add_options(self, parser, file_name_format_hint):
235244
# Html
236245
parser.add_argument('--dark-mode', help='Default to dark mode.',
237246
action='store_true')
247+
parser.add_argument('--show-fabrication',
248+
help='Show fabrication layer by default.',
249+
action='store_true')
238250
parser.add_argument('--hide-silkscreen',
239251
help='Hide silkscreen by default.',
240252
action='store_true')
@@ -306,6 +318,7 @@ def set_from_args(self, args):
306318

307319
# Html
308320
self.dark_mode = args.dark_mode
321+
self.show_fabrication = args.show_fabrication
309322
self.show_silkscreen = not args.hide_silkscreen
310323
self.highlight_pin1 = args.highlight_pin1
311324
self.redraw_on_drag = not args.no_redraw_on_drag

InteractiveHtmlBom/core/ibom.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -342,23 +342,17 @@ def parse_edges(pcb):
342342
return edges, bbox
343343

344344

345-
def parse_silkscreen(pcb):
345+
def parse_drawings_on_layers(drawings, f_layer, b_layer):
346346
front = []
347347
back = []
348-
drawings = list(pcb.GetDrawings())
349-
for m in pcb.GetModules():
350-
drawings.append(m.Reference())
351-
drawings.append(m.Value())
352-
for d in m.GraphicalItems():
353-
drawings.append(d)
354348

355349
for d in drawings:
356-
if d.GetLayer() not in [pcbnew.F_SilkS, pcbnew.B_SilkS]:
350+
if d.GetLayer() not in [f_layer, b_layer]:
357351
continue
358352
drawing = parse_drawing(d)
359353
if not drawing:
360354
continue
361-
if d.GetLayer() == pcbnew.F_SilkS:
355+
if d.GetLayer() == f_layer:
362356
front.append(drawing)
363357
else:
364358
back.append(drawing)
@@ -369,6 +363,16 @@ def parse_silkscreen(pcb):
369363
}
370364

371365

366+
def get_all_drawings(pcb):
367+
drawings = list(pcb.GetDrawings())
368+
for m in pcb.GetModules():
369+
drawings.append(m.Reference())
370+
drawings.append(m.Value())
371+
for d in m.GraphicalItems():
372+
drawings.append(d)
373+
return drawings
374+
375+
372376
def parse_pad(pad):
373377
layers_set = list(pad.GetLayerSet().Seq())
374378
layers = []
@@ -609,11 +613,15 @@ def main(pcb, config, parse_schematic_data, cli=False):
609613
}
610614

611615
pcb_modules = list(pcb.GetModules())
616+
drawings = get_all_drawings(pcb)
612617

613618
pcbdata = {
614619
"edges_bbox": bbox,
615620
"edges": edges,
616-
"silkscreen": parse_silkscreen(pcb),
621+
"silkscreen": parse_drawings_on_layers(
622+
drawings, pcbnew.F_SilkS, pcbnew.B_SilkS),
623+
"fabrication": parse_drawings_on_layers(
624+
drawings, pcbnew.F_Fab, pcbnew.B_Fab),
617625
"modules": parse_modules(pcb_modules),
618626
"metadata": {
619627
"title": title,

InteractiveHtmlBom/dialog/dialog_base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ def __init__( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.
100100
self.darkModeCheckbox = wx.CheckBox( self, wx.ID_ANY, u"Dark mode", wx.DefaultPosition, wx.DefaultSize, 0 )
101101
b_sizer.Add( self.darkModeCheckbox, 0, wx.ALL, 5 )
102102

103+
self.showFabricationCheckbox = wx.CheckBox( self, wx.ID_ANY, u"Show fabrication layer", wx.DefaultPosition, wx.DefaultSize, 0 )
104+
b_sizer.Add( self.showFabricationCheckbox, 0, wx.ALL, 5 )
105+
103106
self.showSilkscreenCheckbox = wx.CheckBox( self, wx.ID_ANY, u"Show silkscreen", wx.DefaultPosition, wx.DefaultSize, 0 )
104107
self.showSilkscreenCheckbox.SetValue(True)
105108
b_sizer.Add( self.showSilkscreenCheckbox, 0, wx.ALL, 5 )

InteractiveHtmlBom/web/ibom.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
--pad-color-highlight: #D04040;
55
--pin1-outline-color: #ffb629;
66
--pin1-outline-color-highlight: #b4ff03;
7+
--silkscreen-edge-color: #aa4;
8+
--silkscreen-polygon-color: #4aa;
9+
--silkscreen-text-color: #4aa;
10+
--fabrication-edge-color: #907651;
11+
--fabrication-polygon-color: #907651;
12+
--fabrication-text-color: #a27c24;
713
}
814

915
html, body {

InteractiveHtmlBom/web/ibom.html

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
<input id="darkmodeCheckbox" type="checkbox" onchange="setDarkMode(this.checked)">
4848
Dark mode
4949
</label>
50+
<label class="menu-label">
51+
<input id="fabricationCheckbox" type="checkbox" checked onchange="fabricationVisible(this.checked)">
52+
Show fabrication layer
53+
</label>
5054
<label class="menu-label">
5155
<input id="silkscreenCheckbox" type="checkbox" checked onchange="silkscreenVisible(this.checked)">
5256
Show silkscreen
@@ -146,15 +150,17 @@
146150
<div id="frontcanvas" class="split" style="overflow: hidden">
147151
<div style="position: relative; width: 100%; height: 100%;">
148152
<canvas id="F_bg" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
149-
<canvas id="F_slk" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
150-
<canvas id="F_hl" style="position: absolute; left: 0; top: 0; z-index: 2;"></canvas>
153+
<canvas id="F_fab" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
154+
<canvas id="F_slk" style="position: absolute; left: 0; top: 0; z-index: 2;"></canvas>
155+
<canvas id="F_hl" style="position: absolute; left: 0; top: 0; z-index: 3;"></canvas>
151156
</div>
152157
</div>
153158
<div id="backcanvas" class="split" style="overflow: hidden">
154159
<div style="position: relative; width: 100%; height: 100%;">
155160
<canvas id="B_bg" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
156-
<canvas id="B_slk" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
157-
<canvas id="B_hl" style="position: absolute; left: 0; top: 0; z-index: 2;"></canvas>
161+
<canvas id="B_fab" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
162+
<canvas id="B_slk" style="position: absolute; left: 0; top: 0; z-index: 2;"></canvas>
163+
<canvas id="B_hl" style="position: absolute; left: 0; top: 0; z-index: 3;"></canvas>
158164
</div>
159165
</div>
160166
</div>

InteractiveHtmlBom/web/ibom.js

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,26 @@ function setDarkMode(value) {
3434
}
3535
}
3636

37+
function layerVisible(visible, frontCavnas, backCanvas, storageString) {
38+
if (visible) {
39+
frontCavnas.style.display = "";
40+
backCanvas.style.display = "";
41+
writeStorage(storageString, true);
42+
} else {
43+
frontCavnas.style.display = "none";
44+
backCanvas.style.display = "none";
45+
writeStorage(storageString, false);
46+
}
47+
}
48+
49+
function fabricationVisible(visible) {
50+
layerVisible(visible, allcanvas.front.fab, allcanvas.back.fab, "fabricationVisible");
51+
}
52+
53+
function silkscreenVisible(visible) {
54+
layerVisible(visible, allcanvas.front.silk, allcanvas.back.silk, "silkscreenVisible");
55+
}
56+
3757
function setHighlightPin1(value) {
3858
writeStorage("highlightpin1", value);
3959
highlightpin1 = value;
@@ -471,18 +491,6 @@ function updateRefLookup(input) {
471491
populateBomTable();
472492
}
473493

474-
function silkscreenVisible(visible) {
475-
if (visible) {
476-
allcanvas.front.silk.style.display = "";
477-
allcanvas.back.silk.style.display = "";
478-
writeStorage("silkscreenVisible", true);
479-
} else {
480-
allcanvas.front.silk.style.display = "none";
481-
allcanvas.back.silk.style.display = "none";
482-
writeStorage("silkscreenVisible", false);
483-
}
484-
}
485-
486494
function changeCanvasLayout(layout) {
487495
document.getElementById("fl-btn").classList.remove("depressed");
488496
document.getElementById("fb-btn").classList.remove("depressed");
@@ -723,7 +731,16 @@ function initDefaults() {
723731
}
724732
document.getElementById("bomCheckboxes").value = bomCheckboxes;
725733

726-
var b = readStorage("silkscreenVisible");
734+
var b = readStorage("fabricationVisible");
735+
if (b === null) {
736+
b = config.show_fabrication;
737+
} else {
738+
b = (b == "true");
739+
}
740+
document.getElementById("fabricationCheckbox").checked = b;
741+
fabricationVisible(b);
742+
743+
b = readStorage("silkscreenVisible");
727744
if (b === null) {
728745
b = config.show_silkscreen;
729746
} else {

InteractiveHtmlBom/web/render.js

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function drawtext(ctx, text, color, flip) {
3333
var interline = (text.height * 1.5 + text.thickness) / 2;
3434
var txt = text.text.split("\n");
3535
// KiCad ignores last empty line.
36-
if (txt[txt.length-1] == '') txt.pop();
36+
if (txt[txt.length - 1] == '') txt.pop();
3737
ctx.rotate(deg2rad(angle));
3838
ctx.fillStyle = color;
3939
ctx.strokeStyle = color;
@@ -262,15 +262,15 @@ function drawModules(canvas, layer, scalefactor, highlight) {
262262
}
263263
}
264264

265-
function drawSilkscreen(canvas, layer, scalefactor) {
265+
function drawBgLayer(layername, canvas, layer, scalefactor, edgeColor, polygonColor, textColor) {
266266
var ctx = canvas.getContext("2d");
267-
for (var d of pcbdata.silkscreen[layer]) {
267+
for (var d of pcbdata[layername][layer]) {
268268
if (["segment", "arc", "circle"].includes(d.type)) {
269-
drawedge(ctx, scalefactor, d, "#aa4");
269+
drawedge(ctx, scalefactor, d, edgeColor);
270270
} else if (d.type == "polygon") {
271-
drawPolygonShape(ctx, d, "#4aa");
271+
drawPolygonShape(ctx, d, polygonColor);
272272
} else {
273-
drawtext(ctx, d, "#4aa", layer == "B");
273+
drawtext(ctx, d, textColor, layer == "B");
274274
}
275275
}
276276
}
@@ -296,11 +296,26 @@ function drawHighlights() {
296296

297297
function drawBackground(canvasdict) {
298298
clearCanvas(canvasdict.bg);
299+
clearCanvas(canvasdict.fab);
299300
clearCanvas(canvasdict.silk);
300301
drawEdges(canvasdict.bg, canvasdict.transform.s);
301302
drawModules(canvasdict.bg, canvasdict.layer,
302303
canvasdict.transform.s * canvasdict.transform.zoom, false);
303-
drawSilkscreen(canvasdict.silk, canvasdict.layer, canvasdict.transform.s);
304+
305+
var style = getComputedStyle(topmostdiv);
306+
var edgeColor = style.getPropertyValue('--silkscreen-edge-color');
307+
var polygonColor = style.getPropertyValue('--silkscreen-polygon-color');
308+
var textColor = style.getPropertyValue('--silkscreen-text-color');
309+
drawBgLayer(
310+
"silkscreen", canvasdict.silk, canvasdict.layer, canvasdict.transform.s,
311+
edgeColor, polygonColor, textColor);
312+
313+
edgeColor = style.getPropertyValue('--fabrication-edge-color');
314+
polygonColor = style.getPropertyValue('--fabrication-polygon-color');
315+
textColor = style.getPropertyValue('--fabrication-text-color');
316+
drawBgLayer(
317+
"fabrication", canvasdict.fab, canvasdict.layer, canvasdict.transform.s,
318+
edgeColor, polygonColor, textColor);
304319
}
305320

306321
function prepareCanvas(canvas, flip, transform) {
@@ -319,7 +334,7 @@ function prepareCanvas(canvas, flip, transform) {
319334

320335
function prepareLayer(canvasdict) {
321336
var flip = (canvasdict.layer == "B");
322-
for (var c of ["bg", "silk", "highlight"]) {
337+
for (var c of ["bg", "fab", "silk", "highlight"]) {
323338
prepareCanvas(canvasdict[c], flip, canvasdict.transform);
324339
}
325340
}
@@ -371,7 +386,7 @@ function recalcLayerScale(canvasdict) {
371386
canvasdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor - width) * 0.5;
372387
}
373388
canvasdict.transform.y = -((bbox.maxy + bbox.miny) * scalefactor - height) * 0.5;
374-
for (var c of ["bg", "silk", "highlight"]) {
389+
for (var c of ["bg", "fab", "silk", "highlight"]) {
375390
canvas = canvasdict[c];
376391
canvas.width = width;
377392
canvas.height = height;
@@ -523,7 +538,7 @@ function addMouseHandlers(div, layerdict) {
523538
div.onwheel = function(e) {
524539
handleMouseWheel(e, layerdict);
525540
}
526-
for (var element of [div, layerdict.bg, layerdict.silk, layerdict.highlight]) {
541+
for (var element of [div, layerdict.bg, layerdict.fab, layerdict.silk, layerdict.highlight]) {
527542
element.addEventListener("contextmenu", function(e) {
528543
e.preventDefault();
529544
}, false);
@@ -557,6 +572,7 @@ function initRender() {
557572
mousedown: false,
558573
},
559574
bg: document.getElementById("F_bg"),
575+
fab: document.getElementById("F_fab"),
560576
silk: document.getElementById("F_slk"),
561577
highlight: document.getElementById("F_hl"),
562578
layer: "F",
@@ -574,6 +590,7 @@ function initRender() {
574590
mousedown: false,
575591
},
576592
bg: document.getElementById("B_bg"),
593+
fab: document.getElementById("B_fab"),
577594
silk: document.getElementById("B_slk"),
578595
highlight: document.getElementById("B_hl"),
579596
layer: "B",

0 commit comments

Comments
 (0)