InteractiveHtmlBom 2.10.0__tar.gz → 2.11.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/DATAFORMAT.md +4 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/__init__.py +2 -2
- interactivehtmlbom-2.11.1/InteractiveHtmlBom/compat.py +23 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/core/config.py +31 -9
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/core/ibom.py +8 -6
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/dialog_base.py +8 -1
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/settings_dialog.py +4 -1
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/kicad.py +67 -26
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/schema/genericjsonpcbdata_v1.schema +14 -3
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/generate_interactive_bom.py +19 -10
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/version.py +1 -1
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/render.js +7 -2
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/table-util.js +1 -1
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/util.js +4 -1
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/PKG-INFO +1 -1
- interactivehtmlbom-2.11.1/make_release.py +158 -0
- interactivehtmlbom-2.11.1/settings_dialog.fbp +3978 -0
- interactivehtmlbom-2.10.0/settings_dialog.fbp +0 -3859
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/.github/workflows/ci.yml +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/.github/workflows/release.yml +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/.gitignore +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/.jsbeautifyrc +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/.gitattributes +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/Run.bat +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/core/__init__.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/core/fontparser.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/core/lzstring.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/core/newstroke_font.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/core/units.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/__init__.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/bitmaps/btn-arrow-down.png +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/bitmaps/btn-arrow-up.png +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/bitmaps/btn-minus.png +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/bitmaps/btn-plus.png +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/bitmaps/btn-question.png +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog_test.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/__init__.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/common.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/easyeda.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/fusion_eagle.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/genericjson.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/kicad_extra/__init__.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/kicad_extra/netlistparser.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/kicad_extra/parser_base.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/kicad_extra/sexpressions.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/kicad_extra/xmlparser.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/ecad/svgpath.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/errors.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/i18n/language_en.bat +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/i18n/language_zh.bat +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/icon.png +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/ibom.css +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/ibom.html +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/ibom.js +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/lz-string.js +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/pep.js +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/split.js +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/LICENSE +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/README.md +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/__init__.py +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/baseline-settings-20px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/bom-grouped-32px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/bom-left-right-32px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/bom-netlist-32px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/bom-only-32px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/bom-top-bot-32px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/bom-ungrouped-32px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/btn-arrow-down.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/btn-arrow-up.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/btn-minus.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/btn-plus.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/btn-question.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/copy-48px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/io-36px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/plugin.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/plugin_icon_big.png +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/icons/stats-36px.svg +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/pyproject.toml +0 -0
- {interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/tests/test_module.py +0 -0
|
@@ -96,6 +96,7 @@ pcbdata = {
|
|
|
96
96
|
"revision": "rev",
|
|
97
97
|
"company": "Horns and Hoofs",
|
|
98
98
|
"date": "2019-04-18",
|
|
99
|
+
"variant": "var" // optional
|
|
99
100
|
},
|
|
100
101
|
// Contains full bom table as well as filtered by front/back.
|
|
101
102
|
// See bom row description below.
|
|
@@ -258,7 +259,10 @@ attribute.
|
|
|
258
259
|
// 0: justify center
|
|
259
260
|
// 1: justify right/bot
|
|
260
261
|
"justify": [horizontal, vertical],
|
|
262
|
+
// Either the thickness or the fillrule must be used
|
|
261
263
|
"thickness": thickness,
|
|
264
|
+
// fillrule is only supported for svgpath
|
|
265
|
+
"fillrule": "nonzero" | "evenodd",
|
|
262
266
|
"attr": [
|
|
263
267
|
// may include none, one or both
|
|
264
268
|
"italic", "mirrored"
|
|
@@ -3,11 +3,11 @@ import sys
|
|
|
3
3
|
import threading
|
|
4
4
|
import time
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import wx.aui
|
|
6
|
+
from .compat import get_wx
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
def check_for_bom_button():
|
|
10
|
+
wx = get_wx()
|
|
11
11
|
# From Miles McCoo's blog
|
|
12
12
|
# https://kicad.mmccoo.com/2017/03/05/adding-your-own-command-buttons-to-the-pcbnew-gui/
|
|
13
13
|
def find_pcbnew_window():
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Compatibility utilities for optional wx dependency."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
_wx = None
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def should_create_wx_app():
|
|
9
|
+
"""Check if we should create a wx app based on environment."""
|
|
10
|
+
return 'INTERACTIVE_HTML_BOM_NO_DISPLAY' not in os.environ
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_wx():
|
|
14
|
+
"""Get the wx module, or None if not available."""
|
|
15
|
+
global _wx
|
|
16
|
+
if _wx is not None:
|
|
17
|
+
return _wx
|
|
18
|
+
try:
|
|
19
|
+
import wx
|
|
20
|
+
_wx = wx
|
|
21
|
+
return _wx
|
|
22
|
+
except ImportError:
|
|
23
|
+
return None
|
|
@@ -4,9 +4,7 @@ import argparse
|
|
|
4
4
|
import os
|
|
5
5
|
import re
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
|
|
9
|
-
from .. import dialog
|
|
7
|
+
from ..compat import get_wx
|
|
10
8
|
|
|
11
9
|
|
|
12
10
|
class Config:
|
|
@@ -17,6 +15,8 @@ class Config:
|
|
|
17
15
|
' %p : pcb/project title from pcb metadata.\n'
|
|
18
16
|
' %c : company from pcb metadata.\n'
|
|
19
17
|
' %r : revision from pcb metadata.\n'
|
|
18
|
+
' %v : pcb variant.\n'
|
|
19
|
+
' %V : pcb variant or \'default\', if empty.\n'
|
|
20
20
|
' %d : pcb date from metadata if available, '
|
|
21
21
|
'file modification date otherwise.\n'
|
|
22
22
|
' %D : bom generation date.\n'
|
|
@@ -39,7 +39,7 @@ class Config:
|
|
|
39
39
|
'dark_mode', 'show_pads', 'show_fabrication', 'show_silkscreen',
|
|
40
40
|
'highlight_pin1', 'redraw_on_drag', 'board_rotation', 'checkboxes',
|
|
41
41
|
'bom_view', 'layer_view', 'offset_back_rotation',
|
|
42
|
-
'kicad_text_formatting'
|
|
42
|
+
'kicad_text_formatting', 'mark_when_checked'
|
|
43
43
|
]
|
|
44
44
|
default_show_group_fields = ["Value", "Footprint"]
|
|
45
45
|
|
|
@@ -55,13 +55,14 @@ class Config:
|
|
|
55
55
|
board_rotation = 0
|
|
56
56
|
offset_back_rotation = False
|
|
57
57
|
checkboxes = ','.join(default_checkboxes)
|
|
58
|
+
mark_when_checked = ''
|
|
58
59
|
bom_view = bom_view_choices[1]
|
|
59
60
|
layer_view = layer_view_choices[1]
|
|
60
61
|
compression = True
|
|
61
62
|
open_browser = True
|
|
62
63
|
|
|
63
64
|
# General section
|
|
64
|
-
bom_dest_dir = 'bom
|
|
65
|
+
bom_dest_dir = 'bom' # This is relative to pcb file directory
|
|
65
66
|
bom_name_format = 'ibom'
|
|
66
67
|
component_sort_order = default_sort_order
|
|
67
68
|
component_blacklist = []
|
|
@@ -82,6 +83,9 @@ class Config:
|
|
|
82
83
|
board_variant_blacklist = []
|
|
83
84
|
dnp_field = ''
|
|
84
85
|
|
|
86
|
+
# this is cli only field
|
|
87
|
+
kicad_variant = ''
|
|
88
|
+
|
|
85
89
|
@staticmethod
|
|
86
90
|
def _split(s):
|
|
87
91
|
"""Splits string by ',' and drops empty strings from resulting array"""
|
|
@@ -106,7 +110,7 @@ class Config:
|
|
|
106
110
|
else:
|
|
107
111
|
return
|
|
108
112
|
|
|
109
|
-
f = FileConfig(localFilename=file)
|
|
113
|
+
f = get_wx().FileConfig(localFilename=file)
|
|
110
114
|
|
|
111
115
|
f.SetPath('/html_defaults')
|
|
112
116
|
self.dark_mode = f.ReadBool('dark_mode', self.dark_mode)
|
|
@@ -121,6 +125,7 @@ class Config:
|
|
|
121
125
|
self.offset_back_rotation = f.ReadBool(
|
|
122
126
|
'offset_back_rotation', self.offset_back_rotation)
|
|
123
127
|
self.checkboxes = f.Read('checkboxes', self.checkboxes)
|
|
128
|
+
self.mark_when_checked = f.Read('mark_when_checked', self.mark_when_checked)
|
|
124
129
|
self.bom_view = f.Read('bom_view', self.bom_view)
|
|
125
130
|
self.layer_view = f.Read('layer_view', self.layer_view)
|
|
126
131
|
self.compression = f.ReadBool('compression', self.compression)
|
|
@@ -168,7 +173,7 @@ class Config:
|
|
|
168
173
|
def save(self, locally):
|
|
169
174
|
file = self.local_config_file if locally else self.global_config_file
|
|
170
175
|
print('Saving to', file)
|
|
171
|
-
f = FileConfig(localFilename=file)
|
|
176
|
+
f = get_wx().FileConfig(localFilename=file)
|
|
172
177
|
|
|
173
178
|
f.SetPath('/html_defaults')
|
|
174
179
|
f.WriteBool('dark_mode', self.dark_mode)
|
|
@@ -180,6 +185,7 @@ class Config:
|
|
|
180
185
|
f.WriteInt('board_rotation', self.board_rotation)
|
|
181
186
|
f.WriteBool('offset_back_rotation', self.offset_back_rotation)
|
|
182
187
|
f.Write('checkboxes', self.checkboxes)
|
|
188
|
+
f.Write('mark_when_checked', self.mark_when_checked)
|
|
183
189
|
f.Write('bom_view', self.bom_view)
|
|
184
190
|
f.Write('layer_view', self.layer_view)
|
|
185
191
|
f.WriteBool('compression', self.compression)
|
|
@@ -226,6 +232,7 @@ class Config:
|
|
|
226
232
|
self.offset_back_rotation = \
|
|
227
233
|
dlg.html.offsetBackRotationCheckbox.IsChecked()
|
|
228
234
|
self.checkboxes = dlg.html.bomCheckboxesCtrl.Value
|
|
235
|
+
# No dialog for mark_when_checked ...
|
|
229
236
|
self.bom_view = self.bom_view_choices[dlg.html.bomDefaultView.Selection]
|
|
230
237
|
self.layer_view = self.layer_view_choices[
|
|
231
238
|
dlg.html.layerDefaultView.Selection]
|
|
@@ -275,6 +282,7 @@ class Config:
|
|
|
275
282
|
dlg.html.boardRotationSlider.Value = self.board_rotation
|
|
276
283
|
dlg.html.offsetBackRotationCheckbox.Value = self.offset_back_rotation
|
|
277
284
|
dlg.html.bomCheckboxesCtrl.Value = self.checkboxes
|
|
285
|
+
# No dialog for mark_when_checked ...
|
|
278
286
|
dlg.html.bomDefaultView.Selection = self.bom_view_choices.index(
|
|
279
287
|
self.bom_view)
|
|
280
288
|
dlg.html.layerDefaultView.Selection = self.layer_view_choices.index(
|
|
@@ -320,14 +328,21 @@ class Config:
|
|
|
320
328
|
self.board_variant_blacklist)
|
|
321
329
|
dlg.fields.dnpFieldBox.Value = self.dnp_field
|
|
322
330
|
|
|
331
|
+
if self.kicad_variant != '':
|
|
332
|
+
dlg.fields.variantLabel.Show()
|
|
333
|
+
dlg.fields.variantLabel.SetLabel(f'Current variant: {self.kicad_variant}')
|
|
334
|
+
|
|
323
335
|
dlg.finish_init()
|
|
324
336
|
|
|
325
337
|
@classmethod
|
|
326
338
|
def add_options(cls, parser, version):
|
|
327
339
|
# type: (argparse.ArgumentParser, str) -> None
|
|
328
340
|
parser.add_argument('--show-dialog', action='store_true',
|
|
329
|
-
help='Shows config dialog. All
|
|
330
|
-
'will be ignored.')
|
|
341
|
+
help='Shows config dialog. All flags except '
|
|
342
|
+
'--kicad-variant will be ignored.')
|
|
343
|
+
parser.add_argument('--kicad-variant', default='',
|
|
344
|
+
help='KiCad board variant, empty is default '
|
|
345
|
+
'variant. (Only for KiCad v10+)')
|
|
331
346
|
parser.add_argument('--version', action='version', version=version)
|
|
332
347
|
# Html
|
|
333
348
|
parser.add_argument('--dark-mode', help='Default to dark mode.',
|
|
@@ -360,6 +375,10 @@ class Config:
|
|
|
360
375
|
parser.add_argument('--checkboxes',
|
|
361
376
|
default=cls.checkboxes,
|
|
362
377
|
help='Comma separated list of checkbox columns.')
|
|
378
|
+
parser.add_argument('--mark-when-checked',
|
|
379
|
+
default=cls.mark_when_checked,
|
|
380
|
+
help='Name of the checkbox column used to mark '
|
|
381
|
+
'components when checked.')
|
|
363
382
|
parser.add_argument('--bom-view', default=cls.bom_view,
|
|
364
383
|
choices=cls.bom_view_choices,
|
|
365
384
|
help='Default BOM view.')
|
|
@@ -436,6 +455,8 @@ class Config:
|
|
|
436
455
|
# type: (argparse.Namespace) -> None
|
|
437
456
|
import math
|
|
438
457
|
|
|
458
|
+
self.kicad_variant = args.kicad_variant
|
|
459
|
+
|
|
439
460
|
# Html
|
|
440
461
|
self.dark_mode = args.dark_mode
|
|
441
462
|
self.show_pads = not args.hide_pads
|
|
@@ -446,6 +467,7 @@ class Config:
|
|
|
446
467
|
self.board_rotation = math.fmod(args.board_rotation // 5, 37)
|
|
447
468
|
self.offset_back_rotation = args.offset_back_rotation
|
|
448
469
|
self.checkboxes = args.checkboxes
|
|
470
|
+
self.mark_when_checked = args.mark_when_checked
|
|
449
471
|
self.bom_view = args.bom_view
|
|
450
472
|
self.layer_view = args.layer_view
|
|
451
473
|
self.compression = not args.no_compression
|
|
@@ -8,13 +8,11 @@ import re
|
|
|
8
8
|
import sys
|
|
9
9
|
from datetime import datetime
|
|
10
10
|
|
|
11
|
-
import wx
|
|
12
|
-
|
|
13
11
|
from . import units
|
|
14
12
|
from .config import Config
|
|
15
|
-
from ..dialog import SettingsDialog
|
|
16
13
|
from ..ecad.common import EcadParser, Component
|
|
17
14
|
from ..errors import ParsingException
|
|
15
|
+
from ..compat import get_wx
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
class Logger(object):
|
|
@@ -38,13 +36,13 @@ class Logger(object):
|
|
|
38
36
|
if self.cli:
|
|
39
37
|
self.logger.error(msg)
|
|
40
38
|
else:
|
|
41
|
-
|
|
39
|
+
get_wx().MessageBox(msg)
|
|
42
40
|
|
|
43
41
|
def warn(self, msg):
|
|
44
42
|
if self.cli:
|
|
45
43
|
self.logger.warning(msg)
|
|
46
44
|
else:
|
|
47
|
-
|
|
45
|
+
get_wx().LogWarning(msg)
|
|
48
46
|
|
|
49
47
|
|
|
50
48
|
log = None
|
|
@@ -234,6 +232,8 @@ def process_substitutions(bom_name_format, pcb_file_name, metadata):
|
|
|
234
232
|
name = name.replace('%c', metadata['company'])
|
|
235
233
|
name = name.replace('%r', metadata['revision'])
|
|
236
234
|
name = name.replace('%d', metadata['date'].replace(':', '-'))
|
|
235
|
+
name = name.replace('%v', metadata.get('variant', ''))
|
|
236
|
+
name = name.replace('%V', metadata.get('variant', '') or 'default')
|
|
237
237
|
now = datetime.now()
|
|
238
238
|
name = name.replace('%D', now.strftime('%Y-%m-%d'))
|
|
239
239
|
name = name.replace('%T', now.strftime('%H-%M-%S'))
|
|
@@ -341,6 +341,8 @@ def main(parser, config, logger):
|
|
|
341
341
|
|
|
342
342
|
def run_with_dialog(parser, config, logger):
|
|
343
343
|
# type: (EcadParser, Config, Logger) -> None
|
|
344
|
+
from ..dialog import SettingsDialog
|
|
345
|
+
|
|
344
346
|
def save_config(dialog_panel, locally=False):
|
|
345
347
|
config.set_from_dialog(dialog_panel)
|
|
346
348
|
config.save(locally)
|
|
@@ -358,7 +360,7 @@ def run_with_dialog(parser, config, logger):
|
|
|
358
360
|
if extra_data_file is not None:
|
|
359
361
|
dlg.set_extra_data_path(extra_data_file)
|
|
360
362
|
config.transfer_to_dialog(dlg.panel)
|
|
361
|
-
if dlg.ShowModal() ==
|
|
363
|
+
if dlg.ShowModal() == get_wx().ID_OK:
|
|
362
364
|
config.set_from_dialog(dlg.panel)
|
|
363
365
|
main(parser, config, logger)
|
|
364
366
|
finally:
|
{interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/dialog_base.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
3
|
###########################################################################
|
|
4
|
-
## Python code generated with wxFormBuilder (version
|
|
4
|
+
## Python code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
|
|
5
5
|
## http://www.wxformbuilder.org/
|
|
6
6
|
##
|
|
7
7
|
## PLEASE DO *NOT* EDIT THIS FILE!
|
|
@@ -413,6 +413,13 @@ class FieldsPanelBase ( wx.Panel ):
|
|
|
413
413
|
self.extraDataFilePicker = wx.FilePickerCtrl( sbSizer7.GetStaticBox(), wx.ID_ANY, wx.EmptyString, u"Select a file", u"Netlist and xml files (*.net; *.xml)|*.net;*.xml", wx.DefaultPosition, wx.DefaultSize, wx.FLP_DEFAULT_STYLE|wx.FLP_FILE_MUST_EXIST|wx.FLP_OPEN|wx.FLP_SMALL|wx.FLP_USE_TEXTCTRL|wx.BORDER_SIMPLE )
|
|
414
414
|
sbSizer7.Add( self.extraDataFilePicker, 0, wx.EXPAND|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 )
|
|
415
415
|
|
|
416
|
+
self.variantLabel = wx.StaticText( sbSizer7.GetStaticBox(), wx.ID_ANY, u"Current variant:", wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
417
|
+
self.variantLabel.Wrap( -1 )
|
|
418
|
+
|
|
419
|
+
self.variantLabel.Hide()
|
|
420
|
+
|
|
421
|
+
sbSizer7.Add( self.variantLabel, 0, wx.ALL, 5 )
|
|
422
|
+
|
|
416
423
|
|
|
417
424
|
bSizer42.Add( sbSizer7, 0, wx.ALL|wx.EXPAND, 5 )
|
|
418
425
|
|
{interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/dialog/settings_dialog.py
RENAMED
|
@@ -334,8 +334,11 @@ class FieldsPanel(dialog_base.FieldsPanelBase):
|
|
|
334
334
|
self.extra_field_data = self.extra_data_func(
|
|
335
335
|
extra_data_file, self.normalizeCaseCheckbox.Value)
|
|
336
336
|
except Exception as e:
|
|
337
|
+
import traceback
|
|
337
338
|
pop_error(
|
|
338
|
-
"Failed to parse file %s\n\n%s" % (
|
|
339
|
+
"Failed to parse file %s\n\n%s" % (
|
|
340
|
+
extra_data_file,
|
|
341
|
+
str(e) + '\n' + traceback.format_exc()))
|
|
339
342
|
self.extraDataFilePicker.Path = ''
|
|
340
343
|
|
|
341
344
|
if self.extra_field_data is not None:
|
|
@@ -30,10 +30,16 @@ class PcbnewParser(EcadParser):
|
|
|
30
30
|
self.board = board
|
|
31
31
|
if self.board is None:
|
|
32
32
|
self.board = pcbnew.LoadBoard(self.file_name) # type: pcbnew.BOARD
|
|
33
|
+
if not self.board:
|
|
34
|
+
raise Exception('Failed to load board file')
|
|
35
|
+
if hasattr(self.board, "SetCurrentVariant"):
|
|
36
|
+
self.board.SetCurrentVariant(config.kicad_variant)
|
|
33
37
|
if hasattr(self.board, 'GetModules'):
|
|
34
|
-
|
|
38
|
+
# type: list[pcbnew.MODULE]
|
|
39
|
+
self.footprints = list(self.board.GetModules())
|
|
35
40
|
else:
|
|
36
|
-
|
|
41
|
+
# type: list[pcbnew.FOOTPRINT]
|
|
42
|
+
self.footprints = list(self.board.GetFootprints())
|
|
37
43
|
self.font_parser = FontParser()
|
|
38
44
|
|
|
39
45
|
def get_extra_field_data(self, file_name):
|
|
@@ -46,8 +52,7 @@ class PcbnewParser(EcadParser):
|
|
|
46
52
|
|
|
47
53
|
return ExtraFieldData(data[0], data[1])
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
def get_footprint_fields(f):
|
|
55
|
+
def get_footprint_fields(self, f):
|
|
51
56
|
# type: (pcbnew.FOOTPRINT) -> dict
|
|
52
57
|
props = {}
|
|
53
58
|
if hasattr(f, "GetProperties"):
|
|
@@ -60,6 +65,15 @@ class PcbnewParser(EcadParser):
|
|
|
60
65
|
if hasattr(f, "IsDNP"):
|
|
61
66
|
if f.IsDNP():
|
|
62
67
|
props["kicad_dnp"] = "DNP"
|
|
68
|
+
if hasattr(f, 'GetVariant'):
|
|
69
|
+
variant = f.GetVariant(self.config.kicad_variant)
|
|
70
|
+
if variant:
|
|
71
|
+
var_fields = variant.GetFields()
|
|
72
|
+
for k in var_fields.keys():
|
|
73
|
+
props[str(k)] = str(f.GetFieldShownText(str(k)))
|
|
74
|
+
if variant.GetDNP():
|
|
75
|
+
props["kicad_dnp"] = "DNP"
|
|
76
|
+
|
|
63
77
|
return props
|
|
64
78
|
|
|
65
79
|
def parse_extra_data_from_pcb(self):
|
|
@@ -209,7 +223,8 @@ class PcbnewParser(EcadParser):
|
|
|
209
223
|
"angle": angle,
|
|
210
224
|
"polygons": polygons
|
|
211
225
|
}
|
|
212
|
-
if hasattr(d, "IsFilled") and not d.IsFilled()
|
|
226
|
+
if ((hasattr(d, "IsFilled") and not d.IsFilled()) or
|
|
227
|
+
(hasattr(d, "IsSolidFill") and not d.IsSolidFill())):
|
|
213
228
|
shape_dict["filled"] = 0
|
|
214
229
|
shape_dict["width"] = d.GetWidth() * 1e-6
|
|
215
230
|
return shape_dict
|
|
@@ -273,7 +288,8 @@ class PcbnewParser(EcadParser):
|
|
|
273
288
|
"svgpath": create_path(lines)
|
|
274
289
|
}
|
|
275
290
|
elif hasattr(d, 'GetEffectiveTextShape'):
|
|
276
|
-
|
|
291
|
+
# type: pcbnew.SHAPE_COMPOUND
|
|
292
|
+
shape = d.GetEffectiveTextShape(False)
|
|
277
293
|
segments = []
|
|
278
294
|
polygons = []
|
|
279
295
|
for s in shape.GetSubshapes():
|
|
@@ -426,7 +442,7 @@ class PcbnewParser(EcadParser):
|
|
|
426
442
|
for d in f.GraphicalItems():
|
|
427
443
|
drawings.append((d.GetClass(), d))
|
|
428
444
|
if hasattr(f, "GetFields"):
|
|
429
|
-
fields = f.GetFields()
|
|
445
|
+
fields = f.GetFields() # type: list[pcbnew.PCB_FIELD]
|
|
430
446
|
for field in fields:
|
|
431
447
|
if field.IsReference() or field.IsValue():
|
|
432
448
|
continue
|
|
@@ -434,16 +450,31 @@ class PcbnewParser(EcadParser):
|
|
|
434
450
|
|
|
435
451
|
return drawings
|
|
436
452
|
|
|
453
|
+
@staticmethod
|
|
454
|
+
def _pad_is_through_hole(pad):
|
|
455
|
+
# type: (pcbnew.PAD) -> bool
|
|
456
|
+
if hasattr(pcbnew, 'PAD_ATTRIB_PTH'):
|
|
457
|
+
through_hole_attributes = [pcbnew.PAD_ATTRIB_PTH,
|
|
458
|
+
pcbnew.PAD_ATTRIB_NPTH]
|
|
459
|
+
else:
|
|
460
|
+
through_hole_attributes = [pcbnew.PAD_ATTRIB_STANDARD,
|
|
461
|
+
pcbnew.PAD_ATTRIB_HOLE_NOT_PLATED]
|
|
462
|
+
return pad.GetAttribute() in through_hole_attributes
|
|
463
|
+
|
|
437
464
|
def parse_pad(self, pad):
|
|
438
465
|
# type: (pcbnew.PAD) -> list[dict]
|
|
439
466
|
custom_padstack = False
|
|
440
467
|
outer_layers = [(pcbnew.F_Cu, "F"), (pcbnew.B_Cu, "B")]
|
|
441
468
|
if hasattr(pad, 'Padstack'):
|
|
442
|
-
padstack = pad.Padstack()
|
|
469
|
+
padstack = pad.Padstack() # type: pcbnew.PADSTACK
|
|
443
470
|
layers_set = list(padstack.LayerSet().Seq())
|
|
471
|
+
if hasattr(pcbnew, "UNCONNECTED_LAYER_MODE_REMOVE_ALL"):
|
|
472
|
+
ULMRA = pcbnew.UNCONNECTED_LAYER_MODE_REMOVE_ALL
|
|
473
|
+
else:
|
|
474
|
+
ULMRA = padstack.UNCONNECTED_LAYER_MODE_REMOVE_ALL
|
|
444
475
|
custom_padstack = (
|
|
445
|
-
padstack.Mode() != padstack.MODE_NORMAL or
|
|
446
|
-
|
|
476
|
+
padstack.Mode() != padstack.MODE_NORMAL or
|
|
477
|
+
padstack.UnconnectedLayerMode() == ULMRA
|
|
447
478
|
)
|
|
448
479
|
else:
|
|
449
480
|
layers_set = list(pad.GetLayerSet().Seq())
|
|
@@ -451,7 +482,7 @@ class PcbnewParser(EcadParser):
|
|
|
451
482
|
for layer, letter in outer_layers:
|
|
452
483
|
if layer in layers_set:
|
|
453
484
|
layers.append(letter)
|
|
454
|
-
if not layers:
|
|
485
|
+
if not layers and not self._pad_is_through_hole(pad):
|
|
455
486
|
return []
|
|
456
487
|
|
|
457
488
|
if custom_padstack:
|
|
@@ -537,13 +568,8 @@ class PcbnewParser(EcadParser):
|
|
|
537
568
|
except TypeError:
|
|
538
569
|
pad_dict["chamfpos"] = pad.GetChamferPositions()
|
|
539
570
|
pad_dict["chamfratio"] = pad.GetChamferRectRatio()
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
pcbnew.PAD_ATTRIB_NPTH]
|
|
543
|
-
else:
|
|
544
|
-
through_hole_attributes = [pcbnew.PAD_ATTRIB_STANDARD,
|
|
545
|
-
pcbnew.PAD_ATTRIB_HOLE_NOT_PLATED]
|
|
546
|
-
if pad.GetAttribute() in through_hole_attributes:
|
|
571
|
+
|
|
572
|
+
if self._pad_is_through_hole(pad):
|
|
547
573
|
pad_dict["type"] = "th"
|
|
548
574
|
pad_dict["drillshape"] = {
|
|
549
575
|
pcbnew.PAD_DRILL_SHAPE_CIRCLE: "circle",
|
|
@@ -552,6 +578,7 @@ class PcbnewParser(EcadParser):
|
|
|
552
578
|
pad_dict["drillsize"] = self.normalize(pad.GetDrillSize())
|
|
553
579
|
else:
|
|
554
580
|
pad_dict["type"] = "smd"
|
|
581
|
+
|
|
555
582
|
if hasattr(pad, "GetOffset"):
|
|
556
583
|
try:
|
|
557
584
|
pad_dict["offset"] = self.normalize(pad.GetOffset(layer))
|
|
@@ -708,6 +735,8 @@ class PcbnewParser(EcadParser):
|
|
|
708
735
|
if (hasattr(zone, 'GetFilledPolysUseThickness') and
|
|
709
736
|
not zone.GetFilledPolysUseThickness()):
|
|
710
737
|
width = 0
|
|
738
|
+
if KICAD_VERSION[0] >= 7:
|
|
739
|
+
width = 0
|
|
711
740
|
zone_dict = {
|
|
712
741
|
"polygons": self.parse_poly_set(poly_set),
|
|
713
742
|
"width": width,
|
|
@@ -728,16 +757,24 @@ class PcbnewParser(EcadParser):
|
|
|
728
757
|
nets = sorted([str(s) for s in nets])
|
|
729
758
|
return nets
|
|
730
759
|
|
|
731
|
-
|
|
732
|
-
|
|
760
|
+
def footprint_to_component(self, footprint, extra_fields):
|
|
761
|
+
# type: (pcbnew.FOOTPRINT, list) -> Component
|
|
733
762
|
try:
|
|
734
763
|
footprint_name = str(footprint.GetFPID().GetFootprintName())
|
|
735
764
|
except AttributeError:
|
|
736
765
|
footprint_name = str(footprint.GetFPID().GetLibItemName())
|
|
737
766
|
|
|
767
|
+
value = footprint.GetValue()
|
|
768
|
+
if hasattr(footprint, 'GetFieldValueForVariant'):
|
|
769
|
+
value = footprint.GetFieldValueForVariant(
|
|
770
|
+
self.config.kicad_variant, 'Value')
|
|
738
771
|
attr = 'Normal'
|
|
739
772
|
if hasattr(pcbnew, 'FP_EXCLUDE_FROM_BOM'):
|
|
740
|
-
if footprint
|
|
773
|
+
if hasattr(footprint, 'GetExcludedFromBOMForVariant'):
|
|
774
|
+
if footprint.GetExcludedFromBOMForVariant(
|
|
775
|
+
self.config.kicad_variant):
|
|
776
|
+
attr = 'Virtual'
|
|
777
|
+
elif footprint.GetAttributes() & pcbnew.FP_EXCLUDE_FROM_BOM:
|
|
741
778
|
attr = 'Virtual'
|
|
742
779
|
elif hasattr(pcbnew, 'MOD_VIRTUAL'):
|
|
743
780
|
if footprint.GetAttributes() == pcbnew.MOD_VIRTUAL:
|
|
@@ -748,7 +785,7 @@ class PcbnewParser(EcadParser):
|
|
|
748
785
|
}.get(footprint.GetLayer())
|
|
749
786
|
|
|
750
787
|
return Component(footprint.GetReference(),
|
|
751
|
-
|
|
788
|
+
value,
|
|
752
789
|
footprint_name,
|
|
753
790
|
layer,
|
|
754
791
|
attr,
|
|
@@ -767,9 +804,9 @@ class PcbnewParser(EcadParser):
|
|
|
767
804
|
self.config.dnp_field)
|
|
768
805
|
|
|
769
806
|
if not self.config.extra_data_file and need_extra_fields:
|
|
770
|
-
self.
|
|
771
|
-
|
|
772
|
-
|
|
807
|
+
self.config.extra_data_file = self.file_name
|
|
808
|
+
self.logger.warn('Assuming extra data file to be the pcb file '
|
|
809
|
+
'since --extra-data-file was not specified.')
|
|
773
810
|
|
|
774
811
|
extra_field_data = None
|
|
775
812
|
if (self.config.extra_data_file and
|
|
@@ -832,6 +869,7 @@ class PcbnewParser(EcadParser):
|
|
|
832
869
|
"revision": revision,
|
|
833
870
|
"company": company,
|
|
834
871
|
"date": file_date,
|
|
872
|
+
"variant": self.config.kicad_variant,
|
|
835
873
|
},
|
|
836
874
|
"bom": {},
|
|
837
875
|
"font_data": self.font_parser.get_parsed_font()
|
|
@@ -898,7 +936,7 @@ class InteractiveHtmlBomPlugin(pcbnew.ActionPlugin, object):
|
|
|
898
936
|
from ..errors import ParsingException
|
|
899
937
|
|
|
900
938
|
logger = ibom.Logger()
|
|
901
|
-
board = pcbnew.GetBoard()
|
|
939
|
+
board = pcbnew.GetBoard() # type: pcbnew.BOARD
|
|
902
940
|
pcb_file_name = board.GetFileName()
|
|
903
941
|
|
|
904
942
|
if not pcb_file_name:
|
|
@@ -906,6 +944,9 @@ class InteractiveHtmlBomPlugin(pcbnew.ActionPlugin, object):
|
|
|
906
944
|
return
|
|
907
945
|
|
|
908
946
|
config = Config(version, os.path.dirname(pcb_file_name))
|
|
947
|
+
if hasattr(board, 'GetCurrentVariant'):
|
|
948
|
+
config.kicad_variant = board.GetCurrentVariant()
|
|
949
|
+
|
|
909
950
|
parser = PcbnewParser(pcb_file_name, config, logger, board)
|
|
910
951
|
|
|
911
952
|
try:
|
|
@@ -305,6 +305,9 @@
|
|
|
305
305
|
},
|
|
306
306
|
"date": {
|
|
307
307
|
"type": "string"
|
|
308
|
+
},
|
|
309
|
+
"variant": {
|
|
310
|
+
"type": "string"
|
|
308
311
|
}
|
|
309
312
|
},
|
|
310
313
|
"required": ["title", "revision", "company", "date"],
|
|
@@ -443,12 +446,20 @@
|
|
|
443
446
|
"properties": {
|
|
444
447
|
"svgpath": { "type": "string" },
|
|
445
448
|
"thickness": { "type": "number" },
|
|
449
|
+
"fillrule": {
|
|
450
|
+
"type": "string",
|
|
451
|
+
"enum": [
|
|
452
|
+
"nonzero",
|
|
453
|
+
"evenodd"
|
|
454
|
+
]
|
|
455
|
+
},
|
|
446
456
|
"ref": { "type": "integer" , "const": 1 },
|
|
447
457
|
"val": { "type": "integer" , "const": 1 }
|
|
448
458
|
},
|
|
449
|
-
"required": [
|
|
450
|
-
|
|
451
|
-
"thickness"
|
|
459
|
+
"required": ["svgpath"],
|
|
460
|
+
"oneOf": [
|
|
461
|
+
{ "required": ["thickness"] },
|
|
462
|
+
{ "required": ["fillrule"] }
|
|
452
463
|
],
|
|
453
464
|
"title": "DrawingText"
|
|
454
465
|
},
|
|
@@ -4,6 +4,7 @@ from __future__ import absolute_import
|
|
|
4
4
|
import argparse
|
|
5
5
|
import os
|
|
6
6
|
import sys
|
|
7
|
+
|
|
7
8
|
# Add ../ to the path
|
|
8
9
|
# Works if this script is executed without installing the module
|
|
9
10
|
script_dir = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
|
|
@@ -23,16 +24,22 @@ def to_utf(s):
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def main():
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if create_wx_app:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
from .compat import get_wx, should_create_wx_app
|
|
28
|
+
wx = get_wx()
|
|
29
|
+
create_wx_app = should_create_wx_app()
|
|
30
|
+
|
|
31
|
+
if wx is None and create_wx_app:
|
|
32
|
+
print("wxpython is required unless INTERACTIVE_HTML_BOM_NO_DISPLAY "
|
|
33
|
+
"environment variable is set")
|
|
34
|
+
sys.exit(1)
|
|
35
|
+
|
|
36
|
+
if wx is not None:
|
|
37
|
+
if create_wx_app:
|
|
38
|
+
app = wx.App()
|
|
39
|
+
if hasattr(wx, "APP_ASSERT_SUPPRESS"):
|
|
40
|
+
app.SetAssertMode(wx.APP_ASSERT_SUPPRESS)
|
|
41
|
+
elif hasattr(wx, "DisableAsserts"):
|
|
42
|
+
wx.DisableAsserts()
|
|
36
43
|
|
|
37
44
|
from .core import ibom
|
|
38
45
|
from .core.config import Config
|
|
@@ -40,6 +47,7 @@ def main():
|
|
|
40
47
|
from .version import version
|
|
41
48
|
from .errors import (ExitCodes, ParsingException, exit_error)
|
|
42
49
|
|
|
50
|
+
|
|
43
51
|
parser = argparse.ArgumentParser(
|
|
44
52
|
description='KiCad InteractiveHtmlBom plugin CLI.',
|
|
45
53
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
@@ -58,6 +66,7 @@ def main():
|
|
|
58
66
|
print("Loading %s" % args.file)
|
|
59
67
|
|
|
60
68
|
config = Config(version, os.path.dirname(os.path.abspath(args.file)))
|
|
69
|
+
config.kicad_variant = args.kicad_variant
|
|
61
70
|
|
|
62
71
|
parser = get_parser_by_extension(
|
|
63
72
|
os.path.abspath(args.file), config, logger)
|
|
@@ -24,12 +24,17 @@ function drawText(ctx, text, color) {
|
|
|
24
24
|
ctx.strokeStyle = color;
|
|
25
25
|
ctx.lineCap = "round";
|
|
26
26
|
ctx.lineJoin = "round";
|
|
27
|
-
ctx.lineWidth = text.thickness;
|
|
28
27
|
if ("svgpath" in text) {
|
|
29
|
-
|
|
28
|
+
if ("thickness" in text) {
|
|
29
|
+
ctx.lineWidth = text.thickness;
|
|
30
|
+
ctx.stroke(new Path2D(text.svgpath));
|
|
31
|
+
} else if ("fillrule" in text) {
|
|
32
|
+
ctx.fill(new Path2D(text.svgpath), text.fillrule);
|
|
33
|
+
}
|
|
30
34
|
ctx.restore();
|
|
31
35
|
return;
|
|
32
36
|
}
|
|
37
|
+
ctx.lineWidth = text.thickness;
|
|
33
38
|
if ("polygons" in text) {
|
|
34
39
|
ctx.fill(getPolygonsPath(text));
|
|
35
40
|
ctx.restore();
|
{interactivehtmlbom-2.10.0 → interactivehtmlbom-2.11.1}/InteractiveHtmlBom/web/table-util.js
RENAMED
|
@@ -20,7 +20,7 @@ function setBomHandlers() {
|
|
|
20
20
|
draggingElement.remove();
|
|
21
21
|
|
|
22
22
|
// Make BOM selectable again
|
|
23
|
-
bom.style.removeProperty("
|
|
23
|
+
bom.style.removeProperty("user-select");
|
|
24
24
|
|
|
25
25
|
// Remove listeners
|
|
26
26
|
document.removeEventListener('mousemove', mouseMoveHandler);
|
|
@@ -549,7 +549,10 @@ function initDefaults() {
|
|
|
549
549
|
setHighlightPin1(highlightpin1);
|
|
550
550
|
document.forms.highlightpin1.highlightpin1.value = highlightpin1;
|
|
551
551
|
|
|
552
|
-
settings.markWhenChecked = readStorage("markWhenChecked")
|
|
552
|
+
settings.markWhenChecked = readStorage("markWhenChecked");
|
|
553
|
+
if (settings.markWhenChecked == null) {
|
|
554
|
+
settings.markWhenChecked = config.mark_when_checked;
|
|
555
|
+
}
|
|
553
556
|
populateMarkWhenCheckedOptions();
|
|
554
557
|
|
|
555
558
|
function initBooleanSetting(storageString, def, elementId, func) {
|