summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/extensions/__init__.py2
-rw-r--r--lib/extensions/satin_multicolor.py56
-rw-r--r--lib/gui/__init__.py1
-rw-r--r--lib/gui/satin_multicolor/colorize.py273
-rw-r--r--lib/gui/satin_multicolor/help_panel.py42
-rw-r--r--lib/gui/satin_multicolor/main_panel.py199
-rw-r--r--lib/gui/tartan/main_panel.py4
7 files changed, 574 insertions, 3 deletions
diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py
index 7674fba5..86c75395 100644
--- a/lib/extensions/__init__.py
+++ b/lib/extensions/__init__.py
@@ -48,6 +48,7 @@ from .preferences import Preferences
from .print_pdf import Print
from .remove_embroidery_settings import RemoveEmbroiderySettings
from .reorder import Reorder
+from .satin_multicolor import SatinMulticolor
from .select_elements import SelectElements
from .selection_to_guide_line import SelectionToGuideLine
from .selection_to_pattern import SelectionToPattern
@@ -108,6 +109,7 @@ __all__ = extensions = [ApplyPalette,
Print,
RemoveEmbroiderySettings,
Reorder,
+ SatinMulticolor,
SelectElements,
SelectionToGuideLine,
SelectionToPattern,
diff --git a/lib/extensions/satin_multicolor.py b/lib/extensions/satin_multicolor.py
new file mode 100644
index 00000000..5657bdbf
--- /dev/null
+++ b/lib/extensions/satin_multicolor.py
@@ -0,0 +1,56 @@
+# Authors: see git history
+#
+# Copyright (c) 2023 Authors
+# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
+
+import sys
+
+import wx
+import wx.adv
+from inkex import errormsg
+
+from ..elements import SatinColumn
+from ..gui import MultiColorSatinPanel
+from ..gui.simulator import SplitSimulatorWindow
+from ..i18n import _
+from ..utils.svg_data import get_pagecolor
+from .base import InkstitchExtension
+
+
+class SatinMulticolor(InkstitchExtension):
+ def __init__(self, *args, **kwargs):
+ self.elements = set()
+ self.cancelled = False
+ InkstitchExtension.__init__(self, *args, **kwargs)
+
+ def cancel(self):
+ self.cancelled = True
+
+ def effect(self):
+ self.get_elements()
+ satins = [element for element in self.elements if isinstance(element, SatinColumn)]
+ if not satins:
+ errormsg(_("Please select at least one satin column."))
+ return
+
+ metadata = self.get_inkstitch_metadata()
+ background_color = get_pagecolor(self.svg.namedview)
+
+ app = wx.App()
+ frame = SplitSimulatorWindow(
+ title=_("Ink/Stitch Multicolor Satin"),
+ panel_class=MultiColorSatinPanel,
+ elements=satins,
+ on_cancel=self.cancel,
+ metadata=metadata,
+ background_color=background_color,
+ target_duration=1
+ )
+
+ frame.Show()
+ app.MainLoop()
+
+ if self.cancelled:
+ # This prevents the superclass from outputting the SVG, because we
+ # may have modified the DOM.
+ sys.exit(0)
diff --git a/lib/gui/__init__.py b/lib/gui/__init__.py
index 8766b5cc..a785e49a 100644
--- a/lib/gui/__init__.py
+++ b/lib/gui/__init__.py
@@ -8,3 +8,4 @@ from .electron import open_url
from .presets import PresetsPanel
from .simulator import PreviewRenderer
from .warnings import WarningPanel
+from .satin_multicolor.main_panel import MultiColorSatinPanel
diff --git a/lib/gui/satin_multicolor/colorize.py b/lib/gui/satin_multicolor/colorize.py
new file mode 100644
index 00000000..87243145
--- /dev/null
+++ b/lib/gui/satin_multicolor/colorize.py
@@ -0,0 +1,273 @@
+# Authors: see git history
+#
+# Copyright (c) 2023 Authors
+# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
+
+from time import time
+
+import wx
+from wx.lib.scrolledpanel import ScrolledPanel
+
+from ...i18n import _
+
+
+class ColorizePanel(ScrolledPanel):
+
+ def __init__(self, parent, panel):
+ self.panel = panel
+ ScrolledPanel.__init__(self, parent)
+
+ self.colorize_sizer = wx.BoxSizer(wx.VERTICAL)
+ general_settings_sizer = wx.FlexGridSizer(8, 2, 10, 20)
+ color_header_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.color_sizer = wx.BoxSizer(wx.VERTICAL)
+
+ # general settings
+ general_settings_headline = wx.StaticText(self, label=_("General Settings"))
+ general_settings_headline.SetFont(wx.Font().Bold())
+
+ equististance_label = wx.StaticText(self, label=_("Equidistant colors"))
+ equististance_label.SetToolTip(_("Whether colors should be equidistant or have varying widths."))
+ self.equististance = wx.CheckBox(self)
+ self.equististance.SetValue(True)
+ self.equististance.Bind(wx.EVT_CHECKBOX, self._on_update_equidistance)
+
+ self.monochrome_width_label = wx.StaticText(self, label=_("Monochrome color width"))
+ self.monochrome_width_label.SetToolTip(_("Adapt color width here when equidistance is enabled."))
+ self.monochrome_width = wx.SpinCtrlDouble(self, min=0, max=100, initial=100, inc=1, style=wx.SP_WRAP)
+ self.monochrome_width.SetDigits(2)
+ self.monochrome_width.Bind(wx.EVT_SPINCTRLDOUBLE, self._on_update_monochrome_width)
+
+ overflow_left_label = wx.StaticText(self, label=_("Overflow left"))
+ self.overflow_left = wx.SpinCtrlDouble(self, min=0, max=100, initial=0, inc=0.1, style=wx.SP_WRAP)
+ self.overflow_left.SetDigits(2)
+ self.overflow_left.Bind(wx.EVT_SPINCTRLDOUBLE, self._update)
+
+ overflow_right_label = wx.StaticText(self, label=_("Overflow right"))
+ self.overflow_right = wx.SpinCtrlDouble(self, min=0, max=100, initial=0, inc=0.1, style=wx.SP_WRAP)
+ self.overflow_right.SetDigits(2)
+ self.overflow_right.Bind(wx.EVT_SPINCTRLDOUBLE, self._update)
+
+ pull_compensation_label = wx.StaticText(self, label=_("Pull compensation (mm)"))
+ self.pull_compensation = wx.SpinCtrlDouble(self, min=0, max=100, initial=0, inc=0.1, style=wx.SP_WRAP)
+ self.pull_compensation.SetDigits(2)
+ self.pull_compensation.Bind(wx.EVT_SPINCTRLDOUBLE, self._update)
+
+ seed_label = wx.StaticText(self, label=_("Random seed"))
+ self.seed = wx.TextCtrl(self)
+ self.seed.SetValue(str(time()))
+ self.seed.Bind(wx.EVT_TEXT, self._update)
+
+ # embroidery settings
+ keep_original_label = wx.StaticText(self, label=_("Keep original satin"))
+ self.keep_original = wx.CheckBox(self)
+ self.keep_original.SetValue(True)
+
+ # Colors
+ color_settings_headline = wx.StaticText(self, label=_("Colors"))
+ color_settings_headline.SetFont(wx.Font().Bold())
+
+ self.total_width = wx.StaticText(self)
+ self.total_width.SetToolTip(_("Overflow excluded"))
+
+ self.add_color_button = wx.Button(self, label=_("Add"))
+ self.add_color_button.Bind(wx.EVT_BUTTON, self._add_color_event)
+
+ # Add to sizers
+ general_settings_sizer.Add(equististance_label, 0, wx.ALL, 0)
+ general_settings_sizer.Add(self.equististance, 0, wx.ALL | wx.EXPAND, 0)
+ general_settings_sizer.Add(self.monochrome_width_label, 0, wx.LEFT, 30)
+ general_settings_sizer.Add(self.monochrome_width, 0, wx.ALL | wx.EXPAND, 0)
+ general_settings_sizer.Add(overflow_left_label, 0, wx.ALL, 0)
+ general_settings_sizer.Add(self.overflow_left, 0, wx.ALL | wx.EXPAND, 0)
+ general_settings_sizer.Add(overflow_right_label, 0, wx.ALL, 0)
+ general_settings_sizer.Add(self.overflow_right, 0, wx.ALL | wx.EXPAND, 0)
+ general_settings_sizer.Add(pull_compensation_label, 0, wx.ALL, 0)
+ general_settings_sizer.Add(self.pull_compensation, 0, wx.ALL | wx.EXPAND, 0)
+ general_settings_sizer.Add(seed_label, 0, wx.ALL, 0)
+ general_settings_sizer.Add(self.seed, 0, wx.ALL | wx.EXPAND, 0)
+ general_settings_sizer.Add(keep_original_label, 0, wx.TOP, 30)
+ general_settings_sizer.Add(self.keep_original, 0, wx.TOP | wx.EXPAND, 30)
+ general_settings_sizer.AddGrowableCol(1)
+
+ color_header_sizer.Add(color_settings_headline, 0, wx.ALL, 10)
+ color_header_sizer.Add((0, 0), 1, wx.ALL | wx.EXPAND, 10)
+ color_header_sizer.Add(self.total_width, 0, wx.ALL, 10)
+
+ self.colorize_sizer.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 10)
+ self.colorize_sizer.Add(general_settings_headline, 0, wx.ALL, 10)
+ self.colorize_sizer.Add(general_settings_sizer, 0, wx.ALL | wx.EXPAND, 20)
+ self.colorize_sizer.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 10)
+ self.colorize_sizer.Add(color_header_sizer, 0, wx.EXPAND | wx.ALL, 10)
+ self.colorize_sizer.Add(self.color_sizer, 0, wx.EXPAND | wx.ALL, 10)
+ self.colorize_sizer.Add(self.add_color_button, 0, wx.ALIGN_RIGHT | wx.ALL, 10)
+
+ self.SetSizer(self.colorize_sizer)
+
+ def _on_update_monochrome_width(self, event):
+ equidistance = self.equististance.GetValue()
+ if not equidistance:
+ return
+ width = self.monochrome_width.GetValue()
+ num_colors = len(self.color_sizer.GetChildren())
+ margin = (100 - width * num_colors) / max(num_colors - 1, 1)
+ self._set_widget_width_value(width, margin)
+ self._update()
+
+ def _add_color_event(self, event):
+ self.add_color()
+
+ def add_color(self, color='black'):
+ colorsizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ position = wx.Button(self, label='↑', style=wx.BU_EXACTFIT)
+ position.SetToolTip(_("Click to move color up."))
+ position.Bind(wx.EVT_BUTTON, self._move_color_up)
+
+ colorpicker = wx.ColourPickerCtrl(self, colour=wx.Colour(color))
+ colorpicker.SetToolTip(_("Select color"))
+ colorpicker.Bind(wx.EVT_COLOURPICKER_CHANGED, self._update)
+
+ color_width = wx.SpinCtrlDouble(self, min=0, max=100, initial=0, style=wx.SP_WRAP)
+ color_width.SetDigits(2)
+ color_width.SetToolTip(_("Monochrome width. Can be changed individually when equidistance is disabled."))
+ color_width.Bind(wx.EVT_SPINCTRLDOUBLE, self._update)
+
+ color_margin_right = wx.SpinCtrlDouble(self, min=0, max=100, initial=0, style=wx.SP_WRAP)
+ color_margin_right.SetDigits(2)
+ color_margin_right.SetToolTip(_("Margin right (bicolor section). Can be changed individually when equidistance is disabled."))
+ color_margin_right.Bind(wx.EVT_SPINCTRLDOUBLE, self._update)
+
+ remove_button = wx.Button(self, label='X')
+ remove_button.SetToolTip(_("Remove color"))
+ remove_button.Bind(wx.EVT_BUTTON, self._remove_color)
+
+ colorsizer.Add(position, 0, wx.CENTER | wx.RIGHT | wx.TOP | wx.RESERVE_SPACE_EVEN_IF_HIDDEN, 5)
+ colorsizer.Add(colorpicker, 0, wx.RIGHT | wx.TOP, 5)
+ colorsizer.Add(color_width, 1, wx.RIGHT | wx.TOP, 5)
+ colorsizer.Add(color_margin_right, 1, wx.RIGHT | wx.TOP | wx.RESERVE_SPACE_EVEN_IF_HIDDEN, 5)
+ colorsizer.Add(remove_button, 0, wx.CENTER | wx.TOP, 5)
+
+ self.color_sizer.Add(colorsizer, 0, wx.EXPAND | wx.ALL, 10)
+
+ if self.equististance.GetValue():
+ color_margin_right.Enable(False)
+ color_width.Enable(False)
+ else:
+ color_margin_right.Enable(True)
+ color_width.Enable(True)
+
+ self._update_colors()
+
+ color_margin_right.Show(False)
+ if len(self.color_sizer.GetChildren()) > 1:
+ self.color_sizer.GetChildren()[-2].GetSizer().GetChildren()[3].GetWindow().Show()
+
+ self._update()
+
+ self.FitInside()
+ self.Layout()
+
+ def _move_color_up(self, event):
+ color = event.GetEventObject()
+ sizer = color.GetContainingSizer()
+ main_sizer = self.color_sizer
+ for i, item in enumerate(main_sizer.GetChildren()):
+ if item.GetSizer() == sizer:
+ index = i
+ break
+ if index == len(main_sizer.GetChildren()) - 1:
+ last_sizer = main_sizer.GetChildren()[-2].GetSizer().GetChildren()
+ last_sizer[2].GetWindow().Show(False)
+ sizer.GetChildren()[2].GetWindow().Show()
+ index = max(0, (index - 1))
+ if index == 0:
+ previous_first = main_sizer.GetChildren()[0].GetSizer().GetChildren()
+ previous_first[0].GetWindow().Show()
+ sizer.GetChildren()[0].GetWindow().Show(False)
+
+ main_sizer.Detach(sizer)
+ main_sizer.Insert(index, sizer, 0, wx.EXPAND | wx.ALL, 10)
+ self.FitInside()
+ self._update()
+ self.Layout()
+
+ def _remove_color(self, event):
+ sizer = event.GetEventObject().GetContainingSizer()
+ sizer.Clear(True)
+ self.color_sizer.Remove(sizer)
+ self.FitInside()
+
+ self._update_colors()
+ self._update()
+
+ def _on_update_equidistance(self, event=None):
+ if self.equististance.GetValue():
+ self.monochrome_width_label.Enable(True)
+ self.monochrome_width.Enable(True)
+ self._set_widget_status(False)
+ self._update_colors()
+ else:
+ self.monochrome_width_label.Enable(False)
+ self.monochrome_width.Enable(False)
+ self._set_widget_status(True)
+ self._update()
+
+ def _set_widget_status(self, status):
+ for color in self.color_sizer.GetChildren():
+ inner_sizer = color.GetSizer()
+ for color_widget in inner_sizer:
+ widget = color_widget.GetWindow()
+ if isinstance(widget, wx.SpinCtrlDouble):
+ widget.Enable(status)
+
+ def _set_widget_width_value(self, value, margin=0):
+ first = True
+ for color in self.color_sizer.GetChildren():
+ inner_sizer = color.GetSizer()
+ for color_widget in inner_sizer:
+ widget = color_widget.GetWindow()
+ if first and widget.Label == "↑":
+ inner_sizer.Hide(widget)
+ first = False
+ if isinstance(widget, wx.SpinCtrlDouble):
+ widget.SetValue(value)
+ widget.GetNextSibling().SetValue(margin)
+ break
+
+ def get_total_width(self):
+ width = 0
+ colors = self.color_sizer.GetChildren()
+ for color in colors:
+ inner_sizer = color.GetSizer()
+ for color_widget in inner_sizer:
+ widget = color_widget.GetWindow()
+ if isinstance(widget, wx.SpinCtrlDouble):
+ width += widget.GetValue()
+ last_margin = inner_sizer.GetChildren()[3].GetWindow().GetValue()
+ width -= last_margin
+ return round(width, 2)
+
+ def _update(self, event=None):
+ width = self.get_total_width()
+ self.total_width.SetLabel(_("Total width: {width}%").format(width=width))
+ if width > 100:
+ self.total_width.SetForegroundColour("red")
+ else:
+ self.total_width.SetForegroundColour(wx.NullColour)
+ self.panel.update_preview()
+
+ def _update_colors(self):
+ equidistance = self.equististance.GetValue()
+ num_colors = len(self.color_sizer.GetChildren())
+ if equidistance:
+ max_width = 100 / max(1, num_colors)
+ monochrome_value = self.monochrome_width.GetValue()
+ if monochrome_value > max_width:
+ self._set_widget_width_value(max_width)
+ else:
+ margin = (100 - monochrome_value * num_colors) / max(1, num_colors - 1)
+ self._set_widget_width_value(monochrome_value, margin)
+ self.monochrome_width.SetMax(max_width)
+ self.Refresh()
+ self._update()
diff --git a/lib/gui/satin_multicolor/help_panel.py b/lib/gui/satin_multicolor/help_panel.py
new file mode 100644
index 00000000..3578d6c9
--- /dev/null
+++ b/lib/gui/satin_multicolor/help_panel.py
@@ -0,0 +1,42 @@
+# Authors: see git history
+#
+# Copyright (c) 2023 Authors
+# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
+
+import wx
+
+from ...i18n import _
+
+
+class HelpPanel(wx.Panel):
+ def __init__(self, parent):
+ wx.Panel.__init__(self, parent)
+ help_sizer = wx.BoxSizer(wx.VERTICAL)
+
+ help_text = wx.StaticText(
+ self,
+ wx.ID_ANY,
+ _("This extension simulates a multicolor satin by creating colored copies of the selected satin(s)."),
+ style=wx.ALIGN_LEFT
+ )
+ help_text.Wrap(500)
+ help_sizer.Add(help_text, 0, wx.ALL, 8)
+
+ help_sizer.Add((20, 20), 0, 0, 0)
+
+ website_info = wx.StaticText(self, wx.ID_ANY, _("More information on our website:"))
+ help_sizer.Add(website_info, 0, wx.ALL, 8)
+
+ website_link = wx.adv.HyperlinkCtrl(
+ self,
+ wx.ID_ANY,
+ _("https://inkstitch.org/docs/satin-tools/#multicolor-satin"),
+ _("https://inkstitch.org/docs/satin-tools/#multicolor-satin")
+ )
+ website_link.Bind(wx.adv.EVT_HYPERLINK, self.on_link_clicked)
+ help_sizer.Add(website_link, 0, wx.ALL, 8)
+
+ self.SetSizer(help_sizer)
+
+ def on_link_clicked(self, event):
+ event.Skip()
diff --git a/lib/gui/satin_multicolor/main_panel.py b/lib/gui/satin_multicolor/main_panel.py
new file mode 100644
index 00000000..fb16413e
--- /dev/null
+++ b/lib/gui/satin_multicolor/main_panel.py
@@ -0,0 +1,199 @@
+# Authors: see git history
+#
+# Copyright (c) 2023 Authors
+# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
+
+from copy import copy
+
+import inkex
+import wx
+import wx.adv
+
+from ...elements import SatinColumn
+from ...exceptions import InkstitchException, format_uncaught_exception
+from ...i18n import _
+from ...stitch_plan import stitch_groups_to_stitch_plan
+from ...utils.threading import ExitThread, check_stop_flag
+from .. import PreviewRenderer, WarningPanel
+from .colorize import ColorizePanel
+from .help_panel import HelpPanel
+
+
+class MultiColorSatinPanel(wx.Panel):
+
+ def __init__(self, parent, simulator, elements, on_cancel=None, metadata=None, background_color='white'):
+ self.parent = parent
+ self.simulator = simulator
+ self.elements = elements
+ self.cancel_hook = on_cancel
+ self.metadata = metadata or dict()
+ self.background_color = background_color
+ self.output_groups = []
+
+ super().__init__(parent, wx.ID_ANY)
+
+ self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT | wx.DEFAULT_FRAME_STYLE)
+
+ # preview
+ self.preview_renderer = PreviewRenderer(self.render_stitch_plan, self.on_stitch_plan_rendered)
+ # warnings
+ self.warning_panel = WarningPanel(self)
+ self.warning_panel.Hide()
+ # notebook
+ self.notebook_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.notebook = wx.Notebook(self, wx.ID_ANY)
+ self.notebook_sizer.Add(self.warning_panel, 0, wx.EXPAND | wx.ALL, 10)
+ self.notebook_sizer.Add(self.notebook, 1, wx.EXPAND, 0)
+ # customize
+ self.colorize_panel = ColorizePanel(self.notebook, self)
+ self.notebook.AddPage(self.colorize_panel, _('Colorize'))
+ self.colorize_panel.SetupScrolling()
+ # help
+ help_panel = HelpPanel(self.notebook)
+ self.notebook.AddPage(help_panel, _("Help"))
+ # apply and cancel buttons
+ apply_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.cancel_button = wx.Button(self, label=_("Cancel"))
+ self.cancel_button.Bind(wx.EVT_BUTTON, self.cancel)
+ self.apply_button = wx.Button(self, label=_("Apply"))
+ self.apply_button.Bind(wx.EVT_BUTTON, self.apply)
+ apply_sizer.Add(self.cancel_button, 0, wx.RIGHT | wx.BOTTOM, 5)
+ apply_sizer.Add(self.apply_button, 0, wx.RIGHT | wx.BOTTOM, 10)
+
+ self.notebook_sizer.Add(apply_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 10)
+
+ self.SetSizer(self.notebook_sizer)
+
+ self.colorize_panel.add_color(self.elements[0].color)
+
+ self.Layout()
+ self.SetMinSize(self.notebook_sizer.CalcMin())
+
+ def _hide_warning(self):
+ self.warning_panel.clear()
+ self.warning_panel.Hide()
+ self.Layout()
+
+ def _show_warning(self, warning_text):
+ self.warning_panel.set_warning_text(warning_text)
+ self.warning_panel.Show()
+ self.Layout()
+
+ def update_preview(self, event=None):
+ self.preview_renderer.update()
+
+ def close(self):
+ self.GetTopLevelParent().Close()
+
+ def cancel(self, event):
+ if self.cancel_hook:
+ self.cancel_hook()
+ self.close()
+
+ def apply(self, event):
+ self.update_satin_elements()
+ if not self.colorize_panel.keep_original.GetValue():
+ for element in self.elements:
+ element.node.getparent().remove(element.node)
+ self.close()
+
+ def render_stitch_plan(self):
+ self.update_satin_elements()
+ stitch_groups = self._get_stitch_groups()
+
+ if stitch_groups:
+ stitch_plan = stitch_groups_to_stitch_plan(
+ stitch_groups,
+ collapse_len=self.metadata['collapse_len_mm'],
+ min_stitch_len=self.metadata['min_stitch_len_mm']
+ )
+ return stitch_plan
+
+ def _get_stitch_groups(self):
+ stitch_groups = []
+ for element in self.satin_elements:
+ try:
+ # copy the embroidery element to drop the cache
+ stitch_group = copy(SatinColumn(element)).embroider(None)
+ stitch_groups.extend(stitch_group)
+ except (SystemExit, ExitThread):
+ raise
+ except InkstitchException as exc:
+ wx.CallAfter(self._show_warning, str(exc))
+ except Exception:
+ wx.CallAfter(self._show_warning, format_uncaught_exception())
+ return stitch_groups
+
+ def update_satin_elements(self):
+ # empty old groups
+ for group in self.output_groups:
+ group.getparent().remove(group)
+ self.output_groups = []
+
+ overflow_left = self.colorize_panel.overflow_left.GetValue()
+ overflow_right = self.colorize_panel.overflow_right.GetValue()
+ pull_compensation = self.colorize_panel.pull_compensation.GetValue()
+ seed = self.colorize_panel.seed.GetValue()
+
+ self.satin_elements = []
+ color_sizer = self.colorize_panel.color_sizer.GetChildren()
+ num_colors = len(color_sizer)
+ for element in self.elements:
+ check_stop_flag()
+ layer = element.node.getparent()
+ index = layer.index(element.node)
+ group = inkex.Group()
+ group.label = _("Multicolor Satin Group")
+ current_position = 0
+ previous_margin = overflow_left
+ for i, segment_sizer in enumerate(color_sizer):
+ segment = segment_sizer.GetSizer().GetChildren()
+ color = segment[1].GetWindow().GetColour().GetAsString(wx.C2S_HTML_SYNTAX)
+ if i == num_colors - 1:
+ margin = overflow_right
+ else:
+ margin = segment[3].GetWindow().GetValue()
+ width = segment[2].GetWindow().GetValue()
+
+ new_satin = copy(element.node)
+ new_satin.style['stroke'] = color
+ new_satin.set('inkstitch:pull_compensation_mm', pull_compensation)
+ new_satin.set('inkstitch:random_seed', seed)
+
+ reverse_rails = self._get_new_reverse_rails_param(element, i)
+ if reverse_rails is not None:
+ new_satin.set('inkstitch:reverse_rails', reverse_rails)
+
+ if i % 2 == 0:
+ new_satin.set('inkstitch:swap_satin_rails', False)
+ new_satin.set('inkstitch:random_width_increase_percent', f'{ margin } 0')
+ new_satin.set('inkstitch:random_width_decrease_percent', f'0 { -previous_margin }')
+ new_satin.set('inkstitch:pull_compensation_percent', f'{ current_position + width - 100} { -current_position }')
+ else:
+ new_satin.set('inkstitch:swap_satin_rails', True)
+ new_satin.set('inkstitch:random_width_increase_percent', f'0 { margin }')
+ new_satin.set('inkstitch:random_width_decrease_percent', f'{ -previous_margin } 0')
+ new_satin.set('inkstitch:pull_compensation_percent', f'{ -current_position } { current_position + width - 100}')
+
+ previous_margin = margin
+ current_position += width + margin
+
+ group.add(new_satin)
+ self.satin_elements.append(new_satin)
+
+ layer.insert(index + 1, group)
+ self.output_groups.append(group)
+
+ def _get_new_reverse_rails_param(self, element, i):
+ reverse_rails = element._get_rails_to_reverse()
+ if any(reverse_rails) and element.reverse_rails == 'automatic':
+ if (reverse_rails[0] and i % 2 == 0) or (reverse_rails[1] and i % 2 != 0):
+ return 'first'
+ else:
+ return 'second'
+ return None
+
+ def on_stitch_plan_rendered(self, stitch_plan):
+ self.simulator.stop()
+ self.simulator.load(stitch_plan)
+ self.simulator.go()
diff --git a/lib/gui/tartan/main_panel.py b/lib/gui/tartan/main_panel.py
index 82638170..74087426 100644
--- a/lib/gui/tartan/main_panel.py
+++ b/lib/gui/tartan/main_panel.py
@@ -6,7 +6,6 @@
import json
from copy import copy
-import inkex
import wx
import wx.adv
@@ -26,7 +25,7 @@ from . import CodePanel, CustomizePanel, EmbroideryPanel, HelpPanel
class TartanMainPanel(wx.Panel):
- def __init__(self, parent, simulator, elements, on_cancel=None, metadata=None, background_color='white', output_groups=inkex.Group()):
+ def __init__(self, parent, simulator, elements, on_cancel=None, metadata=None, background_color='white'):
self.parent = parent
self.simulator = simulator
self.elements = elements
@@ -34,7 +33,6 @@ class TartanMainPanel(wx.Panel):
self.palette = Palette()
self.metadata = metadata or dict()
self.background_color = background_color
- self.output_groups = output_groups
super().__init__(parent, wx.ID_ANY)