kopia lustrzana https://github.com/inkstitch/inkstitch
attach params/lettering simulator window and allow detach (#2557)
rodzic
526cd48a4f
commit
82f2edac1a
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 2.8 KiB |
|
@ -0,0 +1,98 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="256"
|
||||
height="256"
|
||||
viewBox="0 0 256 256"
|
||||
id="svg8375"
|
||||
version="1.1"
|
||||
inkscape:version="1.3 (1:1.3+202307231459+0e150ed6c4)"
|
||||
sodipodi:docname="detach_window.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs8377">
|
||||
<marker
|
||||
style="overflow:visible"
|
||||
id="Triangle"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto-start-reverse"
|
||||
inkscape:stockid="Triangle arrow"
|
||||
markerWidth="0.5"
|
||||
markerHeight="0.5"
|
||||
viewBox="0 0 1 1"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always"
|
||||
preserveAspectRatio="xMidYMid">
|
||||
<path
|
||||
transform="scale(0.5)"
|
||||
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
|
||||
d="M 5.77,0 -2.88,5 V -5 Z"
|
||||
id="path135" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.3183809"
|
||||
inkscape:cx="193.41906"
|
||||
inkscape:cy="284.81905"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="mm"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="705"
|
||||
inkscape:window-x="-4"
|
||||
inkscape:window-y="-4"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
<metadata
|
||||
id="metadata8380">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:#000000;stroke-width:22.3274"
|
||||
id="rect1-3-7"
|
||||
width="94.246475"
|
||||
height="86.769928"
|
||||
x="159.3401"
|
||||
y="3.0987689" />
|
||||
<rect
|
||||
style="fill:#000000;stroke-width:13.626"
|
||||
id="rect1-3-7-5"
|
||||
width="57.516991"
|
||||
height="52.954185"
|
||||
x="3.5270462"
|
||||
y="199.60167" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:17.0079;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Triangle)"
|
||||
d="M 69.827955,184.17307 126.75642,123.7445"
|
||||
id="path3"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 2.8 KiB |
|
@ -14,36 +14,37 @@ import wx
|
|||
import wx.adv
|
||||
import wx.lib.agw.floatspin as fs
|
||||
|
||||
from .commands import CommandsExtension
|
||||
from .lettering_custom_font_dir import get_custom_font_dir
|
||||
from ..elements import nodes_to_elements
|
||||
from ..gui import PresetsPanel, SimulatorPreview, info_dialog
|
||||
from ..gui import PresetsPanel, PreviewRenderer, info_dialog
|
||||
from ..gui.simulator import SplitSimulatorWindow
|
||||
from ..i18n import _
|
||||
from ..lettering import Font, FontError
|
||||
from ..lettering.categories import FONT_CATEGORIES, FontCategory
|
||||
from ..stitch_plan import stitch_groups_to_stitch_plan
|
||||
from ..svg import get_correction_transform
|
||||
from ..svg.tags import (INKSCAPE_LABEL, INKSTITCH_LETTERING, SVG_GROUP_TAG,
|
||||
SVG_PATH_TAG)
|
||||
from ..utils import DotDict, cache, get_bundled_dir, get_resource_dir
|
||||
from ..utils.threading import ExitThread
|
||||
from .commands import CommandsExtension
|
||||
from .lettering_custom_font_dir import get_custom_font_dir
|
||||
from ..utils import DotDict, cache, get_bundled_dir
|
||||
from ..utils.threading import ExitThread, check_stop_flag
|
||||
|
||||
|
||||
class LetteringFrame(wx.Frame):
|
||||
class LetteringPanel(wx.Panel):
|
||||
DEFAULT_FONT = "small_font"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.group = kwargs.pop('group')
|
||||
self.cancel_hook = kwargs.pop('on_cancel', None)
|
||||
self.metadata = kwargs.pop('metadata', [])
|
||||
def __init__(self, parent, simulator, group, on_cancel=None, metadata=None):
|
||||
self.parent = parent
|
||||
self.simulator = simulator
|
||||
self.group = group
|
||||
self.cancel_hook = on_cancel
|
||||
self.metadata = metadata or dict()
|
||||
|
||||
# begin wxGlade: MyFrame.__init__
|
||||
wx.Frame.__init__(self, None, wx.ID_ANY, _("Ink/Stitch Lettering"))
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT)
|
||||
super().__init__(parent, wx.ID_ANY)
|
||||
|
||||
icon = wx.Icon(os.path.join(get_resource_dir("icons"), "inkstitch256x256.png"))
|
||||
self.SetIcon(icon)
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT | wx.DEFAULT_FRAME_STYLE)
|
||||
|
||||
self.preview = SimulatorPreview(self, target_duration=1)
|
||||
self.preview_renderer = PreviewRenderer(self.render_stitch_plan, self.on_stitch_plan_rendered)
|
||||
self.presets_panel = PresetsPanel(self)
|
||||
|
||||
# font
|
||||
|
@ -257,11 +258,11 @@ class LetteringFrame(wx.Frame):
|
|||
self.settings[attribute] = event.GetEventObject().GetValue()
|
||||
if attribute == "text" and self.font_glyph_filter.GetValue() is True:
|
||||
self.on_filter_changed()
|
||||
self.preview.update()
|
||||
self.preview_renderer.update()
|
||||
|
||||
def on_trim_option_change(self, event=None):
|
||||
self.settings.trim_option = self.trim_option_choice.GetCurrentSelection()
|
||||
self.preview.update()
|
||||
self.preview_renderer.update()
|
||||
|
||||
def on_font_changed(self, event=None):
|
||||
font = self.fonts.get(self.font_chooser.GetValue(), self.default_font)
|
||||
|
@ -329,7 +330,7 @@ class LetteringFrame(wx.Frame):
|
|||
self.Layout()
|
||||
|
||||
def update_preview(self, event=None):
|
||||
self.preview.update()
|
||||
self.preview_renderer.update()
|
||||
|
||||
def update_lettering(self, raise_error=False):
|
||||
# return if there is no font in the font list (possibly due to a font size filter)
|
||||
|
@ -367,19 +368,24 @@ class LetteringFrame(wx.Frame):
|
|||
if self.settings.scale != 100 and not destination_group.get('transform', None):
|
||||
destination_group.attrib['transform'] = 'scale(%s)' % (self.settings.scale / 100.0)
|
||||
|
||||
def generate_patches(self, abort_early=None):
|
||||
patches = []
|
||||
def render_stitch_plan(self):
|
||||
stitch_groups = []
|
||||
|
||||
try:
|
||||
self.update_lettering()
|
||||
elements = nodes_to_elements(self.group.iterdescendants(SVG_PATH_TAG))
|
||||
|
||||
for element in elements:
|
||||
if abort_early and abort_early.is_set():
|
||||
# cancel; settings were updated and we need to start over
|
||||
return []
|
||||
check_stop_flag()
|
||||
|
||||
patches.extend(element.embroider(None))
|
||||
stitch_groups.extend(element.embroider(None))
|
||||
|
||||
if stitch_groups:
|
||||
return stitch_groups_to_stitch_plan(
|
||||
stitch_groups,
|
||||
collapse_len=self.metadata['collapse_len_mm'],
|
||||
min_stitch_len=self.metadata['min_stitch_len_mm']
|
||||
)
|
||||
except SystemExit:
|
||||
raise
|
||||
except ExitThread:
|
||||
|
@ -390,7 +396,10 @@ class LetteringFrame(wx.Frame):
|
|||
# satins or division by zero caused by incorrect param values.
|
||||
pass
|
||||
|
||||
return patches
|
||||
def on_stitch_plan_rendered(self, stitch_plan):
|
||||
self.simulator.stop()
|
||||
self.simulator.load(stitch_plan)
|
||||
self.simulator.go()
|
||||
|
||||
def get_preset_data(self):
|
||||
# called by self.presets_panel
|
||||
|
@ -409,14 +418,12 @@ class LetteringFrame(wx.Frame):
|
|||
return "lettering"
|
||||
|
||||
def apply(self, event):
|
||||
self.preview.disable()
|
||||
self.update_lettering(True)
|
||||
self.save_settings()
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
self.preview.close()
|
||||
self.Destroy()
|
||||
self.GetTopLevelParent().Close()
|
||||
|
||||
def cancel(self, event):
|
||||
if self.cancel_hook:
|
||||
|
@ -534,14 +541,14 @@ class Lettering(CommandsExtension):
|
|||
def effect(self):
|
||||
metadata = self.get_inkstitch_metadata()
|
||||
app = wx.App()
|
||||
frame = LetteringFrame(group=self.get_or_create_group(), on_cancel=self.cancel, metadata=metadata)
|
||||
|
||||
# position left, center
|
||||
current_screen = wx.Display.GetFromPoint(wx.GetMousePosition())
|
||||
display = wx.Display(current_screen)
|
||||
display_size = display.GetClientArea()
|
||||
frame_size = frame.GetSize()
|
||||
frame.SetPosition((int(display_size[0]), int(display_size[3] / 2 - frame_size[1] / 2)))
|
||||
frame = SplitSimulatorWindow(
|
||||
title=_("Ink/Stitch Lettering"),
|
||||
panel_class=LetteringPanel,
|
||||
group=self.get_or_create_group(),
|
||||
on_cancel=self.cancel,
|
||||
metadata=metadata,
|
||||
target_duration=1
|
||||
)
|
||||
|
||||
frame.Show()
|
||||
app.MainLoop()
|
||||
|
|
|
@ -15,18 +15,20 @@ from secrets import randbelow
|
|||
import wx
|
||||
from wx.lib.scrolledpanel import ScrolledPanel
|
||||
|
||||
from .base import InkstitchExtension
|
||||
from ..commands import is_command, is_command_symbol
|
||||
from ..elements import (Clone, EmbroideryElement, FillStitch, Polyline,
|
||||
SatinColumn, Stroke)
|
||||
from ..elements.clone import is_clone
|
||||
from ..exceptions import InkstitchException, format_uncaught_exception
|
||||
from ..gui import PresetsPanel, SimulatorPreview, WarningPanel
|
||||
from ..gui import PresetsPanel, PreviewRenderer, WarningPanel
|
||||
from ..gui.simulator import SplitSimulatorWindow
|
||||
from ..i18n import _
|
||||
from ..stitch_plan import stitch_groups_to_stitch_plan
|
||||
from ..svg.tags import SVG_POLYLINE_TAG
|
||||
from ..utils import get_resource_dir
|
||||
from ..utils.param import ParamOption
|
||||
from ..utils.threading import ExitThread, check_stop_flag
|
||||
from .base import InkstitchExtension
|
||||
|
||||
|
||||
def grouper(iterable_obj, count, fillvalue=None):
|
||||
|
@ -439,7 +441,7 @@ class ParamsTab(ScrolledPanel):
|
|||
for item in param.select_items:
|
||||
self.choice_widgets[item].extend([input, col4])
|
||||
|
||||
self.settings_grid.Add(input, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.EXPAND, border=40)
|
||||
self.settings_grid.Add(input, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.EXPAND, border=10)
|
||||
self.settings_grid.Add(col4, flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
|
||||
self.inputs_to_params = {v: k for k, v in self.param_inputs.items()}
|
||||
|
@ -470,20 +472,17 @@ class ParamsTab(ScrolledPanel):
|
|||
# end of class SatinPane
|
||||
|
||||
|
||||
class SettingsFrame(wx.Frame):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.tabs_factory = kwargs.pop('tabs_factory', [])
|
||||
self.cancel_hook = kwargs.pop('on_cancel', None)
|
||||
self.metadata = kwargs.pop('metadata', [])
|
||||
class SettingsPanel(wx.Panel):
|
||||
def __init__(self, parent, tabs_factory=None, on_cancel=None, metadata=None, simulator=None):
|
||||
self.tabs_factory = tabs_factory
|
||||
self.cancel_hook = on_cancel
|
||||
self.metadata = metadata
|
||||
self.simulator = simulator
|
||||
self.parent = parent
|
||||
|
||||
# begin wxGlade: MyFrame.__init__
|
||||
wx.Frame.__init__(self, None, wx.ID_ANY, _("Embroidery Params"))
|
||||
super().__init__(self.parent, wx.ID_ANY)
|
||||
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT)
|
||||
|
||||
icon = wx.Icon(os.path.join(
|
||||
get_resource_dir("icons"), "inkstitch256x256.png"))
|
||||
self.SetIcon(icon)
|
||||
self.preview_renderer = PreviewRenderer(self.render_stitch_plan, self.on_stitch_plan_rendered)
|
||||
|
||||
self.notebook = wx.Notebook(self, wx.ID_ANY)
|
||||
self.tabs = self.tabs_factory(self.notebook)
|
||||
|
@ -491,7 +490,6 @@ class SettingsFrame(wx.Frame):
|
|||
for tab in self.tabs:
|
||||
tab.on_change(self.update_preview)
|
||||
|
||||
self.preview = SimulatorPreview(self)
|
||||
self.presets_panel = PresetsPanel(self)
|
||||
self.warning_panel = WarningPanel(self)
|
||||
self.warning_panel.Hide()
|
||||
|
@ -507,43 +505,45 @@ class SettingsFrame(wx.Frame):
|
|||
self.apply_button = wx.Button(self, wx.ID_ANY, _("Apply and Quit"))
|
||||
self.apply_button.Bind(wx.EVT_BUTTON, self.apply)
|
||||
|
||||
self.notebook.SetMinSize((800, 600))
|
||||
|
||||
self.__do_layout()
|
||||
# end wxGlade
|
||||
self.update_preview()
|
||||
|
||||
def update_preview(self, tab):
|
||||
self.preview.update()
|
||||
def update_preview(self, tab=None):
|
||||
self.simulator.stop()
|
||||
self.simulator.clear()
|
||||
self.preview_renderer.update()
|
||||
|
||||
def generate_patches(self, abort_early):
|
||||
# called by self.preview
|
||||
|
||||
patches = []
|
||||
def render_stitch_plan(self):
|
||||
stitch_groups = []
|
||||
nodes = []
|
||||
|
||||
for tab in self.tabs:
|
||||
tab.apply()
|
||||
|
||||
if tab.enabled() and not tab.is_dependent_tab():
|
||||
nodes.extend(tab.nodes)
|
||||
|
||||
check_stop_flag()
|
||||
|
||||
# sort nodes into the proper stacking order
|
||||
nodes.sort(key=lambda node: node.order)
|
||||
|
||||
try:
|
||||
wx.CallAfter(self._hide_warning)
|
||||
for node in nodes:
|
||||
if abort_early.is_set():
|
||||
# cancel; params were updated and we need to start over
|
||||
return []
|
||||
|
||||
# Making a copy of the embroidery element is an easy
|
||||
# way to drop the cache in the @cache decorators used
|
||||
# for many params in embroider.py.
|
||||
|
||||
patches.extend(copy(node).embroider(None))
|
||||
stitch_groups.extend(copy(node).embroider(None))
|
||||
|
||||
check_stop_flag()
|
||||
|
||||
if stitch_groups:
|
||||
return stitch_groups_to_stitch_plan(
|
||||
stitch_groups,
|
||||
collapse_len=self.metadata['collapse_len_mm'],
|
||||
min_stitch_len=self.metadata['min_stitch_len_mm']
|
||||
)
|
||||
except (SystemExit, ExitThread):
|
||||
raise
|
||||
except InkstitchException as exc:
|
||||
|
@ -551,7 +551,10 @@ class SettingsFrame(wx.Frame):
|
|||
except Exception:
|
||||
wx.CallAfter(self._show_warning, format_uncaught_exception())
|
||||
|
||||
return patches
|
||||
def on_stitch_plan_rendered(self, stitch_plan):
|
||||
self.simulator.stop()
|
||||
self.simulator.load(stitch_plan)
|
||||
self.simulator.go()
|
||||
|
||||
def _hide_warning(self):
|
||||
self.warning_panel.clear()
|
||||
|
@ -589,7 +592,7 @@ class SettingsFrame(wx.Frame):
|
|||
for tab in self.tabs:
|
||||
tab.load_preset(preset_data)
|
||||
|
||||
self.preview.update()
|
||||
self.preview_renderer.update()
|
||||
|
||||
def _apply(self):
|
||||
for tab in self.tabs:
|
||||
|
@ -601,13 +604,11 @@ class SettingsFrame(wx.Frame):
|
|||
self.close()
|
||||
|
||||
def use_last(self, event):
|
||||
self.preview.disable()
|
||||
self.presets_panel.load_preset("__LAST__")
|
||||
self.apply(event)
|
||||
|
||||
def close(self):
|
||||
self.preview.close()
|
||||
self.Destroy()
|
||||
self.GetTopLevelParent().Close()
|
||||
|
||||
def cancel(self, event):
|
||||
if self.cancel_hook:
|
||||
|
@ -781,18 +782,14 @@ class Params(InkstitchExtension):
|
|||
try:
|
||||
app = wx.App()
|
||||
metadata = self.get_inkstitch_metadata()
|
||||
frame = SettingsFrame(
|
||||
frame = SplitSimulatorWindow(
|
||||
title=_("Embroidery Params"),
|
||||
panel_class=SettingsPanel,
|
||||
tabs_factory=self.create_tabs,
|
||||
on_cancel=self.cancel,
|
||||
metadata=metadata)
|
||||
|
||||
# position left, center
|
||||
current_screen = wx.Display.GetFromPoint(wx.GetMousePosition())
|
||||
display = wx.Display(current_screen)
|
||||
display_size = display.GetClientArea()
|
||||
frame_size = frame.GetSize()
|
||||
frame.SetPosition((int(display_size[0]), int(
|
||||
display_size[3]/2 - frame_size[1]/2)))
|
||||
metadata=metadata,
|
||||
target_duration=5
|
||||
)
|
||||
|
||||
frame.Show()
|
||||
app.MainLoop()
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
from .dialogs import confirm_dialog, info_dialog
|
||||
from .electron import open_url
|
||||
from .presets import PresetsPanel
|
||||
from .simulator import EmbroiderySimulator, SimulatorPreview, show_simulator
|
||||
from .simulator import PreviewRenderer, show_simulator
|
||||
from .warnings import WarningPanel
|
||||
|
|
|
@ -16,7 +16,7 @@ class ElementInfoFrame(wx.Frame):
|
|||
self.index = 0
|
||||
wx.Frame.__init__(self, None, wx.ID_ANY, _("Element Info"), *args, **kwargs)
|
||||
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT)
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT | wx.DEFAULT_FRAME_STYLE)
|
||||
|
||||
self.main_panel = wx.Panel(self, wx.ID_ANY)
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class PreferencesFrame(wx.Frame):
|
|||
wx.Frame.__init__(self, None, wx.ID_ANY, _("Preferences"), *args, **kwargs)
|
||||
self.SetTitle(_("Preferences"))
|
||||
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT)
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT | wx.DEFAULT_FRAME_STYLE)
|
||||
|
||||
metadata = self.extension.get_inkstitch_metadata()
|
||||
|
||||
|
|
|
@ -12,9 +12,10 @@ from wx.lib.intctrl import IntCtrl
|
|||
|
||||
from lib.debug import debug
|
||||
from lib.utils import get_resource_dir
|
||||
from lib.utils.settings import global_settings
|
||||
from lib.utils.threading import ExitThread
|
||||
from ..i18n import _
|
||||
from ..stitch_plan import stitch_groups_to_stitch_plan, stitch_plan_from_file
|
||||
from ..stitch_plan import stitch_plan_from_file
|
||||
from ..svg import PIXELS_PER_MM
|
||||
|
||||
# L10N command label at bottom of simulator window
|
||||
|
@ -34,7 +35,8 @@ class ControlPanel(wx.Panel):
|
|||
def __init__(self, parent, *args, **kwargs):
|
||||
""""""
|
||||
self.parent = parent
|
||||
self.stitch_plan = kwargs.pop('stitch_plan')
|
||||
self.stitch_plan = kwargs.pop('stitch_plan', None)
|
||||
self.detach_callback = kwargs.pop('detach_callback', None)
|
||||
self.target_stitches_per_second = kwargs.pop('stitches_per_second')
|
||||
self.target_duration = kwargs.pop('target_duration')
|
||||
kwargs['style'] = wx.BORDER_SUNKEN
|
||||
|
@ -97,16 +99,16 @@ class ControlPanel(wx.Panel):
|
|||
self.btnNpp.Bind(wx.EVT_TOGGLEBUTTON, self.toggle_npp)
|
||||
self.btnNpp.SetBitmap(self.load_icon('npp'))
|
||||
self.btnNpp.SetToolTip(_('Display needle penetration point (O)'))
|
||||
self.slider = SimulatorSlider(self, -1, value=1, minValue=1, maxValue=self.stitch_plan.num_stitches)
|
||||
self.slider = SimulatorSlider(self, -1, value=1, minValue=1, maxValue=2)
|
||||
self.slider.Bind(wx.EVT_SLIDER, self.on_slider)
|
||||
self.stitchBox = IntCtrl(self, -1, value=1, min=1, max=self.stitch_plan.num_stitches,
|
||||
size=((100, -1)), limited=True, allow_none=True, style=wx.TE_PROCESS_ENTER)
|
||||
self.stitchBox = IntCtrl(self, -1, value=1, min=1, max=2, limited=True, allow_none=True,
|
||||
size=((100, -1)), style=wx.TE_PROCESS_ENTER)
|
||||
self.stitchBox.Bind(wx.EVT_LEFT_DOWN, self.on_stitch_box_focus)
|
||||
self.stitchBox.Bind(wx.EVT_SET_FOCUS, self.on_stitch_box_focus)
|
||||
self.stitchBox.Bind(wx.EVT_TEXT_ENTER, self.on_stitch_box_focusout)
|
||||
self.stitchBox.Bind(wx.EVT_KILL_FOCUS, self.on_stitch_box_focusout)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.on_stitch_box_focusout)
|
||||
self.totalstitchText = wx.StaticText(self, -1, label=f"/ { self.stitch_plan.num_stitches }")
|
||||
self.totalstitchText = wx.StaticText(self, -1, label="/ ________")
|
||||
self.btnJump = wx.BitmapToggleButton(self, -1, style=self.button_style)
|
||||
self.btnJump.SetToolTip(_('Show jump stitches'))
|
||||
self.btnJump.SetBitmap(self.load_icon('jump'))
|
||||
|
@ -123,12 +125,17 @@ class ControlPanel(wx.Panel):
|
|||
self.btnColorChange.SetToolTip(_('Show color changes'))
|
||||
self.btnColorChange.SetBitmap(self.load_icon('color_change'))
|
||||
self.btnColorChange.Bind(wx.EVT_TOGGLEBUTTON, lambda event: self.on_marker_button('color_change', event))
|
||||
if self.detach_callback:
|
||||
self.btnDetachSimulator = wx.BitmapButton(self, -1, style=self.button_style)
|
||||
self.btnDetachSimulator.SetToolTip(_('Detach/attach simulator window'))
|
||||
self.btnDetachSimulator.SetBitmap(self.load_icon('detach_window'))
|
||||
self.btnDetachSimulator.Bind(wx.EVT_BUTTON, lambda event: self.detach_callback())
|
||||
|
||||
# Layout
|
||||
self.hbSizer1 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.hbSizer1.Add(self.slider, 1, wx.EXPAND | wx.RIGHT, 10)
|
||||
self.hbSizer1.Add(self.stitchBox, 0, wx.ALIGN_CENTER | wx.RIGHT, 10)
|
||||
self.hbSizer1.Add(self.totalstitchText, 0, wx.ALIGN_CENTER | wx.RIGHT, 10)
|
||||
self.hbSizer1.Add(self.stitchBox, 0, wx.ALIGN_CENTER | wx.Right, 10)
|
||||
self.hbSizer1.Add(self.totalstitchText, 0, wx.ALIGN_CENTER | wx.LEFT, 10)
|
||||
|
||||
self.controls_sizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Controls")), wx.HORIZONTAL)
|
||||
self.controls_inner_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
@ -151,6 +158,8 @@ class ControlPanel(wx.Panel):
|
|||
self.show_inner_sizer.Add(self.btnTrim, 0, wx.ALL, 2)
|
||||
self.show_inner_sizer.Add(self.btnStop, 0, wx.ALL, 2)
|
||||
self.show_inner_sizer.Add(self.btnColorChange, 0, wx.ALL, 2)
|
||||
if self.detach_callback:
|
||||
self.show_inner_sizer.Add(self.btnDetachSimulator, 0, wx.ALL, 2)
|
||||
self.show_sizer.Add((1, 1), 1)
|
||||
self.show_sizer.Add(self.show_inner_sizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
|
||||
self.show_sizer.Add((1, 1), 1)
|
||||
|
@ -209,7 +218,6 @@ class ControlPanel(wx.Panel):
|
|||
(wx.ACCEL_NORMAL, ord('o'), self.on_toggle_npp_shortcut),
|
||||
(wx.ACCEL_NORMAL, ord('p'), self.play_or_pause),
|
||||
(wx.ACCEL_NORMAL, wx.WXK_SPACE, self.play_or_pause),
|
||||
(wx.ACCEL_NORMAL, ord('q'), self.animation_quit),
|
||||
(wx.ACCEL_NORMAL, wx.WXK_PAGEDOWN, self.animation_one_command_backward),
|
||||
(wx.ACCEL_NORMAL, wx.WXK_PAGEUP, self.animation_one_command_forward),
|
||||
|
||||
|
@ -227,7 +235,8 @@ class ControlPanel(wx.Panel):
|
|||
self.SetFocus()
|
||||
|
||||
# wait for layouts so that panel size is set
|
||||
wx.CallLater(50, self.load, self.stitch_plan)
|
||||
if self.stitch_plan:
|
||||
wx.CallLater(50, self.load, self.stitch_plan)
|
||||
|
||||
def set_drawing_panel(self, drawing_panel):
|
||||
self.drawing_panel = drawing_panel
|
||||
|
@ -240,6 +249,7 @@ class ControlPanel(wx.Panel):
|
|||
self.num_stitches = num_stitches
|
||||
self.stitchBox.SetMax(num_stitches)
|
||||
self.slider.SetMax(num_stitches)
|
||||
self.totalstitchText.SetLabel(f"/ { num_stitches }")
|
||||
self.choose_speed()
|
||||
|
||||
def add_color(self, color, num_stitches):
|
||||
|
@ -423,9 +433,6 @@ class ControlPanel(wx.Panel):
|
|||
stitch_number += 1
|
||||
self.drawing_panel.set_current_stitch(stitch_number)
|
||||
|
||||
def animation_quit(self, event):
|
||||
self.parent.quit()
|
||||
|
||||
def animation_restart(self, event):
|
||||
self.drawing_panel.restart()
|
||||
|
||||
|
@ -454,7 +461,7 @@ class DrawingPanel(wx.Panel):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
""""""
|
||||
self.stitch_plan = kwargs.pop('stitch_plan')
|
||||
self.stitch_plan = kwargs.pop('stitch_plan', None)
|
||||
self.control_panel = kwargs.pop('control_panel')
|
||||
kwargs['style'] = wx.BORDER_SUNKEN
|
||||
wx.Panel.__init__(self, *args, **kwargs)
|
||||
|
@ -483,8 +490,11 @@ class DrawingPanel(wx.Panel):
|
|||
self.Bind(wx.EVT_LEFT_DOWN, self.on_left_mouse_button_down)
|
||||
self.Bind(wx.EVT_MOUSEWHEEL, self.on_mouse_wheel)
|
||||
|
||||
self.SetMinSize((400, 400))
|
||||
|
||||
# wait for layouts so that panel size is set
|
||||
wx.CallLater(50, self.load, self.stitch_plan)
|
||||
if self.stitch_plan:
|
||||
wx.CallLater(50, self.load, self.stitch_plan)
|
||||
|
||||
def clamp_current_stitch(self):
|
||||
if self.current_stitch < 1:
|
||||
|
@ -520,10 +530,12 @@ class DrawingPanel(wx.Panel):
|
|||
wx.CallLater(int(1000 * frame_time), self.animate)
|
||||
|
||||
def OnPaint(self, e):
|
||||
dc = wx.PaintDC(self)
|
||||
|
||||
if not self.loaded:
|
||||
dc.Clear()
|
||||
return
|
||||
|
||||
dc = wx.PaintDC(self)
|
||||
canvas = wx.GraphicsContext.Create(dc)
|
||||
|
||||
self.draw_stitches(canvas)
|
||||
|
@ -616,8 +628,8 @@ class DrawingPanel(wx.Panel):
|
|||
canvas.StrokeLineSegments(stitches, [(stitch[0] + 0.001, stitch[1]) for stitch in stitches])
|
||||
|
||||
def clear(self):
|
||||
dc = wx.ClientDC(self)
|
||||
dc.Clear()
|
||||
self.loaded = False
|
||||
self.Refresh()
|
||||
|
||||
def load(self, stitch_plan):
|
||||
self.current_stitch = 1
|
||||
|
@ -722,7 +734,7 @@ class DrawingPanel(wx.Panel):
|
|||
command = self.commands[self.current_stitch]
|
||||
self.control_panel.on_current_stitch(self.current_stitch, command)
|
||||
statusbar = self.GetTopLevelParent().statusbar
|
||||
statusbar.SetStatusText(_("Command: %s") % COMMAND_NAMES[command])
|
||||
statusbar.SetStatusText(_("Command: %s") % COMMAND_NAMES[command], 1)
|
||||
self.stop_if_at_end()
|
||||
self.Refresh()
|
||||
|
||||
|
@ -1012,19 +1024,15 @@ class SimulatorSlider(wx.Panel):
|
|||
class SimulatorPanel(wx.Panel):
|
||||
""""""
|
||||
|
||||
def __init__(self, parent, *args, **kwargs):
|
||||
def __init__(self, parent, stitch_plan=None, target_duration=5, stitches_per_second=16, detach_callback=None):
|
||||
""""""
|
||||
self.parent = parent
|
||||
stitch_plan = kwargs.pop('stitch_plan')
|
||||
target_duration = kwargs.pop('target_duration')
|
||||
stitches_per_second = kwargs.pop('stitches_per_second')
|
||||
kwargs['style'] = wx.BORDER_SUNKEN
|
||||
wx.Panel.__init__(self, parent, *args, **kwargs)
|
||||
super().__init__(parent, style=wx.BORDER_SUNKEN)
|
||||
|
||||
self.cp = ControlPanel(self,
|
||||
stitch_plan=stitch_plan,
|
||||
stitches_per_second=stitches_per_second,
|
||||
target_duration=target_duration)
|
||||
target_duration=target_duration,
|
||||
detach_callback=detach_callback)
|
||||
self.dp = DrawingPanel(self, stitch_plan=stitch_plan, control_panel=self.cp)
|
||||
self.cp.set_drawing_panel(self.dp)
|
||||
|
||||
|
@ -1033,9 +1041,6 @@ class SimulatorPanel(wx.Panel):
|
|||
vbSizer.Add(self.cp, 0, wx.EXPAND | wx.ALL, 2)
|
||||
self.SetSizerAndFit(vbSizer)
|
||||
|
||||
def quit(self):
|
||||
self.parent.quit()
|
||||
|
||||
def go(self):
|
||||
self.dp.go()
|
||||
|
||||
|
@ -1050,108 +1055,161 @@ class SimulatorPanel(wx.Panel):
|
|||
self.dp.clear()
|
||||
|
||||
|
||||
class EmbroiderySimulator(wx.Frame):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.on_close_hook = kwargs.pop('on_close', None)
|
||||
stitch_plan = kwargs.pop('stitch_plan', None)
|
||||
stitches_per_second = kwargs.pop('stitches_per_second', 16)
|
||||
target_duration = kwargs.pop('target_duration', None)
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
class SimulatorWindow(wx.Frame):
|
||||
def __init__(self, panel=None, parent=None, **kwargs):
|
||||
super().__init__(None, title=_("Embroidery Simulation"), **kwargs)
|
||||
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT)
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT | wx.DEFAULT_FRAME_STYLE)
|
||||
|
||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.simulator_panel = SimulatorPanel(self,
|
||||
stitch_plan=stitch_plan,
|
||||
target_duration=target_duration,
|
||||
stitches_per_second=stitches_per_second)
|
||||
sizer.Add(self.simulator_panel, 1, wx.EXPAND)
|
||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.statusbar = self.CreateStatusBar()
|
||||
self.statusbar = self.CreateStatusBar(2)
|
||||
self.statusbar.SetStatusWidths((0, -1))
|
||||
|
||||
# SetSizeHints seems to be ignored in macOS, so we have to adjust size manually
|
||||
# self.SetSizeHints(sizer.CalcMin())
|
||||
frame_width, frame_height = self.GetSize()
|
||||
sizer_width, sizer_height = sizer.CalcMin()
|
||||
size_diff = frame_width - sizer_width
|
||||
if size_diff < 0:
|
||||
frame_x, frame_y = self.GetPosition()
|
||||
self.SetPosition((frame_x + size_diff, frame_y))
|
||||
self.SetSize((sizer_width, frame_height))
|
||||
if panel and parent:
|
||||
self.is_child = True
|
||||
self.panel = panel
|
||||
self.parent = parent
|
||||
self.panel.Reparent(self)
|
||||
self.sizer.Add(self.panel, 1, wx.EXPAND)
|
||||
self.panel.Show()
|
||||
else:
|
||||
self.is_child = False
|
||||
self.simulator_panel = SimulatorPanel(self)
|
||||
self.sizer.Add(self.simulator_panel, 1, wx.EXPAND)
|
||||
|
||||
self.Bind(wx.EVT_CLOSE, self.on_close)
|
||||
self.SetSizer(self.sizer)
|
||||
self.Layout()
|
||||
|
||||
def quit(self):
|
||||
self.Close()
|
||||
self.SetMinSize(self.sizer.CalcMin())
|
||||
|
||||
if self.is_child:
|
||||
self.Bind(wx.EVT_CLOSE, self.on_close)
|
||||
|
||||
def detach_simulator_panel(self):
|
||||
self.sizer.Detach(self.panel)
|
||||
|
||||
def on_close(self, event):
|
||||
self.simulator_panel.stop()
|
||||
self.parent.attach_simulator()
|
||||
|
||||
if self.on_close_hook:
|
||||
self.on_close_hook()
|
||||
|
||||
self.SetFocus()
|
||||
class SplitSimulatorWindow(wx.Frame):
|
||||
def __init__(self, panel_class, title, target_duration=None, **kwargs):
|
||||
super().__init__(None, title=title)
|
||||
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT | wx.DEFAULT_FRAME_STYLE)
|
||||
|
||||
self.detached_simulator_frame = None
|
||||
self.splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
|
||||
self.simulator_panel = SimulatorPanel(self.splitter, target_duration=target_duration, detach_callback=self.toggle_detach_simulator)
|
||||
self.settings_panel = panel_class(self.splitter, simulator=self.simulator_panel, **kwargs)
|
||||
|
||||
self.splitter.SplitVertically(self.settings_panel, self.simulator_panel)
|
||||
self.splitter.SetMinimumPaneSize(100)
|
||||
|
||||
icon = wx.Icon(os.path.join(get_resource_dir("icons"), "inkstitch256x256.png"))
|
||||
self.SetIcon(icon)
|
||||
|
||||
self.statusbar = self.CreateStatusBar(2)
|
||||
|
||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.sizer.Add(self.splitter, 1, wx.EXPAND)
|
||||
self.SetSizer(self.sizer)
|
||||
|
||||
self.SetMinSize(self.sizer.CalcMin())
|
||||
|
||||
self.Maximize()
|
||||
self.Show()
|
||||
wx.CallLater(100, self.set_sash_position)
|
||||
|
||||
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.splitter_resize)
|
||||
self.Bind(wx.EVT_CLOSE, self.on_close)
|
||||
|
||||
if global_settings['pop_out_simulator']:
|
||||
self.detach_simulator()
|
||||
|
||||
def splitter_resize(self, event):
|
||||
self.statusbar.SetStatusWidths((self.simulator_panel.GetScreenPosition()[0], -1))
|
||||
|
||||
def set_sash_position(self):
|
||||
settings_panel_min_size = self.settings_panel.GetSizer().CalcMin()
|
||||
debug.log(f"{settings_panel_min_size=}")
|
||||
self.splitter.SetSashPosition(settings_panel_min_size.width)
|
||||
self.statusbar.SetStatusWidths((settings_panel_min_size.width, -1))
|
||||
|
||||
def on_close(self, event):
|
||||
if self.detached_simulator_frame:
|
||||
self.detached_simulator_frame.Destroy()
|
||||
self.Destroy()
|
||||
|
||||
def go(self):
|
||||
self.simulator_panel.go()
|
||||
def toggle_detach_simulator(self):
|
||||
if self.detached_simulator_frame:
|
||||
self.attach_simulator()
|
||||
else:
|
||||
self.detach_simulator()
|
||||
|
||||
def stop(self):
|
||||
self.simulator_panel.stop()
|
||||
def attach_simulator(self):
|
||||
self.detached_simulator_frame.detach_simulator_panel()
|
||||
self.simulator_panel.Reparent(self.splitter)
|
||||
self.splitter.SplitVertically(self.settings_panel, self.simulator_panel)
|
||||
|
||||
def load(self, stitch_plan):
|
||||
self.simulator_panel.load(stitch_plan)
|
||||
self.GetStatusBar().SetStatusText(self.detached_simulator_frame.GetStatusBar().GetStatusText(1), 1)
|
||||
|
||||
def clear(self):
|
||||
self.simulator_panel.clear()
|
||||
self.detached_simulator_frame.Destroy()
|
||||
self.detached_simulator_frame = None
|
||||
self.Maximize()
|
||||
self.splitter.UpdateSize()
|
||||
self.SetFocus()
|
||||
self.Raise()
|
||||
wx.CallLater(100, self.set_sash_position)
|
||||
global_settings['pop_out_simulator'] = False
|
||||
|
||||
def detach_simulator(self):
|
||||
self.splitter.Unsplit()
|
||||
self.detached_simulator_frame = SimulatorWindow(panel=self.simulator_panel, parent=self)
|
||||
self.splitter.SetMinimumPaneSize(100)
|
||||
|
||||
current_screen = wx.Display.GetFromPoint(wx.GetMousePosition())
|
||||
display = wx.Display(current_screen)
|
||||
screen_rect = display.GetClientArea()
|
||||
settings_panel_size = self.settings_panel.GetSizer().CalcMin()
|
||||
self.SetMinSize(settings_panel_size)
|
||||
self.Maximize(False)
|
||||
self.SetSize((settings_panel_size.width, screen_rect.height))
|
||||
self.SetPosition((screen_rect.left, screen_rect.top))
|
||||
|
||||
self.detached_simulator_frame.SetSize((screen_rect.width - settings_panel_size.width, screen_rect.height))
|
||||
self.detached_simulator_frame.SetPosition((settings_panel_size.width, screen_rect.top))
|
||||
|
||||
self.detached_simulator_frame.GetStatusBar().SetStatusText(self.GetStatusBar().GetStatusText(1), 1)
|
||||
self.GetStatusBar().SetStatusText("", 1)
|
||||
|
||||
self.detached_simulator_frame.Show()
|
||||
|
||||
global_settings['pop_out_simulator'] = True
|
||||
|
||||
|
||||
class SimulatorPreview(Thread):
|
||||
"""Manages a preview simulation and a background thread for generating patches."""
|
||||
class PreviewRenderer(Thread):
|
||||
"""Render stitch plan in a background thread."""
|
||||
|
||||
def __init__(self, parent, *args, **kwargs):
|
||||
"""Construct a SimulatorPreview.
|
||||
|
||||
The parent is expected to be a wx.Window and also implement the following methods:
|
||||
|
||||
def generate_patches(self, abort_event):
|
||||
Produce an list of StitchGroup instances. This method will be
|
||||
invoked in a background thread and it is expected that it may
|
||||
take awhile.
|
||||
|
||||
If possible, this method should periodically check
|
||||
abort_event.is_set(), and if True, stop early. The return
|
||||
value will be ignored in this case.
|
||||
"""
|
||||
self.parent = parent
|
||||
self.target_duration = kwargs.pop('target_duration', 5)
|
||||
super(SimulatorPreview, self).__init__(*args, **kwargs)
|
||||
def __init__(self, render_stitch_plan_hook, rendering_completed_hook):
|
||||
super(PreviewRenderer, self).__init__()
|
||||
self.daemon = True
|
||||
|
||||
self.simulate_window = None
|
||||
self.refresh_needed = Event()
|
||||
|
||||
self.render_stitch_plan_hook = render_stitch_plan_hook
|
||||
self.rendering_completed_hook = rendering_completed_hook
|
||||
|
||||
# This is read by utils.threading.check_stop_flag() to abort stitch plan
|
||||
# generation.
|
||||
self.stop = Event()
|
||||
|
||||
# used when closing to avoid having the window reopen at the last second
|
||||
self._disabled = False
|
||||
|
||||
wx.CallLater(1000, self.update)
|
||||
|
||||
def disable(self):
|
||||
self._disabled = True
|
||||
|
||||
def update(self):
|
||||
"""Request an update of the simulator preview with freshly-generated patches."""
|
||||
"""Request to render a new stitch plan.
|
||||
|
||||
if self.simulate_window:
|
||||
self.simulate_window.stop()
|
||||
self.simulate_window.clear()
|
||||
|
||||
if self._disabled:
|
||||
return
|
||||
self.render_stitch_plan_hook() will be called in a background thread, and then
|
||||
self.rendering_completed_hook() will be called with the resulting stitch plan.
|
||||
"""
|
||||
|
||||
if not self.is_alive():
|
||||
self.start()
|
||||
|
@ -1167,80 +1225,22 @@ class SimulatorPreview(Thread):
|
|||
|
||||
try:
|
||||
debug.log("update_patches")
|
||||
self.update_patches()
|
||||
self.render_stitch_plan()
|
||||
except ExitThread:
|
||||
debug.log("ExitThread caught")
|
||||
self.stop.clear()
|
||||
|
||||
def update_patches(self):
|
||||
def render_stitch_plan(self):
|
||||
try:
|
||||
patches = self.parent.generate_patches(self.refresh_needed)
|
||||
stitch_plan = self.render_stitch_plan_hook()
|
||||
if stitch_plan:
|
||||
# rendering_completed() will be called in the main thread.
|
||||
wx.CallAfter(self.rendering_completed_hook, stitch_plan)
|
||||
except ExitThread:
|
||||
raise
|
||||
except: # noqa: E722
|
||||
# If something goes wrong when rendering patches, it's not great,
|
||||
# but we don't really want the simulator thread to crash. Instead,
|
||||
# just swallow the exception and abort. It'll show up when they
|
||||
# try to actually embroider the shape.
|
||||
return
|
||||
|
||||
if patches and not self.refresh_needed.is_set():
|
||||
metadata = self.parent.metadata
|
||||
collapse_len = metadata['collapse_len_mm']
|
||||
min_stitch_len = metadata['min_stitch_len_mm']
|
||||
stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
|
||||
# GUI stuff needs to happen in the main thread, so we ask the main
|
||||
# thread to call refresh_simulator().
|
||||
wx.CallAfter(self.refresh_simulator, patches, stitch_plan)
|
||||
|
||||
def refresh_simulator(self, patches, stitch_plan):
|
||||
if self.simulate_window:
|
||||
self.simulate_window.stop()
|
||||
self.simulate_window.load(stitch_plan)
|
||||
else:
|
||||
params_rect = self.parent.GetScreenRect()
|
||||
simulator_pos = params_rect.GetTopRight()
|
||||
simulator_pos.x += 5
|
||||
|
||||
current_screen = wx.Display.GetFromPoint(wx.GetMousePosition())
|
||||
display = wx.Display(current_screen)
|
||||
screen_rect = display.GetClientArea()
|
||||
simulator_pos.y = screen_rect.GetTop()
|
||||
|
||||
width = screen_rect.GetWidth() - params_rect.GetWidth()
|
||||
height = screen_rect.GetHeight()
|
||||
|
||||
try:
|
||||
self.simulate_window = EmbroiderySimulator(None, -1, _("Preview"),
|
||||
simulator_pos,
|
||||
size=(width, height),
|
||||
stitch_plan=stitch_plan,
|
||||
on_close=self.simulate_window_closed,
|
||||
target_duration=self.target_duration)
|
||||
except Exception:
|
||||
import traceback
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
try:
|
||||
# a window may have been created, so we need to destroy it
|
||||
# or the app will never exit
|
||||
wx.Window.FindWindowByName(_("Preview")).Destroy()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.simulate_window.Show()
|
||||
wx.CallLater(10, self.parent.Raise)
|
||||
|
||||
wx.CallAfter(self.simulate_window.go)
|
||||
|
||||
def simulate_window_closed(self):
|
||||
self.simulate_window = None
|
||||
|
||||
def close(self):
|
||||
self.disable()
|
||||
if self.simulate_window:
|
||||
self.simulate_window.stop()
|
||||
self.simulate_window.Close()
|
||||
import traceback
|
||||
debug.log("unhandled exception in PreviewRenderer.render_stitch_plan(): " + traceback.format_exc())
|
||||
|
||||
|
||||
def show_simulator(stitch_plan):
|
||||
|
@ -1255,7 +1255,7 @@ def show_simulator(stitch_plan):
|
|||
width = screen_rect[2] - 1
|
||||
height = screen_rect[3] - 1
|
||||
|
||||
frame = EmbroiderySimulator(None, -1, _("Embroidery Simulation"), pos=simulator_pos, size=(width, height), stitch_plan=stitch_plan)
|
||||
frame = SimulatorWindow(pos=simulator_pos, size=(width, height), stitch_plan=stitch_plan)
|
||||
app.SetTopWindow(frame)
|
||||
frame.Show()
|
||||
app.MainLoop()
|
||||
|
|
|
@ -20,7 +20,7 @@ class GenerateSwatchesFrame(wx.Frame):
|
|||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
wx.Frame.__init__(self, None, wx.ID_ANY, _("Generate Swatches"), *args, **kwargs)
|
||||
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT)
|
||||
self.SetWindowStyle(wx.FRAME_FLOAT_ON_PARENT | wx.DEFAULT_FRAME_STYLE)
|
||||
|
||||
self.panel = wx.Panel(self, wx.ID_ANY)
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ DEFAULT_METADATA = {
|
|||
}
|
||||
|
||||
DEFAULT_SETTINGS = {
|
||||
"cache_size": 100
|
||||
"cache_size": 100,
|
||||
"pop_out_simulator": False
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ _default_stop_flag = threading.Event()
|
|||
|
||||
|
||||
def check_stop_flag():
|
||||
# This getattr() actually looks at the PreviewRenderer instance's stop attribute.
|
||||
if getattr(threading.current_thread(), 'stop', _default_stop_flag).is_set():
|
||||
debug.log("exiting thread")
|
||||
raise ExitThread()
|
||||
|
|
Ładowanie…
Reference in New Issue