From d5c9b44a6661f7f357eaf6063f77c33fcc79f8a9 Mon Sep 17 00:00:00 2001
From: Albert Graef <aggraef@gmail.com>
Date: Fri, 3 Feb 2017 04:26:11 +0100
Subject: [PATCH] Add a Print option to the canvas menu which prints the patch
 to a pdf file.

---
 pd/nw/locales/de/translation.json |  2 ++
 pd/nw/locales/en/translation.json |  2 ++
 pd/nw/pd_canvas.html              |  4 +++
 pd/nw/pd_canvas.js                |  7 ++++
 pd/nw/pd_menus.js                 |  6 ++++
 pd/nw/pdgui.js                    | 53 +++++++++++++++++++++++++++++++
 pd/src/g_readwrite.c              | 10 ++++++
 7 files changed, 84 insertions(+)

diff --git a/pd/nw/locales/de/translation.json b/pd/nw/locales/de/translation.json
index d9d820c8a..fa694938b 100644
--- a/pd/nw/locales/de/translation.json
+++ b/pd/nw/locales/de/translation.json
@@ -109,6 +109,8 @@
     "save_tt": "Speichere einen Pd-Patch auf der Festplatte",
     "saveas": "Speichern unter...",
     "saveas_tt": "Speichere einen Pd-Patch unter einem neuen Dateinamen",
+    "print": "Drucken...",
+    "print_tt": "Drucke einen Pd-Patch und speichere das Resultat in einer PDF-Datei",
     "message": "Nachricht...",
     "message_tt": "Sende eine Nachricht direkt an die laufende Pd-Instanz",
 
diff --git a/pd/nw/locales/en/translation.json b/pd/nw/locales/en/translation.json
index 14b758bc8..8e83ee1d7 100644
--- a/pd/nw/locales/en/translation.json
+++ b/pd/nw/locales/en/translation.json
@@ -109,6 +109,8 @@
     "save_tt": "Save a Pd patch to disk",
     "saveas": "Save as...",
     "saveas_tt": "Save a Pd patch by manually choosing a filename",
+    "print": "Print...",
+    "print_tt": "Print a Pd patch, saving the result to a PDF file",
     "message": "Message...",
     "message_tt": "Send a message directly to the running Pd instance",
 
diff --git a/pd/nw/pd_canvas.html b/pd/nw/pd_canvas.html
index a960a8498..78460d810 100644
--- a/pd/nw/pd_canvas.html
+++ b/pd/nw/pd_canvas.html
@@ -15,6 +15,10 @@
       <input style="display:none;" id="saveDialog" type="file"
              nwsaveas nwworkingdir accept=".pd" />
     </span>
+    <span id = "printDialogSpan">
+      <input style="display:none;" id="printDialog" type="file"
+             nwsaveas nwworkingdir accept=".pdf" />
+    </span>
     <input style="display:none;" id="openpanel_dialog" type="file" />
     <input style="display:none;" id="savepanel_dialog" type="file"
            nwsaveas nwworkingdir />
diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js
index 77defb364..8c066b8ad 100644
--- a/pd/nw/pd_canvas.js
+++ b/pd/nw/pd_canvas.js
@@ -1057,6 +1057,13 @@ function nw_create_patch_window_menus(gui, w, name) {
             pdgui.menu_saveas(name);
         }
     });
+    minit(m.file.print, {
+        enabled: true,
+        click: function (){
+            pdgui.canvas_check_geometry(name);
+            pdgui.menu_print(name);
+        }
+    });
     minit(m.file.message, {
         click: function() { pdgui.menu_send(name); }
     });
diff --git a/pd/nw/pd_menus.js b/pd/nw/pd_menus.js
index 829a684a4..85d8fce67 100644
--- a/pd/nw/pd_menus.js
+++ b/pd/nw/pd_menus.js
@@ -99,6 +99,12 @@ function create_menu(gui, type) {
             modifiers: cmd_or_ctrl + "+shift",
             tooltip: l("menu.saveas_tt")
         }));
