A bunch of util changes as building out dynamic context.

This commit is contained in:
rgthree
2023-11-19 00:11:05 -05:00
parent 633d6ba8fb
commit bbb5c5ed4d
7 changed files with 114 additions and 83 deletions
+3 -1
View File
@@ -1,3 +1,5 @@
{
"printWidth": 100
"printWidth": 100,
"bracketSpacing": false,
"bracketSameLine": true
}
+30 -20
View File
@@ -21,6 +21,7 @@ import {
LAYOUT_LABEL_TO_DATA,
addConnectionLayoutSupport,
addMenuItem,
getConnectedOutputNodesAndFilterPassThroughs,
getSlotLinks,
isValidConnection,
} from "./utils.js";
@@ -71,7 +72,6 @@ app.registerExtension({
readonly hideSlotLabels: boolean;
private configuring = true;
private schedulePromise: Promise<void> | null = null;
defaultConnectionsLayout = configLayout;
@@ -137,7 +137,26 @@ app.registerExtension({
}
}
}
this.scheduleStabilize();
if (this.configuring) {
return;
}
this.stabilize();
if (type === LiteGraph.INPUT) {
this.updateDownstream(connected ? 'connect' : 'disconnect', {index: 0, name: this.inputs[0]!.name});
}
}
/**
* Updates connected nodes of a change (checking and calling updateFromUpstream). Used for Dynamic Context.
*/
private updateDownstream(
update: "connect" | "disconnect" | "move" | "update",
updatedIndexes: {index: number; name: string; from?: number},
) {
const nodes = getConnectedOutputNodesAndFilterPassThroughs(this, this, 0);
for (const node of nodes) {
(node as any)?.updateFromUpstream?.(update, this, updatedIndexes);
}
}
override onDrawForeground(ctx: CanvasRenderingContext2D, canvas: TLGraphCanvas): void {
@@ -161,20 +180,6 @@ app.registerExtension({
return super.disconnectOutput(slot, targetNode);
}
scheduleStabilize(ms = 64) {
if (!this.schedulePromise) {
this.schedulePromise = new Promise((resolve) => {
setTimeout(() => {
this.schedulePromise = null
this.stabilize();
resolve();
}, ms);
});
}
return this.schedulePromise;
}
stabilize() {
// If we are currently "configuring" then skip this stabilization. The connected nodes may
// not yet be configured.
@@ -229,7 +234,7 @@ app.registerExtension({
// Find all outputs
const nodes: TLGraphNode[] = [this];
let outputNode = null;
let outputNodes: TLGraphNode[] = [];
let outputType = null;
while (nodes.length) {
currentNode = nodes.pop()!;
@@ -266,8 +271,11 @@ app.registerExtension({
console.warn(`[rgthree] Reroute - Disconnecting connected node's input (${node.id}.${link.target_slot}) (${node.type}) because its type (${String(nodeOutType)}) does not match the reroute type (${String(inputType)})`);
node.disconnectInput(link.target_slot);
} else {
if (outputType != null && outputType !== nodeOutType) {
console.warn(`[rgthree] Reroute - Mismatching output types..`);
}
outputType = nodeOutType;
outputNode = node;
outputNodes.push(node);
}
}
}
@@ -306,8 +314,10 @@ app.registerExtension({
}
}
}
(inputNode as any)?.onConnectionsChainChange?.();
(outputNode as any)?.onConnectionsChainChange?.();
// (inputNode as any)?.onConnectionsChainChange?.(this);
// for (const outputNode of outputNodes) {
// (outputNode as any)?.onConnectionsChainChange?.(this);
// }
app.graph.setDirtyCanvas(true, true);
}
+3 -3
View File
@@ -77,7 +77,7 @@ class LogSession {
export type RgthreeUiMessage = {
id: string;
message: string;
type?: 'warn'|null;
type?: 'warn'|'info'|null;
timeout?: number;
// closeable?: boolean; // TODO
actions?: Array<{
@@ -305,8 +305,8 @@ class Rgthree {
fireEvent(event: string, data: any) {
if (this.eventsToFns.has(event)) {
for (let fn of this.eventsToFns.get(event)!) {
const event = new Event(data);
fn(event);
const e = new CustomEvent(event, {detail:data});
fn(e);
}
}
}
+30 -19
View File
@@ -400,7 +400,7 @@ export function getConnectedInputNodes(
slot?: number,
passThroughFollowing = PassThroughFollowing.ALL,
) : TLGraphNode[] {
return getConnectedNodes(startNode, IoDirection.INPUT, currentNode, slot, passThroughFollowing).map(n => n.node);
return getConnectedNodesInfo(startNode, IoDirection.INPUT, currentNode, slot, passThroughFollowing).map(n => n.node);
}
export function getConnectedInputNodesAndFilterPassThroughs(
startNode: TLGraphNode,
@@ -413,14 +413,16 @@ export function getConnectedInputNodesAndFilterPassThroughs(
passThroughFollowing,
);
}
export function getConnectedOutputNodes(
startNode: TLGraphNode,
currentNode?: TLGraphNode,
slot?: number,
passThroughFollowing = PassThroughFollowing.ALL,
) : TLGraphNode[] {
return getConnectedNodes(startNode, IoDirection.OUTPUT, currentNode, slot, passThroughFollowing).map(n => n.node);
return getConnectedNodesInfo(startNode, IoDirection.OUTPUT, currentNode, slot, passThroughFollowing).map(n => n.node);
}
export function getConnectedOutputNodesAndFilterPassThroughs(
startNode: TLGraphNode,
currentNode?: TLGraphNode,
@@ -434,39 +436,48 @@ export function getConnectedOutputNodesAndFilterPassThroughs(
}
export function getConnectedNodes(
export type ConnectedNodeInfo = {node: TLGraphNode, travelFromSlot: number, travelToSlot: number, originTravelFromSlot: number};
export function getConnectedNodesInfo(
startNode: TLGraphNode,
dir = IoDirection.INPUT,
currentNode?: TLGraphNode,
slot?: number,
passThroughFollowing = PassThroughFollowing.ALL,
) : {node:TLGraphNode, slot: number}[] {
originTravelFromSlot?: number
) : ConnectedNodeInfo[] {
currentNode = currentNode || startNode;
let rootNodes: {node:TLGraphNode, slot: number}[] = [];
let rootNodes: ConnectedNodeInfo[] = [];
const slotsToRemove = [];
if (startNode === currentNode || shouldPassThrough(currentNode, passThroughFollowing)) {
// const removeDups = startNode === currentNode;
let linkIds: Array<number | null>;
if (dir == IoDirection.OUTPUT) {
linkIds = currentNode.outputs?.flatMap((i) => i.links) || [];
} else {
linkIds = currentNode.inputs?.map((i) => i.link) || [];
}
if (typeof slot == "number" && slot > -1) {
if (linkIds[slot]) {
linkIds = [linkIds[slot]!];
if (slot != null && slot > -1) {
linkIds = currentNode.outputs[slot]?.links ?? [];
} else {
return [];
linkIds = currentNode.outputs?.flatMap((i) => i.links) || [];
}
} else {
if (slot != null && slot > -1) {
linkIds = [currentNode.inputs[slot]?.link ?? -1].filter(i => i > -1);
} else {
linkIds = currentNode.inputs?.map((i) => i.link) || [];
}
}
let graph = app.graph as LGraph;
for (const linkId of linkIds) {
const link: LLink = (linkId != null && graph.links[linkId]) as LLink;
let link: LLink | null = null;
if (typeof linkId == "number") {
link = graph.links[linkId] as LLink;
}
if (!link) {
continue;
}
const travelFromSlot = dir == IoDirection.OUTPUT ? link.origin_slot : link.target_slot;
const connectedId = dir == IoDirection.OUTPUT ? link.target_id : link.origin_id;
const originSlot = dir == IoDirection.OUTPUT ? link.target_slot : link.origin_slot;
const travelToSlot = dir == IoDirection.OUTPUT ? link.target_slot : link.origin_slot;
originTravelFromSlot = originTravelFromSlot != null ? originTravelFromSlot : travelFromSlot;
const originNode: TLGraphNode = graph.getNodeById(connectedId)!;
if (!link) {
console.error("No connected node found... weird");
@@ -480,10 +491,10 @@ export function getConnectedNodes(
);
} else {
// Add the node and, if it's a pass through, let's collect all its nodes as well.
rootNodes.push({node: originNode, slot: originSlot});
rootNodes.push({node: originNode, travelFromSlot, travelToSlot, originTravelFromSlot});
if (shouldPassThrough(originNode, passThroughFollowing)) {
for (const foundNode of getConnectedNodes(startNode, dir, originNode)) {
if (!rootNodes.includes(foundNode)) {
for (const foundNode of getConnectedNodesInfo(startNode, dir, originNode, undefined, undefined, originTravelFromSlot)) {
if (!rootNodes.map(n => n.node).includes(foundNode.node)) {
rootNodes.push(foundNode);
}
}
+21 -20
View File
@@ -2,7 +2,7 @@ var _a;
import { app } from "../../scripts/app.js";
import { rgthreeConfig } from "./rgthree_config.js";
import { rgthree } from "./rgthree.js";
import { LAYOUT_CLOCKWISE, LAYOUT_LABEL_OPPOSITES, LAYOUT_LABEL_TO_DATA, addConnectionLayoutSupport, addMenuItem, getSlotLinks, isValidConnection, } from "./utils.js";
import { LAYOUT_CLOCKWISE, LAYOUT_LABEL_OPPOSITES, LAYOUT_LABEL_TO_DATA, addConnectionLayoutSupport, addMenuItem, getConnectedOutputNodesAndFilterPassThroughs, getSlotLinks, isValidConnection, } from "./utils.js";
import { wait } from "./shared_utils.js";
const rerouteConfig = ((_a = rgthreeConfig === null || rgthreeConfig === void 0 ? void 0 : rgthreeConfig['nodes']) === null || _a === void 0 ? void 0 : _a['reroute']) || {};
let configWidth = Math.max(Math.round((Number(rerouteConfig['default_width']) || 40) / 10) * 10, 10);
@@ -31,7 +31,6 @@ app.registerExtension({
var _a;
super(title);
this.configuring = true;
this.schedulePromise = null;
this.defaultConnectionsLayout = configLayout;
this.isVirtualNode = true;
this.hideSlotLabels = true;
@@ -75,7 +74,20 @@ app.registerExtension({
}
}
}
this.scheduleStabilize();
if (this.configuring) {
return;
}
this.stabilize();
if (type === LiteGraph.INPUT) {
this.updateDownstream(connected ? 'connect' : 'disconnect', { index: 0, name: this.inputs[0].name });
}
}
updateDownstream(update, updatedIndexes) {
var _a;
const nodes = getConnectedOutputNodesAndFilterPassThroughs(this, this, 0);
for (const node of nodes) {
(_a = node === null || node === void 0 ? void 0 : node.updateFromUpstream) === null || _a === void 0 ? void 0 : _a.call(node, update, this, updatedIndexes);
}
}
onDrawForeground(ctx, canvas) {
var _a, _b, _c;
@@ -97,20 +109,8 @@ app.registerExtension({
disconnectOutput(slot, targetNode) {
return super.disconnectOutput(slot, targetNode);
}
scheduleStabilize(ms = 64) {
if (!this.schedulePromise) {
this.schedulePromise = new Promise((resolve) => {
setTimeout(() => {
this.schedulePromise = null;
this.stabilize();
resolve();
}, ms);
});
}
return this.schedulePromise;
}
stabilize() {
var _a, _b, _c, _d, _e, _f, _g, _h;
var _a, _b, _c, _d, _e, _f;
if (this.configuring) {
return;
}
@@ -155,7 +155,7 @@ app.registerExtension({
}
}
const nodes = [this];
let outputNode = null;
let outputNodes = [];
let outputType = null;
while (nodes.length) {
currentNode = nodes.pop();
@@ -187,8 +187,11 @@ app.registerExtension({
node.disconnectInput(link.target_slot);
}
else {
if (outputType != null && outputType !== nodeOutType) {
console.warn(`[rgthree] Reroute - Mismatching output types..`);
}
outputType = nodeOutType;
outputNode = node;
outputNodes.push(node);
}
}
}
@@ -220,8 +223,6 @@ app.registerExtension({
}
}
}
(_g = inputNode === null || inputNode === void 0 ? void 0 : inputNode.onConnectionsChainChange) === null || _g === void 0 ? void 0 : _g.call(inputNode);
(_h = outputNode === null || outputNode === void 0 ? void 0 : outputNode.onConnectionsChainChange) === null || _h === void 0 ? void 0 : _h.call(outputNode);
app.graph.setDirtyCanvas(true, true);
}
computeSize(out) {
+2 -2
View File
@@ -245,8 +245,8 @@ class Rgthree {
fireEvent(event, data) {
if (this.eventsToFns.has(event)) {
for (let fn of this.eventsToFns.get(event)) {
const event = new Event(data);
fn(event);
const e = new CustomEvent(event, { detail: data });
fn(e);
}
}
}
+25 -18
View File
@@ -275,46 +275,53 @@ export function filterOutPassthroughNodes(nodes, passThroughFollowing = PassThro
return nodes.filter((n) => !shouldPassThrough(n, passThroughFollowing));
}
export function getConnectedInputNodes(startNode, currentNode, slot, passThroughFollowing = PassThroughFollowing.ALL) {
return getConnectedNodes(startNode, IoDirection.INPUT, currentNode, slot, passThroughFollowing).map(n => n.node);
return getConnectedNodesInfo(startNode, IoDirection.INPUT, currentNode, slot, passThroughFollowing).map(n => n.node);
}
export function getConnectedInputNodesAndFilterPassThroughs(startNode, currentNode, slot, passThroughFollowing = PassThroughFollowing.ALL) {
return filterOutPassthroughNodes(getConnectedInputNodes(startNode, currentNode, slot, passThroughFollowing), passThroughFollowing);
}
export function getConnectedOutputNodes(startNode, currentNode, slot, passThroughFollowing = PassThroughFollowing.ALL) {
return getConnectedNodes(startNode, IoDirection.OUTPUT, currentNode, slot, passThroughFollowing).map(n => n.node);
return getConnectedNodesInfo(startNode, IoDirection.OUTPUT, currentNode, slot, passThroughFollowing).map(n => n.node);
}
export function getConnectedOutputNodesAndFilterPassThroughs(startNode, currentNode, slot, passThroughFollowing = PassThroughFollowing.ALL) {
return filterOutPassthroughNodes(getConnectedOutputNodes(startNode, currentNode, slot, passThroughFollowing), passThroughFollowing);
}
export function getConnectedNodes(startNode, dir = IoDirection.INPUT, currentNode, slot, passThroughFollowing = PassThroughFollowing.ALL) {
var _a, _b;
export function getConnectedNodesInfo(startNode, dir = IoDirection.INPUT, currentNode, slot, passThroughFollowing = PassThroughFollowing.ALL, originTravelFromSlot) {
var _a, _b, _c, _d, _e, _f;
currentNode = currentNode || startNode;
let rootNodes = [];
const slotsToRemove = [];
if (startNode === currentNode || shouldPassThrough(currentNode, passThroughFollowing)) {
let linkIds;
if (dir == IoDirection.OUTPUT) {
linkIds = ((_a = currentNode.outputs) === null || _a === void 0 ? void 0 : _a.flatMap((i) => i.links)) || [];
}
else {
linkIds = ((_b = currentNode.inputs) === null || _b === void 0 ? void 0 : _b.map((i) => i.link)) || [];
}
if (typeof slot == "number" && slot > -1) {
if (linkIds[slot]) {
linkIds = [linkIds[slot]];
if (slot != null && slot > -1) {
linkIds = (_b = (_a = currentNode.outputs[slot]) === null || _a === void 0 ? void 0 : _a.links) !== null && _b !== void 0 ? _b : [];
}
else {
return [];
linkIds = ((_c = currentNode.outputs) === null || _c === void 0 ? void 0 : _c.flatMap((i) => i.links)) || [];
}
}
else {
if (slot != null && slot > -1) {
linkIds = [(_e = (_d = currentNode.inputs[slot]) === null || _d === void 0 ? void 0 : _d.link) !== null && _e !== void 0 ? _e : -1].filter(i => i > -1);
}
else {
linkIds = ((_f = currentNode.inputs) === null || _f === void 0 ? void 0 : _f.map((i) => i.link)) || [];
}
}
let graph = app.graph;
for (const linkId of linkIds) {
const link = (linkId != null && graph.links[linkId]);
let link = null;
if (typeof linkId == "number") {
link = graph.links[linkId];
}
if (!link) {
continue;
}
const travelFromSlot = dir == IoDirection.OUTPUT ? link.origin_slot : link.target_slot;
const connectedId = dir == IoDirection.OUTPUT ? link.target_id : link.origin_id;
const originSlot = dir == IoDirection.OUTPUT ? link.target_slot : link.origin_slot;
const travelToSlot = dir == IoDirection.OUTPUT ? link.target_slot : link.origin_slot;
originTravelFromSlot = originTravelFromSlot != null ? originTravelFromSlot : travelFromSlot;
const originNode = graph.getNodeById(connectedId);
if (!link) {
console.error("No connected node found... weird");
@@ -324,10 +331,10 @@ export function getConnectedNodes(startNode, dir = IoDirection.INPUT, currentNod
console.log(`${startNode.title} (${startNode.id}) seems to have two links to ${originNode.title} (${originNode.id}). One may be stale: ${linkIds.join(", ")}`);
}
else {
rootNodes.push({ node: originNode, slot: originSlot });
rootNodes.push({ node: originNode, travelFromSlot, travelToSlot, originTravelFromSlot });
if (shouldPassThrough(originNode, passThroughFollowing)) {
for (const foundNode of getConnectedNodes(startNode, dir, originNode)) {
if (!rootNodes.includes(foundNode)) {
for (const foundNode of getConnectedNodesInfo(startNode, dir, originNode, undefined, undefined, originTravelFromSlot)) {
if (!rootNodes.map(n => n.node).includes(foundNode.node)) {
rootNodes.push(foundNode);
}
}