From 3cbcce52777d9bf0cc01c26917564f6f4a56f4cd Mon Sep 17 00:00:00 2001 From: rgthree Date: Sun, 1 Oct 2023 22:12:58 -0400 Subject: [PATCH] Add some node config, starting with reroute node. Fixes #32 --- __init__.py | 22 +++++++++++++++++++++- rgthree_config.json.default | 12 ++++++++++-- ts/reroute.ts | 30 ++++++++++++++++++++++++++---- ts/utils.ts | 11 ++++++----- web/reroute.js | 30 +++++++++++++++++++++++++----- web/utils.js | 11 ++++++----- 6 files changed, 94 insertions(+), 22 deletions(-) diff --git a/__init__.py b/__init__.py index 317c3a8..91e604e 100644 --- a/__init__.py +++ b/__init__.py @@ -9,6 +9,7 @@ import glob import json import os import shutil +import re # from .server import server @@ -69,9 +70,28 @@ os.makedirs(DIR_WEB) shutil.copytree(DIR_DEV_WEB, DIR_WEB, dirs_exist_ok=True) +def extend_config(default_config, user_config): + cfg = {} + for key, value in default_config.items(): + if key not in user_config: + cfg[key] = value + elif isinstance(value, dict): + cfg[key] = extend_config(value, user_config[key]) + else: + cfg[key] = user_config[key] if key in user_config else value + return cfg + + +DEFAULT_CONFIG_FILE = os.path.join(THIS_DIR, 'rgthree_config.json.default') +with open(DEFAULT_CONFIG_FILE, 'r', encoding = 'UTF-8') as file: + config = re.sub(r"(?:^|\s)//.*", "", file.read(), flags=re.MULTILINE) + rgthree_config_default = json.loads(config) + CONFIG_FILE = os.path.join(THIS_DIR, 'rgthree_config.json') with open(CONFIG_FILE, 'r', encoding = 'UTF-8') as file: - rgthree_config = json.load(file) + rgthree_config_user = json.load(file) + +rgthree_config = extend_config(rgthree_config_default, rgthree_config_user) with open(os.path.join(DIR_WEB, 'rgthree_config.js'), 'w', encoding = 'UTF-8') as file: file.write('export const rgthreeConfig = ' + json.dumps(rgthree_config)) diff --git a/rgthree_config.json.default b/rgthree_config.json.default index e630f42..c2d7137 100644 --- a/rgthree_config.json.default +++ b/rgthree_config.json.default @@ -1,5 +1,13 @@ +// COPY THIS FILE BEFORE MAKING CHANGES TO: rgthree_config.json { "patch_recursive_execution": true, - "monitor_bad_links": false + "monitor_bad_links": false, + "nodes": { + "reroute": { + "default_width": 40, + "default_height": 30, + "default_resizable": false, + "default_layout": ["Left", "Right"] + } + } } - diff --git a/ts/reroute.ts b/ts/reroute.ts index 6e2c156..2b8d6b4 100644 --- a/ts/reroute.ts +++ b/ts/reroute.ts @@ -1,6 +1,8 @@ // / // @ts-ignore import { app } from "../../scripts/app.js"; +// @ts-ignore +import {rgthreeConfig} from "./rgthree_config.js"; import { rgthree } from "./rgthree.js"; import type { Vector2, @@ -15,6 +17,8 @@ import type { } from "./typings/litegraph.js"; import { LAYOUT_CLOCKWISE, + LAYOUT_LABEL_OPPOSITES, + LAYOUT_LABEL_TO_DATA, addConnectionLayoutSupport, addMenuItem, getSlotLinks, @@ -25,6 +29,22 @@ declare const LiteGraph: typeof TLiteGraph; declare const LGraphNode: typeof TLGraphNode; declare const LGraphCanvas: typeof TLGraphCanvas; +const rerouteConfig = rgthreeConfig?.['nodes']?.['reroute'] || {}; +let configWidth = Math.round((Number(rerouteConfig['default_width']) || 40) / 10) * 10; +let configHeight = Math.round((Number(rerouteConfig['default_height']) || 30) / 10) * 10; +const configDefaultSize = [configWidth, configHeight] as Vector2; +const configResizable = !!rerouteConfig['default_resizable']; +let configLayout: [string, string] = rerouteConfig['default_layout']; +if (!Array.isArray(configLayout)) { + configLayout = ['Left', 'Right']; +} +if (!LAYOUT_LABEL_TO_DATA[configLayout[0]]) { + configLayout[0] = 'Left'; +} +if (!LAYOUT_LABEL_TO_DATA[configLayout[1]] || configLayout[0] == configLayout[1]) { + configLayout[1] = LAYOUT_LABEL_OPPOSITES[configLayout[0]]!; +} + app.registerExtension({ name: "rgthree.Reroute", registerCustomNodes() { @@ -38,7 +58,7 @@ app.registerExtension({ static readonly title_mode = LiteGraph.NO_TITLE; static collapsable = false; static layout_slot_offset = 5; - static size: Vector2 = [40, 30]; // Starting size, read from within litegraph.core + static size: Vector2 = configDefaultSize; // Starting size, read from within litegraph.core readonly isVirtualNode?: boolean; readonly hideSlotLabels: boolean; @@ -46,11 +66,13 @@ app.registerExtension({ private configuring = true; private schedulePromise: Promise | null = null; + defaultConnectionsLayout = configLayout; + constructor(title = RerouteNode.title) { super(title); this.isVirtualNode = true; this.hideSlotLabels = true; - this.setResizable(this.properties['resizable']); + this.setResizable(this.properties['resizable'] ?? configResizable); this.size = RerouteNode.size; // Starting size. this.addInput("", "*"); this.addOutput("", "*"); @@ -60,7 +82,7 @@ app.registerExtension({ override configure(info: SerializedLGraphNode) { this.configuring = true; super.configure(info); - this.setResizable(this.properties['resizable']); + this.setResizable(this.properties['resizable'] ?? configResizable); this.applyNodeSize(); this.configuring = false; } @@ -407,7 +429,7 @@ app.registerExtension({ const h = node.size[1]; node.properties["connections_layout"] = node.properties[ "connections_layout" - ] || ["Left", "Right"]; + ] || this.defaultConnectionsLayout; const inputDirIndex = LAYOUT_CLOCKWISE.indexOf( node.properties["connections_layout"][0], ); diff --git a/ts/utils.ts b/ts/utils.ts index 910f2f7..c37ab81 100644 --- a/ts/utils.ts +++ b/ts/utils.ts @@ -51,7 +51,7 @@ export const LAYOUT_LABEL_TO_DATA: { [label: string]: [LiteGraphDir, Vector2, Ve Top: [LiteGraph.UP, [0.5, 0], [0, PADDING]], Bottom: [LiteGraph.DOWN, [0.5, 1], [0, -PADDING]], }; -const OPPOSITE_LABEL: { [label: string]: string } = { +export const LAYOUT_LABEL_OPPOSITES: { [label: string]: string } = { Left: "Right", Right: "Left", Top: "Bottom", @@ -157,7 +157,7 @@ export function addConnectionLayoutSupport( prepareValue: (value, node) => { const values = value.split(" -> "); if (!values[1] && !node.outputs?.length) { - values[1] = OPPOSITE_LABEL[values[0]!]!; + values[1] = LAYOUT_LABEL_OPPOSITES[values[0]!]!; } if (!LAYOUT_LABEL_TO_DATA[values[0]!] || !LAYOUT_LABEL_TO_DATA[values[1]!]) { throw new Error(`New Layout invalid: [${values[0]}, ${values[1]}]`); @@ -180,12 +180,13 @@ export function addConnectionLayoutSupport( export function setConnectionsLayout( node: TLGraphNode, - newLayout: [string, string] = ["Left", "Right"], + newLayout: [string, string], ) { + newLayout = newLayout || (node as any).defaultConnectionsLayout || ["Left", "Right"]; // If we didn't supply an output layout, and there's no outputs, then just choose the opposite of the // input as a safety. if (!newLayout[1] && !node.outputs?.length) { - newLayout[1] = OPPOSITE_LABEL[newLayout[0]!]!; + newLayout[1] = LAYOUT_LABEL_OPPOSITES[newLayout[0]!]!; } if (!LAYOUT_LABEL_TO_DATA[newLayout[0]] || !LAYOUT_LABEL_TO_DATA[newLayout[1]]) { throw new Error(`New Layout invalid: [${newLayout[0]}, ${newLayout[1]}]`); @@ -213,7 +214,7 @@ export function getConnectionPosForLayout( ) { out = out || new Float32Array(2); node.properties = node.properties || {}; - const layout = node.properties["connections_layout"] || ["Left", "Right"]; + const layout = node.properties["connections_layout"] || (node as any).defaultConnectionsLayout || ["Left", "Right"]; const collapseConnections = node.properties["collapse_connections"] || false; const offset = (node.constructor as any).layout_slot_offset ?? LiteGraph.NODE_SLOT_HEIGHT * 0.5; let side = isInput ? layout[0] : layout[1]; diff --git a/web/reroute.js b/web/reroute.js index 859f8bd..4a7a71c 100644 --- a/web/reroute.js +++ b/web/reroute.js @@ -1,26 +1,46 @@ +var _a; import { app } from "../../scripts/app.js"; +import { rgthreeConfig } from "./rgthree_config.js"; import { rgthree } from "./rgthree.js"; -import { LAYOUT_CLOCKWISE, addConnectionLayoutSupport, addMenuItem, getSlotLinks, wait, } from "./utils.js"; +import { LAYOUT_CLOCKWISE, LAYOUT_LABEL_OPPOSITES, LAYOUT_LABEL_TO_DATA, addConnectionLayoutSupport, addMenuItem, getSlotLinks, wait, } from "./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.round((Number(rerouteConfig['default_width']) || 40) / 10) * 10; +let configHeight = Math.round((Number(rerouteConfig['default_height']) || 30) / 10) * 10; +const configDefaultSize = [configWidth, configHeight]; +const configResizable = !!rerouteConfig['default_resizable']; +let configLayout = rerouteConfig['default_layout']; +if (!Array.isArray(configLayout)) { + configLayout = ['Left', 'Right']; +} +if (!LAYOUT_LABEL_TO_DATA[configLayout[0]]) { + configLayout[0] = 'Left'; +} +if (!LAYOUT_LABEL_TO_DATA[configLayout[1]] || configLayout[0] == configLayout[1]) { + configLayout[1] = LAYOUT_LABEL_OPPOSITES[configLayout[0]]; +} app.registerExtension({ name: "rgthree.Reroute", registerCustomNodes() { class RerouteNode extends LGraphNode { constructor(title = RerouteNode.title) { + var _a; super(title); this.configuring = true; this.schedulePromise = null; + this.defaultConnectionsLayout = configLayout; this.isVirtualNode = true; this.hideSlotLabels = true; - this.setResizable(this.properties['resizable']); + this.setResizable((_a = this.properties['resizable']) !== null && _a !== void 0 ? _a : configResizable); this.size = RerouteNode.size; this.addInput("", "*"); this.addOutput("", "*"); setTimeout(() => this.applyNodeSize(), 20); } configure(info) { + var _a; this.configuring = true; super.configure(info); - this.setResizable(this.properties['resizable']); + this.setResizable((_a = this.properties['resizable']) !== null && _a !== void 0 ? _a : configResizable); this.applyNodeSize(); this.configuring = false; } @@ -234,7 +254,7 @@ app.registerExtension({ RerouteNode.title_mode = LiteGraph.NO_TITLE; RerouteNode.collapsable = false; RerouteNode.layout_slot_offset = 5; - RerouteNode.size = [40, 30]; + RerouteNode.size = configDefaultSize; addMenuItem(RerouteNode, app, { name: (node) => { var _a; return `${((_a = node.properties) === null || _a === void 0 ? void 0 : _a['showLabel']) ? "Hide" : "Show"} Label/Title`; }, property: 'showLabel', @@ -312,7 +332,7 @@ app.registerExtension({ callback: (node, value) => { const w = node.size[0]; const h = node.size[1]; - node.properties["connections_layout"] = node.properties["connections_layout"] || ["Left", "Right"]; + node.properties["connections_layout"] = node.properties["connections_layout"] || this.defaultConnectionsLayout; const inputDirIndex = LAYOUT_CLOCKWISE.indexOf(node.properties["connections_layout"][0]); const outputDirIndex = LAYOUT_CLOCKWISE.indexOf(node.properties["connections_layout"][1]); if (value === null || value === void 0 ? void 0 : value.startsWith("Rotate 90°")) { diff --git a/web/utils.js b/web/utils.js index c5a1dfc..f379403 100644 --- a/web/utils.js +++ b/web/utils.js @@ -18,7 +18,7 @@ export const LAYOUT_LABEL_TO_DATA = { Top: [LiteGraph.UP, [0.5, 0], [0, PADDING]], Bottom: [LiteGraph.DOWN, [0.5, 1], [0, -PADDING]], }; -const OPPOSITE_LABEL = { +export const LAYOUT_LABEL_OPPOSITES = { Left: "Right", Right: "Left", Top: "Bottom", @@ -89,7 +89,7 @@ export function addConnectionLayoutSupport(node, app, options = [ var _a; const values = value.split(" -> "); if (!values[1] && !((_a = node.outputs) === null || _a === void 0 ? void 0 : _a.length)) { - values[1] = OPPOSITE_LABEL[values[0]]; + values[1] = LAYOUT_LABEL_OPPOSITES[values[0]]; } if (!LAYOUT_LABEL_TO_DATA[values[0]] || !LAYOUT_LABEL_TO_DATA[values[1]]) { throw new Error(`New Layout invalid: [${values[0]}, ${values[1]}]`); @@ -105,10 +105,11 @@ export function addConnectionLayoutSupport(node, app, options = [ return getConnectionPosForLayout(this, isInput, slotNumber, out); }; } -export function setConnectionsLayout(node, newLayout = ["Left", "Right"]) { +export function setConnectionsLayout(node, newLayout) { var _a; + newLayout = newLayout || node.defaultConnectionsLayout || ["Left", "Right"]; if (!newLayout[1] && !((_a = node.outputs) === null || _a === void 0 ? void 0 : _a.length)) { - newLayout[1] = OPPOSITE_LABEL[newLayout[0]]; + newLayout[1] = LAYOUT_LABEL_OPPOSITES[newLayout[0]]; } if (!LAYOUT_LABEL_TO_DATA[newLayout[0]] || !LAYOUT_LABEL_TO_DATA[newLayout[1]]) { throw new Error(`New Layout invalid: [${newLayout[0]}, ${newLayout[1]}]`); @@ -126,7 +127,7 @@ export function getConnectionPosForLayout(node, isInput, slotNumber, out) { var _a, _b, _c; out = out || new Float32Array(2); node.properties = node.properties || {}; - const layout = node.properties["connections_layout"] || ["Left", "Right"]; + const layout = node.properties["connections_layout"] || node.defaultConnectionsLayout || ["Left", "Right"]; const collapseConnections = node.properties["collapse_connections"] || false; const offset = (_a = node.constructor.layout_slot_offset) !== null && _a !== void 0 ? _a : LiteGraph.NODE_SLOT_HEIGHT * 0.5; let side = isInput ? layout[0] : layout[1];