From b4c1531e101575c0c1098a3b86b318070c7167c4 Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Wed, 17 Nov 2021 10:51:28 -0300 Subject: [PATCH] PCB PDF Print: mechanism to change the block title. - Related to #102 - Also added %V to expand the variant name - Documented %v and %V --- CHANGELOG.md | 2 ++ README.md | 14 ++++++---- docs/README.in | 12 +++++---- docs/samples/generic_plot.kibot.yaml | 3 +++ kibot/optionable.py | 9 +++++++ kibot/out_base.py | 27 +++++++++++++++++++ kibot/out_pdf_pcb_print.py | 13 ++++++--- kibot/pre_base.py | 3 +++ kibot/var_base.py | 2 +- tests/yaml_samples/print_pcb.kibot.yaml | 2 ++ .../print_pcb_variant_1.kibot.yaml | 1 + 11 files changed, 73 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1b7171c..4f4a89a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Generic filter: options to match if a field is/isn't defined. - Excellon drill: added `route_mode_for_oval_holes` option. - Default global `dir` option. +- Pattern to expand the variant name: %V +- PCB PDF Print: mechanism to change the block title. (#102) ### Changed - Internal BoM: now components with different Tolerance, Voltage, Current diff --git a/README.md b/README.md index cc66a828..4826c19f 100644 --- a/README.md +++ b/README.md @@ -198,16 +198,18 @@ You can always choose the file name for a particular output. The pattern uses the following expansions: -- **%f** original pcb/sch file name without extension. -- **%F** original pcb/sch file name without extension. Including the directory part of the name. -- **%p** pcb/sch title from pcb metadata. - **%c** company from pcb/sch metadata. -- **%r** revision from pcb/sch metadata. - **%d** pcb/sch date from metadata if available, file modification date otherwise. - **%D** date the script was started. -- **%T** time the script was started. +- **%f** original pcb/sch file name without extension. +- **%F** original pcb/sch file name without extension. Including the directory part of the name. - **%i** a contextual ID, depends on the output type. +- **%p** pcb/sch title from pcb metadata. +- **%r** revision from pcb/sch metadata. +- **%T** time the script was started. - **%x** a suitable extension for the output type. +- **%v** the `file_id` of the current variant. +- **%V** the `name` of the current variant. They are compatible with the ones used by IBoM. The default value for `global.output` is `%f-%i.%x`. @@ -1299,6 +1301,8 @@ Next time you need this list just use an alias, like this: - `plot_sheet_reference`: [boolean=true] Include the title-block. - `scaling`: [number=1.0] Scale factor (0 means autoscaling). - `separated`: [boolean=false] Print layers in separated pages. + - `title`: [string=''] Text used to replace the sheet title. %VALUE expansions are allowed. + If it starts with `+` the text is concatenated. - `variant`: [string=''] Board variant to apply. * PDF Schematic Print (Portable Document Format) diff --git a/docs/README.in b/docs/README.in index 696044ac..e951b9cb 100644 --- a/docs/README.in +++ b/docs/README.in @@ -177,16 +177,18 @@ You can always choose the file name for a particular output. The pattern uses the following expansions: -- **%f** original pcb/sch file name without extension. -- **%F** original pcb/sch file name without extension. Including the directory part of the name. -- **%p** pcb/sch title from pcb metadata. - **%c** company from pcb/sch metadata. -- **%r** revision from pcb/sch metadata. - **%d** pcb/sch date from metadata if available, file modification date otherwise. - **%D** date the script was started. -- **%T** time the script was started. +- **%f** original pcb/sch file name without extension. +- **%F** original pcb/sch file name without extension. Including the directory part of the name. - **%i** a contextual ID, depends on the output type. +- **%p** pcb/sch title from pcb metadata. +- **%r** revision from pcb/sch metadata. +- **%T** time the script was started. - **%x** a suitable extension for the output type. +- **%v** the `file_id` of the current variant. +- **%V** the `name` of the current variant. They are compatible with the ones used by IBoM. The default value for `global.output` is `%f-%i.%x`. diff --git a/docs/samples/generic_plot.kibot.yaml b/docs/samples/generic_plot.kibot.yaml index 8b1a8ddf..9a0cf406 100644 --- a/docs/samples/generic_plot.kibot.yaml +++ b/docs/samples/generic_plot.kibot.yaml @@ -898,6 +898,9 @@ outputs: scaling: 1.0 # [boolean=false] Print layers in separated pages separated: false + # [string=''] Text used to replace the sheet title. %VALUE expansions are allowed. + # If it starts with `+` the text is concatenated + title: '' # [string=''] Board variant to apply variant: '' layers: all diff --git a/kibot/optionable.py b/kibot/optionable.py index 46e9d012..9e039deb 100644 --- a/kibot/optionable.py +++ b/kibot/optionable.py @@ -194,6 +194,13 @@ class Optionable(object): return self.variant.file_id return '' + def _find_variant_name(self): + """ Returns the name for the current variant. + If no variant is defined an empty string is returned. """ + if hasattr(self, 'variant') and self.variant and hasattr(self.variant, 'name'): + return self.variant.name + return '' + def expand_filename_pcb(self, name): """ Expands %* values in filenames. Uses data from the PCB. """ @@ -210,6 +217,7 @@ class Optionable(object): name = name.replace('%r', GS.pcb_rev) name = name.replace('%T', GS.time) name = name.replace('%v', self._find_variant() if self else '') + name = name.replace('%V', self._find_variant_name() if self else '') name = name.replace('%x', self._expand_ext) # sanitize the name to avoid characters illegal in file systems name = name.replace('\\', '/') @@ -232,6 +240,7 @@ class Optionable(object): name = name.replace('%r', GS.sch_rev) name = name.replace('%T', GS.time) name = name.replace('%v', self._find_variant() if self else '') + name = name.replace('%V', self._find_variant_name() if self else '') name = name.replace('%x', self._expand_ext) # sanitize the name to avoid characters illegal in file systems name = name.replace('\\', '/') diff --git a/kibot/out_base.py b/kibot/out_base.py index 141ab702..51ee50cb 100644 --- a/kibot/out_base.py +++ b/kibot/out_base.py @@ -179,6 +179,8 @@ class VariantOptions(BaseOptions): def cross_modules(self, board, comps_hash): """ Draw a cross in all 'not fitted' modules using *.Fab layer """ + if comps_hash is None: + return # Cross the affected components ffab = board.GetLayerID('F.Fab') bfab = board.GetLayerID('B.Fab') @@ -214,6 +216,8 @@ class VariantOptions(BaseOptions): def uncross_modules(self, board, comps_hash): """ Undo the crosses in *.Fab layer """ + if comps_hash is None: + return # Undo the drawings for m in board.GetModules(): ref = m.GetReference() @@ -230,6 +234,8 @@ class VariantOptions(BaseOptions): def remove_paste_and_glue(self, board, comps_hash): """ Remove from solder paste layers the filtered components. """ + if comps_hash is None: + return exclude = LSET() fpaste = board.GetLayerID('F.Paste') bpaste = board.GetLayerID('B.Paste') @@ -279,6 +285,8 @@ class VariantOptions(BaseOptions): return exclude def restore_paste_and_glue(self, board, comps_hash): + if comps_hash is None: + return for m in board.GetModules(): ref = m.GetReference() c = comps_hash.get(ref, None) @@ -296,6 +304,8 @@ class VariantOptions(BaseOptions): def remove_fab(self, board, comps_hash): """ Remove from Fab the excluded components. """ + if comps_hash is None: + return ffab = board.GetLayerID('F.Fab') bfab = board.GetLayerID('B.Fab') old_ffab = [] @@ -321,11 +331,28 @@ class VariantOptions(BaseOptions): self.bfab = bfab def restore_fab(self, board, comps_hash): + if comps_hash is None: + return for gi in self.old_ffab: gi.SetLayer(self.ffab) for gi in self.old_bfab: gi.SetLayer(self.bfab) + def set_title(self, title): + self.old_title = None + if title: + tb = GS.board.GetTitleBlock() + self.old_title = tb.GetTitle() + text = self.expand_filename_pcb(title) + if text[0] == '+': + text = self.old_title+text[1:] + tb.SetTitle(text) + + def restore_title(self): + self.old_title = None + if self.old_title is not None: + GS.board.GetTitleBlock().SetTitle(self.old_title) + def run(self, output_dir): """ Makes the list of components available """ if not self.dnf_filter and not self.variant: diff --git a/kibot/out_pdf_pcb_print.py b/kibot/out_pdf_pcb_print.py index 05424ab4..0c0ff97d 100644 --- a/kibot/out_pdf_pcb_print.py +++ b/kibot/out_pdf_pcb_print.py @@ -43,6 +43,9 @@ class PDF_Pcb_PrintOptions(VariantOptions): """ Print mirrored (X axis inverted). ONLY for KiCad 6 """ self.hide_excluded = False """ Hide components in the Fab layer that are marked as excluded by a variant """ + self.title = '' + """ Text used to replace the sheet title. %VALUE expansions are allowed. + If it starts with `+` the text is concatenated """ super().__init__() self._expand_ext = 'pdf' @@ -71,8 +74,8 @@ class PDF_Pcb_PrintOptions(VariantOptions): copy2(pro_name, pro_copy) return pro_copy - def filter_components(self, board): - if not self._comps: + def filter_components(self, board, force_copy): + if not self._comps and not force_copy: return GS.pcb_file, None comps_hash = self.get_refs_hash() self.cross_modules(board, comps_hash) @@ -85,7 +88,7 @@ class PDF_Pcb_PrintOptions(VariantOptions): logger.debug('Storing filtered PCB to `{}`'.format(fname)) GS.board.Save(fname) # Copy the project: avoids warnings, could carry some options - fproj = self._copy_project(fname) + self._copy_project(fname) self.uncross_modules(board, comps_hash) self.restore_paste_and_glue(board, comps_hash) if self.hide_excluded: @@ -111,13 +114,15 @@ class PDF_Pcb_PrintOptions(VariantOptions): cmd.append('--separate') if self.mirror: cmd.append('--mirror') - board_name, board_dir = self.filter_components(GS.board) + self.set_title(self.title) + board_name, board_dir = self.filter_components(GS.board, self.title != '') cmd.extend([board_name, os.path.dirname(output)]) cmd, video_remove = add_extra_options(cmd) # Add the layers cmd.extend([la.layer for la in self._layers]) # Execute it ret = exec_with_retry(cmd) + self.restore_title() # Remove the temporal PCB if board_dir: logger.debug('Removing temporal variant dir `{}`'.format(board_dir)) diff --git a/kibot/pre_base.py b/kibot/pre_base.py index 27bc40d4..430c8e5e 100644 --- a/kibot/pre_base.py +++ b/kibot/pre_base.py @@ -107,3 +107,6 @@ class BasePreFlight(Registrable): def _find_variant(self): return '' + + def _find_variant_name(self): + return '' diff --git a/kibot/var_base.py b/kibot/var_base.py index 3e27d475..a8f9795f 100644 --- a/kibot/var_base.py +++ b/kibot/var_base.py @@ -21,7 +21,7 @@ class BaseVariant(RegVariant): self.comment = '' """ A comment for documentation purposes """ self.file_id = '' - """ Text to use as the """ + """ Text to use as the replacement for %v expansion """ # * Filters self.pre_transform = Optionable """ [string|list(string)=''] Name of the filter to transform fields before applying other filters. diff --git a/tests/yaml_samples/print_pcb.kibot.yaml b/tests/yaml_samples/print_pcb.kibot.yaml index d6c44595..dbb6b368 100644 --- a/tests/yaml_samples/print_pcb.kibot.yaml +++ b/tests/yaml_samples/print_pcb.kibot.yaml @@ -7,6 +7,8 @@ outputs: comment: "Print F.Cu+F.SilkS" type: pdf_pcb_print dir: Layers + options: + title: 'Fake title for front copper and silk' layers: - layer: F.Cu - layer: F.SilkS diff --git a/tests/yaml_samples/print_pcb_variant_1.kibot.yaml b/tests/yaml_samples/print_pcb_variant_1.kibot.yaml index 13687bee..9806699c 100644 --- a/tests/yaml_samples/print_pcb_variant_1.kibot.yaml +++ b/tests/yaml_samples/print_pcb_variant_1.kibot.yaml @@ -15,4 +15,5 @@ outputs: options: variant: default scaling: 0 + title: 'Hello %V' layers: F.Fab