From 9ccf2f552be246f7912e9dc923f8da8ae47fe544 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Wed, 10 Apr 2019 23:37:16 -0400 Subject: switch print pdf gui to electron --- lib/extensions/print_pdf.py | 141 ++++++-------------------------------------- 1 file changed, 17 insertions(+), 124 deletions(-) (limited to 'lib/extensions') diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index 4913a32a..e736b05b 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -1,27 +1,27 @@ -import sys +from copy import deepcopy +from datetime import date +import errno +import json +import logging import os -from threading import Thread import socket -import errno +import sys +from threading import Thread import time -import logging -from copy import deepcopy -import wx + import appdirs -import json +from flask import Flask, request, Response, send_from_directory, jsonify import inkex from jinja2 import Environment, FileSystemLoader, select_autoescape -from datetime import date -from flask import Flask, request, Response, send_from_directory, jsonify -import webbrowser import requests -from .base import InkstitchExtension +from ..gui import open_url from ..i18n import _, translation as inkstitch_translation +from ..stitch_plan import patches_to_stitch_plan from ..svg import render_stitch_plan from ..svg.tags import INKSCAPE_GROUPMODE -from ..stitch_plan import patches_to_stitch_plan from ..threads import ThreadCatalog +from .base import InkstitchExtension def datetimeformat(value, format='%Y/%m/%d'): @@ -51,42 +51,6 @@ def save_defaults(defaults): json.dump(defaults, defaults_file) -def open_url(url): - # Avoid spurious output from xdg-open. Any output on stdout will crash - # inkscape. - null = open(os.devnull, 'w') - old_stdout = os.dup(sys.stdout.fileno()) - os.dup2(null.fileno(), sys.stdout.fileno()) - - if getattr(sys, 'frozen', False): - - # PyInstaller sets LD_LIBRARY_PATH. We need to temporarily clear it - # to avoid confusing xdg-open, which webbrowser will run. - - # The following code is adapted from PyInstaller's documentation - # http://pyinstaller.readthedocs.io/en/stable/runtime-information.html - - old_environ = dict(os.environ) # make a copy of the environment - lp_key = 'LD_LIBRARY_PATH' # for Linux and *BSD. - lp_orig = os.environ.get(lp_key + '_ORIG') # pyinstaller >= 20160820 has this - if lp_orig is not None: - os.environ[lp_key] = lp_orig # restore the original, unmodified value - else: - os.environ.pop(lp_key, None) # last resort: remove the env var - - webbrowser.open(url) - - # restore the old environ - os.environ.clear() - os.environ.update(old_environ) - else: - webbrowser.open(url) - - # restore file descriptors - os.dup2(old_stdout, sys.stdout.fileno()) - os.close(old_stdout) - - class PrintPreviewServer(Thread): def __init__(self, *args, **kwargs): self.html = kwargs.pop('html') @@ -96,7 +60,6 @@ class PrintPreviewServer(Thread): self.realistic_color_block_svgs = kwargs.pop('realistic_color_block_svgs') Thread.__init__(self, *args, **kwargs) self.daemon = True - self.last_request_time = None self.shutting_down = False self.__setup_app() @@ -111,16 +74,6 @@ class PrintPreviewServer(Thread): self.__set_resources_path() self.app = Flask(__name__) - @self.app.before_request - def request_started(): - self.last_request_time = time.time() - - @self.app.before_first_request - def start_watcher(): - self.watcher_thread = Thread(target=self.watch) - self.watcher_thread.daemon = True - self.watcher_thread.start() - @self.app.route('/') def index(): return self.html @@ -129,17 +82,12 @@ class PrintPreviewServer(Thread): def shutdown(): self.shutting_down = True request.environ.get('werkzeug.server.shutdown')() - return _('Closing...') + '

