inkstitch/lib/elements/utils.py

139 wiersze
4.7 KiB
Python
Czysty Zwykły widok Historia

2021-03-12 04:17:19 +00:00
# Authors: see git history
#
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
from typing import List, Optional
from inkex import BaseElement
from lxml.etree import Comment
from ..commands import is_command, layer_commands
from ..debug.utils import safe_get
from ..marker import has_marker
from ..svg.tags import (CONNECTOR_TYPE, EMBROIDERABLE_TAGS, INKSCAPE_GROUPMODE,
NOT_EMBROIDERABLE_TAGS, SVG_CLIPPATH_TAG, SVG_DEFS_TAG,
SVG_GROUP_TAG, SVG_IMAGE_TAG, SVG_MASK_TAG,
SVG_TEXT_TAG)
from ..utils.paths import get_ini
2020-05-16 21:01:00 +00:00
from .clone import Clone, is_clone
from .element import EmbroideryElement
2020-05-27 16:39:04 +00:00
from .empty_d_object import EmptyDObject
from .fill_stitch import FillStitch
2020-05-16 21:01:00 +00:00
from .image import ImageObject
from .marker import MarkerObject
from .satin_column import SatinColumn
from .stroke import Stroke
2020-05-16 21:01:00 +00:00
from .text import TextObject
def node_to_elements(node, clone_to_element=False) -> List[EmbroideryElement]: # noqa: C901
if node.style('display') == 'none':
return []
if is_clone(node) and not clone_to_element:
# clone_to_element: get an actual embroiderable element once a clone has been defined as a clone
2020-05-16 21:01:00 +00:00
return [Clone(node)]
elif node.tag in EMBROIDERABLE_TAGS and not node.get_path():
2020-05-27 16:39:04 +00:00
return [EmptyDObject(node)]
elif has_marker(node):
return [MarkerObject(node)]
elif node.tag in EMBROIDERABLE_TAGS or is_clone(node):
elements = []
Sew Stack first steps (#3133) * handle more recursive cases * scaffolding for stitch layers * scaffolding for SewStack * always use DotDict when parsing json params * add DefaultDotDict + DotDict fixes * first working SewStack (no UI yet) * ignore inkstitch_debug.log and .svg * refactor * early WIP: property grid display temporarily in stitch plan preview * start of sew stack editor extension * add layer properties panel and splitter * spacing and better icon * handle checkbox * add layer action buttons * show selected property help text in an HtmlWindow * rename * rephrase help text for tolerance * refactor into separate file * simplify structure * better property type handling * add randomization button * add random seed re-roll button * simulator preview * update preview in a few more cases * always DotDict * avoid ridiculously slow simulations * preview selected layer or all layers * edit multiple objects and save only modified properties into the SVG * better preview handling * add reverse and jitter * add stitch path jitter * fix types * fix random shuffle button * fixes * fix repeats * type hinting to please pycharm * show layer description * avoid exception in properties with multiple values * fix typing * fix new layer * draw a box around property grid and help box * confirm before closing * rename properties and fix seed * fix close/cancel logic * add buttons to undo changes and reset to default value * set not modified if default is original setting * fix invisible icon * more space for properties * fix random properties * better regulation of simulator rendering speed * Fixed timer being passed a float * fix get_json_param() default handling * fix tests * add checkbox for sew stack only * fix property help * adjustable stitch layer editor help box size, with persistence * repeat exact stitches * "fix" style * adjust for new next_element stuff --------- Co-authored-by: CapellanCitizen <thecapellancitizen@gmail.com>
2025-01-29 17:04:07 +00:00
from ..sew_stack import SewStack
sew_stack = SewStack(node)
if not sew_stack.sew_stack_only:
element = EmbroideryElement(node)
if element.get_style("fill", "black") and not element.get_style('fill-opacity', 1) == "0":
elements.append(FillStitch(node))
if element.get_style("stroke"):
if element.get_boolean_param("satin_column") and len(element.path) > 1:
elements.append(SatinColumn(node))
elif not is_command(element.node):
elements.append(Stroke(node))
if element.get_boolean_param("stroke_first", False):
elements.reverse()
if safe_get(get_ini(), "DEBUG", "sew_stack_enable", default=False):
elements.append(sew_stack)
Sew Stack first steps (#3133) * handle more recursive cases * scaffolding for stitch layers * scaffolding for SewStack * always use DotDict when parsing json params * add DefaultDotDict + DotDict fixes * first working SewStack (no UI yet) * ignore inkstitch_debug.log and .svg * refactor * early WIP: property grid display temporarily in stitch plan preview * start of sew stack editor extension * add layer properties panel and splitter * spacing and better icon * handle checkbox * add layer action buttons * show selected property help text in an HtmlWindow * rename * rephrase help text for tolerance * refactor into separate file * simplify structure * better property type handling * add randomization button * add random seed re-roll button * simulator preview * update preview in a few more cases * always DotDict * avoid ridiculously slow simulations * preview selected layer or all layers * edit multiple objects and save only modified properties into the SVG * better preview handling * add reverse and jitter * add stitch path jitter * fix types * fix random shuffle button * fixes * fix repeats * type hinting to please pycharm * show layer description * avoid exception in properties with multiple values * fix typing * fix new layer * draw a box around property grid and help box * confirm before closing * rename properties and fix seed * fix close/cancel logic * add buttons to undo changes and reset to default value * set not modified if default is original setting * fix invisible icon * more space for properties * fix random properties * better regulation of simulator rendering speed * Fixed timer being passed a float * fix get_json_param() default handling * fix tests * add checkbox for sew stack only * fix property help * adjustable stitch layer editor help box size, with persistence * repeat exact stitches * "fix" style * adjust for new next_element stuff --------- Co-authored-by: CapellanCitizen <thecapellancitizen@gmail.com>
2025-01-29 17:04:07 +00:00
return elements
2020-05-16 21:01:00 +00:00
elif node.tag == SVG_IMAGE_TAG:
return [ImageObject(node)]
elif node.tag == SVG_TEXT_TAG:
return [TextObject(node)]
else:
return []
def nodes_to_elements(nodes):
elements = []
for node in nodes:
elements.extend(node_to_elements(node))
return elements
def iterate_nodes(node: BaseElement, # noqa: C901
selection: Optional[List[BaseElement]] = None,
troubleshoot=False) -> List[BaseElement]:
# Postorder traversal of selected nodes and their descendants.
# Returns all nodes if there is no selection.
def walk(node: BaseElement, selected: bool) -> List[BaseElement]:
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 not selected:
if selection:
if node in selection:
selected = True
else:
# if the user didn't select anything that means we process everything
selected = True
for child in node:
nodes.extend(walk(child, selected))
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
return walk(node, False)