From 7a980f46c9575690d4bb426f9181e4a0c3f5d857 Mon Sep 17 00:00:00 2001
From: pythongosssss <125205205+pythongosssss@users.noreply.github.com>
Date: Sun, 4 Aug 2024 16:54:46 +0100
Subject: [PATCH] Add support for node/input/output tooltips (#287)
* Add support for node/input/output tooltips
* pr feedback
* Remove
---
src/components/graph/GraphCanvas.vue | 2 +
src/components/graph/NodeTooltip.vue | 168 ++++++++++++++++++++++++++
src/extensions/core/widgetInputs.ts | 3 +-
src/scripts/domWidget.ts | 10 +-
src/scripts/ui.ts | 9 +-
src/scripts/widgets.ts | 4 +
src/stores/nodeDefStore.ts | 14 ++-
src/stores/settingStore.ts | 2 +-
src/types/apiTypes.ts | 1 +
src/types/litegraph-augmentation.d.ts | 24 ++++
10 files changed, 227 insertions(+), 10 deletions(-)
create mode 100644 src/components/graph/NodeTooltip.vue
diff --git a/src/components/graph/GraphCanvas.vue b/src/components/graph/GraphCanvas.vue
index 685a8a39e..e0a2cb2db 100644
--- a/src/components/graph/GraphCanvas.vue
+++ b/src/components/graph/GraphCanvas.vue
@@ -8,12 +8,14 @@
+
+
+
diff --git a/src/extensions/core/widgetInputs.ts b/src/extensions/core/widgetInputs.ts
index 2403be68f..ddd3272b6 100644
--- a/src/extensions/core/widgetInputs.ts
+++ b/src/extensions/core/widgetInputs.ts
@@ -571,7 +571,8 @@ export function mergeIfValid(
k !== 'forceInput' &&
k !== 'defaultInput' &&
k !== 'control_after_generate' &&
- k !== 'multiline'
+ k !== 'multiline' &&
+ k !== 'tooltip'
) {
let v1 = config1[1][k]
let v2 = config2[1]?.[k]
diff --git a/src/scripts/domWidget.ts b/src/scripts/domWidget.ts
index 5a6373a6a..146f214ba 100644
--- a/src/scripts/domWidget.ts
+++ b/src/scripts/domWidget.ts
@@ -226,11 +226,8 @@ LGraphCanvas.prototype.computeVisibleNodes = function (): LGraphNode[] {
if (elementWidgets.has(node)) {
const hidden = visibleNodes.indexOf(node) === -1
for (const w of node.widgets) {
- // @ts-expect-error
if (w.element) {
- // @ts-expect-error
w.element.hidden = hidden
- // @ts-expect-error
w.element.style.display = hidden ? 'none' : undefined
if (hidden) {
w.options.onHide?.(w)
@@ -282,6 +279,13 @@ LGraphNode.prototype.addDOMWidget = function (
document.addEventListener('mousedown', mouseDownHandler)
}
+ const { nodeData } = this.constructor
+ const tooltip = (nodeData?.input.required?.[name] ??
+ nodeData?.input.optional?.[name])?.[1]?.tooltip
+ if (tooltip && !element.title) {
+ element.title = tooltip
+ }
+
const widget: DOMWidget = {
type,
name,
diff --git a/src/scripts/ui.ts b/src/scripts/ui.ts
index 4b047f6bb..0f8fa456d 100644
--- a/src/scripts/ui.ts
+++ b/src/scripts/ui.ts
@@ -428,6 +428,13 @@ export class ComfyUI {
defaultValue: 'default'
})
+ this.settings.addSetting({
+ id: 'Comfy.EnableTooltips',
+ name: 'Enable Tooltips',
+ type: 'boolean',
+ defaultValue: true
+ })
+
const fileInput = $el('input', {
id: 'comfy-file-input',
type: 'file',
@@ -437,7 +444,7 @@ export class ComfyUI {
onchange: () => {
app.handleFile(fileInput.files[0])
}
- }) as HTMLInputElement
+ })
this.loadFile = () => fileInput.click()
diff --git a/src/scripts/widgets.ts b/src/scripts/widgets.ts
index 64194cc77..4d06bf690 100644
--- a/src/scripts/widgets.ts
+++ b/src/scripts/widgets.ts
@@ -113,6 +113,8 @@ export function addValueControlWidgets(
serialize: false // Don't include this in prompt.
}
)
+ valueControl.tooltip =
+ 'Allows the linked widget to be changed automatically, for example randomizing the noise seed.'
valueControl[IS_CONTROL_WIDGET] = true
updateControlWidgetLabel(valueControl)
widgets.push(valueControl)
@@ -133,6 +135,8 @@ export function addValueControlWidgets(
}
)
updateControlWidgetLabel(comboFilter)
+ comboFilter.tooltip =
+ "Allows for filtering the list of values when changing the value via the control generate mode. Allows for RegEx matches in the format /abc/ to only filter to values containing 'abc'."
widgets.push(comboFilter)
}
diff --git a/src/stores/nodeDefStore.ts b/src/stores/nodeDefStore.ts
index e588fd84b..dda58ca58 100644
--- a/src/stores/nodeDefStore.ts
+++ b/src/stores/nodeDefStore.ts
@@ -8,7 +8,7 @@ import { TreeNode } from 'primevue/treenode'
export class BaseInputSpec {
name: string
type: string
-
+ tooltip?: string
default?: T
@Type(() => Boolean)
@@ -131,6 +131,10 @@ export class ComfyInputsSpec {
get all() {
return [...Object.values(this.required), ...Object.values(this.optional)]
}
+
+ getInput(name: string): BaseInputSpec | undefined {
+ return this.required[name] ?? this.optional[name]
+ }
}
export class ComfyOutputSpec {
@@ -140,7 +144,8 @@ export class ComfyOutputSpec {
public name: string,
public type: string,
public is_list: boolean,
- public comboOptions?: any[]
+ public comboOptions?: any[],
+ public tooltip?: string
) {}
}
@@ -166,7 +171,7 @@ export class ComfyNodeDefImpl {
output: ComfyOutputsSpec
private static transformOutputSpec(obj: any): ComfyOutputsSpec {
- const { output, output_is_list, output_name } = obj
+ const { output, output_is_list, output_name, output_tooltips } = obj
const result = output.map((type: string | any[], index: number) => {
const typeString = Array.isArray(type) ? 'COMBO' : type
@@ -175,7 +180,8 @@ export class ComfyNodeDefImpl {
output_name[index],
typeString,
output_is_list[index],
- Array.isArray(type) ? type : undefined
+ Array.isArray(type) ? type : undefined,
+ output_tooltips?.[index]
)
})
return new ComfyOutputsSpec(result)
diff --git a/src/stores/settingStore.ts b/src/stores/settingStore.ts
index 6f1df0e0f..3cc06d8d1 100644
--- a/src/stores/settingStore.ts
+++ b/src/stores/settingStore.ts
@@ -32,7 +32,7 @@ export const useSettingStore = defineStore('setting', {
app.ui.settings.setSettingValue(key, value)
},
- get(key: string) {
+ get(key: string): T {
return (
this.settingValues[key] ?? app.ui.settings.getSettingDefaultValue(key)
)
diff --git a/src/types/apiTypes.ts b/src/types/apiTypes.ts
index 58d0e7642..5ca51c9be 100644
--- a/src/types/apiTypes.ts
+++ b/src/types/apiTypes.ts
@@ -272,6 +272,7 @@ const zComfyNodeDef = z.object({
output: zComfyOutputTypesSpec,
output_is_list: z.array(z.boolean()),
output_name: z.array(z.string()),
+ output_tooltips: z.array(z.string()).optional(),
name: z.string(),
display_name: z.string(),
description: z.string(),
diff --git a/src/types/litegraph-augmentation.d.ts b/src/types/litegraph-augmentation.d.ts
index a5befe4e8..359f94870 100644
--- a/src/types/litegraph-augmentation.d.ts
+++ b/src/types/litegraph-augmentation.d.ts
@@ -21,6 +21,13 @@ declare module '@comfyorg/litegraph' {
* Allows for additional cleanup when removing a widget when converting to input.
*/
onRemove?(): void
+
+ /**
+ * DOM element used for the widget
+ */
+ element?: HTMLElement
+
+ tooltip?: string
}
interface INodeOutputSlot {
@@ -43,4 +50,21 @@ declare module '@comfyorg/litegraph' {
interface LGraphNode {
widgets_values?: unknown[]
}
+
+ interface LGraphCanvas {
+ /** This is in the litegraph types but has incorrect return type */
+ isOverNodeInput(
+ node: LGraphNode,
+ canvasX: number,
+ canvasY: number,
+ slotPos: Vector2
+ ): number
+
+ isOverNodeOutput(
+ node: LGraphNode,
+ canvasX: number,
+ canvasY: number,
+ slotPos: Vector2
+ ): number
+ }
}