"use strict"; var gui = require("nw.gui"); var pdgui = require("./pdgui.js"); // Apply gui preset to this canvas pdgui.skin.apply(this); //var name = pdgui.last_loaded(); var l = pdgui.get_local_string; console.log("my working dir is " + pdgui.get_pwd()); document.getElementById("saveDialog") .setAttribute("nwworkingdir", pdgui.get_pwd()); document.getElementById("fileDialog") .setAttribute("nwworkingdir", pdgui.get_pwd()); document.getElementById("fileDialog").setAttribute("accept", Object.keys(pdgui.pd_filetypes).toString()); var last_keydown = ""; // This could probably be in pdgui.js function add_keymods(key, evt) { var shift = evt.shiftKey ? "Shift" : ""; var ctrl = evt.ctrlKey ? "Ctrl" : ""; return shift + ctrl + key; } function text_to_fudi(text) { text = text.trim(); text = text.replace(/(\$[0-9]+)/g, "\\$1"); // escape dollar signs text = text.replace(/(?!\\)(,|;)/g, " \\$1 "); // escape "," and ";" text = text.replace(/\{|\}/g, ""); // filter "{" and "}" text = text.replace(/\s+/g, " "); // filter consecutive /s return text; } // Should probably be in pdgui.js function encode_for_dialog(s) { s = s.replace(/\s/g, "+_"); s = s.replace(/\$/g, "+d"); s = s.replace(/;/g, "+s"); s = s.replace(/,/g, "+c"); s = s.replace(/\+/g, "++"); s = "+" + s; return s; } // These three functions need to be inside canvas_events closure function canvas_find_whole_word(elem) { canvas_events.match_words(elem.checked); } function canvas_find_blur() { canvas_events.normal(); } function canvas_find_focus() { pdgui.post("flub!"); var state = canvas_events.get_state(); canvas_events.search(); } var canvas_events = (function() { var name, state, scalar_draggables = {}, // elements of a scalar which have the "drag" event enabled draggable_elem, // the current scalar element being dragged last_draggable_x, // last x coord for the element we're dragging last_draggable_y, // last y previous_state = "none", /* last state, excluding explicit 'none' */ match_words_state = false, last_search_term = "", svg_view = document.getElementById("patchsvg").viewBox.baseVal, textbox = function () { return document.getElementById("new_object_textentry"); }, events = { mousemove: function(evt) { //pdgui.post("x: " + evt.pageX + " y: " + evt.pageY + // " modifier: " + (evt.shiftKey + (evt.ctrlKey << 1))); pdgui.pdsend(name, "motion", (evt.pageX + svg_view.x), (evt.pageY + svg_view.y), (evt.shiftKey + (evt.ctrlKey << 1)) ); evt.stopPropagation(); evt.preventDefault(); return false; }, mousedown: function(evt) { // tk events (and, therefore, Pd evnets) are one greater // than html5... var b = evt.button + 1; var mod; // See if there are any draggable scalar shapes... if (Object.keys(scalar_draggables)) { // if so, see if our target is one of them... if (scalar_draggables[evt.target.id]) { // then set some state and turn on the drag events draggable_elem = evt.target; last_draggable_x = evt.pageX; last_draggable_y = evt.pageY; canvas_events.scalar_drag(); } } // For some reason right-click sends a modifier value of "8", // and canvas_doclick in g_editor.c depends on that value to // do the right thing. So let's hack... if (b === 3) { // right-click mod = 8; } else { mod = (evt.shiftKey + (evt.ctrlKey << 1)); } pdgui.pdsend(name, "mouse", (evt.pageX + svg_view.x), (evt.pageY + svg_view.y), b, mod ); //evt.stopPropagation(); //evt.preventDefault(); }, mouseup: function(evt) { //pdgui.post("mouseup: x: " + // evt.pageX + " y: " + evt.pageY + // " button: " + (evt.button + 1)); pdgui.pdsend(name, "mouseup", (evt.pageX + svg_view.x), (evt.pageY + svg_view.y), (evt.button + 1) ); evt.stopPropagation(); evt.preventDefault(); }, keydown: function(evt) { var key_code = evt.keyCode; var hack = null; // hack for unprintable ascii codes switch(key_code) { case 8: case 9: case 10: case 27: //case 32: case 127: hack = key_code; break; case 37: hack = add_keymods("Left", evt); break; case 38: hack = add_keymods("Up", evt); break; case 39: hack = add_keymods("Right", evt); break; case 40: hack = add_keymods("Down", evt); break; case 33: hack = add_keymods("Prior", evt); break; case 34: hack = add_keymods("Next", evt); break; case 35: hack = add_keymods("End", evt); break; case 36: hack = add_keymods("Home", evt); break; // These may be different on Safari... case 112: hack = add_keymods("F1", evt); break; case 113: hack = add_keymods("F2", evt); break; case 114: hack = add_keymods("F3", evt); break; case 115: hack = add_keymods("F4", evt); break; case 116: hack = add_keymods("F5", evt); break; case 117: hack = add_keymods("F6", evt); break; case 118: hack = add_keymods("F7", evt); break; case 119: hack = add_keymods("F8", evt); break; case 120: hack = add_keymods("F9", evt); break; case 121: hack = add_keymods("F10", evt); break; case 122: hack = add_keymods("F11", evt); break; case 123: hack = add_keymods("F12", evt); break; // Handle weird behavior for clipboard shortcuts // Which don't fire a keypress for some odd reason case 65: if (evt.ctrlKey === true) { pdgui.pdsend(name, "selectall"); hack = 0; // not sure what to report here... } break; case 88: if (evt.ctrlKey === true) { pdgui.pdsend(name, "cut"); hack = 0; // not sure what to report here... } break; case 67: if (evt.ctrlKey === true) { pdgui.pdsend(name, "copy"); hack = 0; // not sure what to report here... } break; case 86: if (evt.ctrlKey === true) { pdgui.pdsend(name, "paste"); hack = 0; // not sure what to report here... } break; // Need to handle Control key, Alt case 16: hack = "Shift"; break; case 17: hack = "Control"; break; case 18: hack = "Alt"; break; } if (hack !== null) { pdgui.gui_canvas_sendkey(name, 1, evt, hack); pdgui.set_keymap(key_code, hack); } //pdgui.post("keydown time: keycode is " + evt.keyCode); last_keydown = evt.keyCode; //evt.stopPropagation(); //evt.preventDefault(); }, keypress: function(evt) { // Hack to handle undo/redo shortcuts if (evt.charCode === 26) { if (evt.ctrlKey === true) { if (evt.shiftKey === true) { // ctrl-Shift-z pdgui.pdsend(name, "redo"); } else { // ctrl-z pdgui.pdsend(name, "undo"); } return; } } pdgui.gui_canvas_sendkey(name, 1, evt, evt.charCode); pdgui.set_keymap(last_keydown, evt.charCode); //pdgui.post("keypress time: charcode is " + evt.charCode); // Don't do things like scrolling on space, arrow keys, etc. //evt.stopPropagation(); evt.preventDefault(); }, keyup: function(evt) { var my_char_code = pdgui.get_char_code(evt.keyCode); pdgui.gui_canvas_sendkey(name, 0, evt, my_char_code); //pdgui.post("keyup time: charcode is: " + my_char_code); if (evt.keyCode === 13 && evt.ctrlKey) { pdgui.pdsend(name, "reselect"); } evt.stopPropagation(); evt.preventDefault(); }, text_mousemove: function(evt) { evt.stopPropagation(); //evt.preventDefault(); return false; }, text_mousedown: function(evt) { if (textbox() !== evt.target) { // Yes: I _really_ want .innerText and NOT .textContent // here. I want those newlines: although that isn't // standard in Pd-Vanilla, Pd-l2ork uses and preserves // them inside comments utils.create_obj(); //var fudi_msg = text_to_fudi(textbox().innerText); //pdgui.pdsend(name, "createobj", fudi_msg); //pdgui.post("formatted content is " + fudi_msg); events.mousedown(evt); canvas_events.normal(); } evt.stopPropagation(); //evt.preventDefault(); return false; }, text_mouseup: function(evt) { pdgui.post("mouseup target is " + evt.target + " and textbox is " + textbox()); //evt.stopPropagation(); //evt.preventDefault(); return false; }, text_keydown: function(evt) { evt.stopPropagation(); //evt.preventDefault(); return false; }, text_keyup: function(evt) { evt.stopPropagation(); //evt.preventDefault(); // ctrl-Enter to reselect if (evt.keyCode === 13 && evt.ctrlKey) { canvas_events.set_obj(); pdgui.pdsend(name, "reselect"); } return false; }, text_keypress: function(evt) { evt.stopPropagation(); //evt.preventDefault(); return false; }, floating_text_click: function(evt) { //pdgui.post("leaving floating mode"); canvas_events.text(); evt.stopPropagation(); evt.preventDefault(); return false; }, floating_text_keypress: function(evt) { //pdgui.post("leaving floating mode"); canvas_events.text(); //evt.stopPropagation(); //evt.preventDefault(); //return false; }, find_click: function(evt) { var t = document.getElementById("canvas_find_text").value; if (t !== "") { if (t === last_search_term) { pdgui.pdsend(name, "findagain"); } else { pdgui.pdsend(name, "find", encode_for_dialog(t), match_words_state ? "1" : "0"); } } last_search_term = t; }, find_keydown: function(evt) { if (evt.keyCode === 13) { events.find_click(evt); } }, scalar_draggable_mousemove: function(evt) { var new_x = evt.pageX, new_y = evt.pageY; var obj = scalar_draggables[draggable_elem.id]; pdgui.pdsend(obj.cid, "scalar_event", obj.scalar_sym, obj.drawcommand_sym, obj.event_name, new_x - last_draggable_x, new_y - last_draggable_y); last_draggable_x = new_x; last_draggable_y = new_y; }, scalar_draggable_mouseup: function(evt) { canvas_events.normal(); } }, utils = { create_obj: function() { var fudi_msg = text_to_fudi(textbox().innerText); pdgui.pdsend(name, "createobj", fudi_msg); //pdgui.post("formatted content is " + fudi_msg); }, set_obj: function() { var fudi_msg = text_to_fudi(textbox().innerText); pdgui.pdsend(name, "setobj", fudi_msg); //pdgui.post("formatted content is " + fudi_msg); } } ; // Dialog events -- these are set elsewhere now because of a bug // with nwworkingdir document.querySelector("#saveDialog").addEventListener("change", function(evt) { pdgui.saveas_callback(name, this.value); // reset value so that we can open the same file twice this.value = null; console.log("tried to open something"); }, false ); document.querySelector("#fileDialog").addEventListener("change", function(evt) { var file_array = this.value; // reset value so that we can open the same file twice this.value = null; pdgui.menu_open(file_array); console.log("tried to open something"); }, false ); document.querySelector("#openpanel_dialog").addEventListener("change", function(evt) { var file_string = this.value; // reset value so that we can open the same file twice this.value = null; pdgui.file_dialog_callback(file_string); console.log("tried to openpanel something"); }, false ); document.querySelector("#savepanel_dialog").addEventListener("change", function(evt) { var file_string = this.value; // reset value so that we can open the same file twice this.value = null; pdgui.file_dialog_callback(file_string); console.log("tried to savepanel something"); }, false ); document.querySelector("#canvas_find_text").addEventListener("focusin", canvas_find_focus, false ); document.querySelector("#canvas_find_text").addEventListener("blur", canvas_find_blur, false ); document.querySelector("#canvas_find_button").addEventListener("click", events.find_click); // closing the Window // this isn't actually closing the window yet gui.Window.get().on("close", function() { pdgui.pdsend(name, "menuclose 0"); }); // update viewport size when window size changes gui.Window.get().on("maximize", function() { pdgui.gui_canvas_getscroll(name); }); gui.Window.get().on("unmaximize", function() { pdgui.gui_canvas_getscroll(name); }); gui.Window.get().on("resize", function() { pdgui.gui_canvas_getscroll(name); }); // set minimum window size gui.Window.get().setMinimumSize(150, 100); return { none: function() { var name; if (state !== "none") { previous_state = state; } state = "none"; for (var prop in events) { if (events.hasOwnProperty(prop)) { name = prop.split("_"); name = name[name.length -1]; document.removeEventListener(name, events[prop], false); } } }, normal: function() { this.none(); document.addEventListener("mousemove", events.mousemove, false); document.addEventListener("keydown", events.keydown, false); document.addEventListener("keypress", events.keypress, false); document.addEventListener("keyup", events.keyup, false); document.addEventListener("mousedown", events.mousedown, false); document.addEventListener("mouseup", events.mouseup, false); state = "normal"; set_edit_menu_modals(true); }, scalar_drag: function() { // This scalar_drag is a prototype for moving more of the editing environment // directly to the GUI. At the moment we're leaving the other "normal" // events live, since behavior like editmode selection still happens from // the Pd engine. //this.none(); document.addEventListener("mousemove", events.scalar_draggable_mousemove, false); document.addEventListener("mouseup", events.scalar_draggable_mouseup, false); }, text: function() { this.none(); document.addEventListener("mousemove", events.text_mousemove, false); document.addEventListener("keydown", events.text_keydown, false); document.addEventListener("keypress", events.text_keypress, false); document.addEventListener("keyup", events.text_keyup, false); document.addEventListener("mousedown", events.text_mousedown, false); document.addEventListener("mouseup", events.text_mouseup, false); state = "text"; set_edit_menu_modals(false); }, floating_text: function() { this.none(); this.text(); document.removeEventListener("mousedown", events.text_mousedown, false); document.removeEventListener("mouseup", events.text_mouseup, false); document.removeEventListener("keypress", events.text_keypress, false); document.removeEventListener("mousemove", events.text_mousemove, false); document.addEventListener("click", events.floating_text_click, false); document.addEventListener("keypress", events.floating_text_keypress, false); document.addEventListener("mousemove", events.mousemove, false); state = "floating_text"; set_edit_menu_modals(false); }, search: function() { this.none(); document.addEventListener("keydown", events.find_keydown, false); state = "search"; }, register: function(n) { name = n; }, get_state: function() { return state; }, get_previous_state: function() { return previous_state; }, set_obj: function() { utils.set_obj(); }, create_obj: function() { utils.create_obj(); }, match_words: function(state) { match_words_state = state; }, add_scalar_draggable: function(cid, tag, scalar_sym, drawcommand_sym, event_name) { scalar_draggables[tag] = { cid: cid, scalar_sym: scalar_sym, drawcommand_sym, drawcommand_sym, event_name: event_name }; }, remove_scalar_draggable: function(id) { if (scalar_draggables[id]) { scalar_draggables[id] = null; } } } }()); // This gets called from the nw_create_window function in index.html // It provides us with our canvas id from the C side. Once we have it // we can create the menu and register event callbacks function register_canvas_id(cid) { name = cid; // hack // We create the window menus and popup menu before doing anything else // to ensure that we don't try to set the svg size before these are done. // Otherwise we might set the svg size to the window viewport, only to have // the menu push down the svg viewport and create scrollbars. Those same // scrollbars will get erased once canvas_map triggers, causing a quick // (and annoying) scrollbar flash nw_create_patch_window_menus(cid); create_popup_menu(cid); canvas_events.register(cid); canvas_events.normal(); pdgui.canvas_map(cid); // side-effect: triggers gui_canvas_getscroll from Pd } function create_popup_menu(name) { // The right-click popup menu var popup_menu = new gui.Menu(); pdgui.add_popup(name, popup_menu); popup_menu.append(new gui.MenuItem({ label: "Properties", click: function() { pdgui.popup_action(name, 0); } })); popup_menu.append(new gui.MenuItem({ label: "Open", click: function() { pdgui.popup_action(name, 1); } })); popup_menu.append(new gui.MenuItem({ label: "Help", click: function() { pdgui.popup_action(name, 2); } })); } // stop-gap function menu_generic () { alert("Please implement this"); } var modals = {}; // Edit menu items that should be disabled when editing // an object box function set_edit_menu_modals(state) { var item; for (item in modals) { if (modals.hasOwnProperty(item)) { modals[item].enabled = state; } } } function nw_undo_menu(undo_text, redo_text) { if (undo_text === "no") { modals.undo.enabled = false; } else { modals.undo.enabled = true; modals.undo.label = l("menu.undo") + " " + undo_text; } if (redo_text === "no") { modals.redo.enabled = false; } else { modals.redo.enabled = true; modals.redo.label = l("menu.redo") + " " + redo_text; } } function have_live_box() { var state = canvas_events.get_state(); if (state === "text" || state === "floating_text") { return true; } else { return false; } } // If there's a box being edited, send the box's text to Pd function update_live_box() { if (have_live_box()) { canvas_events.set_obj(); } } // If there's a box being edited, try to instantiate it in Pd function instantiate_live_box() { if (have_live_box()) { canvas_events.create_obj(); } } // Menus for the Patch window function nw_create_patch_window_menus(name) { // Window menu var windowMenu = new gui.Menu({ type: "menubar" }); // File menu var fileMenu = new gui.Menu(); // Add to window menu windowMenu.append(new gui.MenuItem({ label: l("menu.file"), submenu: fileMenu })); // File sub-entries fileMenu.append(new gui.MenuItem({ label: l("menu.new"), click: pdgui.menu_new, key: "n", modifiers: "ctrl", tooltip: l("menu.new_tt") })); fileMenu.append(new gui.MenuItem({ label: l("menu.open"), key: "o", modifiers: "ctrl", tooltip: l("menu.open_tt"), click: function() { var input, chooser, span = document.querySelector("#fileDialogSpan"); input = pdgui.build_file_dialog_string({ id: "fileDialog", nwworkingdir: "/user/home", style: "display: none;", type: "file", }); span.innerHTML = input; chooser = document.querySelector("#fileDialog"); chooser.click(); } })); if (pdgui.k12_mode == 1) { fileMenu.append(new gui.MenuItem({ label: l("menu.k12_demos"), tooltip: l("menu.k12_demos_tt"), click: pdgui.menu_k12_open_demos })); } fileMenu.append(new gui.MenuItem({ type: "separator" })); // Note: this must be different for the main Pd window fileMenu.append(new gui.MenuItem({ label: l("menu.save"), click: function () { pdgui.canvas_check_geometry(name); // should this go in menu_save? pdgui.menu_save(name); }, key: "s", modifiers: "ctrl", tooltip: l("menu.save_tt") })); fileMenu.append(new gui.MenuItem({ label: l("menu.saveas"), click: function (){ pdgui.canvas_check_geometry(name); pdgui.menu_saveas(name); }, key: "s", modifiers: "ctrl+shift", tooltip: l("menu.saveas_tt") })); if (pdgui.k12_mode == 0) { fileMenu.append(new gui.MenuItem({ type: "separator" })); } fileMenu.append(new gui.MenuItem({ label: l("menu.message"), click: function() { pdgui.menu_send(name); }, key: "m", modifiers: "ctrl", tooltip: l("menu.message_tt") })); if (pdgui.k12_mode == 0) { fileMenu.append(new gui.MenuItem({ type: "separator" })); } // recent files go here // anther separator goes here if there are any recent files fileMenu.append(new gui.MenuItem({ label: l("menu.close"), tooltip: l("menu.close_tt"), click: function() { pdgui.menu_close(name); }, key: "w", modifiers: "ctrl" })); // Quit Pd fileMenu.append(new gui.MenuItem({ label: l("menu.quit"), click: pdgui.menu_quit, key: "q", modifiers: "ctrl", tooltip: l("menu.quit_tt") })); // Edit menu var editMenu = new gui.Menu(); // Add to window menu windowMenu.append(new gui.MenuItem({ label: l("menu.edit"), submenu: editMenu })); // Edit sub-entries editMenu.append(modals.undo = new gui.MenuItem({ label: l("menu.undo"), click: function () { pdgui.pdsend(name, "undo"); }, tooltip: l("menu.undo_tt"), })); editMenu.append(modals.redo = new gui.MenuItem({ label: l("menu.redo"), click: function () { pdgui.pdsend(name, "redo"); }, tooltip: l("menu.redo_tt"), })); editMenu.append(new gui.MenuItem({ type: "separator" })); editMenu.append(modals.cut = new gui.MenuItem({ label: l("menu.cut"), click: function () { pdgui.pdsend(name, "cut"); }, tooltip: l("menu.cut_tt"), })); editMenu.append(modals.copy = new gui.MenuItem({ label: l("menu.copy"), click: function () { pdgui.pdsend(name, "copy"); }, tooltip: l("menu.copy_tt"), })); editMenu.append(modals.paste = new gui.MenuItem({ label: l("menu.paste"), click: function () { pdgui.pdsend(name, "paste"); }, tooltip: l("menu.paste_tt"), })); editMenu.append(new gui.MenuItem({ label: l("menu.duplicate"), click: function () { pdgui.pdsend(name, "duplicate"); }, key: "d", modifiers: "ctrl", tooltip: l("menu.duplicate_tt") })); editMenu.append(modals.selectall = new gui.MenuItem({ label: l("menu.selectall"), click: function (evt) { if (canvas_events.get_state() === "normal") { pdgui.pdsend(name, "selectall"); } }, tooltip: l("menu.selectall_tt"), })); editMenu.append(new gui.MenuItem({ label: l("menu.reselect"), // Unfortunately nw.js doesn't allow // key: "Return" or key: "Enter", so we // can't bind to ctrl-Enter here. (Even // tried fromCharCode...) click: function () { pdgui.pdsend(name, "reselect"); }, key: String.fromCharCode(10), modifiers: "ctrl", tooltip: l("menu.reselect_tt") })); editMenu.append(new gui.MenuItem({ type: "separator" })); editMenu.append(new gui.MenuItem({ label: l("menu.zoomin"), click: function () { var z = gui.Window.get().zoomLevel; if (z < 8) { z++; } gui.Window.get().zoomLevel = z; }, key: "=", modifiers: "ctrl", tooltip: l("menu.zoomin") })); editMenu.append(new gui.MenuItem({ label: l("menu.zoomout"), click: function () { var z = gui.Window.get().zoomLevel; if (z > -7) { z--; } gui.Window.get().zoomLevel = z; }, key: "-", modifiers: "ctrl", tooltip: l("menu.zoomout_tt"), })); editMenu.append(new gui.MenuItem({ type: "separator" })); editMenu.append(new gui.MenuItem({ label: l("menu.tidyup"), click: function() { pdgui.pdsend(name, "tidy"); }, key: "y", modifiers: "ctrl", tooltip: l("menu.tidyup_tt") })); editMenu.append(new gui.MenuItem({ label: l("menu.tofront"), click: function() { pdgui.popup_action(name, 3); }, tooltip: l("menu.tofront_tt"), })); editMenu.append(new gui.MenuItem({ label: l("menu.toback"), click: function() { pdgui.popup_action(name, 4); }, tooltip: l("menu.toback_tt"), })); editMenu.append(new gui.MenuItem({ type: "separator" })); editMenu.append(new gui.MenuItem({ label: l("menu.font"), click: function () { pdgui.pdsend(name, "menufont"); }, tooltip: l("menu.font_tt"), })); editMenu.append(new gui.MenuItem({ label: l("menu.cordinspector"), click: function() { pdgui.pdsend(name, "magicglass 0"); }, key: "r", modifiers: "ctrl", tooltip: l("menu.cordinspector_tt"), })); editMenu.append(new gui.MenuItem({ type: "separator" })); editMenu.append(new gui.MenuItem({ label: l("menu.find"), click: function () { var find_bar = document.getElementById("canvas_find"), find_bar_text = document.getElementById("canvas_find_text"), state = find_bar.style.getPropertyValue("display"); // if there's a box being edited, try to instantiate it in Pd instantiate_live_box(); if (state === "none") { find_bar.style.setProperty("display", "inline"); find_bar_text.focus(); find_bar_text.select(); canvas_events.search(); } else { find_bar.style.setProperty("display", "none"); // "normal" seems to be the only viable state for the // canvas atm. But if there are other states added later, // we might need to fetch the previous state here. canvas_events.normal(); } }, key: "f", modifiers: "ctrl", tooltip: l("menu.find_tt"), })); editMenu.append(new gui.MenuItem({ label: l("menu.findagain"), click: menu_generic, key: "g", modifiers: "ctrl", tooltip: l("menu.findagain") })); editMenu.append(new gui.MenuItem({ label: l("menu.finderror"), click: function() { pdgui.pdsend("pd finderror"); }, tooltip: l("menu.finderror_tt"), })); editMenu.append(new gui.MenuItem({ type: "separator" })); editMenu.append(new gui.MenuItem({ label: l("menu.autotips"), click: menu_generic, tooltip: l("menu.autotips_tt"), })); editMenu.append(new gui.MenuItem({ label: l("menu.editmode"), click: function() { update_live_box(); pdgui.pdsend(name, "editmode 0"); }, key: "e", modifiers: "ctrl", tooltip: l("menu.editmode_tt") })); editMenu.append(new gui.MenuItem({ type: "separator" })); editMenu.append(new gui.MenuItem({ label: l("menu.preferences"), click: pdgui.open_prefs, key: "p", modifiers: "ctrl", tooltip: l("menu.preferences_tt") })); // Put menu var putMenu = new gui.Menu(); // Add to window menu windowMenu.append(new gui.MenuItem({ label: l("menu.put"), submenu: putMenu })); // Put menu sub-entries putMenu.append(new gui.MenuItem({ label: l("menu.object"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "obj 0"); }, key: "1", modifiers: "ctrl", tooltip: l("menu.object_tt"), })); putMenu.append(new gui.MenuItem({ label: l("menu.msgbox"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "msg 0"); }, key: "2", modifiers: "ctrl", tooltip: l("menu.msgbox_tt"), })); putMenu.append(new gui.MenuItem({ label: l("menu.number"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "floatatom 0"); }, key: "3", modifiers: "ctrl", tooltip: l("menu.number_tt") })); putMenu.append(new gui.MenuItem({ label: l("menu.symbol"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "symbolatom 0"); }, key: "4", modifiers: "ctrl", tooltip: l("menu.symbol_tt") })); putMenu.append(new gui.MenuItem({ label: l("menu.comment"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "text 0"); }, key: "5", modifiers: "ctrl", tooltip: l("menu.comment_tt") })); putMenu.append(new gui.MenuItem({ type: "separator" })); putMenu.append(new gui.MenuItem({ label: l("menu.bang"), click: function(e) { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "bng 0"); }, key: "b", modifiers: "ctrl-shift", tooltip: l("menu.bang_tt") })); putMenu.append(new gui.MenuItem({ label: l("menu.toggle"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "toggle 0"); }, key: "t", modifiers: "ctrl-shift", tooltip: l("menu.toggle_tt") })); putMenu.append(new gui.MenuItem({ label: l("menu.number2"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "numbox 0"); }, key: "n", modifiers: "ctrl-shift", tooltip: l("menu.number2") })); putMenu.append(new gui.MenuItem({ label: l("menu.vslider"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "vslider 0"); }, key: "v", modifiers: "ctrl-shift", tooltip: l("menu.vslider_tt"), })); putMenu.append(new gui.MenuItem({ label: l("menu.hslider"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "hslider 0"); }, key: "h", modifiers: "ctrl-shift", tooltip: l("menu.hslider_tt"), })); putMenu.append(new gui.MenuItem({ label: l("menu.vradio"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "vradio 0"); }, key: "d", modifiers: "ctrl-shift", tooltip: l("menu.vradio_tt"), })); putMenu.append(new gui.MenuItem({ label: l("menu.hradio"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "hradio 0"); }, key: "i", modifiers: "ctrl", tooltip: l("menu.hradio_tt"), })); putMenu.append(new gui.MenuItem({ label: l("menu.vu"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "vumeter 0"); }, key: "u", modifiers: "ctrl", tooltip: l("menu.vu_tt"), })); putMenu.append(new gui.MenuItem({ label: l("menu.cnv"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "mycnv 0"); }, key: "c", modifiers: "ctrl-shift", tooltip: l("menu.cnv_tt") })); putMenu.append(new gui.MenuItem({ type: "separator" })); //putMenu.append(new gui.MenuItem({ // label: l("menu.graph"), // click: function() { // update_live_box(); // pdgui.pdsend(name, "dirty 1"); // // leaving out some placement logic... see pd.tk menu_graph // pdgui.pdsend(name, "graph NULL 0 0 0 0 30 30 0 30"); // }, // tooltip: l("menu.graph_tt"), //})); putMenu.append(new gui.MenuItem({ label: l("menu.array"), click: function() { update_live_box(); pdgui.pdsend(name, "dirty 1"); pdgui.pdsend(name, "menuarray"); }, tooltip: l("menu.array_tt"), })); // Windows menu... call it "winman" (i.e., window management) // to avoid confusion var winmanMenu = new gui.Menu(); // Add to windows menu windowMenu.append(new gui.MenuItem({ label: l("menu.windows"), submenu: winmanMenu })); // Winman sub-entries winmanMenu.append(new gui.MenuItem({ label: l("menu.fullscreen"), click: function() { var win = gui.Window.get(); var fullscreen = win.isFullscreen; win.isFullscreen = !fullscreen; pdgui.post("fullscreen is " + fullscreen); }, key: "f11", //modifiers: "ctrl", tooltip: l("menu.nextwin_tt"), })); winmanMenu.append(new gui.MenuItem({ label: l("menu.nextwin"), click: function() { pdgui.raise_next(name); }, key: String.fromCharCode(12), // Page down modifiers: "ctrl", tooltip: l("menu.nextwin_tt"), })); winmanMenu.append(new gui.MenuItem({ label: l("menu.prevwin"), click: function() { pdgui.raise_prev(name); }, key: String.fromCharCode(11), // Page up modifiers: "ctrl", tooltip: l("menu.prevwin_tt"), })); winmanMenu.append(new gui.MenuItem({ type: "separator" })); winmanMenu.append(new gui.MenuItem({ label: l("menu.parentwin"), click: function() { pdgui.pdsend(name, "findparent", 0); }, tooltip: l("menu.parentwin_tt"), })); winmanMenu.append(new gui.MenuItem({ label: l("menu.visible_ancestor"), click: function() { pdgui.pdsend(name, "findparent", 1); }, tooltip: l("menu.visible_ancestor_tt"), })); winmanMenu.append(new gui.MenuItem({ label: l("menu.pdwin"), click: function() { pdgui.raise_pd_window(); }, tooltip: l("menu.pdwin_tt"), key: "r", modifiers: "ctrl" })); // Media menu var mediaMenu = new gui.Menu(); // Add to window menu windowMenu.append(new gui.MenuItem({ label: l("menu.media"), submenu: mediaMenu })); // Media sub-entries mediaMenu.append(new gui.MenuItem({ label: l("menu.audio_on"), click: function() { pdgui.pdsend("pd dsp 1"); }, key: "/", modifiers: "ctrl", tooltip: l("menu.audio_on_tt"), })); mediaMenu.append(new gui.MenuItem({ label: l("menu.audio_off"), click: function() { pdgui.pdsend("pd dsp 0"); }, key: ".", modifiers: "ctrl", tooltip: l("menu.audio_off_tt"), })); mediaMenu.append(new gui.MenuItem({ type: "separator" })); mediaMenu.append(new gui.MenuItem({ label: l("menu.test"), click: function() { pdgui.pd_doc_open("doc/7.stuff/tools", "testtone.pd"); }, tooltip: l("menu.test_tt"), })); mediaMenu.append(new gui.MenuItem({ label: l("menu.loadmeter"), click: function() { pdgui.pd_doc_open("doc/7.stuff/tools", "load-meter.pd"); }, tooltip: l("menu.loadmeter_tt"), })); // Help menu var helpMenu = new gui.Menu(); // Add to window menu windowMenu.append(new gui.MenuItem({ label: l("menu.help"), submenu: helpMenu })); // Help sub-entries helpMenu.append(new gui.MenuItem({ label: l("menu.about"), click: menu_generic, //key: "c", //modifiers: "ctrl", tooltip: l("menu.about_tt"), })); helpMenu.append(new gui.MenuItem({ label: l("menu.manual"), click: menu_generic, tooltip: l("menu.manual"), })); helpMenu.append(new gui.MenuItem({ label: l("menu.browser"), click: menu_generic, tooltip: l("menu.browser_tt"), })); helpMenu.append(new gui.MenuItem({ type: "separator" })); helpMenu.append(new gui.MenuItem({ label: l("menu.l2ork_list"), click: menu_generic, tooltip: l("menu.l2ork_list_tt"), })); helpMenu.append(new gui.MenuItem({ label: l("menu.pd_list"), click: menu_generic, tooltip: l("menu.pd_list_tt"), })); helpMenu.append(new gui.MenuItem({ label: l("menu.forums"), click: menu_generic, tooltip: l("menu.forums_tt"), })); helpMenu.append(new gui.MenuItem({ label: l("menu.irc"), click: menu_generic, tooltip: l("menu.irc_tt"), })); helpMenu.append(new gui.MenuItem({ label: l("menu.devtools"), key: "b", // temporary convenience shortcut-- can change if needed modifiers: "ctrl", click: function () { gui.Window.get().showDevTools(); }, tooltip: l("menu.devtools_tt"), })); // Assign to window gui.Window.get().menu = windowMenu; }