Remove electron entirely (#2859)

Co-authored-by: rejbasket
pull/2876/head
Kaalleen 2024-05-01 19:34:25 +02:00 zatwierdzone przez GitHub
rodzic eb64c88a8b
commit 2ee4175437
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
65 zmienionych plików z 12 dodań i 2867 usunięć

Wyświetl plik

@ -30,18 +30,6 @@ jobs:
restore-keys: |
${{ runner.os }}-20.04-pip-
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: install dependencies
shell: bash
run: |

Wyświetl plik

@ -57,8 +57,7 @@ jobs:
# files when a new translation string is added but we don't need to
# commit those until folks actually translate the new strings.
if git diff translations | grep -qE '^[-+]msgstr ".+"$'; then
make electron/src/renderer/assets/translations.json
git add translations electron/src/renderer/assets/translations.json
git add translations
git commit -m "new translations from Crowdin"
git push https://github.com/inkstitch/inkstitch main
fi

2
.gitignore vendored
Wyświetl plik

@ -18,8 +18,6 @@ locales/
/src/
.DS_STORE
.DS_Store
flaskserverport.json
electron/yarn.lock
# debug and profile files
/DEBUG.ini

Wyświetl plik

@ -8,7 +8,6 @@ Feel free to find something that interests you. If you're looking for ideas, co
* **please read our [coding style guide](CODING_STYLE.md)**
* build / CI system (GitHub actions)
* we need someone to figure out how we can start code-signing our application
* web design (electron UI)
* translations ([how to translate](https://github.com/inkstitch/inkstitch/blob/main/LOCALIZATION.md))
* issue wrangling
* combining duplicate issues

Wyświetl plik

@ -2,18 +2,16 @@
OS=$(shell uname)
dist: version locales inx
python bin/generate-flaskserverport-file
bash bin/build-python
bash bin/build-electron
bash bin/build-distribution-archives
distclean:
rm -rf build dist inx locales artifacts win mac *.spec *.tar.gz *.zip electron/node_modules electron/dist electron/build/mac electron/build/mac-arm64 electron/build/win-ia32-unpacked electron/build/linux-unpacked electron/build/linux-arm64-unpacked electron/src/lib/flaskserverport.json
rm -rf build dist inx locales artifacts win mac *.spec *.tar.gz *.zip
distlocal:
@case ${OS} in "Darwin") export BUILD=osx ;; "Linux")export BUILD=linux ;; *) export BUILD=windows ;; esac; export VERSION=local-build; make distclean && make dist;
manual:
make inx && cd electron && yarn install && cd ..
make inx
.PHONY: inx
inx: version locales
@ -33,13 +31,7 @@ messages.po: inx
rm -rf src/
pybabel extract -o messages-babel.po -F babel.conf --add-location=full --add-comments=l10n,L10n,L10N --sort-by-file --strip-comments -k N_ -k '$$gettext' .
rm pyembroidery-format-descriptions.py inkstitch-fonts-metadata.py inkstitch-tiles-metadata.py
cd electron && yarn --link-duplicates --pure-lockfile
find electron/src -name '*.html' -o -name '*.js' -o -name '*.vue' | xargs electron/node_modules/.bin/gettext-extract --quiet --attribute v-translate --output messages-vue.po
msgcat -o messages.po messages-babel.po messages-vue.po messages-inx.po
electron/src/renderer/assets/translations.json: $(wildcard translations/messages_*.po)
find translations -name '*.po' -a ! -empty | \
xargs electron/node_modules/.bin/gettext-compile --output electron/src/renderer/assets/translations.json
msgcat -o messages.po messages-babel.po messages-inx.po
%.po: %.mo
msgunfmt -o $@ $<

Wyświetl plik

@ -4,21 +4,13 @@ ARCH="$(uname -m)"
mkdir artifacts
if [ "$BUILD" = "osx" ]; then
cp -a icons locales print LICENSE VERSION images/examples palettes symbols fonts tiles dbus inx dist/inkstitch.app/Contents/Resources
cp -a icons locales print LICENSE VERSION palettes symbols fonts tiles dbus inx dist/inkstitch.app/Contents/Resources
# adding version to Info.plist
plutil -replace CFBundleShortVersionString -string ${VERSION} dist/inkstitch.app/Contents/Info.plist
rm -rf dist/inkstitch/
# Install location for pkgbuild
PKG_INSTALL_PATH="/tmp/inkstitch/"
# Checking arch of macos and setting path of electron for arm64 or intel
echo "Checking for macOS arch."
if [ "${ARCH}" = "arm64" ]; then
ELECTRON_BUILD_PATH="electron/build/mac-arm64"
echo "found arm64"
else
ELECTRON_BUILD_PATH="electron/build/mac"
echo "found intel"
fi
# inside the scripts folder are:
# - preinstaller (checks for previously installed inkstitch and deletes it, Inkscape check with error message) and
# - postinstaller (moves inkstitch folder from /tmp to user Inkscape extensions folder in $HOME)
@ -33,8 +25,6 @@ if [ "$BUILD" = "osx" ]; then
# This code signs and notarize the inkstitch.app
DEV_IDENT="Developer ID Application: Lex Neva (929A568N58)"
echo "Signing of inkstitch.app"
# Coyping inkstitch-gui.app into inkstitch
ditto "${ELECTRON_BUILD_PATH}" dist/inkstitch.app/Contents/Frameworks/electron
# signing the binary may fix notary issue
/usr/bin/codesign -s "${DEV_IDENT}" \
--deep \
@ -55,7 +45,6 @@ if [ "$BUILD" = "osx" ]; then
INSTALLER_IDENT="Developer ID Installer: Lex Neva (929A568N58)"
/usr/bin/pkgbuild --root dist/inkstitch.app \
-s "${INSTALLER_IDENT}" \
--component-plist installer_scripts/inkstitch.plist \
--ownership recommended \
--identifier org.inkstitch.installer \
--version ${VERSION} \
@ -90,9 +79,7 @@ if [ "$BUILD" = "osx" ]; then
fi
else
# local builds will not be signed or notarized
cp -a "${ELECTRON_BUILD_PATH}" dist/inkstitch.app/Contents/Frameworks/electron
pkgbuild --root dist/inkstitch.app \
--component-plist installer_scripts/inkstitch.plist \
--ownership recommended \
--identifier org.inkstitch.installer \
--version ${VERSION} \
@ -107,7 +94,6 @@ if [ "$BUILD" = "osx" ]; then
else
cp -a images/examples palettes symbols fonts tiles dbus inx LICENSE VERSION dist/inkstitch
cp -a icons locales print dist/inkstitch/bin
cp -a electron/build/*-unpacked dist/inkstitch/electron
fi
if [ "$BUILD" = "windows" ]; then

Wyświetl plik

@ -1,27 +0,0 @@
#!/bin/bash
ARCH=$(python -c "import platform; n = platform.architecture()[0]; print(n)")
set -e
set -x
if [ "$BUILD" = "windows" ]; then
if [ "$ARCH" = "32bit" ]; then
args="-w --ia32"
else
args="-w --x64"
fi
elif [ "$BUILD" = "linux" ]; then
args="-l"
elif [ "$BUILD" = "osx" ]; then
cp installer_scripts/electron-entitlements.plist electron/build/
args="-m"
fi
# electron version setting on release
if [[ "$VERSION" =~ ^v[0-9][.0-9]+$ ]]; then
sed -i'' -e 's/11.99.11/'"${VERSION#v}"'/' electron/package.json
fi
cd electron
which yarn > /dev/null 2>&1 || npm install -g yarn
yarn --link-duplicates --pure-lockfile
yarn run dist ${args}

Wyświetl plik

@ -17,7 +17,7 @@ pyinstaller_args+="--log-level DEBUG "
# This adds bundle identifier in reverse DSN format for macos
if [ "$BUILD" = "osx" ]; then
pyinstaller_args+="--osx-bundle-identifier org.inkstitch.app "
pyinstaller_args+="-i electron/build/icons/mac/inkstitch.icns "
pyinstaller_args+="-i images/inkstitch/mac/inkstitch.icns "
if [[ -z ${GITHUB_REF} ]]; then
echo "Dev or Local Build"
else
@ -43,11 +43,11 @@ if [ "$BUILD" = "windows" ]; then
done;
sed -i'' 's/3, 2, 1,/'"${INFO_VERSION[0]}, ${INFO_VERSION[1]}, ${INFO_VERSION[2]},"'/' installer_scripts/file_version_info.txt
fi
# set year and version in version_info
# set year and version in version_info
sed -i'' 's/1.1.1/'"${VERSION#v}"'/' installer_scripts/file_version_info.txt
sed -i'' 's/1234/'"${info_year}"'/' installer_scripts/file_version_info.txt
# sets icon to inkstitch.exe
pyinstaller_args+="--i electron/build/icons/win/inkstitch.ico "
# sets icon to inkstitch.exe
pyinstaller_args+="-i images/inkstitch/win/inkstitch.ico "
pyinstaller_args+="--version-file installer_scripts/file_version_info.txt "
python -m PyInstaller $pyinstaller_args inkstitch.py
elif [ "$BUILD" = "osx" ]; then

Wyświetl plik

@ -1,12 +0,0 @@
#!/usr/bin/env python
import os
from json import dump
from os.path import dirname
path = os.path.join(dirname(dirname(__file__)), 'electron', 'src', 'lib', 'flaskserverport.json')
data = {"_comment1" : "port should not be declared when commiting"}
# write data to font.json into the same directory as the font file
with open(path, 'w', encoding="utf8") as output:
dump(data, output, indent=4, ensure_ascii=False)

Wyświetl plik

@ -5,4 +5,4 @@
# Instead of files, "--diff" may be passed to check only the lines changed
# by a diff piped to standard input.
flake8 --count --max-complexity=10 --max-line-length=150 --statistics --exclude=pyembroidery,__init__.py,electron,build,src,dist,./*-metadata.py,./pyembroidery-format-descriptions.py "${@:-.}"
flake8 --count --max-complexity=10 --max-line-length=150 --statistics --exclude=pyembroidery,__init__.py,build,src,dist,./*-metadata.py,./pyembroidery-format-descriptions.py "${@:-.}"

Wyświetl plik

@ -1,4 +0,0 @@
# https://github.com/browserslist/browserslist#queries
> 1%
last 2 versions
not dead

Wyświetl plik

@ -1 +0,0 @@
* text=auto eol=lf

10
electron/.gitignore vendored
Wyświetl plik

@ -1,10 +0,0 @@
.DS_Store
dist/electron/*
dist/web/*
build/*
!build/icons
node_modules/
npm-debug.log
npm-debug.log.*
thumbs.db
!.gitkeep

Wyświetl plik

@ -1,6 +0,0 @@
Electron UI
===========
This is the home of the future Electron-based UI. Currently only the Print extension uses Electron.
For local development, run `yarn` in this directory to install dependencies and build Electron.

Wyświetl plik

@ -1,16 +0,0 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage', // adds specific imports for polyfills when they are used in each file.
modules: false, // preserve ES modules.
corejs: { version: 3, proposals: true }, // enable polyfilling of every proposal supported by core-js.
},
],
],
plugins: [
'@babel/plugin-transform-runtime', // enables the re-use of Babel's injected helper code to save on codesize.
],
exclude: [/core-js/],
}

Wyświetl plik

@ -1,120 +0,0 @@
{
"name": "inkstitch-gui",
"productName": "inkstitch-gui",
"version": "11.99.11",
"description": "Ink/Stitch GUI",
"main": "./dist/electron/main.js",
"private": true,
"scripts": {
"dev": "node service/commands/dev.js",
"just-build": "node service/commands/build.js && node service/commands/build-main.js",
"dist": "yarn just-build && electron-builder",
"print": "yarn just-build && yarn dev"
},
"build": {
"productName": "inkstitch-gui",
"appId": "org.inkstitch.gui",
"directories": {
"output": "build"
},
"files": [
"dist/electron/**/*"
],
"linux": {
"icon": "build/icons",
"target": [
{
"target": "dir"
}
]
},
"win": {
"icon": "build/icons/win/inkstitch.ico",
"target": "dir"
},
"mac": {
"icon": "build/icons/mac/inkstitch.icns",
"target": [
{
"target": "dir"
}
],
"hardenedRuntime": true,
"gatekeeperAssess": false,
"strictVerify": false,
"entitlements": "build/electron-entitlements.plist",
"entitlementsInherit": "build/electron-entitlements.plist"
}
},
"keywords": [],
"author": "lex",
"license": "GPL-3.0-or-later",
"dependencies": {
"@babel/plugin-transform-runtime": "^7.21.0",
"@babel/runtime": "^7.17.9",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/vue-fontawesome": "^3.0.0-5",
"@svgdotjs/svg.filter.js": "^3.0.8",
"@svgdotjs/svg.js": "^3.1.2",
"@svgdotjs/svg.panzoom.js": "^2.1.2",
"axios": "^0.27.2",
"core-js": "^3.22.2",
"lodash.throttle": "^4.1.1",
"node-polyfill-webpack-plugin": "^2.0.1",
"query-string": "^7.1.1",
"svgpath": "^2.5.0",
"vue": "^3.2.33",
"vue-loading-overlay": "^5.0",
"vue-mousetrap": "^1.0.5",
"vue-router": "4",
"vue-slider-component": "^4.1.0-beta.0",
"vue3-gettext": "^2.2.3",
"vue3-transitions": "^1.0.0",
"vuetify": "3.3.0",
"webpack-plugin-vuetify": "^2.0.1"
},
"devDependencies": {
"@babel/core": "^7.17.9",
"@babel/preset-env": "^7.16.11",
"@types/webpack-env": "^1.16.4",
"@vue/compiler-sfc": "^3.2.33",
"autoprefixer": "^10.4.5",
"babel-loader": "^8.2.5",
"case-sensitive-paths-webpack-plugin": "^2.4.0",
"chalk": "^4.1.2",
"copy-webpack-plugin": "^10.2.4",
"css-loader": "^6.7.1",
"deepmerge": "^4.2.2",
"dotenv": "^16.0.0",
"dotenv-expand": "^8.0.3",
"easygettext": "^2.17.0",
"electron": "14.2.9",
"electron-builder": "^23.0.3",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.6.0",
"ora": "^5.4.1",
"postcss": "^8.4.12",
"postcss-html": "^1.4.1",
"postcss-loader": "^6.2.1",
"rimraf": "^3.0.2",
"sass": "~1.32",
"sass-loader": "^13.0.0",
"strip-ansi": "^6.0.0",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.1",
"thread-loader": "^3.0.4",
"ts-loader": "^9.2.8",
"typescript": "^4.6.3",
"url-loader": "^4.1.1",
"vue-loader": "^17.0.0",
"vue-style-loader": "^4.1.3",
"wait-on": "^6.0.1",
"webpack": "^5.72.0",
"webpack-dev-server": "^4.8.1",
"webpack-merge": "^5.8.0"
},
"engines": {
"node": ">=12.13.0"
}
}

