diff --git a/pd/nw/index.js b/pd/nw/index.js index 95836df6384ce2ef5d301f8764a20964e39d32ef..9c84762a7c92a3f8e33ebee8f9ffcc4c26dd9e31 100644 --- a/pd/nw/index.js +++ b/pd/nw/index.js @@ -456,6 +456,7 @@ function nw_create_pd_window_menus(gui, w) { }); if (osx) { minit(m.edit.paste, { enabled: false }); + minit(m.edit.paste_clipboard, { enabled: false }); minit(m.edit.duplicate, { enabled: false }); } minit(m.edit.selectall, { diff --git a/pd/nw/locales/de/translation.json b/pd/nw/locales/de/translation.json index 6a199fbdc9a3be829f02a101dc0e0d7356032e5b..f275b2538bafc1a5086283792b40279d3c5ad527 100644 --- a/pd/nw/locales/de/translation.json +++ b/pd/nw/locales/de/translation.json @@ -122,6 +122,8 @@ "copy_tt": "Kopiere die selektierten Objekte in die Ablage", "paste": "Einfügen", "paste_tt": "Füge Objekte aus der Ablage in den Patch ein", + "paste_clipboard": "Einfügen aus Zwischenablage", + "paste_clipboard_tt": "Füge Pd code aus der Zwischenablage in den Patch ein (mit Vorsicht verwenden!)", "duplicate": "Duplizieren", "duplicate_tt": "Füge eine Kopie der aktuell selektierten Objekte in den Patch ein (verwendet nicht die Zwischenablage)", "selectall": "Alles auswählen", diff --git a/pd/nw/locales/en/translation.json b/pd/nw/locales/en/translation.json index 2b98e8d02807275d68896ffc345d57f21effe19f..e5cfb44ec8a4c4794de0fd58dacc3c5e06651ac4 100644 --- a/pd/nw/locales/en/translation.json +++ b/pd/nw/locales/en/translation.json @@ -122,6 +122,8 @@ "copy_tt": "Copy selected objects to the clipboard", "paste": "Paste", "paste_tt": "Add any objects to the canvas which were previously cut or copied", + "paste_clipboard": "Paste from Clipboard", + "paste_clipboard_tt": "Paste Pd code from the clipboard to the canvas (use with caution!)", "duplicate": "Duplicate", "duplicate_tt": "Paste a copy of the current selection on the canvas (doesn't use clipboard)", "selectall": "Select All", diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js index b600fb045db845f3adb8e9b3fdaab6ca2b22c2c2..894a094bd6da336ca8e01074bfea18a4a3621c52 100644 --- a/pd/nw/pd_canvas.js +++ b/pd/nw/pd_canvas.js @@ -363,12 +363,6 @@ var canvas_events = (function() { break; case 86: if (cmd_or_ctrl_key(evt)) { // ctrl-v - // Instead of sending the "paste" message to Pd - // here, we wait for the "paste" DOM listener to - // pick it up. That way it can check to see if - // there's anything in the paste buffer, and if so - // forward it to Pd. - // We also use "cut" and "copy" DOM event handlers // and leave this code in case we need to change // tactics for some reason. @@ -684,81 +678,14 @@ var canvas_events = (function() { } }); - // Listen to paste event using the half-baked Clipboard API from HTML5 + // Listen to paste event + // XXXTODO: Not sure whether this is even needed any more, as the + // paste-from-clipboard functionality has been moved to its own menu + // option. So this code may possibly be removed in the future. -ag document.addEventListener("paste", function(evt) { - var clipboard_data = evt.clipboardData.getData("text"), - line, - lines, - i, - pd_message; - // Precarious, overly complicated and prone to bugs... - // Basically, if a Pd user copies some Pd source file from another - // application, we give them a single paste operation to paste the - // code directly into a window (empty or otherwise). We supply a - // warning prompt to let the user know this is what's happening, so - // they could cancel if that's not what they wanted. - - // After the prompt, the user can no longer paste that particular - // string from the OS clipboard buffer. All paste actions - // will instead apply to whatever has been copied or cut from within - // a Pd patch. To paste from the OS clipboard again, the user - // must cut/copy a _different_ snippet of Pd source file than the - // one they previously tried to paste. - - // A temporary workaround to this confusing behavior would be to give - // external code-pasting its own menu button. Another possibility is - // to let copy/cut actions within the patch actually get written to - // the OS clipboard. The latter would involve a lot more work (e.g., - // sending FUDI messages from Pd to set the OS clipboard, etc.) - - // Also, we check below to make sure the OS clipboard is holding - // text that could conceivably be Pd source code. If not then the - // user won't get bothered with a prompt at all, and normal Pd - // paste behavior will follow. - - // From a usability standpoint the main drawback is that - // you can't try to paste the same Pd source code more than once. - // For users who want to pasting lots of source code this could be - // a frustration, but Pd's normal copy/paste behavior remains - // intuitive and in line with the way other apps tend to work. - - // Yet another caveat: we only want to check the external buffer - // and/or send a "paste" event to Pd if the canvas is in a "normal" - // state. if (canvas_events.get_state() !== "normal") { return; } - - if (might_be_a_pd_file(clipboard_data) && - clipboard_data !== pdgui.get_last_clipboard_data()) { - if (permission_to_paste_from_external_clipboard()) { - // clear the buffer - pdgui.pdsend(name, "copyfromexternalbuffer"); - pd_message = ""; - lines = clipboard_data.split("\n"); - for (i = 0; i < lines.length; i++) { - line = lines[i]; - // process pd_message if it ends with a semicolon that - // isn't preceded by a backslash - if (line.slice(-1) === ";" && - (line.length < 2 || line.slice(-2, -1) !== "\\")) { - if (pd_message === "") { - pd_message = line; - } else { - pd_message = pd_message + " " + line; - } - pdgui.pdsend(name, "copyfromexternalbuffer", pd_message); - pd_message = ""; - } else { - pd_message = pd_message + " " + line; - pd_message = pd_message.replace(/\n/g, ""); - } - } - // This isn't needed, but pd-l2ork did it for some reason... - pdgui.pdsend(name, "copyfromexternalbuffer"); - } - pdgui.set_last_clipboard_data(clipboard_data); - } // Send a canvas "paste" message to Pd pdgui.pdsend(name, "paste"); }); @@ -1096,6 +1023,65 @@ function instantiate_live_box() { } } +function canvas_paste_from_clipboard(name, clipboard_data) +{ + var line, lines, i, pd_message; + + // This lets the user copy some Pd source file from another application + // and paste the code directly into a canvas window (empty or otherwise). + // It does a quick check to make sure the OS clipboard is holding text + // that could conceivably be Pd source code. But that's not 100% foolproof + // and if it's not then the engine might crash and burn, so be careful! :) + + // We only want to check the external buffer and/or send a "paste" event + // to Pd if the canvas is in a "normal" state. + if (canvas_events.get_state() !== "normal") { + return; + } + + // Maybe we want a warning prompt here? Then uncomment the line below. I + // disabled this for now, as the paste-from-clipboard command now has its + // own menu option, so presumably the user knows what he's doing. -ag + if (!might_be_a_pd_file(clipboard_data) + //|| !permission_to_paste_from_external_clipboard() + ) { + return; + } + + // clear the buffer + pdgui.pdsend(name, "copyfromexternalbuffer"); + pd_message = ""; + lines = clipboard_data.split("\n"); + for (i = 0; i < lines.length; i++) { + line = lines[i]; + // process pd_message if it ends with a semicolon that + // isn't preceded by a backslash + if (line.slice(-1) === ";" && + (line.length < 2 || line.slice(-2, -1) !== "\\")) { + if (pd_message === "") { + pd_message = line; + } else { + pd_message = pd_message + " " + line; + } + pdgui.pdsend(name, "copyfromexternalbuffer", pd_message); + pd_message = ""; + } else { + pd_message = pd_message + " " + line; + pd_message = pd_message.replace(/\n/g, ""); + } + } + // This signals to the engine that we're done filling the external buffer, + // so this might conceivably call some internal cleanup code. At present + // it doesn't do anything, though. + pdgui.pdsend(name, "copyfromexternalbuffer"); + // Send a canvas "paste" message to Pd + pdgui.pdsend(name, "paste"); + // Finally, make sure to reset the buffer so that next time around we + // start from a clean slate. (Otherwise, the engine will just add stuff to + // the existing buffer contents.) + pdgui.pdsend(name, "reset_copyfromexternalbuffer"); +} + // Menus for the Patch window var canvas_menu = {}; @@ -1242,6 +1228,15 @@ function nw_create_patch_window_menus(gui, w, name) { enabled: true, click: function () { pdgui.pdsend(name, "paste"); } }); + minit(m.edit.paste_clipboard, { + enabled: true, + click: function () { + var clipboard = nw.Clipboard.get(); + var text = clipboard.get('text'); + //pdgui.post("** paste from clipboard: "+text); + canvas_paste_from_clipboard(name, text); + } + }); minit(m.edit.duplicate, { enabled: true, click: function () { pdgui.pdsend(name, "duplicate"); } diff --git a/pd/nw/pd_menus.js b/pd/nw/pd_menus.js index dead27ceb16d8e995715070fcccd341cbb0a8bef..d1fcf91188e485e951c8d035ac07999a946101c2 100644 --- a/pd/nw/pd_menus.js +++ b/pd/nw/pd_menus.js @@ -184,12 +184,6 @@ function create_menu(gui, type) { tooltip: l("menu.copy_tt") })); if (canvas_menu) { - // The nwjs menubar keybindings don't propagate down - // to the DOM. Here, we need the DOM to receive the - // "paste" event in case we want to paste a Pd file - // from an external buffer. So unfortunately we can't - // do the keybindings here. The side-effect is that - // "Ctrl-V" isn't displayed in the menu item. edit_menu.append(m.edit.paste = new gui.MenuItem({ label: l("menu.paste"), key: "v", @@ -203,6 +197,10 @@ function create_menu(gui, type) { // part of the builtin Edit menu... if (canvas_menu) { + edit_menu.append(m.edit.paste_clipboard = new gui.MenuItem({ + label: l("menu.paste_clipboard"), + tooltip: l("menu.paste_clipboard_tt") + })); edit_menu.append(m.edit.duplicate = new gui.MenuItem({ label: l("menu.duplicate"), key: "d", diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index ef3c25aa76efe3c2e4235fb1de8a116b19a05d62..09244de1fc77db09573b31da760769c28d572ce3 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -3,7 +3,6 @@ var pwd; var gui_dir; var lib_dir; -var last_clipboard_data; var pd_engine_id; exports.set_pwd = function(pwd_string) { @@ -67,14 +66,6 @@ function gui_set_gui_preset(name) { skin.set(name); } -exports.set_last_clipboard_data = function(data) { - last_clipboard_data = data; -} - -exports.get_last_clipboard_data = function() { - return last_clipboard_data; -} - // Modules var fs = require("fs"); // for fs.existsSync