diff --git a/embroider_params.py b/embroider_params.py index 7d76c9d91..58feafcb1 100644 --- a/embroider_params.py +++ b/embroider_params.py @@ -5,6 +5,8 @@ import os import sys import json import traceback +import time +from threading import Thread from copy import copy from cStringIO import StringIO import wx @@ -16,6 +18,40 @@ from functools import partial from itertools import groupby from embroider_simulate import EmbroiderySimulator +class KillableThread(Thread): + """A subclass of threading.Thread, with a kill() method.""" + def __init__(self, *args, **keywords): + Thread.__init__(self, *args, **keywords) + self.killed = False + + def start(self): + """Start the thread.""" + self.__run_backup = self.run + self.run = self.__run # Force the Thread to install our trace. + Thread.start(self) + + def __run(self): + """Hacked run function, which installs the trace.""" + sys.settrace(self.globaltrace) + self.__run_backup() + self.run = self.__run_backup + + def globaltrace(self, frame, why, arg): + if why == 'call': + return self.localtrace + else: + return None + + def localtrace(self, frame, why, arg): + if self.killed: + if why == 'line': + raise SystemExit() + return self.localtrace + + def kill(self): + self.killed = True + + def presets_path(): try: import appdirs @@ -328,6 +364,8 @@ class SettingsFrame(wx.Frame): tab.on_change(self.params_changed) self.simulate_window = None + self.simulate_thread = None + self.thread_num = 0 self.presets_box = wx.StaticBox(self, wx.ID_ANY, label="Presets") @@ -360,11 +398,24 @@ class SettingsFrame(wx.Frame): # end wxGlade def params_changed(self, tab): + if self.simulate_window: + self.simulate_window.stop() + self.simulate_window.clear() + + if self.simulate_thread and self.simulate_thread.is_alive(): + self.simulate_thread.kill() + + self.simulate_thread = KillableThread(target=self.update_patches, name="Simulate%d" % self.thread_num) + self.simulate_thread.start() + self.thread_num += 1 + + def update_patches(self): patches = self.generate_patches() - if not patches: - return + if patches: + wx.CallAfter(self.update_simulator, patches) + def update_simulator(self, patches): if self.simulate_window: self.simulate_window.stop() self.simulate_window.load(patches=patches) @@ -402,6 +453,8 @@ class SettingsFrame(wx.Frame): # for many params in embroider.py. patches.extend(copy(node).to_patches(None)) + except SystemExit: + raise except: # Ignore errors. This can be things like incorrect paths for # satins or division by zero caused by incorrect param values. diff --git a/embroider_simulate.py b/embroider_simulate.py index d80dbe6e7..6db203add 100644 --- a/embroider_simulate.py +++ b/embroider_simulate.py @@ -179,6 +179,8 @@ class EmbroiderySimulator(wx.Frame): def clear(self): self.dc.SetBackground(wx.Brush('white')) self.dc.Clear() + self.last_pos = None + self.Refresh() def on_size(self, e): # ensure that the whole canvas is visible