From 07e9a6b8266326c5f51ea7b0cc20c6129bf5d238 Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Fri, 7 Apr 2023 15:11:00 -0400 Subject: [PATCH] Update litegraph from upstream. --- web/lib/litegraph.core.js | 321 +++++++++++++++++++------------------- 1 file changed, 164 insertions(+), 157 deletions(-) diff --git a/web/lib/litegraph.core.js b/web/lib/litegraph.core.js index 862d5906..066f5193 100644 --- a/web/lib/litegraph.core.js +++ b/web/lib/litegraph.core.js @@ -89,6 +89,7 @@ NO_TITLE: 1, TRANSPARENT_TITLE: 2, AUTOHIDE_TITLE: 3, + VERTICAL_LAYOUT: "vertical", // arrange nodes vertically proxy: null, //used to redirect calls node_images_path: "", @@ -125,14 +126,14 @@ 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 + slot_types_default_in: [], // specify for each IN slot type a(/many) default 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) default 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 - allow_multi_output_for_events: 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 sequentially, one by one middle_click_slot_add_default_node: false, //[true!] allows to create and connect a ndoe clicking with the third button (wheel) @@ -158,80 +159,67 @@ console.log("Node registered: " + type); } - var categories = type.split("/"); - var classname = base_class.name; + const classname = base_class.name; - var pos = type.lastIndexOf("/"); - base_class.category = type.substr(0, pos); + const pos = type.lastIndexOf("/"); + base_class.category = type.substring(0, pos); if (!base_class.title) { base_class.title = classname; } - //info.name = name.substr(pos+1,name.length - pos); //extend class - if (base_class.prototype) { - //is a class - for (var i in LGraphNode.prototype) { - if (!base_class.prototype[i]) { - base_class.prototype[i] = LGraphNode.prototype[i]; - } + for (var i in LGraphNode.prototype) { + if (!base_class.prototype[i]) { + base_class.prototype[i] = LGraphNode.prototype[i]; } } - var prev = this.registered_node_types[type]; - if(prev) - console.log("replacing node type: " + type); - else - { - if( !Object.hasOwnProperty( base_class.prototype, "shape") ) - Object.defineProperty(base_class.prototype, "shape", { - set: function(v) { - switch (v) { - case "default": - delete this._shape; - break; - case "box": - this._shape = LiteGraph.BOX_SHAPE; - break; - case "round": - this._shape = LiteGraph.ROUND_SHAPE; - break; - case "circle": - this._shape = LiteGraph.CIRCLE_SHAPE; - break; - case "card": - this._shape = LiteGraph.CARD_SHAPE; - break; - default: - this._shape = v; - } - }, - get: function(v) { - return this._shape; - }, - enumerable: true, - configurable: true - }); + const prev = this.registered_node_types[type]; + if(prev) { + console.log("replacing node type: " + type); + } + if( !Object.prototype.hasOwnProperty.call( base_class.prototype, "shape") ) { + Object.defineProperty(base_class.prototype, "shape", { + set: function(v) { + switch (v) { + case "default": + delete this._shape; + break; + case "box": + this._shape = LiteGraph.BOX_SHAPE; + break; + case "round": + this._shape = LiteGraph.ROUND_SHAPE; + break; + case "circle": + this._shape = LiteGraph.CIRCLE_SHAPE; + break; + case "card": + this._shape = LiteGraph.CARD_SHAPE; + break; + default: + this._shape = v; + } + }, + get: function() { + return this._shape; + }, + enumerable: true, + configurable: true + }); + - //warnings - if (base_class.prototype.onPropertyChange) { - console.warn( - "LiteGraph node class " + - type + - " has onPropertyChange method, it must be called onPropertyChanged with d at the end" - ); - } - - //used to know which nodes create when dragging files to the canvas - if (base_class.supported_extensions) { - for (var i in base_class.supported_extensions) { - var ext = base_class.supported_extensions[i]; - if(ext && ext.constructor === String) - this.node_types_by_file_extension[ ext.toLowerCase() ] = base_class; - } - } - } + //used to know which nodes to create when dragging files to the canvas + if (base_class.supported_extensions) { + for (let i in base_class.supported_extensions) { + const ext = base_class.supported_extensions[i]; + if(ext && ext.constructor === String) { + this.node_types_by_file_extension[ ext.toLowerCase() ] = base_class; + } + } + } + } this.registered_node_types[type] = base_class; if (base_class.constructor.name) { @@ -252,19 +240,11 @@ " has onPropertyChange method, it must be called onPropertyChanged with d at the end" ); } - - //used to know which nodes create when dragging files to the canvas - if (base_class.supported_extensions) { - for (var i=0; i < base_class.supported_extensions.length; i++) { - var ext = base_class.supported_extensions[i]; - if(ext && ext.constructor === String) - this.node_types_by_file_extension[ ext.toLowerCase() ] = base_class; - } - } - // TODO one would want to know input and ouput :: this would allow trought registerNodeAndSlotType to get all the slots types - //console.debug("Registering "+type); - if (this.auto_load_slot_types) nodeTmp = new base_class(base_class.title || "tmpnode"); + // TODO one would want to know input and ouput :: this would allow through registerNodeAndSlotType to get all the slots types + if (this.auto_load_slot_types) { + new base_class(base_class.title || "tmpnode"); + } }, /** @@ -1260,37 +1240,39 @@ * Positions every node in a more readable manner * @method arrange */ - LGraph.prototype.arrange = function(margin) { + LGraph.prototype.arrange = function (margin, layout) { margin = margin || 100; - var nodes = this.computeExecutionOrder(false, true); - var columns = []; - for (var i = 0; i < nodes.length; ++i) { - var node = nodes[i]; - var col = node._level || 1; + const nodes = this.computeExecutionOrder(false, true); + const columns = []; + for (let i = 0; i < nodes.length; ++i) { + const node = nodes[i]; + const col = node._level || 1; if (!columns[col]) { columns[col] = []; } columns[col].push(node); } - var x = margin; + let x = margin; - for (var i = 0; i < columns.length; ++i) { - var column = columns[i]; + for (let i = 0; i < columns.length; ++i) { + const column = columns[i]; if (!column) { continue; } - var max_size = 100; - var y = margin + LiteGraph.NODE_TITLE_HEIGHT; - for (var j = 0; j < column.length; ++j) { - var node = column[j]; - node.pos[0] = x; - node.pos[1] = y; - if (node.size[0] > max_size) { - max_size = node.size[0]; + let max_size = 100; + let y = margin + LiteGraph.NODE_TITLE_HEIGHT; + for (let j = 0; j < column.length; ++j) { + const node = column[j]; + node.pos[0] = (layout == LiteGraph.VERTICAL_LAYOUT) ? y : x; + node.pos[1] = (layout == LiteGraph.VERTICAL_LAYOUT) ? x : y; + const max_size_index = (layout == LiteGraph.VERTICAL_LAYOUT) ? 1 : 0; + if (node.size[max_size_index] > max_size) { + max_size = node.size[max_size_index]; } - y += node.size[1] + margin + LiteGraph.NODE_TITLE_HEIGHT; + const node_size_index = (layout == LiteGraph.VERTICAL_LAYOUT) ? 0 : 1; + y += node.size[node_size_index] + margin + LiteGraph.NODE_TITLE_HEIGHT; } x += max_size + margin; } @@ -2468,43 +2450,34 @@ this.title = this.constructor.title; } - if (this.onConnectionsChange) { - if (this.inputs) { - for (var i = 0; i < this.inputs.length; ++i) { - var input = this.inputs[i]; - var link_info = this.graph - ? this.graph.links[input.link] - : null; - this.onConnectionsChange( - LiteGraph.INPUT, - i, - true, - link_info, - input - ); //link_info has been created now, so its updated - } - } + if (this.inputs) { + for (var i = 0; i < this.inputs.length; ++i) { + var input = this.inputs[i]; + var link_info = this.graph ? this.graph.links[input.link] : null; + if (this.onConnectionsChange) + this.onConnectionsChange( LiteGraph.INPUT, i, true, link_info, input ); //link_info has been created now, so its updated - if (this.outputs) { - for (var i = 0; i < this.outputs.length; ++i) { - var output = this.outputs[i]; - if (!output.links) { - continue; - } - for (var j = 0; j < output.links.length; ++j) { - var link_info = this.graph - ? this.graph.links[output.links[j]] - : null; - this.onConnectionsChange( - LiteGraph.OUTPUT, - i, - true, - link_info, - output - ); //link_info has been created now, so its updated - } - } - } + if( this.onInputAdded ) + this.onInputAdded(input); + + } + } + + if (this.outputs) { + for (var i = 0; i < this.outputs.length; ++i) { + var output = this.outputs[i]; + if (!output.links) { + continue; + } + for (var j = 0; j < output.links.length; ++j) { + var link_info = this.graph ? this.graph.links[output.links[j]] : null; + if (this.onConnectionsChange) + this.onConnectionsChange( LiteGraph.OUTPUT, i, true, link_info, output ); //link_info has been created now, so its updated + } + + if( this.onOutputAdded ) + this.onOutputAdded(output); + } } if( this.widgets ) @@ -3200,6 +3173,15 @@ return; } + if(slot == null) + { + console.error("slot must be a number"); + return; + } + + if(slot.constructor !== Number) + console.warn("slot must be a number, use node.trigger('name') if you want to use a string"); + var output = this.outputs[slot]; if (!output) { return; @@ -3346,26 +3328,26 @@ * @param {Object} extra_info this can be used to have special properties of an output (label, special color, position, etc) */ LGraphNode.prototype.addOutput = function(name, type, extra_info) { - var o = { name: name, type: type, links: null }; + var output = { name: name, type: type, links: null }; if (extra_info) { for (var i in extra_info) { - o[i] = extra_info[i]; + output[i] = extra_info[i]; } } if (!this.outputs) { this.outputs = []; } - this.outputs.push(o); + this.outputs.push(output); if (this.onOutputAdded) { - this.onOutputAdded(o); + this.onOutputAdded(output); } if (LiteGraph.auto_load_slot_types) LiteGraph.registerNodeAndSlotType(this,type,true); this.setSize( this.computeSize() ); this.setDirtyCanvas(true, true); - return o; + return output; }; /** @@ -3437,10 +3419,10 @@ */ LGraphNode.prototype.addInput = function(name, type, extra_info) { type = type || 0; - var o = { name: name, type: type, link: null }; + var input = { name: name, type: type, link: null }; if (extra_info) { for (var i in extra_info) { - o[i] = extra_info[i]; + input[i] = extra_info[i]; } } @@ -3448,17 +3430,17 @@ this.inputs = []; } - this.inputs.push(o); + this.inputs.push(input); this.setSize( this.computeSize() ); if (this.onInputAdded) { - this.onInputAdded(o); + this.onInputAdded(input); } LiteGraph.registerNodeAndSlotType(this,type); this.setDirtyCanvas(true, true); - return o; + return input; }; /** @@ -5210,6 +5192,7 @@ LGraphNode.prototype.executeAction = function(action) this.allow_dragcanvas = true; this.allow_dragnodes = true; this.allow_interaction = true; //allow to control widgets, buttons, collapse, etc + this.multi_select = false; //allow selecting multi nodes without pressing extra keys this.allow_searchbox = true; this.allow_reconnect_links = true; //allows to change a connection with having to redo it again this.align_to_grid = false; //snap to grid @@ -5435,7 +5418,7 @@ LGraphNode.prototype.executeAction = function(action) }; /** - * returns the visualy active graph (in case there are more in the stack) + * returns the visually active graph (in case there are more in the stack) * @method getCurrentGraph * @return {LGraph} the active graph */ @@ -6060,9 +6043,13 @@ LGraphNode.prototype.executeAction = function(action) this.graph.beforeChange(); this.node_dragged = node; } - if (!this.selected_nodes[node.id]) { - this.processNodeSelected(node, e); - } + this.processNodeSelected(node, e); + } else { // double-click + /** + * Don't call the function if the block is already selected. + * Otherwise, it could cause the block to be unselected while its panel is open. + */ + if (!node.is_selected) this.processNodeSelected(node, e); } this.dirty_canvas = true; @@ -6474,6 +6461,10 @@ LGraphNode.prototype.executeAction = function(action) var n = this.selected_nodes[i]; n.pos[0] += delta[0] / this.ds.scale; n.pos[1] += delta[1] / this.ds.scale; + if (!n.is_selected) this.processNodeSelected(n, e); /* + * Don't call the function if the block is already selected. + * Otherwise, it could cause the block to be unselected while dragging. + */ } this.dirty_canvas = true; @@ -7287,7 +7278,7 @@ LGraphNode.prototype.executeAction = function(action) }; LGraphCanvas.prototype.processNodeSelected = function(node, e) { - this.selectNode(node, e && (e.shiftKey||e.ctrlKey)); + this.selectNode(node, e && (e.shiftKey || e.ctrlKey || this.multi_select)); if (this.onNodeSelected) { this.onNodeSelected(node); } @@ -7323,6 +7314,7 @@ LGraphNode.prototype.executeAction = function(action) for (var i in nodes) { var node = nodes[i]; if (node.is_selected) { + this.deselectNode(node); continue; } @@ -7489,8 +7481,8 @@ LGraphNode.prototype.executeAction = function(action) clientY_rel = e.clientY; } - e.deltaX = clientX_rel - this.last_mouse_position[0]; - e.deltaY = clientY_rel- this.last_mouse_position[1]; + // e.deltaX = clientX_rel - this.last_mouse_position[0]; + // e.deltaY = clientY_rel- this.last_mouse_position[1]; this.last_mouse_position[0] = clientX_rel; this.last_mouse_position[1] = clientY_rel; @@ -9742,13 +9734,17 @@ LGraphNode.prototype.executeAction = function(action) ctx.fillRect(margin, y, widget_width - margin * 2, H); var range = w.options.max - w.options.min; var nvalue = (w.value - w.options.min) / range; - ctx.fillStyle = active_widget == w ? "#89A" : "#678"; + if(nvalue < 0.0) nvalue = 0.0; + if(nvalue > 1.0) nvalue = 1.0; + ctx.fillStyle = w.options.hasOwnProperty("slider_color") ? w.options.slider_color : (active_widget == w ? "#89A" : "#678"); ctx.fillRect(margin, y, nvalue * (widget_width - margin * 2), H); if(show_text && !w.disabled) ctx.strokeRect(margin, y, widget_width - margin * 2, H); if (w.marker) { var marker_nvalue = (w.marker - w.options.min) / range; - ctx.fillStyle = "#AA9"; + if(marker_nvalue < 0.0) marker_nvalue = 0.0; + if(marker_nvalue > 1.0) marker_nvalue = 1.0; + ctx.fillStyle = w.options.hasOwnProperty("marker_color") ? w.options.marker_color : "#AA9"; ctx.fillRect( margin + marker_nvalue * (widget_width - margin * 2), y, 2, H ); } if (show_text) { @@ -9915,6 +9911,7 @@ LGraphNode.prototype.executeAction = function(action) case "slider": var range = w.options.max - w.options.min; var nvalue = Math.clamp((x - 15) / (widget_width - 30), 0, 1); + if(w.options.read_only) break; w.value = w.options.min + (w.options.max - w.options.min) * nvalue; if (w.callback) { setTimeout(function() { @@ -9927,7 +9924,8 @@ LGraphNode.prototype.executeAction = function(action) case "combo": var old_value = w.value; if (event.type == LiteGraph.pointerevents_method+"move" && w.type == "number") { - w.value += event.deltaX * 0.1 * (w.options.step || 1); + if(event.deltaX) + w.value += event.deltaX * 0.1 * (w.options.step || 1); if ( w.options.min != null && w.value < w.options.min ) { w.value = w.options.min; } @@ -9994,6 +9992,12 @@ LGraphNode.prototype.executeAction = function(action) var delta = x < 40 ? -1 : x > widget_width - 40 ? 1 : 0; if (event.click_time < 200 && delta == 0) { this.prompt("Value",w.value,function(v) { + // check if v is a valid equation or a number + if (/^[0-9+\-*/()\s]+$/.test(v)) { + try {//solve the equation if possible + v = eval(v); + } catch (e) { } + } this.value = Number(v); inner_value_change(this, this.value); }.bind(w), @@ -10022,7 +10026,6 @@ LGraphNode.prototype.executeAction = function(action) case "text": if (event.type == LiteGraph.pointerevents_method+"down") { this.prompt("Value",w.value,function(v) { - this.value = v; inner_value_change(this, v); }.bind(w), event,w.options ? w.options.multiline : false ); @@ -10047,6 +10050,9 @@ LGraphNode.prototype.executeAction = function(action) }//end for function inner_value_change(widget, value) { + if(widget.type == "number"){ + value = Number(value); + } widget.value = value; if ( widget.options && widget.options.property && node.properties[widget.options.property] !== undefined ) { node.setProperty( widget.options.property, value ); @@ -11165,7 +11171,7 @@ LGraphNode.prototype.executeAction = function(action) LGraphCanvas.search_limit = -1; LGraphCanvas.prototype.showSearchBox = function(event, options) { // proposed defaults - def_options = { slot_from: null + var def_options = { slot_from: null ,node_from: null ,node_to: null ,do_type_filter: LiteGraph.search_filter_enabled // TODO check for registered_slot_[in/out]_types not empty // this will be checked for functionality enabled : filter on slot type, in and out @@ -11863,7 +11869,7 @@ LGraphNode.prototype.executeAction = function(action) // TODO refactor, theer are different dialog, some uses createDialog, some dont LGraphCanvas.prototype.createDialog = function(html, options) { - def_options = { checkForInput: false, closeOnLeave: true, closeOnLeave_checkModified: true }; + var def_options = { checkForInput: false, closeOnLeave: true, closeOnLeave_checkModified: true }; options = Object.assign(def_options, options || {}); var dialog = document.createElement("div"); @@ -11993,7 +11999,8 @@ LGraphNode.prototype.executeAction = function(action) if (root.onClose && typeof root.onClose == "function"){ root.onClose(); } - root.parentNode.removeChild(root); + if(root.parentNode) + root.parentNode.removeChild(root); /* XXX CHECK THIS */ if(this.parentNode){ this.parentNode.removeChild(this); @@ -12285,7 +12292,7 @@ LGraphNode.prototype.executeAction = function(action) var ref_window = this.getCanvasWindow(); var that = this; var graphcanvas = this; - panel = this.createPanel(node.title || "",{ + var panel = this.createPanel(node.title || "",{ closable: true ,window: ref_window ,onOpen: function(){