kopia lustrzana https://github.com/inkstitch/inkstitch
Fix lettering scale, etc. (#1620)
* fix lettering scale * adapt to updated inkex: transform operator, selections * fix #1597 * no traceback error message on broken satin columns * highlight troubleshoot "steps to solve" through additional headline * set a minimum value for running stitch repeats * rename "import" thread list to "apply" thread listpull/1644/head
rodzic
4058712139
commit
f9d57f6ea5
lib
elements
extensions
lettering
stitch_plan
|
@ -5,8 +5,6 @@
|
|||
|
||||
from math import atan, degrees
|
||||
|
||||
import inkex
|
||||
|
||||
from ..commands import is_command, is_command_symbol
|
||||
from ..i18n import _
|
||||
from ..svg.path import get_node_transform
|
||||
|
@ -128,7 +126,7 @@ class Clone(EmbroideryElement):
|
|||
return patches
|
||||
|
||||
def get_clone_style(self, style_name, node, default=None):
|
||||
style = inkex.styles.AttrFallbackStyle(node).get(style_name) or default
|
||||
style = node.style[style_name] or default
|
||||
return style
|
||||
|
||||
def center(self, source_node):
|
||||
|
|
|
@ -6,17 +6,18 @@
|
|||
from copy import deepcopy
|
||||
from itertools import chain
|
||||
|
||||
from inkex import paths
|
||||
from shapely import affinity as shaffinity
|
||||
from shapely import geometry as shgeo
|
||||
from shapely.ops import nearest_points
|
||||
|
||||
from .element import EmbroideryElement, param
|
||||
from .validation import ValidationError, ValidationWarning
|
||||
from inkex import paths
|
||||
|
||||
from ..i18n import _
|
||||
from ..stitch_plan import StitchGroup
|
||||
from ..svg import line_strings_to_csp, point_lists_to_csp
|
||||
from ..utils import Point, cache, collapse_duplicate_point, cut
|
||||
from .element import EmbroideryElement, param
|
||||
from .validation import ValidationError, ValidationWarning
|
||||
|
||||
|
||||
class SatinHasFillError(ValidationError):
|
||||
|
@ -51,6 +52,15 @@ class UnequalPointsError(ValidationError):
|
|||
]
|
||||
|
||||
|
||||
class NotStitchableError(ValidationError):
|
||||
name = _("Not stitchable satin column")
|
||||
description = _("A satin column consists out of two rails and one or more rungs. This satin column may have a different setup.")
|
||||
steps_to_solve = [
|
||||
_('Make sure your satin column is not a combination of multiple satin columns.'),
|
||||
_('Go to our website and read how a satin column should look like https://inkstitch.org/docs/stitches/satin-column/'),
|
||||
]
|
||||
|
||||
|
||||
rung_message = _("Each rung should intersect both rails once.")
|
||||
|
||||
|
||||
|
@ -422,6 +432,9 @@ class SatinColumn(EmbroideryElement):
|
|||
if not intersection.is_empty and not isinstance(intersection, shgeo.Point):
|
||||
yield TooManyIntersectionsError(rung.interpolate(0.5, normalized=True))
|
||||
|
||||
if not self.to_stitch_groups():
|
||||
yield NotStitchableError(self.shape.centroid)
|
||||
|
||||
def reverse(self):
|
||||
"""Return a new SatinColumn like this one but in the opposite direction.
|
||||
|
||||
|
@ -859,7 +872,7 @@ class SatinColumn(EmbroideryElement):
|
|||
points.append(Point(split_point.x, split_point.y))
|
||||
return [points, split_count]
|
||||
|
||||
def to_stitch_groups(self, last_patch):
|
||||
def to_stitch_groups(self, last_patch=None):
|
||||
# Stitch a variable-width satin column, zig-zagging between two paths.
|
||||
|
||||
# The algorithm will draw zigzags between each consecutive pair of
|
||||
|
@ -884,4 +897,7 @@ class SatinColumn(EmbroideryElement):
|
|||
else:
|
||||
patch += self.do_satin()
|
||||
|
||||
if not patch.stitches:
|
||||
return []
|
||||
|
||||
return [patch]
|
||||
|
|
|
@ -77,7 +77,8 @@ class Stroke(EmbroideryElement):
|
|||
default="1",
|
||||
sort_index=1)
|
||||
def repeats(self):
|
||||
return self.get_int_param("repeats", 1)
|
||||
repeats = self.get_int_param("repeats", 1)
|
||||
return max(1, repeats)
|
||||
|
||||
@property
|
||||
def paths(self):
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
from lib.extensions.troubleshoot import Troubleshoot
|
||||
|
||||
from .apply_threadlist import ApplyThreadlist
|
||||
from .auto_satin import AutoSatin
|
||||
from .break_apart import BreakApart
|
||||
from .cleanup import Cleanup
|
||||
|
@ -18,7 +19,6 @@ from .embroider_settings import EmbroiderSettings
|
|||
from .flip import Flip
|
||||
from .generate_palette import GeneratePalette
|
||||
from .global_commands import GlobalCommands
|
||||
from .import_threadlist import ImportThreadlist
|
||||
from .input import Input
|
||||
from .install import Install
|
||||
from .install_custom_palette import InstallCustomPalette
|
||||
|
@ -71,7 +71,7 @@ __all__ = extensions = [StitchPlanPreview,
|
|||
RemoveEmbroiderySettings,
|
||||
Cleanup,
|
||||
BreakApart,
|
||||
ImportThreadlist,
|
||||
ApplyThreadlist,
|
||||
InstallCustomPalette,
|
||||
GeneratePalette,
|
||||
PaletteSplitText,
|
||||
|
|
|
@ -14,7 +14,12 @@ from ..threads import ThreadCatalog
|
|||
from .base import InkstitchExtension
|
||||
|
||||
|
||||
class ImportThreadlist(InkstitchExtension):
|
||||
class ApplyThreadlist(InkstitchExtension):
|
||||
'''
|
||||
Applies colors of a thread list to elements
|
||||
Count of colors and elements should fit together
|
||||
Use case: reapply colors to e.g. a dst file
|
||||
'''
|
||||
def __init__(self, *args, **kwargs):
|
||||
InkstitchExtension.__init__(self, *args, **kwargs)
|
||||
self.arg_parser.add_argument("-f", "--filepath", type=str, default="", dest="filepath")
|
||||
|
@ -23,7 +28,7 @@ class ImportThreadlist(InkstitchExtension):
|
|||
|
||||
def effect(self):
|
||||
# Remove selection, we want all the elements in the document
|
||||
self.svg.selected.clear()
|
||||
self.svg.selection.clear()
|
||||
|
||||
if not self.get_elements():
|
||||
return
|
|
@ -44,7 +44,7 @@ class AutoSatin(CommandsExtension):
|
|||
if not self.get_elements():
|
||||
return
|
||||
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
# L10N auto-route satin columns extension
|
||||
inkex.errormsg(_("Please select one or more satin columns."))
|
||||
return False
|
||||
|
|
|
@ -121,7 +121,7 @@ class InkstitchExtension(inkex.Effect):
|
|||
return current_layer
|
||||
|
||||
def no_elements_error(self):
|
||||
if self.svg.selected:
|
||||
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.") + "\n")
|
||||
else:
|
||||
|
@ -156,8 +156,8 @@ class InkstitchExtension(inkex.Effect):
|
|||
if is_command(node) or node.get(CONNECTOR_TYPE):
|
||||
return []
|
||||
|
||||
if self.svg.selected:
|
||||
if node.get("id") in self.svg.selected:
|
||||
if self.svg.selection:
|
||||
if node.get("id") in self.svg.selection:
|
||||
selected = True
|
||||
else:
|
||||
# if the user didn't select anything that means we process everything
|
||||
|
@ -188,14 +188,6 @@ class InkstitchExtension(inkex.Effect):
|
|||
self.no_elements_error()
|
||||
return False
|
||||
|
||||
def get_selected_in_order(self):
|
||||
selected = []
|
||||
for i in self.options.ids:
|
||||
path = '//*[@id="%s"]' % i
|
||||
for node in self.document.xpath(path, namespaces=inkex.NSS):
|
||||
selected.append(node)
|
||||
return selected
|
||||
|
||||
def elements_to_stitch_groups(self, elements):
|
||||
patches = []
|
||||
for element in elements:
|
||||
|
|
|
@ -27,7 +27,7 @@ class BreakApart(InkstitchExtension):
|
|||
self.minimum_size = 5
|
||||
|
||||
def effect(self): # noqa: C901
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
inkex.errormsg(_("Please select one or more fill areas to break apart."))
|
||||
return
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class Cleanup(InkstitchExtension):
|
|||
self.fill_threshold = self.options.fill_threshold
|
||||
self.stroke_threshold = self.options.stroke_threshold
|
||||
|
||||
self.svg.selected.clear()
|
||||
self.svg.selection.clear()
|
||||
|
||||
count = 0
|
||||
svg = self.document.getroot()
|
||||
|
|
|
@ -31,7 +31,7 @@ class ConvertToSatin(InkstitchExtension):
|
|||
if not self.get_elements():
|
||||
return
|
||||
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
inkex.errormsg(_("Please select at least one line to convert to a satin column."))
|
||||
return
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class ConvertToStroke(InkstitchExtension):
|
|||
self.arg_parser.add_argument("-k", "--keep_satin", type=inkex.Boolean, default=False, dest="keep_satin")
|
||||
|
||||
def effect(self):
|
||||
if not self.svg.selected or not self.get_elements():
|
||||
if not self.svg.selection or not self.get_elements():
|
||||
inkex.errormsg(_("Please select at least one satin column to convert to a running stitch."))
|
||||
return
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class CutSatin(InkstitchExtension):
|
|||
if not self.get_elements():
|
||||
return
|
||||
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
inkex.errormsg(_("Please select one or more satin columns to cut."))
|
||||
return
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class CutworkSegmentation(InkstitchExtension):
|
|||
self.arg_parser.add_argument("-k", "--keep_original", type=inkex.Boolean, default=False, dest="keep_original")
|
||||
|
||||
def effect(self):
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
inkex.errormsg(_("Please select one or more stroke elements."))
|
||||
return
|
||||
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
# Copyright (c) 2021 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
import inkex
|
||||
from inkex import NSS, ShapeElement, errormsg
|
||||
|
||||
from ..i18n import _
|
||||
from ..svg.tags import EMBROIDERABLE_TAGS, SVG_GROUP_TAG
|
||||
from .base import InkstitchExtension
|
||||
|
||||
|
||||
|
@ -14,36 +13,29 @@ class DuplicateParams(InkstitchExtension):
|
|||
# Transfer inkstitch namespaced attributes from the first selected element to the rest of selection
|
||||
|
||||
def effect(self):
|
||||
objects = self.get_selected_in_order()
|
||||
objects = self.svg.selection.get(ShapeElement)
|
||||
if len(objects) < 2:
|
||||
inkex.errormsg(_("This function copies Ink/Stitch parameters from the first selected element to the rest of the selection. "
|
||||
"Please select at least two elements."))
|
||||
errormsg(_("This function copies Ink/Stitch parameters from the first selected element to the rest of the selection. "
|
||||
"Please select at least two elements."))
|
||||
return
|
||||
|
||||
copy_from = objects[0]
|
||||
copy_from = objects.first()
|
||||
copy_from_attribs = self.get_inkstitch_attributes(copy_from)
|
||||
|
||||
copy_to_selection = objects[1:]
|
||||
self.copy_to = []
|
||||
|
||||
# extract copy_to group elements
|
||||
for element in copy_to_selection:
|
||||
if element.tag == SVG_GROUP_TAG:
|
||||
for descendant in element.iterdescendants(EMBROIDERABLE_TAGS):
|
||||
self.copy_to.append(descendant)
|
||||
elif element.tag in EMBROIDERABLE_TAGS:
|
||||
self.copy_to.append(element)
|
||||
copy_to = objects
|
||||
|
||||
# remove inkstitch params from copy_to elements
|
||||
for element in self.copy_to:
|
||||
for element in copy_to:
|
||||
if element == copy_to.first():
|
||||
continue
|
||||
copy_to_attribs = self.get_inkstitch_attributes(element)
|
||||
for attrib in copy_to_attribs:
|
||||
element.pop(attrib)
|
||||
|
||||
# paste inkstitch params from copy_from element to copy_to elements
|
||||
for attrib in copy_from_attribs:
|
||||
for element in self.copy_to:
|
||||
for element in copy_to:
|
||||
element.attrib[attrib] = copy_from_attribs[attrib]
|
||||
|
||||
def get_inkstitch_attributes(self, node):
|
||||
return {k: v for k, v in node.attrib.iteritems() if inkex.NSS['inkstitch'] in k}
|
||||
return {k: v for k, v in node.attrib.iteritems() if NSS['inkstitch'] in k}
|
||||
|
|
|
@ -24,7 +24,7 @@ class Flip(InkstitchExtension):
|
|||
if not self.get_elements():
|
||||
return
|
||||
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
inkex.errormsg(_("Please select one or more satin columns to flip."))
|
||||
return
|
||||
|
||||
|
|
|
@ -9,10 +9,11 @@ import sys
|
|||
from base64 import b64decode
|
||||
|
||||
import appdirs
|
||||
import inkex
|
||||
import wx
|
||||
import wx.adv
|
||||
|
||||
import inkex
|
||||
|
||||
from ..elements import nodes_to_elements
|
||||
from ..gui import PresetsPanel, SimulatorPreview, info_dialog
|
||||
from ..i18n import _
|
||||
|
@ -272,12 +273,15 @@ class LetteringFrame(wx.Frame):
|
|||
font.render_text(self.settings.text, destination_group, back_and_forth=self.settings.back_and_forth, trim=self.settings.trim)
|
||||
except FontError as e:
|
||||
if raise_error:
|
||||
inkex.errormsg("Error: Text cannot be applied to the document.\n%s" % e)
|
||||
inkex.errormsg(_("Error: Text cannot be applied to the document.\n%s") % e)
|
||||
return
|
||||
else:
|
||||
pass
|
||||
|
||||
if self.settings.scale != 100:
|
||||
# destination_group isn't always the text scaling group (but also the parent group)
|
||||
# the text scaling group label is dependend on the user language, so it would break in international file exchange if we used it
|
||||
# scaling (correction transform) on the parent group is already applied, so let's use that for recognition
|
||||
if self.settings.scale != 100 and not destination_group.get('transform', None):
|
||||
destination_group.attrib['transform'] = 'scale(%s)' % (self.settings.scale / 100.0)
|
||||
|
||||
def generate_patches(self, abort_early=None):
|
||||
|
@ -395,10 +399,10 @@ class Lettering(CommandsExtension):
|
|||
self.cancelled = True
|
||||
|
||||
def get_or_create_group(self):
|
||||
if self.svg.selected:
|
||||
if self.svg.selection:
|
||||
groups = set()
|
||||
|
||||
for node in self.svg.selected.values():
|
||||
for node in self.svg.selection:
|
||||
if node.tag == SVG_GROUP_TAG and INKSTITCH_LETTERING in node.attrib:
|
||||
groups.add(node)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class ObjectCommands(CommandsExtension):
|
|||
if not self.get_elements():
|
||||
return
|
||||
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
inkex.errormsg(_("Please select one or more objects to which to attach commands."))
|
||||
return
|
||||
|
||||
|
|
|
@ -22,22 +22,21 @@ class PaletteSplitText(InkstitchExtension):
|
|||
|
||||
line_height = self.options.line_height
|
||||
|
||||
for text in self.svg.selected:
|
||||
if type(text) == inkex.elements.TextElement:
|
||||
parent = text.getparent()
|
||||
content = text.get_text()
|
||||
lines = content.split('\n')
|
||||
lines.reverse()
|
||||
style = text.get('style')
|
||||
x = text.get('x')
|
||||
y = text.get('y')
|
||||
y = float(y) + (len(lines) - 1) * line_height
|
||||
for line in lines:
|
||||
element = inkex.TextElement()
|
||||
element.text = line
|
||||
element.set('style', style)
|
||||
element.set('x', x)
|
||||
element.set('y', str(y))
|
||||
y = float(y) - line_height
|
||||
parent.insert(0, element)
|
||||
parent.remove(text)
|
||||
for text in self.svg.selection.get(inkex.elements.TextElement):
|
||||
parent = text.getparent()
|
||||
content = text.get_text()
|
||||
lines = content.split('\n')
|
||||
lines.reverse()
|
||||
style = text.get('style')
|
||||
x = text.get('x')
|
||||
y = text.get('y')
|
||||
y = float(y) + (len(lines) - 1) * line_height
|
||||
for line in lines:
|
||||
element = inkex.TextElement()
|
||||
element.text = line
|
||||
element.set('style', style)
|
||||
element.set('x', x)
|
||||
element.set('y', str(y))
|
||||
y = float(y) - line_height
|
||||
parent.insert(0, element)
|
||||
parent.remove(text)
|
||||
|
|
|
@ -301,7 +301,7 @@ class Print(InkstitchExtension):
|
|||
# objects. It's almost certain they meant to print the whole design.
|
||||
# If they really wanted to print just a few objects, they could set
|
||||
# the rest invisible temporarily.
|
||||
self.svg.selected.clear()
|
||||
self.svg.selection.clear()
|
||||
|
||||
if not self.get_elements():
|
||||
return
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
# Copyright (c) 2010 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
from inkex import NSS, Boolean
|
||||
from inkex import NSS, Boolean, ShapeElement
|
||||
|
||||
from ..commands import find_commands
|
||||
from ..svg.svg import find_elements
|
||||
from ..svg.tags import EMBROIDERABLE_TAGS, SVG_GROUP_TAG
|
||||
from .base import InkstitchExtension
|
||||
|
||||
|
||||
|
@ -36,7 +35,7 @@ class RemoveEmbroiderySettings(InkstitchExtension):
|
|||
self.remove_element(print_setting)
|
||||
|
||||
def remove_params(self):
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
xpath = ".//svg:path|.//svg:circle|.//svg:rect|.//svg:ellipse"
|
||||
elements = find_elements(self.svg, xpath)
|
||||
self.remove_inkstitch_attributes(elements)
|
||||
|
@ -45,7 +44,7 @@ class RemoveEmbroiderySettings(InkstitchExtension):
|
|||
self.remove_inkstitch_attributes(elements)
|
||||
|
||||
def remove_commands(self):
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
# remove intact command groups
|
||||
xpath = ".//svg:g[starts-with(@id,'command_group')]"
|
||||
groups = find_elements(self.svg, xpath)
|
||||
|
@ -58,7 +57,7 @@ class RemoveEmbroiderySettings(InkstitchExtension):
|
|||
group = command.connector.getparent()
|
||||
group.getparent().remove(group)
|
||||
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
# remove standalone commands and ungrouped object commands
|
||||
standalone_commands = ".//svg:use[starts-with(@xlink:href, '#inkstitch_')]|.//svg:path[starts-with(@id, 'command_connector')]"
|
||||
self.remove_elements(standalone_commands)
|
||||
|
@ -68,14 +67,7 @@ class RemoveEmbroiderySettings(InkstitchExtension):
|
|||
self.remove_elements(symbols)
|
||||
|
||||
def get_selected_elements(self):
|
||||
elements = []
|
||||
for node in self.svg.selected.values():
|
||||
if node.tag == SVG_GROUP_TAG:
|
||||
for child in node.iterdescendants(EMBROIDERABLE_TAGS):
|
||||
elements.append(child)
|
||||
else:
|
||||
elements.append(node)
|
||||
return elements
|
||||
return self.svg.selection.get(ShapeElement)
|
||||
|
||||
def remove_elements(self, xpath):
|
||||
elements = find_elements(self.svg, xpath)
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
# Copyright (c) 2010 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
from inkex import errormsg
|
||||
|
||||
from ..i18n import _
|
||||
from .base import InkstitchExtension
|
||||
|
||||
|
||||
|
@ -11,10 +14,15 @@ class Reorder(InkstitchExtension):
|
|||
# were selected.
|
||||
|
||||
def effect(self):
|
||||
objects = self.get_selected_in_order()
|
||||
objects = self.svg.selection
|
||||
|
||||
for obj in objects[1:]:
|
||||
obj.getparent().remove(obj)
|
||||
if not objects:
|
||||
errormsg(_("Please select at least to elements to reorder."))
|
||||
return
|
||||
|
||||
for obj in objects:
|
||||
if not obj == objects.first():
|
||||
obj.getparent().remove(obj)
|
||||
|
||||
insert_parent = objects[0].getparent()
|
||||
insert_pos = insert_parent.index(objects[0])
|
||||
|
|
|
@ -17,7 +17,7 @@ class SelectionToPattern(InkstitchExtension):
|
|||
if not self.get_elements():
|
||||
return
|
||||
|
||||
if not self.svg.selected:
|
||||
if not self.svg.selection:
|
||||
inkex.errormsg(_("Please select at least one object to be marked as a pattern."))
|
||||
return
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ class Troubleshoot(InkstitchExtension):
|
|||
self.warning_group = warning_group
|
||||
self.type_warning_group = type_warning_group
|
||||
|
||||
def add_descriptions(self, problem_types):
|
||||
def add_descriptions(self, problem_types): # noqa: C901
|
||||
svg = self.document.getroot()
|
||||
|
||||
# We could use svg.viewport_width, but then we would need to do unit conversions,
|
||||
|
@ -174,6 +174,8 @@ class Troubleshoot(InkstitchExtension):
|
|||
text.append([problem.name, "font-weight: bold; fill: %s;" % text_color])
|
||||
text.append([problem.description, "font-size: 3px;"])
|
||||
text.append(["", ""])
|
||||
if problem.steps_to_solve:
|
||||
text.append([_("Possible solutions"), "font-weight: bold; text-decoration: underline; font-size: 4px;"])
|
||||
for step in problem.steps_to_solve:
|
||||
text.append([step, "font-size: 4px;"])
|
||||
text.append(["", ""])
|
||||
|
|
|
@ -87,14 +87,14 @@ class Font(object):
|
|||
|
||||
def _load_metadata(self):
|
||||
try:
|
||||
with open(os.path.join(self.path, "font.json"), encoding="utf-8") as metadata_file:
|
||||
with open(os.path.join(self.path, "font.json"), encoding="utf-8-sig") as metadata_file:
|
||||
self.metadata = json.load(metadata_file)
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
def _load_license(self):
|
||||
try:
|
||||
with open(os.path.join(self.path, "LICENSE"), encoding="utf-8") as license_file:
|
||||
with open(os.path.join(self.path, "LICENSE"), encoding="utf-8-sig") as license_file:
|
||||
self.license = license_file.read()
|
||||
except IOError:
|
||||
pass
|
||||
|
|
|
@ -3,9 +3,14 @@
|
|||
# Copyright (c) 2010 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
from .ties import add_ties
|
||||
from .color_block import ColorBlock
|
||||
from sys import exit
|
||||
|
||||
from inkex import errormsg
|
||||
|
||||
from ..i18n import _
|
||||
from ..svg import PIXELS_PER_MM
|
||||
from .color_block import ColorBlock
|
||||
from .ties import add_ties
|
||||
|
||||
|
||||
def stitch_groups_to_stitch_plan(stitch_groups, collapse_len=None, disable_ties=False): # noqa: C901
|
||||
|
@ -17,6 +22,11 @@ def stitch_groups_to_stitch_plan(stitch_groups, collapse_len=None, disable_ties=
|
|||
* adds jump-stitches between stitch_group if necessary
|
||||
"""
|
||||
|
||||
if not stitch_groups:
|
||||
errormsg(_("There is no selected stitchable element. Please run "
|
||||
"Extensions > Ink/Stitch > Troubleshoot > Troubleshoot objects in case you have expected a stitchout."))
|
||||
exit(1)
|
||||
|
||||
if collapse_len is None:
|
||||
collapse_len = 3.0
|
||||
collapse_len = collapse_len * PIXELS_PER_MM
|
||||
|
|
|
@ -24,7 +24,7 @@ def compose_parent_transforms(node, mat):
|
|||
|
||||
trans = node.get('transform')
|
||||
if trans:
|
||||
mat = inkex.transforms.Transform(trans) * mat
|
||||
mat = inkex.transforms.Transform(trans) @ mat
|
||||
if node.getparent() is not None:
|
||||
if node.getparent().tag in [SVG_GROUP_TAG, SVG_LINK_TAG]:
|
||||
mat = compose_parent_transforms(node.getparent(), mat)
|
||||
|
@ -47,7 +47,7 @@ def get_node_transform(node):
|
|||
|
||||
# add in the transform implied by the viewBox
|
||||
viewbox_transform = get_viewbox_transform(node.getroottree().getroot())
|
||||
transform = viewbox_transform * transform
|
||||
transform = viewbox_transform @ transform
|
||||
|
||||
return transform
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ def get_viewbox_transform(node):
|
|||
sx = sy = max(sx, sy) if 'slice' in aspect_ratio else min(sx, sy)
|
||||
|
||||
scale_transform = inkex.transforms.Transform("scale(%f, %f)" % (sx, sy))
|
||||
transform = transform * scale_transform
|
||||
transform = transform @ scale_transform
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension translationdomain="inkstitch" xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Import Threadlist</name>
|
||||
<id>org.inkstitch.import_threadlist</id>
|
||||
<param name="extension" type="string" gui-hidden="true">import_threadlist</param>
|
||||
<name>Apply Threadlist</name>
|
||||
<id>org.inkstitch.apply_threadlist</id>
|
||||
<param name="extension" type="string" gui-hidden="true">apply_threadlist</param>
|
||||
<param name="filepath" type="path" gui-text="Choose file" mode="file" filetypes="txt"/>
|
||||
<param name="method" type="optiongroup" gui-text="Choose method">
|
||||
<option value="1">Import Ink/Stitch threadlist</option>
|
||||
<option value="2">Import other threadlist*</option>
|
||||
<option value="1">Apply Ink/Stitch threadlist</option>
|
||||
<option value="2">Apply other threadlist*</option>
|
||||
</param>
|
||||
<param name="palette" type="enum" gui-text="*Choose color palette">
|
||||
{%- for item in threadcatalog %}
|
|
@ -8,7 +8,9 @@
|
|||
<object-type>all</object-type>
|
||||
<effects-menu>
|
||||
<submenu name="Ink/Stitch" translatable="no">
|
||||
<submenu name="Commands" />
|
||||
<submenu name="Commands">
|
||||
<submenu name="View" />
|
||||
</submenu>
|
||||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
<object-type>all</object-type>
|
||||
<effects-menu>
|
||||
<submenu name="Ink/Stitch" translatable="no">
|
||||
<submenu name="Commands" />
|
||||
<submenu name="Commands">
|
||||
<submenu name="View" />
|
||||
</submenu>
|
||||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
|
|
Ładowanie…
Reference in New Issue