summaryrefslogtreecommitdiff
path: root/lib/extensions
diff options
context:
space:
mode:
authorKaalleen <36401965+kaalleen@users.noreply.github.com>2020-05-16 23:01:00 +0200
committerGitHub <noreply@github.com>2020-05-16 23:01:00 +0200
commita308db7ae152626c84ade069e307864a7e7e6213 (patch)
tree3af8a13562021796743378d16a1e7cc725ac75e4 /lib/extensions
parent4e950332419743dcbaf661fdda1f7c7970241d93 (diff)
support svg objects (#643)
Diffstat (limited to 'lib/extensions')
-rw-r--r--lib/extensions/base.py44
-rw-r--r--lib/extensions/params.py32
-rw-r--r--lib/extensions/remove_embroidery_settings.py20
-rw-r--r--lib/extensions/simulator.py2
-rw-r--r--lib/extensions/troubleshoot.py118
5 files changed, 138 insertions, 78 deletions
diff --git a/lib/extensions/base.py b/lib/extensions/base.py
index 440a5413..310dd873 100644
--- a/lib/extensions/base.py
+++ b/lib/extensions/base.py
@@ -1,18 +1,20 @@
-from collections import MutableMapping
-from copy import deepcopy
import json
import os
import re
+from collections import MutableMapping
+from copy import deepcopy
-import inkex
from stringcase import snakecase
-from ..commands import layer_commands
+import inkex
+
+from ..commands import is_command, layer_commands
from ..elements import EmbroideryElement, nodes_to_elements
+from ..elements.clone import is_clone, is_embroiderable_clone
from ..i18n import _
from ..svg import generate_unique_id
-from ..svg.tags import SVG_GROUP_TAG, INKSCAPE_GROUPMODE, SVG_DEFS_TAG, EMBROIDERABLE_TAGS
-
+from ..svg.tags import (CONNECTOR_TYPE, EMBROIDERABLE_TAGS, INKSCAPE_GROUPMODE,
+ NOT_EMBROIDERABLE_TAGS, SVG_DEFS_TAG, SVG_GROUP_TAG)
SVG_METADATA_TAG = inkex.addNS("metadata", "svg")
@@ -128,10 +130,9 @@ class InkstitchExtension(inkex.Effect):
else:
inkex.errormsg(_("There are no objects in the entire document that Ink/Stitch knows how to work with.") + "\n")
- inkex.errormsg(_("Ink/Stitch only knows how to work with paths. It can't work with objects like text, rectangles, or circles.") + "\n")
- inkex.errormsg(_("Tip: select some objects and use Path -> Object to Path to convert them to paths.") + "\n")
+ inkex.errormsg(_("Tip: Select some objects and use Path -> Object to Path to convert them to paths.") + "\n")
- def descendants(self, node, selected=False):
+ def descendants(self, node, selected=False, troubleshoot=False): # noqa: C901
nodes = []
element = EmbroideryElement(node)
@@ -148,6 +149,10 @@ class InkstitchExtension(inkex.Effect):
if node.tag == SVG_DEFS_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.selected:
if node.get("id") in self.selected:
selected = True
@@ -156,23 +161,26 @@ class InkstitchExtension(inkex.Effect):
selected = True
for child in node:
- nodes.extend(self.descendants(child, selected))
+ nodes.extend(self.descendants(child, selected, troubleshoot))
- if selected and node.tag in EMBROIDERABLE_TAGS:
- nodes.append(node)
+ if selected:
+ if node.tag in EMBROIDERABLE_TAGS or is_embroiderable_clone(node):
+ nodes.append(node)
+ elif troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or is_clone(node)):
+ nodes.append(node)
return nodes
- def get_nodes(self):
- return self.descendants(self.document.getroot())
+ def get_nodes(self, troubleshoot=False):
+ return self.descendants(self.document.getroot(), troubleshoot=troubleshoot)
- def get_elements(self):
- self.elements = nodes_to_elements(self.get_nodes())
+ def get_elements(self, troubleshoot=False):
+ self.elements = nodes_to_elements(self.get_nodes(troubleshoot))
if self.elements:
return True
- else:
+ if not troubleshoot:
self.no_elements_error()
- return False
+ return False
def elements_to_patches(self, elements):
patches = []
diff --git a/lib/extensions/params.py b/lib/extensions/params.py
index a3ba7784..600a4669 100644
--- a/lib/extensions/params.py
+++ b/lib/extensions/params.py
@@ -1,19 +1,21 @@
# -*- coding: UTF-8 -*-
+import os
+import sys
from collections import defaultdict
from copy import copy
from itertools import groupby
-import os
-import sys
-
import wx
from wx.lib.scrolledpanel import ScrolledPanel
from ..commands import is_command
-from ..elements import EmbroideryElement, Fill, AutoFill, Stroke, SatinColumn
+from ..elements import (AutoFill, Clone, EmbroideryElement, Fill, Polyline,
+ SatinColumn, Stroke)
+from ..elements.clone import is_clone
from ..gui import PresetsPanel, SimulatorPreview
from ..i18n import _
+from ..svg.tags import SVG_POLYLINE_TAG
from ..utils import get_resource_dir
from .base import InkstitchExtension
@@ -465,16 +467,18 @@ class Params(InkstitchExtension):
classes = []
if not is_command(node):
- if element.get_style("fill", "black") is not None:
- classes.append(AutoFill)
- classes.append(Fill)
-
- if element.get_style("stroke") is not None:
- classes.append(Stroke)
-
- if element.get_style("stroke-dasharray") is None:
- classes.append(SatinColumn)
-
+ if node.tag == SVG_POLYLINE_TAG:
+ classes.append(Polyline)
+ elif is_clone(node):
+ classes.append(Clone)
+ else:
+ if element.get_style("fill", 'black') and not element.get_style("fill-opacity", 1) == "0":
+ classes.append(AutoFill)
+ classes.append(Fill)
+ if element.get_style("stroke") is not None:
+ classes.append(Stroke)
+ if element.get_style("stroke-dasharray") is None:
+ classes.append(SatinColumn)
return classes
def get_nodes_by_class(self):
diff --git a/lib/extensions/remove_embroidery_settings.py b/lib/extensions/remove_embroidery_settings.py
index d39c7e94..2a4d06dd 100644
--- a/lib/extensions/remove_embroidery_settings.py
+++ b/lib/extensions/remove_embroidery_settings.py
@@ -1,6 +1,7 @@
import inkex
from ..commands import find_commands
+from ..svg.svg import find_elements
from .base import InkstitchExtension
@@ -12,6 +13,8 @@ class RemoveEmbroiderySettings(InkstitchExtension):
self.OptionParser.add_option("-d", "--del_print", dest="del_print", type="inkbool", default=False)
def effect(self):
+ self.svg = self.document.getroot()
+
if self.options.del_params:
self.remove_params()
if self.options.del_commands:
@@ -21,7 +24,7 @@ class RemoveEmbroiderySettings(InkstitchExtension):
def remove_print_settings(self):
print_settings = "svg:metadata//*"
- print_settings = self.find_elements(print_settings)
+ print_settings = find_elements(self.svg, print_settings)
for print_setting in print_settings:
if print_setting.prefix == "inkstitch":
self.remove_element(print_setting)
@@ -29,7 +32,7 @@ class RemoveEmbroiderySettings(InkstitchExtension):
def remove_params(self):
if not self.selected:
xpath = ".//svg:path"
- elements = self.find_elements(xpath)
+ elements = find_elements(self.svg, xpath)
self.remove_inkstitch_attributes(elements)
else:
for node in self.selected:
@@ -41,7 +44,7 @@ class RemoveEmbroiderySettings(InkstitchExtension):
# we are not able to grab commands by a specific id
# so let's move through every object instead and see if it has a command
xpath = ".//svg:path|.//svg:circle|.//svg:rect|.//svg:ellipse"
- elements = self.find_elements(xpath)
+ elements = find_elements(self.svg, xpath)
else:
elements = []
for node in self.selected:
@@ -64,19 +67,14 @@ class RemoveEmbroiderySettings(InkstitchExtension):
def get_selected_elements(self, element_id):
xpath = ".//svg:g[@id='%(id)s']//svg:path|.//svg:g[@id='%(id)s']//svg:use" % dict(id=element_id)
- elements = self.find_elements(xpath)
+ elements = find_elements(self.svg, xpath)
if not elements:
xpath = ".//*[@id='%s']" % element_id
- elements = self.find_elements(xpath)
- return elements
-
- def find_elements(self, xpath):
- svg = self.document.getroot()
- elements = svg.xpath(xpath, namespaces=inkex.NSS)
+ elements = find_elements(self.svg, xpath)
return elements
def remove_elements(self, xpath):
- elements = self.find_elements(xpath)
+ elements = find_elements(self.svg, xpath)
for element in elements:
self.remove_element(element)
diff --git a/lib/extensions/simulator.py b/lib/extensions/simulator.py
index 1c0627ba..66be752b 100644
--- a/lib/extensions/simulator.py
+++ b/lib/extensions/simulator.py
@@ -9,6 +9,8 @@ class Simulator(InkstitchExtension):
InkstitchExtension.__init__(self)
def effect(self):
+ if not self.get_elements():
+ return
api_server = APIServer(self)
port = api_server.start_server()
electron = open_url("/simulator?port=%d" % port)
diff --git a/lib/extensions/troubleshoot.py b/lib/extensions/troubleshoot.py
index b67a5dc1..6b63390a 100644
--- a/lib/extensions/troubleshoot.py
+++ b/lib/extensions/troubleshoot.py
@@ -1,43 +1,48 @@
-from itertools import chain
import textwrap
import inkex
from ..commands import add_layer_commands
-from ..elements.validation import ValidationWarning, ValidationError
+from ..elements.validation import (ObjectTypeWarning, ValidationError,
+ ValidationWarning)
from ..i18n import _
from ..svg import get_correction_transform
-from ..svg.tags import (INKSCAPE_GROUPMODE, INKSCAPE_LABEL,
- SODIPODI_ROLE, SVG_GROUP_TAG, SVG_PATH_TAG,
- SVG_TEXT_TAG, SVG_TSPAN_TAG)
+from ..svg.tags import (INKSCAPE_GROUPMODE, INKSCAPE_LABEL, SODIPODI_ROLE,
+ SVG_GROUP_TAG, SVG_PATH_TAG, SVG_TEXT_TAG,
+ SVG_TSPAN_TAG)
from .base import InkstitchExtension
class Troubleshoot(InkstitchExtension):
def effect(self):
- if not self.get_elements():
- return
self.create_troubleshoot_layer()
- problem_types = set()
- for element in self.elements:
- for problem in chain(element.validation_errors(), element.validation_warnings()):
- problem_types.add(type(problem))
- self.insert_pointer(problem)
-
- if problem_types:
+ problem_types = {'error': set(), 'warning': set(), 'type_warning': set()}
+
+ if self.get_elements(True):
+ for element in self.elements:
+ for problem in element.validation_errors():
+ problem_types['error'].add(type(problem))
+ self.insert_pointer(problem)
+ for problem in element.validation_warnings():
+ if isinstance(problem, ObjectTypeWarning):
+ problem_types['type_warning'].add(type(problem))
+ else:
+ problem_types['warning'].add(type(problem))
+ self.insert_pointer(problem)
+
+ if any(problem_types.values()):
self.add_descriptions(problem_types)
else:
svg = self.document.getroot()
svg.remove(self.troubleshoot_layer)
- message = _("All selected shapes are valid!")
+ message = _("All selected shapes are valid! ")
message += "\n\n"
- message += _("Tip: If you are still having an issue with an object not being rendered, "
- "you might need to convert it it to a path (Path -> Object to Path) or check if it is possibly in an ignored layer.")
-
+ message += _("If you are still having trouble with a shape not being embroidered, "
+ "check if it is in a layer with an ignore command.")
inkex.errormsg(message)
def insert_pointer(self, problem):
@@ -49,9 +54,12 @@ class Troubleshoot(InkstitchExtension):
elif isinstance(problem, ValidationError):
fill_color = "#ff0000"
layer = self.error_group
+ elif isinstance(problem, ObjectTypeWarning):
+ fill_color = "#ff9900"
+ layer = self.type_warning_group
- pointer_style = "stroke:#ffffff;stroke-width:0.2;fill:%s;" % (fill_color)
- text_style = "fill:%s;stroke:#ffffff;stroke-width:0.2;font-size:8px;text-align:center;text-anchor:middle" % (fill_color)
+ pointer_style = "stroke:#000000;stroke-width:0.2;fill:%s;" % (fill_color)
+ text_style = "fill:%s;stroke:#000000;stroke-width:0.2;font-size:8px;text-align:center;text-anchor:middle" % (fill_color)
path = inkex.etree.Element(
SVG_PATH_TAG,
@@ -119,13 +127,23 @@ class Troubleshoot(InkstitchExtension):
})
layer.append(warning_group)
+ type_warning_group = inkex.etree.SubElement(
+ layer,
+ SVG_GROUP_TAG,
+ {
+ "id": '__validation_ignored__',
+ INKSCAPE_LABEL: _("Type Warnings"),
+ })
+ layer.append(type_warning_group)
+
self.troubleshoot_layer = layer
self.error_group = error_group
self.warning_group = warning_group
+ self.type_warning_group = type_warning_group
def add_descriptions(self, problem_types):
svg = self.document.getroot()
- text_x = str(self.unittouu(svg.get('width')) + 5)
+ text_x = str(float(svg.get('viewBox', '0 0 800 0').split(' ')[2]) + 5.0)
text_container = inkex.etree.Element(
SVG_TEXT_TAG,
@@ -138,23 +156,40 @@ class Troubleshoot(InkstitchExtension):
self.troubleshoot_layer.append(text_container)
text = [
- [_("Troubleshoot"), "font-weight: bold; font-size: 6px;"],
+ [_("Troubleshoot"), "font-weight: bold; font-size: 8px;"],
["", ""]
]
- for problem in problem_types:
- text_color = "#ff0000"
- if issubclass(problem, ValidationWarning):
+ for problem_type, problems in problem_types.items():
+ if problem_type == "error":
+ text_color = "#ff0000"
+ problem_type_header = _("Errors")
+ problem_type_description = _("Problems that will prevent the shape from being embroidered.")
+ elif problem_type == "warning":
text_color = "#ffdd00"
-
- text.append([problem.name, "font-weight: bold; fill:%s;" % text_color])
- description_parts = textwrap.wrap(problem.description, 60)
- for description in description_parts:
- text.append([description, "font-size: 3px;"])
- text.append(["", ""])
- for step in problem.steps_to_solve:
- text.append([step, "font-size: 4px;"])
- text.append(["", ""])
+ problem_type_header = _("Warnings")
+ problem_type_description = _("These are problems that won't prevent the shape from being embroidered. "
+ "You should consider to fix the warning, but if you don't, "
+ "Ink/Stitch will do its best to process the object.")
+ elif problem_type == "type_warning":
+ text_color = "#ff9900"
+ problem_type_header = _("Object Type Warnings")
+ problem_type_description = _("Ink/Stitch only knows how to works with paths and ignores everything else. "
+ "You might want these shapes to be ignored, but if you don't, "
+ "follow the instructions to change this behaviour.")
+ if problems:
+ text.append([problem_type_header, "font-weight: bold; fill: %s; text-decoration: underline; font-size: 7px;" % text_color])
+ text.append(["", ""])
+ text.append([problem_type_description, "fill:%s;" % text_color])
+ text.append(["", ""])
+
+ for problem in problems:
+ text.append([problem.name, "font-weight: bold; fill: %s;" % text_color])
+ text.append([problem.description, "font-size: 3px;"])
+ text.append(["", ""])
+ for step in problem.steps_to_solve:
+ text.append([step, "font-size: 4px;"])
+ text.append(["", ""])
explain_layer = _('It is possible, that one object contains more than one error, ' +
'yet there will be only one pointer per object. Run this function again, ' +
@@ -162,7 +197,9 @@ class Troubleshoot(InkstitchExtension):
'"Troubleshoot" through the objects panel (Object -> Objects...).')
explain_layer_parts = textwrap.wrap(explain_layer, 60)
for description in explain_layer_parts:
- text.append([description, "font-style: italic; font-size: 3px;"])
+ text.append([description, "font-style: italic; font-size: 4px;"])
+
+ text = self.split_text(text)
for text_line in text:
tspan = inkex.etree.Element(
@@ -174,3 +211,14 @@ class Troubleshoot(InkstitchExtension):
)
tspan.text = text_line[0]
text_container.append(tspan)
+
+ def split_text(self, text):
+ splitted_text = []
+ for text_part, style in text:
+ if text_part:
+ description_parts = textwrap.wrap(text_part, 60)
+ for description in description_parts:
+ splitted_text.append([description, style])
+ else:
+ splitted_text.append(["", ""])
+ return splitted_text