diff --git a/DATAFORMAT.md b/DATAFORMAT.md index c7c345b..a8d0959 100644 --- a/DATAFORMAT.md +++ b/DATAFORMAT.md @@ -96,6 +96,7 @@ pcbdata = { "revision": "rev", "company": "Horns and Hoofs", "date": "2019-04-18", + "variant": "var" // optional }, // Contains full bom table as well as filtered by front/back. // See bom row description below. @@ -258,7 +259,10 @@ attribute. // 0: justify center // 1: justify right/bot "justify": [horizontal, vertical], + // Either the thickness or the fillrule must be used "thickness": thickness, + // fillrule is only supported for svgpath + "fillrule": "nonzero" | "evenodd", "attr": [ // may include none, one or both "italic", "mirrored" diff --git a/InteractiveHtmlBom/__init__.py b/InteractiveHtmlBom/__init__.py index 276c246..f171a41 100644 --- a/InteractiveHtmlBom/__init__.py +++ b/InteractiveHtmlBom/__init__.py @@ -3,11 +3,11 @@ import threading import time -import wx -import wx.aui +from .compat import get_wx def check_for_bom_button(): + wx = get_wx() # From Miles McCoo's blog # https://kicad.mmccoo.com/2017/03/05/adding-your-own-command-buttons-to-the-pcbnew-gui/ def find_pcbnew_window(): diff --git a/InteractiveHtmlBom/compat.py b/InteractiveHtmlBom/compat.py new file mode 100644 index 0000000..cced2fa --- /dev/null +++ b/InteractiveHtmlBom/compat.py @@ -0,0 +1,23 @@ +"""Compatibility utilities for optional wx dependency.""" + +import os + +_wx = None + + +def should_create_wx_app(): + """Check if we should create a wx app based on environment.""" + return 'INTERACTIVE_HTML_BOM_NO_DISPLAY' not in os.environ + + +def get_wx(): + """Get the wx module, or None if not available.""" + global _wx + if _wx is not None: + return _wx + try: + import wx + _wx = wx + return _wx + except ImportError: + return None diff --git a/InteractiveHtmlBom/core/config.py b/InteractiveHtmlBom/core/config.py index b39d0b6..f183e20 100644 --- a/InteractiveHtmlBom/core/config.py +++ b/InteractiveHtmlBom/core/config.py @@ -4,9 +4,7 @@ import os import re -from wx import FileConfig - -from .. import dialog +from ..compat import get_wx class Config: @@ -17,6 +15,8 @@ class Config: ' %p : pcb/project title from pcb metadata.\n' ' %c : company from pcb metadata.\n' ' %r : revision from pcb metadata.\n' + ' %v : pcb variant.\n' + ' %V : pcb variant or \'default\', if empty.\n' ' %d : pcb date from metadata if available, ' 'file modification date otherwise.\n' ' %D : bom generation date.\n' @@ -39,7 +39,7 @@ class Config: 'dark_mode', 'show_pads', 'show_fabrication', 'show_silkscreen', 'highlight_pin1', 'redraw_on_drag', 'board_rotation', 'checkboxes', 'bom_view', 'layer_view', 'offset_back_rotation', - 'kicad_text_formatting' + 'kicad_text_formatting', 'mark_when_checked' ] default_show_group_fields = ["Value", "Footprint"] @@ -55,13 +55,14 @@ class Config: board_rotation = 0 offset_back_rotation = False checkboxes = ','.join(default_checkboxes) + mark_when_checked = '' bom_view = bom_view_choices[1] layer_view = layer_view_choices[1] compression = True open_browser = True # General section - bom_dest_dir = 'bom/' # This is relative to pcb file directory + bom_dest_dir = 'bom' # This is relative to pcb file directory bom_name_format = 'ibom' component_sort_order = default_sort_order component_blacklist = [] @@ -82,6 +83,9 @@ class Config: board_variant_blacklist = [] dnp_field = '' + # this is cli only field + kicad_variant = '' + @staticmethod def _split(s): """Splits string by ',' and drops empty strings from resulting array""" @@ -106,7 +110,7 @@ def load_from_ini(self): else: return - f = FileConfig(localFilename=file) + f = get_wx().FileConfig(localFilename=file) f.SetPath('/html_defaults') self.dark_mode = f.ReadBool('dark_mode', self.dark_mode) @@ -121,6 +125,7 @@ def load_from_ini(self): self.offset_back_rotation = f.ReadBool( 'offset_back_rotation', self.offset_back_rotation) self.checkboxes = f.Read('checkboxes', self.checkboxes) + self.mark_when_checked = f.Read('mark_when_checked', self.mark_when_checked) self.bom_view = f.Read('bom_view', self.bom_view) self.layer_view = f.Read('layer_view', self.layer_view) self.compression = f.ReadBool('compression', self.compression) @@ -168,7 +173,7 @@ def load_from_ini(self): def save(self, locally): file = self.local_config_file if locally else self.global_config_file print('Saving to', file) - f = FileConfig(localFilename=file) + f = get_wx().FileConfig(localFilename=file) f.SetPath('/html_defaults') f.WriteBool('dark_mode', self.dark_mode) @@ -180,6 +185,7 @@ def save(self, locally): f.WriteInt('board_rotation', self.board_rotation) f.WriteBool('offset_back_rotation', self.offset_back_rotation) f.Write('checkboxes', self.checkboxes) + f.Write('mark_when_checked', self.mark_when_checked) f.Write('bom_view', self.bom_view) f.Write('layer_view', self.layer_view) f.WriteBool('compression', self.compression) @@ -226,6 +232,7 @@ def set_from_dialog(self, dlg): self.offset_back_rotation = \ dlg.html.offsetBackRotationCheckbox.IsChecked() self.checkboxes = dlg.html.bomCheckboxesCtrl.Value + # No dialog for mark_when_checked ... self.bom_view = self.bom_view_choices[dlg.html.bomDefaultView.Selection] self.layer_view = self.layer_view_choices[ dlg.html.layerDefaultView.Selection] @@ -275,6 +282,7 @@ def transfer_to_dialog(self, dlg): dlg.html.boardRotationSlider.Value = self.board_rotation dlg.html.offsetBackRotationCheckbox.Value = self.offset_back_rotation dlg.html.bomCheckboxesCtrl.Value = self.checkboxes + # No dialog for mark_when_checked ... dlg.html.bomDefaultView.Selection = self.bom_view_choices.index( self.bom_view) dlg.html.layerDefaultView.Selection = self.layer_view_choices.index( @@ -320,27 +328,46 @@ def safe_set_checked_strings(clb, strings): self.board_variant_blacklist) dlg.fields.dnpFieldBox.Value = self.dnp_field + if self.kicad_variant != '': + dlg.fields.variantLabel.Show() + dlg.fields.variantLabel.SetLabel(f'Current variant: {self.kicad_variant}') + dlg.finish_init() @classmethod def add_options(cls, parser, version): # type: (argparse.ArgumentParser, str) -> None parser.add_argument('--show-dialog', action='store_true', - help='Shows config dialog. All other flags ' - 'will be ignored.') + help='Shows config dialog. All flags except ' + '--kicad-variant will be ignored.') + parser.add_argument('--kicad-variant', default='', + help='KiCad board variant, empty is default ' + 'variant. (Only for KiCad v10+)') parser.add_argument('--version', action='version', version=version) # Html parser.add_argument('--dark-mode', help='Default to dark mode.', action='store_true') + parser.add_argument('--no-dark-mode', dest='dark_mode', + help='Do not default to dark mode.', + action='store_false', default=False) parser.add_argument('--hide-pads', help='Hide footprint pads by default.', action='store_true') + parser.add_argument('--show-pads', dest='hide_pads', + help='Show footprint pads by default.', + action='store_false', default=False) parser.add_argument('--show-fabrication', help='Show fabrication layer by default.', action='store_true') + parser.add_argument('--hide-fabrication', dest='show_fabrication', + help='Hide fabrication layer by default.', + action='store_false', default=False) parser.add_argument('--hide-silkscreen', help='Hide silkscreen by default.', action='store_true') + parser.add_argument('--show-silkscreen', dest='hide_silkscreen', + help='Show silkscreen by default.', + action='store_false', default=False) parser.add_argument('--highlight-pin1', default=cls.highlight_pin1_choices[0], const=cls.highlight_pin1_choices[1], @@ -350,6 +377,9 @@ def add_options(cls, parser, version): parser.add_argument('--no-redraw-on-drag', help='Do not redraw pcb on drag by default.', action='store_true') + parser.add_argument('--redraw-on-drag', dest='no_redraw_on_drag', + help='Redraw pcb on drag by default.', + action='store_false', default=False) parser.add_argument('--board-rotation', type=int, default=cls.board_rotation * 5, help='Board rotation in degrees (-180 to 180). ' @@ -357,9 +387,17 @@ def add_options(cls, parser, version): parser.add_argument('--offset-back-rotation', help='Offset the back of the pcb by 180 degrees', action='store_true') + parser.add_argument('--no-offset-back-rotation', + dest='offset_back_rotation', + help='Do not offset the back of the pcb by 180 degrees', + action='store_false', default=False) parser.add_argument('--checkboxes', default=cls.checkboxes, help='Comma separated list of checkbox columns.') + parser.add_argument('--mark-when-checked', + default=cls.mark_when_checked, + help='Name of the checkbox column used to mark ' + 'components when checked.') parser.add_argument('--bom-view', default=cls.bom_view, choices=cls.bom_view_choices, help='Default BOM view.') @@ -369,8 +407,16 @@ def add_options(cls, parser, version): parser.add_argument('--no-compression', help='Disable compression of pcb data.', action='store_true') + parser.add_argument('--compression', dest='no_compression', + help='Enable compression of pcb data.', + action='store_false', default=False) parser.add_argument('--no-browser', help='Do not launch browser.', action='store_true') + parser.add_argument('--browser', dest='no_browser', + help='Launch browser.', + action='store_false', default=False) + parser.add_argument('--use-ini', help='Use all run options from ibom ini file.', + action='store_true') # General parser.add_argument('--dest-dir', default=cls.bom_dest_dir, @@ -381,8 +427,14 @@ def add_options(cls, parser, version): parser.add_argument('--include-tracks', action='store_true', help='Include track/zone information in output. ' 'F.Cu and B.Cu layers only.') + parser.add_argument('--exclude-tracks', dest='include_tracks', + action='store_false', default=False, + help='Exclude track/zone information from output.') parser.add_argument('--include-nets', action='store_true', help='Include netlist information in output.') + parser.add_argument('--exclude-nets', dest='include_nets', + action='store_false', default=False, + help='Exclude netlist information from output.') parser.add_argument('--sort-order', help='Default sort order for components. ' 'Must contain "~" once.', @@ -394,8 +446,15 @@ def add_options(cls, parser, version): 'E.g. "X1,MH*"') parser.add_argument('--no-blacklist-virtual', action='store_true', help='Do not blacklist virtual components.') + parser.add_argument('--blacklist-virtual', dest='no_blacklist_virtual', + action='store_false', default=False, + help='Blacklist virtual components.') parser.add_argument('--blacklist-empty-val', action='store_true', help='Blacklist components with empty value.') + parser.add_argument('--no-blacklist-empty-val', + dest='blacklist_empty_val', + action='store_false', default=False, + help='Do not blacklist components with empty value.') # Fields section parser.add_argument('--netlist-file', @@ -416,6 +475,10 @@ def add_options(cls, parser, version): help='Normalize extra field name case. E.g. "MPN" ' ', "mpn" will be considered the same field.', action='store_true') + parser.add_argument('--no-normalize-field-case', + dest='normalize_field_case', + help='Do not normalize extra field name case.', + action='store_false', default=False) parser.add_argument('--variant-field', help='Name of the extra field that stores board ' 'variant for component.') @@ -432,10 +495,115 @@ def add_options(cls, parser, version): 'do not populate status. Components with ' 'this field not empty will be excluded.') + def get_ini_defaults(self): + # type: () -> dict | None + """Read the ibom ini file and return its values keyed by the dest + of the matching command line option, suitable for passing to + ArgumentParser.set_defaults(). Installing the ini values as parser + defaults makes options given on the command line override the ini + while all other options fall back to the ini values. + + Returns None if no ini file exists in the usual locations. + """ + import configparser + + if os.path.isfile(self.local_config_file): + file = self.local_config_file + elif os.path.isfile(self.global_config_file): + file = self.global_config_file + else: + return None + print("Loading options from %s" % file) + + # Interpolation is disabled because values like bom_name_format + # legitimately contain '%'. + ini = configparser.ConfigParser(interpolation=None) + ini.read(file) + + # Each entry is (section, key, dest, kind) mapping an ini key to + # the dest of the command line option holding the same setting. + # kind describes how the ini value translates to the value argparse + # would have produced for that dest: + # 'bool': same boolean + # 'not' : inverted boolean (the ini stores the positive setting, + # the option's dest stores the negated one) + # 'str' : verbatim string; comma separated lists stay joined, + # set_from_args splits them + # board_rotation is handled separately below. extra_data_file is + # intentionally not read from the ini; it is chosen dynamically + # unless given on the command line. + ini_options = [ + # Html + ('html_defaults', 'dark_mode', 'dark_mode', 'bool'), + ('html_defaults', 'show_pads', 'hide_pads', 'not'), + ('html_defaults', 'show_fabrication', 'show_fabrication', + 'bool'), + ('html_defaults', 'show_silkscreen', 'hide_silkscreen', 'not'), + ('html_defaults', 'highlight_pin1', 'highlight_pin1', 'str'), + ('html_defaults', 'redraw_on_drag', 'no_redraw_on_drag', 'not'), + ('html_defaults', 'offset_back_rotation', 'offset_back_rotation', + 'bool'), + ('html_defaults', 'checkboxes', 'checkboxes', 'str'), + ('html_defaults', 'mark_when_checked', 'mark_when_checked', + 'str'), + ('html_defaults', 'bom_view', 'bom_view', 'str'), + ('html_defaults', 'layer_view', 'layer_view', 'str'), + ('html_defaults', 'compression', 'no_compression', 'not'), + ('html_defaults', 'open_browser', 'no_browser', 'not'), + # General + ('general', 'bom_dest_dir', 'dest_dir', 'str'), + ('general', 'bom_name_format', 'name_format', 'str'), + ('general', 'component_sort_order', 'sort_order', 'str'), + ('general', 'component_blacklist', 'blacklist', 'str'), + ('general', 'blacklist_virtual', 'no_blacklist_virtual', 'not'), + ('general', 'blacklist_empty_val', 'blacklist_empty_val', + 'bool'), + ('general', 'include_tracks', 'include_tracks', 'bool'), + ('general', 'include_nets', 'include_nets', 'bool'), + # Fields + ('fields', 'show_fields', 'show_fields', 'str'), + ('fields', 'group_fields', 'group_fields', 'str'), + ('fields', 'normalize_field_case', 'normalize_field_case', + 'bool'), + ('fields', 'board_variant_field', 'variant_field', 'str'), + ('fields', 'board_variant_whitelist', 'variants_whitelist', + 'str'), + ('fields', 'board_variant_blacklist', 'variants_blacklist', + 'str'), + ('fields', 'dnp_field', 'dnp_field', 'str'), + ] + + defaults = {} + for section, key, dest, kind in ini_options: + if not ini.has_option(section, key): + continue + if kind == 'bool': + defaults[dest] = ini.getboolean(section, key) + elif kind == 'not': + defaults[dest] = not ini.getboolean(section, key) + else: + defaults[dest] = ini.get(section, key) + + # The ini stores rotation in multiples of 5 degrees, the command + # line option takes degrees. + if ini.has_option('html_defaults', 'board_rotation'): + defaults['board_rotation'] = \ + ini.getint('html_defaults', 'board_rotation') * 5 + + # migration from previous settings + if defaults.get('highlight_pin1') == '0': + defaults['highlight_pin1'] = 'none' + if defaults.get('highlight_pin1') == '1': + defaults['highlight_pin1'] = 'all' + + return defaults + def set_from_args(self, args): # type: (argparse.Namespace) -> None import math + self.kicad_variant = args.kicad_variant + # Html self.dark_mode = args.dark_mode self.show_pads = not args.hide_pads @@ -446,6 +614,7 @@ def set_from_args(self, args): self.board_rotation = math.fmod(args.board_rotation // 5, 37) self.offset_back_rotation = args.offset_back_rotation self.checkboxes = args.checkboxes + self.mark_when_checked = args.mark_when_checked self.bom_view = args.bom_view self.layer_view = args.layer_view self.compression = not args.no_compression diff --git a/InteractiveHtmlBom/core/ibom.py b/InteractiveHtmlBom/core/ibom.py index 178467c..e8af1cc 100644 --- a/InteractiveHtmlBom/core/ibom.py +++ b/InteractiveHtmlBom/core/ibom.py @@ -8,13 +8,11 @@ import sys from datetime import datetime -import wx - from . import units from .config import Config -from ..dialog import SettingsDialog from ..ecad.common import EcadParser, Component from ..errors import ParsingException +from ..compat import get_wx class Logger(object): @@ -38,13 +36,13 @@ def error(self, msg): if self.cli: self.logger.error(msg) else: - wx.MessageBox(msg) + get_wx().MessageBox(msg) def warn(self, msg): if self.cli: self.logger.warning(msg) else: - wx.LogWarning(msg) + get_wx().LogWarning(msg) log = None @@ -234,6 +232,8 @@ def process_substitutions(bom_name_format, pcb_file_name, metadata): name = name.replace('%c', metadata['company']) name = name.replace('%r', metadata['revision']) name = name.replace('%d', metadata['date'].replace(':', '-')) + name = name.replace('%v', metadata.get('variant', '')) + name = name.replace('%V', metadata.get('variant', '') or 'default') now = datetime.now() name = name.replace('%D', now.strftime('%Y-%m-%d')) name = name.replace('%T', now.strftime('%H-%M-%S')) @@ -341,6 +341,8 @@ def main(parser, config, logger): def run_with_dialog(parser, config, logger): # type: (EcadParser, Config, Logger) -> None + from ..dialog import SettingsDialog + def save_config(dialog_panel, locally=False): config.set_from_dialog(dialog_panel) config.save(locally) @@ -358,7 +360,7 @@ def save_config(dialog_panel, locally=False): if extra_data_file is not None: dlg.set_extra_data_path(extra_data_file) config.transfer_to_dialog(dlg.panel) - if dlg.ShowModal() == wx.ID_OK: + if dlg.ShowModal() == get_wx().ID_OK: config.set_from_dialog(dlg.panel) main(parser, config, logger) finally: diff --git a/InteractiveHtmlBom/dialog/dialog_base.py b/InteractiveHtmlBom/dialog/dialog_base.py index 6b3c5d4..0565f8a 100644 --- a/InteractiveHtmlBom/dialog/dialog_base.py +++ b/InteractiveHtmlBom/dialog/dialog_base.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ########################################################################### -## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) +## Python code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6) ## http://www.wxformbuilder.org/ ## ## PLEASE DO *NOT* EDIT THIS FILE! @@ -413,6 +413,13 @@ def __init__( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx. 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 ) sbSizer7.Add( self.extraDataFilePicker, 0, wx.EXPAND|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) + self.variantLabel = wx.StaticText( sbSizer7.GetStaticBox(), wx.ID_ANY, u"Current variant:", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.variantLabel.Wrap( -1 ) + + self.variantLabel.Hide() + + sbSizer7.Add( self.variantLabel, 0, wx.ALL, 5 ) + bSizer42.Add( sbSizer7, 0, wx.ALL|wx.EXPAND, 5 ) diff --git a/InteractiveHtmlBom/dialog/settings_dialog.py b/InteractiveHtmlBom/dialog/settings_dialog.py index 107af59..a976a0d 100644 --- a/InteractiveHtmlBom/dialog/settings_dialog.py +++ b/InteractiveHtmlBom/dialog/settings_dialog.py @@ -334,8 +334,11 @@ def OnExtraDataFileChanged(self, event): self.extra_field_data = self.extra_data_func( extra_data_file, self.normalizeCaseCheckbox.Value) except Exception as e: + import traceback pop_error( - "Failed to parse file %s\n\n%s" % (extra_data_file, e)) + "Failed to parse file %s\n\n%s" % ( + extra_data_file, + str(e) + '\n' + traceback.format_exc())) self.extraDataFilePicker.Path = '' if self.extra_field_data is not None: diff --git a/InteractiveHtmlBom/ecad/kicad.py b/InteractiveHtmlBom/ecad/kicad.py index 61b1f0e..bef0b30 100644 --- a/InteractiveHtmlBom/ecad/kicad.py +++ b/InteractiveHtmlBom/ecad/kicad.py @@ -30,10 +30,16 @@ def __init__(self, file_name, config, logger, board=None): self.board = board if self.board is None: self.board = pcbnew.LoadBoard(self.file_name) # type: pcbnew.BOARD + if not self.board: + raise Exception('Failed to load board file') + if hasattr(self.board, "SetCurrentVariant"): + self.board.SetCurrentVariant(config.kicad_variant) if hasattr(self.board, 'GetModules'): - self.footprints = list(self.board.GetModules()) # type: list[pcbnew.MODULE] + # type: list[pcbnew.MODULE] + self.footprints = list(self.board.GetModules()) else: - self.footprints = list(self.board.GetFootprints()) # type: list[pcbnew.FOOTPRINT] + # type: list[pcbnew.FOOTPRINT] + self.footprints = list(self.board.GetFootprints()) self.font_parser = FontParser() def get_extra_field_data(self, file_name): @@ -46,8 +52,7 @@ def get_extra_field_data(self, file_name): return ExtraFieldData(data[0], data[1]) - @staticmethod - def get_footprint_fields(f): + def get_footprint_fields(self, f): # type: (pcbnew.FOOTPRINT) -> dict props = {} if hasattr(f, "GetProperties"): @@ -60,6 +65,14 @@ def get_footprint_fields(f): if hasattr(f, "IsDNP"): if f.IsDNP(): props["kicad_dnp"] = "DNP" + if hasattr(f, 'GetVariant'): + variant = f.GetVariant(self.config.kicad_variant) + if variant: + var_fields = variant.GetFields() + for k in var_fields.keys(): + props[str(k)] = str(f.GetFieldShownText(str(k))) + props["kicad_dnp"] = "DNP" if variant.GetDNP() else "" + return props def parse_extra_data_from_pcb(self): @@ -209,7 +222,8 @@ def parse_shape(self, d): "angle": angle, "polygons": polygons } - if hasattr(d, "IsFilled") and not d.IsFilled(): + if ((hasattr(d, "IsFilled") and not d.IsFilled()) or + (hasattr(d, "IsSolidFill") and not d.IsSolidFill())): shape_dict["filled"] = 0 shape_dict["width"] = d.GetWidth() * 1e-6 return shape_dict @@ -273,7 +287,8 @@ def parse_text(self, d): "svgpath": create_path(lines) } elif hasattr(d, 'GetEffectiveTextShape'): - shape = d.GetEffectiveTextShape(False) # type: pcbnew.SHAPE_COMPOUND + # type: pcbnew.SHAPE_COMPOUND + shape = d.GetEffectiveTextShape(False) segments = [] polygons = [] for s in shape.GetSubshapes(): @@ -426,7 +441,7 @@ def get_all_drawings(self): for d in f.GraphicalItems(): drawings.append((d.GetClass(), d)) if hasattr(f, "GetFields"): - fields = f.GetFields() # type: list[pcbnew.PCB_FIELD] + fields = f.GetFields() # type: list[pcbnew.PCB_FIELD] for field in fields: if field.IsReference() or field.IsValue(): continue @@ -450,11 +465,15 @@ def parse_pad(self, pad): custom_padstack = False outer_layers = [(pcbnew.F_Cu, "F"), (pcbnew.B_Cu, "B")] if hasattr(pad, 'Padstack'): - padstack = pad.Padstack() # type: pcbnew.PADSTACK + padstack = pad.Padstack() # type: pcbnew.PADSTACK layers_set = list(padstack.LayerSet().Seq()) + if hasattr(pcbnew, "UNCONNECTED_LAYER_MODE_REMOVE_ALL"): + ULMRA = pcbnew.UNCONNECTED_LAYER_MODE_REMOVE_ALL + else: + ULMRA = padstack.UNCONNECTED_LAYER_MODE_REMOVE_ALL custom_padstack = ( - padstack.Mode() != padstack.MODE_NORMAL or \ - padstack.UnconnectedLayerMode() == padstack.UNCONNECTED_LAYER_MODE_REMOVE_ALL + padstack.Mode() != padstack.MODE_NORMAL or + padstack.UnconnectedLayerMode() == ULMRA ) else: layers_set = list(pad.GetLayerSet().Seq()) @@ -474,7 +493,8 @@ def parse_pad(self, pad): pads.append(pad_dict) return pads else: - pad_dict = self.parse_pad_layer(pad, layers_set[0]) + pad_layer = layers_set[0] if layers_set else pcbnew.F_Cu + pad_dict = self.parse_pad_layer(pad, pad_layer) pad_dict["layers"] = layers return [pad_dict] @@ -715,6 +735,8 @@ def parse_zones(self, zones): if (hasattr(zone, 'GetFilledPolysUseThickness') and not zone.GetFilledPolysUseThickness()): width = 0 + if KICAD_VERSION[0] >= 7: + width = 0 zone_dict = { "polygons": self.parse_poly_set(poly_set), "width": width, @@ -735,16 +757,24 @@ def parse_netlist(net_info): nets = sorted([str(s) for s in nets]) return nets - @staticmethod - def footprint_to_component(footprint, extra_fields): + def footprint_to_component(self, footprint, extra_fields): + # type: (pcbnew.FOOTPRINT, list) -> Component try: footprint_name = str(footprint.GetFPID().GetFootprintName()) except AttributeError: footprint_name = str(footprint.GetFPID().GetLibItemName()) + value = footprint.GetValue() + if hasattr(footprint, 'GetFieldValueForVariant'): + value = footprint.GetFieldValueForVariant( + self.config.kicad_variant, 'Value') attr = 'Normal' if hasattr(pcbnew, 'FP_EXCLUDE_FROM_BOM'): - if footprint.GetAttributes() & pcbnew.FP_EXCLUDE_FROM_BOM: + if hasattr(footprint, 'GetExcludedFromBOMForVariant'): + if footprint.GetExcludedFromBOMForVariant( + self.config.kicad_variant): + attr = 'Virtual' + elif footprint.GetAttributes() & pcbnew.FP_EXCLUDE_FROM_BOM: attr = 'Virtual' elif hasattr(pcbnew, 'MOD_VIRTUAL'): if footprint.GetAttributes() == pcbnew.MOD_VIRTUAL: @@ -755,7 +785,7 @@ def footprint_to_component(footprint, extra_fields): }.get(footprint.GetLayer()) return Component(footprint.GetReference(), - footprint.GetValue(), + value, footprint_name, layer, attr, @@ -774,9 +804,9 @@ def parse(self): self.config.dnp_field) if not self.config.extra_data_file and need_extra_fields: - self.logger.warn('Ignoring extra fields related config parameters ' - 'since no netlist/xml file was specified.') - need_extra_fields = False + self.config.extra_data_file = self.file_name + self.logger.warn('Assuming extra data file to be the pcb file ' + 'since --extra-data-file was not specified.') extra_field_data = None if (self.config.extra_data_file and @@ -839,6 +869,7 @@ def parse(self): "revision": revision, "company": company, "date": file_date, + "variant": self.config.kicad_variant, }, "bom": {}, "font_data": self.font_parser.get_parsed_font() @@ -905,7 +936,7 @@ def Run(self): from ..errors import ParsingException logger = ibom.Logger() - board = pcbnew.GetBoard() + board = pcbnew.GetBoard() # type: pcbnew.BOARD pcb_file_name = board.GetFileName() if not pcb_file_name: @@ -913,6 +944,9 @@ def Run(self): return config = Config(version, os.path.dirname(pcb_file_name)) + if hasattr(board, 'GetCurrentVariant'): + config.kicad_variant = board.GetCurrentVariant() + parser = PcbnewParser(pcb_file_name, config, logger, board) try: diff --git a/InteractiveHtmlBom/ecad/schema/genericjsonpcbdata_v1.schema b/InteractiveHtmlBom/ecad/schema/genericjsonpcbdata_v1.schema index d59127a..53a87a0 100644 --- a/InteractiveHtmlBom/ecad/schema/genericjsonpcbdata_v1.schema +++ b/InteractiveHtmlBom/ecad/schema/genericjsonpcbdata_v1.schema @@ -305,6 +305,9 @@ }, "date": { "type": "string" + }, + "variant": { + "type": "string" } }, "required": ["title", "revision", "company", "date"], @@ -443,12 +446,20 @@ "properties": { "svgpath": { "type": "string" }, "thickness": { "type": "number" }, + "fillrule": { + "type": "string", + "enum": [ + "nonzero", + "evenodd" + ] + }, "ref": { "type": "integer" , "const": 1 }, "val": { "type": "integer" , "const": 1 } }, - "required": [ - "svgpath", - "thickness" + "required": ["svgpath"], + "oneOf": [ + { "required": ["thickness"] }, + { "required": ["fillrule"] } ], "title": "DrawingText" }, diff --git a/InteractiveHtmlBom/generate_interactive_bom.py b/InteractiveHtmlBom/generate_interactive_bom.py index bca7f80..726cf76 100755 --- a/InteractiveHtmlBom/generate_interactive_bom.py +++ b/InteractiveHtmlBom/generate_interactive_bom.py @@ -4,6 +4,7 @@ import argparse import os import sys + # Add ../ to the path # Works if this script is executed without installing the module script_dir = os.path.dirname(os.path.abspath(os.path.realpath(__file__))) @@ -23,16 +24,22 @@ def to_utf(s): def main(): - create_wx_app = 'INTERACTIVE_HTML_BOM_NO_DISPLAY' not in os.environ - - import wx - - if create_wx_app: - app = wx.App() - if hasattr(wx, "APP_ASSERT_SUPPRESS"): - app.SetAssertMode(wx.APP_ASSERT_SUPPRESS) - elif hasattr(wx, "DisableAsserts"): - wx.DisableAsserts() + from .compat import get_wx, should_create_wx_app + wx = get_wx() + create_wx_app = should_create_wx_app() + + if wx is None and create_wx_app: + print("wxpython is required unless INTERACTIVE_HTML_BOM_NO_DISPLAY " + "environment variable is set") + sys.exit(1) + + if wx is not None: + if create_wx_app: + app = wx.App() + if hasattr(wx, "APP_ASSERT_SUPPRESS"): + app.SetAssertMode(wx.APP_ASSERT_SUPPRESS) + elif hasattr(wx, "DisableAsserts"): + wx.DisableAsserts() from .core import ibom from .core.config import Config @@ -40,6 +47,7 @@ def main(): from .version import version from .errors import (ExitCodes, ParsingException, exit_error) + parser = argparse.ArgumentParser( description='KiCad InteractiveHtmlBom plugin CLI.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) @@ -48,16 +56,34 @@ def main(): help="KiCad PCB file") Config.add_options(parser, version) - args = parser.parse_args() logger = ibom.Logger(cli=True) - if not os.path.isfile(args.file): + # First pass over the arguments to find the pcb file and --use-ini. + pre_args, _ = parser.parse_known_args() + + if not os.path.isfile(pre_args.file): exit_error(logger, ExitCodes.ERROR_FILE_NOT_FOUND, - "File %s does not exist." % args.file) + "File %s does not exist." % pre_args.file) + + config = Config(version, + os.path.dirname(os.path.abspath(pre_args.file))) + + # With --use-ini the ini values are installed as parser defaults before + # the final parse: options given on the command line override the ini + # while all other options fall back to the ini values. + if pre_args.use_ini and not pre_args.show_dialog: + ini_defaults = config.get_ini_defaults() + if ini_defaults is None: + exit_error(logger, ExitCodes.ERROR_FILE_NOT_FOUND, + "No ibom ini file found in usual locations.") + else: + parser.set_defaults(**ini_defaults) + + args = parser.parse_args() print("Loading %s" % args.file) - config = Config(version, os.path.dirname(os.path.abspath(args.file))) + config.kicad_variant = args.kicad_variant parser = get_parser_by_extension( os.path.abspath(args.file), config, logger) diff --git a/InteractiveHtmlBom/version.py b/InteractiveHtmlBom/version.py index f12921c..434904f 100644 --- a/InteractiveHtmlBom/version.py +++ b/InteractiveHtmlBom/version.py @@ -3,7 +3,7 @@ import subprocess -LAST_TAG = 'v2.10.0' +LAST_TAG = 'v2.11.2' def _get_git_version(): diff --git a/InteractiveHtmlBom/web/ibom.css b/InteractiveHtmlBom/web/ibom.css index a601c3f..d3f16c3 100644 --- a/InteractiveHtmlBom/web/ibom.css +++ b/InteractiveHtmlBom/web/ibom.css @@ -8,7 +8,7 @@ --pin1-outline-color: #ffb629; --pin1-outline-color-highlight: #ffb629; --pin1-outline-color-highlight-both: #fcbb39; - --pin1-outline-color-highlight-marked: #fdbe41; + --pin1-outline-color-highlight-marked: #00000000; --silkscreen-edge-color: #aa4; --silkscreen-polygon-color: #4aa; --silkscreen-text-color: #4aa; diff --git a/InteractiveHtmlBom/web/render.js b/InteractiveHtmlBom/web/render.js index 9fc2e9b..c2304ac 100644 --- a/InteractiveHtmlBom/web/render.js +++ b/InteractiveHtmlBom/web/render.js @@ -24,12 +24,17 @@ function drawText(ctx, text, color) { ctx.strokeStyle = color; ctx.lineCap = "round"; ctx.lineJoin = "round"; - ctx.lineWidth = text.thickness; if ("svgpath" in text) { - ctx.stroke(new Path2D(text.svgpath)); + if ("thickness" in text) { + ctx.lineWidth = text.thickness; + ctx.stroke(new Path2D(text.svgpath)); + } else if ("fillrule" in text) { + ctx.fill(new Path2D(text.svgpath), text.fillrule); + } ctx.restore(); return; } + ctx.lineWidth = text.thickness; if ("polygons" in text) { ctx.fill(getPolygonsPath(text)); ctx.restore(); @@ -381,7 +386,7 @@ function drawFootprints(canvas, layer, scalefactor, highlight) { } for (var i = 0; i < pcbdata.footprints.length; i++) { - var mod = pcbdata.footprints[i]; + var fp = pcbdata.footprints[i]; var outline = settings.renderDnpOutline && pcbdata.bom.skipped.includes(i); var h = highlightedFootprints.includes(i); var d = markedFootprints.has(i); @@ -398,7 +403,7 @@ function drawFootprints(canvas, layer, scalefactor, highlight) { } } if( h || d || !highlight) { - drawFootprint(ctx, layer, scalefactor, mod, colors, highlight, outline); + drawFootprint(ctx, layer, scalefactor, fp, colors, highlight, outline); } } } diff --git a/InteractiveHtmlBom/web/table-util.js b/InteractiveHtmlBom/web/table-util.js index 00e23f8..ba0c9fc 100644 --- a/InteractiveHtmlBom/web/table-util.js +++ b/InteractiveHtmlBom/web/table-util.js @@ -20,7 +20,7 @@ function setBomHandlers() { draggingElement.remove(); // Make BOM selectable again - bom.style.removeProperty("userSelect"); + bom.style.removeProperty("user-select"); // Remove listeners document.removeEventListener('mousemove', mouseMoveHandler); diff --git a/InteractiveHtmlBom/web/util.js b/InteractiveHtmlBom/web/util.js index 3f84b6d..e3f4947 100644 --- a/InteractiveHtmlBom/web/util.js +++ b/InteractiveHtmlBom/web/util.js @@ -549,7 +549,10 @@ function initDefaults() { setHighlightPin1(highlightpin1); document.forms.highlightpin1.highlightpin1.value = highlightpin1; - settings.markWhenChecked = readStorage("markWhenChecked") || ""; + settings.markWhenChecked = readStorage("markWhenChecked"); + if (settings.markWhenChecked == null) { + settings.markWhenChecked = config.mark_when_checked; + } populateMarkWhenCheckedOptions(); function initBooleanSetting(storageString, def, elementId, func) { diff --git a/make_release.py b/make_release.py new file mode 100644 index 0000000..1c0a8db --- /dev/null +++ b/make_release.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +"""Create a release zip for InteractiveHtmlBom per user's steps. + +Steps implemented: +1. Determine current git tag; require repo clean and HEAD tagged. +2. Verify LAST_TAG in InteractiveHtmlBom/version.py matches git tag. +3. Create releases/ folder. +4. Create a tmp dir. +5. Copy `resources` folder into tmp dir. +6. Copy `InteractiveHtmlBom` into tmp/plugins, + excluding __pycache__ and .ini files. +7. Set `versions[0].version` in `releases/metadata.json` to tag + without leading 'v'. +8. Copy resulting metadata.json into tmp dir. +9. Zip tmp dir contents to `InteractiveHtmlBom_{version}_pcm.zip` + inside releases/. +10.Zip plugin code into InteractiveHtmlBom.zip suitable for manual install. +""" + +from __future__ import annotations + +import json +import re +import shutil +import subprocess +import sys +import tempfile +from pathlib import Path + + +def run(cmd: list[str]) -> str: + return subprocess.check_output(cmd, stderr=subprocess.STDOUT, text=True).strip() + + +def get_head_tag() -> str: + tags = run(["git", "tag", "--points-at", "HEAD"]).splitlines() + if not tags: + raise SystemExit("ERROR: current commit is not tagged. Aborting.") + return tags[0] + + +def repo_is_dirty() -> bool: + status = run(["git", "status", "--porcelain"]).strip() + return bool(status) + + +def read_last_tag_from_version_file(path: Path) -> str | None: + text = path.read_text(encoding="utf8") + m = re.search(r"LAST_TAG\s*=\s*['\"]([^'\"]+)['\"]", text) + return m.group(1) if m else None + + +def update_metadata_version(metadata_path: Path, version: str) -> None: + data = json.loads(metadata_path.read_text(encoding="utf8")) + if "versions" not in data or not isinstance(data["versions"], list) or not data["versions"]: + raise SystemExit(f"ERROR: {metadata_path} has no versions[0] entry") + data["versions"][0]["version"] = version + metadata_path.write_text(json.dumps( + data, indent=4, ensure_ascii=False), encoding="utf8") + + +def copy_interactive_html_bom(src: Path, dst: Path) -> None: + # copytree with ignore patterns for __pycache__ directories and .ini files + def _ignore(dir, names): + ignored = set() + for name in list(names): + if name == "__pycache__" or name.endswith(".ini"): + ignored.add(name) + return ignored + + shutil.copytree(src, dst, ignore=_ignore) + + +def main() -> None: + root = Path.cwd() + + # 1. Ensure repo clean and HEAD is tagged + if repo_is_dirty(): + raise SystemExit( + "ERROR: repository has uncommitted changes (dirty). Commit or stash before releasing.") + + tag = get_head_tag() + print(f"Found tag: {tag}") + + # 2. Verify LAST_TAG in InteractiveHtmlBom/version.py + version_file = root / "InteractiveHtmlBom" / "version.py" + if not version_file.exists(): + raise SystemExit(f"ERROR: {version_file} not found") + last_tag = read_last_tag_from_version_file(version_file) + if last_tag is None: + raise SystemExit(f"ERROR: LAST_TAG not found in {version_file}") + if last_tag != tag: + raise SystemExit( + f"ERROR: LAST_TAG ({last_tag}) does not match git tag ({tag})") + print("LAST_TAG matches git tag.") + + # 3. Create releases/ folder + releases_dir = root / "releases" + version_dir = releases_dir / tag + version_dir.mkdir(parents=True, exist_ok=True) + print(f"Created/verified release folder: {version_dir}") + + # 4-9 inside a temporary directory + with tempfile.TemporaryDirectory() as tmp: + tmp_path = Path(tmp) + + # 5. Copy resources folder from repo root into tmp dir + resources_src = root / "releases" / "resources" + if not resources_src.exists() or not resources_src.is_dir(): + raise SystemExit( + f"ERROR: resources folder not found at {resources_src}") + shutil.copytree(resources_src, tmp_path / "resources") + print("Copied resources into tmp dir.") + + # 6. Copy InteractiveHtmlBom into tmp/plugins excluding patterns + plugins_dir = tmp_path / "plugins" + copy_interactive_html_bom( + root / "InteractiveHtmlBom", plugins_dir) + print("Copied InteractiveHtmlBom into tmp/plugins (excluded __pycache__ and .ini files)") + + # 7. Set versions[0].version inside releases/metadata.json to package version without leading 'v' + metadata_path = releases_dir / "metadata.json" + if not metadata_path.exists(): + raise SystemExit(f"ERROR: {metadata_path} not found") + package_version = tag.lstrip("v") + update_metadata_version(metadata_path, package_version) + print( + f"Updated {metadata_path} versions[0].version to {package_version}") + + # 8. Copy resulting metadata.json file into tmp dir + shutil.copy2(metadata_path, tmp_path / "metadata.json") + print("Copied metadata.json into tmp dir.") + + # 9. Zip tmp dir contents into InteractiveHtmlBom-{version}-pcm.zip into the version folder + zip_name = f"InteractiveHtmlBom_{tag}_pcm" + archive_path = shutil.make_archive( + str(version_dir / zip_name), 'zip', root_dir=tmp_path) + print(f"Created archive: {archive_path}") + + # 10. Create "normal" zip of just plugin code + shutil.move(plugins_dir, tmp_path / "InteractiveHtmlBom") + zip_name = f"InteractiveHtmlBom" + archive_path = shutil.make_archive( + str(version_dir / zip_name), 'zip', root_dir=tmp_path, base_dir="InteractiveHtmlBom") + print(f"Created archive: {archive_path}") + + print("Release package created successfully.") + + +if __name__ == '__main__': + try: + main() + except subprocess.CalledProcessError as e: + print("ERROR: git command failed:\n", e.output, file=sys.stderr) + sys.exit(2) + except Exception as e: + print(e, file=sys.stderr) + sys.exit(1) diff --git a/settings_dialog.fbp b/settings_dialog.fbp index 629f833..218bf6c 100644 --- a/settings_dialog.fbp +++ b/settings_dialog.fbp @@ -1,106 +1,1751 @@ - + - - - - Python - 1 - source_name - 0 - 0 - ./InteractiveHtmlBom/dialog - UTF-8 - connect - dialog_base - 2000 - none - - 1 - 0 - InteractiveHtmlBom - - ./InteractiveHtmlBom/dialog - - 1 - 1 - 1 - 1 - UI - 0 - 0 - 0 - - 0 - wxAUI_MGR_DEFAULT + + + Python + + 1 + connect + none + + + 0 + 0 + ./InteractiveHtmlBom/dialog + UTF-8 + dialog_base + 2000 + 0 + 1 + UI + InteractiveHtmlBom + ./InteractiveHtmlBom/dialog + 0 + source_name + 1 + 0 + source_name + + 1 + 1 + 1 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 0 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + SettingsDialogBase + + 463,497 + wxDEFAULT_DIALOG_STYLE|wxSTAY_ON_TOP + ; ; forward_declare + InteractiveHtmlBom + + 0 + + + wxBORDER_DEFAULT + + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 0 + 1 + impl_virtual + + + 0 + wxID_ANY + + + SettingsDialogPanel + + 400,300 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + + + bSizer20 + wxVERTICAL + none + + 5 + wxEXPAND | wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + - wxBOTH + + + 1 + 0 + 1 1 + 0 + Dock + 0 + Left + 0 1 - impl_virtual - + 1 + 0 0 wxID_ANY + + 0 + + 0 - SettingsDialogBase + 1 + notebook + 1 + + + protected + 1 - 463,497 - wxDEFAULT_DIALOG_STYLE|wxSTAY_ON_TOP + Resizable + 1 + + wxNB_TOP ; ; forward_declare - InteractiveHtmlBom + 0 - 0 wxBORDER_DEFAULT + + + + 5 + wxEXPAND + 0 + + + bSizer39 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Save current settings... + + 0 + + 0 + + + 0 + + 1 + saveSettingsBtn + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + wxBORDER_DEFAULT + OnSave + + + + 5 + wxEXPAND + 1 + + 0 + protected + 50 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 1 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Generate BOM + + 0 + + 0 + + + 0 + + 1 + generateBomBtn + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + wxBORDER_DEFAULT + OnGenerateBom + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + 0 + + + 0 + + 1 + cancelBtn + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + wxBORDER_DEFAULT + OnExit + + + + + + + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 0 + 1 + impl_virtual + + + 0 + wxID_ANY + + + HtmlSettingsPanelBase + + -1,-1 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + + + b_sizer + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Dark mode + + 0 + + + 0 + + 1 + darkModeCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Show footprint pads + + 0 + + + 0 + + 1 + showPadsCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Show fabrication layer + + 0 + + + 0 + + 1 + showFabricationCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Show silkscreen + + 0 + + + 0 + + 1 + showSilkscreenCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Continuous redraw on drag + + 0 + + + 0 + + 1 + continuousRedrawCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + "None" "All" "Selected" + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Highlight first pin + 3 + + 0 + + + 0 + + 1 + highlightPin1 + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_COLS + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer18 + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizer19 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Board rotation + 0 + + 0 + + + 0 + + 1 + m_boardRotationLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 0 + + 0 + + + 0 + + 1 + rotationDegreeLabel + 1 + + + protected + 1 + + Resizable + 1 + 30,-1 + wxALIGN_RIGHT|wxST_NO_AUTORESIZE + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + + 0 + + 0 + protected + 8 + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + 36 + + 0 + + -36 + + 0 + + 1 + boardRotationSlider + 1 + + + protected + 1 + + Resizable + 1 + + wxSL_HORIZONTAL + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + OnBoardRotationSlider + + + - - 0 - wxAUI_MGR_DEFAULT + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + 1 + 0 + 0 + 1 1 + 0 + Dock + 0 + Left + 0 1 - impl_virtual + 1 + 0 0 wxID_ANY + Offset back rotation + + 0 + + 0 - SettingsDialogPanel + 1 + offsetBackRotationCheckbox + 1 + + + protected + 1 - 400,300 + Resizable + 1 + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + wxID_ANY + Checkboxes + + sbSizer31 + wxHORIZONTAL + 1 + none + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + bomCheckboxesCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + Sourced,Placed + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + "BOM only" "BOM left, drawings right" "BOM top, drawings bottom" + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + BOM View + 1 + + 0 + + + 0 + + 1 + bomDefaultView + 1 + + + protected + 1 + + Resizable + 1 + 1 + + wxRA_SPECIFY_COLS + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + "Front only" "Front and Back" "Back only" + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Layer View + 1 + + 0 + + + 0 + + 1 + layerDefaultView + 1 + + + protected + 1 + + Resizable + 1 + 1 + + wxRA_SPECIFY_COLS + ; forward_declare + 0 - 0 + + wxFILTER_NONE + wxDefaultValidator + - wxTAB_TRAVERSAL - + + + + + 5 + wxEXPAND|wxALL + 1 + + wxID_ANY + Miscellaneous + + sbSizer10 + wxVERTICAL + 1 + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Enable compression + + 0 + + + 0 + + 1 + compressionCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Open browser + + 0 + + + 0 + + 1 + openBrowserCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 0 + 1 + impl_virtual + + + 0 + wxID_ANY + + + GeneralSettingsPanelBase + + -1,-1 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + OnSize + + + bSizer32 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + wxID_ANY + Bom destination + + sbSizer6 + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 1 + + 0 - bSizer20 - wxVERTICAL + fgSizer1 + wxFLEX_GROWMODE_SPECIFIED none - - 5 - wxEXPAND | wxALL - 1 - + 0 + 0 + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Directory + 0 + + 0 + + + 0 + + 1 + m_staticText8 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + Select bom folder + + 0 + + 1 + bomDirPicker + 1 + + + protected + 1 + + Resizable + 1 + + wxDIRP_SMALL|wxDIRP_USE_TEXTCTRL + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + wxBORDER_SIMPLE + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Name format + 0 + + 0 + + + 0 + + 1 + m_staticText9 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + + bSizer20 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP + 1 + 1 1 1 1 - + 0 - - + 0 + 0 - 1 0 @@ -111,6 +1756,7 @@ Dock 0 Left + 0 1 1 @@ -121,11 +1767,12 @@ 0 + 0 0 1 - notebook + fileNameFormatTextControl 1 @@ -135,340 +1782,82 @@ Resizable 1 - wxNB_TOP + ; ; forward_declare 0 + + wxFILTER_NONE + wxDefaultValidator + + - wxBORDER_DEFAULT - - - - 5 - wxEXPAND - 0 - - - bSizer39 - wxHORIZONTAL - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - Save current settings... - - 0 - - 0 - - - 0 - - 1 - saveSettingsBtn - 1 - - - protected - 1 - - - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - wxBORDER_DEFAULT - OnSave - - - - 5 - wxEXPAND - 1 - - 0 - protected - 50 - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 1 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - Generate BOM - - 0 - - 0 - - - 0 - - 1 - generateBomBtn - 1 - - - protected - 1 - - - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - wxBORDER_DEFAULT - OnGenerateBom - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_CANCEL - Cancel - - 0 - - 0 - - - 0 - - 1 - cancelBtn - 1 - - - protected - 1 - - - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - wxBORDER_DEFAULT - OnExit - - + + - - - - - 0 - wxAUI_MGR_DEFAULT - - - 1 - 1 - impl_virtual - - - 0 - wxID_ANY - - - HtmlSettingsPanelBase - - -1,-1 - ; ; forward_declare - - 0 - - - wxTAB_TRAVERSAL - - - b_sizer - wxVERTICAL - none - - 5 - wxALL - 0 - + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + 1 1 1 1 - + 0 - - + 0 + 0 + 0 + 1 0 - 0 1 1 + + 0 0 + Dock 0 Left + 0 1 1 + 0 0 wxID_ANY - Dark mode + + + 0 0 0 - + 30,30 1 - darkModeCheckbox + m_btnNameHint 1 protected 1 + + Resizable 1 - + wxBU_EXACTFIT ; ; forward_declare 0 @@ -479,27 +1868,208 @@ + OnNameFormatHintClick + + - - 5 - wxALL - 0 - + + + + + + 5 + wxALL|wxEXPAND + 0 + + wxID_ANY + Additional pcb data + + sbSizer9 + wxHORIZONTAL + 1 + none + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Include tracks/zones + + 0 + + + 0 + + 1 + includeTracksCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Include nets + + 0 + + + 0 + + 1 + includeNetsCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + wxID_ANY + Component sort order + + sortingSizer + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + + bSizer4 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bSizer6 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + 1 1 1 1 - + 0 - - + 0 + 0 1 0 - 1 + 1 1 @@ -507,6 +2077,7 @@ Dock 0 Left + 0 1 1 @@ -514,7 +2085,6 @@ 0 0 wxID_ANY - Show footprint pads 0 @@ -522,7 +2092,7 @@ 0 1 - showPadsCheckbox + componentSortOrderBox 1 @@ -532,7 +2102,7 @@ Resizable 1 - + wxLB_SINGLE ; ; forward_declare 0 @@ -542,61 +2112,82 @@ - + wxBORDER_SIMPLE + + - - 5 - wxALL - 0 - + + 5 + + 0 + + + bSizer5 + wxVERTICAL + none + + 5 + wxALL + 0 + 1 1 1 1 - + 0 - - + 0 + 0 + 0 + 1 0 - 0 1 1 + + 0 0 + Dock 0 Left + 0 1 1 + 0 0 wxID_ANY - Show fabrication layer + + + 0 0 0 - + 30,30 1 - showFabricationCheckbox + m_btnSortUp 1 protected 1 + + Resizable 1 - + wxBU_EXACTFIT ; ; forward_declare 0 @@ -607,60 +2198,71 @@ + OnComponentSortOrderUp + - - - 5 - wxALL - 0 - + + 5 + wxALL + 0 + 1 1 1 1 - + 0 - - + 0 + 0 + 0 + 1 0 - 1 1 1 + + 0 0 + Dock 0 Left + 0 1 1 + 0 0 wxID_ANY - Show silkscreen + + + 0 0 0 - + 30,30 1 - showSilkscreenCheckbox + m_btnSortDown 1 protected 1 + + Resizable 1 - + wxBU_EXACTFIT ; ; forward_declare 0 @@ -671,60 +2273,71 @@ + OnComponentSortOrderDown + - - - 5 - wxALL - 0 - + + 5 + wxALL + 0 + 1 1 1 1 - + 0 - - + 0 + 0 + 0 + 1 0 - 1 1 1 + + 0 0 + Dock 0 Left + 0 1 1 + 0 0 wxID_ANY - Continuous redraw on drag + + + 0 0 0 - + 30,30 1 - continuousRedrawCheckbox + m_btnSortAdd 1 protected 1 + + Resizable 1 - + wxBU_EXACTFIT ; ; forward_declare 0 @@ -735,62 +2348,71 @@ + OnComponentSortOrderAdd + - - - 5 - wxALL|wxEXPAND - 0 - + + 5 + wxALL + 0 + 1 1 1 1 - + 0 - - + 0 + 0 + 0 + 1 0 - "None" "All" "Selected" 1 1 + + 0 0 + Dock 0 Left + 0 1 1 + 0 0 wxID_ANY - Highlight first pin - 3 + + + 0 0 0 - + 30,30 1 - highlightPin1 + m_btnSortRemove 1 protected 1 + + Resizable - 0 1 - wxRA_SPECIFY_COLS + wxBU_EXACTFIT ; ; forward_declare 0 @@ -801,257 +2423,64 @@ + OnComponentSortOrderRemove + + - - 5 - wxEXPAND - 0 - - - bSizer18 - wxVERTICAL - none - - 5 - wxEXPAND - 1 - - - bSizer19 - wxHORIZONTAL - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Board rotation - 0 - - 0 - - - 0 - - 1 - m_boardRotationLabel - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - - - -1 - - - - 5 - wxEXPAND - 1 - - 0 - protected - 0 - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - 0 - 0 - - 0 - - - 0 - - 1 - rotationDegreeLabel - 1 - - - protected - 1 - - Resizable - 1 - 30,-1 - wxALIGN_RIGHT|wxST_NO_AUTORESIZE - ; ; forward_declare - 0 - - - - - -1 - - - - 5 - - 0 - - 0 - protected - 8 - - - - - - 5 - wxALL|wxEXPAND - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - 36 - - 0 - - -36 - - 0 - - 1 - boardRotationSlider - 1 - - - protected - 1 - - Resizable - 1 - - wxSL_HORIZONTAL - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - 0 - - - - OnBoardRotationSlider - - - - - - 5 - wxALL - 0 - + + + + + + 5 + wxALL|wxEXPAND|wxTOP + 1 + + wxID_ANY + Component blacklist + + blacklistSizer + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + + bSizer412 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bSizer612 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + 1 1 1 1 - + 0 - - + 0 + 0 1 0 - 0 + 1 1 @@ -1059,6 +2488,7 @@ Dock 0 Left + 0 1 1 @@ -1066,7 +2496,6 @@ 0 0 wxID_ANY - Offset back rotation 0 @@ -1074,7 +2503,7 @@ 0 1 - offsetBackRotationCheckbox + blacklistBox 1 @@ -1084,7 +2513,7 @@ Resizable 1 - + wxLB_SINGLE|wxLB_SORT ; ; forward_declare 0 @@ -1094,142 +2523,83 @@ - - - - - 5 - wxALL|wxEXPAND - 0 - - wxID_ANY - Checkboxes - - sbSizer31 - wxHORIZONTAL - 1 - none - - 5 - wxALL - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - - 0 - - 1 - bomCheckboxesCtrl - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - Sourced,Placed - - - - - + wxBORDER_SIMPLE + + - - 5 - wxALL|wxEXPAND - 0 - + + 5 + + 0 + + + bSizer512 + wxVERTICAL + none + + 5 + wxALL + 0 + 1 1 1 1 - + 0 - - + 0 + 0 + 0 + 1 0 - "BOM only" "BOM left, drawings right" "BOM top, drawings bottom" 1 1 + + 0 0 + Dock 0 Left + 0 1 1 + 0 0 wxID_ANY - BOM View - 1 + + + 0 0 0 - + 30,30 1 - bomDefaultView + m_btnBlacklistAdd 1 protected 1 + + Resizable - 1 1 - wxRA_SPECIFY_COLS - ; forward_declare + wxBU_EXACTFIT + ; ; forward_declare 0 @@ -1239,63 +2609,72 @@ + OnComponentBlacklistAdd + - - - 5 - wxALL|wxEXPAND - 0 - + + 5 + wxALL + 0 + 1 1 1 1 - + 0 - - + 0 + 0 + 0 + 1 0 - "Front only" "Front and Back" "Back only" 1 1 + + 0 0 + Dock 0 Left + 0 1 1 + 0 0 wxID_ANY - Layer View - 1 + + + 0 0 0 - + 30,30 1 - layerDefaultView + m_btnBlacklistRemove 1 protected 1 + + Resizable - 1 1 - wxRA_SPECIFY_COLS - ; forward_declare + wxBU_EXACTFIT + ; ; forward_declare 0 @@ -1305,2555 +2684,1295 @@ + OnComponentBlacklistRemove + + - - 5 - wxEXPAND|wxALL - 1 - - wxID_ANY - Miscellaneous - - sbSizer10 - wxVERTICAL - 1 - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Enable compression - - 0 - - - 0 - - 1 - compressionCheckbox - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Open browser - - 0 - - - 0 - - 1 - openBrowserCheckbox - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - - - + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Globs are supported, e.g. MH* + 0 + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Blacklist virtual components + + 0 + + + 0 + + 1 + blacklistVirtualCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Blacklist components with empty value + + 0 + + + 0 + + 1 + blacklistEmptyValCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + - - 0 - wxAUI_MGR_DEFAULT - - - 1 - 1 - impl_virtual - - - 0 + + + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 0 + 1 + impl_virtual + + + 0 + wxID_ANY + + + FieldsPanelBase + + -1,-1 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + OnSize + + + bSizer42 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + wxID_ANY - + Extra data file - GeneralSettingsPanelBase - - -1,-1 - ; ; forward_declare - - 0 - - - wxTAB_TRAVERSAL - OnSize - + sbSizer7 + wxVERTICAL + 1 + none + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + Select a file + + 0 - bSizer32 - wxVERTICAL + 1 + extraDataFilePicker + 1 + + + protected + 1 + + Resizable + 1 + + wxFLP_DEFAULT_STYLE|wxFLP_FILE_MUST_EXIST|wxFLP_OPEN|wxFLP_SMALL|wxFLP_USE_TEXTCTRL + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + Netlist and xml files (*.net; *.xml)|*.net;*.xml + + + wxBORDER_SIMPLE + OnExtraDataFileChanged + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 1 + wxID_ANY + Current variant: + 0 + + 0 + + + 0 + + 1 + variantLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + 5 + wxALL|wxEXPAND + 2 + + wxID_ANY + Fields + + fieldsSizer + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + + bSizer4 + wxHORIZONTAL none - - 5 - wxALL|wxEXPAND - 0 - - wxID_ANY - Bom destination - - sbSizer6 - wxVERTICAL - 1 - none - - 5 - wxEXPAND - 1 - - 2 - wxBOTH - 1 - - 0 - - fgSizer1 - wxFLEX_GROWMODE_SPECIFIED - none - 0 - 0 - - 5 - wxALIGN_CENTER_VERTICAL|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Directory - 0 - - 0 - - - 0 - - 1 - m_staticText8 - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - - - -1 - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - Select bom folder - - 0 - - 1 - bomDirPicker - 1 - - - protected - 1 - - Resizable - 1 - - wxDIRP_SMALL|wxDIRP_USE_TEXTCTRL - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - wxBORDER_SIMPLE - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Name format - 0 - - 0 - - - 0 - - 1 - m_staticText9 - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - - - -1 - - - - 5 - wxEXPAND - 1 - - - bSizer20 - wxHORIZONTAL - none - - 5 - wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - - 0 - - 1 - fileNameFormatTextControl - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - - - 0 - - 0 - - - 0 - 30,30 - 1 - m_btnNameHint - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBU_EXACTFIT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnNameFormatHintClick - - - - - - - + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 1 + 0 + + + + 1 + + + wxALIGN_CENTER + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTER + 30 + "Show" "Group" "Name" + wxALIGN_CENTER + 3 + + + 1 + 0 + Dock + 0 + Left + 0 + 0 + 1 + 0 + 0 + 1 + 1 + + 1 + + + 1 + 0 + 0 + wxID_ANY + + + + 0 + 0 + + 0 + -1,200 + + 0 + + 1 + fieldsGrid + 1 + + + protected + 1 + + Resizable + wxALIGN_CENTER + 0 + + wxALIGN_CENTER + + 2 + 1 + + ; ; forward_declare + 0 + + + + + OnGridCellClicked + - - 5 - wxALL|wxEXPAND - 0 - - wxID_ANY - Additional pcb data - - sbSizer9 - wxHORIZONTAL - 1 - none - - 5 - wxALL - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Include tracks/zones - - 0 - - - 0 - - 1 - includeTracksCheckbox - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - - - 5 - wxALL - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Include nets - - 0 - - - 0 - - 1 - includeNetsCheckbox - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - - - - - 5 - wxALL|wxEXPAND - 1 - + + 5 + + 0 + + + bSizer5 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 wxID_ANY - Component sort order - - sortingSizer - wxVERTICAL - 1 - none - - 5 - wxEXPAND - 1 - - - bSizer4 - wxHORIZONTAL - none - - 5 - wxEXPAND - 1 - - - bSizer6 - wxVERTICAL - none - - 5 - wxALL|wxEXPAND - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - 0 - - 1 - componentSortOrderBox - 1 - - - protected - 1 - - Resizable - 1 - - wxLB_SINGLE - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - wxBORDER_SIMPLE - - - - - - 5 - - 0 - - - bSizer5 - wxVERTICAL - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - - - 0 - - 0 - - - 0 - 30,30 - 1 - m_btnSortUp - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBU_EXACTFIT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnComponentSortOrderUp - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - - - 0 - - 0 - - - 0 - 30,30 - 1 - m_btnSortDown - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBU_EXACTFIT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnComponentSortOrderDown - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - - - 0 - - 0 - - - 0 - 30,30 - 1 - m_btnSortAdd - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBU_EXACTFIT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnComponentSortOrderAdd - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - - - 0 - - 0 - - - 0 - 30,30 - 1 - m_btnSortRemove - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBU_EXACTFIT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnComponentSortOrderRemove - - - - - - + + + 0 + + 0 + + + 0 + 30,30 + 1 + m_btnUp + 1 + + + protected + 1 + + + + Resizable + 1 + + wxBU_EXACTFIT + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnFieldsUp + - - - 5 - wxALL|wxEXPAND|wxTOP - 1 - + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 wxID_ANY - Component blacklist - - blacklistSizer - wxVERTICAL - 1 - none - - 5 - wxEXPAND - 1 - - - bSizer412 - wxHORIZONTAL - none - - 5 - wxEXPAND - 1 - - - bSizer612 - wxVERTICAL - none - - 5 - wxALL|wxEXPAND - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - 0 - - 1 - blacklistBox - 1 - - - protected - 1 - - Resizable - 1 - - wxLB_SINGLE|wxLB_SORT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - wxBORDER_SIMPLE - - - - - - 5 - - 0 - - - bSizer512 - wxVERTICAL - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - - - 0 - - 0 - - - 0 - 30,30 - 1 - m_btnBlacklistAdd - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBU_EXACTFIT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnComponentBlacklistAdd - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - - - 0 - - 0 - - - 0 - 30,30 - 1 - m_btnBlacklistRemove - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBU_EXACTFIT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnComponentBlacklistRemove - - - - - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Globs are supported, e.g. MH* - 0 - - 0 - - - 0 - - 1 - m_staticText1 - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - - - -1 - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Blacklist virtual components - - 0 - - - 0 - - 1 - blacklistVirtualCheckbox - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Blacklist components with empty value - - 0 - - - 0 - - 1 - blacklistEmptyValCheckbox - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - + + + 0 + + 0 + + + 0 + 30,30 + 1 + m_btnDown + 1 + + + protected + 1 + + + + Resizable + 1 + + wxBU_EXACTFIT + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnFieldsDown + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Normalize field name case + + 0 + + + 0 + + 1 + normalizeCaseCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnExtraDataFileChanged + + + - - 0 - wxAUI_MGR_DEFAULT - - - 1 - 1 - impl_virtual - - - 0 + + 5 + wxALL|wxEXPAND + 3 + wxID_ANY - + Board variant - FieldsPanelBase - - -1,-1 - ; ; forward_declare - - 0 - - - wxTAB_TRAVERSAL - OnSize - + sbSizer32 + wxVERTICAL + 1 + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Board variant field name + 0 + + 0 + + + 0 + + 1 + m_staticText5 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + boardVariantFieldBox + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY|wxCB_SORT + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + wxBORDER_SIMPLE + OnBoardVariantFieldChange + + + + 5 + wxEXPAND + 1 + - bSizer42 - wxVERTICAL + bSizer17 + wxHORIZONTAL none - - 5 - wxALL|wxEXPAND - 0 - + + 5 + wxEXPAND + 1 + + + bSizer18 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 wxID_ANY - Extra data file + Whitelist + 0 + + 0 + + + 0 - sbSizer7 - wxVERTICAL - 1 - none - - 5 - wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - Select a file - - 0 - - 1 - extraDataFilePicker - 1 - - - protected - 1 - - Resizable - 1 - - wxFLP_DEFAULT_STYLE|wxFLP_FILE_MUST_EXIST|wxFLP_OPEN|wxFLP_SMALL|wxFLP_USE_TEXTCTRL - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - Netlist and xml files (*.net; *.xml)|*.net;*.xml - - - wxBORDER_SIMPLE - OnExtraDataFileChanged - - + 1 + m_staticText6 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + - - - 5 - wxALL|wxEXPAND - 2 - + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 wxID_ANY - Fields + + 0 + + + 0 - fieldsSizer - wxVERTICAL - 1 - none - - 5 - wxEXPAND - 1 - - - bSizer4 - wxHORIZONTAL - none - - 5 - wxALL|wxEXPAND - 1 - - 1 - 1 - 1 - 1 - - - - - 1 - 0 - - - - 1 - - - wxALIGN_CENTER - - wxALIGN_TOP - 0 - 1 - wxALIGN_CENTER - 30 - "Show" "Group" "Name" - wxALIGN_CENTER - 3 - - - 1 - 0 - Dock - 0 - Left - 0 - 1 - 0 - 0 - 1 - 1 - - 1 - - - 1 - 0 - 0 - wxID_ANY - - - - 0 - 0 - - 0 - -1,200 - - 0 - - 1 - fieldsGrid - 1 - - - protected - 1 - - Resizable - wxALIGN_CENTER - 0 - - wxALIGN_CENTER - - 2 - 1 - - ; ; forward_declare - 0 - - - - - OnGridCellClicked - - - - 5 - - 0 - - - bSizer5 - wxVERTICAL - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - - - 0 - - 0 - - - 0 - 30,30 - 1 - m_btnUp - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBU_EXACTFIT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnFieldsUp - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - 0 - - - - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 1 - - 1 - - - 0 - 0 - wxID_ANY - - - 0 - - 0 - - - 0 - 30,30 - 1 - m_btnDown - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBU_EXACTFIT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnFieldsDown - - - - - - - - 5 - wxALL|wxEXPAND - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Normalize field name case - - 0 - - - 0 - - 1 - normalizeCaseCheckbox - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnExtraDataFileChanged - - + 1 + boardVariantWhitelist + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + wxBORDER_SIMPLE + + - - 5 - wxALL|wxEXPAND - 3 - + + 5 + wxEXPAND + 1 + + + bSizer19 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 wxID_ANY - Board variant + Blacklist + 0 + + 0 + + + 0 - sbSizer32 - wxVERTICAL - 1 - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Board variant field name - 0 - - 0 - - - 0 - - 1 - m_staticText5 - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - - - -1 - - - - 5 - wxALL|wxEXPAND - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - 0 - - 1 - boardVariantFieldBox - 1 - - - protected - 1 - - Resizable - -1 - 1 - - wxCB_READONLY|wxCB_SORT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - wxBORDER_SIMPLE - OnBoardVariantFieldChange - - - - 5 - wxEXPAND - 1 - - - bSizer17 - wxHORIZONTAL - none - - 5 - wxEXPAND - 1 - - - bSizer18 - wxVERTICAL - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Whitelist - 0 - - 0 - - - 0 - - 1 - m_staticText6 - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - - - -1 - - - - 5 - wxALL|wxEXPAND - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - 0 - - 1 - boardVariantWhitelist - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - wxBORDER_SIMPLE - - - - - - 5 - wxEXPAND - 1 - - - bSizer19 - wxVERTICAL - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Blacklist - 0 - - 0 - - - 0 - - 1 - m_staticText7 - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - - - -1 - - - - 5 - wxALL|wxEXPAND - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - 0 - - 1 - boardVariantBlacklist - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - wxBORDER_SIMPLE - - - - - - + 1 + m_staticText7 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + - - - 5 - wxALL|wxEXPAND - 0 - + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 wxID_ANY - DNP field name + + 0 + + + 0 - sbSizer8 - wxVERTICAL - 1 - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Components with this field not empty will be ignored - 0 - - 0 - - - 0 - - 1 - m_staticText4 - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - - - -1 - - - - 5 - wxALL|wxEXPAND - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - 0 - - 1 - dnpFieldBox - 1 - - - protected - 1 - - Resizable - -1 - 1 - - wxCB_READONLY|wxCB_SORT - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - -None- - - - wxBORDER_NONE - - + 1 + boardVariantBlacklist + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + wxBORDER_SIMPLE + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + wxID_ANY + DNP field name + + sbSizer8 + wxVERTICAL + 1 + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Components with this field not empty will be ignored + 0 + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + dnpFieldBox + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY|wxCB_SORT + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + -None- + + + wxBORDER_NONE + + + +