diff --git a/js/ue_debug.js b/js/ue_debug.js deleted file mode 100644 index 588af86..0000000 --- a/js/ue_debug.js +++ /dev/null @@ -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 \ No newline at end of file diff --git a/js/use_everywhere.js b/js/use_everywhere.js index b359472..c9a9486 100644 --- a/js/use_everywhere.js +++ b/js/use_everywhere.js @@ -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 diff --git a/js/use_everywhere_classes.js b/js/use_everywhere_classes.js index 1134430..a38fdec 100644 --- a/js/use_everywhere_classes.js +++ b/js/use_everywhere_classes.js @@ -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(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; } } diff --git a/js/use_everywhere_graph_analysis.js b/js/use_everywhere_graph_analysis.js index 8828c55..9037e97 100644 --- a/js/use_everywhere_graph_analysis.js +++ b/js/use_everywhere_graph_analysis.js @@ -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; diff --git a/js/use_everywhere_settings.js b/js/use_everywhere_settings.js index 3e71632..5c9ff92 100644 --- a/js/use_everywhere_settings.js +++ b/js/use_everywhere_settings.js @@ -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")) } }) } diff --git a/js/use_everywhere_ui.js b/js/use_everywhere_ui.js index 12bc28d..5179163 100644 --- a/js/use_everywhere_ui.js +++ b/js/use_everywhere_ui.js @@ -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" diff --git a/js/use_everywhere_utilities.js b/js/use_everywhere_utilities.js index 771b23f..fa6354e 100644 --- a/js/use_everywhere_utilities.js +++ b/js/use_everywhere_utilities.js @@ -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