Wyświetl plik

@ -1,41 +0,0 @@
'use strict'
const loadEnv = require('../utils/loadEnv')
loadEnv()
loadEnv('production')
const rm = require('rimraf')
const webpack = require('webpack')
const { error, done } = require('../utils/logger')
const { logWithSpinner, stopSpinner } = require('../utils/spinner')
const paths = require('../utils/paths')
// after renderer is built, main is next to build
const webpackConfig = require('../config/main')
const config = require('../project.config')
logWithSpinner('Building for production...')
// removed rm function to prevent the deletion of renderer
webpack(webpackConfig, (err, stats) => {
stopSpinner(false)
if (err) throw err
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
}) + '\n\n'
)
if (stats.hasErrors()) {
error('Build failed with errors.\n')
process.exit(1)
}
done('Build complete.\n')
})

Wyświetl plik

@ -1,44 +0,0 @@
'use strict'
const loadEnv = require('../utils/loadEnv')
loadEnv()
loadEnv('production')
const rm = require('rimraf')
const webpack = require('webpack')
const { error, done } = require('../utils/logger')
const { logWithSpinner, stopSpinner } = require('../utils/spinner')
const paths = require('../utils/paths')
// build renderer first
const webpackConfig = require('../config/renderer')
const config = require('../project.config')
logWithSpinner('Building for production...')
rm(paths.resolve(config.outputDir), (err) => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
stopSpinner(false)
if (err) throw err
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
}) + '\n\n'
)
if (stats.hasErrors()) {
error('Build failed with errors.\n')
process.exit(1)
}
done('Build complete.\n')
})
})

Wyświetl plik

@ -1,102 +0,0 @@
'use strict'
const loadEnv = require('../utils/loadEnv')
loadEnv()
loadEnv('development')
const chalk = require('chalk')
const webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const { info } = require('../utils/logger')
const getLocalIP = require('../utils/getLocalIP')
const devWebpackConfig = require('../config/dev')
const devServerOptions = devWebpackConfig.devServer
const { spawn } = require('node:child_process')
const electron = require('electron')
const path = require('path')
const url = require('url')
const fs = require('fs');
let electronProcess = null
let manualRestart = false
// disable warnings in browser console
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'false'
const protocol = devServerOptions.https ? 'https' : 'http'
const host = devServerOptions.host || '0.0.0.0'
const port = devServerOptions.port || 8080
// older code that sets the url for the path I would assume
var parseArg = process.argv[2] || ""
var yarnArg = url.parse(parseArg)
function resetPort() {
let resetData = { "_comment1": "port should not be declared when commiting" }
fs.writeFileSync(path.join(__dirname, "../../src/lib/flaskserverport.json"), JSON.stringify(resetData), 'utf8')
console.log("Resetting the flaskport")
}
function startElectron(webpackport) {
var wbport = webpackport
// this sends url to proper position
process.argv.shift()
process.argv.shift()
// get URL from PrintPDF
// checks if url is http
if (yarnArg.protocol) {
var args = [
'--inspect=5858',
path.join(__dirname, '../../dist/electron/main.js')
].concat(process.argv)
} else {
var args = [
'--inspect=5858',
`http://0.0.0.0:${wbport}/#${process.argv}`
].concat(process.argv)
}
// detect yarn or npm and process commandline args accordingly
if (process.env.npm_execpath.endsWith('yarn.js')) {
args = args.concat(process.argv.slice(3))
} else if (process.env.npm_execpath.endsWith('npm-cli.js')) {
args = args.concat(process.argv.slice(2))
}
electronProcess = spawn(electron, args)
electronProcess.on('close', () => {
if (!manualRestart) {
process.exit()
} else {
process.kill(electronProcess.pid)
}
resetPort()
})
electronProcess.on('exit', () => {
resetPort()
})
}
info('Starting development server...')
const compiler = webpack(devWebpackConfig)
const server = new WebpackDevServer(devServerOptions, compiler)
compiler.hooks.done.tap('serve', (stats) => {
console.log()
console.log()
console.log(`App running at:`)
console.log(` - Local: ${chalk.cyan(`${protocol}://${host}:${port}`)}`)
console.log(` - Network: ${chalk.cyan(`${protocol}://${getLocalIP()}:${port}`)}`)
console.log()
// allows livereload for webpack devserver to work without multiple instances of electron
if (electronProcess) {
manualRestart = true
} else {
manualRestart = false
// starts nodejs electron commandline browser
startElectron(devServerOptions.port)
}
})
server.start(port, host, (err) => {
if (err) {
process.exit(0)
}
})

Wyświetl plik

@ -1,126 +0,0 @@
'use strict'
const { DefinePlugin, EnvironmentPlugin } = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const HTMLPlugin = require('html-webpack-plugin')
const { VuetifyPlugin } = require('webpack-plugin-vuetify')
const resolveClientEnv = require('../utils/resolveClientEnv')
const paths = require('../utils/paths')
const config = require('../project.config')
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
context: process.cwd(),
output: {
path: paths.resolve(config.outputDir),
publicPath: config.dev.publicPath,
filename: '[name].js',
},
resolve: {
alias: {
'@': paths.resolve('src'),
},
extensions: ['.ts', '.tsx', '.js', '.jsx', '.vue', '.json', '.html', '.ejs'],
},
plugins: [
new VueLoaderPlugin(),
new EnvironmentPlugin(['NODE_ENV']),
new CaseSensitivePathsPlugin(),
new HTMLPlugin({
template: paths.resolve('src/index.html'),
templateParameters: {
...resolveClientEnv(
{ publicPath: isProd ? config.build.publicPath : config.dev.publicPath },
false /* raw */
),
},
}),
new VuetifyPlugin({ autoImport: true }),
new DefinePlugin({
// vue3 feature flags <http://link.vuejs.org/feature-flags>
__VUE_OPTIONS_API__: 'true',
__VUE_PROD_DEVTOOLS__: 'false',
...resolveClientEnv({
publicPath: isProd ? config.build.publicPath : config.dev.publicPath,
}),
}),
],
module: {
noParse: /^(vue|vue-router)$/,
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
// babel
{
test: /\.m?jsx?$/,
exclude: (file) => {
// always transpile js in vue files
if (/\.vue\.jsx?$/.test(file)) {
return false
}
// Don't transpile node_modules
return /node_modules/.test(file)
},
use: ['thread-loader', 'babel-loader'],
},
// ts
{
test: /\.tsx?$/,
use: [
'thread-loader',
'babel-loader',
{
loader: 'ts-loader',
options: {
transpileOnly: true,
appendTsSuffixTo: ['\\.vue$'],
happyPackMode: true,
},
},
],
},
// images
{
test: /\.(png|jpe?g|gif|webp)(\?.*)?$/,
type: 'asset',
generator: { filename: 'img/[contenthash:8][ext][query]' },
},
// do not base64-inline SVGs.
// https://github.com/facebookincubator/create-react-app/pull/1180
{
test: /\.(svg)(\?.*)?$/,
type: 'asset/resource',
generator: { filename: 'img/[contenthash:8][ext][query]' },
},
// media
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
type: 'asset',
generator: { filename: 'media/[contenthash:8][ext][query]' },
},
// fonts
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
type: 'asset',
generator: { filename: 'fonts/[contenthash:8][ext][query]' },
},
],
},
}