' + _('It is safe to close this window now.') + return "shutting down" @self.app.route('/resources/', methods=['GET']) def resources(resource): return send_from_directory(self.resources_path, resource, cache_timeout=1) - @self.app.route('/ping') - def ping(): - # Javascript is letting us know it's still there. This resets self.last_request_time. - return "pong" - @self.app.route('/printing/start') def printing_start(): # temporarily turn off the watcher while the print dialog is up, @@ -215,21 +163,6 @@ class PrintPreviewServer(Thread): # the context of a flask request, so we'll just make one requests.post("http://%s:%s/shutdown" % (self.host, self.port)) - def watch(self): - try: - while True: - time.sleep(1) - if self.shutting_down: - break - - if self.last_request_time is not None and \ - (time.time() - self.last_request_time) > 3: - self.stop() - break - except BaseException: - # seems like sometimes this thread blows up during shutdown - pass - def disable_logging(self): logging.getLogger('werkzeug').setLevel(logging.ERROR) @@ -252,42 +185,6 @@ class PrintPreviewServer(Thread): break -class PrintInfoFrame(wx.Frame): - def __init__(self, *args, **kwargs): - self.print_server = kwargs.pop("print_server") - wx.Frame.__init__(self, *args, **kwargs) - - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - - message = _("A print preview has been opened in your web browser. " - "This window will stay open in order to communicate with the JavaScript code running in your browser.\n\n" - "This window will close after you close the print preview in your browser, or you can close it manually if necessary.") - text = wx.StaticText(panel, label=message) - font = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.NORMAL) - text.SetFont(font) - sizer.Add(text, proportion=1, flag=wx.ALL | wx.EXPAND, border=20) - - stop_button = wx.Button(panel, id=wx.ID_CLOSE) - stop_button.Bind(wx.EVT_BUTTON, self.close_button_clicked) - sizer.Add(stop_button, proportion=0, flag=wx.ALIGN_CENTER | wx.ALL, border=10) - - panel.SetSizer(sizer) - panel.Layout() - - self.timer = wx.PyTimer(self.__watcher) - self.timer.Start(250) - - def close_button_clicked(self, event): - self.print_server.stop() - - def __watcher(self): - if not self.print_server.is_alive(): - self.timer.Stop() - self.timer = None - self.Destroy() - - class Print(InkstitchExtension): def build_environment(self): if getattr(sys, 'frozen', False): @@ -409,11 +306,7 @@ class Print(InkstitchExtension): realistic_color_block_svgs=realistic_color_block_svgs ) print_server.start() - - time.sleep(1) - open_url("http://%s:%s/" % (print_server.host, print_server.port)) - - app = wx.App() - info_frame = PrintInfoFrame(None, title=_("Ink/Stitch Print"), size=(450, 350), print_server=print_server) - info_frame.Show() - app.MainLoop() + browser_window = open_url("http://%s:%s/" % (print_server.host, print_server.port)) + browser_window.wait() + print_server.stop() + print_server.join() -- cgit v1.3.1 From 7e04b879c27fd0ece9193adf48cc2939c66de08b Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Thu, 11 Apr 2019 00:03:33 -0400 Subject: wait for server to (probably) be up --- lib/extensions/print_pdf.py | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/extensions') diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index e736b05b..6eef1f8d 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -306,6 +306,7 @@ class Print(InkstitchExtension): realistic_color_block_svgs=realistic_color_block_svgs ) print_server.start() + time.sleep(0.5) browser_window = open_url("http://%s:%s/" % (print_server.host, print_server.port)) browser_window.wait() print_server.stop() -- cgit v1.3.1 From 3a3c9e5406563edd00c2ec08102ca7c69aaa360c Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Fri, 12 Apr 2019 15:32:37 -0400 Subject: fix style --- Makefile | 2 +- lib/extensions/print_pdf.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/extensions') diff --git a/Makefile b/Makefile index 14ac69ff..4433c00f 100644 --- a/Makefile +++ b/Makefile @@ -63,4 +63,4 @@ locales: .PHONY: style style: - flake8 . --count --max-complexity=10 --max-line-length=150 --statistics --exclude=pyembroidery,__init__.py + flake8 . --count --max-complexity=10 --max-line-length=150 --statistics --exclude=pyembroidery,__init__.py,electron,build diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index 6eef1f8d..4d8ffbd4 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -16,7 +16,7 @@ from jinja2 import Environment, FileSystemLoader, select_autoescape import requests from ..gui import open_url -from ..i18n import _, translation as inkstitch_translation +from ..i18n import translation as inkstitch_translation from ..stitch_plan import patches_to_stitch_plan from ..svg import render_stitch_plan from ..svg.tags import INKSCAPE_GROUPMODE -- cgit v1.3.1 From 9b2a47136b34a4b9cfcc42282a39fdd909e9f8af Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Fri, 12 Apr 2019 17:45:57 -0400 Subject: enable print button --- electron/package.json | 15 +++++++++++---- electron/src/index.js | 21 +++++++++++++++++++-- lib/extensions/print_pdf.py | 12 ------------ lib/gui/electron.py | 22 +++++++--------------- print/resources/inkstitch.js | 11 ++++------- 5 files changed, 41 insertions(+), 40 deletions(-) (limited to 'lib/extensions') diff --git a/electron/package.json b/electron/package.json index 1306eb68..c902b205 100644 --- a/electron/package.json +++ b/electron/package.json @@ -6,12 +6,19 @@ "main": "src/index.js", "scripts": { "pack": "electron-builder --dir", - "dist": "electron-builder" + "dist": "electron-builder", + "dev": "electron ." }, "build": { - "linux": { "target": "dir" }, - "win": { "target": "dir" }, - "mac": { "target": "dir" } + "linux": { + "target": "dir" + }, + "win": { + "target": "dir" + }, + "mac": { + "target": "dir" + } }, "keywords": [], "author": "lex", diff --git a/electron/src/index.js b/electron/src/index.js index 398a9580..90aaea63 100644 --- a/electron/src/index.js +++ b/electron/src/index.js @@ -1,4 +1,5 @@ -import { app, BrowserWindow } from 'electron'; +import { app, BrowserWindow, ipcMain, dialog } from 'electron'; +var fs = require('fs'); // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,8 +12,16 @@ const createWindow = () => { mainWindow.maximize(); // and load the index.html of the app. - mainWindow.loadURL(process.argv[1]); + if (process.argv[1] == ".") { + // run in development mode with `electron . ` + var url = process.argv[2]; + } else { + var url = process.argv[1]; + } + mainWindow.loadURL(url); + mainWindow.webContents.openDevTools(); + // Emitted when the window is closed. mainWindow.on('closed', () => { // Dereference the window object, usually you would store windows @@ -31,3 +40,11 @@ app.on('ready', createWindow); app.on('window-all-closed', () => { app.quit(); }); + +ipcMain.on('print', function (event, pageSize) { + mainWindow.webContents.printToPDF({"pageSize": pageSize}, function(error, data) { + dialog.showSaveDialog(mainWindow, {"defaultPath": "inkstitch.pdf"}, function(filename, bookmark) { + fs.writeFileSync(filename, data, 'utf-8'); + }) + }) +}) \ No newline at end of file diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index 4d8ffbd4..0cbce479 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -88,18 +88,6 @@ class PrintPreviewServer(Thread): def resources(resource): return send_from_directory(self.resources_path, resource, cache_timeout=1) - @self.app.route('/printing/start') - def printing_start(): - # temporarily turn off the watcher while the print dialog is up, - # because javascript will be frozen - self.last_request_time = None - return "OK" - - @self.app.route('/printing/end') - def printing_end(): - # nothing to do here -- request_started() will restart the watcher - return "OK" - @self.app.route('/settings/', methods=['POST']) def set_field(field_name): self.metadata[field_name] = request.json['value'] diff --git a/lib/gui/electron.py b/lib/gui/electron.py index ced3ad66..f1bdeb61 100644 --- a/lib/gui/electron.py +++ b/lib/gui/electron.py @@ -1,4 +1,3 @@ -from glob import glob import os import subprocess import sys @@ -14,21 +13,14 @@ def open_url(url): if getattr(sys, 'frozen', None) is not None: electron_path = os.path.join(get_bundled_dir("electron"), "inkstitch-gui") - else: - # It's a bit trickier to find the electron app in a development environment. - base_dir = get_bundled_dir("electron") - - try: - package_dir = glob(os.path.join(base_dir, 'dist', '*-unpacked'))[0] - except IndexError: - raise Exception("Electron app not found. Be sure to run 'yarn; yarn dist' in %s." % base_dir) - - electron_path = os.path.join(base_dir, package_dir, "inkstitch-gui") - if sys.platform == "darwin": - electron_path += ".app/Contents/MacOS/inkstitch-gui" - app_process = subprocess.Popen(["open", "-a", electron_path, "--args", url]) + if sys.platform == "darwin": + electron_path += ".app/Contents/MacOS/inkstitch-gui" + subprocess.Popen(["open", "-a", electron_path, "--args", url]) + else: + app_process = subprocess.Popen([electron_path, url]) else: - app_process = subprocess.Popen([electron_path, url]) + # if we're not running in a pyinstaller bundle, run electron directly + app_process = subprocess.Popen(["yarn", "dev", url], cwd=get_bundled_dir("electron")) return app_process diff --git a/print/resources/inkstitch.js b/print/resources/inkstitch.js index c58aed8a..32a9a207 100644 --- a/print/resources/inkstitch.js +++ b/print/resources/inkstitch.js @@ -1,3 +1,5 @@ +var electron = require('electron'); + $.postJSON = function(url, data, success=null) { return $.ajax(url, { type: 'POST', @@ -366,13 +368,8 @@ $(function() { }); $('button.print').click(function() { - // printing halts all javascript activity, so we need to tell the backend - // not to shut down until we're done. - $.get("/printing/start") - .done(function() { - window.print(); - $.get("/printing/end"); - }); + var pageSize = $('select#printing-size').find(':selected').text(); + electron.ipcRenderer.send('print', pageSize) }); $('button.settings').click(function(){ -- cgit v1.3.1 From 352aebad5e9f5439f428efdeb1c29a51fa4bad96 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Tue, 23 Apr 2019 19:57:49 -0400 Subject: comment to explain sleep --- lib/extensions/print_pdf.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib/extensions') diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index 0cbce479..befb7861 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -294,7 +294,12 @@ class Print(InkstitchExtension): realistic_color_block_svgs=realistic_color_block_svgs ) print_server.start() + + # Wait for print_server.host and print_server.port to be populated. + # Hacky, but Flask doesn't have an option for a callback to be run + # after startup. time.sleep(0.5) + browser_window = open_url("http://%s:%s/" % (print_server.host, print_server.port)) browser_window.wait() print_server.stop() -- cgit v1.3.1