WIP: revamp UI and rendering algorithm

pull/284/head
Lex Neva 2018-08-25 21:54:11 -04:00
rodzic 11d3cea80c
commit bf70fd9031
2 zmienionych plików z 328 dodań i 20 usunięć

Wyświetl plik

@ -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)

Wyświetl plik

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2018-08-25 11:47-0400\n"
"POT-Creation-Date: 2018-08-25 21:54-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -674,79 +674,79 @@ msgstr ""
msgid "Generate INX files"
msgstr ""
#: lib/simulator.py:45
#: lib/simulator.py:353
msgid "<<"
msgstr ""
#: lib/simulator.py:45
#: lib/simulator.py:353
msgid "Play reverse (arrow left)"
msgstr ""
#: lib/simulator.py:46
#: lib/simulator.py:354
msgid "-"
msgstr ""
#: lib/simulator.py:46
#: lib/simulator.py:354
msgid "Play one frame backward (+)"
msgstr ""
#: lib/simulator.py:47
#: lib/simulator.py:355
msgid "+"
msgstr ""
#: lib/simulator.py:47
#: lib/simulator.py:355
msgid "Play one frame forward (+)"
msgstr ""
#: lib/simulator.py:48
#: lib/simulator.py:356
msgid ">>"
msgstr ""
#: lib/simulator.py:48
#: lib/simulator.py:356
msgid "Play forward (arrow right)"
msgstr ""
#: lib/simulator.py:49
#: lib/simulator.py:357
msgid "^"
msgstr ""
#: lib/simulator.py:49
#: lib/simulator.py:357
msgid "Speed up (arrow up)"
msgstr ""
#: lib/simulator.py:50
#: lib/simulator.py:358
msgid "v"
msgstr ""
#: lib/simulator.py:50
#: lib/simulator.py:358
msgid "Slow down (arrow down)"
msgstr ""
#: lib/simulator.py:51
#: lib/simulator.py:359
msgid "Pause"
msgstr ""
#: lib/simulator.py:51
#: lib/simulator.py:359
msgid "Pause (P)"
msgstr ""
#: lib/simulator.py:52
#: lib/simulator.py:360
msgid "Restart"
msgstr ""
#: lib/simulator.py:52
#: lib/simulator.py:360
msgid "Restart (R)"
msgstr ""
#: lib/simulator.py:53
#: lib/simulator.py:361
msgid "Quit"
msgstr ""
#: lib/simulator.py:53
#: lib/simulator.py:361
msgid "Close (Q)"
msgstr ""
#: lib/simulator.py:231
#: lib/simulator.py:539
msgid "Stitch # "
msgstr ""