kopia lustrzana https://github.com/inkstitch/inkstitch
Merge pull request #2284 from inkstitch/kaalleen/various-fixes
commit
1193b4f206
|
@ -352,14 +352,14 @@ class FillStitch(EmbroideryElement):
|
|||
'Also used for meander and circular fill.'),
|
||||
unit='mm',
|
||||
type='float',
|
||||
default=1.5,
|
||||
default=2.5,
|
||||
select_items=[('fill_method', 'auto_fill'),
|
||||
('fill_method', 'guided_fill'),
|
||||
('fill_method', 'meander_fill'),
|
||||
('fill_method', 'circular_fill')],
|
||||
sort_index=31)
|
||||
def running_stitch_length(self):
|
||||
return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01)
|
||||
return max(self.get_float_param("running_stitch_length_mm", 2.5), 0.01)
|
||||
|
||||
@property
|
||||
@param('running_stitch_tolerance_mm',
|
||||
|
@ -607,13 +607,13 @@ class FillStitch(EmbroideryElement):
|
|||
def validation_errors(self):
|
||||
if not self.shape_is_valid(self.shape):
|
||||
why = explain_validity(self.shape)
|
||||
message, x, y = re.findall(r".+?(?=\[)|-?\d+(?:\.\d+)?", why)
|
||||
message, x, y = re.match(r"(?P<message>.+)\[(?P<x>.+)\s(?P<y>.+)\]", why).groups()
|
||||
yield InvalidShapeError((x, y))
|
||||
|
||||
def validation_warnings(self): # noqa: C901
|
||||
if not self.shape_is_valid(self.original_shape):
|
||||
why = explain_validity(self.original_shape)
|
||||
message, x, y = re.findall(r".+?(?=\[)|-?\d+(?:\.\d+)?", why)
|
||||
message, x, y = re.match(r"(?P<message>.+)\[(?P<x>.+)\s(?P<y>.+)\]", why).groups()
|
||||
if "Hole lies outside shell" in message:
|
||||
yield UnconnectedWarning((x, y))
|
||||
else:
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
from math import pi
|
||||
|
||||
from inkex import DirectedLineSegment, Transform
|
||||
from shapely import geometry as shgeo
|
||||
from shapely.affinity import affine_transform, rotate
|
||||
from shapely.ops import split
|
||||
|
||||
from ..svg import PIXELS_PER_MM, get_correction_transform
|
||||
|
||||
|
||||
def gradient_shapes_and_attributes(element, shape):
|
||||
# e.g. url(#linearGradient872) -> linearGradient872
|
||||
color = element.color[5:-1]
|
||||
xpath = f'.//svg:defs/svg:linearGradient[@id="{color}"]'
|
||||
gradient = element.node.getroottree().getroot().findone(xpath)
|
||||
gradient.apply_transform()
|
||||
point1 = (float(gradient.get('x1')), float(gradient.get('y1')))
|
||||
point2 = (float(gradient.get('x2')), float(gradient.get('y2')))
|
||||
# get 90° angle to calculate the splitting angle
|
||||
line = DirectedLineSegment(point1, point2)
|
||||
angle = line.angle - (pi / 2)
|
||||
# Ink/Stitch somehow turns the stitch angle
|
||||
stitch_angle = angle * -1
|
||||
# create bbox polygon to calculate the length necessary to make sure that
|
||||
# the gradient splitter lines will cut the entire design
|
||||
bbox = element.node.bounding_box()
|
||||
bbox_polygon = shgeo.Polygon([(bbox.left, bbox.top), (bbox.right, bbox.top),
|
||||
(bbox.right, bbox.bottom), (bbox.left, bbox.bottom)])
|
||||
# gradient stops
|
||||
offsets = gradient.stop_offsets
|
||||
stop_styles = gradient.stop_styles
|
||||
# now split the shape according to the gradient stops
|
||||
polygons = []
|
||||
colors = []
|
||||
attributes = []
|
||||
previous_color = None
|
||||
end_row_spacing = None
|
||||
for i, offset in enumerate(offsets):
|
||||
shape_rest = []
|
||||
split_point = shgeo.Point(line.point_at_ratio(float(offset)))
|
||||
length = split_point.hausdorff_distance(bbox_polygon)
|
||||
split_line = shgeo.LineString([(split_point.x - length - 2, split_point.y),
|
||||
(split_point.x + length + 2, split_point.y)])
|
||||
split_line = rotate(split_line, angle, origin=split_point, use_radians=True)
|
||||
transform = -Transform(get_correction_transform(element.node))
|
||||
transform = list(transform.to_hexad())
|
||||
split_line = affine_transform(split_line, transform)
|
||||
offset_line = split_line.parallel_offset(1, 'right')
|
||||
polygon = split(shape, split_line)
|
||||
color = stop_styles[i]['stop-color']
|
||||
# does this gradient line split the shape
|
||||
offset_outside_shape = len(polygon.geoms) == 1
|
||||
for poly in polygon.geoms:
|
||||
if isinstance(poly, shgeo.Polygon) and element.shape_is_valid(poly):
|
||||
if poly.intersects(offset_line):
|
||||
if previous_color:
|
||||
polygons.append(poly)
|
||||
colors.append(previous_color)
|
||||
attributes.append({'angle': stitch_angle, 'end_row_spacing': end_row_spacing, 'color': previous_color})
|
||||
polygons.append(poly)
|
||||
attributes.append({'angle': stitch_angle + pi, 'end_row_spacing': end_row_spacing, 'color': color})
|
||||
else:
|
||||
shape_rest.append(poly)
|
||||
shape = shgeo.MultiPolygon(shape_rest)
|
||||
previous_color = color
|
||||
end_row_spacing = element.row_spacing / PIXELS_PER_MM * 2
|
||||
# add left over shape(s)
|
||||
if shape:
|
||||
if offset_outside_shape:
|
||||
for s in shape.geoms:
|
||||
polygons.append(s)
|
||||
attributes.append({'color': stop_styles[-2]['stop-color'], 'angle': stitch_angle, 'end_row_spacing': end_row_spacing})
|
||||
stitch_angle += pi
|
||||
else:
|
||||
end_row_spacing = None
|
||||
for s in shape.geoms:
|
||||
polygons.append(s)
|
||||
attributes.append({'color': stop_styles[-1]['stop-color'], 'angle': stitch_angle, 'end_row_spacing': end_row_spacing})
|
||||
return polygons, attributes
|
|
@ -101,10 +101,10 @@ class Stroke(EmbroideryElement):
|
|||
unit='mm',
|
||||
type='float',
|
||||
select_items=[('stroke_method', 'running_stitch'), ('stroke_method', 'ripple_stitch')],
|
||||
default=1.5,
|
||||
default=2.5,
|
||||
sort_index=4)
|
||||
def running_stitch_length(self):
|
||||
return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01)
|
||||
return max(self.get_float_param("running_stitch_length_mm", 2.5), 0.01)
|
||||
|
||||
@property
|
||||
@param('running_stitch_tolerance_mm',
|
||||
|
@ -261,6 +261,27 @@ class Stroke(EmbroideryElement):
|
|||
def reverse(self):
|
||||
return self.get_boolean_param("reverse", False)
|
||||
|
||||
_reverse_rails_options = [ParamOption('automatic', _('Automatic')),
|
||||
ParamOption('none', _("Don't reverse")),
|
||||
ParamOption('first', _('Reverse first rail')),
|
||||
ParamOption('second', _('Reverse second rail')),
|
||||
ParamOption('both', _('Reverse both rails'))
|
||||
]
|
||||
|
||||
@property
|
||||
@param(
|
||||
'reverse_rails',
|
||||
_('Reverse rails'),
|
||||
tooltip=_('Reverse satin ripple rails. ' +
|
||||
'Default: automatically detect and fix a reversed rail.'),
|
||||
type='combo',
|
||||
options=_reverse_rails_options,
|
||||
default='automatic',
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=15)
|
||||
def reverse_rails(self):
|
||||
return self.get_param('reverse_rails', 'automatic')
|
||||
|
||||
@property
|
||||
@param('grid_size_mm',
|
||||
_('Grid size'),
|
||||
|
@ -269,7 +290,7 @@ class Stroke(EmbroideryElement):
|
|||
default=0,
|
||||
unit='mm',
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=15)
|
||||
sort_index=16)
|
||||
@cache
|
||||
def grid_size(self):
|
||||
return abs(self.get_float_param("grid_size_mm", 0))
|
||||
|
@ -283,7 +304,7 @@ class Stroke(EmbroideryElement):
|
|||
# 0: xy, 1: x, 2: y, 3: none
|
||||
options=["X Y", "X", "Y", _("None")],
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=16)
|
||||
sort_index=17)
|
||||
def scale_axis(self):
|
||||
return self.get_int_param('scale_axis', 0)
|
||||
|
||||
|
@ -295,7 +316,7 @@ class Stroke(EmbroideryElement):
|
|||
unit='%',
|
||||
default=100,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=17)
|
||||
sort_index=18)
|
||||
def scale_start(self):
|
||||
return self.get_float_param('scale_start', 100.0)
|
||||
|
||||
|
@ -307,7 +328,7 @@ class Stroke(EmbroideryElement):
|
|||
unit='%',
|
||||
default=0.0,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=18)
|
||||
sort_index=19)
|
||||
def scale_end(self):
|
||||
return self.get_float_param('scale_end', 0.0)
|
||||
|
||||
|
@ -318,7 +339,7 @@ class Stroke(EmbroideryElement):
|
|||
type='boolean',
|
||||
default=True,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=19)
|
||||
sort_index=20)
|
||||
@cache
|
||||
def rotate_ripples(self):
|
||||
return self.get_boolean_param("rotate_ripples", True)
|
||||
|
@ -331,7 +352,7 @@ class Stroke(EmbroideryElement):
|
|||
default=0,
|
||||
options=(_("flat"), _("point")),
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=20)
|
||||
sort_index=21)
|
||||
@cache
|
||||
def join_style(self):
|
||||
return self.get_int_param('join_style', 0)
|
||||
|
|
|
@ -99,6 +99,7 @@ class ConvertToSatin(InkstitchExtension):
|
|||
path[0] = start.as_tuple()
|
||||
|
||||
def remove_duplicate_points(self, path):
|
||||
path = [[round(coord, 4) for coord in point] for point in path]
|
||||
return [point for point, repeats in groupby(path)]
|
||||
|
||||
def join_style_args(self, element):
|
||||
|
|
|
@ -3,17 +3,18 @@
|
|||
# Copyright (c) 2010 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
from math import degrees
|
||||
from math import degrees, pi
|
||||
|
||||
from inkex import DirectedLineSegment, PathElement, errormsg
|
||||
from inkex import DirectedLineSegment, PathElement, Transform, errormsg
|
||||
from shapely import geometry as shgeo
|
||||
from shapely.affinity import affine_transform, rotate
|
||||
from shapely.geometry import Point
|
||||
from shapely.ops import nearest_points
|
||||
from shapely.ops import nearest_points, split
|
||||
|
||||
from ..commands import add_commands
|
||||
from ..elements import FillStitch
|
||||
from ..elements.gradient_fill import gradient_shapes_and_attributes
|
||||
from ..i18n import _
|
||||
from ..svg import get_correction_transform
|
||||
from ..svg import PIXELS_PER_MM, get_correction_transform
|
||||
from ..svg.tags import INKSTITCH_ATTRIBS
|
||||
from .commands import CommandsExtension
|
||||
from .duplicate_params import get_inkstitch_attributes
|
||||
|
@ -28,6 +29,9 @@ class GradientBlocks(CommandsExtension):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
CommandsExtension.__init__(self, *args, **kwargs)
|
||||
self.arg_parser.add_argument("--notebook", type=str, default=0.0)
|
||||
self.arg_parser.add_argument("--options", type=str, default=0.0)
|
||||
self.arg_parser.add_argument("--info", type=str, default=0.0)
|
||||
self.arg_parser.add_argument("-e", "--end-row-spacing", type=float, default=0.0, dest="end_row_spacing")
|
||||
|
||||
def effect(self):
|
||||
|
@ -53,35 +57,45 @@ class GradientBlocks(CommandsExtension):
|
|||
fill_shapes.reverse()
|
||||
attributes.reverse()
|
||||
|
||||
if self.options.end_row_spacing != 0:
|
||||
end_row_spacing = self.options.end_row_spacing
|
||||
else:
|
||||
end_row_spacing = element.row_spacing / PIXELS_PER_MM * 2
|
||||
end_row_spacing = f'{end_row_spacing: .2f}'
|
||||
|
||||
previous_color = None
|
||||
previous_element = None
|
||||
for i, shape in enumerate(fill_shapes):
|
||||
color = attributes[i]['color']
|
||||
style['fill'] = color
|
||||
end_row_spacing = attributes[i]['end_row_spacing'] or None
|
||||
is_gradient = attributes[i]['is_gradient']
|
||||
angle = degrees(attributes[i]['angle'])
|
||||
angle = f'{angle: .2f}'
|
||||
d = "M " + " ".join([f'{x}, {y}' for x, y in list(shape.exterior.coords)]) + " Z"
|
||||
block = PathElement(attrib={
|
||||
"id": self.uniqueId("path"),
|
||||
"style": str(style),
|
||||
"transform": correction_transform,
|
||||
"d": d,
|
||||
INKSTITCH_ATTRIBS['angle']: f'{angle: .2f}'
|
||||
INKSTITCH_ATTRIBS['angle']: angle
|
||||
})
|
||||
# apply parameters from original element
|
||||
params = get_inkstitch_attributes(element.node)
|
||||
for attrib in params:
|
||||
block.attrib[attrib] = str(element.node.attrib[attrib])
|
||||
# set end_row_spacing
|
||||
if end_row_spacing:
|
||||
if self.options.end_row_spacing != 0:
|
||||
end_row_spacing = self.options.end_row_spacing
|
||||
block.set('inkstitch:end_row_spacing_mm', f'{end_row_spacing: .2f}')
|
||||
else:
|
||||
block.pop('inkstitch:end_row_spacing_mm')
|
||||
# disable underlay and underpath
|
||||
block.set('inkstitch:fill_underlay', False)
|
||||
block.set('inkstitch:underpath', False)
|
||||
# set end_row_spacing
|
||||
if is_gradient:
|
||||
block.set('inkstitch:end_row_spacing_mm', end_row_spacing)
|
||||
else:
|
||||
block.pop('inkstitch:end_row_spacing_mm')
|
||||
# use underlay to compensate for higher density in the gradient parts
|
||||
block.set('inkstitch:fill_underlay', True)
|
||||
block.set('inkstitch:fill_underlay_angle', angle)
|
||||
block.set('inkstitch:fill_underlay_row_spacing_mm', end_row_spacing)
|
||||
|
||||
parent.insert(index, block)
|
||||
|
||||
if previous_color == color:
|
||||
|
@ -106,6 +120,77 @@ class GradientBlocks(CommandsExtension):
|
|||
return Point(pos)
|
||||
|
||||
|
||||
def gradient_shapes_and_attributes(element, shape):
|
||||
# e.g. url(#linearGradient872) -> linearGradient872
|
||||
color = element.color[5:-1]
|
||||
xpath = f'.//svg:defs/svg:linearGradient[@id="{color}"]'
|
||||
gradient = element.node.getroottree().getroot().findone(xpath)
|
||||
gradient.apply_transform()
|
||||
point1 = (float(gradient.get('x1')), float(gradient.get('y1')))
|
||||
point2 = (float(gradient.get('x2')), float(gradient.get('y2')))
|
||||
# get 90° angle to calculate the splitting angle
|
||||
line = DirectedLineSegment(point1, point2)
|
||||
angle = line.angle - (pi / 2)
|
||||
# Ink/Stitch somehow turns the stitch angle
|
||||
stitch_angle = angle * -1
|
||||
# create bbox polygon to calculate the length necessary to make sure that
|
||||
# the gradient splitter lines will cut the entire design
|
||||
bbox = element.node.bounding_box()
|
||||
bbox_polygon = shgeo.Polygon([(bbox.left, bbox.top), (bbox.right, bbox.top),
|
||||
(bbox.right, bbox.bottom), (bbox.left, bbox.bottom)])
|
||||
# gradient stops
|
||||
offsets = gradient.stop_offsets
|
||||
stop_styles = gradient.stop_styles
|
||||
# now split the shape according to the gradient stops
|
||||
polygons = []
|
||||
colors = []
|
||||
attributes = []
|
||||
previous_color = None
|
||||
is_gradient = False
|
||||
for i, offset in enumerate(offsets):
|
||||
shape_rest = []
|
||||
split_point = shgeo.Point(line.point_at_ratio(float(offset)))
|
||||
length = split_point.hausdorff_distance(bbox_polygon)
|
||||
split_line = shgeo.LineString([(split_point.x - length - 2, split_point.y),
|
||||
(split_point.x + length + 2, split_point.y)])
|
||||
split_line = rotate(split_line, angle, origin=split_point, use_radians=True)
|
||||
transform = -Transform(get_correction_transform(element.node))
|
||||
transform = list(transform.to_hexad())
|
||||
split_line = affine_transform(split_line, transform)
|
||||
offset_line = split_line.parallel_offset(1, 'right')
|
||||
polygon = split(shape, split_line)
|
||||
color = stop_styles[i]['stop-color']
|
||||
# does this gradient line split the shape
|
||||
offset_outside_shape = len(polygon.geoms) == 1
|
||||
for poly in polygon.geoms:
|
||||
if isinstance(poly, shgeo.Polygon) and element.shape_is_valid(poly):
|
||||
if poly.intersects(offset_line):
|
||||
if previous_color:
|
||||
polygons.append(poly)
|
||||
colors.append(previous_color)
|
||||
attributes.append({'color': previous_color, 'angle': stitch_angle, 'is_gradient': is_gradient})
|
||||
polygons.append(poly)
|
||||
attributes.append({'color': color, 'angle': stitch_angle + pi, 'is_gradient': is_gradient})
|
||||
else:
|
||||
shape_rest.append(poly)
|
||||
shape = shgeo.MultiPolygon(shape_rest)
|
||||
previous_color = color
|
||||
is_gradient = True
|
||||
# add left over shape(s)
|
||||
if shape:
|
||||
if offset_outside_shape:
|
||||
for s in shape.geoms:
|
||||
polygons.append(s)
|
||||
attributes.append({'color': stop_styles[-2]['stop-color'], 'angle': stitch_angle, 'is_gradient': is_gradient})
|
||||
stitch_angle += pi
|
||||
else:
|
||||
is_gradient = False
|
||||
for s in shape.geoms:
|
||||
polygons.append(s)
|
||||
attributes.append({'color': stop_styles[-1]['stop-color'], 'angle': stitch_angle, 'is_gradient': is_gradient})
|
||||
return polygons, attributes
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
e = GradientBlocks()
|
||||
e.effect()
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import inkex
|
||||
|
||||
from ..elements import SatinColumn, Stroke
|
||||
from ..elements import EmptyDObject, SatinColumn, Stroke
|
||||
from ..i18n import _
|
||||
from ..svg.tags import ORIGINAL_D, PATH_EFFECT, SODIPODI_NODETYPES
|
||||
from .base import InkstitchExtension
|
||||
|
@ -35,7 +35,10 @@ class StrokeToLpeSatin(InkstitchExtension):
|
|||
|
||||
if not any((isinstance(item, Stroke) or isinstance(item, SatinColumn)) for item in self.elements):
|
||||
# L10N: Convert To Satin extension, user selected one or more objects that were not lines.
|
||||
inkex.errormsg(_("Please select at least one stroke to convert to a satin column."))
|
||||
if any(isinstance(item, EmptyDObject) for item in self.elements):
|
||||
inkex.errormsg(_("This element has lost its path information. Please move the element slightly back and forth before you try again."))
|
||||
else:
|
||||
inkex.errormsg(_("Please select at least one stroke to convert to a satin column."))
|
||||
return
|
||||
|
||||
pattern = self.options.pattern
|
||||
|
|
|
@ -14,8 +14,8 @@ class UpdateSvg(InkstitchExtension):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
InkstitchExtension.__init__(self, *args, **kwargs)
|
||||
# TODO: When there are more legacy versions than only one, this can be transformed in a user input
|
||||
# inkstitch_svg_version history: 1 -> v2.3.0
|
||||
# TODO: When there are more legacy versions than only one, this can be transformed into a user input
|
||||
# inkstitch_svg_version history: 1 -> v3.0.0, May 2023
|
||||
self.update_from = 0
|
||||
|
||||
def effect(self):
|
||||
|
|
|
@ -182,7 +182,10 @@ class Font(object):
|
|||
return self.name + '*'
|
||||
|
||||
def is_custom_font(self):
|
||||
return get_custom_font_dir() in self.path
|
||||
custom_dir = get_custom_font_dir()
|
||||
if not custom_dir:
|
||||
return False
|
||||
return custom_dir in self.path
|
||||
|
||||
def render_text(self, text, destination_group, variant=None, back_and_forth=True, trim_option=0, use_trim_symbols=False):
|
||||
|
||||
|
|
|
@ -103,9 +103,7 @@ def _get_satin_line_count(stroke, pairs):
|
|||
if shortest_line_len == 0 or length < shortest_line_len:
|
||||
shortest_line_len = length
|
||||
num_lines = ceil(shortest_line_len / stroke.min_line_dist)
|
||||
if stroke.join_style == 1:
|
||||
num_lines += 1
|
||||
return num_lines
|
||||
return _line_count_adjust(stroke, num_lines)
|
||||
|
||||
|
||||
def _get_target_line_count(stroke, target, outline):
|
||||
|
@ -117,7 +115,19 @@ def _get_guided_line_count(stroke, guide_line):
|
|||
num_lines = stroke.line_count
|
||||
else:
|
||||
num_lines = ceil(guide_line.length / stroke.min_line_dist)
|
||||
return _line_count_adjust(stroke, num_lines)
|
||||
|
||||
|
||||
def _line_count_adjust(stroke, num_lines):
|
||||
if stroke.min_line_dist and stroke.line_count % 2 != num_lines % 2:
|
||||
# We want the line count always to be either even or odd - depending on the line count value.
|
||||
# So that the end point stays the same even if the design is resized. This is necessary to enable
|
||||
# the user to carefully plan the output and and connect the end point to the following object
|
||||
num_lines -= 1
|
||||
# ensure minimum line count
|
||||
num_lines = max(1, num_lines)
|
||||
if stroke.is_closed or stroke.join_style == 1:
|
||||
# for flat join styles we need to add an other line
|
||||
num_lines += 1
|
||||
return num_lines
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ def _update_to_one(element): # noqa: C901
|
|||
element.remove_param('e_stitch')
|
||||
element.set_param('satin_method', 'e_stitch')
|
||||
|
||||
if element.get_boolean_param('satin_column', False):
|
||||
if element.get_boolean_param('satin_column', False) or element.get_int_param('stroke_method', 0) == 1:
|
||||
# reverse_rails defaults to Automatic, but we should never reverse an
|
||||
# old satin automatically, only new ones
|
||||
element.set_param('reverse_rails', 'none')
|
||||
|
@ -112,6 +112,9 @@ def _update_to_one(element): # noqa: C901
|
|||
# default setting for fill_underlay has changed
|
||||
if legacy_attribs and not element.get_param('fill_underlay', ""):
|
||||
element.set_param('fill_underlay', False)
|
||||
# default setting for running stitch length has changed (fills and strokes, not satins)
|
||||
if not element.get_boolean_param('satin_column', False) and element.get_float_param('running_stitch_length_mm', None) is None:
|
||||
element.set_param('running_stitch_length_mm', 1.5)
|
||||
|
||||
# convert legacy stroke_method
|
||||
if element.get_style("stroke") and not element.node.get('inkscape:connection-start', None):
|
||||
|
|
|
@ -11,12 +11,26 @@
|
|||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<param name="end-row-spacing"
|
||||
gui-text="End row spacing"
|
||||
gui-description="Set to zero to use twice the row spacing value"
|
||||
type="float"
|
||||
min="0" max="100"
|
||||
indents="1">0.5</param>
|
||||
<param name="notebook" type="notebook">
|
||||
<page name="options" gui-text="Options">
|
||||
<param name="end-row-spacing"
|
||||
gui-text="End row spacing"
|
||||
gui-description="Set to zero to use twice the row spacing value"
|
||||
type="float"
|
||||
min="0" max="100"
|
||||
precision="2"
|
||||
indents="1">0</param>
|
||||
</page>
|
||||
<page name="info" gui-text="Help">
|
||||
<label appearance="header">Converts a fill with a linear color gradient into color blocks with variable row spacing.</label>
|
||||
<spacer />
|
||||
<label>This may add density at the center.</label>
|
||||
<spacer />
|
||||
<label>If necessary adapt the end row spacing value after the conversion with the params dialog.</label>
|
||||
<spacer />
|
||||
<label appearance="url">https://inkstitch.org/docs/fill-tools/#convert-to-gradient-blocks</label>
|
||||
</page>
|
||||
</param>
|
||||
<script>
|
||||
{{ command_tag | safe }}
|
||||
</script>
|
||||
|
|
Ładowanie…
Reference in New Issue