diff --git a/editor/editor_mobile.html b/editor/editor_mobile.html new file mode 100644 index 000000000..da5b1e104 --- /dev/null +++ b/editor/editor_mobile.html @@ -0,0 +1,144 @@ + + + + + LiteGraph + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/editor/index.html b/editor/index.html index 01dce5054..c43922b45 100755 --- a/editor/index.html +++ b/editor/index.html @@ -1,44 +1,47 @@ - - - - LiteGraph - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + LiteGraph + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/editor/js/code.js b/editor/js/code.js index 28c8dc442..fe9e89076 100644 --- a/editor/js/code.js +++ b/editor/js/code.js @@ -1,6 +1,7 @@ var webgl_canvas = null; LiteGraph.node_images_path = "../nodes_data/"; + var editor = new LiteGraph.Editor("main",{miniwindow:false}); window.graphcanvas = editor.graphcanvas; window.graph = editor.graph; @@ -19,8 +20,10 @@ LiteGraph.allow_scripts = true; //create scene selector var elem = document.createElement("span"); +elem.id = "LGEditorTopBarSelector"; elem.className = "selector"; -elem.innerHTML = "Demo | "; +elem.innerHTML = ""; +elem.innerHTML += "Demo | "; editor.tools.appendChild(elem); var select = elem.querySelector("select"); select.addEventListener("change", function(e){ @@ -167,4 +170,4 @@ function enableWebGL() gl.viewport(0,0,gl.canvas.width, gl.canvas.height ); } } -} +} \ No newline at end of file diff --git a/editor/js/defaults.js b/editor/js/defaults.js new file mode 100644 index 000000000..3709e645a --- /dev/null +++ b/editor/js/defaults.js @@ -0,0 +1,31 @@ + +LiteGraph.debug = false; +LiteGraph.catch_exceptions = true; +LiteGraph.throw_errors = true; +LiteGraph.allow_scripts = false; //if set to true some nodes like Formula would be allowed to evaluate code that comes from unsafe sources (like node configuration); which could lead to exploits + +LiteGraph.searchbox_extras = {}; //used to add extra features to the search box +LiteGraph.auto_sort_node_types = true; // [true!] If set to true; will automatically sort node types / categories in the context menus +LiteGraph.node_box_coloured_when_on = true; // [true!] this make the nodes box (top left circle) coloured when triggered (execute/action); visual feedback +LiteGraph.node_box_coloured_by_mode = true; // [true!] nodebox based on node mode; visual feedback +LiteGraph.dialog_close_on_mouse_leave = true; // [false on mobile] better true if not touch device; +LiteGraph.dialog_close_on_mouse_leave_delay = 500; +LiteGraph.shift_click_do_break_link_from = false; // [false!] prefer false if results too easy to break links +LiteGraph.click_do_break_link_to = false; // [false!]prefer false; way too easy to break links +LiteGraph.search_hide_on_mouse_leave = true; // [false on mobile] better true if not touch device; +LiteGraph.search_filter_enabled = true; // [true!] enable filtering slots type in the search widget; !requires auto_load_slot_types or manual set registered_slot_[in/out]_types and slot_types_[in/out] +LiteGraph.search_show_all_on_open = true; // [true!] opens the results list when opening the search widget + +LiteGraph.auto_load_slot_types = true; // [if want false; use true; run; get vars values to be statically set; than disable] nodes types and nodeclass association with node types need to be calculated; if dont want this; calculate once and set registered_slot_[in/out]_types and slot_types_[in/out] +/*// set these values if not using auto_load_slot_types +LiteGraph.registered_slot_in_types = {}; // slot types for nodeclass +LiteGraph.registered_slot_out_types = {}; // slot types for nodeclass +LiteGraph.slot_types_in = []; // slot types IN +LiteGraph.slot_types_out = []; // slot types OUT*/ + +LiteGraph.alt_drag_do_clone_nodes = true; // [true!] very handy; ALT click to clone and drag the new node +LiteGraph.do_add_triggers_slots = true; // [true!] will create and connect event slots when using action/events connections; !WILL CHANGE node mode when using onTrigger (enable mode colors); onExecuted does not need this +LiteGraph.allow_multi_output_for_events = false; // [false!] being events; it is strongly reccomended to use them sequentually; one by one +LiteGraph.middle_click_slot_add_default_node = true; //[true!] allows to create and connect a ndoe clicking with the third button (wheel) +LiteGraph.release_link_on_empty_shows_menu = true; //[true!] dragging a link to empty space will open a menu, add from list, search or defaults +LiteGraph.pointerevents_method = "pointer"; // "mouse"|"pointer" use mouse for retrocompatibility issues? (none found @ now) \ No newline at end of file diff --git a/editor/js/defaults_mobile.js b/editor/js/defaults_mobile.js new file mode 100644 index 000000000..d4ef831c7 --- /dev/null +++ b/editor/js/defaults_mobile.js @@ -0,0 +1,31 @@ + +LiteGraph.debug = false; +LiteGraph.catch_exceptions = true; +LiteGraph.throw_errors = true; +LiteGraph.allow_scripts = false; //if set to true some nodes like Formula would be allowed to evaluate code that comes from unsafe sources (like node configuration); which could lead to exploits + +LiteGraph.searchbox_extras = {}; //used to add extra features to the search box +LiteGraph.auto_sort_node_types = true; // [true!] If set to true; will automatically sort node types / categories in the context menus +LiteGraph.node_box_coloured_when_on = true; // [true!] this make the nodes box (top left circle) coloured when triggered (execute/action); visual feedback +LiteGraph.node_box_coloured_by_mode = true; // [true!] nodebox based on node mode; visual feedback +LiteGraph.dialog_close_on_mouse_leave = false; // [false on mobile] better true if not touch device; +LiteGraph.dialog_close_on_mouse_leave_delay = 500; +LiteGraph.shift_click_do_break_link_from = false; // [false!] prefer false if results too easy to break links +LiteGraph.click_do_break_link_to = false; // [false!]prefer false; way too easy to break links +LiteGraph.search_hide_on_mouse_leave = false; // [false on mobile] better true if not touch device; +LiteGraph.search_filter_enabled = true; // [true!] enable filtering slots type in the search widget; !requires auto_load_slot_types or manual set registered_slot_[in/out]_types and slot_types_[in/out] +LiteGraph.search_show_all_on_open = true; // [true!] opens the results list when opening the search widget + +LiteGraph.auto_load_slot_types = true; // [if want false; use true; run; get vars values to be statically set; than disable] nodes types and nodeclass association with node types need to be calculated; if dont want this; calculate once and set registered_slot_[in/out]_types and slot_types_[in/out] +/*// set these values if not using auto_load_slot_types +LiteGraph.registered_slot_in_types = {}; // slot types for nodeclass +LiteGraph.registered_slot_out_types = {}; // slot types for nodeclass +LiteGraph.slot_types_in = []; // slot types IN +LiteGraph.slot_types_out = []; // slot types OUT*/ + +LiteGraph.alt_drag_do_clone_nodes = true; // [true!] very handy; ALT click to clone and drag the new node +LiteGraph.do_add_triggers_slots = true; // [true!] will create and connect event slots when using action/events connections; !WILL CHANGE node mode when using onTrigger (enable mode colors); onExecuted does not need this +LiteGraph.allow_multi_output_for_events = false; // [false!] being events; it is strongly reccomended to use them sequentually; one by one +LiteGraph.middle_click_slot_add_default_node = true; //[true!] allows to create and connect a ndoe clicking with the third button (wheel) +LiteGraph.release_link_on_empty_shows_menu = true; //[true!] dragging a link to empty space will open a menu, add from list, search or defaults +LiteGraph.pointerevents_method = "pointer"; // "mouse"|"pointer" use mouse for retrocompatibility issues? (none found @ now) \ No newline at end of file diff --git a/src/litegraph.js b/src/litegraph.js index 9f3b1428e..b5d30a68b 100644 --- a/src/litegraph.js +++ b/src/litegraph.js @@ -123,13 +123,19 @@ registered_slot_out_types: {}, // slot types for nodeclass slot_types_in: [], // slot types IN slot_types_out: [], // slot types OUT - + slot_types_default_in: [], // specify for each IN slot type a(/many) deafult node(s), use single string, array, or object (with node, title, parameters, ..) like for search + slot_types_default_out: [], // specify for each OUT slot type a(/many) deafult node(s), use single string, array, or object (with node, title, parameters, ..) like for search + alt_drag_do_clone_nodes: false, // [true!] very handy, ALT click to clone and drag the new node do_add_triggers_slots: false, // [true!] will create and connect event slots when using action/events connections, !WILL CHANGE node mode when using onTrigger (enable mode colors), onExecuted does not need this - allowMultiOutputForEvents: true, // [false!] being events, it is strongly reccomended to use them sequentually, one by one + allow_multi_output_for_events: true, // [false!] being events, it is strongly reccomended to use them sequentually, one by one + middle_click_slot_add_default_node: false, //[true!] allows to create and connect a ndoe clicking with the third button (wheel) + + release_link_on_empty_shows_menu: false, //[true!] dragging a link to empty space will open a menu, add from list, search or defaults + pointerevents_method: "pointer", // "mouse"|"pointer" use mouse for retrocompatibility issues? (none found @ now) // TODO implement pointercancel, gotpointercapture, lostpointercapture, (pointerover, pointerout if necessary) @@ -288,7 +294,7 @@ if (typeof slot_type == "string"){ var aTypes = slot_type.split(","); }else if (slot_type == this.EVENT || slot_type == this.ACTION){ - var aTypes = ["EVENT/ACTION"]; + var aTypes = ["_event_"]; }else{ var aTypes = ["*"]; } @@ -304,13 +310,13 @@ // check if is a new type if (!out){ - if (!this.slot_types_in.includes(sT)){ - this.slot_types_in.push(sT); + if (!this.slot_types_in.includes(sT.toLowerCase())){ + this.slot_types_in.push(sT.toLowerCase()); this.slot_types_in.sort(); } }else{ - if (!this.slot_types_out.includes(sT)){ - this.slot_types_out.push(sT); + if (!this.slot_types_out.includes(sT.toLowerCase())){ + this.slot_types_out.push(sT.toLowerCase()); this.slot_types_out.sort(); } } @@ -832,6 +838,10 @@ this.catch_errors = true; + this.nodes_executing = []; + this.nodes_actioning = []; + this.nodes_executedAction = []; + //subgraph_data this.inputs = {}; this.outputs = {}; @@ -3098,12 +3108,8 @@ // enable this to give the event an ID if (!options.action_call) options.action_call = this.id+"_exec_"+Math.floor(Math.random()*9999); - if (this.graph.nodes_executing) this.graph.nodes_executing[this.id] = true; //.push(this.id); - else{ - this.graph.nodes_executing = {}; - this.graph.nodes_executing[this.id] = true; - } - + this.graph.nodes_executing[this.id] = true; //.push(this.id); + this.onExecute(param, options); this.graph.nodes_executing[this.id] = false; //.pop(); @@ -4213,7 +4219,7 @@ if (output.links !== null && output.links.length){ switch(output.type){ case LiteGraph.EVENT: - if (!LiteGraph.allowMultiOutputForEvents){ + if (!LiteGraph.allow_multi_output_for_events){ this.graph.beforeChange(); this.disconnectOutput(slot, false, {doProcessChange: false}); // Input(target_slot, {doProcessChange: false}); changed = true; @@ -6083,6 +6089,148 @@ LGraphNode.prototype.executeAction = function(action) } else if (e.which == 2) { //middle button + + if (LiteGraph.middle_click_slot_add_default_node){ + if (node && this.allow_interaction && !skip_action && !this.read_only){ + //not dragging mouse to connect two slots + if ( + !this.connecting_node && + !node.flags.collapsed && + !this.live_mode + ) { + var middleClickedSlot = false; + var middleClickedSlot_index = false; + var middleClickedSlot_isOut = false; + //search for outputs + if (node.outputs) { + for ( var i = 0, l = node.outputs.length; i < l; ++i ) { + var output = node.outputs[i]; + var link_pos = node.getConnectionPos(false, i); + if ( + isInsideRectangle( + e.canvasX, + e.canvasY, + link_pos[0] - 15, + link_pos[1] - 10, + 30, + 20 + ) + ) { + middleClickedSlot = output; + middleClickedSlot_index = i; + middleClickedSlot_isOut = true; + break; + } + } + } + + //search for inputs + if (node.inputs) { + for ( var i = 0, l = node.inputs.length; i < l; ++i ) { + var input = node.inputs[i]; + var link_pos = node.getConnectionPos(true, i); + if ( + isInsideRectangle( + e.canvasX, + e.canvasY, + link_pos[0] - 15, + link_pos[1] - 10, + 30, + 20 + ) + ) { + middleClickedSlot = input; + middleClickedSlot_index = i; + middleClickedSlot_isOut = false; + break; + } + } + } + //console.log("middleClickSlots? "+middleClickedSlot+" & "+(middleClickedSlot_index!==false)); + if (middleClickedSlot && middleClickedSlot_index!==false){ + // check for defaults nodes for this slottype + var slotTypesDefault = middleClickedSlot_isOut ? LiteGraph.slot_types_default_out : LiteGraph.slot_types_default_in; + //console.log("middleClickSlots "+middleClickedSlot.type+" in "+slotTypesDefault[middleClickedSlot.type]); + if(slotTypesDefault && slotTypesDefault[middleClickedSlot.type]){ + if (middleClickedSlot.link !== null) { + // is connected + }else{ + // is not not connected + } + nodeNewType = false; + if(typeof slotTypesDefault[middleClickedSlot.type] == "object" || typeof slotTypesDefault[middleClickedSlot.type] == "array"){ + for (typeX in slotTypesDefault[middleClickedSlot.type]){ + nodeNewType = slotTypesDefault[middleClickedSlot.type][typeX]; + break; // -------- + } + }else{ + nodeNewType = slotTypesDefault[middleClickedSlot.type]; + } + if (nodeNewType) { + var nodeNewOpts = false; + if (typeof nodeNewType == "object" && nodeNewType.node){ + nodeNewOpts = nodeNewType; + nodeNewType = nodeNewType.node; + } + //that.graph.beforeChange(); + var newNode = LiteGraph.createNode(nodeNewType); + if(newNode){ + // if is object pass options + if (nodeNewOpts){ + if (nodeNewOpts.properties) { + for (var i in nodeNewOpts.properties) { + newNode.addProperty( i, nodeNewOpts.properties[i] ); + } + } + if (nodeNewOpts.inputs) { + newNode.inputs = []; + for (var i in nodeNewOpts.inputs) { + newNode.addOutput( + nodeNewOpts.inputs[i][0], + nodeNewOpts.inputs[i][1] + ); + } + } + if (nodeNewOpts.outputs) { + newNode.outputs = []; + for (var i in nodeNewOpts.outputs) { + newNode.addOutput( + nodeNewOpts.outputs[i][0], + nodeNewOpts.outputs[i][1] + ); + } + } + if (nodeNewOpts.title) { + newNode.title = nodeNewOpts.title; + } + if (nodeNewOpts.json) { + newNode.configure(nodeNewOpts.json); + } + + } + // add the node + that.graph.add(newNode); + // connect the two! + if (middleClickedSlot_isOut){ + newNode.pos = [e.canvasX+30,e.canvasY]; //that.last_click_position; //[e.canvasX+30, e.canvasX+5]; + node.connectByType( middleClickedSlot_index, newNode, middleClickedSlot.type ); + }else{ + newNode.pos = [e.canvasX-30-(newNode.size?newNode.size[0]:0),e.canvasY]; //that.last_click_position; //[e.canvasX+30, e.canvasX+5]; + node.connectByTypeOutput( middleClickedSlot_index, newNode, middleClickedSlot.type ); + } + //that.graph.afterChange(); + }else{ + console.log("failed creating "+nodeNewType); + } + } + }else{ + //console.log("no slotTypesDefault for MIDDLECLICK "+middleClickedSlot.type); + } + } + } + } + } + } else if (e.which == 3 || this.pointer_is_double) { //right button if(!this.read_only) @@ -6570,20 +6718,21 @@ LGraphNode.prototype.executeAction = function(action) }else{ // add menu when releasing link in empty space - - if (e.shiftKey && this.allow_searchbox){ - if(this.connecting_output){ - this.showSearchBox(e,{node_from: this.connecting_node, slot_from: this.connecting_output, type_filter_in: this.connecting_output.type}); - }else if(this.connecting_input){ - this.showSearchBox(e,{node_to: this.connecting_node, slot_from: this.connecting_input, type_filter_out: this.connecting_input.type}); - } - }else{ - if(this.connecting_output){ - this.showConnectionMenu({nodeFrom: this.connecting_node, slotFrom: this.connecting_output, e: e}); - }else if(this.connecting_input){ - this.showConnectionMenu({nodeTo: this.connecting_node, slotTo: this.connecting_input, e: e}); - } - } + if (LiteGraph.release_link_on_empty_shows_menu){ + if (e.shiftKey && this.allow_searchbox){ + if(this.connecting_output){ + this.showSearchBox(e,{node_from: this.connecting_node, slot_from: this.connecting_output, type_filter_in: this.connecting_output.type}); + }else if(this.connecting_input){ + this.showSearchBox(e,{node_to: this.connecting_node, slot_from: this.connecting_input, type_filter_out: this.connecting_input.type}); + } + }else{ + if(this.connecting_output){ + this.showConnectionMenu({nodeFrom: this.connecting_node, slotFrom: this.connecting_output, e: e}); + }else if(this.connecting_input){ + this.showConnectionMenu({nodeTo: this.connecting_node, slotTo: this.connecting_input, e: e}); + } + } + } } this.connecting_output = null; @@ -10569,14 +10718,40 @@ LGraphNode.prototype.executeAction = function(action) } var options = ["Add Node",null]; + + if (that.allow_searchbox){ + options.push("Search"); + options.push(null); + } + + // get defaults nodes for this slottype + var slotTypesDefault = isFrom ? LiteGraph.slot_types_default_out : LiteGraph.slot_types_default_in; + if(slotTypesDefault && slotTypesDefault[slotX.type]){ + //console.log("TypeDefaulMenu (OUT?"+isFrom+") "+slotX.type+" :: "+slotTypesDefault[slotX.type]); + if (slotX.link !== null) { + // is connected + }else{ + // is not not connected + } + //console.log(typeof slotTypesDefault[slotX.type]); + if(typeof slotTypesDefault[slotX.type] == "object" || typeof slotTypesDefault[slotX.type] == "array"){ + for(var typeX in slotTypesDefault[slotX.type]){ + //console.log(slotX.type+" has default "+slotTypesDefault[slotX.type][typeX]); + options.push(slotTypesDefault[slotX.type][typeX]); + } + }else{ + options.push(slotTypesDefault[slotX.type]); + } + } + var menu = new LiteGraph.ContextMenu(options, { event: opts.e, - title: slotX && slotX.name ? slotX.name : null, + title: (slotX && slotX.name!="" ? (slotX.name + (slotX.type?" | ":"")) : "")+(slotX && slotX.type ? slotX.type : ""), callback: inner_clicked }); function inner_clicked(v,options,e) { - console.debug("menuadd"); + //console.log("Process showConnectionMenu selection"); switch (v) { case "Add Node": LGraphCanvas.onMenuAdd(null, null, e, menu, function(node){ @@ -10587,10 +10762,90 @@ LGraphNode.prototype.executeAction = function(action) } }); break; - /*case "Delete": - that.graph.removeLink(link.id); - break;*/ + case "Search": + if(isFrom){ + that.showSearchBox(e,{node_from: opts.nodeFrom, slot_from: slotX, type_filter_in: slotX.type}); + }else{ + that.showSearchBox(e,{node_to: opts.nodeTo, slot_from: slotX, type_filter_out: slotX.type}); + } + break; default: + // check for defaults nodes for this slottype + var slotTypesDefault = isFrom ? LiteGraph.slot_types_default_out : LiteGraph.slot_types_default_in; + if(slotTypesDefault && slotTypesDefault[slotX.type]){ + if (slotX.link !== null) { + // is connected + }else{ + // is not not connected + } + nodeNewType = false; + if(typeof slotTypesDefault[slotX.type] == "object" || typeof slotTypesDefault[slotX.type] == "array"){ + for(var typeX in slotTypesDefault[slotX.type]){ + if (v == slotTypesDefault[slotX.type][typeX]) nodeNewType = slotTypesDefault[slotX.type][typeX]; + } + }else{ + if (v == slotTypesDefault[slotX.type]) nodeNewType = slotTypesDefault[slotX.type]; + } + if (nodeNewType) { + var nodeNewOpts = false; + if (typeof nodeNewType == "object" && nodeNewType.node){ + nodeNewOpts = nodeNewType; + nodeNewType = nodeNewType.node; + } + //that.graph.beforeChange(); + var newNode = LiteGraph.createNode(nodeNewType); + if(newNode){ + // if is object pass options + if (nodeNewOpts){ + if (nodeNewOpts.properties) { + for (var i in nodeNewOpts.properties) { + newNode.addProperty( i, nodeNewOpts.properties[i] ); + } + } + if (nodeNewOpts.inputs) { + newNode.inputs = []; + for (var i in nodeNewOpts.inputs) { + newNode.addOutput( + nodeNewOpts.inputs[i][0], + nodeNewOpts.inputs[i][1] + ); + } + } + if (nodeNewOpts.outputs) { + newNode.outputs = []; + for (var i in nodeNewOpts.outputs) { + newNode.addOutput( + nodeNewOpts.outputs[i][0], + nodeNewOpts.outputs[i][1] + ); + } + } + if (nodeNewOpts.title) { + newNode.title = nodeNewOpts.title; + } + if (nodeNewOpts.json) { + newNode.configure(nodeNewOpts.json); + } + + } + // add the node + newNode.pos = [opts.e.canvasX,opts.e.canvasY]; //that.last_click_position; //[e.canvasX+30, e.canvasX+5]; + that.graph.add(newNode); + //that.graph.afterChange(); + // connect the two! + if (isFrom){ + opts.nodeFrom.connectByType( iSlotConn, newNode, slotX.type ); + }else{ + opts.nodeTo.connectByTypeOutput( iSlotConn, newNode, slotX.type ); + } + }else{ + console.log("failed creating "+nodeNewType); + } + } + }else{ + //console.log("no slotTypesDefault for "+slotX.type); + } + break; } } @@ -10974,7 +11229,7 @@ LGraphNode.prototype.executeAction = function(action) var nSlots = aSlots.length; // this for object :: Object.keys(aSlots).length; if (options.type_filter_in == LiteGraph.EVENT || options.type_filter_in == LiteGraph.ACTION) - options.type_filter_in = "event/action"; + options.type_filter_in = "_event_"; /* this will filter on * .. but better do it manually in case else if(options.type_filter_in === "" || options.type_filter_in === 0) options.type_filter_in = "*";*/ @@ -11001,7 +11256,7 @@ LGraphNode.prototype.executeAction = function(action) var nSlots = aSlots.length; // this for object :: Object.keys(aSlots).length; if (options.type_filter_out == LiteGraph.EVENT || options.type_filter_out == LiteGraph.ACTION) - options.type_filter_out = "event/action"; + options.type_filter_out = "_event_"; /* this will filter on * .. but better do it manually in case else if(options.type_filter_out === "" || options.type_filter_out === 0) options.type_filter_out = "*";*/ @@ -11317,7 +11572,7 @@ LGraphNode.prototype.executeAction = function(action) var sV = sIn.value; if (opts.inTypeOverride!==false) sV = opts.inTypeOverride; - //if (sV.toLowerCase() == "event/action") sV = LiteGraph.EVENT; // -1 + //if (sV.toLowerCase() == "_event_") sV = LiteGraph.EVENT; // -1 if(sIn && sV){ //console.log("will check filter against "+sV); @@ -11336,7 +11591,7 @@ LGraphNode.prototype.executeAction = function(action) var sV = sOut.value; if (opts.outTypeOverride!==false) sV = opts.outTypeOverride; - //if (sV.toLowerCase() == "event/action") sV = LiteGraph.EVENT; // -1 + //if (sV.toLowerCase() == "_event_") sV = LiteGraph.EVENT; // -1 if(sOut && sV){ //console.log("search will check filter against "+sV); @@ -11846,8 +12101,8 @@ LGraphNode.prototype.executeAction = function(action) // assume coming from the menu event click if (!obEv || !obEv.event || !obEv.event.target || !obEv.event.target.lgraphcanvas){ console.warn("Canvas not found"); // need a ref to canvas obj - console.debug(event); - console.debug(event.target); + /*console.debug(event); + console.debug(event.target);*/ return; } var graphcanvas = obEv.event.target.lgraphcanvas; @@ -12597,16 +12852,16 @@ LGraphNode.prototype.executeAction = function(action) menu_info.push({ content: "Disconnect Links", slot: slot }); } var _slot = slot.input || slot.output; - menu_info.push( - _slot.locked || !_slot.removable - ? "Cannot remove" - : { content: "Remove Slot", slot: slot } - ); - menu_info.push( - _slot.nameLocked - ? "Cannot rename" - : { content: "Rename Slot", slot: slot } - ); + if (_slot.removable){ + menu_info.push( + _slot.locked + ? "Cannot remove" + : { content: "Remove Slot", slot: slot } + ); + } + if (!_slot.nameLocked){ + menu_info.push({ content: "Rename Slot", slot: slot }); + } } options.title = @@ -12687,19 +12942,32 @@ LGraphNode.prototype.executeAction = function(action) if (input && slot_info) { input.value = slot_info.label || ""; } - dialog - .querySelector("button") - .addEventListener("click", function(e) { - node.graph.beforeChange(); - if (input.value) { - if (slot_info) { - slot_info.label = input.value; - } - that.setDirty(true); + var inner = function(){ + node.graph.beforeChange(); + if (input.value) { + if (slot_info) { + slot_info.label = input.value; } + that.setDirty(true); + } + dialog.close(); + node.graph.afterChange(); + } + dialog.querySelector("button").addEventListener("click", inner); + input.addEventListener("keydown", function(e) { + dialog.is_modified = true; + if (e.keyCode == 27) { + //ESC dialog.close(); - node.graph.afterChange(); - }); + } else if (e.keyCode == 13) { + inner(); // save + } else if (e.keyCode != 13 && e.target.localName != "textarea") { + return; + } + e.preventDefault(); + e.stopPropagation(); + }); + input.focus(); } //if(v.callback) diff --git a/src/nodes/others.js b/src/nodes/others.js index 7d720af64..2b2f0fe95 100755 --- a/src/nodes/others.js +++ b/src/nodes/others.js @@ -1 +1,37 @@ -// extra generic nodes \ No newline at end of file +(function(global) { + var LiteGraph = global.LiteGraph; + + /* in types :: run in console :: var s=""; LiteGraph.slot_types_in.forEach(function(el){s+=el+"\n";}); console.log(s); */ + + if(typeof LiteGraph.slot_types_default_in == "undefined") LiteGraph.slot_types_default_in = {}; + LiteGraph.slot_types_default_in["_event_"] = "widget/button"; + LiteGraph.slot_types_default_in["array"] = "basic/array"; + LiteGraph.slot_types_default_in["boolean"] = "basic/boolean"; + LiteGraph.slot_types_default_in["number"] = "widget/number"; + LiteGraph.slot_types_default_in["object"] = "basic/data"; + LiteGraph.slot_types_default_in["string"] = ["basic/string","string/concatenate"]; + LiteGraph.slot_types_default_in["vec2"] = "math3d/xy-to-vec2"; + LiteGraph.slot_types_default_in["vec3"] = "math3d/xyz-to-vec3"; + LiteGraph.slot_types_default_in["vec4"] = "math3d/xyzw-to-vec4"; + + /* out types :: run in console :: var s=""; LiteGraph.slot_types_out.forEach(function(el){s+=el+"\n";}); console.log(s); */ + if(typeof LiteGraph.slot_types_default_out == "undefined") LiteGraph.slot_types_default_out = {}; + LiteGraph.slot_types_default_out["_event_"] = ["logic/IF","events/sequence","events/log","events/counter"]; + LiteGraph.slot_types_default_out["array"] = ["basic/watch","basic/set_array","basic/array[]"]; + LiteGraph.slot_types_default_out["boolean"] = ["logic/IF","basic/watch","math/branch","math/gate"]; + LiteGraph.slot_types_default_out["number"] = ["basic/watch" + ,{node:"math/operation",properties:{OP:"*"},title:"A*B"} + ,{node:"math/operation",properties:{OP:"/"},title:"A/B"} + ,{node:"math/operation",properties:{OP:"+"},title:"A+B"} + ,{node:"math/operation",properties:{OP:"-"},title:"A-B"} + ,{node:"math/compare",outputs:[["A==B", "boolean"]],title:"A==B"} + ,{node:"math/compare",outputs:[["A>B", "boolean"]],title:"A>B"} + ,{node:"math/compare",outputs:[["A