diff --git a/lib/commands.py b/lib/commands.py index f2ab8c3ee..ea6d35091 100644 --- a/lib/commands.py +++ b/lib/commands.py @@ -46,10 +46,12 @@ COMMANDS = { # L10N command attached to an object "satin_cut_point": N_("Satin cut point (use with Cut Satin Column)"), - # L10N command that affects a layer "ignore_layer": N_("Ignore layer (do not stitch any objects in this layer)"), + # L10N command that affects a group + "pattern_group": N_("Strokes in this group will be interpretet as a pattern"), + # L10N command that affects entire document "origin": N_("Origin for exported embroidery files"), @@ -58,6 +60,7 @@ COMMANDS = { } OBJECT_COMMANDS = ["fill_start", "fill_end", "satin_start", "satin_end", "stop", "trim", "ignore_object", "satin_cut_point"] +GROUP_COMMANDS = ["pattern_group"] LAYER_COMMANDS = ["ignore_layer"] GLOBAL_COMMANDS = ["origin", "stop_position"] @@ -184,6 +187,12 @@ def find_commands(node): return commands +def group_commands(node, command): + xpath = "./ancestor::svg:g/svg:use[@xlink:href='#inkstitch_%(command)s']" % dict(id=node.get('id'), command=command) + group_command = node.xpath(xpath, namespaces=inkex.NSS) + return group_command + + def layer_commands(layer, command): """Find standalone (unconnected) command symbols in this layer.""" diff --git a/lib/elements/satin_column.py b/lib/elements/satin_column.py index 3f5f05e55..43948e425 100644 --- a/lib/elements/satin_column.py +++ b/lib/elements/satin_column.py @@ -6,7 +6,7 @@ from copy import deepcopy from itertools import chain -from inkex import paths +from inkex import paths, NSS from shapely import affinity as shaffinity from shapely import geometry as shgeo from shapely.ops import nearest_points @@ -14,6 +14,7 @@ from shapely.ops import nearest_points from ..i18n import _ from ..svg import (PIXELS_PER_MM, apply_transforms, line_strings_to_csp, point_lists_to_csp) +from ..svg.tags import EMBROIDERABLE_TAGS from ..utils import Point, cache, collapse_duplicate_point, cut from .element import EmbroideryElement, Patch, param from .validation import ValidationError, ValidationWarning @@ -577,10 +578,13 @@ class SatinColumn(EmbroideryElement): return SatinColumn(node) def get_patterns(self): - xpath = ".//*[@inkstitch:pattern='%(id)s']" % dict(id=self.node.get('id')) - patterns = self.node.getroottree().getroot().xpath(xpath) + xpath = "./ancestor::svg:g[svg:use[@xlink:href='#inkstitch_pattern_group']]//*[not(@inkstitch:satin_column='true')]" + patterns = self.node.xpath(xpath, namespaces=NSS) line_strings = [] for pattern in patterns: + # TODO: exclude fills in case we will want to use them with the pattern too + if pattern.tag not in EMBROIDERABLE_TAGS: + continue d = pattern.get_path() path = paths.Path(d).to_superpath() path = apply_transforms(path, pattern) diff --git a/lib/elements/utils.py b/lib/elements/utils.py index 03ea48d4d..cbac3d40c 100644 --- a/lib/elements/utils.py +++ b/lib/elements/utils.py @@ -17,6 +17,7 @@ from .polyline import Polyline from .satin_column import SatinColumn from .stroke import Stroke from .text import TextObject +from ..commands import group_commands def node_to_elements(node): # noqa: C901 @@ -29,7 +30,8 @@ def node_to_elements(node): # noqa: C901 elif node.tag == SVG_PATH_TAG and not node.get('d', ''): return [EmptyDObject(node)] - elif node.get(INKSTITCH_ATTRIBS['pattern']): + # TODO: exclude fills + elif group_commands(node, 'pattern_group') and not node.get(INKSTITCH_ATTRIBS['satin_column']): return [PatternObject(node)] elif node.tag in EMBROIDERABLE_TAGS: diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index 70df7c373..25f835c33 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -5,7 +5,6 @@ from lib.extensions.troubleshoot import Troubleshoot -from .apply_satin_pattern import ApplySatinPattern from .auto_satin import AutoSatin from .break_apart import BreakApart from .cleanup import Cleanup @@ -46,7 +45,6 @@ __all__ = extensions = [StitchPlanPreview, GlobalCommands, ConvertToSatin, CutSatin, - ApplySatinPattern, AutoSatin, Lettering, LetteringGenerateJson, diff --git a/lib/extensions/apply_satin_pattern.py b/lib/extensions/apply_satin_pattern.py deleted file mode 100644 index 47eb4d836..000000000 --- a/lib/extensions/apply_satin_pattern.py +++ /dev/null @@ -1,79 +0,0 @@ -# Authors: see git history -# -# Copyright (c) 2021 Authors -# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. - -import inkex -from lxml import etree - -from ..elements import SatinColumn -from ..i18n import _ -from ..svg.tags import INKSTITCH_ATTRIBS, SVG_DEFS_TAG -from .base import InkstitchExtension - - -class ApplySatinPattern(InkstitchExtension): - # Add inkstitch:pattern attribute to selected patterns. The patterns will be projected on a satin column, which must be in the selection too - - def effect(self): - if not self.get_elements(): - return - - if not self.svg.selected or not any(isinstance(item, SatinColumn) for item in self.elements) or len(self.svg.selected) < 2: - inkex.errormsg(_("Please select at least one satin column and a pattern.")) - return - - if sum(isinstance(item, SatinColumn) for item in self.elements) > 1: - inkex.errormsg(_("Please select only one satin column.")) - return - - satin_id = self.get_satin_column().node.get('id', None) - patterns = self.get_patterns() - - for pattern in patterns: - pattern.node.set(INKSTITCH_ATTRIBS['pattern'], satin_id) - self.set_marker(pattern.node) - - def get_satin_column(self): - return list(filter(lambda satin: isinstance(satin, SatinColumn), self.elements))[0] - - def get_patterns(self): - return list(filter(lambda satin: not isinstance(satin, SatinColumn), self.elements)) - - def set_marker(self, node): - document = node.getroottree().getroot() - xpath = ".//marker[@id='inkstitch-pattern-marker']" - pattern_marker = document.xpath(xpath) - if not pattern_marker: - # get or create def element - defs = document.find(SVG_DEFS_TAG) - if defs is None: - defs = etree.SubElement(document, SVG_DEFS_TAG) - - # insert marker - marker = """ - - - - - """ # noqa: E501 - defs.append(etree.fromstring(marker)) - - # attach marker to node - style = node.get('style', '').split(";") - import sys - print(style, file=sys.stderr) - style = [i for i in style if not i.startswith('marker-start')] - style.append('marker-start:url(#inkstitch-pattern-marker)') - node.set('style', ";".join(style)) diff --git a/lib/extensions/base.py b/lib/extensions/base.py index 00d4a00df..ce5f8b1d8 100644 --- a/lib/extensions/base.py +++ b/lib/extensions/base.py @@ -12,7 +12,7 @@ import inkex from lxml import etree from stringcase import snakecase -from ..commands import is_command, layer_commands +from ..commands import is_command, layer_commands, group_commands from ..elements import EmbroideryElement, nodes_to_elements from ..elements.clone import is_clone from ..i18n import _ @@ -171,9 +171,12 @@ class InkstitchExtension(inkex.Effect): if selected: if node.tag == SVG_GROUP_TAG: pass - elif (node.tag in EMBROIDERABLE_TAGS or is_clone(node)) and not node.get(INKSTITCH_ATTRIBS['pattern']): + elif ((node.tag in EMBROIDERABLE_TAGS or is_clone(node)) and not + (len(list(group_commands(node, 'pattern_group'))) and not node.get(INKSTITCH_ATTRIBS['satin_column']))): nodes.append(node) - elif troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or node.get(INKSTITCH_ATTRIBS['pattern'])): + # add images, text and patterns for the troubleshoot extension + elif (troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or + (len(list(group_commands(node, 'pattern_group'))) and not node.get(INKSTITCH_ATTRIBS['satin_column'])))): nodes.append(node) return nodes diff --git a/symbols/inkstitch.svg b/symbols/inkstitch.svg index 4a67ae1cd..f380d1064 100644 --- a/symbols/inkstitch.svg +++ b/symbols/inkstitch.svg @@ -58,6 +58,21 @@ id="title9425">Ink/Stitch Commands + + Pattern group + + + + <use + xlink:href="#inkstitch_pattern_group" + id="use9462" + x="0" + y="0" + width="100%" + height="100%" + transform="translate(189.0002,37.680421)" /> <use xlink:href="#inkstitch_trim" id="use9461" diff --git a/templates/apply_satin_pattern.xml b/templates/apply_satin_pattern.xml deleted file mode 100644 index e52fb1a41..000000000 --- a/templates/apply_satin_pattern.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <name>{% trans %}Apply Satin Pattern{% endtrans %}</name> - <id>org.inkstitch.apply_satin_pattern.{{ locale }}</id> - <param name="extension" type="string" gui-hidden="true">apply_satin_pattern</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu name="Ink/Stitch"> - <submenu name="{% trans %}Satin Tools{% endtrans %}" /> - </submenu> - </effects-menu> - </effect> - <script> - {{ command_tag | safe }} - </script> -</inkscape-extension>