+        file_menu.append(m.file.print = new gui.MenuItem({
+            label: l("menu.print"),
+            key: "p",
+            modifiers: cmd_or_ctrl + "+shift",
+            tooltip: l("menu.print_tt")
+        }));
     }
     if (pdgui.k12_mode == 0) {
         file_menu.append(new gui.MenuItem({ type: "separator" }));
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 6e340c9ef..a8c6ac30d 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -756,6 +756,59 @@ function menu_saveas(name) {
 
 exports.menu_saveas = menu_saveas;
 
+function gui_canvas_print(name, initfile, initdir) {
+    // AG: This works mostly like gui_canvas_saveas above, except that we
+    // create a pdf file and use a different input element and callback.
+    var input, chooser,
+        span = patchwin[name].window.document.querySelector("#printDialogSpan");
+    if (!fs.existsSync(initdir)) {
+        initdir = pwd;
+    }
+    // If we don't have a ".pd" file extension (e.g., "Untitled-1", add one)
+    if (initfile.slice(-3) !== ".pd") {
+        initfile += ".pd";
+    }
+    // Adding an "f" now gives .pdf which is what we want.
+    initfile += "f";
+    input = build_file_dialog_string({
+        style: "display: none;",
+        type: "file",
+        id: "printDialog",
+        nwsaveas: path.join(initdir, initfile),
+        nwworkingdir: initdir,
+        accept: ".pdf"
+    });
+    span.innerHTML = input;
+    chooser = patchwin[name].window.document.querySelector("#printDialog");
+    chooser.onchange = function() {
+        print_callback(name, this.value);
+        // reset value so that we can open the same file twice
+        this.value = null;
+        console.log("tried to print something");
+    }
+    chooser.click();
+}
+
+function print_callback(cid, file) {
+    var filename = defunkify_windows_path(file);
+    // It probably isn't possible to arrive at the callback with an
+    // empty string.  But I've only tested on Debian so far...
+    if (filename === null) {
+        return;
+    }
+    // Let nw.js do the rest (requires nw.js 0.14.6+)
+    patchwin[cid].print({ pdf_path: filename, headerFooterEnabled: false });
+    post("printed to: " + filename);
+}
+
+exports.print_callback = print_callback;
+
+function menu_print(name) {
+    pdsend(name + " menuprint");
+}
+
+exports.menu_print = menu_print;
+
 function menu_new () {
     // try not to use a global here
     untitled_directory = get_pd_opendir();
diff --git a/pd/src/g_readwrite.c b/pd/src/g_readwrite.c
index 024be4c76..ca888857e 100644
--- a/pd/src/g_readwrite.c
+++ b/pd/src/g_readwrite.c
@@ -899,6 +899,12 @@ static void canvas_menusave(t_canvas *x, t_floatarg fdestroy)
     else canvas_menusaveas(x2, fdestroy);
 }
 
+static void canvas_menuprint(t_canvas *x)
+{
+    t_canvas *x2 = canvas_getrootfor(x);
+    gui_vmess("gui_canvas_print", "xss", x, x->gl_name->s_name, canvas_getdir(x2)->s_name);
+}
+
 void g_readwrite_setup(void)
 {
     class_addmethod(canvas_class, (t_method)glist_write,
@@ -916,6 +922,8 @@ void g_readwrite_setup(void)
         gensym("menusave"), A_DEFFLOAT, 0);
     class_addmethod(canvas_class, (t_method)canvas_menusaveas,
         gensym("menusaveas"), A_DEFFLOAT, 0);
+    class_addmethod(canvas_class, (t_method)canvas_menuprint,
+        gensym("menuprint"), 0);
 }
 
 void canvas_readwrite_for_class(t_class *c)
@@ -924,4 +932,6 @@ void canvas_readwrite_for_class(t_class *c)
         gensym("menusave"), 0);
     class_addmethod(c, (t_method)canvas_menusaveas,
         gensym("menusaveas"), 0);
+    class_addmethod(c, (t_method)canvas_menuprint,
+        gensym("menuprint"), 0);
 }
-- 
GitLab