Wyświetl plik

@ -1,72 +0,0 @@
'use strict'
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const isProd = process.env.NODE_ENV === 'production'
const plugins = []
if (isProd) {
const filename = 'css/[name].[contenthash:8].css'
plugins.push(
new MiniCssExtractPlugin({
filename,
chunkFilename: filename,
})
)
}
const genStyleRules = () => {
const cssLoader = {
loader: 'css-loader',
options: {
// how many loaders before css-loader should be applied to [@import]ed resources.
// stylePostLoader injected by vue-loader + postcss-loader
importLoaders: 1 + 1,
esModule: false, // css-loader using ES Modules as default in v4, but vue-style-loader support cjs only.
},
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('autoprefixer')]
},
},
}
const extractPluginLoader = {
loader: MiniCssExtractPlugin.loader,
}
const vueStyleLoader = {
loader: 'vue-style-loader',
}
function createCSSRule(test, loader, loaderOptions) {
const loaders = [cssLoader, postcssLoader]
if (isProd) {
loaders.unshift(extractPluginLoader)
} else {
loaders.unshift(vueStyleLoader)
}
if (loader) {
loaders.push({ loader, options: loaderOptions })
}
return { test, use: loaders }
}
return [
createCSSRule(/\.css$/),
createCSSRule(/\.p(ost)?css$/),
createCSSRule(/\.scss$/, 'sass-loader')
]
}
module.exports = {
plugins,
module: {
rules: genStyleRules(),
},
}

Wyświetl plik

@ -1,43 +0,0 @@
'use strict'
const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./base')
const cssWebpackConfig = require('./css')
const config = require('../project.config')
const { ProvidePlugin, DefinePlugin } = require('webpack')
module.exports = merge(baseWebpackConfig, cssWebpackConfig, {
entry: {
main: './src/renderer/main.js'
},
mode: 'development',
devtool: 'eval-cheap-module-source-map',
devServer: {
watchFiles: ['src/**/*'],
historyApiFallback: {
rewrites: [{ from: /./, to: '/index.html' }],
},
devMiddleware: {
publicPath: config.dev.publicPath,
},
open: false,
host: '0.0.0.0',
port: 'auto',
liveReload: true,
},
infrastructureLogging: {
level: 'warn',
},
stats: {
assets: false,
modules: false,
errorDetails: false,
},
})

Wyświetl plik

@ -1,73 +0,0 @@
'use strict'
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const config = require('../project.config')
const resolveClientEnv = require('../utils/resolveClientEnv')
const paths = require('../utils/paths')
const { merge } = require('webpack-merge')
const TerserPlugin = require('terser-webpack-plugin')
const cssWebpackConfig = require('./css')
const terserOptions = require('./terserOptions')
const isProd = process.env.NODE_ENV === 'production'
module.exports = merge(cssWebpackConfig, {
context: process.cwd(),
mode: 'production',
entry: {
main: './src/main/index.js',
preload: './src/main/preload.js',
},
node: {
__dirname: false,
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin(terserOptions())],
moduleIds: 'named',
},
target: ['electron-main'],
output: {
path: paths.resolve(config.outputDir),
publicPath: config.dev.publicPath,
filename: '[name].js',
},
resolve: {
alias: {
'@': paths.resolve('src'),
},
extensions: ['.ts', '.tsx', '.js', '.jsx', '.vue', '.json', 'html', 'ejs'],
},
plugins: [
new CaseSensitivePathsPlugin(),
],
module: {
noParse: /^(vue|vue-router)$/,
rules: [
// ts
{
test: /\.tsx?$/,
use: [
'thread-loader',
'babel-loader',
{
loader: 'ts-loader',
options: {
transpileOnly: true,
appendTsSuffixTo: ['\\.vue$'],
happyPackMode: true,
},
},
],
},
],
},
}
)

Wyświetl plik

@ -1,41 +0,0 @@
'use strict'
const { merge } = require('webpack-merge')
const TerserPlugin = require('terser-webpack-plugin')
const baseWebpackConfig = require('./base')
const cssWebpackConfig = require('./css')
const config = require('../project.config')
const terserOptions = require('./terserOptions')
module.exports = merge(baseWebpackConfig, cssWebpackConfig, {
mode: 'production',
output: {
publicPath: config.build.publicPath,
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin(terserOptions())],
moduleIds: 'deterministic',
moduleIds: 'named',
splitChunks: {
cacheGroups: {
defaultVendors: {
name: `chunk-vendors`,
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial',
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true,
},
},
},
},
})

Wyświetl plik

@ -1,45 +0,0 @@
'use strict'
const { merge } = require('webpack-merge')
const TerserPlugin = require('terser-webpack-plugin')
const baseWebpackConfig = require('./base')
const cssWebpackConfig = require('./css')
const config = require('../project.config')
const terserOptions = require('./terserOptions')
module.exports = merge(baseWebpackConfig, cssWebpackConfig, {
mode: 'production',
entry: {
renderer: './src/renderer/main.js',
},
output: {
publicPath: config.build.publicPath,
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin(terserOptions())],
moduleIds: 'deterministic',
moduleIds: 'named',
splitChunks: {
cacheGroups: {
defaultVendors: {
name: `chunk-vendors`,
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial',
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true,
},
},
},
},
target: ['electron-renderer'],
})

Wyświetl plik

@ -1,42 +0,0 @@
'use strict'
module.exports = (options) => ({
terserOptions: {
compress: {
// turn off flags with small gains to speed up minification
arrows: false,
collapse_vars: false, // 0.3kb
comparisons: false,
computed_props: false,
hoist_funs: false,
hoist_props: false,
hoist_vars: false,
inline: false,
loops: false,
negate_iife: false,
properties: false,
reduce_funcs: false,
reduce_vars: false,
switches: false,
toplevel: false,
typeofs: false,
// a few flags with noticable gains/speed ratio
// numbers based on out of the box vendor bundle
booleans: true, // 0.7kb
if_return: true, // 0.4kb
sequences: true, // 0.7kb
unused: true, // 2.3kb
// required features to drop conditional branches
conditionals: true,
dead_code: true,
evaluate: true,
},
mangle: {
safari10: true,
},
},
// parallel: options.parallel,
extractComments: false,
})

Wyświetl plik

@ -1,16 +0,0 @@
'use strict'
module.exports = {
// orginal was dist
outputDir: 'dist/electron',
dev: {
publicPath: '/',
port: 8080,
},
build: {
// orginal was /
publicPath: './',
},
}

Wyświetl plik

@ -1,17 +0,0 @@
'use strict'
const os = require('os')
module.exports = function getLocalIP() {
const interfaces = os.networkInterfaces()
for (const devName in interfaces) {
const iface = interfaces[devName]
for (let i = 0; i < iface.length; i++) {
const alias = iface[i]
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
return alias.address
}
}
}
}

Wyświetl plik

@ -1,39 +0,0 @@
'use strict'
const path = require('path')
const dotenv = require('dotenv')
const dotenvExpand = require('dotenv-expand')
const { error } = require('./logger')
module.exports = function loadEnv(mode) {
const basePath = path.resolve(process.cwd(), `.env${mode ? `.${mode}` : ``}`)
const localPath = `${basePath}.local`
const load = (envPath) => {
try {
const env = dotenv.config({ path: envPath, debug: process.env.DEBUG })
dotenvExpand.expand(env)
} catch (err) {
// only ignore error if file is not found
if (err.toString().indexOf('ENOENT') < 0) {
error(err)
}
}
}
load(localPath)
load(basePath)
// by default, NODE_ENV and BABEL_ENV are set to "development" unless mode
// is production or test. However the value in .env files will take higher
// priority.
if (mode) {
const defaultNodeEnv = mode === 'production' || mode === 'test' ? mode : 'development'
if (process.env.NODE_ENV == null) {
process.env.NODE_ENV = defaultNodeEnv
}
if (process.env.BABEL_ENV == null) {
process.env.BABEL_ENV = defaultNodeEnv
}
}
}

Wyświetl plik

