Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Includes 30 custom nodes committed directly, 7 Civitai-exclusive loras stored via Git LFS, and a setup script that installs all dependencies and downloads HuggingFace-hosted models on vast.ai. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
163
custom_nodes/rgthree-comfy/src_web/comfyui/bookmark.ts
Normal file
163
custom_nodes/rgthree-comfy/src_web/comfyui/bookmark.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import type {
|
||||
LGraph,
|
||||
LGraphCanvas,
|
||||
LGraphNode,
|
||||
Point,
|
||||
CanvasMouseEvent,
|
||||
Subgraph,
|
||||
} from "@comfyorg/frontend";
|
||||
|
||||
import {app} from "scripts/app.js";
|
||||
import {RgthreeBaseVirtualNode} from "./base_node.js";
|
||||
import {SERVICE as KEY_EVENT_SERVICE} from "./services/key_events_services.js";
|
||||
import {SERVICE as BOOKMARKS_SERVICE} from "./services/bookmarks_services.js";
|
||||
import {NodeTypesString} from "./constants.js";
|
||||
import {getClosestOrSelf, query} from "rgthree/common/utils_dom.js";
|
||||
import {wait} from "rgthree/common/shared_utils.js";
|
||||
import {findFromNodeForSubgraph} from "./utils.js";
|
||||
|
||||
/**
|
||||
* A bookmark node. Can be placed anywhere in the workflow, and given a shortcut key that will
|
||||
* navigate to that node, with it in the top-left corner.
|
||||
*/
|
||||
export class Bookmark extends RgthreeBaseVirtualNode {
|
||||
static override type = NodeTypesString.BOOKMARK;
|
||||
static override title = NodeTypesString.BOOKMARK;
|
||||
override comfyClass = NodeTypesString.BOOKMARK;
|
||||
|
||||
// Really silly, but Litegraph assumes we have at least one input/output... so we need to
|
||||
// counteract it's computeSize calculation by offsetting the start.
|
||||
static slot_start_y = -20;
|
||||
|
||||
// LiteGraph adds mroe spacing than we want when calculating a nodes' `_collapsed_width`, so we'll
|
||||
// override it with a setter and re-set it measured exactly as we want.
|
||||
___collapsed_width: number = 0;
|
||||
|
||||
override isVirtualNode = true;
|
||||
override serialize_widgets = true;
|
||||
|
||||
//@ts-ignore - TS Doesn't like us overriding a property with accessors but, too bad.
|
||||
override get _collapsed_width() {
|
||||
return this.___collapsed_width;
|
||||
}
|
||||
|
||||
override set _collapsed_width(width: number) {
|
||||
const canvas = app.canvas as LGraphCanvas;
|
||||
const ctx = canvas.canvas.getContext("2d")!;
|
||||
const oldFont = ctx.font;
|
||||
ctx.font = canvas.title_text_font;
|
||||
this.___collapsed_width = 40 + ctx.measureText(this.title).width;
|
||||
ctx.font = oldFont;
|
||||
}
|
||||
|
||||
readonly keypressBound;
|
||||
|
||||
constructor(title = Bookmark.title) {
|
||||
super(title);
|
||||
const nextShortcutChar = BOOKMARKS_SERVICE.getNextShortcut();
|
||||
this.addWidget(
|
||||
"text",
|
||||
"shortcut_key",
|
||||
nextShortcutChar,
|
||||
(value: string, ...args) => {
|
||||
value = value.trim()[0] || "1";
|
||||
},
|
||||
{
|
||||
y: 8,
|
||||
},
|
||||
);
|
||||
this.addWidget("number", "zoom", 1, (value: number) => {}, {
|
||||
y: 8 + LiteGraph.NODE_WIDGET_HEIGHT + 4,
|
||||
max: 2,
|
||||
min: 0.5,
|
||||
precision: 2,
|
||||
});
|
||||
this.keypressBound = this.onKeypress.bind(this);
|
||||
this.title = "🔖";
|
||||
this.onConstructed();
|
||||
}
|
||||
|
||||
// override computeSize(out?: Vector2 | undefined): Vector2 {
|
||||
// super.computeSize(out);
|
||||
// const minHeight = (this.widgets?.length || 0) * (LiteGraph.NODE_WIDGET_HEIGHT + 4) + 16;
|
||||
// this.size[1] = Math.max(minHeight, this.size[1]);
|
||||
// }
|
||||
|
||||
get shortcutKey(): string {
|
||||
return (this.widgets[0]?.value as string)?.toLocaleLowerCase() ?? "";
|
||||
}
|
||||
|
||||
override onAdded(graph: LGraph): void {
|
||||
KEY_EVENT_SERVICE.addEventListener("keydown", this.keypressBound as EventListener);
|
||||
}
|
||||
|
||||
override onRemoved(): void {
|
||||
KEY_EVENT_SERVICE.removeEventListener("keydown", this.keypressBound as EventListener);
|
||||
}
|
||||
|
||||
onKeypress(event: CustomEvent<{originalEvent: KeyboardEvent}>) {
|
||||
const originalEvent = event.detail.originalEvent;
|
||||
const target = (originalEvent.target as HTMLElement)!;
|
||||
if (getClosestOrSelf(target, 'input,textarea,[contenteditable="true"]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only the shortcut keys are held down, optionally including "shift".
|
||||
if (KEY_EVENT_SERVICE.areOnlyKeysDown(this.widgets[0]!.value as string, true)) {
|
||||
this.canvasToBookmark();
|
||||
originalEvent.preventDefault();
|
||||
originalEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from LiteGraph's `processMouseDown` after it would invoke the input box for the
|
||||
* shortcut_key, so we check if it exists and then add our own event listener so we can track the
|
||||
* keys down for the user. Note, blocks drag if the return is truthy.
|
||||
*/
|
||||
override onMouseDown(event: CanvasMouseEvent, pos: Point, graphCanvas: LGraphCanvas): boolean {
|
||||
const input = query<HTMLInputElement>(".graphdialog > input.value");
|
||||
if (input && input.value === this.widgets[0]?.value) {
|
||||
input.addEventListener("keydown", (e) => {
|
||||
// ComfyUI swallows keydown on inputs, so we need to call out to rgthree to use downkeys.
|
||||
KEY_EVENT_SERVICE.handleKeyDownOrUp(e);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
input.value = Object.keys(KEY_EVENT_SERVICE.downKeys).join(" + ");
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async canvasToBookmark() {
|
||||
const canvas = app.canvas as LGraphCanvas;
|
||||
if (this.graph !== app.canvas.getCurrentGraph()) {
|
||||
const subgraph = this.graph as Subgraph;
|
||||
// At some point, ComfyUI made a second param for openSubgraph which appears to be the node
|
||||
// that id double-clicked on to open the subgraph. We don't have that in the bookmark, so
|
||||
// we'll look for it. Note, that when opening the root graph, this will be null (since there's
|
||||
// no such node). It seems to still navigate fine, though there's a console error about
|
||||
// proxyWidgets or something..
|
||||
const fromNode = findFromNodeForSubgraph(subgraph.id);
|
||||
canvas.openSubgraph(subgraph, fromNode!);
|
||||
await wait(16);
|
||||
}
|
||||
// ComfyUI seemed to break us again, but couldn't repro. No reason to not check, I guess.
|
||||
// https://github.com/rgthree/rgthree-comfy/issues/71
|
||||
if (canvas?.ds?.offset) {
|
||||
canvas.ds.offset[0] = -this.pos[0] + 16;
|
||||
canvas.ds.offset[1] = -this.pos[1] + 40;
|
||||
}
|
||||
if (canvas?.ds?.scale != null) {
|
||||
canvas.ds.scale = Number(this.widgets[1]!.value || 1);
|
||||
}
|
||||
canvas.setDirty(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: "rgthree.Bookmark",
|
||||
registerCustomNodes() {
|
||||
Bookmark.setUp();
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user