# Authors: see git history # # Copyright (c) 2010 Authors # Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. import os import inkex from lxml.etree import Comment from ..commands import is_command, layer_commands from ..elements import EmbroideryElement, nodes_to_elements from ..elements.clone import is_clone from ..i18n import _ from ..marker import has_marker from ..metadata import InkStitchMetadata from ..svg import generate_unique_id from ..svg.tags import (CONNECTOR_TYPE, EMBROIDERABLE_TAGS, INKSCAPE_GROUPMODE, NOT_EMBROIDERABLE_TAGS, SVG_CLIPPATH_TAG, SVG_DEFS_TAG, SVG_GROUP_TAG, SVG_MASK_TAG) from ..update import update_inkstitch_document class InkstitchExtension(inkex.EffectExtension): """Base class for Inkstitch extensions. Not intended for direct use.""" def load(self, *args, **kwargs): document = super().load(*args, **kwargs) update_inkstitch_document(document) return document @classmethod def name(cls): # Convert CamelCase to snake_case return cls.__name__[0].lower() + ''.join([x if x.islower() else f'_{x.lower()}' for x in cls.__name__[1:]]) def hide_all_layers(self): for g in self.document.getroot().findall(SVG_GROUP_TAG): if g.get(INKSCAPE_GROUPMODE) == "layer": g.set("style", "display:none") def get_current_layer(self): # if no layer is selected, inkex defaults to the root, which isn't # particularly useful current_layer = self.svg.get_current_layer() if current_layer is self.document.getroot(): try: current_layer = self.document.xpath(".//svg:g[@inkscape:groupmode='layer']", namespaces=inkex.NSS)[0] except IndexError: # No layers at all?? Fine, we'll stick with the default. pass return current_layer def no_elements_error(self): if self.svg.selection: # l10n This was previously: "No embroiderable paths selected." inkex.errormsg(_("Ink/Stitch doesn't know how to work with any of the objects you've selected. " "Please check if selected elements are visible.") + "\n") else: inkex.errormsg(_("There are no objects in the entire document that Ink/Stitch knows how to work with.") + "\n") inkex.errormsg(_("Tip: Run Extensions > Ink/Stitch > Troubleshoot > Troubleshoot Objects") + "\n") def descendants(self, node, selected=False, troubleshoot=False): # noqa: C901 nodes = [] if node.tag == Comment: return [] element = EmbroideryElement(node) if element.has_command('ignore_object'): return [] if node.tag == SVG_GROUP_TAG and node.get(INKSCAPE_GROUPMODE) == "layer": if len(list(layer_commands(node, "ignore_layer"))): return [] if (node.tag in EMBROIDERABLE_TAGS or node.tag == SVG_GROUP_TAG) and element.get_style('display', 'inline') is None: return [] # defs, masks and clippaths can contain embroiderable elements # but should never be rendered directly. if node.tag in [SVG_DEFS_TAG, SVG_MASK_TAG, SVG_CLIPPATH_TAG]: return [] # command connectors with a fill color set, will glitch into the elements list if is_command(node) or node.get(CONNECTOR_TYPE): return [] if self.svg.selection: if node in list(self.svg.selection): selected = True else: # if the user didn't select anything that means we process everything selected = True for child in node: nodes.extend(self.descendants(child, selected, troubleshoot)) if selected: if node.tag == SVG_GROUP_TAG: pass elif (node.tag in EMBROIDERABLE_TAGS or is_clone(node)) and not has_marker(node): nodes.append(node) # add images, text and elements with a marker for the troubleshoot extension elif troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or has_marker(node)): nodes.append(node) return nodes def get_nodes(self, troubleshoot=False): # Postorder traversal of selected nodes and their descendants. # Returns all nodes if there is no selection. return self.descendants(self.document.getroot(), troubleshoot=troubleshoot) def get_elements(self, troubleshoot=False): self.elements = nodes_to_elements(self.get_nodes(troubleshoot)) if self.elements: return True if not troubleshoot: self.no_elements_error() return False def elements_to_stitch_groups(self, elements): stitch_groups = [] for element in elements: if stitch_groups: last_stitch_group = stitch_groups[-1] else: last_stitch_group = None stitch_groups.extend(element.embroider(last_stitch_group)) return stitch_groups def get_inkstitch_metadata(self): return InkStitchMetadata(self.svg) def get_base_file_name(self): svg_filename = self.document.getroot().get(inkex.addNS('docname', 'sodipodi'), "embroidery.svg") return os.path.splitext(svg_filename)[0] def uniqueId(self, prefix, make_new_id=True): """Override inkex.Effect.uniqueId with a nicer naming scheme.""" return generate_unique_id(self.document, prefix)