From bcd16c78b4ba772bfc6187b2452390a7a37d3329 Mon Sep 17 00:00:00 2001 From: Momo Date: Sun, 19 Aug 2018 20:39:37 +0200 Subject: simulator timeline 0.0.1 --- lib/simulator.py | 190 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 112 insertions(+), 78 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 5620f65b..f937e614 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -3,6 +3,7 @@ import numpy import wx import colorsys from itertools import izip +from itertools import cycle from .svg import PIXELS_PER_MM, color_block_to_point_lists @@ -23,22 +24,31 @@ class EmbroiderySimulator(wx.Frame): self.max_height = kwargs.pop('max_height', screen_rect[3]) self.scale = 1 - self.min_width = 600 + self.min_width = 800 if self.max_width < self.min_width: self.max_width = self.min_width + self.load(stitch_plan) + wx.Frame.__init__(self, *args, **kwargs) + self.SetBackgroundColour('white') + self.panel = wx.Panel(self, wx.ID_ANY) + self.panel.SetBackgroundStyle(wx.BG_STYLE_PAINT) - self.panel.SetDoubleBuffered(True) + self.stitch_slider = wx.Slider(self, value=1, minValue=1, maxValue=len(self.lines), + style = wx.SL_HORIZONTAL|wx.SL_LABELS) - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.button_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.slider_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.slider_sizer.Add(self.stitch_slider, 1, wx.EXPAND) + self.button_sizer = wx.StdDialogButtonSizer() self.button_label = ( [_("Speed up"), _('Press + or arrow up to speed up'), self.animation_speed_up], [_("Slow down"), _('Press - or arrow down to slow down'), self.animation_slow_down], + [_("Backwards"), _('Backwards'), self.animation_backwards], + [_("Forwards"), _('Forwards'), self.animation_forwards], [_("Pause"), _("Press P to pause the animation"), self.animation_pause], [_("Restart"), _("Press R to restart the animation"), self.animation_restart], [_("Quit"), _("Press Q to close the simulation window"), self.animation_quit]) @@ -49,23 +59,26 @@ class EmbroiderySimulator(wx.Frame): self.buttons[i].SetToolTip(self.button_label[i][1]) self.buttons[i].Bind(wx.EVT_BUTTON, self.button_label[i][2]) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.panel, 1, wx.EXPAND) + self.sizer.Add(self.slider_sizer, 0, wx.EXPAND) self.sizer.Add(self.button_sizer, 0, wx.EXPAND) self.SetSizer(self.sizer) - self.load(stitch_plan) - if self.target_duration: self.adjust_speed(self.target_duration) self.buffer = wx.Bitmap(self.width * self.scale + self.margin * 2, self.height * self.scale + self.margin * 2) - self.dc = wx.MemoryDC() + self.dc = wx.BufferedDC() self.dc.SelectObject(self.buffer) self.canvas = wx.GraphicsContext.Create(self.dc) self.clear() - self.set_stitch_counter(1) + self.current_frame = 1 + self.set_stitch_counter(0) + self.animation_direction = 1 shortcut_keys = [ (wx.ACCEL_NORMAL, ord('+'), self.animation_speed_up), @@ -81,6 +94,10 @@ class EmbroiderySimulator(wx.Frame): (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, self.animation_slow_down), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DOWN, self.animation_slow_down), (wx.ACCEL_NORMAL, wx.WXK_DOWN, self.animation_slow_down), + (wx.ACCEL_NORMAL, wx.WXK_RIGHT, self.animation_forwards), + (wx.ACCEL_NORMAL, wx.WXK_LEFT, self.animation_backwards), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_RIGHT, self.animation_forwards), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_LEFT, self.animation_backwards), (wx.ACCEL_NORMAL, ord('r'), self.animation_restart), (wx.ACCEL_NORMAL, ord('p'), self.animation_pause), (wx.ACCEL_NORMAL, ord('q'), self.animation_quit)] @@ -97,6 +114,7 @@ class EmbroiderySimulator(wx.Frame): self.Bind(wx.EVT_SIZE, self.on_size) self.Bind(wx.EVT_CLOSE, self.on_close) + self.Bind(wx.EVT_SLIDER, self.on_slider) self.panel.Bind(wx.EVT_PAINT, self.on_paint) self.panel.SetFocus() @@ -114,15 +132,13 @@ class EmbroiderySimulator(wx.Frame): def load(self, stitch_plan=None): if stitch_plan: self.mirror = False - self.segments = self._stitch_plan_to_segments(stitch_plan) - else: + self.stitch_plan_to_lines(stitch_plan) + self.move_to_top_left() + self.calculate_dimensions() return - self.trim_margins() - self.calculate_dimensions() - def adjust_speed(self, duration): - self.frame_period = 1000 * float(duration) / len(self.segments) + self.frame_period = 1000 * float(duration) / len(self.lines) self.stitches_per_frame = 1 while self.frame_period < 1.0: @@ -144,6 +160,7 @@ class EmbroiderySimulator(wx.Frame): self.animation_update_timer() def animation_restart(self, event): + self.current_frame = 1 self.stop() self.clear() self.go() @@ -160,20 +177,41 @@ class EmbroiderySimulator(wx.Frame): def animation_update_timer(self): self.frame_period = max(1, self.frame_period) self.stitches_per_frame = max(self.stitches_per_frame, 1) + self.set_stitch_counter(self.current_frame) if self.timer.IsRunning(): self.timer.Stop() self.timer.Start(self.frame_period) - def set_stitch_counter(self, current_stitch): + def animation_backwards(self, event): + self.animation_direction = -1 + if self.current_frame > 0: + self.timer.Start(self.frame_period) + + def animation_forwards(self, event): + self.animation_direction = 1 + if self.current_frame <= len(self.lines): + self.timer.Start(self.frame_period) + + def set_stitch_counter(self, current_frame): if hasattr(self.panel, 'stitch_counter'): - self.panel.stitch_counter.SetLabel(_("Stitch # ") + str(current_stitch) + ' / ' + str(len(self.segments) + 1)) + self.panel.stitch_counter.SetLabel(_("Stitch # ") + str(current_frame) + ' / ' + str(len(self.lines))) else: self.font = wx.Font(9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) - self.panel.stitch_counter = wx.StaticText(self, label=_("Stitch #") + '1 / ' + str(len(self.segments)), pos=(30, 10)) + self.panel.stitch_counter = wx.StaticText(self, label=_("Stitch #") + '1 / ' + str(len(self.lines)), pos=(30, 10)) self.panel.stitch_counter.SetFont(self.font) self.panel.stitch_counter.SetForegroundColour('red') self.panel.stitch_counter.SetBackgroundColour('white') + def on_slider(self, event): + self.panel.SetFocus() + self.draw_one_frame() + obj = event.GetEventObject() + self.current_frame = obj.GetValue() + self.animation_update_timer() + + def set_stitch_slider(self, val): + self.stitch_slider.SetValue(val) + def _strip_quotes(self, string): if string.startswith('"') and string.endswith('"'): string = string[1:-1] @@ -183,55 +221,46 @@ class EmbroiderySimulator(wx.Frame): def color_to_pen(self, color): return wx.Pen(color.visible_on_white.rgb) - def _stitch_plan_to_segments(self, stitch_plan): - segments = [] + def stitch_plan_to_lines(self, stitch_plan): + self.pens = [] + self.lines = [] for color_block in stitch_plan: pen = self.color_to_pen(color_block.color) - for point_list in color_block_to_point_lists(color_block): + for i, point_list in enumerate(color_block_to_point_lists(color_block)): + if i == 0: + # add the first stitch + first_x, first_y = point_list[0] + self.lines.append((first_x, first_y, first_x, first_y)) + self.pens.append(pen) + # if there's only one point, there's nothing to do, so skip if len(point_list) < 2: continue for start, end in izip(point_list[:-1], point_list[1:]): - segments.append(((start, end), pen)) - - return segments + line = (start[0], start[1], end[0], end[1]) + self.lines.append(line) + self.pens.append(pen) - def all_coordinates(self): - for segment in self.segments: - start, end = segment[0] - - yield start - yield end - - def trim_margins(self): + def move_to_top_left(self): """remove any unnecessary whitespace around the design""" min_x = sys.maxint min_y = sys.maxint - for x, y in self.all_coordinates(): - min_x = min(min_x, x) - min_y = min(min_y, y) - - new_segments = [] - - for segment in self.segments: - (start, end), color = segment + for x1, y1, x2, y2 in self.lines: + min_x = min(min_x, x2) + min_y = min(min_y, y2) - new_segment = ( - ( - (start[0] - min_x, start[1] - min_y), - (end[0] - min_x, end[1] - min_y), - ), - color - ) + new_lines = [] - new_segments.append(new_segment) + for line in self.lines: + (start, end, start1, end1) = line + new_lines.append((start - min_x, end - min_y, start1 - min_x, end1 - min_y)) - self.segments = new_segments + self.lines = new_lines def calculate_dimensions(self): # 0.01 avoids a division by zero below for designs with no width or @@ -239,24 +268,34 @@ class EmbroiderySimulator(wx.Frame): width = 0.01 height = 0.01 - for x, y in self.all_coordinates(): - width = max(width, x) - height = max(height, y) + for x1, y1, x2, y2 in self.lines: + width = max(width, x2) + height = max(height, y2) self.width = width self.height = height - self.scale = min(float(self.max_width - self.margin * 2) / width, float(self.max_height - self.margin * 2 - 40) / height) + + self.scale = min(float(self.max_width - self.margin * 2) / width, float(self.max_height - self.margin * 2 - 90) / height) # make room for decorations and the margin self.scale *= 0.95 + for i, point in enumerate(self.lines): + x1, x2, y1, y2 = point + x1 = x1 * self.scale + self.margin + y1 = y1 * self.scale + self.margin + x2 = x2 * self.scale + self.margin + y2 = y2 * self.scale + self.margin + + self.lines[i] = (x1, x2, y1, y2) + def go(self): self.clear() - self.current_stitch = 0 + self.current_frame = 1 if not self.timer: - self.timer = wx.PyTimer(self.draw_one_frame) + self.timer = wx.PyTimer(self.iterate_frames) self.timer.Start(self.frame_period) @@ -287,7 +326,7 @@ class EmbroiderySimulator(wx.Frame): client_width, client_height = self.GetClientSize() decorations_width = window_width - client_width - decorations_height = window_height - client_height + 40 + decorations_height = window_height - client_height + 90 setsize_window_width = self.width * self.scale + decorations_width + self.margin * 2 setsize_window_height = (self.height) * self.scale + decorations_height + self.margin * 2 @@ -309,35 +348,30 @@ class EmbroiderySimulator(wx.Frame): e.Skip() def on_paint(self, e): - dc = wx.PaintDC(self.panel) + dc = wx.AutoBufferedPaintDC(self.panel) dc.Blit(0, 0, self.buffer.GetWidth(), self.buffer.GetHeight(), self.dc, 0, 0) - if self.last_pos: - dc.DrawLine(self.last_pos[0] - 10, self.last_pos[1], self.last_pos[0] + 10, self.last_pos[1]) - dc.DrawLine(self.last_pos[0], self.last_pos[1] - 10, self.last_pos[0], self.last_pos[1] + 10) + self.last_pos_x, self.last_pos_y, self.last_pos_x1, self.last_pos_y1 = self.lines[0] - def draw_one_frame(self): - for i in xrange(self.stitches_per_frame): - try: - ((x1, y1), (x2, y2)), color = self.segments[self.current_stitch] + if hasattr(self, 'visible_lines'): + if len(self.visible_lines) > 0: + self.last_pos_x1, self.last_pos_y1, self.last_pos_x, self.last_pos_y = self.visible_lines[-1] - if self.mirror: - y1 = self.height - y1 - y2 = self.height - y2 + dc.DrawLine(self.last_pos_x - 10, self.last_pos_y, self.last_pos_x + 10, self.last_pos_y) + dc.DrawLine(self.last_pos_x, self.last_pos_y - 10, self.last_pos_x, self.last_pos_y + 10) - x1 = x1 * self.scale + self.margin - y1 = y1 * self.scale + self.margin - x2 = x2 * self.scale + self.margin - y2 = y2 * self.scale + self.margin + def iterate_frames(self): + self.current_frame += 1 * self.animation_direction + self.set_stitch_counter(self.current_frame) + self.set_stitch_slider(self.current_frame) - self.canvas.SetPen(color) - self.canvas.DrawLines(((x1, y1), (x2, y2))) - self.Refresh() + self.draw_one_frame() - self.current_stitch += 1 - self.last_pos = (x2, y2) + if self.current_frame >= len(self.lines) or self.current_frame <= 1: + self.timer.Stop() - self.set_stitch_counter(self.current_stitch + 1) + def draw_one_frame(self): + self.clear() + self.visible_lines = self.lines[:self.current_frame] + self.dc.DrawLineList(self.visible_lines, self.pens[:self.current_frame]) - except IndexError: - self.timer.Stop() -- cgit v1.2.3 From a1440903cb91f3effd7cd23a395dbe3f8f9bed00 Mon Sep 17 00:00:00 2001 From: Momo Date: Mon, 20 Aug 2018 18:28:52 +0200 Subject: update slider maxValue when params have changed --- lib/extensions/params.py | 7 ++++++- lib/simulator.py | 12 +++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/extensions/params.py b/lib/extensions/params.py index c464e044..ce06cf2c 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -287,7 +287,6 @@ class ParamsTab(ScrolledPanel): summary_box = wx.StaticBox(self, wx.ID_ANY, label=_("Inkscape objects")) sizer = wx.StaticBoxSizer(summary_box, wx.HORIZONTAL) -# sizer = wx.BoxSizer(wx.HORIZONTAL) self.description = wx.StaticText(self) self.update_description() self.description.SetLabel(self.description_text) @@ -423,6 +422,12 @@ class SettingsFrame(wx.Frame): if self.simulate_window: self.simulate_window.stop() self.simulate_window.load(stitch_plan=stitch_plan) + + children = self.simulate_window.GetChildren() + for child in children: + if isinstance(child, wx.Slider): + child.Destroy() + self.simulate_window.set_slider() else: params_rect = self.GetScreenRect() simulator_pos = params_rect.GetTopRight() diff --git a/lib/simulator.py b/lib/simulator.py index f937e614..67a261c6 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -37,11 +37,8 @@ class EmbroiderySimulator(wx.Frame): self.panel = wx.Panel(self, wx.ID_ANY) self.panel.SetBackgroundStyle(wx.BG_STYLE_PAINT) - self.stitch_slider = wx.Slider(self, value=1, minValue=1, maxValue=len(self.lines), - style = wx.SL_HORIZONTAL|wx.SL_LABELS) - self.slider_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.slider_sizer.Add(self.stitch_slider, 1, wx.EXPAND) + self.set_slider() self.button_sizer = wx.StdDialogButtonSizer() self.button_label = ( @@ -123,6 +120,11 @@ class EmbroiderySimulator(wx.Frame): self.last_pos = None + def set_slider(self): + self.stitch_slider = wx.Slider(self, value=1, minValue=1, maxValue=len(self.lines), + style = wx.SL_HORIZONTAL|wx.SL_LABELS) + self.slider_sizer.Add(self.stitch_slider, 1, wx.EXPAND) + def get_current_screen_rect(self): current_screen = wx.Display.GetFromPoint(wx.GetMousePosition()) display = wx.Display(current_screen) @@ -361,7 +363,7 @@ class EmbroiderySimulator(wx.Frame): dc.DrawLine(self.last_pos_x, self.last_pos_y - 10, self.last_pos_x, self.last_pos_y + 10) def iterate_frames(self): - self.current_frame += 1 * self.animation_direction + self.current_frame += self.stitches_per_frame * self.animation_direction self.set_stitch_counter(self.current_frame) self.set_stitch_slider(self.current_frame) -- cgit v1.2.3 From 6defc29587c763b1ee3cd4d0adb96e1c76bd13f4 Mon Sep 17 00:00:00 2001 From: Momo Date: Tue, 21 Aug 2018 19:21:53 +0200 Subject: StartOnce and unicode control symbols --- lib/simulator.py | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 67a261c6..ad8ead8d 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -24,7 +24,7 @@ class EmbroiderySimulator(wx.Frame): self.max_height = kwargs.pop('max_height', screen_rect[3]) self.scale = 1 - self.min_width = 800 + self.min_width = 600 if self.max_width < self.min_width: self.max_width = self.min_width @@ -42,13 +42,14 @@ class EmbroiderySimulator(wx.Frame): self.button_sizer = wx.StdDialogButtonSizer() self.button_label = ( - [_("Speed up"), _('Press + or arrow up to speed up'), self.animation_speed_up], - [_("Slow down"), _('Press - or arrow down to slow down'), self.animation_slow_down], - [_("Backwards"), _('Backwards'), self.animation_backwards], - [_("Forwards"), _('Forwards'), self.animation_forwards], - [_("Pause"), _("Press P to pause the animation"), self.animation_pause], - [_("Restart"), _("Press R to restart the animation"), self.animation_restart], - [_("Quit"), _("Press Q to close the simulation window"), self.animation_quit]) + [u"\u2BC7", _('Play backwards (arrow left)'), self.animation_backwards], + [u"\u2BC8", _('Play forwards (arrow right)'), self.animation_forwards], + [u"\u2BC5", _('Speed up (arrow up)'), self.animation_speed_up], + [u"\u2BC6", _('Slow down (arrow down)'), self.animation_slow_down], + [u"\u23F8", _("Pause (P)"), self.animation_pause], + [u"\u2B8C", _("Restart (R)"), self.animation_restart], + [u"\u2BBF", _("Close (Q)"), self.animation_quit]) + self.buttons = [] for i in range(0, len(self.button_label)): self.buttons.append(wx.Button(self, -1, self.button_label[i][0])) @@ -73,7 +74,7 @@ class EmbroiderySimulator(wx.Frame): self.clear() - self.current_frame = 1 + self.current_frame = 0 self.set_stitch_counter(0) self.animation_direction = 1 @@ -171,7 +172,7 @@ class EmbroiderySimulator(wx.Frame): if self.timer.IsRunning(): self.timer.Stop() else: - self.timer.Start(self.frame_period) + self.timer.StartOnce(self.frame_period) def animation_quit(self, event): self.Close() @@ -182,17 +183,17 @@ class EmbroiderySimulator(wx.Frame): self.set_stitch_counter(self.current_frame) if self.timer.IsRunning(): self.timer.Stop() - self.timer.Start(self.frame_period) + self.timer.StartOnce(self.frame_period) def animation_backwards(self, event): self.animation_direction = -1 - if self.current_frame > 0: - self.timer.Start(self.frame_period) + if self.current_frame > 1: + self.timer.StartOnce(self.frame_period) def animation_forwards(self, event): self.animation_direction = 1 - if self.current_frame <= len(self.lines): - self.timer.Start(self.frame_period) + if self.current_frame < len(self.lines): + self.timer.StartOnce(self.frame_period) def set_stitch_counter(self, current_frame): if hasattr(self.panel, 'stitch_counter'): @@ -294,12 +295,12 @@ class EmbroiderySimulator(wx.Frame): def go(self): self.clear() - self.current_frame = 1 + self.current_frame = 0 if not self.timer: self.timer = wx.PyTimer(self.iterate_frames) - self.timer.Start(self.frame_period) + self.timer.StartOnce(self.frame_period) def on_close(self, event): self.stop() @@ -364,14 +365,22 @@ class EmbroiderySimulator(wx.Frame): def iterate_frames(self): self.current_frame += self.stitches_per_frame * self.animation_direction - self.set_stitch_counter(self.current_frame) - self.set_stitch_slider(self.current_frame) - self.draw_one_frame() - - if self.current_frame >= len(self.lines) or self.current_frame <= 1: + if self.current_frame <= len(self.lines) and self.current_frame >= 1: + self.draw_one_frame() + self.timer.StartOnce(self.frame_period) + elif self.current_frame > len(self.lines): + self.current_frame = len(self.lines) + self.draw_one_frame() + elif self.current_frame < 1: + self.current_frame = 1 + self.draw_one_frame() + else: self.timer.Stop() + self.set_stitch_counter(self.current_frame) + self.set_stitch_slider(self.current_frame) + def draw_one_frame(self): self.clear() self.visible_lines = self.lines[:self.current_frame] -- cgit v1.2.3 From 505388a9c1f16f351e353061e0588543fd96c824 Mon Sep 17 00:00:00 2001 From: Momo Date: Wed, 22 Aug 2018 19:24:53 +0200 Subject: fix jumping timeline and remove symbols --- lib/extensions/params.py | 3 +++ lib/simulator.py | 57 ++++++++++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 24 deletions(-) (limited to 'lib') diff --git a/lib/extensions/params.py b/lib/extensions/params.py index ce06cf2c..4b21d1dc 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -428,6 +428,9 @@ class SettingsFrame(wx.Frame): if isinstance(child, wx.Slider): child.Destroy() self.simulate_window.set_slider() + + self.simulate_window.Layout() + self.simulate_window.Refresh() else: params_rect = self.GetScreenRect() simulator_pos = params_rect.GetTopRight() diff --git a/lib/simulator.py b/lib/simulator.py index ad8ead8d..d7059b53 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -1,9 +1,9 @@ import sys import numpy import wx +import time import colorsys from itertools import izip -from itertools import cycle from .svg import PIXELS_PER_MM, color_block_to_point_lists @@ -24,7 +24,7 @@ class EmbroiderySimulator(wx.Frame): self.max_height = kwargs.pop('max_height', screen_rect[3]) self.scale = 1 - self.min_width = 600 + self.min_width = 800 if self.max_width < self.min_width: self.max_width = self.min_width @@ -32,23 +32,23 @@ class EmbroiderySimulator(wx.Frame): wx.Frame.__init__(self, *args, **kwargs) - self.SetBackgroundColour('white') - self.panel = wx.Panel(self, wx.ID_ANY) self.panel.SetBackgroundStyle(wx.BG_STYLE_PAINT) + self.SetBackgroundColour('white') + self.slider_sizer = wx.BoxSizer(wx.HORIZONTAL) self.set_slider() self.button_sizer = wx.StdDialogButtonSizer() self.button_label = ( - [u"\u2BC7", _('Play backwards (arrow left)'), self.animation_backwards], - [u"\u2BC8", _('Play forwards (arrow right)'), self.animation_forwards], - [u"\u2BC5", _('Speed up (arrow up)'), self.animation_speed_up], - [u"\u2BC6", _('Slow down (arrow down)'), self.animation_slow_down], - [u"\u23F8", _("Pause (P)"), self.animation_pause], - [u"\u2B8C", _("Restart (R)"), self.animation_restart], - [u"\u2BBF", _("Close (Q)"), self.animation_quit]) + [_("Reverse"), _('Play reverse (arrow left)'), self.animation_backwards], + [_("Forward"), _('Play forward (arrow right)'), self.animation_forwards], + [_("Speed up"), _('Speed up (+ or arrow up)'), self.animation_speed_up], + [_("Slow down"), _('Slow down (- or arrow down)'), self.animation_slow_down], + [_("Pause"), _("Pause (P)"), self.animation_pause], + [_("Restart"), _("Restart (R)"), self.animation_restart], + [_("Quit"), _("Close (Q)"), self.animation_quit]) self.buttons = [] for i in range(0, len(self.button_label)): @@ -64,6 +64,8 @@ class EmbroiderySimulator(wx.Frame): self.sizer.Add(self.button_sizer, 0, wx.EXPAND) self.SetSizer(self.sizer) + self.calculate_dimensions() + if self.target_duration: self.adjust_speed(self.target_duration) @@ -137,7 +139,6 @@ class EmbroiderySimulator(wx.Frame): self.mirror = False self.stitch_plan_to_lines(stitch_plan) self.move_to_top_left() - self.calculate_dimensions() return def adjust_speed(self, duration): @@ -196,14 +197,8 @@ class EmbroiderySimulator(wx.Frame): self.timer.StartOnce(self.frame_period) def set_stitch_counter(self, current_frame): - if hasattr(self.panel, 'stitch_counter'): - self.panel.stitch_counter.SetLabel(_("Stitch # ") + str(current_frame) + ' / ' + str(len(self.lines))) - else: - self.font = wx.Font(9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) - self.panel.stitch_counter = wx.StaticText(self, label=_("Stitch #") + '1 / ' + str(len(self.lines)), pos=(30, 10)) - self.panel.stitch_counter.SetFont(self.font) - self.panel.stitch_counter.SetForegroundColour('red') - self.panel.stitch_counter.SetBackgroundColour('white') + self.dc.SetTextForeground('red') + self.dc.DrawText(_("Stitch # ") + str(current_frame) + ' / ' + str(len(self.lines)), 30, 10) def on_slider(self, event): self.panel.SetFocus() @@ -278,7 +273,11 @@ class EmbroiderySimulator(wx.Frame): self.width = width self.height = height - self.scale = min(float(self.max_width - self.margin * 2) / width, float(self.max_height - self.margin * 2 - 90) / height) + button_width, button_height = self.buttons[0].GetSize() + slider_width, slider_height = self.stitch_slider.GetSize() + self.controls_height = button_height + slider_height + + self.scale = min(float(self.max_width - self.margin * 2) / width, float(self.max_height - self.margin * 2 - self.controls_height) / height) # make room for decorations and the margin self.scale *= 0.95 @@ -329,10 +328,10 @@ class EmbroiderySimulator(wx.Frame): client_width, client_height = self.GetClientSize() decorations_width = window_width - client_width - decorations_height = window_height - client_height + 90 + decorations_height = window_height - client_height + self.controls_height setsize_window_width = self.width * self.scale + decorations_width + self.margin * 2 - setsize_window_height = (self.height) * self.scale + decorations_height + self.margin * 2 + setsize_window_height = self.height * self.scale + decorations_height + self.margin * 2 # set minimum width (force space for control buttons) if setsize_window_width < self.min_width: @@ -342,7 +341,7 @@ class EmbroiderySimulator(wx.Frame): # center the simulation on screen if not called by params # else center vertically - if self.x_position == None: + if self.x_position is None: self.Centre() else: display_rect = self.get_current_screen_rect() @@ -386,3 +385,13 @@ class EmbroiderySimulator(wx.Frame): self.visible_lines = self.lines[:self.current_frame] self.dc.DrawLineList(self.visible_lines, self.pens[:self.current_frame]) + ''' + Calculate time_to_next_frame + start = time.time() + self.draw_one_frame() + duration = time.time() - start + duration_ms = int(duration * 1000) + time_to_next_frame = self.frame_period - duration_ms + time_to_next_frame = max(0.01, time_to_next_frame) + self.timer.StartOnce(time_to_next_frame) + ''' -- cgit v1.2.3 From 479cebb56dd704b256fe9e00c69752a9f08731dd Mon Sep 17 00:00:00 2001 From: Momo Date: Wed, 22 Aug 2018 20:01:38 +0200 Subject: fix bug on updating params --- lib/simulator.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index d7059b53..c3ddc55e 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -64,8 +64,6 @@ class EmbroiderySimulator(wx.Frame): self.sizer.Add(self.button_sizer, 0, wx.EXPAND) self.SetSizer(self.sizer) - self.calculate_dimensions() - if self.target_duration: self.adjust_speed(self.target_duration) @@ -139,6 +137,7 @@ class EmbroiderySimulator(wx.Frame): self.mirror = False self.stitch_plan_to_lines(stitch_plan) self.move_to_top_left() + self.calculate_dimensions() return def adjust_speed(self, duration): @@ -273,11 +272,7 @@ class EmbroiderySimulator(wx.Frame): self.width = width self.height = height - button_width, button_height = self.buttons[0].GetSize() - slider_width, slider_height = self.stitch_slider.GetSize() - self.controls_height = button_height + slider_height - - self.scale = min(float(self.max_width - self.margin * 2) / width, float(self.max_height - self.margin * 2 - self.controls_height) / height) + self.scale = min(float(self.max_width - self.margin * 2) / width, float(self.max_height - self.margin * 2) / height) # make room for decorations and the margin self.scale *= 0.95 @@ -328,7 +323,7 @@ class EmbroiderySimulator(wx.Frame): client_width, client_height = self.GetClientSize() decorations_width = window_width - client_width - decorations_height = window_height - client_height + self.controls_height + decorations_height = window_height - client_height setsize_window_width = self.width * self.scale + decorations_width + self.margin * 2 setsize_window_height = self.height * self.scale + decorations_height + self.margin * 2 -- cgit v1.2.3 From 56e153e87187a6bdad99faebc43253dfc40d4588 Mon Sep 17 00:00:00 2001 From: Momo Date: Thu, 23 Aug 2018 12:48:41 +0200 Subject: merge forward/backward/speed --- lib/extensions/params.py | 1 + lib/simulator.py | 135 ++++++++++++++++++++++++++++++----------------- 2 files changed, 88 insertions(+), 48 deletions(-) (limited to 'lib') diff --git a/lib/extensions/params.py b/lib/extensions/params.py index 4b21d1dc..a77c96f1 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -422,6 +422,7 @@ class SettingsFrame(wx.Frame): if self.simulate_window: self.simulate_window.stop() self.simulate_window.load(stitch_plan=stitch_plan) + self.simulate_window.calculate_dimensions() children = self.simulate_window.GetChildren() for child in children: diff --git a/lib/simulator.py b/lib/simulator.py index c3ddc55e..41302822 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -24,7 +24,7 @@ class EmbroiderySimulator(wx.Frame): self.max_height = kwargs.pop('max_height', screen_rect[3]) self.scale = 1 - self.min_width = 800 + self.min_width = 600 if self.max_width < self.min_width: self.max_width = self.min_width @@ -42,10 +42,10 @@ class EmbroiderySimulator(wx.Frame): self.button_sizer = wx.StdDialogButtonSizer() self.button_label = ( - [_("Reverse"), _('Play reverse (arrow left)'), self.animation_backwards], - [_("Forward"), _('Play forward (arrow right)'), self.animation_forwards], - [_("Speed up"), _('Speed up (+ or arrow up)'), self.animation_speed_up], - [_("Slow down"), _('Slow down (- or arrow down)'), self.animation_slow_down], + [_("<<"), _('Speed / Play reverse (arrow left)'), self.animation_reverse], + [_(">>"), _('Speed / Play forward (arrow right)'), self.animation_forward], + #[_("Speed up"), _('Speed up (+ or arrow up)'), self.animation_speed_up], + #[_("Slow down"), _('Slow down (- or arrow down)'), self.animation_slow_down], [_("Pause"), _("Pause (P)"), self.animation_pause], [_("Restart"), _("Restart (R)"), self.animation_restart], [_("Quit"), _("Close (Q)"), self.animation_quit]) @@ -64,6 +64,8 @@ class EmbroiderySimulator(wx.Frame): self.sizer.Add(self.button_sizer, 0, wx.EXPAND) self.SetSizer(self.sizer) + self.calculate_dimensions() + if self.target_duration: self.adjust_speed(self.target_duration) @@ -75,8 +77,9 @@ class EmbroiderySimulator(wx.Frame): self.clear() self.current_frame = 0 - self.set_stitch_counter(0) self.animation_direction = 1 + self.speed_info = self.calculate_speed_level() + self.set_stitch_counter(0) shortcut_keys = [ (wx.ACCEL_NORMAL, ord('+'), self.animation_speed_up), @@ -92,10 +95,10 @@ class EmbroiderySimulator(wx.Frame): (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, self.animation_slow_down), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DOWN, self.animation_slow_down), (wx.ACCEL_NORMAL, wx.WXK_DOWN, self.animation_slow_down), - (wx.ACCEL_NORMAL, wx.WXK_RIGHT, self.animation_forwards), - (wx.ACCEL_NORMAL, wx.WXK_LEFT, self.animation_backwards), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_RIGHT, self.animation_forwards), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_LEFT, self.animation_backwards), + (wx.ACCEL_NORMAL, wx.WXK_RIGHT, self.animation_forward), + (wx.ACCEL_NORMAL, wx.WXK_LEFT, self.animation_reverse), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_RIGHT, self.animation_forward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_LEFT, self.animation_reverse), (wx.ACCEL_NORMAL, ord('r'), self.animation_restart), (wx.ACCEL_NORMAL, ord('p'), self.animation_pause), (wx.ACCEL_NORMAL, ord('q'), self.animation_quit)] @@ -121,11 +124,6 @@ class EmbroiderySimulator(wx.Frame): self.last_pos = None - def set_slider(self): - self.stitch_slider = wx.Slider(self, value=1, minValue=1, maxValue=len(self.lines), - style = wx.SL_HORIZONTAL|wx.SL_LABELS) - self.slider_sizer.Add(self.stitch_slider, 1, wx.EXPAND) - def get_current_screen_rect(self): current_screen = wx.Display.GetFromPoint(wx.GetMousePosition()) display = wx.Display(current_screen) @@ -137,7 +135,6 @@ class EmbroiderySimulator(wx.Frame): self.mirror = False self.stitch_plan_to_lines(stitch_plan) self.move_to_top_left() - self.calculate_dimensions() return def adjust_speed(self, duration): @@ -148,18 +145,44 @@ class EmbroiderySimulator(wx.Frame): self.frame_period *= 2 self.stitches_per_frame *= 2 - def animation_speed_up(self, event): - if self.frame_period == 1: - self.stitches_per_frame *= 2 + def animation_forward(self, event): + if self.current_frame == 1: + self.animation_direction = 1 + self.timer.StartOnce(self.frame_period) + elif self.animation_direction == -1 and self.frame_period > 1280: + self.animation_direction = 1 + self.set_speed_info(self.calculate_speed_level()) + elif self.animation_direction == 1: + self.animation_speed_up('speed_up') else: - self.frame_period = self.frame_period / 2 + self.animation_slow_down('slow_down') + + def animation_reverse(self, event): + if self.current_frame == len(self.lines): + self.animation_direction = -1 + self.timer.StartOnce(self.frame_period) + elif self.animation_direction == 1 and self.frame_period > 1280: + self.animation_direction = -1 + self.set_speed_info(self.calculate_speed_level()) + elif self.animation_direction == -1: + self.animation_speed_up('speed_up') + else: + self.animation_slow_down('slow_down') + + def animation_speed_up(self, event): + if self.stitches_per_frame <= 2560: + if self.frame_period == 1: + self.stitches_per_frame *= 2 + else: + self.frame_period = self.frame_period / 2 self.animation_update_timer() def animation_slow_down(self, event): - if self.stitches_per_frame == 1: - self.frame_period *= 2 - else: - self.stitches_per_frame /= 2 + if self.frame_period <= 2560: + if self.stitches_per_frame == 1: + self.frame_period *= 2 + else: + self.stitches_per_frame /= 2 self.animation_update_timer() def animation_restart(self, event): @@ -180,24 +203,36 @@ class EmbroiderySimulator(wx.Frame): def animation_update_timer(self): self.frame_period = max(1, self.frame_period) self.stitches_per_frame = max(self.stitches_per_frame, 1) + self.speed_info = self.calculate_speed_level() self.set_stitch_counter(self.current_frame) if self.timer.IsRunning(): self.timer.Stop() self.timer.StartOnce(self.frame_period) - def animation_backwards(self, event): - self.animation_direction = -1 - if self.current_frame > 1: - self.timer.StartOnce(self.frame_period) - - def animation_forwards(self, event): - self.animation_direction = 1 - if self.current_frame < len(self.lines): - self.timer.StartOnce(self.frame_period) + def calculate_speed_level(self): + count = 0 + speed = self.frame_period + speed_plus = 1 + animation_direction = '>>' if self.animation_direction == 1 else '<<' + while speed <= 2560: + speed = speed * 2 + count += 1 + while speed_plus < self.stitches_per_frame: + speed_plus = speed_plus * 2 + count += 1 + return animation_direction + ' x' + str(count) def set_stitch_counter(self, current_frame): self.dc.SetTextForeground('red') - self.dc.DrawText(_("Stitch # ") + str(current_frame) + ' / ' + str(len(self.lines)), 30, 10) + stitch_counter_text = _("Stitch # ") + str(current_frame) + ' / ' + str(len(self.lines)) + self.dc.DrawText(stitch_counter_text, 30, 5) + self.set_speed_info(self.speed_info) + + def set_speed_info(self, speed_info): + self.speed_info = speed_info + #counter_width, counter_height= self.dc.GetTextExtent(speed_info) + self.dc.SetTextForeground('blue') + self.dc.DrawText(_("Speed ") + str(speed_info), 220, 5) def on_slider(self, event): self.panel.SetFocus() @@ -206,6 +241,11 @@ class EmbroiderySimulator(wx.Frame): self.current_frame = obj.GetValue() self.animation_update_timer() + def set_slider(self): + self.stitch_slider = wx.Slider(self, value=1, minValue=1, maxValue=len(self.lines), + style=wx.SL_HORIZONTAL | wx.SL_LABELS) + self.slider_sizer.Add(self.stitch_slider, 1, wx.EXPAND) + def set_stitch_slider(self, val): self.stitch_slider.SetValue(val) @@ -272,7 +312,11 @@ class EmbroiderySimulator(wx.Frame): self.width = width self.height = height - self.scale = min(float(self.max_width - self.margin * 2) / width, float(self.max_height - self.margin * 2) / height) + button_width, button_height = self.buttons[0].GetSize() + slider_width, slider_height = self.stitch_slider.GetSize() + self.controls_height = button_height + slider_height + + self.scale = min(float(self.max_width - self.margin * 2) / width, float(self.max_height - self.margin * 2 - self.controls_height) / height) # make room for decorations and the margin self.scale *= 0.95 @@ -326,7 +370,7 @@ class EmbroiderySimulator(wx.Frame): decorations_height = window_height - client_height setsize_window_width = self.width * self.scale + decorations_width + self.margin * 2 - setsize_window_height = self.height * self.scale + decorations_height + self.margin * 2 + setsize_window_height = self.height * self.scale + decorations_height + self.controls_height + self.margin * 2 # set minimum width (force space for control buttons) if setsize_window_width < self.min_width: @@ -361,8 +405,14 @@ class EmbroiderySimulator(wx.Frame): self.current_frame += self.stitches_per_frame * self.animation_direction if self.current_frame <= len(self.lines) and self.current_frame >= 1: + #Calculate time_to_next_frame + start = time.time() self.draw_one_frame() - self.timer.StartOnce(self.frame_period) + duration = time.time() - start + duration_ms = int(duration * 1000) + time_to_next_frame = self.frame_period - duration_ms + time_to_next_frame = max(1, time_to_next_frame) + self.timer.StartOnce(time_to_next_frame) elif self.current_frame > len(self.lines): self.current_frame = len(self.lines) self.draw_one_frame() @@ -379,14 +429,3 @@ class EmbroiderySimulator(wx.Frame): self.clear() self.visible_lines = self.lines[:self.current_frame] self.dc.DrawLineList(self.visible_lines, self.pens[:self.current_frame]) - - ''' - Calculate time_to_next_frame - start = time.time() - self.draw_one_frame() - duration = time.time() - start - duration_ms = int(duration * 1000) - time_to_next_frame = self.frame_period - duration_ms - time_to_next_frame = max(0.01, time_to_next_frame) - self.timer.StartOnce(time_to_next_frame) - ''' -- cgit v1.2.3 From 403a1c533dbd4987aeec45390b6b7a5f80c49f6c Mon Sep 17 00:00:00 2001 From: Momo Date: Thu, 23 Aug 2018 16:36:11 +0200 Subject: reset speed when starting simulation through arrow buttons --- lib/simulator.py | 112 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 41302822..10ee0569 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -1,11 +1,9 @@ import sys -import numpy import wx import time -import colorsys from itertools import izip -from .svg import PIXELS_PER_MM, color_block_to_point_lists +from .svg import color_block_to_point_lists class EmbroiderySimulator(wx.Frame): @@ -42,10 +40,12 @@ class EmbroiderySimulator(wx.Frame): self.button_sizer = wx.StdDialogButtonSizer() self.button_label = ( - [_("<<"), _('Speed / Play reverse (arrow left)'), self.animation_reverse], - [_(">>"), _('Speed / Play forward (arrow right)'), self.animation_forward], - #[_("Speed up"), _('Speed up (+ or arrow up)'), self.animation_speed_up], - #[_("Slow down"), _('Slow down (- or arrow down)'), self.animation_slow_down], + [_("<<"), + _('Speed | Play reverse (arrow left)'), + self.animation_reverse], + [_(">>"), + _('Speed | Play forward (arrow right)'), + self.animation_forward], [_("Pause"), _("Pause (P)"), self.animation_pause], [_("Restart"), _("Restart (R)"), self.animation_restart], [_("Quit"), _("Close (Q)"), self.animation_quit]) @@ -69,7 +69,9 @@ class EmbroiderySimulator(wx.Frame): if self.target_duration: self.adjust_speed(self.target_duration) - self.buffer = wx.Bitmap(self.width * self.scale + self.margin * 2, self.height * self.scale + self.margin * 2) + self.buffer = wx.Bitmap( + self.width * self.scale + self.margin * 2, + self.height * self.scale + self.margin * 2) self.dc = wx.BufferedDC() self.dc.SelectObject(self.buffer) self.canvas = wx.GraphicsContext.Create(self.dc) @@ -84,7 +86,7 @@ class EmbroiderySimulator(wx.Frame): shortcut_keys = [ (wx.ACCEL_NORMAL, ord('+'), self.animation_speed_up), (wx.ACCEL_NORMAL, ord('='), self.animation_speed_up), - (wx.ACCEL_SHIFT, ord('='), self.animation_speed_up), + (wx.ACCEL_SHIFT, ord('='), self.animation_speed_up), (wx.ACCEL_NORMAL, wx.WXK_ADD, self.animation_speed_up), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ADD, self.animation_speed_up), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_speed_up), @@ -137,6 +139,14 @@ class EmbroiderySimulator(wx.Frame): self.move_to_top_left() return + def reset_speed(self): + if self.target_duration: + self.adjust_speed(self, self.target_duration) + else: + self.stitches_per_frame = 1 + self.frame_period = 80 + self.set_speed_info(self.calculate_speed_level()) + def adjust_speed(self, duration): self.frame_period = 1000 * float(duration) / len(self.lines) self.stitches_per_frame = 1 @@ -148,6 +158,7 @@ class EmbroiderySimulator(wx.Frame): def animation_forward(self, event): if self.current_frame == 1: self.animation_direction = 1 + self.reset_speed() self.timer.StartOnce(self.frame_period) elif self.animation_direction == -1 and self.frame_period > 1280: self.animation_direction = 1 @@ -160,6 +171,7 @@ class EmbroiderySimulator(wx.Frame): def animation_reverse(self, event): if self.current_frame == len(self.lines): self.animation_direction = -1 + self.reset_speed() self.timer.StartOnce(self.frame_period) elif self.animation_direction == 1 and self.frame_period > 1280: self.animation_direction = -1 @@ -170,7 +182,7 @@ class EmbroiderySimulator(wx.Frame): self.animation_slow_down('slow_down') def animation_speed_up(self, event): - if self.stitches_per_frame <= 2560: + if self.stitches_per_frame <= 1280: if self.frame_period == 1: self.stitches_per_frame *= 2 else: @@ -178,7 +190,7 @@ class EmbroiderySimulator(wx.Frame): self.animation_update_timer() def animation_slow_down(self, event): - if self.frame_period <= 2560: + if self.frame_period <= 1280: if self.stitches_per_frame == 1: self.frame_period *= 2 else: @@ -224,15 +236,15 @@ class EmbroiderySimulator(wx.Frame): def set_stitch_counter(self, current_frame): self.dc.SetTextForeground('red') - stitch_counter_text = _("Stitch # ") + str(current_frame) + ' / ' + str(len(self.lines)) + stitch_counter_text = _("Stitch # ") + \ + str(current_frame) + ' / ' + str(len(self.lines)) self.dc.DrawText(stitch_counter_text, 30, 5) self.set_speed_info(self.speed_info) def set_speed_info(self, speed_info): self.speed_info = speed_info - #counter_width, counter_height= self.dc.GetTextExtent(speed_info) self.dc.SetTextForeground('blue') - self.dc.DrawText(_("Speed ") + str(speed_info), 220, 5) + self.dc.DrawText(_("Speed ") + str(speed_info), 210, 5) def on_slider(self, event): self.panel.SetFocus() @@ -242,8 +254,9 @@ class EmbroiderySimulator(wx.Frame): self.animation_update_timer() def set_slider(self): - self.stitch_slider = wx.Slider(self, value=1, minValue=1, maxValue=len(self.lines), - style=wx.SL_HORIZONTAL | wx.SL_LABELS) + self.stitch_slider = wx.Slider( + self, value=1, minValue=1, maxValue=len( + self.lines), style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.slider_sizer.Add(self.stitch_slider, 1, wx.EXPAND) def set_stitch_slider(self, val): @@ -265,7 +278,8 @@ class EmbroiderySimulator(wx.Frame): for color_block in stitch_plan: pen = self.color_to_pen(color_block.color) - for i, point_list in enumerate(color_block_to_point_lists(color_block)): + for i, point_list in enumerate( + color_block_to_point_lists(color_block)): if i == 0: # add the first stitch first_x, first_y = point_list[0] @@ -284,8 +298,8 @@ class EmbroiderySimulator(wx.Frame): def move_to_top_left(self): """remove any unnecessary whitespace around the design""" - min_x = sys.maxint - min_y = sys.maxint + min_x = sys.maxsize + min_y = sys.maxsize for x1, y1, x2, y2 in self.lines: min_x = min(min_x, x2) @@ -295,7 +309,11 @@ class EmbroiderySimulator(wx.Frame): for line in self.lines: (start, end, start1, end1) = line - new_lines.append((start - min_x, end - min_y, start1 - min_x, end1 - min_y)) + new_lines.append( + (start - min_x, + end - min_y, + start1 - min_x, + end1 - min_y)) self.lines = new_lines @@ -316,7 +334,18 @@ class EmbroiderySimulator(wx.Frame): slider_width, slider_height = self.stitch_slider.GetSize() self.controls_height = button_height + slider_height - self.scale = min(float(self.max_width - self.margin * 2) / width, float(self.max_height - self.margin * 2 - self.controls_height) / height) + self.scale = min( + float( + self.max_width - + self.margin * + 2) / + width, + float( + self.max_height - + self.margin * + 2 - + self.controls_height) / + height) # make room for decorations and the margin self.scale *= 0.95 @@ -369,14 +398,16 @@ class EmbroiderySimulator(wx.Frame): decorations_width = window_width - client_width decorations_height = window_height - client_height - setsize_window_width = self.width * self.scale + decorations_width + self.margin * 2 - setsize_window_height = self.height * self.scale + decorations_height + self.controls_height + self.margin * 2 + setsize_window_width = self.width * self.scale + \ + decorations_width + self.margin * 2 + setsize_window_height = self.height * self.scale + \ + decorations_height + self.controls_height + self.margin * 2 # set minimum width (force space for control buttons) if setsize_window_width < self.min_width: setsize_window_width = self.min_width - self.SetSize(( setsize_window_width, setsize_window_height)) + self.SetSize((setsize_window_width, setsize_window_height)) # center the simulation on screen if not called by params # else center vertically @@ -384,13 +415,25 @@ class EmbroiderySimulator(wx.Frame): self.Centre() else: display_rect = self.get_current_screen_rect() - self.SetPosition((self.x_position, display_rect[3] / 2 - setsize_window_height / 2)) + self.SetPosition( + (self.x_position, + display_rect[3] / + 2 - + setsize_window_height / + 2)) e.Skip() def on_paint(self, e): dc = wx.AutoBufferedPaintDC(self.panel) - dc.Blit(0, 0, self.buffer.GetWidth(), self.buffer.GetHeight(), self.dc, 0, 0) + dc.Blit( + 0, + 0, + self.buffer.GetWidth(), + self.buffer.GetHeight(), + self.dc, + 0, + 0) self.last_pos_x, self.last_pos_y, self.last_pos_x1, self.last_pos_y1 = self.lines[0] @@ -398,14 +441,22 @@ class EmbroiderySimulator(wx.Frame): if len(self.visible_lines) > 0: self.last_pos_x1, self.last_pos_y1, self.last_pos_x, self.last_pos_y = self.visible_lines[-1] - dc.DrawLine(self.last_pos_x - 10, self.last_pos_y, self.last_pos_x + 10, self.last_pos_y) - dc.DrawLine(self.last_pos_x, self.last_pos_y - 10, self.last_pos_x, self.last_pos_y + 10) + dc.DrawLine( + self.last_pos_x - 10, + self.last_pos_y, + self.last_pos_x + 10, + self.last_pos_y) + dc.DrawLine( + self.last_pos_x, + self.last_pos_y - 10, + self.last_pos_x, + self.last_pos_y + 10) def iterate_frames(self): self.current_frame += self.stitches_per_frame * self.animation_direction if self.current_frame <= len(self.lines) and self.current_frame >= 1: - #Calculate time_to_next_frame + # calculate time_to_next_frame start = time.time() self.draw_one_frame() duration = time.time() - start @@ -428,4 +479,5 @@ class EmbroiderySimulator(wx.Frame): def draw_one_frame(self): self.clear() self.visible_lines = self.lines[:self.current_frame] - self.dc.DrawLineList(self.visible_lines, self.pens[:self.current_frame]) + self.dc.DrawLineList(self.visible_lines, + self.pens[:self.current_frame]) -- cgit v1.2.3 From c5bd1878846c17309c99ad7554d4645088de9629 Mon Sep 17 00:00:00 2001 From: Momo Date: Sat, 25 Aug 2018 10:57:17 +0200 Subject: * seperated controls * one frame movements --- lib/extensions/params.py | 1 - lib/simulator.py | 130 +++++++++++++++++++++-------------------------- 2 files changed, 58 insertions(+), 73 deletions(-) (limited to 'lib') diff --git a/lib/extensions/params.py b/lib/extensions/params.py index a77c96f1..6d1464a3 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -431,7 +431,6 @@ class SettingsFrame(wx.Frame): self.simulate_window.set_slider() self.simulate_window.Layout() - self.simulate_window.Refresh() else: params_rect = self.GetScreenRect() simulator_pos = params_rect.GetTopRight() diff --git a/lib/simulator.py b/lib/simulator.py index 10ee0569..e662eaf9 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -40,15 +40,17 @@ class EmbroiderySimulator(wx.Frame): self.button_sizer = wx.StdDialogButtonSizer() self.button_label = ( - [_("<<"), - _('Speed | Play reverse (arrow left)'), - self.animation_reverse], - [_(">>"), - _('Speed | Play forward (arrow right)'), - self.animation_forward], - [_("Pause"), _("Pause (P)"), self.animation_pause], - [_("Restart"), _("Restart (R)"), self.animation_restart], - [_("Quit"), _("Close (Q)"), self.animation_quit]) + # Switch direction button (currently not in use - would this be better?) + #[_('>>'), _('Switch direction | Play reverse (arrow left) | Play forward (arrow right)'), self.animation_switch_direction], + [_('<<'), _('Play reverse (arrow left)'), self.animation_reverse], + [_('-'), _('Play one frame backward (+)'), self.animation_one_frame_back], + [_('+'), _('Play one frame forward (+)'), self.animation_one_frame_forward], + [_('>>'), _('Play forward (arrow right)'), self.animation_forward], + [_('^'), _('Speed up (arrow up)'), self.animation_speed_up], + [_('v'), _('Slow down (arrow down)'), self.animation_slow_down], + [_('Pause'), _('Pause (P)'), self.animation_pause], + [_('Restart'), _('Restart (R)'), self.animation_restart], + [_('Quit'), _('Close (Q)'), self.animation_quit]) self.buttons = [] for i in range(0, len(self.button_label)): @@ -80,29 +82,30 @@ class EmbroiderySimulator(wx.Frame): self.current_frame = 0 self.animation_direction = 1 - self.speed_info = self.calculate_speed_level() self.set_stitch_counter(0) shortcut_keys = [ - (wx.ACCEL_NORMAL, ord('+'), self.animation_speed_up), - (wx.ACCEL_NORMAL, ord('='), self.animation_speed_up), - (wx.ACCEL_SHIFT, ord('='), self.animation_speed_up), - (wx.ACCEL_NORMAL, wx.WXK_ADD, self.animation_speed_up), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ADD, self.animation_speed_up), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_speed_up), - (wx.ACCEL_NORMAL, wx.WXK_UP, self.animation_speed_up), - (wx.ACCEL_NORMAL, ord('-'), self.animation_slow_down), - (wx.ACCEL_NORMAL, ord('_'), self.animation_slow_down), - (wx.ACCEL_NORMAL, wx.WXK_SUBTRACT, self.animation_slow_down), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, self.animation_slow_down), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DOWN, self.animation_slow_down), - (wx.ACCEL_NORMAL, wx.WXK_DOWN, self.animation_slow_down), (wx.ACCEL_NORMAL, wx.WXK_RIGHT, self.animation_forward), - (wx.ACCEL_NORMAL, wx.WXK_LEFT, self.animation_reverse), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_RIGHT, self.animation_forward), + (wx.ACCEL_NORMAL, wx.WXK_LEFT, self.animation_reverse), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_LEFT, self.animation_reverse), + (wx.ACCEL_NORMAL, wx.WXK_UP, self.animation_speed_up), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_speed_up), + (wx.ACCEL_NORMAL, wx.WXK_DOWN, self.animation_slow_down), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DOWN, self.animation_slow_down), + (wx.ACCEL_NORMAL, ord('+'), self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, ord('='), self.animation_one_frame_forward), + (wx.ACCEL_SHIFT, ord('='), self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, wx.WXK_ADD, self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ADD, self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, ord('-'), self.animation_one_frame_back), + (wx.ACCEL_NORMAL, ord('_'), self.animation_one_frame_back), + (wx.ACCEL_NORMAL, wx.WXK_SUBTRACT, self.animation_one_frame_back), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, self.animation_one_frame_back), (wx.ACCEL_NORMAL, ord('r'), self.animation_restart), (wx.ACCEL_NORMAL, ord('p'), self.animation_pause), + (wx.ACCEL_NORMAL, wx.WXK_SPACE, self.animation_pause), (wx.ACCEL_NORMAL, ord('q'), self.animation_quit)] accel_entries = [] @@ -139,14 +142,6 @@ class EmbroiderySimulator(wx.Frame): self.move_to_top_left() return - def reset_speed(self): - if self.target_duration: - self.adjust_speed(self, self.target_duration) - else: - self.stitches_per_frame = 1 - self.frame_period = 80 - self.set_speed_info(self.calculate_speed_level()) - def adjust_speed(self, duration): self.frame_period = 1000 * float(duration) / len(self.lines) self.stitches_per_frame = 1 @@ -155,31 +150,42 @@ class EmbroiderySimulator(wx.Frame): self.frame_period *= 2 self.stitches_per_frame *= 2 + # Switch direction button (currently not in use - would this be better?) + def animation_switch_direction(self, event): + direction_button = event.GetEventObject() + lbl = direction_button.GetLabel() + if self.animation_direction == 1: + self.animation_reverse('backward') + direction_button.SetLabel('<<') + else: + self.animation_forward('forward') + direction_button.SetLabel('>>') + def animation_forward(self, event): - if self.current_frame == 1: - self.animation_direction = 1 - self.reset_speed() + self.animation_direction = 1 + if not self.timer.IsRunning(): self.timer.StartOnce(self.frame_period) - elif self.animation_direction == -1 and self.frame_period > 1280: - self.animation_direction = 1 - self.set_speed_info(self.calculate_speed_level()) - elif self.animation_direction == 1: - self.animation_speed_up('speed_up') - else: - self.animation_slow_down('slow_down') def animation_reverse(self, event): - if self.current_frame == len(self.lines): - self.animation_direction = -1 - self.reset_speed() + self.animation_direction = -1 + if not self.timer.IsRunning(): self.timer.StartOnce(self.frame_period) - elif self.animation_direction == 1 and self.frame_period > 1280: - self.animation_direction = -1 - self.set_speed_info(self.calculate_speed_level()) - elif self.animation_direction == -1: - self.animation_speed_up('speed_up') - else: - self.animation_slow_down('slow_down') + + def animation_one_frame_forward(self, event): + if self.current_frame < len(self.lines): + self.timer.Stop() + self.current_frame = self.current_frame + 1 + self.draw_one_frame() + self.set_stitch_counter(self.current_frame) + self.set_stitch_slider(self.current_frame) + + def animation_one_frame_back(self, event): + if self.current_frame > 1: + self.timer.Stop() + self.current_frame = self.current_frame - 1 + self.draw_one_frame() + self.set_stitch_counter(self.current_frame) + self.set_stitch_slider(self.current_frame) def animation_speed_up(self, event): if self.stitches_per_frame <= 1280: @@ -215,36 +221,16 @@ class EmbroiderySimulator(wx.Frame): def animation_update_timer(self): self.frame_period = max(1, self.frame_period) self.stitches_per_frame = max(self.stitches_per_frame, 1) - self.speed_info = self.calculate_speed_level() self.set_stitch_counter(self.current_frame) if self.timer.IsRunning(): self.timer.Stop() self.timer.StartOnce(self.frame_period) - def calculate_speed_level(self): - count = 0 - speed = self.frame_period - speed_plus = 1 - animation_direction = '>>' if self.animation_direction == 1 else '<<' - while speed <= 2560: - speed = speed * 2 - count += 1 - while speed_plus < self.stitches_per_frame: - speed_plus = speed_plus * 2 - count += 1 - return animation_direction + ' x' + str(count) - def set_stitch_counter(self, current_frame): self.dc.SetTextForeground('red') stitch_counter_text = _("Stitch # ") + \ str(current_frame) + ' / ' + str(len(self.lines)) self.dc.DrawText(stitch_counter_text, 30, 5) - self.set_speed_info(self.speed_info) - - def set_speed_info(self, speed_info): - self.speed_info = speed_info - self.dc.SetTextForeground('blue') - self.dc.DrawText(_("Speed ") + str(speed_info), 210, 5) def on_slider(self, event): self.panel.SetFocus() -- cgit v1.2.3 From bf70fd9031e837f7f0aab60208ab21702b41f90b Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sat, 25 Aug 2018 21:54:11 -0400 Subject: WIP: revamp UI and rendering algorithm --- lib/simulator.py | 308 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 530f6ebf..be87fe1e 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -6,7 +6,315 @@ from itertools import izip from .svg import color_block_to_point_lists from .i18n import _ +class ControlPanel(wx.Panel): + """""" + def __init__(self, parent, *args, **kwargs): + """""" + self.parent = parent + self.drawing_panel = kwargs.pop('drawing_panel') + self.stitch_plan = kwargs.pop('stitch_plan') + kwargs['style'] = wx.BORDER_SUNKEN + wx.Panel.__init__(self, parent, *args, **kwargs) + + # Widgets + self.btnMinus = wx.Button(self, -1, label='-') + self.btnMinus.Bind(wx.EVT_BUTTON, self.OnSpeedMinus) + self.btnPlus = wx.Button(self, -1, label='+') + self.btnPlus.Bind(wx.EVT_BUTTON, self.OnSpeedPlus) + self.direction = wx.Button(self, -1, label='>>') + self.direction.Bind(wx.EVT_BUTTON, self.OnDirection) + self.pauseBtn = wx.Button(self, -1, label='Pause') + self.pauseBtn.Bind(wx.EVT_BUTTON, self.OnPauseStart) + self.restartBtn = wx.Button(self, -1, label='Restart') + self.quitBtn = wx.Button(self, -1, label='Quit') + self.quitBtn.Bind(wx.EVT_BUTTON, self.on_quit) + self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=1000, + style=wx.SL_HORIZONTAL | wx.SL_LABELS) + self.st1 = wx.StaticText(self, -1, label='Stitch # 1234/56789', style=wx.ALIGN_CENTER) + self.st1.SetForegroundColour('#FF0000') + self.speedST = wx.StaticText(self, -1, label='', style=wx.ALIGN_CENTER) + self.speedST.SetForegroundColour('#0000FF') + + # Layout + self.vbSizer = vbSizer = wx.BoxSizer(wx.VERTICAL) + self.hbSizer = hbSizer = wx.BoxSizer(wx.HORIZONTAL) + vbSizer.Add(self.slider, 1, wx.EXPAND | wx.ALL, 3) + hbSizer.Add(self.st1, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 2) + hbSizer.AddStretchSpacer(prop=1) + hbSizer.Add(self.speedST, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 2) + hbSizer.Add(self.btnMinus, 0, wx.ALL, 2) + hbSizer.Add(self.btnPlus, 0, wx.ALL, 2) + hbSizer.Add(self.direction, 0, wx.EXPAND | wx.ALL, 2) + hbSizer.Add(self.pauseBtn, 0, wx.EXPAND | wx.ALL, 2) + hbSizer.Add(self.restartBtn, 0, wx.EXPAND | wx.ALL, 2) + hbSizer.Add(self.quitBtn, 0, wx.EXPAND | wx.ALL, 2) + vbSizer.Add(hbSizer, 0, wx.EXPAND | wx.ALL, 3) + self.SetSizer(vbSizer) + + self.set_speed(16) + + def OnDirection(self, event): + """ + Handles the ``wx.EVT_BUTTON`` event. + + :param `event`: A `wx.CommandEvent` to be processed. + :type `event`: `wx.CommandEvent` + """ + evtObj = event.GetEventObject() + lbl = evtObj.GetLabel() + if lbl == '>>': + evtObj.SetLabel('<<') + self.drawing_panel.reverse() + else: + evtObj.SetLabel('>>') + self.drawing_panel.forward() + + def set_speed(self, speed): + self.speed = max(speed, 1) + self.drawing_panel.set_speed(self.speed) + self.speedST.SetLabel('Speed x%s' % self.speed) + self.hbSizer.Layout() + + def OnSpeedMinus(self, event): + """""" + self.set_speed(self.speed / 2.0) + + def OnSpeedPlus(self, event): + """""" + self.set_speed(self.speed * 2.0) + + def OnPauseStart(self, event): + """""" + evtObj = event.GetEventObject() + lbl = evtObj.GetLabel() + if lbl == 'Pause': + self.drawing_panel.stop() + evtObj.SetLabel('Start') + else: + self.drawing_panel.go() + evtObj.SetLabel('Pause') + + def on_quit(self, event): + self.parent.quit() + +class DrawingPanel(wx.Panel): + """""" + + # render no faster than this many frames per second + TARGET_FPS = 30 + + # It's not possible to specify a line thickness less than 1 pixel, even + # though we're drawing anti-aliased lines. To get around this we scale + # the stitch positions up by this factor and then scale down by a + # corresponding amount during rendering. + PIXEL_DENSITY = 10 + + # Line width in pixels. + LINE_THICKNESS = 0.4 + + def __init__(self, *args, **kwargs): + """""" + self.stitch_plan = kwargs.pop('stitch_plan') + kwargs['style'] = wx.BORDER_SUNKEN + wx.Panel.__init__(self, *args, **kwargs) + + self.SetBackgroundColour('#FFFFFF') + self.SetDoubleBuffered(True) + + self.animating = False + self.target_frame_period = 1.0 / self.TARGET_FPS + self.last_frame_duration = 0 + self.direction = 1 + self.current_stitch = 0 + + # desired simulation speed in stitches per second + self.speed = 10 + + self.black_pen = self.create_pen((0, 0, 0)) + + self.load(self.stitch_plan) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + + def animate(self): + if not self.animating: + return + + frame_time = max(self.target_frame_period, self.last_frame_duration) + + # No sense in rendering more frames per second than our desired stitches + # per second. + frame_time = max(frame_time, 1.0 / self.speed) + + stitch_increment = int(self.speed * frame_time) + + #print >> sys.stderr, time.time(), "animate", self.current_stitch, stitch_increment, self.last_frame_duration, frame_time + + self.current_stitch += self.direction * stitch_increment + + if self.direction == -1 and self.current_stitch < 0: + self.current_stitch = 0 + self.stop() + elif self.direction == 1 and self.current_stitch >= self.num_stitches: + self.current_stitch = self.num_stitches + self.stop() + + self.Refresh() + + wx.CallLater(int(1000 * max(0.001, frame_time - self.last_frame_duration)), self.animate) + + def OnPaint(self, e): + dc = wx.PaintDC(self) + canvas = wx.GraphicsContext.Create(dc) + + transform = canvas.GetTransform() + transform.Scale(2.0 / self.PIXEL_DENSITY, 2.0 / self.PIXEL_DENSITY) + canvas.SetTransform(transform) + + stitch = 0 + last_stitch = None + + start = time.time() + for pen, stitches in izip(self.pens, self.stitch_blocks): + canvas.SetPen(pen) + if stitch + len(stitches) < self.current_stitch: + stitch += len(stitches) + canvas.DrawLines(stitches) + last_stitch = stitches[-1] + else: + stitches = stitches[:self.current_stitch - stitch] + if len(stitches) > 1: + canvas.DrawLines(stitches) + last_stitch = stitches[-1] + break + self.last_frame_duration = time.time() - start + + if last_stitch: + x = last_stitch[0] + y = last_stitch[1] + crosshair_radius = 4 * self.PIXEL_DENSITY + canvas.SetPen(self.black_pen) + canvas.DrawLines(((x - crosshair_radius, y), (x + crosshair_radius, y))) + canvas.DrawLines(((x, y - crosshair_radius), (x, y + crosshair_radius))) + + + def load(self, stitch_plan=None): + if stitch_plan: + self.num_stitches = stitch_plan.num_stitches + self.parse_stitch_plan(stitch_plan) + self.move_to_top_left() + return + + def stop(self): + self.animating = False + + def go(self): + if not self.animating: + self.animating = True + self.animate() + + def create_pen(self, rgb): + return wx.Pen(rgb, width=int(0.4 * self.PIXEL_DENSITY)) + + def color_to_pen(self, color): + return self.create_pen(color.visible_on_white.rgb) + + def parse_stitch_plan(self, stitch_plan): + self.pens = [] + self.stitch_blocks = [] + + for color_block in stitch_plan: + pen = self.color_to_pen(color_block.color) + + for point_list in color_block_to_point_lists(color_block): + self.pens.append(pen) + self.stitch_blocks.append(point_list) + + def move_to_top_left(self): + """remove any unnecessary whitespace around the design""" + + minx, miny, maxx, maxy = self.stitch_plan.bounding_box + + for block in self.stitch_blocks: + stitches = [] + for stitch in block: + stitches.append((self.PIXEL_DENSITY * (stitch[0] - minx), self.PIXEL_DENSITY * (stitch[1] - miny))) + block[:] = stitches + + def set_speed(self, speed): + self.speed = speed + + def forward(self): + self.direction = 1 + if self.current_stitch < self.num_stitches: + self.go() + + def reverse(self): + self.direction = -1 + if self.current_stitch > 0: + self.go() + + +class SimulatorPanel(wx.Panel): + """""" + def __init__(self, parent, *args, **kwargs): + """""" + self.parent = parent + stitch_plan = kwargs.pop('stitch_plan') + kwargs['style'] = wx.BORDER_SUNKEN + wx.Panel.__init__(self, parent, *args, **kwargs) + + self.dp = DrawingPanel(self, stitch_plan=stitch_plan) + self.cp = ControlPanel(self, stitch_plan=stitch_plan, drawing_panel=self.dp) + + vbSizer = wx.BoxSizer(wx.VERTICAL) + vbSizer.Add(self.dp, 1, wx.EXPAND | wx.ALL, 2) + vbSizer.Add(self.cp, 0, wx.EXPAND | wx.ALL, 2) + self.SetSizer(vbSizer) + + self.dp.go() + + def quit(self): + self.parent.quit() + + def stop(self): + self.dp.stop() + + class EmbroiderySimulator(wx.Frame): + def __init__(self, *args, **kwargs): + stitch_plan = kwargs.pop('stitch_plan', None) + self.x_position = kwargs.pop('x_position', None) + self.on_close_hook = kwargs.pop('on_close', None) + self.frame_period = kwargs.pop('frame_period', 80) + self.stitches_per_frame = kwargs.pop('stitches_per_frame', 1) + self.target_duration = kwargs.pop('target_duration', None) + self.max_height = kwargs.pop('max_height', None) + self.max_width = kwargs.pop('max_width', None) + wx.Frame.__init__(self, *args, **kwargs) + + # self.status_bar = self.CreateStatusBar() + # self.status_bar.SetStatusText(text) + + self.simulator_panel = SimulatorPanel(self, stitch_plan=stitch_plan) + self.Bind(wx.EVT_CLOSE, self.on_close) + + def quit(self): + self.Close() + + def on_close(self, event): + self.simulator_panel.stop() + + if self.on_close_hook: + self.on_close_hook() + + self.Destroy() + + def go(self): + pass + + +class OldEmbroiderySimulator(wx.Frame): def __init__(self, *args, **kwargs): stitch_plan = kwargs.pop('stitch_plan', None) self.x_position = kwargs.pop('x_position', None) -- cgit v1.2.3 From c44e0080296dbf771dba113d82372cffb88952a9 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sat, 25 Aug 2018 22:48:11 -0400 Subject: draggable slider and editable stitch number --- lib/simulator.py | 118 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 89 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index be87fe1e..82de3201 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -1,5 +1,6 @@ import sys import wx +from wx.lib.intctrl import IntCtrl import time from itertools import izip @@ -16,6 +17,8 @@ class ControlPanel(wx.Panel): kwargs['style'] = wx.BORDER_SUNKEN wx.Panel.__init__(self, parent, *args, **kwargs) + self.num_stitches = self.stitch_plan.num_stitches + # Widgets self.btnMinus = wx.Button(self, -1, label='-') self.btnMinus.Bind(wx.EVT_BUTTON, self.OnSpeedMinus) @@ -26,29 +29,32 @@ class ControlPanel(wx.Panel): self.pauseBtn = wx.Button(self, -1, label='Pause') self.pauseBtn.Bind(wx.EVT_BUTTON, self.OnPauseStart) self.restartBtn = wx.Button(self, -1, label='Restart') + self.restartBtn.Bind(wx.EVT_BUTTON, self.on_restart) self.quitBtn = wx.Button(self, -1, label='Quit') self.quitBtn.Bind(wx.EVT_BUTTON, self.on_quit) - self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=1000, + self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=self.num_stitches, style=wx.SL_HORIZONTAL | wx.SL_LABELS) - self.st1 = wx.StaticText(self, -1, label='Stitch # 1234/56789', style=wx.ALIGN_CENTER) - self.st1.SetForegroundColour('#FF0000') + self.slider.Bind(wx.EVT_SLIDER, self.on_slider) + self.stitchBox = IntCtrl(self, -1, value=0, min=0, max=self.num_stitches, limited=True, allow_none=False) + self.stitchBox.Bind(wx.EVT_TEXT, self.on_stitch_box) self.speedST = wx.StaticText(self, -1, label='', style=wx.ALIGN_CENTER) - self.speedST.SetForegroundColour('#0000FF') # Layout self.vbSizer = vbSizer = wx.BoxSizer(wx.VERTICAL) - self.hbSizer = hbSizer = wx.BoxSizer(wx.HORIZONTAL) - vbSizer.Add(self.slider, 1, wx.EXPAND | wx.ALL, 3) - hbSizer.Add(self.st1, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 2) - hbSizer.AddStretchSpacer(prop=1) - hbSizer.Add(self.speedST, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 2) - hbSizer.Add(self.btnMinus, 0, wx.ALL, 2) - hbSizer.Add(self.btnPlus, 0, wx.ALL, 2) - hbSizer.Add(self.direction, 0, wx.EXPAND | wx.ALL, 2) - hbSizer.Add(self.pauseBtn, 0, wx.EXPAND | wx.ALL, 2) - hbSizer.Add(self.restartBtn, 0, wx.EXPAND | wx.ALL, 2) - hbSizer.Add(self.quitBtn, 0, wx.EXPAND | wx.ALL, 2) - vbSizer.Add(hbSizer, 0, wx.EXPAND | wx.ALL, 3) + self.hbSizer1 = hbSizer1 = wx.BoxSizer(wx.HORIZONTAL) + self.hbSizer2 = hbSizer2 = wx.BoxSizer(wx.HORIZONTAL) + hbSizer1.Add(self.slider, 1, wx.EXPAND | wx.ALL, 3) + hbSizer1.Add(self.stitchBox, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 2) + vbSizer.Add(hbSizer1, 1, wx.EXPAND | wx.ALL, 3) + hbSizer2.Add(self.speedST, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 2) + hbSizer2.AddStretchSpacer(prop=1) + hbSizer2.Add(self.btnMinus, 0, wx.ALL, 2) + hbSizer2.Add(self.btnPlus, 0, wx.ALL, 2) + hbSizer2.Add(self.direction, 0, wx.EXPAND | wx.ALL, 2) + hbSizer2.Add(self.pauseBtn, 0, wx.EXPAND | wx.ALL, 2) + hbSizer2.Add(self.restartBtn, 0, wx.EXPAND | wx.ALL, 2) + hbSizer2.Add(self.quitBtn, 0, wx.EXPAND | wx.ALL, 2) + vbSizer.Add(hbSizer2, 0, wx.EXPAND | wx.ALL, 3) self.SetSizer(vbSizer) self.set_speed(16) @@ -70,10 +76,27 @@ class ControlPanel(wx.Panel): self.drawing_panel.forward() def set_speed(self, speed): - self.speed = max(speed, 1) + self.speed = int(max(speed, 1)) self.drawing_panel.set_speed(self.speed) - self.speedST.SetLabel('Speed x%s' % self.speed) - self.hbSizer.Layout() + self.speedST.SetLabel('Speed: %s stitches/sec' % self.speed) + self.hbSizer2.Layout() + + def on_slider(self, event): + stitch = event.GetEventObject().GetValue() + self.stitchBox.SetValue(stitch) + self.drawing_panel.set_current_stitch(stitch) + + def set_current_stitch(self, stitch): + self.slider.SetValue(stitch) + self.stitchBox.SetValue(stitch) + + def set_stitch_label(self, stitch): + self.st1.SetLabel("Stitch # %d/%d" % (stitch, self.num_stitches)) + + def on_stitch_box(self, event): + stitch = self.stitchBox.GetValue() + self.slider.SetValue(stitch) + self.drawing_panel.set_current_stitch(stitch) def OnSpeedMinus(self, event): """""" @@ -97,6 +120,9 @@ class ControlPanel(wx.Panel): def on_quit(self, event): self.parent.quit() + def on_restart(self, event): + self.drawing_panel.restart() + class DrawingPanel(wx.Panel): """""" @@ -126,6 +152,7 @@ class DrawingPanel(wx.Panel): self.last_frame_duration = 0 self.direction = 1 self.current_stitch = 0 + self.control_panel = None # desired simulation speed in stitches per second self.speed = 10 @@ -136,6 +163,28 @@ class DrawingPanel(wx.Panel): self.Bind(wx.EVT_PAINT, self.OnPaint) + def set_control_panel(self, control_panel): + self.control_panel = control_panel + + def clamp_current_stitch(self): + if self.current_stitch < 0: + self.current_stitch = 0 + elif self.current_stitch > self.num_stitches: + self.current_stitch = self.num_stitches + + def stop_if_at_end(self): + if self.direction == -1 and self.current_stitch == 0: + self.stop() + elif self.direction == 1 and self.current_stitch == self.num_stitches: + self.stop() + + def start_if_not_at_end(self): + if self.direction == -1 and self.current_stitch > 0: + self.go() + elif self.direction == 1 and self.current_stitch < self.num_stitches: + self.go() + + def animate(self): if not self.animating: return @@ -151,13 +200,11 @@ class DrawingPanel(wx.Panel): #print >> sys.stderr, time.time(), "animate", self.current_stitch, stitch_increment, self.last_frame_duration, frame_time self.current_stitch += self.direction * stitch_increment + self.clamp_current_stitch() + self.stop_if_at_end() - if self.direction == -1 and self.current_stitch < 0: - self.current_stitch = 0 - self.stop() - elif self.direction == 1 and self.current_stitch >= self.num_stitches: - self.current_stitch = self.num_stitches - self.stop() + if self.control_panel: + self.control_panel.set_current_stitch(self.current_stitch) self.Refresh() @@ -246,13 +293,25 @@ class DrawingPanel(wx.Panel): def forward(self): self.direction = 1 - if self.current_stitch < self.num_stitches: - self.go() + self.start_if_not_at_end() def reverse(self): self.direction = -1 - if self.current_stitch > 0: - self.go() + self.start_if_not_at_end() + + def set_current_stitch(self, stitch): + self.current_stitch = stitch + self.clamp_current_stitch() + self.stop_if_at_end() + self.Refresh() + + def restart(self): + if self.direction == 1: + self.current_stitch = 0 + elif self.direction == -1: + self.current_stitch = self.num_stitches + + self.go() class SimulatorPanel(wx.Panel): @@ -266,6 +325,7 @@ class SimulatorPanel(wx.Panel): self.dp = DrawingPanel(self, stitch_plan=stitch_plan) self.cp = ControlPanel(self, stitch_plan=stitch_plan, drawing_panel=self.dp) + self.dp.set_control_panel(self.cp) vbSizer = wx.BoxSizer(wx.VERTICAL) vbSizer.Add(self.dp, 1, wx.EXPAND | wx.ALL, 2) -- cgit v1.2.3 From 0bc2992686339fcdd8b71018f43fecb3c9111349 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sun, 26 Aug 2018 00:10:11 -0400 Subject: shouldn't subtract rendering time from CallLater time --- lib/simulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 82de3201..070213c5 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -208,7 +208,7 @@ class DrawingPanel(wx.Panel): self.Refresh() - wx.CallLater(int(1000 * max(0.001, frame_time - self.last_frame_duration)), self.animate) + wx.CallLater(int(1000 * frame_time), self.animate) def OnPaint(self, e): dc = wx.PaintDC(self) -- cgit v1.2.3 From 8351cf21a09168ae1faa3be916b1b418d3d388e8 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sun, 26 Aug 2018 14:32:34 -0400 Subject: add keyboard shortcut support --- lib/simulator.py | 107 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 070213c5..b9e8692b 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -21,17 +21,17 @@ class ControlPanel(wx.Panel): # Widgets self.btnMinus = wx.Button(self, -1, label='-') - self.btnMinus.Bind(wx.EVT_BUTTON, self.OnSpeedMinus) + self.btnMinus.Bind(wx.EVT_BUTTON, self.animation_slow_down) self.btnPlus = wx.Button(self, -1, label='+') - self.btnPlus.Bind(wx.EVT_BUTTON, self.OnSpeedPlus) + self.btnPlus.Bind(wx.EVT_BUTTON, self.animation_speed_up) self.direction = wx.Button(self, -1, label='>>') - self.direction.Bind(wx.EVT_BUTTON, self.OnDirection) + self.direction.Bind(wx.EVT_BUTTON, self.on_direction_button) self.pauseBtn = wx.Button(self, -1, label='Pause') - self.pauseBtn.Bind(wx.EVT_BUTTON, self.OnPauseStart) + self.pauseBtn.Bind(wx.EVT_BUTTON, self.on_pause_start_button) self.restartBtn = wx.Button(self, -1, label='Restart') - self.restartBtn.Bind(wx.EVT_BUTTON, self.on_restart) + self.restartBtn.Bind(wx.EVT_BUTTON, self.animation_restart) self.quitBtn = wx.Button(self, -1, label='Quit') - self.quitBtn.Bind(wx.EVT_BUTTON, self.on_quit) + self.quitBtn.Bind(wx.EVT_BUTTON, self.animation_quit) self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=self.num_stitches, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.slider.Bind(wx.EVT_SLIDER, self.on_slider) @@ -57,23 +57,60 @@ class ControlPanel(wx.Panel): vbSizer.Add(hbSizer2, 0, wx.EXPAND | wx.ALL, 3) self.SetSizer(vbSizer) + # Keyboard Shortcuts + shortcut_keys = [ + (wx.ACCEL_NORMAL, wx.WXK_RIGHT, self.animation_forward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_RIGHT, self.animation_forward), + (wx.ACCEL_NORMAL, wx.WXK_LEFT, self.animation_reverse), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_LEFT, self.animation_reverse), + (wx.ACCEL_NORMAL, wx.WXK_UP, self.animation_speed_up), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_speed_up), + (wx.ACCEL_NORMAL, wx.WXK_DOWN, self.animation_slow_down), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DOWN, self.animation_slow_down), + (wx.ACCEL_NORMAL, ord('+'), self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, ord('='), self.animation_one_frame_forward), + (wx.ACCEL_SHIFT, ord('='), self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, wx.WXK_ADD, self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ADD, self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_one_frame_forward), + (wx.ACCEL_NORMAL, ord('-'), self.animation_one_frame_backward), + (wx.ACCEL_NORMAL, ord('_'), self.animation_one_frame_backward), + (wx.ACCEL_NORMAL, wx.WXK_SUBTRACT, self.animation_one_frame_backward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, self.animation_one_frame_backward), + (wx.ACCEL_NORMAL, ord('r'), self.animation_restart), + (wx.ACCEL_NORMAL, ord('p'), self.on_pause_start_button), + (wx.ACCEL_NORMAL, wx.WXK_SPACE, self.on_pause_start_button), + (wx.ACCEL_NORMAL, ord('q'), self.animation_quit)] + + accel_entries = [] + + for shortcut_key in shortcut_keys: + eventId = wx.NewId() + accel_entries.append((shortcut_key[0], shortcut_key[1], eventId)) + self.Bind(wx.EVT_MENU, shortcut_key[2], id=eventId) + + accel_table = wx.AcceleratorTable(accel_entries) + self.SetAcceleratorTable(accel_table) + self.set_speed(16) - def OnDirection(self, event): - """ - Handles the ``wx.EVT_BUTTON`` event. + self.SetFocus() - :param `event`: A `wx.CommandEvent` to be processed. - :type `event`: `wx.CommandEvent` - """ + def animation_forward(self, event=None): + self.direction.SetLabel(">>") + self.drawing_panel.forward() + + def animation_reverse(self, event=None): + self.direction.SetLabel("<<") + self.drawing_panel.reverse() + + def on_direction_button(self, event): evtObj = event.GetEventObject() lbl = evtObj.GetLabel() if lbl == '>>': - evtObj.SetLabel('<<') - self.drawing_panel.reverse() + self.animation_reverse() else: - evtObj.SetLabel('>>') - self.drawing_panel.forward() + self.animation_forward() def set_speed(self, speed): self.speed = int(max(speed, 1)) @@ -86,7 +123,7 @@ class ControlPanel(wx.Panel): self.stitchBox.SetValue(stitch) self.drawing_panel.set_current_stitch(stitch) - def set_current_stitch(self, stitch): + def on_current_stitch(self, stitch): self.slider.SetValue(stitch) self.stitchBox.SetValue(stitch) @@ -98,29 +135,39 @@ class ControlPanel(wx.Panel): self.slider.SetValue(stitch) self.drawing_panel.set_current_stitch(stitch) - def OnSpeedMinus(self, event): + def animation_slow_down(self, event): """""" self.set_speed(self.speed / 2.0) - def OnSpeedPlus(self, event): + def animation_speed_up(self, event): """""" self.set_speed(self.speed * 2.0) - def OnPauseStart(self, event): + def animation_pause(self, event=None): + self.drawing_panel.stop() + self.pauseBtn.SetLabel('Start') + + def animation_start(self, event=None): + self.drawing_panel.go() + self.pauseBtn.SetLabel('Pause') + + def on_pause_start_button(self, event): """""" - evtObj = event.GetEventObject() - lbl = evtObj.GetLabel() - if lbl == 'Pause': - self.drawing_panel.stop() - evtObj.SetLabel('Start') + if self.pauseBtn.GetLabel() == 'Pause': + self.animation_pause() else: - self.drawing_panel.go() - evtObj.SetLabel('Pause') + self.animation_start() - def on_quit(self, event): + def animation_one_frame_forward(self, event): + pass + + def animation_one_frame_backward(self, event): + pass + + def animation_quit(self, event): self.parent.quit() - def on_restart(self, event): + def animation_restart(self, event): self.drawing_panel.restart() class DrawingPanel(wx.Panel): @@ -204,7 +251,7 @@ class DrawingPanel(wx.Panel): self.stop_if_at_end() if self.control_panel: - self.control_panel.set_current_stitch(self.current_stitch) + self.control_panel.on_current_stitch(self.current_stitch) self.Refresh() -- cgit v1.2.3 From 79e8ad5b31f18a622b8ce8ed9ee9563cca579a38 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sun, 26 Aug 2018 14:43:23 -0400 Subject: forward/backward one frame support --- lib/simulator.py | 57 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index b9e8692b..4483d653 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -35,7 +35,7 @@ class ControlPanel(wx.Panel): self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=self.num_stitches, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.slider.Bind(wx.EVT_SLIDER, self.on_slider) - self.stitchBox = IntCtrl(self, -1, value=0, min=0, max=self.num_stitches, limited=True, allow_none=False) + self.stitchBox = IntCtrl(self, -1, value=1, min=0, max=self.num_stitches, limited=True, allow_none=False) self.stitchBox.Bind(wx.EVT_TEXT, self.on_stitch_box) self.speedST = wx.StaticText(self, -1, label='', style=wx.ALIGN_CENTER) @@ -67,16 +67,16 @@ class ControlPanel(wx.Panel): (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_speed_up), (wx.ACCEL_NORMAL, wx.WXK_DOWN, self.animation_slow_down), (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DOWN, self.animation_slow_down), - (wx.ACCEL_NORMAL, ord('+'), self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, ord('='), self.animation_one_frame_forward), - (wx.ACCEL_SHIFT, ord('='), self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, wx.WXK_ADD, self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ADD, self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, ord('-'), self.animation_one_frame_backward), - (wx.ACCEL_NORMAL, ord('_'), self.animation_one_frame_backward), - (wx.ACCEL_NORMAL, wx.WXK_SUBTRACT, self.animation_one_frame_backward), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, self.animation_one_frame_backward), + (wx.ACCEL_NORMAL, ord('+'), self.animation_one_stitch_forward), + (wx.ACCEL_NORMAL, ord('='), self.animation_one_stitch_forward), + (wx.ACCEL_SHIFT, ord('='), self.animation_one_stitch_forward), + (wx.ACCEL_NORMAL, wx.WXK_ADD, self.animation_one_stitch_forward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ADD, self.animation_one_stitch_forward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_one_stitch_forward), + (wx.ACCEL_NORMAL, ord('-'), self.animation_one_stitch_backward), + (wx.ACCEL_NORMAL, ord('_'), self.animation_one_stitch_backward), + (wx.ACCEL_NORMAL, wx.WXK_SUBTRACT, self.animation_one_stitch_backward), + (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, self.animation_one_stitch_backward), (wx.ACCEL_NORMAL, ord('r'), self.animation_restart), (wx.ACCEL_NORMAL, ord('p'), self.on_pause_start_button), (wx.ACCEL_NORMAL, wx.WXK_SPACE, self.on_pause_start_button), @@ -92,6 +92,7 @@ class ControlPanel(wx.Panel): accel_table = wx.AcceleratorTable(accel_entries) self.SetAcceleratorTable(accel_table) + self.current_stitch = 1 self.set_speed(16) self.SetFocus() @@ -124,8 +125,10 @@ class ControlPanel(wx.Panel): self.drawing_panel.set_current_stitch(stitch) def on_current_stitch(self, stitch): - self.slider.SetValue(stitch) - self.stitchBox.SetValue(stitch) + if self.current_stitch != stitch: + self.current_stitch = stitch + self.slider.SetValue(stitch) + self.stitchBox.SetValue(stitch) def set_stitch_label(self, stitch): self.st1.SetLabel("Stitch # %d/%d" % (stitch, self.num_stitches)) @@ -158,11 +161,11 @@ class ControlPanel(wx.Panel): else: self.animation_start() - def animation_one_frame_forward(self, event): - pass + def animation_one_stitch_forward(self, event): + self.drawing_panel.one_stitch_forward() - def animation_one_frame_backward(self, event): - pass + def animation_one_stitch_backward(self, event): + self.drawing_panel.one_stitch_backward() def animation_quit(self, event): self.parent.quit() @@ -231,7 +234,6 @@ class DrawingPanel(wx.Panel): elif self.direction == 1 and self.current_stitch < self.num_stitches: self.go() - def animate(self): if not self.animating: return @@ -246,15 +248,7 @@ class DrawingPanel(wx.Panel): #print >> sys.stderr, time.time(), "animate", self.current_stitch, stitch_increment, self.last_frame_duration, frame_time - self.current_stitch += self.direction * stitch_increment - self.clamp_current_stitch() - self.stop_if_at_end() - - if self.control_panel: - self.control_panel.on_current_stitch(self.current_stitch) - - self.Refresh() - + self.set_current_stitch(self.current_stitch + self.direction * stitch_increment) wx.CallLater(int(1000 * frame_time), self.animate) def OnPaint(self, e): @@ -352,6 +346,9 @@ class DrawingPanel(wx.Panel): self.stop_if_at_end() self.Refresh() + if self.control_panel: + self.control_panel.on_current_stitch(self.current_stitch) + def restart(self): if self.direction == 1: self.current_stitch = 0 @@ -360,6 +357,12 @@ class DrawingPanel(wx.Panel): self.go() + def one_stitch_forward(self): + self.set_current_stitch(self.current_stitch + 1) + + def one_stitch_backward(self): + self.set_current_stitch(self.current_stitch - 1) + class SimulatorPanel(wx.Panel): """""" -- cgit v1.2.3 From a355af287484a62a021808b4ced20c4b85877759 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sun, 26 Aug 2018 15:02:51 -0400 Subject: handle window size and target duration --- lib/extensions/params.py | 11 ++++------- lib/extensions/simulate.py | 4 +++- lib/simulator.py | 34 ++++++++++++++++++++++++---------- 3 files changed, 31 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/extensions/params.py b/lib/extensions/params.py index 6d1464a3..9bde2a66 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -440,19 +440,16 @@ class SettingsFrame(wx.Frame): display = wx.Display(current_screen) screen_rect = display.GetClientArea() - max_width = screen_rect.GetWidth() - params_rect.GetWidth() - max_height = screen_rect.GetHeight() + width = screen_rect.GetWidth() - params_rect.GetWidth() + height = screen_rect.GetHeight() try: self.simulate_window = EmbroiderySimulator(None, -1, _("Preview"), simulator_pos, - size=(300, 300), - x_position=simulator_pos.x, + size=(width, height), stitch_plan=stitch_plan, on_close=self.simulate_window_closed, - target_duration=5, - max_width=max_width, - max_height=max_height) + target_duration=5) except: error = traceback.format_exc() diff --git a/lib/extensions/simulate.py b/lib/extensions/simulate.py index 38f86156..2e414ac6 100644 --- a/lib/extensions/simulate.py +++ b/lib/extensions/simulate.py @@ -25,8 +25,10 @@ class Simulate(InkstitchExtension): screen_rect = display.GetClientArea() simulator_pos = (screen_rect[0], screen_rect[1]) + width = screen_rect[2] + height = screen_rect[3] - frame = EmbroiderySimulator(None, -1, _("Embroidery Simulation"), pos=simulator_pos, size=(1000, 1000), stitch_plan=stitch_plan) + frame = EmbroiderySimulator(None, -1, _("Embroidery Simulation"), pos=simulator_pos, size=(width, height), stitch_plan=stitch_plan) app.SetTopWindow(frame) frame.Show() wx.CallAfter(frame.go) diff --git a/lib/simulator.py b/lib/simulator.py index 4483d653..5be503ef 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -14,6 +14,8 @@ class ControlPanel(wx.Panel): self.parent = parent self.drawing_panel = kwargs.pop('drawing_panel') self.stitch_plan = kwargs.pop('stitch_plan') + stitches_per_second = kwargs.pop('stitches_per_second') + target_duration = kwargs.pop('target_duration') kwargs['style'] = wx.BORDER_SUNKEN wx.Panel.__init__(self, parent, *args, **kwargs) @@ -93,10 +95,17 @@ class ControlPanel(wx.Panel): self.SetAcceleratorTable(accel_table) self.current_stitch = 1 - self.set_speed(16) + + self.choose_speed(stitches_per_second, target_duration) self.SetFocus() + def choose_speed(self, stitches_per_second, target_duration): + if target_duration: + self.set_speed(int(self.num_stitches / float(target_duration))) + else: + self.set_speed(stitches_per_second) + def animation_forward(self, event=None): self.direction.SetLabel(">>") self.drawing_panel.forward() @@ -370,11 +379,17 @@ class SimulatorPanel(wx.Panel): """""" 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) self.dp = DrawingPanel(self, stitch_plan=stitch_plan) - self.cp = ControlPanel(self, stitch_plan=stitch_plan, drawing_panel=self.dp) + self.cp = ControlPanel(self, + stitch_plan=stitch_plan, + drawing_panel=self.dp, + stitches_per_second=stitches_per_second, + target_duration=target_duration) self.dp.set_control_panel(self.cp) vbSizer = wx.BoxSizer(wx.VERTICAL) @@ -393,20 +408,19 @@ class SimulatorPanel(wx.Panel): class EmbroiderySimulator(wx.Frame): def __init__(self, *args, **kwargs): - stitch_plan = kwargs.pop('stitch_plan', None) - self.x_position = kwargs.pop('x_position', None) self.on_close_hook = kwargs.pop('on_close', None) - self.frame_period = kwargs.pop('frame_period', 80) - self.stitches_per_frame = kwargs.pop('stitches_per_frame', 1) - self.target_duration = kwargs.pop('target_duration', None) - self.max_height = kwargs.pop('max_height', None) - self.max_width = kwargs.pop('max_width', 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) # self.status_bar = self.CreateStatusBar() # self.status_bar.SetStatusText(text) - self.simulator_panel = SimulatorPanel(self, stitch_plan=stitch_plan) + self.simulator_panel = SimulatorPanel(self, + stitch_plan=stitch_plan, + target_duration=target_duration, + stitches_per_second=stitches_per_second) self.Bind(wx.EVT_CLOSE, self.on_close) def quit(self): -- cgit v1.2.3 From e854df43073ce3158654b0db304edd0bba7a7d6d Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sun, 26 Aug 2018 15:34:13 -0400 Subject: handle auto-refresh from Params --- lib/extensions/params.py | 11 +---- lib/simulator.py | 109 +++++++++++++++++++++++++++++++---------------- 2 files changed, 73 insertions(+), 47 deletions(-) (limited to 'lib') diff --git a/lib/extensions/params.py b/lib/extensions/params.py index 9bde2a66..73ce069d 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -421,16 +421,7 @@ class SettingsFrame(wx.Frame): stitch_plan = patches_to_stitch_plan(patches) if self.simulate_window: self.simulate_window.stop() - self.simulate_window.load(stitch_plan=stitch_plan) - self.simulate_window.calculate_dimensions() - - children = self.simulate_window.GetChildren() - for child in children: - if isinstance(child, wx.Slider): - child.Destroy() - self.simulate_window.set_slider() - - self.simulate_window.Layout() + self.simulate_window.load(stitch_plan) else: params_rect = self.GetScreenRect() simulator_pos = params_rect.GetTopRight() diff --git a/lib/simulator.py b/lib/simulator.py index 5be503ef..cae0e019 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -12,14 +12,16 @@ class ControlPanel(wx.Panel): def __init__(self, parent, *args, **kwargs): """""" self.parent = parent - self.drawing_panel = kwargs.pop('drawing_panel') self.stitch_plan = kwargs.pop('stitch_plan') - stitches_per_second = kwargs.pop('stitches_per_second') - target_duration = kwargs.pop('target_duration') + self.target_stitches_per_second = kwargs.pop('stitches_per_second') + self.target_duration = kwargs.pop('target_duration') kwargs['style'] = wx.BORDER_SUNKEN wx.Panel.__init__(self, parent, *args, **kwargs) - self.num_stitches = self.stitch_plan.num_stitches + self.drawing_panel = None + self.num_stitches = 1 + self.current_stitch = 0 + self.speed = 1 # Widgets self.btnMinus = wx.Button(self, -1, label='-') @@ -34,7 +36,7 @@ class ControlPanel(wx.Panel): self.restartBtn.Bind(wx.EVT_BUTTON, self.animation_restart) self.quitBtn = wx.Button(self, -1, label='Quit') self.quitBtn.Bind(wx.EVT_BUTTON, self.animation_quit) - self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=self.num_stitches, + self.slider = wx.Slider(self, -1, value=0, minValue=0, maxValue=self.num_stitches, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.slider.Bind(wx.EVT_SLIDER, self.on_slider) self.stitchBox = IntCtrl(self, -1, value=1, min=0, max=self.num_stitches, limited=True, allow_none=False) @@ -93,18 +95,23 @@ class ControlPanel(wx.Panel): accel_table = wx.AcceleratorTable(accel_entries) self.SetAcceleratorTable(accel_table) + self.SetFocus() - self.current_stitch = 1 - - self.choose_speed(stitches_per_second, target_duration) + def set_drawing_panel(self, drawing_panel): + self.drawing_panel = drawing_panel + self.drawing_panel.set_speed(self.speed) - self.SetFocus() + def set_num_stitches(self, num_stitches): + self.num_stitches = num_stitches + self.stitchBox.SetMax(num_stitches) + self.slider.SetMax(num_stitches) + self.choose_speed() - def choose_speed(self, stitches_per_second, target_duration): - if target_duration: - self.set_speed(int(self.num_stitches / float(target_duration))) + def choose_speed(self): + if self.target_duration: + self.set_speed(int(self.num_stitches / float(self.target_duration))) else: - self.set_speed(stitches_per_second) + self.set_speed(self.target_stitches_per_second) def animation_forward(self, event=None): self.direction.SetLabel(">>") @@ -124,14 +131,18 @@ class ControlPanel(wx.Panel): def set_speed(self, speed): self.speed = int(max(speed, 1)) - self.drawing_panel.set_speed(self.speed) self.speedST.SetLabel('Speed: %s stitches/sec' % self.speed) self.hbSizer2.Layout() + if self.drawing_panel: + self.drawing_panel.set_speed(self.speed) + def on_slider(self, event): stitch = event.GetEventObject().GetValue() self.stitchBox.SetValue(stitch) - self.drawing_panel.set_current_stitch(stitch) + + if self.drawing_panel: + self.drawing_panel.set_current_stitch(stitch) def on_current_stitch(self, stitch): if self.current_stitch != stitch: @@ -145,7 +156,9 @@ class ControlPanel(wx.Panel): def on_stitch_box(self, event): stitch = self.stitchBox.GetValue() self.slider.SetValue(stitch) - self.drawing_panel.set_current_stitch(stitch) + + if self.drawing_panel: + self.drawing_panel.set_current_stitch(stitch) def animation_slow_down(self, event): """""" @@ -157,12 +170,16 @@ class ControlPanel(wx.Panel): def animation_pause(self, event=None): self.drawing_panel.stop() - self.pauseBtn.SetLabel('Start') def animation_start(self, event=None): self.drawing_panel.go() + + def on_start(self): self.pauseBtn.SetLabel('Pause') + def on_stop(self): + self.pauseBtn.SetLabel('Start') + def on_pause_start_button(self, event): """""" if self.pauseBtn.GetLabel() == 'Pause': @@ -200,6 +217,7 @@ class DrawingPanel(wx.Panel): def __init__(self, *args, **kwargs): """""" self.stitch_plan = kwargs.pop('stitch_plan') + self.control_panel = kwargs.pop('control_panel') kwargs['style'] = wx.BORDER_SUNKEN wx.Panel.__init__(self, *args, **kwargs) @@ -211,10 +229,9 @@ class DrawingPanel(wx.Panel): self.last_frame_duration = 0 self.direction = 1 self.current_stitch = 0 - self.control_panel = None # desired simulation speed in stitches per second - self.speed = 10 + self.speed = 16 self.black_pen = self.create_pen((0, 0, 0)) @@ -222,9 +239,6 @@ class DrawingPanel(wx.Panel): self.Bind(wx.EVT_PAINT, self.OnPaint) - def set_control_panel(self, control_panel): - self.control_panel = control_panel - def clamp_current_stitch(self): if self.current_stitch < 0: self.current_stitch = 0 @@ -294,21 +308,29 @@ class DrawingPanel(wx.Panel): canvas.DrawLines(((x - crosshair_radius, y), (x + crosshair_radius, y))) canvas.DrawLines(((x, y - crosshair_radius), (x, y + crosshair_radius))) + def clear(self): + dc = wx.ClientDC(self) + dc.Clear() - def load(self, stitch_plan=None): - if stitch_plan: - self.num_stitches = stitch_plan.num_stitches - self.parse_stitch_plan(stitch_plan) - self.move_to_top_left() - return + def load(self, stitch_plan): + self.last_frame_duration = 0 + self.direction = 1 + self.num_stitches = stitch_plan.num_stitches + self.control_panel.set_num_stitches(self.num_stitches) + self.parse_stitch_plan(stitch_plan) + self.move_to_top_left() + self.set_current_stitch(0) + self.go() def stop(self): self.animating = False + self.control_panel.on_stop() def go(self): if not self.animating: self.animating = True self.animate() + self.control_panel.on_start() def create_pen(self, rgb): return wx.Pen(rgb, width=int(0.4 * self.PIXEL_DENSITY)) @@ -352,12 +374,10 @@ class DrawingPanel(wx.Panel): def set_current_stitch(self, stitch): self.current_stitch = stitch self.clamp_current_stitch() + self.control_panel.on_current_stitch(self.current_stitch) self.stop_if_at_end() self.Refresh() - if self.control_panel: - self.control_panel.on_current_stitch(self.current_stitch) - def restart(self): if self.direction == 1: self.current_stitch = 0 @@ -384,27 +404,33 @@ class SimulatorPanel(wx.Panel): kwargs['style'] = wx.BORDER_SUNKEN wx.Panel.__init__(self, parent, *args, **kwargs) - self.dp = DrawingPanel(self, stitch_plan=stitch_plan) self.cp = ControlPanel(self, stitch_plan=stitch_plan, - drawing_panel=self.dp, stitches_per_second=stitches_per_second, target_duration=target_duration) - self.dp.set_control_panel(self.cp) + self.dp = DrawingPanel(self, stitch_plan=stitch_plan, control_panel=self.cp) + self.cp.set_drawing_panel(self.dp) vbSizer = wx.BoxSizer(wx.VERTICAL) vbSizer.Add(self.dp, 1, wx.EXPAND | wx.ALL, 2) vbSizer.Add(self.cp, 0, wx.EXPAND | wx.ALL, 2) self.SetSizer(vbSizer) - self.dp.go() - def quit(self): self.parent.quit() + def go(self): + self.dp.go() + def stop(self): self.dp.stop() + def load(self, stitch_plan): + self.dp.load(stitch_plan) + + def clear(self): + self.dp.clear() + class EmbroiderySimulator(wx.Frame): def __init__(self, *args, **kwargs): @@ -435,7 +461,16 @@ class EmbroiderySimulator(wx.Frame): self.Destroy() def go(self): - pass + self.simulator_panel.go() + + def stop(self): + self.simulator_panel.stop() + + def load(self, stitch_plan): + self.simulator_panel.load(stitch_plan) + + def clear(self): + self.simulator_panel.clear() class OldEmbroiderySimulator(wx.Frame): -- cgit v1.2.3 From b3516785aafef79a02059cf29591ec978331e703 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sun, 26 Aug 2018 16:14:03 -0400 Subject: automatically scale and center the design --- lib/extensions/simulate.py | 7 +++--- lib/simulator.py | 63 +++++++++++++++++++++++++++++++++------------- 2 files changed, 50 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/extensions/simulate.py b/lib/extensions/simulate.py index 2e414ac6..dcb5e604 100644 --- a/lib/extensions/simulate.py +++ b/lib/extensions/simulate.py @@ -25,11 +25,12 @@ class Simulate(InkstitchExtension): screen_rect = display.GetClientArea() simulator_pos = (screen_rect[0], screen_rect[1]) - width = screen_rect[2] - height = screen_rect[3] + + # subtract 1 because otherwise the window becomes maximized on Linux + 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) app.SetTopWindow(frame) frame.Show() - wx.CallAfter(frame.go) app.MainLoop() diff --git a/lib/simulator.py b/lib/simulator.py index cae0e019..2565e42f 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -229,15 +229,19 @@ class DrawingPanel(wx.Panel): self.last_frame_duration = 0 self.direction = 1 self.current_stitch = 0 + self.black_pen = self.create_pen((0, 0, 0)) + self.width = 0 + self.height = 0 + self.loaded = False # desired simulation speed in stitches per second self.speed = 16 - self.black_pen = self.create_pen((0, 0, 0)) - - self.load(self.stitch_plan) - self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.choose_zoom_and_pan) + + # wait for layouts so that panel size is set + wx.CallLater(50, self.load, self.stitch_plan) def clamp_current_stitch(self): if self.current_stitch < 0: @@ -275,11 +279,16 @@ class DrawingPanel(wx.Panel): wx.CallLater(int(1000 * frame_time), self.animate) def OnPaint(self, e): + if not self.loaded: + return + dc = wx.PaintDC(self) canvas = wx.GraphicsContext.Create(dc) transform = canvas.GetTransform() - transform.Scale(2.0 / self.PIXEL_DENSITY, 2.0 / self.PIXEL_DENSITY) + transform.Translate(*self.pan) + transform.Scale(self.zoom / self.PIXEL_DENSITY, self.zoom / self.PIXEL_DENSITY) + #transform.Translate(self.pan[0] * self.PIXEL_DENSITY, self.pan[1] * self.PIXEL_DENSITY) canvas.SetTransform(transform) stitch = 0 @@ -303,7 +312,7 @@ class DrawingPanel(wx.Panel): if last_stitch: x = last_stitch[0] y = last_stitch[1] - crosshair_radius = 4 * self.PIXEL_DENSITY + crosshair_radius = 10 / self.zoom * self.PIXEL_DENSITY canvas.SetPen(self.black_pen) canvas.DrawLines(((x - crosshair_radius, y), (x + crosshair_radius, y))) canvas.DrawLines(((x, y - crosshair_radius), (x, y + crosshair_radius))) @@ -317,16 +326,39 @@ class DrawingPanel(wx.Panel): self.direction = 1 self.num_stitches = stitch_plan.num_stitches self.control_panel.set_num_stitches(self.num_stitches) + self.minx, self.miny, self.maxx, self.maxy = stitch_plan.bounding_box + self.width = self.maxx - self.minx + self.height = self.maxy - self.miny self.parse_stitch_plan(stitch_plan) - self.move_to_top_left() + self.choose_zoom_and_pan() self.set_current_stitch(0) + self.loaded = True self.go() + def choose_zoom_and_pan(self, event=None): + # ignore if called before we load the stitch plan + if not self.width or not self.height: + return + + panel_width, panel_height = self.GetClientSize() + + # add some padding to make stitches at the edge more visible + width_ratio = panel_width / float(self.width + 10) + height_ratio = panel_height / float(self.height + 10) + self.zoom = min(width_ratio, height_ratio) + + # center the design + self.pan = ((panel_width - self.zoom * self.width) / 2.0, + (panel_height - self.zoom * self.height) / 2.0) + def stop(self): self.animating = False self.control_panel.on_stop() def go(self): + if not self.loaded: + return + if not self.animating: self.animating = True self.animate() @@ -347,18 +379,15 @@ class DrawingPanel(wx.Panel): for point_list in color_block_to_point_lists(color_block): self.pens.append(pen) - self.stitch_blocks.append(point_list) - - def move_to_top_left(self): - """remove any unnecessary whitespace around the design""" - minx, miny, maxx, maxy = self.stitch_plan.bounding_box + points = [] + for x, y in point_list: + # trim any whitespace on the left and top and scale to the + # pixel density + points.append((self.PIXEL_DENSITY * (x - self.minx), + self.PIXEL_DENSITY * (y - self.miny))) - for block in self.stitch_blocks: - stitches = [] - for stitch in block: - stitches.append((self.PIXEL_DENSITY * (stitch[0] - minx), self.PIXEL_DENSITY * (stitch[1] - miny))) - block[:] = stitches + self.stitch_blocks.append(points) def set_speed(self, speed): self.speed = speed -- cgit v1.2.3 From 6bb2fa0c911e9526b87452196b50adc431ca8d62 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sun, 26 Aug 2018 16:41:57 -0400 Subject: uniform crosshair size independent of zoom --- lib/simulator.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 2565e42f..37747b10 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -229,7 +229,7 @@ class DrawingPanel(wx.Panel): self.last_frame_duration = 0 self.direction = 1 self.current_stitch = 0 - self.black_pen = self.create_pen((0, 0, 0)) + self.black_pen = wx.Pen((128, 128, 128)) self.width = 0 self.height = 0 self.loaded = False @@ -312,7 +312,9 @@ class DrawingPanel(wx.Panel): if last_stitch: x = last_stitch[0] y = last_stitch[1] - crosshair_radius = 10 / self.zoom * self.PIXEL_DENSITY + x, y = transform.TransformPoint(float(x), float(y)) + canvas.SetTransform(canvas.CreateMatrix()) + crosshair_radius = 10 canvas.SetPen(self.black_pen) canvas.DrawLines(((x - crosshair_radius, y), (x + crosshair_radius, y))) canvas.DrawLines(((x, y - crosshair_radius), (x, y + crosshair_radius))) @@ -364,11 +366,8 @@ class DrawingPanel(wx.Panel): self.animate() self.control_panel.on_start() - def create_pen(self, rgb): - return wx.Pen(rgb, width=int(0.4 * self.PIXEL_DENSITY)) - def color_to_pen(self, color): - return self.create_pen(color.visible_on_white.rgb) + return wx.Pen(color.visible_on_white.rgb, width=int(0.4 * self.PIXEL_DENSITY)) def parse_stitch_plan(self, stitch_plan): self.pens = [] -- cgit v1.2.3 From 7637848ad8d6ec8ae0eca1fe1a0979572e93415a Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sun, 26 Aug 2018 23:34:27 -0400 Subject: zoom and pan support --- lib/simulator.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 37747b10..610e4ee4 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -239,6 +239,8 @@ class DrawingPanel(wx.Panel): self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.choose_zoom_and_pan) + self.Bind(wx.EVT_LEFT_DOWN, self.on_left_mouse_button_down) + self.Bind(wx.EVT_MOUSEWHEEL, self.on_mouse_wheel) # wait for layouts so that panel size is set wx.CallLater(50, self.load, self.stitch_plan) @@ -420,6 +422,72 @@ class DrawingPanel(wx.Panel): def one_stitch_backward(self): self.set_current_stitch(self.current_stitch - 1) + def on_left_mouse_button_down(self, event): + self.CaptureMouse() + self.drag_start = event.GetPosition() + self.drag_original_pan = self.pan + self.Bind(wx.EVT_MOTION, self.on_drag) + self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.on_drag_end) + self.Bind(wx.EVT_LEFT_UP, self.on_drag_end) + + def on_drag(self, event): + if self.HasCapture() and event.Dragging(): + delta = event.GetPosition() + offset = (delta[0] - self.drag_start[0], delta[1] - self.drag_start[1]) + self.pan = (self.drag_original_pan[0] + offset[0], self.drag_original_pan[1] + offset[1]) + self.Refresh() + + def on_drag_end(self, event): + if self.HasCapture(): + self.ReleaseMouse() + + self.Unbind(wx.EVT_MOTION) + self.Unbind(wx.EVT_MOUSE_CAPTURE_LOST) + self.Unbind(wx.EVT_LEFT_UP) + + def on_mouse_wheel(self, event): + if event.GetWheelRotation() > 0: + zoom_delta = 1.03 + else: + zoom_delta = 0.97 + + # If we just change the zoom, the design will appear to move on the + # screen. We have to adjust the pan to compensate. We want to keep + # the part of the design under the mouse pointer in the same spot + # after we zoom, so that we appar to be zooming centered on the + # mouse pointer. + + # This will create a matrix that takes a point in the design and + # converts it to screen coordinates: + matrix = wx.AffineMatrix2D() + matrix.Translate(*self.pan) + matrix.Scale(self.zoom, self.zoom) + + # First, figure out where the mouse pointer is in the coordinate system + # of the design: + pos = event.GetPosition() + inverse_matrix = wx.AffineMatrix2D() + inverse_matrix.Set(*matrix.Get()) + inverse_matrix.Invert() + pos = inverse_matrix.TransformPoint(*pos) + + # Next, see how that point changes position on screen before and after + # we apply the zoom change: + x_old, y_old = matrix.TransformPoint(*pos) + matrix.Scale(zoom_delta, zoom_delta) + x_new, y_new = matrix.TransformPoint(*pos) + x_delta = x_new - x_old + y_delta = y_new - y_old + + # Finally, compensate for that change in position: + self.pan = (self.pan[0] - x_delta, self.pan[1] - y_delta) + + + self.zoom *= zoom_delta + + + self.Refresh() + class SimulatorPanel(wx.Panel): """""" -- cgit v1.2.3 From 7319937ea6c568aba8d613eed66433ddb24b6cc3 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sun, 26 Aug 2018 23:50:17 -0400 Subject: make line thickness value less magical --- lib/simulator.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 610e4ee4..598d201b 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -4,7 +4,7 @@ from wx.lib.intctrl import IntCtrl import time from itertools import izip -from .svg import color_block_to_point_lists +from .svg import color_block_to_point_lists, PIXELS_PER_MM from .i18n import _ class ControlPanel(wx.Panel): @@ -369,7 +369,10 @@ class DrawingPanel(wx.Panel): self.control_panel.on_start() def color_to_pen(self, color): - return wx.Pen(color.visible_on_white.rgb, width=int(0.4 * self.PIXEL_DENSITY)) + # We draw the thread with a thickness of 0.1mm. Real thread has a + # thickness of ~0.4mm, but if we did that, we wouldn't be able to + # see the individual stitches. + return wx.Pen(color.visible_on_white.rgb, width=int(0.1 * PIXELS_PER_MM * self.PIXEL_DENSITY)) def parse_stitch_plan(self, stitch_plan): self.pens = [] -- cgit v1.2.3 From 165d96e3b182d28388b84cc49680a34be033e837 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Mon, 27 Aug 2018 15:36:54 -0400 Subject: show command name in simulator (STITCH, JUMP, etc) --- lib/output.py | 8 +++++ lib/simulator.py | 77 ++++++++++++++++++++++++++++++------------ lib/stitch_plan/stitch_plan.py | 6 ++++ 3 files changed, 69 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/output.py b/lib/output.py index d5c513e2..147d084e 100644 --- a/lib/output.py +++ b/lib/output.py @@ -84,4 +84,12 @@ def write_embroidery_file(file_path, stitch_plan, svg): "full_jump": True, } + if file_path.endswith('.csv'): + # Special treatment for CSV: instruct pyembroidery not to do any post- + # processing. This will allow the user to match up stitch numbers seen + # in the simulator with commands in the CSV. + settings['max_stitch'] = float('inf') + settings['max_jump'] = float('inf') + settings['explicit_trim'] = False + pyembroidery.write(pattern, file_path, settings) diff --git a/lib/simulator.py b/lib/simulator.py index 598d201b..18bf1d7e 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -7,6 +7,16 @@ from itertools import izip from .svg import color_block_to_point_lists, PIXELS_PER_MM from .i18n import _ +# L10N command label at bottom of simulator window +COMMAND_NAMES = [_("STITCH"), _("JUMP"), _("TRIM"), _("STOP"), _("COLOR CHANGE")] + +STITCH = 0 +JUMP = 1 +TRIM = 2 +STOP = 3 +COLOR_CHANGE = 4 + + class ControlPanel(wx.Panel): """""" def __init__(self, parent, *args, **kwargs): @@ -20,7 +30,7 @@ class ControlPanel(wx.Panel): self.drawing_panel = None self.num_stitches = 1 - self.current_stitch = 0 + self.current_stitch = 1 self.speed = 1 # Widgets @@ -36,12 +46,13 @@ class ControlPanel(wx.Panel): self.restartBtn.Bind(wx.EVT_BUTTON, self.animation_restart) self.quitBtn = wx.Button(self, -1, label='Quit') self.quitBtn.Bind(wx.EVT_BUTTON, self.animation_quit) - self.slider = wx.Slider(self, -1, value=0, minValue=0, maxValue=self.num_stitches, + self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=self.num_stitches, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.slider.Bind(wx.EVT_SLIDER, self.on_slider) - self.stitchBox = IntCtrl(self, -1, value=1, min=0, max=self.num_stitches, limited=True, allow_none=False) + self.stitchBox = IntCtrl(self, -1, value=1, min=1, max=self.num_stitches, limited=True, allow_none=False) self.stitchBox.Bind(wx.EVT_TEXT, self.on_stitch_box) self.speedST = wx.StaticText(self, -1, label='', style=wx.ALIGN_CENTER) + self.commandST = wx.StaticText(self, -1, label='', style=wx.ALIGN_CENTER) # Layout self.vbSizer = vbSizer = wx.BoxSizer(wx.VERTICAL) @@ -52,6 +63,8 @@ class ControlPanel(wx.Panel): vbSizer.Add(hbSizer1, 1, wx.EXPAND | wx.ALL, 3) hbSizer2.Add(self.speedST, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 2) hbSizer2.AddStretchSpacer(prop=1) + hbSizer2.Add(self.commandST, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 2) + hbSizer2.AddStretchSpacer(prop=1) hbSizer2.Add(self.btnMinus, 0, wx.ALL, 2) hbSizer2.Add(self.btnPlus, 0, wx.ALL, 2) hbSizer2.Add(self.direction, 0, wx.EXPAND | wx.ALL, 2) @@ -144,11 +157,12 @@ class ControlPanel(wx.Panel): if self.drawing_panel: self.drawing_panel.set_current_stitch(stitch) - def on_current_stitch(self, stitch): + def on_current_stitch(self, stitch, command): if self.current_stitch != stitch: self.current_stitch = stitch self.slider.SetValue(stitch) self.stitchBox.SetValue(stitch) + self.commandST.SetLabel(COMMAND_NAMES[command]) def set_stitch_label(self, stitch): self.st1.SetLabel("Stitch # %d/%d" % (stitch, self.num_stitches)) @@ -246,19 +260,19 @@ class DrawingPanel(wx.Panel): wx.CallLater(50, self.load, self.stitch_plan) def clamp_current_stitch(self): - if self.current_stitch < 0: - self.current_stitch = 0 + if self.current_stitch < 1: + self.current_stitch = 1 elif self.current_stitch > self.num_stitches: self.current_stitch = self.num_stitches def stop_if_at_end(self): - if self.direction == -1 and self.current_stitch == 0: + if self.direction == -1 and self.current_stitch == 1: self.stop() elif self.direction == 1 and self.current_stitch == self.num_stitches: self.stop() def start_if_not_at_end(self): - if self.direction == -1 and self.current_stitch > 0: + if self.direction == -1 and self.current_stitch > 1: self.go() elif self.direction == 1 and self.current_stitch < self.num_stitches: self.go() @@ -307,7 +321,7 @@ class DrawingPanel(wx.Panel): stitches = stitches[:self.current_stitch - stitch] if len(stitches) > 1: canvas.DrawLines(stitches) - last_stitch = stitches[-1] + last_stitch = stitches[-1] break self.last_frame_duration = time.time() - start @@ -326,8 +340,9 @@ class DrawingPanel(wx.Panel): dc.Clear() def load(self, stitch_plan): - self.last_frame_duration = 0 + self.current_stitch = 1 self.direction = 1 + self.last_frame_duration = 0 self.num_stitches = stitch_plan.num_stitches self.control_panel.set_num_stitches(self.num_stitches) self.minx, self.miny, self.maxx, self.maxy = stitch_plan.bounding_box @@ -378,20 +393,38 @@ class DrawingPanel(wx.Panel): self.pens = [] self.stitch_blocks = [] + # There is no 0th stitch, so add a place-holder. + self.commands = [None] + for color_block in stitch_plan: pen = self.color_to_pen(color_block.color) + stitch_block = [] + + for stitch in color_block: + # trim any whitespace on the left and top and scale to the + # pixel density + stitch_block.append((self.PIXEL_DENSITY * (stitch.x - self.minx), + self.PIXEL_DENSITY * (stitch.y - self.miny))) + + if stitch.trim: + self.commands.append(TRIM) + elif stitch.jump: + self.commands.append(JUMP) + elif stitch.stop: + self.commands.append(STOP) + elif stitch.color_change: + self.commands.append(COLOR_CHANGE) + else: + self.commands.append(STITCH) + + if stitch.trim or stitch.stop or stitch.color_change: + self.pens.append(pen) + self.stitch_blocks.append(stitch_block) + stitch_block = [] - for point_list in color_block_to_point_lists(color_block): + if stitch_block: self.pens.append(pen) - - points = [] - for x, y in point_list: - # trim any whitespace on the left and top and scale to the - # pixel density - points.append((self.PIXEL_DENSITY * (x - self.minx), - self.PIXEL_DENSITY * (y - self.miny))) - - self.stitch_blocks.append(points) + self.stitch_blocks.append(stitch_block) def set_speed(self, speed): self.speed = speed @@ -407,13 +440,13 @@ class DrawingPanel(wx.Panel): def set_current_stitch(self, stitch): self.current_stitch = stitch self.clamp_current_stitch() - self.control_panel.on_current_stitch(self.current_stitch) + self.control_panel.on_current_stitch(self.current_stitch, self.commands[self.current_stitch]) self.stop_if_at_end() self.Refresh() def restart(self): if self.direction == 1: - self.current_stitch = 0 + self.current_stitch = 1 elif self.direction == -1: self.current_stitch = self.num_stitches diff --git a/lib/stitch_plan/stitch_plan.py b/lib/stitch_plan/stitch_plan.py index c713b42e..808fa626 100644 --- a/lib/stitch_plan/stitch_plan.py +++ b/lib/stitch_plan/stitch_plan.py @@ -36,6 +36,12 @@ def patches_to_stitch_plan(patches, collapse_len=3.0 * PIXELS_PER_MM): # make a new block of our color color_block = stitch_plan.new_color_block(color=patch.color) + # always start a color with a JUMP to the first stitch position + color_block.add_stitch(patch.stitches[0], jump=True) + else: + if len(color_block) and (patch.stitches[0] - color_block.stitches[-1]).length() > collapse_len: + color_block.add_stitch(patch.stitches[0], jump=True) + color_block.add_stitches(patch.stitches, no_ties=patch.stitch_as_is) if patch.trim_after: -- cgit v1.2.3 From e56e99329a750f6b002c9230fbbd62518c65f083 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Mon, 27 Aug 2018 15:42:36 -0400 Subject: remove old code --- lib/simulator.py | 466 ------------------------------------------------------- 1 file changed, 466 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 18bf1d7e..d1db35e4 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -572,9 +572,6 @@ class EmbroiderySimulator(wx.Frame): target_duration = kwargs.pop('target_duration', None) wx.Frame.__init__(self, *args, **kwargs) - # self.status_bar = self.CreateStatusBar() - # self.status_bar.SetStatusText(text) - self.simulator_panel = SimulatorPanel(self, stitch_plan=stitch_plan, target_duration=target_duration, @@ -603,466 +600,3 @@ class EmbroiderySimulator(wx.Frame): def clear(self): self.simulator_panel.clear() - - -class OldEmbroiderySimulator(wx.Frame): - def __init__(self, *args, **kwargs): - stitch_plan = kwargs.pop('stitch_plan', None) - self.x_position = kwargs.pop('x_position', None) - self.on_close_hook = kwargs.pop('on_close', None) - self.frame_period = kwargs.pop('frame_period', 80) - self.stitches_per_frame = kwargs.pop('stitches_per_frame', 1) - self.target_duration = kwargs.pop('target_duration', None) - - self.margin = 30 - - screen_rect = self.get_current_screen_rect() - self.max_width = kwargs.pop('max_width', screen_rect[2]) - self.max_height = kwargs.pop('max_height', screen_rect[3]) - self.scale = 1 - - self.min_width = 600 - if self.max_width < self.min_width: - self.max_width = self.min_width - - self.load(stitch_plan) - - wx.Frame.__init__(self, *args, **kwargs) - - self.panel = wx.Panel(self, wx.ID_ANY) - self.panel.SetBackgroundStyle(wx.BG_STYLE_PAINT) - - self.SetBackgroundColour('white') - - self.slider_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.set_slider() - - self.button_sizer = wx.StdDialogButtonSizer() - self.button_label = ( - # Switch direction button (currently not in use - would this be better?) - #[_('>>'), _('Switch direction | Play reverse (arrow left) | Play forward (arrow right)'), self.animation_switch_direction], - [_('<<'), _('Play reverse (arrow left)'), self.animation_reverse], - [_('-'), _('Play one frame backward (+)'), self.animation_one_frame_back], - [_('+'), _('Play one frame forward (+)'), self.animation_one_frame_forward], - [_('>>'), _('Play forward (arrow right)'), self.animation_forward], - [_('^'), _('Speed up (arrow up)'), self.animation_speed_up], - [_('v'), _('Slow down (arrow down)'), self.animation_slow_down], - [_('Pause'), _('Pause (P)'), self.animation_pause], - [_('Restart'), _('Restart (R)'), self.animation_restart], - [_('Quit'), _('Close (Q)'), self.animation_quit]) - - self.buttons = [] - for i in range(0, len(self.button_label)): - self.buttons.append(wx.Button(self, -1, self.button_label[i][0])) - self.button_sizer.Add(self.buttons[i], 1, wx.EXPAND) - self.buttons[i].SetToolTip(self.button_label[i][1]) - self.buttons[i].Bind(wx.EVT_BUTTON, self.button_label[i][2]) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.sizer.Add(self.panel, 1, wx.EXPAND) - self.sizer.Add(self.slider_sizer, 0, wx.EXPAND) - self.sizer.Add(self.button_sizer, 0, wx.EXPAND) - self.SetSizer(self.sizer) - - self.calculate_dimensions() - - if self.target_duration: - self.adjust_speed(self.target_duration) - - self.buffer = wx.Bitmap( - self.width * self.scale + self.margin * 2, - self.height * self.scale + self.margin * 2) - self.dc = wx.BufferedDC() - self.dc.SelectObject(self.buffer) - self.canvas = wx.GraphicsContext.Create(self.dc) - - self.clear() - - self.current_frame = 0 - self.animation_direction = 1 - self.set_stitch_counter(0) - - shortcut_keys = [ - (wx.ACCEL_NORMAL, wx.WXK_RIGHT, self.animation_forward), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_RIGHT, self.animation_forward), - (wx.ACCEL_NORMAL, wx.WXK_LEFT, self.animation_reverse), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_LEFT, self.animation_reverse), - (wx.ACCEL_NORMAL, wx.WXK_UP, self.animation_speed_up), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_speed_up), - (wx.ACCEL_NORMAL, wx.WXK_DOWN, self.animation_slow_down), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_DOWN, self.animation_slow_down), - (wx.ACCEL_NORMAL, ord('+'), self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, ord('='), self.animation_one_frame_forward), - (wx.ACCEL_SHIFT, ord('='), self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, wx.WXK_ADD, self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ADD, self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_UP, self.animation_one_frame_forward), - (wx.ACCEL_NORMAL, ord('-'), self.animation_one_frame_back), - (wx.ACCEL_NORMAL, ord('_'), self.animation_one_frame_back), - (wx.ACCEL_NORMAL, wx.WXK_SUBTRACT, self.animation_one_frame_back), - (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, self.animation_one_frame_back), - (wx.ACCEL_NORMAL, ord('r'), self.animation_restart), - (wx.ACCEL_NORMAL, ord('p'), self.animation_pause), - (wx.ACCEL_NORMAL, wx.WXK_SPACE, self.animation_pause), - (wx.ACCEL_NORMAL, ord('q'), self.animation_quit)] - - accel_entries = [] - - for shortcut_key in shortcut_keys: - eventId = wx.NewId() - accel_entries.append((shortcut_key[0], shortcut_key[1], eventId)) - self.Bind(wx.EVT_MENU, shortcut_key[2], id=eventId) - - accel_table = wx.AcceleratorTable(accel_entries) - self.SetAcceleratorTable(accel_table) - - self.Bind(wx.EVT_SIZE, self.on_size) - self.Bind(wx.EVT_CLOSE, self.on_close) - self.Bind(wx.EVT_SLIDER, self.on_slider) - self.panel.Bind(wx.EVT_PAINT, self.on_paint) - - self.panel.SetFocus() - - self.timer = None - - self.last_pos = None - - def get_current_screen_rect(self): - current_screen = wx.Display.GetFromPoint(wx.GetMousePosition()) - display = wx.Display(current_screen) - screen_rect = display.GetClientArea() - return screen_rect - - def load(self, stitch_plan=None): - if stitch_plan: - self.mirror = False - self.stitch_plan_to_lines(stitch_plan) - self.move_to_top_left() - return - - def adjust_speed(self, duration): - self.frame_period = 1000 * float(duration) / len(self.lines) - self.stitches_per_frame = 1 - - while self.frame_period < 1.0: - self.frame_period *= 2 - self.stitches_per_frame *= 2 - - # Switch direction button (currently not in use - would this be better?) - def animation_switch_direction(self, event): - direction_button = event.GetEventObject() - lbl = direction_button.GetLabel() - if self.animation_direction == 1: - self.animation_reverse('backward') - direction_button.SetLabel('<<') - else: - self.animation_forward('forward') - direction_button.SetLabel('>>') - - def animation_forward(self, event): - self.animation_direction = 1 - if not self.timer.IsRunning(): - self.timer.StartOnce(self.frame_period) - - def animation_reverse(self, event): - self.animation_direction = -1 - if not self.timer.IsRunning(): - self.timer.StartOnce(self.frame_period) - - def animation_one_frame_forward(self, event): - if self.current_frame < len(self.lines): - self.timer.Stop() - self.current_frame = self.current_frame + 1 - self.draw_one_frame() - self.set_stitch_counter(self.current_frame) - self.set_stitch_slider(self.current_frame) - - def animation_one_frame_back(self, event): - if self.current_frame > 1: - self.timer.Stop() - self.current_frame = self.current_frame - 1 - self.draw_one_frame() - self.set_stitch_counter(self.current_frame) - self.set_stitch_slider(self.current_frame) - - def animation_speed_up(self, event): - if self.stitches_per_frame <= 1280: - if self.frame_period == 1: - self.stitches_per_frame *= 2 - else: - self.frame_period = self.frame_period / 2 - self.animation_update_timer() - - def animation_slow_down(self, event): - if self.frame_period <= 1280: - if self.stitches_per_frame == 1: - self.frame_period *= 2 - else: - self.stitches_per_frame /= 2 - self.animation_update_timer() - - def animation_restart(self, event): - self.current_frame = 1 - self.stop() - self.clear() - self.go() - - def animation_pause(self, event): - if self.timer.IsRunning(): - self.timer.Stop() - else: - self.timer.StartOnce(self.frame_period) - - def animation_quit(self, event): - self.Close() - - def animation_update_timer(self): - self.frame_period = max(1, self.frame_period) - self.stitches_per_frame = max(self.stitches_per_frame, 1) - self.set_stitch_counter(self.current_frame) - if self.timer.IsRunning(): - self.timer.Stop() - self.timer.StartOnce(self.frame_period) - - def set_stitch_counter(self, current_frame): - self.dc.SetTextForeground('red') - stitch_counter_text = _("Stitch # ") + \ - str(current_frame) + ' / ' + str(len(self.lines)) - self.dc.DrawText(stitch_counter_text, 30, 5) - - def on_slider(self, event): - self.panel.SetFocus() - self.draw_one_frame() - obj = event.GetEventObject() - self.current_frame = obj.GetValue() - self.animation_update_timer() - - def set_slider(self): - self.stitch_slider = wx.Slider( - self, value=1, minValue=1, maxValue=len( - self.lines), style=wx.SL_HORIZONTAL | wx.SL_LABELS) - self.slider_sizer.Add(self.stitch_slider, 1, wx.EXPAND) - - def set_stitch_slider(self, val): - self.stitch_slider.SetValue(val) - - def _strip_quotes(self, string): - if string.startswith('"') and string.endswith('"'): - string = string[1:-1] - - return string - - def color_to_pen(self, color): - return wx.Pen(color.visible_on_white.rgb) - - def stitch_plan_to_lines(self, stitch_plan): - self.pens = [] - self.lines = [] - - for color_block in stitch_plan: - pen = self.color_to_pen(color_block.color) - - for i, point_list in enumerate( - color_block_to_point_lists(color_block)): - if i == 0: - # add the first stitch - first_x, first_y = point_list[0] - self.lines.append((first_x, first_y, first_x, first_y)) - self.pens.append(pen) - - # if there's only one point, there's nothing to do, so skip - if len(point_list) < 2: - continue - - for start, end in izip(point_list[:-1], point_list[1:]): - line = (start[0], start[1], end[0], end[1]) - self.lines.append(line) - self.pens.append(pen) - - def move_to_top_left(self): - """remove any unnecessary whitespace around the design""" - - min_x = sys.maxsize - min_y = sys.maxsize - - for x1, y1, x2, y2 in self.lines: - min_x = min(min_x, x2) - min_y = min(min_y, y2) - - new_lines = [] - - for line in self.lines: - (start, end, start1, end1) = line - new_lines.append( - (start - min_x, - end - min_y, - start1 - min_x, - end1 - min_y)) - - self.lines = new_lines - - def calculate_dimensions(self): - # 0.01 avoids a division by zero below for designs with no width or - # height (e.g. a straight vertical or horizontal line) - width = 0.01 - height = 0.01 - - for x1, y1, x2, y2 in self.lines: - width = max(width, x2) - height = max(height, y2) - - self.width = width - self.height = height - - button_width, button_height = self.buttons[0].GetSize() - slider_width, slider_height = self.stitch_slider.GetSize() - self.controls_height = button_height + slider_height - - self.scale = min( - float( - self.max_width - - self.margin * - 2) / - width, - float( - self.max_height - - self.margin * - 2 - - self.controls_height) / - height) - - # make room for decorations and the margin - self.scale *= 0.95 - - for i, point in enumerate(self.lines): - x1, x2, y1, y2 = point - x1 = x1 * self.scale + self.margin - y1 = y1 * self.scale + self.margin - x2 = x2 * self.scale + self.margin - y2 = y2 * self.scale + self.margin - - self.lines[i] = (x1, x2, y1, y2) - - def go(self): - self.clear() - - self.current_frame = 0 - - if not self.timer: - self.timer = wx.PyTimer(self.iterate_frames) - - self.timer.StartOnce(self.frame_period) - - def on_close(self, event): - self.stop() - - if self.on_close_hook: - self.on_close_hook() - - # If we keep a reference here, wx crashes when the process exits. - self.canvas = None - - self.Destroy() - - def stop(self): - if self.timer: - self.timer.Stop() - - 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 - window_width, window_height = self.GetSize() - client_width, client_height = self.GetClientSize() - - decorations_width = window_width - client_width - decorations_height = window_height - client_height - - setsize_window_width = self.width * self.scale + \ - decorations_width + self.margin * 2 - setsize_window_height = self.height * self.scale + \ - decorations_height + self.controls_height + self.margin * 2 - - # set minimum width (force space for control buttons) - if setsize_window_width < self.min_width: - setsize_window_width = self.min_width - - self.SetSize((setsize_window_width, setsize_window_height)) - - # center the simulation on screen if not called by params - # else center vertically - if self.x_position is None: - self.Centre() - else: - display_rect = self.get_current_screen_rect() - self.SetPosition( - (self.x_position, - display_rect[3] / - 2 - - setsize_window_height / - 2)) - - e.Skip() - - def on_paint(self, e): - dc = wx.AutoBufferedPaintDC(self.panel) - dc.Blit( - 0, - 0, - self.buffer.GetWidth(), - self.buffer.GetHeight(), - self.dc, - 0, - 0) - - self.last_pos_x, self.last_pos_y, self.last_pos_x1, self.last_pos_y1 = self.lines[0] - - if hasattr(self, 'visible_lines'): - if len(self.visible_lines) > 0: - self.last_pos_x1, self.last_pos_y1, self.last_pos_x, self.last_pos_y = self.visible_lines[-1] - - dc.DrawLine( - self.last_pos_x - 10, - self.last_pos_y, - self.last_pos_x + 10, - self.last_pos_y) - dc.DrawLine( - self.last_pos_x, - self.last_pos_y - 10, - self.last_pos_x, - self.last_pos_y + 10) - - def iterate_frames(self): - self.current_frame += self.stitches_per_frame * self.animation_direction - - if self.current_frame <= len(self.lines) and self.current_frame >= 1: - # calculate time_to_next_frame - start = time.time() - self.draw_one_frame() - duration = time.time() - start - duration_ms = int(duration * 1000) - time_to_next_frame = self.frame_period - duration_ms - time_to_next_frame = max(1, time_to_next_frame) - self.timer.StartOnce(time_to_next_frame) - elif self.current_frame > len(self.lines): - self.current_frame = len(self.lines) - self.draw_one_frame() - elif self.current_frame < 1: - self.current_frame = 1 - self.draw_one_frame() - else: - self.timer.Stop() - - self.set_stitch_counter(self.current_frame) - self.set_stitch_slider(self.current_frame) - - def draw_one_frame(self): - self.clear() - self.visible_lines = self.lines[:self.current_frame] - self.dc.DrawLineList(self.visible_lines, - self.pens[:self.current_frame]) -- cgit v1.2.3 From 7eb36c5fc6dc4cd36a136a1858096d9523945c82 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Mon, 27 Aug 2018 15:51:27 -0400 Subject: buttons for backward and forward one stitch --- lib/simulator.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index d1db35e4..7789ec91 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -38,6 +38,10 @@ class ControlPanel(wx.Panel): self.btnMinus.Bind(wx.EVT_BUTTON, self.animation_slow_down) self.btnPlus = wx.Button(self, -1, label='+') self.btnPlus.Bind(wx.EVT_BUTTON, self.animation_speed_up) + self.btnBackwardStitch = wx.Button(self, -1, label='<|') + self.btnBackwardStitch.Bind(wx.EVT_BUTTON, self.animation_one_stitch_backward) + self.btnForwardStitch = wx.Button(self, -1, label='|>') + self.btnForwardStitch.Bind(wx.EVT_BUTTON, self.animation_one_stitch_forward) self.direction = wx.Button(self, -1, label='>>') self.direction.Bind(wx.EVT_BUTTON, self.on_direction_button) self.pauseBtn = wx.Button(self, -1, label='Pause') @@ -67,6 +71,8 @@ class ControlPanel(wx.Panel): hbSizer2.AddStretchSpacer(prop=1) hbSizer2.Add(self.btnMinus, 0, wx.ALL, 2) hbSizer2.Add(self.btnPlus, 0, wx.ALL, 2) + hbSizer2.Add(self.btnBackwardStitch, 0, wx.ALL, 2) + hbSizer2.Add(self.btnForwardStitch, 0, wx.ALL, 2) hbSizer2.Add(self.direction, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.pauseBtn, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.restartBtn, 0, wx.EXPAND | wx.ALL, 2) -- cgit v1.2.3 From a636462803342683210bbeb64e49782209c2794f Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Mon, 27 Aug 2018 15:54:06 -0400 Subject: i18n --- lib/simulator.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 7789ec91..5b497cd8 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -44,11 +44,11 @@ class ControlPanel(wx.Panel): self.btnForwardStitch.Bind(wx.EVT_BUTTON, self.animation_one_stitch_forward) self.direction = wx.Button(self, -1, label='>>') self.direction.Bind(wx.EVT_BUTTON, self.on_direction_button) - self.pauseBtn = wx.Button(self, -1, label='Pause') + self.pauseBtn = wx.Button(self, -1, label=_('Pause')) self.pauseBtn.Bind(wx.EVT_BUTTON, self.on_pause_start_button) - self.restartBtn = wx.Button(self, -1, label='Restart') + self.restartBtn = wx.Button(self, -1, label=_('Restart')) self.restartBtn.Bind(wx.EVT_BUTTON, self.animation_restart) - self.quitBtn = wx.Button(self, -1, label='Quit') + self.quitBtn = wx.Button(self, -1, label=_('Quit')) self.quitBtn.Bind(wx.EVT_BUTTON, self.animation_quit) self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=self.num_stitches, style=wx.SL_HORIZONTAL | wx.SL_LABELS) @@ -150,7 +150,7 @@ class ControlPanel(wx.Panel): def set_speed(self, speed): self.speed = int(max(speed, 1)) - self.speedST.SetLabel('Speed: %s stitches/sec' % self.speed) + self.speedST.SetLabel(_('Speed: %d stitches/sec') % self.speed) self.hbSizer2.Layout() if self.drawing_panel: @@ -170,9 +170,6 @@ class ControlPanel(wx.Panel): self.stitchBox.SetValue(stitch) self.commandST.SetLabel(COMMAND_NAMES[command]) - def set_stitch_label(self, stitch): - self.st1.SetLabel("Stitch # %d/%d" % (stitch, self.num_stitches)) - def on_stitch_box(self, event): stitch = self.stitchBox.GetValue() self.slider.SetValue(stitch) @@ -195,14 +192,14 @@ class ControlPanel(wx.Panel): self.drawing_panel.go() def on_start(self): - self.pauseBtn.SetLabel('Pause') + self.pauseBtn.SetLabel(_('Pause')) def on_stop(self): - self.pauseBtn.SetLabel('Start') + self.pauseBtn.SetLabel(_('Start')) def on_pause_start_button(self, event): """""" - if self.pauseBtn.GetLabel() == 'Pause': + if self.pauseBtn.GetLabel() == _('Pause'): self.animation_pause() else: self.animation_start() -- cgit v1.2.3 From ab656800a067b9ebbe7f200ade0e5a5006da1cda Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Mon, 27 Aug 2018 16:15:58 -0400 Subject: fix windows issue --- lib/simulator.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 5b497cd8..0b805acf 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -50,10 +50,10 @@ class ControlPanel(wx.Panel): self.restartBtn.Bind(wx.EVT_BUTTON, self.animation_restart) self.quitBtn = wx.Button(self, -1, label=_('Quit')) self.quitBtn.Bind(wx.EVT_BUTTON, self.animation_quit) - self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=self.num_stitches, + self.slider = wx.Slider(self, -1, value=1, minValue=1, maxValue=2, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.slider.Bind(wx.EVT_SLIDER, self.on_slider) - self.stitchBox = IntCtrl(self, -1, value=1, min=1, max=self.num_stitches, limited=True, allow_none=False) + self.stitchBox = IntCtrl(self, -1, value=1, min=1, max=2, limited=True, allow_none=False) self.stitchBox.Bind(wx.EVT_TEXT, self.on_stitch_box) self.speedST = wx.StaticText(self, -1, label='', style=wx.ALIGN_CENTER) self.commandST = wx.StaticText(self, -1, label='', style=wx.ALIGN_CENTER) @@ -121,6 +121,9 @@ class ControlPanel(wx.Panel): self.drawing_panel.set_speed(self.speed) def set_num_stitches(self, num_stitches): + if num_stitches < 2: + # otherwise the slider and intctrl get mad + num_stitches = 2 self.num_stitches = num_stitches self.stitchBox.SetMax(num_stitches) self.slider.SetMax(num_stitches) -- cgit v1.2.3 From 8d196ace7fb01d2ac011d1c685ff422ef891320c Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Mon, 27 Aug 2018 16:43:23 -0400 Subject: position params's simulator window at the top of the screen --- lib/extensions/params.py | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/extensions/params.py b/lib/extensions/params.py index 73ce069d..c9c994c9 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -430,6 +430,7 @@ class SettingsFrame(wx.Frame): 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() -- cgit v1.2.3 From e749fdc781d1cf7518e120e512ccbf0a313414c6 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Mon, 27 Aug 2018 20:57:49 -0400 Subject: reverse the >> button --- lib/simulator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 0b805acf..c1f86905 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -42,7 +42,7 @@ class ControlPanel(wx.Panel): self.btnBackwardStitch.Bind(wx.EVT_BUTTON, self.animation_one_stitch_backward) self.btnForwardStitch = wx.Button(self, -1, label='|>') self.btnForwardStitch.Bind(wx.EVT_BUTTON, self.animation_one_stitch_forward) - self.direction = wx.Button(self, -1, label='>>') + self.direction = wx.Button(self, -1, label='<<') self.direction.Bind(wx.EVT_BUTTON, self.on_direction_button) self.pauseBtn = wx.Button(self, -1, label=_('Pause')) self.pauseBtn.Bind(wx.EVT_BUTTON, self.on_pause_start_button) @@ -147,9 +147,9 @@ class ControlPanel(wx.Panel): evtObj = event.GetEventObject() lbl = evtObj.GetLabel() if lbl == '>>': - self.animation_reverse() - else: self.animation_forward() + else: + self.animation_reverse() def set_speed(self, speed): self.speed = int(max(speed, 1)) -- cgit v1.2.3 From 5f29e5a4a52ae8e5a434676648b0baa6253bd325 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Mon, 27 Aug 2018 21:56:25 -0400 Subject: show negative speed when animating backward --- lib/simulator.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index c1f86905..c797d221 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -32,6 +32,7 @@ class ControlPanel(wx.Panel): self.num_stitches = 1 self.current_stitch = 1 self.speed = 1 + self.direction = 1 # Widgets self.btnMinus = wx.Button(self, -1, label='-') @@ -42,8 +43,8 @@ class ControlPanel(wx.Panel): self.btnBackwardStitch.Bind(wx.EVT_BUTTON, self.animation_one_stitch_backward) self.btnForwardStitch = wx.Button(self, -1, label='|>') self.btnForwardStitch.Bind(wx.EVT_BUTTON, self.animation_one_stitch_forward) - self.direction = wx.Button(self, -1, label='<<') - self.direction.Bind(wx.EVT_BUTTON, self.on_direction_button) + self.directionBtn = wx.Button(self, -1, label='<<') + self.directionBtn.Bind(wx.EVT_BUTTON, self.on_direction_button) self.pauseBtn = wx.Button(self, -1, label=_('Pause')) self.pauseBtn.Bind(wx.EVT_BUTTON, self.on_pause_start_button) self.restartBtn = wx.Button(self, -1, label=_('Restart')) @@ -73,7 +74,7 @@ class ControlPanel(wx.Panel): hbSizer2.Add(self.btnPlus, 0, wx.ALL, 2) hbSizer2.Add(self.btnBackwardStitch, 0, wx.ALL, 2) hbSizer2.Add(self.btnForwardStitch, 0, wx.ALL, 2) - hbSizer2.Add(self.direction, 0, wx.EXPAND | wx.ALL, 2) + hbSizer2.Add(self.directionBtn, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.pauseBtn, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.restartBtn, 0, wx.EXPAND | wx.ALL, 2) hbSizer2.Add(self.quitBtn, 0, wx.EXPAND | wx.ALL, 2) @@ -136,29 +137,37 @@ class ControlPanel(wx.Panel): self.set_speed(self.target_stitches_per_second) def animation_forward(self, event=None): - self.direction.SetLabel(">>") + self.directionBtn.SetLabel("<<") self.drawing_panel.forward() + self.direction = 1 + self.update_speed_text() def animation_reverse(self, event=None): - self.direction.SetLabel("<<") + self.directionBtn.SetLabel(">>") self.drawing_panel.reverse() + self.direction = -1 + self.update_speed_text() def on_direction_button(self, event): evtObj = event.GetEventObject() lbl = evtObj.GetLabel() - if lbl == '>>': + if self.direction == 1: self.animation_forward() else: self.animation_reverse() def set_speed(self, speed): self.speed = int(max(speed, 1)) - self.speedST.SetLabel(_('Speed: %d stitches/sec') % self.speed) - self.hbSizer2.Layout() + self.update_speed_text() if self.drawing_panel: self.drawing_panel.set_speed(self.speed) + def update_speed_text(self): + self.speedST.SetLabel(_('Speed: %d stitches/sec') % (self.speed * self.direction)) + self.hbSizer2.Layout() + + def on_slider(self, event): stitch = event.GetEventObject().GetValue() self.stitchBox.SetValue(stitch) -- cgit v1.2.3 From 3fe3399d909de6549a7ce64f4347b342933b2465 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sat, 1 Sep 2018 13:35:47 -0400 Subject: simulator standalone mode --- lib/extensions/simulate.py | 20 ++------------------ lib/simulator.py | 28 ++++++++++++++++++++++++++-- lib/stitch_plan/__init__.py | 3 ++- lib/stitch_plan/read_file.py | 21 +++++++++++++++++++++ 4 files changed, 51 insertions(+), 21 deletions(-) create mode 100644 lib/stitch_plan/read_file.py (limited to 'lib') diff --git a/lib/extensions/simulate.py b/lib/extensions/simulate.py index dcb5e604..e23d391b 100644 --- a/lib/extensions/simulate.py +++ b/lib/extensions/simulate.py @@ -1,8 +1,6 @@ -import wx - from .base import InkstitchExtension from ..i18n import _ -from ..simulator import EmbroiderySimulator +from ..simulator import show_simulator from ..stitch_plan import patches_to_stitch_plan @@ -19,18 +17,4 @@ class Simulate(InkstitchExtension): return patches = self.elements_to_patches(self.elements) stitch_plan = patches_to_stitch_plan(patches) - app = wx.App() - current_screen = wx.Display.GetFromPoint(wx.GetMousePosition()) - display = wx.Display(current_screen) - screen_rect = display.GetClientArea() - - simulator_pos = (screen_rect[0], screen_rect[1]) - - # subtract 1 because otherwise the window becomes maximized on Linux - 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) - app.SetTopWindow(frame) - frame.Show() - app.MainLoop() + show_simulator(stitch_plan) diff --git a/lib/simulator.py b/lib/simulator.py index c797d221..8f316be3 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -4,8 +4,9 @@ from wx.lib.intctrl import IntCtrl import time from itertools import izip -from .svg import color_block_to_point_lists, PIXELS_PER_MM +from .svg import PIXELS_PER_MM from .i18n import _ +from .stitch_plan import stitch_plan_from_file # L10N command label at bottom of simulator window COMMAND_NAMES = [_("STITCH"), _("JUMP"), _("TRIM"), _("STOP"), _("COLOR CHANGE")] @@ -330,7 +331,8 @@ class DrawingPanel(wx.Panel): canvas.SetPen(pen) if stitch + len(stitches) < self.current_stitch: stitch += len(stitches) - canvas.DrawLines(stitches) + if len(stitches) > 1: + canvas.DrawLines(stitches) last_stitch = stitches[-1] else: stitches = stitches[:self.current_stitch - stitch] @@ -615,3 +617,25 @@ class EmbroiderySimulator(wx.Frame): def clear(self): self.simulator_panel.clear() + +def show_simulator(stitch_plan): + app = wx.App() + current_screen = wx.Display.GetFromPoint(wx.GetMousePosition()) + display = wx.Display(current_screen) + screen_rect = display.GetClientArea() + + simulator_pos = (screen_rect[0], screen_rect[1]) + + # subtract 1 because otherwise the window becomes maximized on Linux + 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) + app.SetTopWindow(frame) + frame.Show() + app.MainLoop() + + +if __name__ == "__main__": + stitch_plan = stitch_plan_from_file(sys.argv[1]) + show_simulator(stitch_plan) diff --git a/lib/stitch_plan/__init__.py b/lib/stitch_plan/__init__.py index 791a5f20..2aaa0ab9 100644 --- a/lib/stitch_plan/__init__.py +++ b/lib/stitch_plan/__init__.py @@ -1,2 +1,3 @@ -from stitch_plan import patches_to_stitch_plan, StitchPlan, ColorBlock +from .stitch_plan import patches_to_stitch_plan, StitchPlan, ColorBlock from .stitch import Stitch +from .read_file import stitch_plan_from_file diff --git a/lib/stitch_plan/read_file.py b/lib/stitch_plan/read_file.py new file mode 100644 index 00000000..ff5a68ac --- /dev/null +++ b/lib/stitch_plan/read_file.py @@ -0,0 +1,21 @@ +import pyembroidery +from .stitch_plan import StitchPlan + +from ..svg import PIXELS_PER_MM + + +def stitch_plan_from_file(embroidery_file): + """Read a machine embroidery file in any supported format and return a stitch plan.""" + pattern = pyembroidery.read(embroidery_file) + + stitch_plan = StitchPlan() + color_block = None + + for raw_stitches, thread in pattern.get_as_colorblocks(): + color_block = stitch_plan.new_color_block(thread) + for x, y, command in raw_stitches: + color_block.add_stitch(x * PIXELS_PER_MM / 10.0, y * PIXELS_PER_MM / 10.0, + jump=(command == pyembroidery.JUMP), + trim=(command == pyembroidery.TRIM)) + + return stitch_plan -- cgit v1.2.3 From 9360e9b9304a6b9a50c5586a04ebf0a13859d5fe Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sat, 1 Sep 2018 14:22:46 -0400 Subject: fix code style --- lib/extensions/simulate.py | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/extensions/simulate.py b/lib/extensions/simulate.py index e23d391b..f962b206 100644 --- a/lib/extensions/simulate.py +++ b/lib/extensions/simulate.py @@ -1,5 +1,4 @@ from .base import InkstitchExtension -from ..i18n import _ from ..simulator import show_simulator from ..stitch_plan import patches_to_stitch_plan -- cgit v1.2.3 From 7b5995c7052c8fe2b67944fea75b8ec543464be1 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Mon, 10 Sep 2018 23:06:18 -0400 Subject: fix logic --- lib/simulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/simulator.py b/lib/simulator.py index 8f316be3..4408adb8 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -373,7 +373,7 @@ class DrawingPanel(wx.Panel): def choose_zoom_and_pan(self, event=None): # ignore if called before we load the stitch plan - if not self.width or not self.height: + if not self.width and not self.height: return panel_width, panel_height = self.GetClientSize() -- cgit v1.2.3