File size: 4,522 Bytes
c6535db | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | import { BaseSteppedWidget } from "./BaseSteppedWidget.js"
import { warnDeprecated, clamp } from "../utils/widget.js"
const UNIQUE_MESSAGE_LIMIT = 10_000
/**
* This is used as an (invalid) assertion to resolve issues with legacy duck-typed values.
*
* Function style in use by:
* https://github.com/kijai/ComfyUI-KJNodes/blob/c3dc82108a2a86c17094107ead61d63f8c76200e/web/js/setgetnodes.js#L401-L404
*/
function toArray(values) {
return Array.isArray(values) ? values : Object.keys(values)
}
export class ComboWidget extends BaseSteppedWidget {
constructor(widget, node) {
super(widget, node);
this.type = "combo";
}
get _displayValue() {
const { values: rawValues } = this.options
if (rawValues) {
const values = typeof rawValues === "function" ? rawValues() : rawValues
if (values && !Array.isArray(values)) {
return values[this.value]
}
}
return typeof this.value === "number" ? String(this.value) : this.value
}
#getValues(node) {
const { values } = this.options
if (values == null) throw new Error("[ComboWidget]: values is required")
return typeof values === "function"
? values(this, node)
: values
}
/**
* Checks if the value is {@link Array.at at} the given index in the combo list.
* @param increment `true` if checking the use of the increment button, `false` for decrement
* @returns `true` if the value is at the given index, otherwise `false`.
*/
#canUseButton(increment) {
const { values } = this.options
// If using legacy duck-typed method, false is the most permissive return value
if (typeof values === "function") return false
const valuesArray = toArray(values)
if (!(valuesArray.length > 1)) return false
// Edge case where the value is both the first and last item in the list
const firstValue = valuesArray.at(0)
const lastValue = valuesArray.at(-1)
if (firstValue === lastValue) return true
return this.value !== (increment ? lastValue : firstValue)
}
/**
* Returns `true` if the current value is not the last value in the list.
* Handles edge case where the value is both the first and last item in the list.
*/
canIncrement() {
return this.#canUseButton(true)
}
canDecrement() {
return this.#canUseButton(false)
}
incrementValue(options) {
this.#tryChangeValue(1, options)
}
decrementValue(options) {
this.#tryChangeValue(-1, options)
}
#tryChangeValue(delta, options) {
const values = this.#getValues(options.node)
const indexedValues = toArray(values)
// avoids double click event
options.canvas.last_mouseclick = 0
const foundIndex = typeof values === "object"
? indexedValues.indexOf(String(this.value)) + delta
: indexedValues.indexOf(this.value) + delta
const index = clamp(foundIndex, 0, indexedValues.length - 1)
const value = Array.isArray(values)
? values[index]
: index
this.setValue(value, options)
}
onClick({ e, node, canvas }) {
const x = e.canvasX - node.pos[0]
const width = this.width || node.size[0]
// Deprecated functionality (warning as of v0.14.5)
if (typeof this.options.values === "function") {
warnDeprecated("Using a function for values is deprecated. Use an array of unique values instead.")
}
// Determine if clicked on left/right arrows
if (x < 40) return this.decrementValue({ e, node, canvas })
if (x > width - 40) return this.incrementValue({ e, node, canvas })
// Otherwise, show dropdown menu
const values = this.#getValues(node)
const values_list = toArray(values)
// Handle center click - show dropdown menu
const text_values = values != values_list ? Object.values(values) : values
new LiteGraph.ContextMenu(text_values, {
scale: Math.max(1, canvas.ds.scale),
event: e,
className: "dark",
callback: (value) => {
this.setValue(
values != values_list
? text_values.indexOf(value)
: value,
{ e, node, canvas },
)
},
})
}
} |