kopia lustrzana https://github.com/inkstitch/inkstitch
Merge remote-tracking branch 'origin/master' into lexelby-e-stitch
commit
f749c4c1e8
42
.travis.yml
42
.travis.yml
|
@ -23,6 +23,11 @@ matrix:
|
|||
sudo: required
|
||||
env: BUILD=windows
|
||||
if: tag =~ ^v[0-9.]+$ OR branch != master
|
||||
- language: generic
|
||||
os: osx
|
||||
sudo: required
|
||||
env: BUILD=osx
|
||||
if: tag =~ ^v[0-9.]+$ OR branch != master
|
||||
branches:
|
||||
except:
|
||||
- /^dev-build-/
|
||||
|
@ -89,6 +94,31 @@ install:
|
|||
|
||||
wine c:\\Python\\python.exe c:\\Python\\scripts\\pip.exe install -r requirements.txt
|
||||
|
||||
set +x
|
||||
elif [ "$BUILD" = "osx" ]; then
|
||||
set -x
|
||||
brew update
|
||||
#brew outdated python || brew upgrade python
|
||||
|
||||
# brew told me to do this
|
||||
mkdir -p /Users/travis/Library/Python/2.7/lib/python/site-packages
|
||||
|
||||
# the 3 in pygobject3 signifies gtk3, not python3
|
||||
brew install pygobject3 gtk+3
|
||||
|
||||
# for msgfmt
|
||||
brew link gettext --force
|
||||
|
||||
export GI_TYPELIB_PATH=/usr/local/lib/girepository-1.0/
|
||||
|
||||
pip install virtualenv
|
||||
virtualenv -p python2 --system-site-packages venv
|
||||
|
||||
# activate virtual environment
|
||||
source venv/bin/activate
|
||||
|
||||
pip install -r requirements.txt
|
||||
pip install pyinstaller
|
||||
set +x
|
||||
elif [ -n "$LINT" ]; then
|
||||
pip install flake8
|
||||
|
@ -97,11 +127,19 @@ before_script:
|
|||
- "echo LINT: $LINT BUILD: $BUILD"
|
||||
script:
|
||||
- |
|
||||
set -e
|
||||
if [ -n "$BUILD" -a "$DEBUG_BUILD" = "$BUILD" ]; then
|
||||
mkdir .ssh
|
||||
echo -e "${SSH_KEY}" > .ssh/id_rsa
|
||||
chmod -R go-rwx .ssh
|
||||
mkfifo fifo
|
||||
( while :; do cat fifo | /bin/bash -i 2>&1 | nc -l 127.0.0.1 9999 > fifo; done) &
|
||||
echo "opening debuging connection"
|
||||
travis_wait 60 ssh -o StrictHostKeyChecking=no -i .ssh/id_rsa -N -R 9999:localhost:9999 debug@lex.gd
|
||||
fi
|
||||
if [ -n "$LINT" ]; then
|
||||
flake8 . --count --exit-zero --select=E901,E999,F821,F822,F823 --show-source --statistics --exclude=embroidermodder
|
||||
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --exclude=embroidermodder
|
||||
elif [ "$BUILD" = "linux" ]; then
|
||||
elif [ "$BUILD" = "linux" -o "$BUILD" = "osx" ]; then
|
||||
make dist
|
||||
elif [ "$BUILD" = "windows" ]; then
|
||||
# work around some bug... pyinstaller? shapely? not sure.
|
||||
|
|
4
Makefile
4
Makefile
|
@ -2,7 +2,7 @@ EXTENSIONS:=inkstitch
|
|||
|
||||
# This gets the branch name or the name of the tag
|
||||
VERSION:=$(TRAVIS_BRANCH)
|
||||
OS:=$(shell uname)
|
||||
OS:=$(TRAVIS_OS_NAME)
|
||||
ARCH:=$(shell uname -m)
|
||||
|
||||
dist: distclean locales
|
||||
|
@ -17,7 +17,7 @@ dist: distclean locales
|
|||
if [ "$$BUILD" = "windows" ]; then \
|
||||
cd dist; zip -r ../inkstitch-$(VERSION)-win32.zip *; \
|
||||
else \
|
||||
cd dist; tar zcf ../inkstitch-$(VERSION)-$(OS)-$(ARCH).tar.gz *; \
|
||||
cd dist; tar zcf ../inkstitch-$(VERSION)-$(OS)-$(ARCH).tar.gz *; \
|
||||
fi
|
||||
|
||||
distclean:
|
||||
|
|
|
@ -10,7 +10,7 @@ Want to learn more?
|
|||
|
||||
* Check out our list of [features](https://inkstitch.org/features/)
|
||||
* [Quick Install](https://inkstitch.org/docs/install/) on Linux and Windows (Mac support in the works!)
|
||||
* See some [photos](https://inkstitch.org/tutorials/inspiration/lexelby/) showing what Ink/Stitch can do
|
||||
* See some [photos](https://inkstitch.org/tutorials/inspiration/) showing what Ink/Stitch can do
|
||||
* Watch some [videos](https://inkstitch.org/tutorials/video/) of Ink/Stitch in action
|
||||
* ...and lots more on our [website](https://inkstitch.org)
|
||||
|
||||
|
|
|
@ -22,6 +22,12 @@ pyinstaller_args+="--hidden-import gi.repository.Gtk "
|
|||
# mac and windows build seem to miss wx import
|
||||
pyinstaller_args+="--hidden-import wx "
|
||||
|
||||
# We need to use the precompiled bootloader linked with graphical Mac OS X
|
||||
# libraries if we develop a GUI application for Mac:
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
pyinstaller_args+="--windowed "
|
||||
fi
|
||||
|
||||
# This lets pyinstaller see inkex.py, etc.
|
||||
pyinstaller_args+="-p inkscape-0.92.3/share/extensions "
|
||||
|
||||
|
@ -45,6 +51,11 @@ mkdir dist/bin
|
|||
mv dist/inkstitch/* dist/bin
|
||||
mv dist/bin dist/inkstitch
|
||||
|
||||
# on Mac, pyinstaller creates a .app version as well, but we don't need that
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
rm -rf dist/inkstitch.app/
|
||||
fi
|
||||
|
||||
# Inkscape doesn't let us run native binaries as extensions(?!). Instead we
|
||||
# add this stub script which executes the binary that pyinstaller creates.
|
||||
cp stub.py dist/inkstitch.py
|
||||
|
|
|
@ -4,19 +4,19 @@
|
|||
<id>jonh.embroider</id>
|
||||
<dependency type="executable" location="extensions">inkstitch.py</dependency>
|
||||
<dependency type="executable" location="extensions">inkex.py</dependency>
|
||||
<param name="collapse_len_mm" type="float" min="0.0" max="10.0" _gui-text="Collapse length (mm)"> _gui-description="Jump stitches smaller than this will be treated as normal stitches.">3.0</param>
|
||||
<param name="hide_layers" type="boolean" _gui-text="Hide other layers" description="Hide all other top-level layers when the embroidery layer is generated, in order to make stitching discernable.">true</param>
|
||||
<param name="collapse_len_mm" type="float" min="0.0" max="10.0" _gui-text="Collapse length (mm)" _gui-description="Jump stitches smaller than this will be treated as normal stitches.">3.0</param>
|
||||
<param name="hide_layers" type="boolean" _gui-text="Hide other layers" _gui-description="Hide all other top-level layers when the embroidery layer is generated, in order to make stitching discernable.">true</param>
|
||||
<param name="output_format" type="optiongroup" _gui-text="Output file format" appearance="minimal">
|
||||
<_option value="dst">Tajima Embroidery Format(DST)</_option>
|
||||
<_option value="exp">Melco Embroidery Format(EXP)</_option>
|
||||
<_option value="jef">Janome Embroidery Format(JEF)</_option>
|
||||
<_option value="pec">Brother Embroidery Format(PEC)</_option>
|
||||
<_option value="pes">Brother Embroidery Format(PES)</_option>
|
||||
<_option value="vp3">Pfaff Embroidery Format(VP3)</_option>
|
||||
<_option value="csv">Comma-separated values(CSV) [DEBUG]</_option>
|
||||
<_option value="svg">Scalable Vector Graphics(SVG) [DEBUG]</_option>
|
||||
<_option value="dst">Tajima Embroidery Format (DST)</_option>
|
||||
<_option value="exp">Melco Embroidery Format (EXP)</_option>
|
||||
<_option value="jef">Janome Embroidery Format (JEF)</_option>
|
||||
<_option value="pec">Brother Embroidery Format (PEC)</_option>
|
||||
<_option value="pes">Brother Embroidery Format (PES)</_option>
|
||||
<_option value="vp3">Pfaff Embroidery Format (VP3)</_option>
|
||||
<_option value="csv">Comma-separated values (CSV) [DEBUG]</_option>
|
||||
<_option value="svg">Scalable Vector Graphics (SVG) [DEBUG]</_option>
|
||||
</param>
|
||||
<param name="path" type="string" _gui-text="Directory"></param>
|
||||
<param name="path" type="string" _gui-text="Directory" _gui-description="Leave empty to save the output in Inkscape's extension directory."></param>
|
||||
<param name="extension" type="string" gui-hidden="true">embroider</param>
|
||||
<effect>
|
||||
<object-type>all</object-type>
|
||||
|
|
|
@ -4,7 +4,7 @@ import shapely.geometry
|
|||
from .element import param, EmbroideryElement, Patch
|
||||
from ..i18n import _
|
||||
from ..utils import cache, Point
|
||||
from ..stitches import running_stitch
|
||||
from ..stitches import running_stitch, bean_stitch
|
||||
from ..svg import parse_length_with_units
|
||||
|
||||
warned_about_legacy_running_stitch = False
|
||||
|
@ -27,18 +27,28 @@ class Stroke(EmbroideryElement):
|
|||
return self.get_style("stroke-dasharray") is not None
|
||||
|
||||
@property
|
||||
@param('running_stitch_length_mm', _('Running stitch length'), unit='mm', type='float', default=1.5)
|
||||
@param('running_stitch_length_mm', _('Running stitch length'), unit='mm', type='float', default=1.5, sort_index=3)
|
||||
def running_stitch_length(self):
|
||||
return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01)
|
||||
|
||||
@property
|
||||
@param('zigzag_spacing_mm', _('Zig-zag spacing (peak-to-peak)'), unit='mm', type='float', default=0.4)
|
||||
@param('bean_stitch_repeats',
|
||||
_('Bean stitch number of repeats'),
|
||||
tooltip=_('Backtrack each stitch this many times. A value of 1 would triple each stitch (forward, back, forward). A value of 2 would quintuple each stitch, etc. Only applies to running stitch.'),
|
||||
type='int',
|
||||
default=0,
|
||||
sort_index=2)
|
||||
def bean_stitch_repeats(self):
|
||||
return self.get_int_param("bean_stitch_repeats", 0)
|
||||
|
||||
@property
|
||||
@param('zigzag_spacing_mm', _('Zig-zag spacing (peak-to-peak)'), unit='mm', type='float', default=0.4, sort_index=3)
|
||||
@cache
|
||||
def zigzag_spacing(self):
|
||||
return max(self.get_float_param("zigzag_spacing_mm", 0.4), 0.01)
|
||||
|
||||
@property
|
||||
@param('repeats', _('Repeats'), type='int', default="1")
|
||||
@param('repeats', _('Repeats'), type='int', default="1", sort_index=1)
|
||||
def repeats(self):
|
||||
return self.get_int_param("repeats", 1)
|
||||
|
||||
|
@ -58,7 +68,7 @@ class Stroke(EmbroideryElement):
|
|||
return shapely.geometry.MultiLineString(line_strings)
|
||||
|
||||
@property
|
||||
@param('manual_stitch', _('Manual stitch placement'), tooltip=_("Stitch every node in the path. Stitch length and zig-zag spacing are ignored."), type='boolean', default=False)
|
||||
@param('manual_stitch', _('Manual stitch placement'), tooltip=_("Stitch every node in the path. Stitch length and zig-zag spacing are ignored."), type='boolean', default=False, sort_index=0)
|
||||
def manual_stitch_mode(self):
|
||||
return self.get_boolean_param('manual_stitch')
|
||||
|
||||
|
@ -152,6 +162,10 @@ class Stroke(EmbroideryElement):
|
|||
patch = Patch(color=self.color, stitches=path, stitch_as_is=True)
|
||||
elif self.is_running_stitch():
|
||||
patch = self.running_stitch(path, self.running_stitch_length)
|
||||
|
||||
if self.bean_stitch_repeats > 0:
|
||||
patch.stitches = bean_stitch(patch.stitches, self.bean_stitch_repeats)
|
||||
|
||||
else:
|
||||
patch = self.simple_satin(path, self.zigzag_spacing, self.stroke_width)
|
||||
|
||||
|
|
|
@ -424,7 +424,7 @@ class SettingsFrame(wx.Frame):
|
|||
self.simulate_window.stop()
|
||||
self.simulate_window.load(stitch_plan=stitch_plan)
|
||||
else:
|
||||
my_rect = self.GetRect()
|
||||
my_rect = self.GetScreenRect()
|
||||
simulator_pos = my_rect.GetTopRight()
|
||||
simulator_pos.x += 5
|
||||
|
||||
|
|
|
@ -27,6 +27,26 @@ class EmbroiderySimulator(wx.Frame):
|
|||
self.panel = wx.Panel(self, wx.ID_ANY)
|
||||
self.panel.SetFocus()
|
||||
|
||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.button_label = (
|
||||
[_("Speed up"),_('Press + or arrow up to speed up')],
|
||||
[_("Slow down"),_('Press - or arrow down to slow down')],
|
||||
[_("Pause"),_("Press P to pause the animation")],
|
||||
[_("Restart"),_("Press R to restart the animation")],
|
||||
[_("Quit"),_("Press Q to close the simulation window")])
|
||||
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].Bind(wx.EVT_BUTTON, self.on_key_down)
|
||||
self.buttons[i].SetToolTip(self.button_label[i][1])
|
||||
|
||||
self.sizer.Add(self.panel, 1, wx.EXPAND)
|
||||
self.sizer.Add(self.button_sizer, 0, wx.EXPAND)
|
||||
self.SetSizer(self.sizer)
|
||||
|
||||
self.load(stitch_plan)
|
||||
|
||||
if self.target_duration:
|
||||
|
@ -68,26 +88,30 @@ class EmbroiderySimulator(wx.Frame):
|
|||
self.stitches_per_frame *= 2
|
||||
|
||||
def on_key_down(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if hasattr(event, 'GetKeyCode'):
|
||||
keycode = event.GetKeyCode()
|
||||
else:
|
||||
keycode = event.GetEventObject().GetLabelText()
|
||||
self.panel.SetFocus()
|
||||
|
||||
if keycode == ord("+") or keycode == ord("=") or keycode == wx.WXK_UP:
|
||||
if keycode == ord("+") or keycode == ord("=") or keycode == wx.WXK_UP or keycode == "Speed up":
|
||||
if self.frame_period == 1:
|
||||
self.stitches_per_frame *= 2
|
||||
else:
|
||||
self.frame_period = self.frame_period / 2
|
||||
elif keycode == ord("-") or keycode == ord("_") or keycode == wx.WXK_DOWN:
|
||||
elif keycode == ord("-") or keycode == ord("_") or keycode == wx.WXK_DOWN or keycode == "Slow down":
|
||||
if self.stitches_per_frame == 1:
|
||||
self.frame_period *= 2
|
||||
else:
|
||||
self.stitches_per_frame /= 2
|
||||
elif keycode == ord("Q"):
|
||||
elif keycode == ord("Q") or keycode == "Quit":
|
||||
self.Close()
|
||||
elif keycode == ord('P'):
|
||||
elif keycode == ord("P") or keycode == "Pause":
|
||||
if self.timer.IsRunning():
|
||||
self.timer.Stop()
|
||||
else:
|
||||
self.timer.Start(self.frame_period)
|
||||
elif keycode == ord("R"):
|
||||
elif keycode == ord("R") or keycode == "Restart":
|
||||
self.stop()
|
||||
self.clear()
|
||||
self.go()
|
||||
|
@ -170,7 +194,7 @@ class EmbroiderySimulator(wx.Frame):
|
|||
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.scale = min(float(self.max_width) / width, float(self.max_height) / height)
|
||||
self.scale = min(float(self.max_width) / width, float(self.max_height - 60) / height)
|
||||
|
||||
# make room for decorations and the margin
|
||||
self.scale *= 0.95
|
||||
|
@ -212,10 +236,15 @@ class EmbroiderySimulator(wx.Frame):
|
|||
client_width, client_height = self.GetClientSize()
|
||||
|
||||
decorations_width = window_width - client_width
|
||||
decorations_height = window_height - client_height
|
||||
decorations_height = window_height - client_height + 40
|
||||
|
||||
self.SetSize((self.width * self.scale + decorations_width + self.margin * 2,
|
||||
self.height * self.scale + decorations_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.margin * 2
|
||||
|
||||
if setsize_window_width < 600:
|
||||
setsize_window_width = 600
|
||||
|
||||
self.SetSize(( setsize_window_width, setsize_window_height))
|
||||
|
||||
e.Skip()
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from copy import copy
|
||||
|
||||
|
||||
""" Utility functions to produce running stitches. """
|
||||
|
||||
|
||||
|
@ -64,3 +67,29 @@ def running_stitch(points, stitch_length):
|
|||
output.append(segment_start)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def bean_stitch(stitches, repeats):
|
||||
"""Generate bean stitch from a set of stitches.
|
||||
|
||||
"Bean" stitch is made by backtracking each stitch to make it heaver. A
|
||||
simple bean stitch would be two stitches forward, one stitch back, two
|
||||
stitches forward, etc. This would result in each stitch being tripled.
|
||||
|
||||
We'll say that the above counts as 1 repeat. Backtracking each stitch
|
||||
repeatedly will result in a heavier bean stitch. There will always be
|
||||
an odd number of threads piled up for each stitch.
|
||||
"""
|
||||
|
||||
if len(stitches) < 2:
|
||||
return stitches
|
||||
|
||||
new_stitches = [stitches[0]]
|
||||
|
||||
for stitch in stitches:
|
||||
new_stitches.append(stitch)
|
||||
|
||||
for i in xrange(repeats):
|
||||
new_stitches.extend(copy(new_stitches[-2:]))
|
||||
|
||||
return new_stitches
|
||||
|
|
63
messages.po
63
messages.po
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2018-07-27 21:10-0400\n"
|
||||
"POT-Creation-Date: 2018-08-05 20:31-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"
|
||||
|
@ -104,7 +104,7 @@ msgstr ""
|
|||
msgid "\"E\" stitch"
|
||||
msgstr ""
|
||||
|
||||
#: lib/elements/satin_column.py:31 lib/elements/stroke.py:35
|
||||
#: lib/elements/satin_column.py:31 lib/elements/stroke.py:45
|
||||
msgid "Zig-zag spacing (peak-to-peak)"
|
||||
msgstr ""
|
||||
|
||||
|
@ -199,21 +199,32 @@ msgstr ""
|
|||
msgid "Running stitch length"
|
||||
msgstr ""
|
||||
|
||||
#: lib/elements/stroke.py:41
|
||||
#: lib/elements/stroke.py:36
|
||||
msgid "Bean stitch number of repeats"
|
||||
msgstr ""
|
||||
|
||||
#: lib/elements/stroke.py:37
|
||||
msgid ""
|
||||
"Backtrack each stitch this many times. A value of 1 would triple each "
|
||||
"stitch (forward, back, forward). A value of 2 would quintuple each "
|
||||
"stitch, etc. Only applies to running stitch."
|
||||
msgstr ""
|
||||
|
||||
#: lib/elements/stroke.py:51
|
||||
msgid "Repeats"
|
||||
msgstr ""
|
||||
|
||||
#: lib/elements/stroke.py:61
|
||||
#: lib/elements/stroke.py:71
|
||||
msgid "Manual stitch placement"
|
||||
msgstr ""
|
||||
|
||||
#: lib/elements/stroke.py:61
|
||||
#: lib/elements/stroke.py:71
|
||||
msgid ""
|
||||
"Stitch every node in the path. Stitch length and zig-zag spacing are "
|
||||
"ignored."
|
||||
msgstr ""
|
||||
|
||||
#: lib/elements/stroke.py:92
|
||||
#: lib/elements/stroke.py:102
|
||||
msgid ""
|
||||
"Legacy running stitch setting detected!\n"
|
||||
"\n"
|
||||
|
@ -426,6 +437,46 @@ msgstr ""
|
|||
msgid "No embroidery file formats selected."
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:34
|
||||
msgid "Speed up"
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:34
|
||||
msgid "Press + or arrow up to speed up"
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:35
|
||||
msgid "Slow down"
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:35
|
||||
msgid "Press - or arrow down to slow down"
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:36
|
||||
msgid "Pause"
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:36
|
||||
msgid "Press P to pause the animation"
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:37
|
||||
msgid "Restart"
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:37
|
||||
msgid "Press R to restart the animation"
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:38
|
||||
msgid "Quit"
|
||||
msgstr ""
|
||||
|
||||
#: lib/simulator.py:38
|
||||
msgid "Press Q to close the simulation window"
|
||||
msgstr ""
|
||||
|
||||
#: lib/stitches/auto_fill.py:167
|
||||
msgid ""
|
||||
"Unable to autofill. This most often happens because your shape is made "
|
||||
|
|
Ładowanie…
Reference in New Issue