@ -1,72 +0,0 @@
'use strict'
const chalk = require('chalk')
const stripAnsi = require('strip-ansi')
const readline = require('readline')
const EventEmitter = require('events')
exports.events = new EventEmitter()
function _log(type, tag, message) {
if (process.env.VUE_CLI_API_MODE && message) {
exports.events.emit('log', {
message,
type,
tag,
})
}
}
const format = (label, msg) => {
return msg
.split('\n')
.map((line, i) => {
return i === 0 ? `${label} ${line}` : line.padStart(stripAnsi(label).length)
})
.join('\n')
}
const chalkTag = (msg) => chalk.bgBlackBright.white.dim(` ${msg} `)
exports.log = (msg = '', tag = null) => {
tag ? console.log(format(chalkTag(tag), msg)) : console.log(msg)
_log('log', tag, msg)
}
exports.info = (msg, tag = null) => {
console.log(format(chalk.bgBlue.black(' INFO ') + (tag ? chalkTag(tag) : ''), msg))
_log('info', tag, msg)
}
exports.done = (msg, tag = null) => {
console.log(format(chalk.bgGreen.black(' DONE ') + (tag ? chalkTag(tag) : ''), msg))
_log('done', tag, msg)
}
exports.warn = (msg, tag = null) => {
console.warn(
format(chalk.bgYellow.black(' WARN ') + (tag ? chalkTag(tag) : ''), chalk.yellow(msg))
)
_log('warn', tag, msg)
}
exports.error = (msg, tag = null) => {
console.error(format(chalk.bgRed(' ERROR ') + (tag ? chalkTag(tag) : ''), chalk.red(msg)))
_log('error', tag, msg)
if (msg instanceof Error) {
console.error(msg.stack)
_log('error', tag, msg.stack)
}
}
exports.clearConsole = (title) => {
if (process.stdout.isTTY) {
const blank = '\n'.repeat(process.stdout.rows)
console.log(blank)
readline.cursorTo(process.stdout, 0, 0)
readline.clearScreenDown(process.stdout)
if (title) {
console.log(title)
}
}
}

Wyświetl plik

@ -1,6 +0,0 @@
'use strict'
const path = require('path')
// gen absolute path
exports.resolve = (...args) => path.posix.join(process.cwd(), ...args)

Wyświetl plik

@ -1,11 +0,0 @@
'use strict'
const prefixRE = /^VUE_APP_/
module.exports = function resolveClientEnv(options, raw) {
process.env.PUBLIC_PATH = options.publicPath
if (raw) {
return env
}
}

Wyświetl plik

@ -1,57 +0,0 @@
'use strict'
const ora = require('ora')
const chalk = require('chalk')
const spinner = ora()
let lastMsg = null
let isPaused = false
exports.logWithSpinner = (symbol, msg) => {
if (!msg) {
msg = symbol
symbol = chalk.green('✔')
}
if (lastMsg) {
spinner.stopAndPersist({
symbol: lastMsg.symbol,
text: lastMsg.text,
})
}
spinner.text = ' ' + msg
lastMsg = {
symbol: symbol + ' ',
text: msg,
}
spinner.start()
}
exports.stopSpinner = (persist) => {
if (lastMsg && persist !== false) {
spinner.stopAndPersist({
symbol: lastMsg.symbol,
text: lastMsg.text,
})
} else {
spinner.stop()
}
lastMsg = null
}
exports.pauseSpinner = () => {
if (spinner.isSpinning) {
spinner.stop()
isPaused = true
}
}
exports.resumeSpinner = () => {
if (isPaused) {
spinner.start()
isPaused = false
}
}
exports.failSpinner = (text) => {
spinner.fail(text)
}

Wyświetl plik

@ -1,20 +0,0 @@
<!--
Authors: see git history
Copyright (c) 2010 Authors
Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="app"></div>
</body>
</html>
<script>
global = globalThis
</script>

Wyświetl plik

@ -1,24 +0,0 @@
/*
* Authors: see git history
*
* Copyright (c) 2010 Authors
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
*
*/
import axios from 'axios';
import flaskserverport from './flaskserverport.json'
if (flaskserverport.port === undefined) {
var theflaskport = window.inkstitchAPI.flaskport()
console.log("Installed mode")
console.log(theflaskport)
} else {
var theflaskport = flaskserverport.port
console.log("Dev mode")
console.log(theflaskport)
}
export const inkStitch = axios.create({
baseURL: `http://127.0.0.1:${theflaskport}`
})

Wyświetl plik

@ -1,47 +0,0 @@
/*
* Authors: see git history
*
* Copyright (c) 2010 Authors
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
*
*/
export function selectLanguage(translations, flaskport) {
var port = flaskport
// get language from flask server, process in modern electron isn't exposed to renderer
const request = new XMLHttpRequest();
request.open('GET', `http://127.0.0.1:${port}/languages`, false)
request.send(null)
var process = undefined
if (request.status === 200) {
process = JSON.parse(request.responseText)
}
// get a list of available translations
var availableTranslations = ['en_US'];
for (var k in translations) availableTranslations.push(k);
var lang = undefined;
// get system language / Inkscape language
['LANG', 'LC_MESSAGES', 'LC_ALL', 'LANGUAGE'].forEach(language => {
if (process[language]) {
// split encoding information, we don't need it
var current_lang = process[language].split('.')[0];
if (current_lang.length == 2) {
// current language has only two letters (e.g. en),
// compare with available languages and if present, set to a long locale name (e.g. en_US)
lang = availableTranslations.find((elem) => elem.startsWith(current_lang));
} else {
lang = current_lang;
}
}
})
// set default language
if (lang === undefined) {
lang = "en_US"
}
return lang
}

Wyświetl plik

@ -1,112 +0,0 @@
/*
* Authors: see git history
*
* Copyright (c) 2010 Authors
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
*
*/
'use strict'
const path = require('path')
const fs = require('fs')
const tmp = require('tmp')
const url = require('url')
const { app, BrowserWindow, ipcMain, dialog, shell, Menu} = require('electron')
// url for printPDF flask server which is used in development and production mode
var port = process.env.FLASKPORT
const printPdfUrl = `http://127.0.0.1:${port}/`
const isDev = process.env.BABEL_ENV === 'development'
var target = null
// Finds this url in the argv array and sets to target value
if (process.argv.includes(printPdfUrl)) {
target = printPdfUrl
} else {
target = process.argv[1] || "";
}
var targetURL = url.parse(target)
var winURL = null
// Eventually this will be migrated to Vue.
if (targetURL.protocol) {
winURL = target
} else {
winURL = `file://${__dirname}/index.html?${targetURL.query || ""}#${targetURL.pathname || ""}`
}
function createWindow() {
const mainWindow = new BrowserWindow({
useContentSize: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true,
},
})
if (isDev) {
// printPDF in development mode will have dev tools activated
// Vuejs parts of Ink/Stich will not and dev tools must be accessed though the menu of electron window
mainWindow.loadURL(winURL)
mainWindow.webContents.openDevTools()
} else {
mainWindow.loadURL(winURL)
}
// This will remove the menu from the release, in dev mode the menu is available.
if(process.platform === "darwin" && !isDev) {
Menu.setApplicationMenu(Menu.buildFromTemplate([]));
} if(process.platform === "win32" || process.platform === "linux" && !isDev) {
mainWindow.removeMenu();
}
mainWindow.maximize()
// save to PDF
ipcMain.on('save-pdf', (event, pageSize) => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
const saveOpt = {
title: "Save PDF",
defaultPath: "Inkstitch.pdf",
filters: [{ name: 'PDF', extensions: ['pdf'] }],
bookmark: "true",
}
win.webContents.printToPDF({}).then(pageSize => {
dialog.showSaveDialog(saveOpt).then(filename => {
const { filePath } = filename;
fs.writeFileSync(filePath, pageSize, (error) => {
if (error) {
throw error
}
console.log(`Wrote PDF successfully to ${pdfPath}`)
})
}).catch(error => {
console.log(`Failed to write PDF to ${pdfPath}: `, error)
})
})
})
// openPDF
ipcMain.on('open-pdf', (event, pageSize) => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win.webContents.printToPDF({}).then(pageSize => {
tmp.file({keep: true, discardDescriptor: true}, function(err, path, fd, cleanupCallback) {
fs.writeFileSync(path, pageSize, 'utf-8');
shell.openPath(path);
})
})
})
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if(BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
app.quit()
})

Wyświetl plik

@ -1,7 +0,0 @@
const { contextBridge, ipcRenderer } = require ('electron')
contextBridge.exposeInMainWorld('inkstitchAPI', {
savepdf: (pageSize) => { ipcRenderer.send('save-pdf', pageSize) },
openpdf: (pageSize) => { ipcRenderer.send('open-pdf', pageSize) },
flaskport: () => process.env.FLASKPORT,
})

Wyświetl plik

@ -1,17 +0,0 @@
<!--
Authors: see git history
Copyright (c) 2010 Authors
Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
-->
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<style>
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons');
</style>

Wyświetl plik

