kopia lustrzana https://github.com/inkstitch/inkstitch
149 wiersze
5.5 KiB
Python
149 wiersze
5.5 KiB
Python
# 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)
|