Type cleanup, annotation as function, fix import

Naming now uniformly refers to the widget as an Annotated Number and the
widget is now implemented as a proper typescript class

annotatedNumber widgets can optionally have an annotation function set.
This allows for extensions to set annotations on ranges of values.

Fixed the app import incorrectly having an extension
This commit is contained in:
Austin Mroz
2024-09-26 15:17:06 -05:00
parent 330633355a
commit 72535eb88d

View File

@@ -1,5 +1,5 @@
import { LiteGraph, LGraphCanvas } from '@comfyorg/litegraph' import { LiteGraph, LGraphCanvas } from '@comfyorg/litegraph'
import { app } from '../../scripts/app.js' import { app } from '../../scripts/app'
import { getColorPalette } from './colorPalette' import { getColorPalette } from './colorPalette'
import { ComfyWidgets } from '../../scripts/widgets' import { ComfyWidgets } from '../../scripts/widgets'
import { LGraphNode } from '@comfyorg/litegraph' import { LGraphNode } from '@comfyorg/litegraph'
@@ -96,12 +96,21 @@ function draw(ctx, node, widget_width, y, H) {
this.options.precision !== undefined ? this.options.precision : 3 this.options.precision !== undefined ? this.options.precision : 3
) )
ctx.fillText(text, widget_width - margin * 2 - 20, y + H * 0.7) ctx.fillText(text, widget_width - margin * 2 - 20, y + H * 0.7)
if (this.options.mappedValues && this.value in this.options.mappedValues) { let annotation = ''
if (this.annotation) {
annotation = this.annotation(this.value)
} else if (
this.options.annotation &&
this.value in this.options.annotation
) {
annotation = this.options.annotation[this.value]
}
if (annotation) {
//TODO: measure this text //TODO: measure this text
ctx.fillStyle = litegraph_base.WIDGET_OUTLINE_COLOR ctx.fillStyle = litegraph_base.WIDGET_OUTLINE_COLOR
const value_width = ctx.measureText(text).width const value_width = ctx.measureText(text).width
ctx.fillText( ctx.fillText(
this.options.mappedValues[this.value], annotation,
widget_width - margin * 2 - 25 - value_width, widget_width - margin * 2 - 25 - value_width,
y + H * 0.7 y + H * 0.7
) )
@@ -171,28 +180,35 @@ function mouse(event, [x, y], node) {
) )
return true return true
} }
function mappednumber(node, inputName, inputData, app): { widget: IWidget } { class AnnotatedNumber implements IWidget {
// @ts-expect-error We are defining a new type // @ts-expect-error We must forcibly set a type here to allow custom mouse and draw
const type: widgetType = 'MAPPEDNUMBER' type: widgetTypes = 'annotatedNumber'
let w = { draw = draw
name: inputName, mouse = mouse
type: type, options = {}
value: 0, linkedWidgets = []
draw: draw, name: string
mouse: mouse, value: number
computeSize: undefined, //TODO: calculate minimum width annotation: (value: number) => string
options: {}, computeSize(width: number): [number, number] {
linkedWidgets: [] return [width, 20]
} }
if (inputData.length > 1) { constructor(inputName, inputData) {
w.options = inputData[1] this.name = inputName
for (let k of ['default', 'min', 'max']) { if (inputData.length > 1) {
if (inputData[1][k] != undefined) { this.options = inputData[1]
w.value = inputData[1][k] for (let k of ['default', 'min', 'max']) {
break if (inputData[1][k] != undefined) {
this.value = inputData[1][k]
break
}
} }
} }
} }
}
function annotatedNumber(node, inputName, inputData, app): { widget: IWidget } {
let w = new AnnotatedNumber(inputName, inputData)
if (!node.widgets) { if (!node.widgets) {
node.widgets = [] node.widgets = []
} }
@@ -209,14 +225,14 @@ ComfyWidgets.FLOAT = function (
if ( if (
inputData[1]?.reset == undefined && inputData[1]?.reset == undefined &&
inputData[1]?.disable == undefined && inputData[1]?.disable == undefined &&
inputData[1]?.mappedValues == undefined inputData[1]?.annotation == undefined
) { ) {
return originalFLOAT(node, inputName, inputData, app) return originalFLOAT(node, inputName, inputData, app)
} }
if (inputData[1]['display'] === 'slider') { if (inputData[1]['display'] === 'slider') {
return originalFLOAT(node, inputName, inputData, app) return originalFLOAT(node, inputName, inputData, app)
} }
return mappednumber(node, inputName, inputData, app) return annotatedNumber(node, inputName, inputData, app)
} }
const originalINT = ComfyWidgets.INT const originalINT = ComfyWidgets.INT
ComfyWidgets.INT = function ( ComfyWidgets.INT = function (
@@ -228,27 +244,23 @@ ComfyWidgets.INT = function (
if ( if (
inputData[1]?.reset || inputData[1]?.reset ||
inputData[1]?.disable || inputData[1]?.disable ||
inputData[1]?.mappedValues inputData[1]?.annotation
) { ) {
return mappednumber(node, inputName, inputData, app) return annotatedNumber(node, inputName, inputData, app)
} }
return originalINT(node, inputName, inputData, app) return originalINT(node, inputName, inputData, app)
} }
app.registerExtension({ app.registerExtension({
name: 'Comfy.MappedNumber', name: 'Comfy.AnnotatedNumber',
async getCustomWidgets(app) { async getCustomWidgets(app) {
return { return {
MAPPEDNUMBER: mappednumber ANNOTATEDNUMBER: annotatedNumber
} }
}, },
registerCustomNodes() { registerCustomNodes() {
class TestNum extends LGraphNode { class TestNum extends LGraphNode {
static category = 'utils' static category = 'utils'
color = LGraphCanvas.node_colors.yellow.color
bgcolor = LGraphCanvas.node_colors.yellow.bgcolor
groupcolor = LGraphCanvas.node_colors.yellow.groupcolor
isVirtualNode = true isVirtualNode = true
collapsable = true collapsable = true
title_mode = LiteGraph.NORMAL_TITLE title_mode = LiteGraph.NORMAL_TITLE
@@ -256,25 +268,30 @@ app.registerExtension({
constructor(title?: string) { constructor(title?: string) {
super(title) super(title)
app.widgets.MAPPEDNUMBER( app.widgets.ANNOTATEDNUMBER(
// Should we extends LGraphNode? Yesss // Should we extends LGraphNode? Yesss
this, this,
'x', 'x',
[ [
'MAPPEDNUMBER', 'ANNOTATEDNUMBER',
{ {
default: 5, default: 5,
reset: 5, reset: 5,
disable: 0, disable: 0,
mappedValues: { 6: 'def+1', 5: 'default', 0: 'disabled' }, annotation: { 6: 'def+1', 5: 'default', 0: 'disabled' },
step: 10 step: 10
} }
], ],
app app
) )
let annotatedWidget = this.widgets[0] as AnnotatedNumber
annotatedWidget.annotation = function (value) {
return ['smol', 'medium', 'big', 'real big'][
Math.floor(Math.log10(value))
]
}
} }
} }
// Load default visibility // Load default visibility
LiteGraph.registerNodeType('TestNum', TestNum) LiteGraph.registerNodeType('TestNum', TestNum)