From b61ac28b2f64dc064fb40b1f2c6dd9d459cb1c4f Mon Sep 17 00:00:00 2001 From: DrJKL Date: Wed, 17 Apr 2024 15:03:51 -0700 Subject: [PATCH] Add bookmarks list menu. Also adds a label property to them. Think it's worth exposing it on hover as a pseudo-title? --- rgthree_config.json.default | 4 ++++ src_web/comfyui/bookmark.ts | 12 ++++++++++-- src_web/comfyui/config.ts | 14 ++++++++++++++ src_web/comfyui/rgthree.ts | 34 ++++++++++++++++++++++++++++++++++ web/comfyui/bookmark.js | 4 +++- web/comfyui/config.js | 13 +++++++++++++ web/comfyui/rgthree.js | 28 ++++++++++++++++++++++++++++ 7 files changed, 106 insertions(+), 3 deletions(-) diff --git a/rgthree_config.json.default b/rgthree_config.json.default index e56911b..3bd55f5 100644 --- a/rgthree_config.json.default +++ b/rgthree_config.json.default @@ -20,6 +20,10 @@ "height": 16, "position": "top" }, + "bookmark_menu": { + "enabled": true, + "labeled_only": false + }, // Enables invokeExtensionsAsync for rgthree-nodes allowing other extensions to hook into the // nodes like the default ComfyNodes. This was not possible before Apr 2024, so it's a config // entry in case it causes issues. This is only for the nodeCreated event/function as of now. diff --git a/src_web/comfyui/bookmark.ts b/src_web/comfyui/bookmark.ts index af5a935..5e8c1b6 100644 --- a/src_web/comfyui/bookmark.ts +++ b/src_web/comfyui/bookmark.ts @@ -14,6 +14,7 @@ import type { declare const LiteGraph: typeof TLiteGraph; +const PROPERTY_LABEL = "label"; /** * A bookmark node. Can be placed anywhere in the workflow, and given a shortcut key that will @@ -37,6 +38,8 @@ export class Bookmark extends RgthreeBaseVirtualNode { override isVirtualNode = true; override serialize_widgets = true; + static "@label" = { type: "string" }; + //@ts-ignore - TS Doesn't like us overriding a property with accessors but, too bad. override get _collapsed_width() { return this.___collapsed_width; @@ -55,6 +58,7 @@ export class Bookmark extends RgthreeBaseVirtualNode { constructor(title = Bookmark.title) { super(title); + this.properties[PROPERTY_LABEL] = ""; this.addWidget('text', 'shortcut_key', '1', (value: string, ...args) => { value = value.trim()[0] || '1'; },{ @@ -78,6 +82,9 @@ export class Bookmark extends RgthreeBaseVirtualNode { // this.size[1] = Math.max(minHeight, this.size[1]); // } + get shortcutKey(): string { + return this.widgets[0]?.value?.toLocaleLowerCase() ?? ''; + } override onAdded(graph: TLGraph): void { window.addEventListener("keydown", this.keypressBound); @@ -89,13 +96,14 @@ export class Bookmark extends RgthreeBaseVirtualNode { async onKeypress(event: KeyboardEvent) { const target = (event.target as HTMLElement)!; - if (['input','textarea'].includes(target.localName)) { + // Span because the properties panel uses a contenteditable + if (['input','textarea', 'span'].includes(target.localName)) { return; } if (event.ctrlKey || event.metaKey || event.altKey) { return; } - if (event.key.toLocaleLowerCase() === this.widgets[0]!.value.toLocaleLowerCase()) { + if (event.key.toLocaleLowerCase() === this.shortcutKey) { this.canvasToBookmark(); } } diff --git a/src_web/comfyui/config.ts b/src_web/comfyui/config.ts index 908b204..97a73c4 100644 --- a/src_web/comfyui/config.ts +++ b/src_web/comfyui/config.ts @@ -127,6 +127,20 @@ const CONFIGURABLE: { features: ConfigurationSchema[] } = { "Will show a message at the top of the screen when loading a workflow that has " + "corrupt linking data.", }, + { + key: "features.bookmark_menu.enabled", + type: ConfigType.BOOLEAN, + label: "Show bookmark shortcuts in context menu", + description: + "Will list the bookmarks in the rgthree-comfy context menu", + subconfig: [ + { + key: "features.bookmark_menu.labeled_only", + type: ConfigType.BOOLEAN, + label: "Only show explicitly labeled bookmarks (set in Properties)", + }, + ], + }, { key: "log_level", type: ConfigType.STRING, diff --git a/src_web/comfyui/rgthree.ts b/src_web/comfyui/rgthree.ts index 51688a7..ffa38e2 100644 --- a/src_web/comfyui/rgthree.ts +++ b/src_web/comfyui/rgthree.ts @@ -22,6 +22,7 @@ import { NodeTypesString } from "./constants.js"; import { RgthreeProgressBar } from "rgthree/common/progress_bar.js"; import { RgthreeConfigDialog } from "./config.js"; import { iconGear, iconReplace, iconStarFilled, logoRgthree } from "rgthree/common/media/svgs.js"; +import type { Bookmark } from './bookmark'; declare const LiteGraph: typeof TLiteGraph; declare const LGraphCanvas: typeof TLGraphCanvas; @@ -496,6 +497,38 @@ class Rgthree extends EventTarget { } const rerouteLabel = selectedNodes.length ? "selected" : "all"; + function getBookmarks(): ContextMenuItem[] { + const showBookmarks = CONFIG_SERVICE.getFeatureValue("bookmark_menu.enabled"); + + if (!showBookmarks) { return []; } + + const bookmarkNodes = graph._nodes.filter((n): n is Bookmark => n.type == NodeTypesString.BOOKMARK); + const labeledOnly = CONFIG_SERVICE.getFeatureValue("bookmark_menu.labeled_only"); + + const bookmarksToList = bookmarkNodes + .filter((n) => !labeledOnly || n.properties['label']) + // Sort by shortcut key. + // I could see an option to sort by either Shortcut, Label, or Position. + .sort((a, b) => a.shortcutKey.localeCompare(b.shortcutKey)); + const bookmarkMenuItems = bookmarksToList.map((n) => ({ + content: `[${n.shortcutKey}] ${n.properties['label']}`, + className: "rgthree-contextmenu-item", + callback: () => { + n.canvasToBookmark(); + }, + })); + return [ + { + content: "🔖 Bookmarks", + disabled: true, + className: "rgthree-contextmenu-item rgthree-contextmenu-label", + }, + ...bookmarkMenuItems, + ] + } + + const bookmarkMenuItems = getBookmarks(); + return [ { content: "Actions", @@ -535,6 +568,7 @@ class Rgthree extends EventTarget { })(); }, }, + ...bookmarkMenuItems, { content: "More...", disabled: true, diff --git a/web/comfyui/bookmark.js b/web/comfyui/bookmark.js index c863d09..99c2788 100644 --- a/web/comfyui/bookmark.js +++ b/web/comfyui/bookmark.js @@ -19,6 +19,7 @@ export class Bookmark extends RgthreeBaseVirtualNode { this.___collapsed_width = 0; this.isVirtualNode = true; this.serialize_widgets = true; + this.properties[PROPERTY_LABEL] = ""; this.addWidget('text', 'shortcut_key', '1', (value, ...args) => { value = value.trim()[0] || '1'; }, { @@ -42,7 +43,7 @@ export class Bookmark extends RgthreeBaseVirtualNode { } async onKeypress(event) { const target = event.target; - if (['input', 'textarea'].includes(target.localName)) { + if (['input', 'textarea', 'span'].includes(target.localName)) { return; } if (event.ctrlKey || event.metaKey || event.altKey) { @@ -72,6 +73,7 @@ export class Bookmark extends RgthreeBaseVirtualNode { Bookmark.type = NodeTypesString.BOOKMARK; Bookmark.title = NodeTypesString.BOOKMARK; Bookmark.slot_start_y = -20; +Bookmark["@label"] = { type: "string" }; app.registerExtension({ name: "rgthree.Bookmark", registerCustomNodes() { diff --git a/web/comfyui/config.js b/web/comfyui/config.js index c59341f..e7b37cf 100644 --- a/web/comfyui/config.js +++ b/web/comfyui/config.js @@ -102,6 +102,19 @@ const CONFIGURABLE = { description: "Will show a message at the top of the screen when loading a workflow that has " + "corrupt linking data.", }, + { + key: "features.bookmark_menu.enabled", + type: ConfigType.BOOLEAN, + label: "Show bookmark shortcuts in context menu", + description: "Will list the bookmarks in the rgthree-comfy context menu", + subconfig: [ + { + key: "features.bookmark_menu.labeled_only", + type: ConfigType.BOOLEAN, + label: "Only show explicitly labeled bookmarks (set in Properties)", + }, + ], + }, { key: "log_level", type: ConfigType.STRING, diff --git a/web/comfyui/rgthree.js b/web/comfyui/rgthree.js index bf71826..0c1e3bd 100644 --- a/web/comfyui/rgthree.js +++ b/web/comfyui/rgthree.js @@ -308,6 +308,33 @@ class Rgthree extends EventTarget { rerouteNodes = graph._nodes.filter((n) => n.type == "Reroute"); } const rerouteLabel = selectedNodes.length ? "selected" : "all"; + function getBookmarks() { + const showBookmarks = CONFIG_SERVICE.getFeatureValue("bookmark_menu.enabled"); + if (!showBookmarks) { + return []; + } + const bookmarkNodes = graph._nodes.filter((n) => n.type == NodeTypesString.BOOKMARK); + const labeledOnly = CONFIG_SERVICE.getFeatureValue("bookmark_menu.labeled_only"); + const bookmarksToList = bookmarkNodes + .filter((n) => !labeledOnly || n.properties['label']) + .sort((a, b) => a.shortcutKey.localeCompare(b.shortcutKey)); + const bookmarkMenuItems = bookmarksToList.map((n) => ({ + content: `[${n.shortcutKey}] ${n.properties['label']}`, + className: "rgthree-contextmenu-item", + callback: () => { + n.canvasToBookmark(); + }, + })); + return [ + { + content: "🔖 Bookmarks", + disabled: true, + className: "rgthree-contextmenu-item rgthree-contextmenu-label", + }, + ...bookmarkMenuItems, + ]; + } + const bookmarkMenuItems = getBookmarks(); return [ { content: "Actions", @@ -346,6 +373,7 @@ class Rgthree extends EventTarget { })(); }, }, + ...bookmarkMenuItems, { content: "More...", disabled: true,