kopia lustrzana https://github.com/inkstitch/inkstitch
Add multicolor satin extension (#2863)
rodzic
b218aac86c
commit
0c825d2163
|
@ -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,
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension translationdomain="inkstitch" xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Multicolor Satin</name>
|
||||
<id>org.{{ id_inkstitch }}.satin_multicolor</id>
|
||||
<param name="extension" type="string" gui-hidden="true">satin_multicolor</param>
|
||||
<effect needs-live-preview="false">
|
||||
<object-type>all</object-type>
|
||||
<effects-menu>
|
||||
<submenu name="{{ menu_inkstitch }}" translatable="no">
|
||||
<submenu name="Tools: Satin" />
|
||||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<script>
|
||||
{{ command_tag | safe }}
|
||||
</script>
|
||||
</inkscape-extension>
|
Ładowanie…
Reference in New Issue