@ -1,654 +0,0 @@
/*
* Authors: see git history
*
* Copyright (c) 2010 Authors
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
*
*/
import { inkStitch } from '../../../lib/api.js'
import { SVG } from '@svgdotjs/svg.js'
import '@svgdotjs/svg.panzoom.js'
import '@svgdotjs/svg.filter.js'
import svgpath from 'svgpath'
import Loading from 'vue-loading-overlay';
import 'vue-loading-overlay/dist/vue-loading.css';
import { reactive, toRefs } from 'vue'
import VueSlider from 'vue-slider-component'
import 'vue-slider-component/theme/antd.css'
import throttle from 'lodash/throttle'
function SliderMark(command, icon) {
this.label = ""
this.command = command
this.icon = icon
}
export default {
name: 'simulator',
components: {
Loading,
VueSlider
},
setup() {
const data = reactive({ value: 0 })
return toRefs(data)
},
data: function () {
return {
loading: false,
controlsExpanded: true,
infoExpanded: false,
infoMaxHeight: 0,
speed: 16,
currentStitch: 1,
currentStitchDisplay: 1,
direction: 1,
numStitches: 1,
animating: false,
sliderProcess: dotPos => this.sliderColorSections,
showTrims: false,
showJumps: false,
showColorChanges: false,
showStops: false,
showNeedlePenetrationPoints: false,
renderJumps: true,
showRealisticPreview: false,
showCursor: true,
error: false,
error_message: ""
}
},
watch: {
currentStitch: throttle(function () {
this.currentStitchDisplay = Math.floor(this.currentStitch)
}, 100, {leading: true, trailing: true}),
showNeedlePenetrationPoints: function () {
if (this.needlePenetrationPoints === null) {
return;
}
this.needlePenetrationPoints.forEach(npp => {
if (this.showNeedlePenetrationPoints) {
npp.show()
} else {
npp.hide()
}
})
},
renderJumps() {
this.renderedStitch = 1
this.renderFrame()
},
showRealisticPreview() {
let animating = this.animating
this.stop()
if (this.showRealisticPreview) {
if (this.realisticPreview === null) {
// This workflow should be improved and might be a bit unconventional.
// We don't want to make the user wait for it too long.
// It would be best, if the realistic preview could load before it is actually requested.
this.$nextTick(() => {this.loading=true})
setImmediate(()=> {this.generateRealisticPaths()})
setImmediate(()=> {this.loading = false})
}
setImmediate(()=> {
this.renderedStitch = 0
this.renderFrame()
this.simulation.hide()
this.realisticPreview.show()
})
} else {
this.renderedStitch = 0
this.renderFrame()
this.simulation.show()
this.realisticPreview.hide()
}
if (animating) {
this.start()
}
},
showCursor: function () {
if (this.showCursor) {
this.cursor.show()
} else {
this.cursor.hide()
}
}
},
computed: {
speedDisplay() {
return this.speed * this.direction
},
currentCommand() {
let stitch = this.stitches[Math.floor(this.currentStitch)]
if (stitch === undefined || stitch === null) {
return ""
}
let label = this.$gettext("STITCH")
switch (true) {
case stitch.jump:
label = this.$gettext("JUMP")
break
case stitch.trim:
label = this.$gettext("TRIM")
break
case stitch.stop:
label = this.$gettext("STOP")
break
case stitch.color_change:
label = this.$gettext("COLOR CHANGE")
break
}
return label
},
paused() {
return !this.animating
},
forward() {
return this.direction > 0
},
reverse() {
return this.direction < 0
},
sliderMarks() {
var marks = {}
if (this.showTrims)
Object.assign(marks, this.trimMarks);
if (this.showJumps)
Object.assign(marks, this.jumpMarks);
if (this.showColorChanges)
Object.assign(marks, this.colorChangeMarks);
if (this.showStops)
Object.assign(marks, this.stopMarks);
return marks
}
},
methods: {
toggleInfo() {
this.infoExpanded = !this.infoExpanded;
this.infoMaxHeight = this.$refs.controlInfoButton.getBoundingClientRect().top;
},
toggleControls() {
this.controlsExpanded = !this.controlsExpanded;
},
animationSpeedUp() {
this.speed *= 2.0
},
animationSlowDown() {
this.speed = Math.max(this.speed / 2.0, 1)
},
animationReverse() {
this.direction = -1
this.start()
},
animationForward() {
this.direction = 1
this.start()
},
toggleAnimation(e) {
if (this.animating) {
this.stop()
} else {
this.start()
}
e.preventDefault();
},
animationForwardOneStitch() {
this.setCurrentStitch(this.currentStitch + 1)
},
animationBackwardOneStitch() {
this.setCurrentStitch(this.currentStitch - 1)
},
animationNextCommand() {
let nextCommandIndex = this.getNextCommandIndex()
if (nextCommandIndex === -1) {
this.setCurrentStitch(this.stitches.length)
} else {
this.setCurrentStitch(this.commandList[nextCommandIndex])
}
},
animationPreviousCommand() {
let nextCommandIndex = this.getNextCommandIndex()
let prevCommandIndex = 0
if (nextCommandIndex === -1) {
prevCommandIndex = this.commandList.length - 2
} else {
prevCommandIndex = nextCommandIndex - 2
}
let previousCommand = this.commandList[prevCommandIndex]
if (previousCommand === undefined) {
previousCommand = 1
}
this.setCurrentStitch(previousCommand)
},
getNextCommandIndex() {
let currentStitch = this.currentStitchDisplay
let nextCommand = this.commandList.findIndex(function (command) {
return command > currentStitch
})
return nextCommand
},
onCurrentStitchEntered() {
let newCurrentStitch = parseInt(this.$refs.currentStitchInput.value)
if (isNaN(newCurrentStitch)) {
this.$refs.currentStitchInput.value = Math.floor(this.currentStitch)
} else {
this.setCurrentStitch(parseInt(newCurrentStitch))
}
},
setCurrentStitch(newCurrentStitch) {
this.stop()
this.currentStitch = newCurrentStitch
this.clampCurrentStitch()
this.renderFrame()
},
clampCurrentStitch() {
this.currentStitch = Math.max(Math.min(this.currentStitch, this.numStitches), 0)
},
animate() {
let frameStart = performance.now()
let frameTime = null
if (this.lastFrameStart !== null) {
frameTime = frameStart - this.lastFrameStart
} else {
frameTime = this.targetFramePeriod
}
this.lastFrameStart = frameStart
let numStitches = this.speed * Math.max(frameTime, this.targetFramePeriod) / 1000.0;
this.currentStitch = this.currentStitch + numStitches * this.direction
this.clampCurrentStitch()
this.renderFrame()
if (this.animating && this.shouldAnimate()) {
this.timer = setTimeout(this.animate, Math.max(0, this.targetFramePeriod - frameTime))
} else {
this.timer = null;
this.stop()
}
},
renderFrame() {
while (this.renderedStitch < this.currentStitch) {
this.renderedStitch += 1
if (!this.renderJumps && this.stitches[this.renderedStitch].jump){
if (this.showRealisticPreview) {
this.realisticPaths[this.renderedStitch].hide();
} else {
this.stitchPaths[this.renderedStitch].hide();
}
continue;
}
if (this.showRealisticPreview) {
this.realisticPaths[this.renderedStitch].show()
} else {
this.stitchPaths[this.renderedStitch].show();
}
}
while (this.renderedStitch > this.currentStitch) {
if (this.showRealisticPreview) {
this.realisticPaths[this.renderedStitch].hide()
} else {
this.stitchPaths[this.renderedStitch].hide();
}
this.renderedStitch -= 1
}
this.moveCursor()
},
shouldAnimate() {
if (this.direction == 1 && this.currentStitch < this.numStitches) {
return true;
} else if (this.direction == -1 && this.currentStitch > 0) {
return true;
} else {
return false;
}
},
start() {
if (!this.animating && this.shouldAnimate()) {
this.animating = true
this.timer = setTimeout(this.animate, 0);
}
},
stop() {
if (this.animating) {
if (this.timer) {
clearTimeout(this.timer)
this.timer = null
}
this.animating = false
this.lastFrameStart = null
}
},
resizeCursor() {
// This makes the cursor stay the same size when zooming in or out.
// I'm not exactly sure how it works, but it does.
this.cursor.size(25 / this.svg.zoom())
this.cursor.stroke({width: 2 / this.svg.zoom()})
// SVG.js seems to move the cursor when we resize it, so we need to put
// it back where it goes.
this.moveCursor()
this.adjustScale()
},
moveCursor() {
let stitch = this.stitches[Math.floor(this.currentStitch)]
if (stitch === null || stitch === undefined) {
this.cursor.hide()
} else if (this.showCursor) {
this.cursor.show()
this.cursor.center(stitch.x, stitch.y)
}
},
adjustScale: throttle(function () {
let one_mm = 96 / 25.4 * this.svg.zoom();
let scaleWidth = one_mm
let simulatorWidth = this.$refs.simulator.getBoundingClientRect().width
let maxWidth = Math.min(simulatorWidth / 2, 300)
while (scaleWidth > maxWidth) {
scaleWidth /= 2.0
}
while (scaleWidth < 100) {
scaleWidth += one_mm
}
let scaleMM = scaleWidth / one_mm
this.scale.plot(`M0,0 v10 h${scaleWidth / 2} v-5 v5 h${scaleWidth / 2} v-10`)
// round and strip trailing zeros, source: https://stackoverflow.com/a/53397618
let mm = scaleMM.toFixed(8).replace(/([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1')
this.scaleLabel.text(`${mm} mm`)
}, 100, {leading: true, trailing: true}
),
generateMarks() {
this.commandList = Array()
for (let i = 1; i < this.stitches.length; i++) {
if (this.stitches[i].trim) {
this.trimMarks[i] = new SliderMark("trim", "cut")
this.commandList.push(i)
} else if (this.stitches[i].stop) {
this.stopMarks[i] = new SliderMark("stop", "pause")
this.commandList.push(i)
} else if (this.stitches[i].jump) {
this.jumpMarks[i] = new SliderMark("jump", "frog")
this.commandList.push(i)
} else if (this.stitches[i].color_change) {
this.colorChangeMarks[i] = new SliderMark("color-change", "exchange-alt")
this.commandList.push(i)
}
}
},
generateColorSections() {
var currentStitch = 0
this.stitchPlan.color_blocks.forEach(color_block => {
this.sliderColorSections.push([
(currentStitch + 1) / this.numStitches * 100,
(currentStitch + color_block.stitches.length) / this.numStitches * 100,
{backgroundColor: color_block.color.visible_on_white.hex}
])
currentStitch += color_block.stitches.length
})
},
generateMarker(color) {
return this.svg.marker(3, 3, add => {
let needlePenetrationPoint = add.circle(3).fill(color).hide()
this.needlePenetrationPoints.push(needlePenetrationPoint)
})
},
generateScale() {
let svg = SVG().addTo(this.$refs.simulator)
svg.node.classList.add("simulation-scale")
this.scale = svg.path("M0,0").stroke({color: "black", width: "1px"}).fill("none")
this.scaleLabel = svg.text("0 mm").move(0, 12)
this.scaleLabel.node.classList.add("simulation-scale-label")
},
generateCursor() {
this.cursor =
this.svg.path("M0,0 v2.8 h1.2 v-2.8 h2.8 v-1.2 h-2.8 v-2.8 h-1.2 v2.8 h-2.8 v1.2 h2.8")
.stroke({
width: 0.1,
color: '#FFFFFF',
})
.fill('#000000')
this.cursor.node.classList.add("cursor")
},
generateRealisticPaths() {
// Create Realistic Filter
this.filter = this.svg.defs().filter()
this.filter.attr({id: "realistic-stitch-filter", x: "-0.1", y: "-0.1", height: "1.2", width: "1.2", style: "color-interpolation-filters:sRGB"})
this.filter.gaussianBlur({id: "gaussianBlur1", stdDeviation: "1.5", in: "SourceAlpha"})
this.filter.componentTransfer(function (add) {
add.funcR({ type: "identity" }),
add.funcG({ type: "identity" }),
add.funcB({ type: "identity", slope: "4.53" }),
add.funcA({ type: "gamma", slope: "0.149", intercept: "0", amplitude: "3.13", offset: "-0.33" })
}).attr({id: "componentTransfer1", in: "gaussianBlur1"})
this.filter.composite({id: "composite1", in: "componentTransfer1", in2: "SourceAlpha", operator: "in"})
this.filter.gaussianBlur({id: "gaussianBlur2", in: "composite1", stdDeviation: 0.09})
this.filter.morphology({id: "morphology1", in: "gaussianBlur2", operator: "dilate", radius: 0.1})
this.filter.specularLighting({id: "specularLighting1", in: "morphology1", specularConstant: 0.709, surfaceScale: 30}).pointLight({z: 10})
this.filter.gaussianBlur({id: "gaussianBlur3", in: "specularLighting1", stdDeviation: 0.04})
this.filter.composite({id: "composite2", in: "gaussianBlur3", in2: "SourceGraphic", operator: "arithmetic", k2: 1, k3: 1, k1: 0, k4: 0})
this.filter.composite({in: "composite2", in2: "SourceAlpha", operator: "in"})
// Create realistic paths in it's own group and move it behind the cursor
this.realisticPreview = this.svg.group({id: 'realistic'}).backward()
this.stitchPlan.color_blocks.forEach(color_block => {
let color = `${color_block.color.visible_on_white.hex}`
let realistic_path_attrs = {fill: color, stroke: "none", filter: this.filter}
let stitching = false
let prevStitch = null
color_block.stitches.forEach(stitch => {
let realisticPath = null
if (stitching && prevStitch) {
// Position
let stitch_center = []
stitch_center.x = (prevStitch.x + stitch.x) / 2.0
stitch_center.y = (prevStitch.y + stitch.y) / 2.0
// Angle
var stitch_angle = Math.atan2(stitch.y - prevStitch.y, stitch.x - prevStitch.x) * (180 / Math.PI)
// Length
let path_length = Math.hypot(stitch.x - prevStitch.x, stitch.y - prevStitch.y)
var path = `M0,0 c 0.4,0,0.4,0.3,0.4,0.6 c 0,0.3,-0.1,0.6,-0.4,0.6 v 0.2,-0.2 h -${path_length} c -0.4,0,-0.4,-0.3,-0.4,-0.6 c 0,-0.3,0.1,-0.6,0.4,-0.6 v -0.2,0.2 z`
path = svgpath(path).rotate(stitch_angle).toString()
realisticPath = this.realisticPreview.path(path).attr(realistic_path_attrs).center(stitch_center.x, stitch_center.y).hide()
} else {
realisticPath = this.realisticPreview.rect(0, 1).attr(realistic_path_attrs).center(stitch.x, stitch.y).hide()
}
this.realisticPaths.push(realisticPath)
if (stitch.trim || stitch.color_change) {
stitching = false
} else if (!stitch.jump) {
stitching = true
}
prevStitch = stitch
})
})
},
generatePage () {
this.$refs.simulator.style.backgroundColor = this.page_specs.deskcolor
let page = this.svg.rect(this.page_specs.width, this.page_specs.height)
.move(-this.stitchPlan.bounding_box[0],-this.stitchPlan.bounding_box[1])
.fill(this.page_specs.pagecolor)
.stroke({width: 0.1, color: this.page_specs.bordercolor})
.back()
if (this.page_specs.showpageshadow === "true") {
let shadow = this.svg.rect(this.page_specs.width, this.page_specs.height)
.move(-this.stitchPlan.bounding_box[0],-this.stitchPlan.bounding_box[1])
.fill(this.page_specs.bordercolor)
.filterWith(add => {
let blur = add.offset(.5,.5).in(add.$source).gaussianBlur(.5)
})
.back()
}
this.page_specs["bbox"] = page.bbox()
},
zoomDesign () {
let [minx, miny, maxx, maxy] = this.stitchPlan.bounding_box
let designWidth = maxx - minx
let designHeight = maxy - miny
this.svg.viewbox(0, 0, designWidth, designHeight);
this.resizeCursor()
},
zoomPage () {
this.svg.viewbox(this.page_specs.bbox.x, this.page_specs.bbox.y - 50, this.page_specs.bbox.width + 100, this.page_specs.bbox.height + 100)
this.resizeCursor()
},
close () {
window.close()
}
},
created: function () {
// non-reactive properties
this.targetFPS = 30
this.targetFramePeriod = 1000.0 / this.targetFPS
this.renderedStitch = 0
this.lastFrameStart = null
this.stitchPaths = [null] // 1-indexed to match up with stitch number display
this.realisticPaths = [null]
this.stitches = [null]
this.svg = null
this.simulation = null
this.realisticPreview = null
this.timer = null
this.sliderColorSections = []
this.trimMarks = {}
this.stopMarks = {}
this.colorChangeMarks = {}
this.jumpMarks = {}
this.needlePenetrationPoints = []
this.cursor = null
this.page_specs = {}
},
mounted: function () {
this.svg = SVG().addTo(this.$refs.simulator).size('100%', '100%').panZoom({zoomMin: 0.1})
this.svg.node.classList.add('simulation')
this.simulation = this.svg.group({id: 'line'})
this.loading = true
inkStitch.get('stitch_plan').then(response => {
this.stitchPlan = response.data
let [minx, miny, maxx, maxy] = this.stitchPlan.bounding_box
let width = maxx - minx
let height = maxy - miny
this.svg.viewbox(0, 0, width, height);
this.stitchPlan.color_blocks.forEach(color_block => {
let color = `${color_block.color.visible_on_white.hex}`
let path_attrs = {fill: "none", stroke: color, "stroke-width": 0.3}
let marker = this.generateMarker(color)
let stitching = false
let prevStitch = null
color_block.stitches.forEach(stitch => {
stitch.x -= minx
stitch.y -= miny
let path = null
if (stitching && prevStitch) {
path = this.simulation.path(`M${prevStitch.x},${prevStitch.y} ${stitch.x},${stitch.y}`).attr(path_attrs).hide()
} else {
path = this.simulation.path(`M${stitch.x},${stitch.y} ${stitch.x},${stitch.y}`).attr(path_attrs).hide()
}
path.marker('end', marker)
this.stitchPaths.push(path)
this.stitches.push(stitch)
if (stitch.trim || stitch.color_change) {
stitching = false
} else if (!stitch.jump) {
stitching = true
}
prevStitch = stitch
})
})
this.numStitches = this.stitches.length - 1
this.generateMarks()
this.generateColorSections()
this.generateScale()
this.generateCursor()
this.resizeCursor()
this.loading = false
// v-on:keydown doesn't seem to work, maybe an Electron issue?
this.$mousetrap.bind("up", this.animationSpeedUp)
this.$mousetrap.bind("down", this.animationSlowDown)
this.$mousetrap.bind("left", this.animationReverse)
this.$mousetrap.bind("right", this.animationForward)
this.$mousetrap.bind("pagedown", this.animationPreviousCommand)
this.$mousetrap.bind("pageup", this.animationNextCommand)
this.$mousetrap.bind("space", this.toggleAnimation)
this.$mousetrap.bind("+", this.animationForwardOneStitch)
this.$mousetrap.bind("-", this.animationBackwardOneStitch)
this.$mousetrap.bind("]", this.zoomDesign)
this.$mousetrap.bind("[", this.zoomPage)
this.svg.on('zoom', this.resizeCursor)
inkStitch.get('page_specs').then(response => {
this.page_specs = response.data
this.generatePage()
})
this.start()
}).catch(error => {
this.loading = false
if (error.response) {
// Stitch plan generation had an error. Show it to the user.
this.error_message = error.response.data.error_message
} else if (error.request) {
// We sent the request and didn't get a response.
this.error_message = "Stitch plan generation failed."
} else {
// Something weird happened in axios.
this.error_message = error.message
}
this.error = true
})
}
}

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 60 KiB

Wyświetl plik

@ -1,307 +0,0 @@
/*
* Authors: see git history
*
* Copyright (c) 2010 Authors
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
*
*/
* {
padding: 1px;
margin: 1px;
}
.loading-icon {
text-align: center;
margin-bottom: 1rem;
color: rgb(0, 51, 153);
}
.loading-text {
font-family: sans-serif;
}
.loading {
border-radius: 1rem;
border: 3px solid rgb(0, 51, 153);
background-color: rgba(0, 51, 153, 0.1);
padding: 1rem;
}
.controls button {
color: rgb(0, 51, 153);
align-items: flex-start;
text-align: center;
cursor: default;
background: linear-gradient(0deg, rgba(169, 169, 169, 1) 0%, rgba(255, 255, 255, 1) 68%, rgba(227, 227, 227, 1) 100%);
box-sizing: border-box;
padding: 2px 6px 3px;
border-width: 2px;
border-style: outset;
border-color: buttonface;
border-image: initial;
margin-bottom: 5px;
}
.fa-spin-fast {
animation: fa-spin 0.4s infinite linear;
}
.fa-button {
margin: 3px;
}
.fa-fast {
transform: skew(-15deg, -15deg) rotate(15deg) scale(1.25, 0.90);
}
.fa-motion-lines {
transform: scale(1.0, 1.6) translate(0, -18%) skew(-15deg, -15deg) rotate(15deg);
}
.fa-thin-line {
transform: scale(1.4, 0.4);
}
.panel {
display: flex;
justify-content: space-between;
flex-flow: wrap;
}
.panel > * {
display: inline-block;
vertical-align: middle;
text-align: center;
}
.panel fieldset {
text-align: center;
flex: 1;
white-space: nowrap;
margin: 0 5px;
}
fieldset {
border: 2px solid rgb(0, 51, 153);
position: relative;
padding: 0 5px;
font-size: 90%;
background-color: white;
}
.window-controls {
position: absolute;
top: -0.2rem;
right: -2px;
font-size: 0.8rem;
color: white;
background: rgb(0, 51, 153);
transform: scale(1, 0.8) translate(0, -100%);
}
.window-controls > div {
display: inline-block;
padding: 5px;
}
.control-info {
position: absolute;
top: 0;
left: 0;
overflow-y: auto;
transform: translate(-100%, -100%);
padding: 0 1rem 1rem;
background: white;
color: black;
border: 1px solid rgb(0, 51, 153);
border-radius: 5px;
font-size: 1rem;
}
.info-icon {
float: right;
}
.control-info h1 {
background: rgb(0, 51, 153);
color: white;
margin: 0 -1rem 1rem;
padding: 1rem;
}
.control-info div {
display: table-row;
}
.control-info > div {
display: table;
}
.control-info div:first-child p {
font-weight: bold;
}
.control-info p {
display: table-cell;
white-space: nowrap;
border-bottom: 1px solid #ccc;
padding: 0.5rem;
}
fieldset button {
display: inline-block;
}
fieldset.command span.current-command {
display: block;
width: 18rem;
margin: 0 auto;
font-family: sans-serif;
font-size: 2rem;
vertical-align: middle;
}
fieldset.show-commands {
text-align: left;
}
fieldset.show-commands legend {
text-align: center;
}
fieldset.show-commands span {
display: inline-block;
vertical-align: top;
}
fieldset.show-commands span:first-of-type {
padding: 0 5px;
}
button.pressed {
border-style: inset;
}
.vue-slider {
height: 10px !important;
margin-bottom: 14px;
}
.slider-container {
margin: 25px 5px;
flex-grow: 0;
}
.slider-container > * {
display: inline-block;
vertical-align: middle;
}
.slider-box {
width: calc(100% - 11rem);
margin-left: 10px;
margin-right: 10px;
}
.slider-container :deep(.vue-slider-mark-step) {
width: 2px;
height: 20px;
border-radius: 2px;
background: #545454;
transform: translate(1px, -25%);
box-shadow: inset 1px 0 1px #ffffffbd, inset -1px 0 1px black;
}
.slider-container :deep(.vue-slider-mark:first-child .vue-slider-mark-step),
.slider-container :deep(.vue-slider-mark:last-child .vue-slider-mark-step) {
display: block;
}
.slider-container :deep(.vue-slider-rail) {
border: 1px solid #dedede;
}
.slider-container :deep(.vue-slider-process) {
border-radius: 0;
box-shadow: inset 0px 2px 2px #ffffff80, inset 0px -2px 2px #0000002e;
}
.slider-container :deep(.vue-slider-process:first-child) {
border-top-left-radius: 15px;
border-bottom-left-radius: 15px;
}
.slider-container :deep(.vue-slider-process:nth-last-child(3)) {
border-top-right-radius: 15px;
border-bottom-right-radius: 15px;
}
.vue-slider-mark-label {
font-size: 1.4rem;
color: #545454;
}
.vue-slider-mark-label svg path {
stroke: white;
stroke-width: 10px;
}
.slider-label-trim {
transform: scale(1, 0.75) translate(-50%, -9px) !important;;
}
.slider-label-stop {
font-size: 1.2rem;
transform: translate(-50%, 12px) !important;;
}
.slider-label-jump {
transform: translate(-50%, -50px) !important;;
}
.slider-label-color-change {
transform: translate(-50%, 10px) !important;;
}
.current-stitch-input {
width: 4rem;
float: right;
font-size: 1rem;
border-style: inset;
padding: 0 3px;
}
.simulator {
display: flex;
flex-direction: column;
height: 95vh;
margin: 10px;
}
.current-command {
color: rgb(0, 51, 153);
font-weight: bold;
}
/* we need ::v-deep here because the svg tag is added by svg.js and so Vue
can't add the data-v-* attribute
*/
div.simulator :deep(svg.simulation) {
flex-grow: 1;
flex-shrink: 1;
order: -2;
margin-bottom: -48px;
}
div.simulator :deep(svg.simulation-scale) {
height: 50px;
order: -1;
margin-left: 5px;
}
div.simulator :deep(.simulation-scale-label) {
font-size: 14px;
}
div.simulator :deep(.cursor) {
/* not sure what to add here to make it more visible */
}

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -1,12 +0,0 @@
<!--
Authors: see git history
Copyright (c) 2010 Authors
Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
-->
<template>
<h1>Oops, it looks like the page you're looking for doesn't exist.</h1>
</template>

Wyświetl plik

@ -1,327 +0,0 @@
<!--
Authors: see git history
Copyright (c) 2010 Authors
Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
-->
<template>
<div ref="simulator" class="simulator vld-parent">
<fieldset>
<div class="window-controls">
<div ref="controlInfoButton" class="control-info-button" v-on:click="toggleInfo">
<font-awesome-icon icon="info"/>
<Transition name="collapse">
<div class="control-info" v-show="infoExpanded" v-bind:style="{'max-height': infoMaxHeight + 'px'}">
<h1>
<font-awesome-icon icon="info" class="info-icon"/>
<translate>Simulator Shortcut Keys</translate>
</h1>
<div>
<div>
<p>
<translate>Button</translate>
</p>
<p>
<translate>Function</translate>
</p>
<p>
<translate>Shortcut Key</translate>
</p>
</div>
<div>
<p>
<font-awesome-icon icon="pause" class="fa-button"/>
</p>
<p>
<translate>Pause</translate>
</p>
<p>
<translate>Space</translate>
</p>
</div>
<div>
<p>
<font-awesome-icon icon="play" class="fa-button"/>
</p>
<p>
<translate>Play</translate>
</p>
<p>P</p>
</div>
<div>
<p>
<font-awesome-icon icon="angle-double-left" class="fa-button"/>
</p>
<p>
<translate>Play backward</translate>
</p>
<p>
<translate translate-comment="name for left arrow keyboard key"> Arrow left</translate>
</p>
</div>
<div>
<p>
<font-awesome-icon icon="angle-double-right" class="fa-button"/>
</p>
<p>
<translate>Play forward</translate>
</p>
<p>
<translate translate-comment="name for right arrow keyboard key"> Arrow right</translate>
</p>
</div>
<div>
<p>
<font-awesome-icon icon="shoe-prints" class="fa-button fa-flip-horizontal"/>
</p>
<p>
<translate translate-comment="description of keyboard shortcut that moves one stitch backward in simulator">
One step backward
</translate>
</p>
<p>-
<translate translate-comment="name for this keyboard key: -">Minus</translate>
</p>
</div>
<div>
<p>
<font-awesome-icon icon="shoe-prints" class="fa-button"/>
</p>
<p>
<translate translate-comment="description of keyboard shortcut that moves one stitch forward in simulator">
One step forward
</translate>
</p>
<p>
<translate translate-comment="name for this keyboard key: +">+ Plus</translate>
</p>
</div>
<div>
<p>
<font-awesome-icon icon="step-backward" class="fa-button"/>
</p>
<p>
<translate>Jump to previous command</translate>
</p>
<p><translate translate-comment="name for page down keyboard key">Page down (PgDn)</translate></p>
</div>
<div>
<p>
<font-awesome-icon icon="step-forward" class="fa-button"/>
</p>
<p>
<translate>Jump to next command</translate>
</p>
<p><translate translate-comment="name for page up keyboard key">Page up (PgUp)</translate></p>
</div>
<div>
<p>
<font-awesome-icon icon="hippo" class="fa-button"/>
</p>
<p>
<translate>Slow down</translate>
</p>
<p>
<translate translate-comment="name for down arrow keyboard key"> Arrow down</translate>
</p>
</div>
<div>
<p>
<font-awesome-icon icon="horse" class="fa-button"/>
</p>
<p>
<translate>Speed up</translate>
</p>
<p>
<translate translate-comment="name for up arrow keyboard key"> Arrow up</translate>
</p>
</div>
</div>
<div>
<p>
<font-awesome-icon icon="search-minus" class="fa-button"/>
</p>
<p>
<translate>Zoom page</translate>
</p>
<p>
<translate>[ Left square bracket</translate>
</p>
</div>
<div>
<p>
<font-awesome-icon icon="search-plus" class="fa-button"/>
</p>
<p>
<translate>Zoom design</translate>
</p>
<p>
<translate>] Right square bracket</translate>
</p>
</div>
</div>
</Transition>
</div>
<div class="toggle-controls" v-on:click="toggleControls">
<font-awesome-icon v-if="controlsExpanded" icon="minus"/>
<font-awesome-icon v-else icon="plus"/>
</div>
</div>
<Transition name="collapse">
<div class="panel" v-show="controlsExpanded">
<fieldset class="controls">
<legend>
<translate>Controls</translate>
</legend>
<button v-on:click="stop" :class="{pressed: paused}" :title="$gettext('Pause (space)')">
<font-awesome-icon icon="pause" size="2x" class="fa-button"/>
</button>
<button v-on:click="start" :class="{pressed: animating}" :title="$gettext('Play (arrow left | arrow right)')">
<font-awesome-icon icon="play" size="2x" class="fa-button"/>
</button>
<button v-on:click="animationReverse" :class="{pressed: reverse}" :title="$gettext('Play backward (arrow left)')">
<font-awesome-icon icon="angle-double-left" size="2x" class="fa-button" :mask="['fas', 'stop']"/>
</button>
<button v-on:click="animationForward" :class="{pressed: forward}" :title="$gettext('Play forward (arrow right)')">
<font-awesome-icon icon="angle-double-right" size="2x" class="fa-button" :mask="['fas', 'stop']"/>
</button>
<button v-on:click="animationBackwardOneStitch" :title="$gettext('One step backward (-)')">
<font-awesome-icon icon="shoe-prints" size="2x" class="fa-button fa-flip-horizontal"/>
</button>
<button v-on:click="animationForwardOneStitch" :title="$gettext('One step forward (+)')">
<font-awesome-icon icon="shoe-prints" size="2x" class="fa-button"/>
</button>
<button v-on:click="animationPreviousCommand" :title="$gettext('Jump to previous command (Page down)')">
<font-awesome-icon icon="step-backward" size="2x" class="fa-button"/>
</button>
<button v-on:click="animationNextCommand" :title="$gettext('Jump to next command (Page up)')">
<font-awesome-icon icon="step-forward" size="2x" class="fa-button"/>
</button>
</fieldset>
<fieldset class="speed">
<legend>
<translate :translate-params="{ speed: speed }" :translate-n="speed" translate-plural="Speed: %{speed} stitches/sec">Speed: %{speed} stitch/sec</translate>
</legend>
<button v-on:click="animationSlowDown" :title="$gettext('Slow down (arrow down)')">
<font-awesome-icon icon="hippo" size="2x" class="fa-button"/>
</button>
<button v-on:click="animationSpeedUp" :title="$gettext('Speed up (arrow up)')">
<font-awesome-icon icon="align-right" class="fa-motion-lines"/>
<font-awesome-icon icon="horse" size="2x" class="fa-button fa-fast"/>
</button>
</fieldset>
<fieldset class="view">
<legend>
<translate>View</translate>
</legend>
<button v-on:click="zoomPage" :title="$gettext('Zoom page ([)')">
<font-awesome-icon icon="search-minus" size="2x" class="fa-button"/>
</button>
<button v-on:click="zoomDesign" :title="$gettext('Zoom design (])')">
<font-awesome-icon icon="search-plus" size="2x" class="fa-button"/>
</button>
</fieldset>
<fieldset class="command">
<legend>
<translate>Command</translate>
</legend>
<span class="current-command">{{currentCommand}}</span>
</fieldset>
<fieldset class="show-commands">
<legend>
<translate>Show</translate>
</legend>
<span>
<input id="trim-checkbox" type="checkbox" v-model="showTrims"/>
<label for="trim-checkbox"><font-awesome-icon icon="cut"/> <translate>trims</translate></label>
<br/>
<input id="jump-checkbox" type="checkbox" v-model="showJumps"/>
<label for="jump-checkbox"><font-awesome-icon icon="frog"/> <translate>jumps</translate></label>
</span>
<span>
<input id="color-change-checkbox" type="checkbox" v-model="showColorChanges"/>
<label for="color-change-checkbox"><font-awesome-icon icon="exchange-alt"/> <translate>color changes</translate></label>
<br/>
<input id="stop-checkbox" type="checkbox" v-model="showStops"/>
<label for="stop-checkbox"><font-awesome-icon icon="pause"/> <translate>stops</translate></label>
</span>
<span class="npp">
<input id="npp-checkbox" type="checkbox" v-model="showNeedlePenetrationPoints"/>
<label for="npp-checkbox">
<font-awesome-layers>
<font-awesome-icon icon="circle" transform="shrink-9"/>
<font-awesome-icon icon="minus" class="fa-thin-line"/>
</font-awesome-layers>
<span v-translate>needle points</span>
</label>
<br />
<input id="render-jumps-checkbox" type="checkbox" v-model="renderJumps"/>
<label for="render-jumps-checkbox"><font-awesome-icon icon="link"/><span v-translate>render jumps</span></label>
</span>
<span>
<input id="realistic-checkbox" type="checkbox" v-model="showRealisticPreview"/>
<label for="realistic-checkbox"><font-awesome-icon icon="eye"/> <span v-translate>realistic</span></label>
<br/>
<input id="cursor-checkbox" type="checkbox" v-model="showCursor"/>
<label for="cursor-checkbox"><font-awesome-icon icon="plus"/> <span v-translate>cursor</span></label>
</span>
</fieldset>
</div>
</Transition>
<div class="slider-container">
<span>1</span>
<span class="slider-box">
<vue-slider v-model="currentStitchDisplay"
@change="setCurrentStitch"
:min="0"
:max="numStitches"
:duration="0"
:marks="sliderMarks"
:process="sliderProcess">
<template v-slot:label="mark">
<div :class="['vue-slider-mark-label', `slider-label-${mark.command}`, { active: mark.active }]">
<font-awesome-icon :icon="mark.icon"/>
</div>
</template>
</vue-slider>
</span>
<span>{{numStitches}}</span>
<input ref="currentStitchInput"
class="current-stitch-input"
:value="currentStitchDisplay"
@change="onCurrentStitchEntered"
@focus="stop"/>
</div>
</fieldset>
<loading :active="loading" :is-full-page="false">
<div class="loading">
<div class="loading-icon">
<font-awesome-icon icon="spinner" size="4x" pulse/>
</div>
<div class="loading-text">
<translate>Rendering stitch-plan...</translate>
</div>
</div>
</loading>
<v-dialog v-model="error" width="auto">
<v-card flat>
<v-card-title class="pa-4">
Error Generating Stitch Plan
</v-card-title>
<v-card-text>
<p style="white-space: pre-wrap;">{{ error_message }}</p>
</v-card-text>
<v-card-actions class="justify-center">
<v-btn color="primary" variant="text" class="dialog-button" @click="close">Close</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script src="../assets/js/simulator.js"></script>
<style src="../assets/style/simulator.css" scoped></style>

Wyświetl plik

@ -1,74 +0,0 @@
/*
* Authors: see git history
*
* Copyright (c) 2010 Authors
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
*
*/
// ES6
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { library } from '@fortawesome/fontawesome-svg-core'
import { fas } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
import { createGettext } from 'vue3-gettext'
import translations from './assets/translations.json'
import { selectLanguage } from '../lib/i18n.js'
import flaskserverport from '../lib/flaskserverport.json'
import { createVuetify, ThemeDefinition } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import 'vuetify/styles'
import VueMousetrapPlugin from 'vue-mousetrap'
if (flaskserverport.port === undefined) {
var theflaskport = window.inkstitchAPI.flaskport()
console.log("Installed mode")
console.log(theflaskport)
} else {
var theflaskport = flaskserverport.port
console.log("Dev mode")
console.log(theflaskport)
}
const inkStitchTheme = {
dark: false,
colors: {
primary: '#003399',
secondary: '#000000',
accent: '#8c9eff',
error: '#b71c1c',
}
}
const vuetify = new createVuetify({
components,
directives,
ssr: true,
theme: {
defaultTheme: 'inkStitchTheme',
themes: {
inkStitchTheme,
}
}
})
library.add(fas)
const app = createApp(App)
app.component('font-awesome-icon', FontAwesomeIcon)
app.component('font-awesome-layers', FontAwesomeLayers)
app.use(createGettext({
defaultLanguage: selectLanguage(translations, theflaskport),
translations: translations,
silent: true,
setGlobalProperties: true,
}))
app.use(VueMousetrapPlugin)
app.use(vuetify)
app.use(router)
app.mount('#app')

Wyświetl plik

@ -1,31 +0,0 @@
/*
* Authors: see git history
*
* Copyright (c) 2010 Authors
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
*
*/
import { createWebHashHistory, createRouter } from 'vue-router'
const routes = [
{
path: '/simulator',
name: 'simulator',
component: () => import('../components/Simulator.vue')
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('../components/NotFound.vue')
},
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
// Sets title for each routes
const DEFAULT_TITLE = 'Ink/Stitch';
router.beforeEach((to) => {
document.title = to.meta.title || DEFAULT_TITLE
})
export default router

Wyświetl plik

@ -1,21 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": ["webpack-env"],
"paths": {
"@/*": ["src/*"]
},
"lib": ["ESNext", "DOM", "DOM.Iterable", "ScriptHost"]
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts", "tests/**/*.tsx"],
"exclude": ["node_modules", "dist"]
}

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 8.0 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 8.0 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 938 B

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 938 B

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 19 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 19 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.0 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.0 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.0 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.0 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 38 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 38 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 4.0 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.0 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 6.0 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 6.0 KiB

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 39 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 39 KiB

Wyświetl plik

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.debugger</key>
<true/>
</dict>
</plist>

Wyświetl plik

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>BundleHasStrictIdentifier</key>
<false/>
<key>BundleIsRelocatable</key>
<false/>
<key>BundleIsVersionChecked</key>
<false/>
<key>BundleOverwriteAction</key>
<string>install</string>
<key>RootRelativeBundlePath</key>
<string>Contents/Frameworks/electron/inkstitch-gui.app</string>
</dict>
</array>
</plist>

Wyświetl plik

@ -264,7 +264,7 @@ class PrintPreviewServer(Thread):
self.host = "127.0.0.1"
self.port = self.find_free_port()
# exporting the port number for languages to work in electron vuejs part of inkstitch
# exporting the port number for languages to work
os.environ['FLASKPORT'] = str(self.port)
self.flask_server = make_server(self.host, self.port, self.app)

Wyświetl plik

@ -4,7 +4,6 @@
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
from .dialogs import confirm_dialog, info_dialog
from .electron import open_url
from .presets import PresetsPanel
from .simulator import PreviewRenderer
from .warnings import WarningPanel

Wyświetl plik

@ -1,91 +0,0 @@
# Authors: see git history
#
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
import json
import os
import subprocess
import sys
from ..utils import get_bundled_dir
app_process = None
def open_url(url, port, pdf=False): # noqa: C901
global app
if not pdf:
url = f'{url}?port={port}'
os.environ['FLASKPORT'] = str(port)
# this creates the .json for dev mode to get translations
if getattr(sys, 'frozen', None) is None:
dynamic_port = {
"_comment1": "port should not be declared when commiting",
"port": port,
}
port_object = json.dumps(dynamic_port, indent=1)
with open(os.path.join("electron/src/lib/flaskserverport.json"), "w") as outfile:
outfile.write(port_object)
else:
url = f'http://{url}:{port}/'
cwd = None
searchstring = "http"
if getattr(sys, 'frozen', None) is not None:
electron_path = os.path.join(get_bundled_dir("electron"), "inkstitch-gui")
if sys.platform == "darwin":
electron_path = os.path.join(sys._MEIPASS, "electron", "inkstitch-gui.app", "Contents", "MacOS", "inkstitch-gui")
command = ["open", "-W", "-a", electron_path, "--args", url]
else:
command = [electron_path, url]
else:
# if we're not running in a pyinstaller bundle, run electron directly
command = ["yarn", "dev", url]
cwd = get_bundled_dir("electron")
# Any output on stdout will crash inkscape.
# In macos manual install the python env paths are incomplete
# Adding the yarn path to the env paths fixes this issue
if sys.platform == "darwin" and getattr(sys, 'frozen', None) is None:
mac_dev_env = os.environ.copy()
# these are paths installed by brew or macports
yarn_path = "/opt/homebrew/bin:/usr/local/bin:/opt/local/bin:"
if yarn_path in mac_dev_env["PATH"]:
pass
else:
mac_dev_env["PATH"] = yarn_path + mac_dev_env["PATH"]
# checking URL for flask server address for printToPDF
if searchstring in url:
with open(os.devnull, 'w') as null:
subprocess.Popen(["yarn", "just-build"], cwd=cwd, stdout=null, env=mac_dev_env).wait()
else:
pass
with open(os.devnull, 'w') as null:
return subprocess.Popen(command, cwd=cwd, stdout=null, env=mac_dev_env)
else:
if searchstring in url and getattr(sys, 'frozen', None) is None:
with open(os.devnull, 'w') as null:
subprocess.Popen(["yarn", "just-build"], cwd=cwd, stdout=null).wait()
else:
pass
if sys.platform == "linux":
# Pyinstaller fix for gnome document view not opening.
lenv = dict(os.environ)
lp_key = 'LD_LIBRARY_PATH'
lp_orig = lenv.get(lp_key + '_ORIG')
if lp_orig is not None:
lenv[lp_key] = lp_orig # restore the original, unmodified value
else:
lenv.pop(lp_key, None)
with open(os.devnull, 'w') as null:
return subprocess.Popen(command, cwd=cwd, stdout=null, env=lenv)
else:
with open(os.devnull, 'w') as null:
return subprocess.Popen(command, cwd=cwd, stdout=null)