This commit is contained in:
Chris
2025-10-28 13:25:14 +11:00
parent 6112251ffa
commit cbed9b460f
7 changed files with 121 additions and 124 deletions
-21
View File
@@ -1,21 +0,0 @@
import { app } from "../../scripts/app.js";
import { defineProperty } from "./use_everywhere_utilities.js";
/*
Things that can be useful (generally as breakpoints) when debugging
*/
export function add_debug() {
var dirty_canvas = true;
defineProperty(app.canvas, 'dirty_canvas', {
get : () => { return dirty_canvas },
set : (v) => { dirty_canvas = v;} // a breakpoint here catches the calls that mark the canvas as dirty
})
var dirty_bg_canvas = true;
defineProperty(app.canvas, 'dirty_bg_canvas', {
get : () => { return dirty_bg_canvas },
set : (v) => { dirty_bg_canvas = v;} // a breakpoint here catches the calls that mark the background canvas as dirty
})
}
export const version = 500006
+15 -36
View File
@@ -3,11 +3,10 @@ import { api } from "../../scripts/api.js";
import { shared, deferred_actions } from "./shared.js";
import { is_UEnode, inject, Logger, defineProperty, graphConverter, create, node_can_broadcast } from "./use_everywhere_utilities.js";
import { is_UEnode, inject, Logger, graphConverter, create, node_can_broadcast } from "./use_everywhere_utilities.js";
import { title_bar_additions, LinkRenderController } from "./use_everywhere_ui.js";
import { GraphAnalyser } from "./use_everywhere_graph_analysis.js";
import { canvas_menu_settings, SETTINGS, add_extra_menu_items } from "./use_everywhere_settings.js";
import { add_debug } from "./ue_debug.js";
import { settingsCache } from "./use_everywhere_cache.js";
import { convert_to_links } from "./use_everywhere_apply.js";
import { visible_graph, fix_new_subgraph_node } from "./use_everywhere_subgraph_utils.js";
@@ -32,6 +31,19 @@ function add_methods_to_all_nodes(node) {
if (original_onDrawTitleBar) original_onDrawTitleBar.apply(this, arguments);
title_bar_additions(node, ctx, title_height)
}
const original_onMouseEnter = node.onMouseEnter;
node.onMouseEnter = function(e) {
if (original_onMouseEnter) original_onMouseEnter(e)
shared.linkRenderController.node_over_changed()
}
const original_onMouseLeave = node.onMouseLeave;
node.onMouseEnter = function(e) {
if (original_onMouseLeave) original_onMouseLeave(e)
shared.linkRenderController.node_over_changed()
}
node.ue_methods_added = true;
} catch (e) {
Logger.log_error(e);
@@ -105,14 +117,7 @@ app.registerExtension({
// When a graph node is loaded convert it if needed
loadedGraphNode(node) {
//if (graphConverter.running_116_plus()) {
graphConverter.convert_if_pre_116(node);
//if (node.isSubgraphNode?.()) {
// node.subgraph.nodes.forEach((n) => {
// graphConverter.convert_if_pre_116(n);
// })
//}
//}
graphConverter.convert_if_pre_116(node);
setup_ue_properties_onload(node)
},
@@ -211,23 +216,6 @@ app.registerExtension({
return options;
}
/*
Finding a widget by it's name is something done a lot of times in rendering,
so add a method that caches the names that can be used deep in the rendering code.
TODO: Ought to delete this._widgetNameMap when widgets are added or removed.
TODO: Or better maybe to retire this.
LGraphNode.prototype._getWidgetByName = function(nm) {
if (this._widgetNameMap === undefined || !this._widgetNameMap[nm]) {
this._widgetNameMap = {}
this.widgets?.forEach((w)=>{this._widgetNameMap[w.name] = w})
}
if (!this._widgetNameMap[nm]) {
let breakpoint_be_here; // someone is asking for a widget that doesn't exist
}
return this._widgetNameMap[nm]
}*/
},
init() {
@@ -269,12 +257,6 @@ app.registerExtension({
shared.prompt_being_queued = false;
}
}
app.canvas.__node_over = app.canvas.node_over;
defineProperty(app.canvas, 'node_over', {
get: ( )=>{return app.canvas.__node_over },
set: (v)=>{app.canvas.__node_over = v; shared.linkRenderController.node_over_changed(v)}
} )
app.canvas.canvas.addEventListener('litegraph:set-graph', ()=>{
shared.linkRenderController.mark_link_list_outdated()
@@ -291,9 +273,6 @@ app.registerExtension({
}
})
if (false) add_debug();
const original_subgraph = app.graph.convertToSubgraph
app.graph.convertToSubgraph = function () {
const ctb_was = shared.graphAnalyser.connect_to_bypassed
+36 -16
View File
@@ -28,13 +28,6 @@ function regex_for(node, k) {
const P_REGEXES = ['prompt', 'negative']
const PROMPT_REGEXES = [new RegExp(i18n_functional('prompt_regex')), new RegExp(i18n_functional('negative_regex'))]
function prompt_regex(node, i) {
const reg = node.properties.ue_properties[`${P_REGEXES[i]}_regex`]
if (reg) return {regex:new RegExp(reg), invert:node.properties.ue_properties[`${P_REGEXES[i]}_regex_invert`]}
else return {regex:i18n_functional_regex(`${P_REGEXES[i]}_regex`), invert:!!node.properties.ue_properties[`${P_REGEXES[i]}_regex_invert`]}
}
/*
The UseEverywhere object represents a single 'broadcast'. It generally contains
controller - the UE node that controls the broadcase
@@ -158,6 +151,29 @@ function validity_errors(params) {
return "";
}
export class Ambiguity {
/*
name : display_name of node
id : node.id
input : input.name
matches : [
{
type : m[i].controller.type,
id : m[i].controller.id,
index : m[i].control_node_input_index
}
]
*/
toString() {
var m = `Node ${this.name} (${this.id}) input ${this.input} matches ${this.matches.length} sources:`
this.matches.forEach((match)=>{
m += `\n - ${match.type} (${match.id}) slot ${match.index}`
})
return m
}
}
export class UseEverywhereList {
constructor() { this.ues = []; this.unmatched_inputs = []; }
@@ -209,7 +225,7 @@ export class UseEverywhereList {
}
}
find_best_match(node, input, _ambiguity_messages) {
find_best_match(node, input, _ambiguities) {
this.unmatched_inputs.push({"node":node, "input":input});
var matches = this.ues.filter((candidate) => (
candidate.matches(node, input)
@@ -221,14 +237,18 @@ export class UseEverywhereList {
if (matches.length>1) {
matches.sort((a,b) => b.priority-a.priority);
if(matches[0].priority == matches[1].priority) {
const msg = `'${display_name(node)}' (${node.id}) input '${input.name}' matches multiple Use Everwhere sources:`;
_ambiguity_messages.push(msg);
for (var i=0; i<matches.length; i++) {
if (matches[0].priority == matches[i].priority) {
const inner_msg = ` - ${matches[i].controller.type} (${matches[i].controller.id}) input ${matches[i].control_node_input_index}`;
_ambiguity_messages.push(inner_msg);
}
}
const msg = new Ambiguity()
Object.assign(msg, { name:display_name(node), id:node.id, input:input.name, matches:[] })
matches.filter((m)=>(m.priority == matches[0].priority)).forEach((m)=>{
msg.matches.push( {
type : m.controller.type,
id : m.controller.id,
index : m.control_node_input_index
})
})
_ambiguities.push(msg);
return undefined;
}
}
+4 -4
View File
@@ -11,7 +11,7 @@ class GraphAnalyser extends Pausable {
constructor() {
super('GraphAnalyser')
this.original_graphToPrompt = app.graphToPrompt;
this.ambiguity_messages = [];
this.ambiguities = [];
this.latest_ues = null
this.mods = []
}
@@ -77,7 +77,7 @@ class GraphAnalyser extends Pausable {
})
}
this.ambiguity_messages = [];
this.ambiguities = [];
const treat_bypassed_as_live = settingsCache.getSettingValue("Use Everywhere.Options.connect_to_bypassed") || this.connect_to_bypassed
const live_nodes = graph.nodes.filter((node) => node_is_live(node, treat_bypassed_as_live))
@@ -108,7 +108,7 @@ class GraphAnalyser extends Pausable {
// see if we can connect them
const links_added = new Set();
connectable.forEach(({node, input, index}) => {
var ue = ues.find_best_match(node, input, this.ambiguity_messages);
var ue = ues.find_best_match(node, input, this.ambiguities);
if (ue) {
links_added.add({
"downstream":node.id, "downstream_slot":index,
@@ -121,7 +121,7 @@ class GraphAnalyser extends Pausable {
graph.extra['ue_links'] = Array.from(links_added)
if (this.ambiguity_messages.length) Logger.log_info("Ambiguous connections", this.ambiguity_messages, true);
if (this.ambiguities.length) Logger.log_info("Ambiguous connections", this.ambiguities, true);
this.latest_ues = ues;
return this.latest_ues;
+2 -2
View File
@@ -353,11 +353,11 @@ export function canvas_menu_settings(options) {
}
},
);
if (shared.graphAnalyser.ambiguity_messages.length) {
if (shared.graphAnalyser.ambiguities.length) {
options.push({
content: "Show UE broadcast clashes",
callback: async () => {
alert(shared.graphAnalyser.ambiguity_messages.join("\n"))
alert(shared.graphAnalyser.ambiguities.join("\n"))
}
})
}
+64 -18
View File
@@ -113,7 +113,7 @@ export class LinkRenderController extends Pausable {
//on_unpause() {app.graph.change();}
node_over_changed(v) {
node_over_changed() {
const mode = settingsCache.getSettingValue('Use Everywhere.Graphics.showlinks');
if (mode==2 || mode==3) app.canvas.setDirty(true,true)
}
@@ -207,15 +207,15 @@ export class LinkRenderController extends Pausable {
unconnected_connectable_names.delete(name_sent_to); // remove the name from the list of connectables
const pos2 = this._relative_connection_pos(node, true, ue_connection.input_index);
circle(ctx, pos2, {...CONNECTED_1, strokeStyle:LGraphCanvas.link_type_colors[ue_connection.type]})
circle(ctx, pos2, {...CONNECTED_2})
drawcircle(ctx, pos2, {...CONNECTED_1, strokeStyle:LGraphCanvas.link_type_colors[ue_connection.type]})
drawcircle(ctx, pos2, {...CONNECTED_2})
});
}
unconnected_connectable_names.forEach((name) => {
const index = node.inputs.findIndex((i) => i.name == name);
const pos2 = this._relative_connection_pos(node, true, index);
circle(ctx, pos2, {...UNCONNECTED_CONNECTABLE})
drawcircle(ctx, pos2, {...UNCONNECTED_CONNECTABLE})
})
if (node.properties.ue_convert) {
@@ -225,15 +225,35 @@ export class LinkRenderController extends Pausable {
if (is_able_to_broadcast(node, output.name)) {
const pos2 = this._relative_connection_pos(node, false, i);
if (sending_slots.has(i)) {
circle(ctx, pos2, {...CONNECTED_1, strokeStyle:LGraphCanvas.link_type_colors[node.outputs[i].type]})
circle(ctx, pos2, {...CONNECTED_2})
drawcircle(ctx, pos2, {...CONNECTED_1, strokeStyle:LGraphCanvas.link_type_colors[node.outputs[i].type]})
drawcircle(ctx, pos2, {...CONNECTED_2})
} else {
circle(ctx, pos2, {...UNCONNECTED_CONNECTABLE})
drawcircle(ctx, pos2, {...UNCONNECTED_CONNECTABLE})
}
}
})
}
/*
name : display_name of node
id : node.id
input : input.name
matches : [
{
type : m[i].controller.type,
id : m[i].controller.id,
index : m[i].control_node_input_index
}
]
*/
shared.graphAnalyser.ambiguities.filter((ambiguity)=>(ambiguity.id==node.id)).forEach((ambiguity)=>{
const index = node.inputs.findIndex((input)=>(input.name==ambiguity.input))
if (index>=0) {
const pos2 = this._relative_connection_pos(node, true, index);
drawcross(ctx, pos2, {...AMBIGUITY})
}
})
} catch (e) {
Logger.log_error(e);
} finally {
@@ -405,6 +425,7 @@ export class LinkRenderController extends Pausable {
}
const UNCONNECTED_CONNECTABLE = {
lineWidth : 1,
radius : 3,
strokeStyle : "black",
shadowColor : "green",
@@ -414,23 +435,30 @@ const UNCONNECTED_CONNECTABLE = {
}
const CONNECTED_1 = {
radius:5,
first_last:"first",
lineWidth:1,
shadowColor : "white",
shadowBlur : 10,
radius : 5,
first_last : "first",
lineWidth : 1,
shadowColor : "white",
shadowBlur : 10,
shadowOffsetX : 0,
shadowOffsetY : 0,
}
const CONNECTED_2 = {
radius:4,
first_last:"last",
shadowBlur : 0,
strokeStyle : "black",
lineWidth : 1,
radius : 4,
first_last : "last",
shadowBlur : 0,
strokeStyle : "black",
}
function circle(ctx, position, properties) {
const AMBIGUITY = {
lineWidth : 1,
radius : 7,
strokeStyle : "red",
}
function drawcircle(ctx, position, properties) {
const p = {...properties}
const radius = p.radius
@@ -440,13 +468,31 @@ function circle(ctx, position, properties) {
if (!first_last || first_last=='first') ctx.save()
Object.assign(ctx, p)
ctx.lineWidth = 1;
ctx.beginPath();
ctx.roundRect(position[0]-radius,position[1]-radius,2*radius,2*radius,radius);
ctx.stroke();
if (!first_last || first_last=='last') ctx.restore()
}
function drawcross(ctx, position, properties) {
const p = {...properties}
const radius = p.radius
const first_last = p.first_last
delete p.radius
delete p.first_last
if (!first_last || first_last=='first') ctx.save()
Object.assign(ctx, p)
ctx.beginPath();
ctx.moveTo(position[0]-radius,position[1]-radius)
ctx.lineTo(position[0]+radius,position[1]+radius)
ctx.moveTo(position[0]-radius,position[1]+radius)
ctx.lineTo(position[0]+radius,position[1]-radius)
ctx.stroke();
if (!first_last || first_last=='last') ctx.restore()
}
function modify(c) {
if (c.length==4) return c + "6"
if (c.length==7) return c + "66"
-27
View File
@@ -291,33 +291,6 @@ export function inject(object, methodname, tracetext, injection, injectionthis,
}
}
export function defineProperty(instance, property, desc) {
const existingDesc = Object.getOwnPropertyDescriptor(instance, property);
if (existingDesc?.configurable === false) {
throw new Error(`Error: Cannot define un-configurable property "${property}"`);
}
if (existingDesc?.get && desc.get) {
const descGet = desc.get;
desc.get = () => {
existingDesc.get.apply(instance, []);
return descGet.apply(instance, []);
};
}
if (existingDesc?.set && desc.set) {
const descSet = desc.set;
desc.set = (v) => {
existingDesc.set.apply(instance, [v]);
return descSet.apply(instance, [v]);
};
}
desc.enumerable = desc.enumerable ?? existingDesc?.enumerable ?? true;
desc.configurable = desc.configurable ?? existingDesc?.configurable ?? true;
if (!desc.get && !desc.set) {
desc.writable = desc.writable ?? existingDesc?.writable ?? true;
}
return Object.defineProperty(instance, property, desc);
}
export class Pausable {
constructor(name) {
this.name = name