mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-14 17:37:46 +00:00
fix in widgets
This commit is contained in:
@@ -142,6 +142,16 @@ Editor.prototype.createPanel = function(title, options) {
|
||||
this.parentNode.removeChild(this);
|
||||
}
|
||||
|
||||
root.addHTML = function(code, classname)
|
||||
{
|
||||
var elem = document.createElement("div");
|
||||
if(classname)
|
||||
elem.className = classname;
|
||||
elem.innerHTML = code;
|
||||
root.content.appendChild(elem);
|
||||
return elem;
|
||||
}
|
||||
|
||||
root.addButton = function( name, callback, options )
|
||||
{
|
||||
var elem = document.createElement("button");
|
||||
@@ -152,6 +162,13 @@ Editor.prototype.createPanel = function(title, options) {
|
||||
return elem;
|
||||
}
|
||||
|
||||
root.addSeparator = function()
|
||||
{
|
||||
var elem = document.createElement("div");
|
||||
elem.className = "separator";
|
||||
root.content.appendChild(elem);
|
||||
}
|
||||
|
||||
root.addWidget = function( type, name, value, options, callback )
|
||||
{
|
||||
options = options || {};
|
||||
@@ -332,92 +349,40 @@ Editor.prototype.onShowNodePanel = function(node)
|
||||
function inner_refresh()
|
||||
{
|
||||
panel.content.innerHTML = ""; //clear
|
||||
var elem = document.createElement("div");
|
||||
elem.innerHTML = "<span class='node_type'>"+node.type+"</span><span class='node_desc'>"+(node.constructor.desc || "")+"</span><span class='separator'></span>";
|
||||
panel.content.appendChild(elem);
|
||||
panel.addHTML("<span class='node_type'>"+node.type+"</span><span class='node_desc'>"+(node.constructor.desc || "")+"</span><span class='separator'></span>");
|
||||
|
||||
panel.addHTML("<h3>Properties</h3>");
|
||||
|
||||
for(var i in node.properties)
|
||||
{
|
||||
var value = node.properties[i];
|
||||
var info = node.getPropertyInfo(i);
|
||||
var type = info.type || "string";
|
||||
|
||||
//in case the user wants control over the side panel widget
|
||||
if( node.onAddPropertyToPanel && node.onAddPropertyToPanel(i,panel) )
|
||||
continue;
|
||||
|
||||
panel.addWidget( info.widget || info.type, i, value, info, function(name,value){
|
||||
node.setProperty(name,value);
|
||||
graphcanvas.dirty_canvas = true;
|
||||
});
|
||||
}
|
||||
|
||||
panel.addSeparator();
|
||||
|
||||
/*
|
||||
panel.addHTML("<h3>Connections</h3>");
|
||||
var connection_containers = panel.addHTML("<div class='inputs connections_side'></div><div class='outputs connections_side'></div>","connections");
|
||||
var inputs = connection_containers.querySelector(".inputs");
|
||||
var outputs = connection_containers.querySelector(".outputs");
|
||||
*/
|
||||
|
||||
|
||||
panel.addButton("Delete",function(){
|
||||
node.graph.remove(node);
|
||||
panel.close();
|
||||
}).classList.add("delete");
|
||||
|
||||
/*
|
||||
for(var i in node.properties)
|
||||
{
|
||||
var value = node.properties[i];
|
||||
var type = "string";
|
||||
var info = node.getPropertyInfo(i);
|
||||
var type = info.type;
|
||||
|
||||
var str_value = String(value);
|
||||
if(type == "number")
|
||||
str_value = value.toFixed(3);
|
||||
|
||||
var elem = document.createElement("div");
|
||||
elem.className = "property";
|
||||
elem.innerHTML = "<span class='property_name'></span><span class='property_value'></span>";
|
||||
elem.querySelector(".property_name").innerText = i;
|
||||
var value_element = elem.querySelector(".property_value");
|
||||
value_element.innerText = str_value;
|
||||
elem.dataset["property"] = i;
|
||||
elem.dataset["type"] = type;
|
||||
elem.datainfo = info;
|
||||
|
||||
if( type == "code" )
|
||||
elem.addEventListener("click", function(){ inner_showCodePad( node, this.dataset["property"] ); });
|
||||
else if (type == "boolean")
|
||||
elem.addEventListener("click", function(){
|
||||
var v = node.properties[this.dataset["property"]];
|
||||
node.setProperty(this.dataset["property"],!v); this.innerText = v ? "true" : "false";
|
||||
});
|
||||
else if (type == "string" || type == "number")
|
||||
{
|
||||
value_element.setAttribute("contenteditable",true);
|
||||
value_element.addEventListener("change", function(){
|
||||
var v = this.innerText;
|
||||
var propname = this.parentNode.dataset["property"];
|
||||
if( propname == "number")
|
||||
v = Number(v);
|
||||
node.setProperty(propname,v);
|
||||
that.dirty_canvas = true;
|
||||
});
|
||||
}
|
||||
else if (type == "enum")
|
||||
value_element.addEventListener("click", function(event){
|
||||
var values = this.parentNode.datainfo.values || [];
|
||||
var propname = this.parentNode.dataset["property"];
|
||||
var elem_that = this;
|
||||
var menu = new LiteGraph.ContextMenu(values,{
|
||||
event: event,
|
||||
className: "dark",
|
||||
callback: inner_clicked
|
||||
},
|
||||
ref_window);
|
||||
function inner_clicked(v, option, event) {
|
||||
node.setProperty(propname,v);
|
||||
elem_that.innerText = v;
|
||||
graphcanvas.dirty_canvas = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
else //generic
|
||||
elem.addEventListener("click", function(){
|
||||
that.graphcanvas.showEditPropertyValue( node, this.dataset["property"], {onclose: inner_refresh} );
|
||||
});
|
||||
panel.content.appendChild(elem);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
function inner_showCodePad( node, propname )
|
||||
|
||||
@@ -392,7 +392,6 @@
|
||||
* @method getNodeTypesCategories
|
||||
* @return {Array} array with all the names of the categories
|
||||
*/
|
||||
|
||||
getNodeTypesCategories: function( filter ) {
|
||||
var categories = { "": 1 };
|
||||
for (var i in this.registered_node_types) {
|
||||
@@ -472,6 +471,13 @@
|
||||
return target;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns if the types of two slots are compatible (taking into account wildcards, etc)
|
||||
* @method isValidConnection
|
||||
* @param {String} type_a
|
||||
* @param {String} type_b
|
||||
* @return {Boolean} true if they can be connected
|
||||
*/
|
||||
isValidConnection: function(type_a, type_b) {
|
||||
if (
|
||||
!type_a || //generic output
|
||||
@@ -507,13 +513,85 @@
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Register a string in the search box so when the user types it it will recommend this node
|
||||
* @method registerSearchboxExtra
|
||||
* @param {String} node_type the node recommended
|
||||
* @param {String} description text to show next to it
|
||||
* @param {Object} data it could contain info of how the node should be configured
|
||||
* @return {Boolean} true if they can be connected
|
||||
*/
|
||||
registerSearchboxExtra: function(node_type, description, data) {
|
||||
this.searchbox_extras[description.toLowerCase()] = {
|
||||
type: node_type,
|
||||
desc: description,
|
||||
data: data
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Wrapper to load files (from url using fetch or from file using FileReader)
|
||||
* @method fetchFile
|
||||
* @param {String|File|Blob} url the url of the file (or the file itself)
|
||||
* @param {String} type an string to know how to fetch it: "text","arraybuffer","json","blob"
|
||||
* @param {Function} on_complete callback(data)
|
||||
* @param {Function} on_error in case of an error
|
||||
* @return {FileReader|Promise} returns the object used to
|
||||
*/
|
||||
fetchFile: function( url, type, on_complete, on_error ) {
|
||||
var that = this;
|
||||
if(!url)
|
||||
return null;
|
||||
|
||||
type = type || "text";
|
||||
if( url.constructor === String )
|
||||
{
|
||||
if (url.substr(0, 4) == "http" && LiteGraph.proxy) {
|
||||
url = LiteGraph.proxy + url.substr(url.indexOf(":") + 3);
|
||||
}
|
||||
return fetch(url)
|
||||
.then(function(response) {
|
||||
if(!response.ok)
|
||||
throw new Error("File not found"); //it will be catch below
|
||||
if(type == "arraybuffer")
|
||||
return response.arrayBuffer();
|
||||
else if(type == "text" || type == "string")
|
||||
return response.text();
|
||||
else if(type == "json")
|
||||
return response.json();
|
||||
else if(type == "blob")
|
||||
return response.blob();
|
||||
})
|
||||
.then(function(data) {
|
||||
if(on_complete)
|
||||
on_complete(data);
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.error("error fetching file:",url);
|
||||
if(on_error)
|
||||
on_error(error);
|
||||
});
|
||||
}
|
||||
else if( url.constructor === File || url.constructor === Blob)
|
||||
{
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e)
|
||||
{
|
||||
var v = e.target.result;
|
||||
if( type == "json" )
|
||||
v = JSON.parse(v);
|
||||
if(on_complete)
|
||||
on_complete(v);
|
||||
}
|
||||
if(type == "arraybuffer")
|
||||
return reader.readAsArrayBuffer(url);
|
||||
else if(type == "text" || type == "json")
|
||||
return reader.readAsText(url);
|
||||
else if(type == "blob")
|
||||
return reader.readAsBinaryString(url);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
//timer that works everywhere
|
||||
@@ -8413,7 +8491,10 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
if (values && values.constructor === Function) {
|
||||
values = w.options.values(w, node);
|
||||
}
|
||||
var values_list = values.constructor === Array ? values : Object.keys(values);
|
||||
var values_list = null;
|
||||
|
||||
if( w.type != "number")
|
||||
values_list = values.constructor === Array ? values : Object.keys(values);
|
||||
|
||||
var delta = x < 40 ? -1 : x > width - 40 ? 1 : 0;
|
||||
if (w.type == "number") {
|
||||
|
||||
@@ -530,6 +530,15 @@
|
||||
|
||||
ConstantBoolean.prototype.setValue = ConstantNumber.prototype.setValue;
|
||||
|
||||
ConstantBoolean.prototype.onGetInputs = function() {
|
||||
return [["toggle", LiteGraph.ACTION]];
|
||||
};
|
||||
|
||||
ConstantBoolean.prototype.onAction = function(action)
|
||||
{
|
||||
this.setValue( !this.properties.value );
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("basic/boolean", ConstantBoolean);
|
||||
|
||||
function ConstantString() {
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
function MathRange() {
|
||||
this.addInput("in", "number", { locked: true });
|
||||
this.addOutput("out", "number", { locked: true });
|
||||
this.addOutput("clamped", "number", { locked: true });
|
||||
|
||||
this.addProperty("in", 0);
|
||||
this.addProperty("in_min", 0);
|
||||
@@ -117,7 +118,7 @@
|
||||
this.addProperty("out_min", 0);
|
||||
this.addProperty("out_max", 1);
|
||||
|
||||
this.size = [80, 30];
|
||||
this.size = [120, 50];
|
||||
}
|
||||
|
||||
MathRange.title = "Range";
|
||||
@@ -151,10 +152,22 @@
|
||||
var in_max = this.properties.in_max;
|
||||
var out_min = this.properties.out_min;
|
||||
var out_max = this.properties.out_max;
|
||||
/*
|
||||
if( in_min > in_max )
|
||||
{
|
||||
in_min = in_max;
|
||||
in_max = this.properties.in_min;
|
||||
}
|
||||
if( out_min > out_max )
|
||||
{
|
||||
out_min = out_max;
|
||||
out_max = this.properties.out_min;
|
||||
}
|
||||
*/
|
||||
|
||||
this._last_v =
|
||||
((v - in_min) / (in_max - in_min)) * (out_max - out_min) + out_min;
|
||||
this._last_v = ((v - in_min) / (in_max - in_min)) * (out_max - out_min) + out_min;
|
||||
this.setOutputData(0, this._last_v);
|
||||
this.setOutputData(1, Math.clamp( this._last_v, out_min, out_max ));
|
||||
};
|
||||
|
||||
MathRange.prototype.onDrawBackground = function(ctx) {
|
||||
|
||||
@@ -464,6 +464,21 @@
|
||||
var target_min = this.properties.target_min;
|
||||
var target_max = this.properties.target_max;
|
||||
|
||||
//swap to avoid errors
|
||||
/*
|
||||
if(range_min > range_max)
|
||||
{
|
||||
range_min = range_max;
|
||||
range_max = this.properties.range_min;
|
||||
}
|
||||
|
||||
if(target_min > target_max)
|
||||
{
|
||||
target_min = target_max;
|
||||
target_max = this.properties.target_min;
|
||||
}
|
||||
*/
|
||||
|
||||
for(var i = 0; i < 3; ++i)
|
||||
{
|
||||
var r = range_max[i] - range_min[i];
|
||||
|
||||
@@ -882,6 +882,24 @@
|
||||
this.properties.value1 = (v | 0) % 255;
|
||||
}
|
||||
break;
|
||||
case "cmd":
|
||||
var v = this.getInputData(i);
|
||||
if (v != null) {
|
||||
this.properties.cmd = v;
|
||||
}
|
||||
break;
|
||||
case "value1":
|
||||
var v = this.getInputData(i);
|
||||
if (v != null) {
|
||||
this.properties.value1 = Math.clamp(v|0,0,127);
|
||||
}
|
||||
break;
|
||||
case "value2":
|
||||
var v = this.getInputData(i);
|
||||
if (v != null) {
|
||||
this.properties.value2 = Math.clamp(v|0,0,127);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -950,7 +968,7 @@
|
||||
};
|
||||
|
||||
LGMIDIEvent.prototype.onGetInputs = function() {
|
||||
return [["note", "number"]];
|
||||
return [["cmd", "number"],["note", "number"],["value1", "number"],["value2", "number"]];
|
||||
};
|
||||
|
||||
LGMIDIEvent.prototype.onGetOutputs = function() {
|
||||
@@ -1207,6 +1225,119 @@
|
||||
|
||||
LiteGraph.registerNodeType("midi/quantize", LGMIDIQuantize);
|
||||
|
||||
function LGMIDIFromFile() {
|
||||
this.properties = {
|
||||
url: "",
|
||||
autoplay: true
|
||||
};
|
||||
|
||||
this.addInput("play", LiteGraph.ACTION);
|
||||
this.addInput("pause", LiteGraph.ACTION);
|
||||
this.addOutput("note", LiteGraph.EVENT);
|
||||
this._midi = null;
|
||||
this._current_time = 0;
|
||||
this._playing = false;
|
||||
|
||||
if (typeof MidiParser == "undefined") {
|
||||
console.error(
|
||||
"midi-parser.js not included, LGMidiPlay requires that library: https://raw.githubusercontent.com/colxi/midi-parser-js/master/src/main.js"
|
||||
);
|
||||
this.boxcolor = "red";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LGMIDIFromFile.title = "MIDI fromFile";
|
||||
LGMIDIFromFile.desc = "Plays a MIDI file";
|
||||
LGMIDIFromFile.color = MIDI_COLOR;
|
||||
|
||||
LGMIDIFromFile.prototype.onAction = function( name )
|
||||
{
|
||||
if(name == "play")
|
||||
this.play();
|
||||
else if(name == "pause")
|
||||
this._playing = !this._playing;
|
||||
}
|
||||
|
||||
LGMIDIFromFile.prototype.onPropertyChanged = function(name,value)
|
||||
{
|
||||
if(name == "url")
|
||||
this.loadMIDIFile(value);
|
||||
}
|
||||
|
||||
LGMIDIFromFile.prototype.onExecute = function() {
|
||||
if(!this._midi)
|
||||
return;
|
||||
|
||||
if(!this._playing)
|
||||
return;
|
||||
|
||||
this._current_time += this.graph.elapsed_time;
|
||||
var current_time = this._current_time * 100;
|
||||
|
||||
for(var i = 0; i < this._midi.tracks; ++i)
|
||||
{
|
||||
var track = this._midi.track[i];
|
||||
if(!track._last_pos)
|
||||
{
|
||||
track._last_pos = 0;
|
||||
track._time = 0;
|
||||
}
|
||||
|
||||
var elem = track.event[ track._last_pos ];
|
||||
if(elem && (track._time + elem.deltaTime) <= current_time )
|
||||
{
|
||||
track._last_pos++;
|
||||
track._time += elem.deltaTime;
|
||||
|
||||
if(elem.data)
|
||||
{
|
||||
var midi_cmd = elem.type << 4 + elem.channel;
|
||||
var midi_event = new MIDIEvent();
|
||||
midi_event.setup([midi_cmd, elem.data[0], elem.data[1]]);
|
||||
this.trigger("note", midi_event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
LGMIDIFromFile.prototype.play = function()
|
||||
{
|
||||
this._playing = true;
|
||||
this._current_time = 0;
|
||||
for(var i = 0; i < this._midi.tracks; ++i)
|
||||
{
|
||||
var track = this._midi.track[i];
|
||||
track._last_pos = 0;
|
||||
track._time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LGMIDIFromFile.prototype.loadMIDIFile = function(url)
|
||||
{
|
||||
var that = this;
|
||||
LiteGraph.fetchFile( url, "arraybuffer", function(data)
|
||||
{
|
||||
that.boxcolor = "#AFA";
|
||||
that._midi = MidiParser.parse( new Uint8Array(data) );
|
||||
if(that.properties.autoplay)
|
||||
that.play();
|
||||
}, function(err){
|
||||
that.boxcolor = "#FAA";
|
||||
that._midi = null;
|
||||
});
|
||||
}
|
||||
|
||||
LGMIDIFromFile.prototype.onDropFile = function(file)
|
||||
{
|
||||
this.properties.url = "";
|
||||
this.loadMIDIFile( file );
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("midi/fromFile", LGMIDIFromFile);
|
||||
|
||||
|
||||
function LGMIDIPlay() {
|
||||
this.properties = {
|
||||
volume: 0.5,
|
||||
|
||||
Reference in New Issue
Block a user