The widget part is very much WIP... an input takes precedence over the widget. i.e the widget is only used if there is no input.
174 lines
5.5 KiB
JavaScript
174 lines
5.5 KiB
JavaScript
// Define the Color Picker widget class
|
|
import parseCss from '/extensions/mtb/extern/parse-css.js'
|
|
import { app } from "/scripts/app.js";
|
|
import { ComfyWidgets } from "/scripts/widgets.js";
|
|
|
|
export function CUSTOM_INT(node, inputName, val, func, config = {}) {
|
|
return {
|
|
widget: node.addWidget(
|
|
"number",
|
|
inputName,
|
|
val,
|
|
func,
|
|
Object.assign({}, { min: 0, max: 4096, step: 640, precision: 0 }, config)
|
|
),
|
|
};
|
|
}
|
|
const dumb_call = (v,d,node) => {
|
|
console.log("dumb_call", {v,d,node});
|
|
}
|
|
function isColorBright (rgb, threshold=240) {
|
|
const brightess = getBrightness(rgb)
|
|
|
|
return brightess > threshold
|
|
}
|
|
|
|
function getBrightness (rgbObj) {
|
|
return Math.round(((parseInt(rgbObj[0]) * 299) + (parseInt(rgbObj[1]) * 587) + (parseInt(rgbObj[2]) * 114)) /1000)
|
|
}
|
|
|
|
|
|
/**
|
|
* @returns {import("/types/litegraph").IWidget} widget
|
|
*/
|
|
const custom = (key,val) => {
|
|
/** @type {import("/types/litegraph").IWidget} */
|
|
const widget = {}
|
|
// widget.y = 0;
|
|
widget.name = key;
|
|
widget.type = "COLOR";
|
|
widget.options = { default: "#ff0000" };
|
|
widget.value = val || "#ff0000";
|
|
widget.draw = function (ctx,
|
|
node,
|
|
widgetWidth,
|
|
widgetY,
|
|
height) {
|
|
const border = 3;
|
|
|
|
// draw a rect with a border and a fill color
|
|
ctx.fillStyle = "#000";
|
|
ctx.fillRect(0, widgetY, widgetWidth, height);
|
|
ctx.fillStyle = this.value;
|
|
ctx.fillRect(border, widgetY + border, widgetWidth - border * 2, height - border * 2);
|
|
// write the input name
|
|
// choose the fill based on the luminoisty of this.value color
|
|
const color = parseCss(this.value.default || this.value)
|
|
if (!color) {
|
|
return
|
|
}
|
|
ctx.fillStyle = isColorBright(color.values, 125) ? "#000" : "#fff";
|
|
|
|
|
|
ctx.font = "14px Arial";
|
|
ctx.textAlign = "center";
|
|
ctx.fillText(this.name, widgetWidth * 0.5, widgetY + 14);
|
|
|
|
|
|
widget.mouse = function (e, pos, node) {
|
|
if (e.type === "pointerdown") {
|
|
console.log({e,pos,node})
|
|
// get widgets of type type : "COLOR"
|
|
const widgets = node.widgets.filter(w => w.type === "COLOR");
|
|
|
|
for (const w of widgets) {
|
|
// color picker
|
|
const rect = [w.last_y, w.last_y + 32];
|
|
console.log({rect,pos})
|
|
if (pos[1] > rect[0] && pos[1] < rect[1]) {
|
|
console.log("color picker", node)
|
|
const picker = document.createElement("input");
|
|
picker.type = "color";
|
|
picker.value = this.value;
|
|
|
|
|
|
document.body.appendChild(picker);
|
|
|
|
picker.addEventListener("change", () => {
|
|
this.value = picker.value;
|
|
node.graph._version++;
|
|
node.setDirtyCanvas(true, true);
|
|
document.body.removeChild(picker);
|
|
});
|
|
|
|
// simulate click with screen center
|
|
const pointer_event = new MouseEvent('click', {
|
|
bubbles: false,
|
|
// cancelable: true,
|
|
pointerType: "mouse",
|
|
clientX: window.innerWidth / 2,
|
|
clientY: window.innerHeight / 2,
|
|
x: window.innerWidth / 2,
|
|
y: window.innerHeight / 2,
|
|
offsetX: window.innerWidth / 2,
|
|
offsetY: window.innerHeight / 2,
|
|
screenX: window.innerWidth / 2,
|
|
screenY: window.innerHeight / 2,
|
|
|
|
|
|
});
|
|
console.log(e)
|
|
picker.dispatchEvent(pointer_event);
|
|
|
|
}}}}
|
|
widget.computeSize = function (width) {
|
|
return [width, 32];
|
|
}
|
|
return widget;
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "mtb.ColorPicker",
|
|
init: () => {
|
|
ComfyWidgets.COLOR = function () {
|
|
return {
|
|
widget:custom("color", "#ff0000")
|
|
};
|
|
};
|
|
},
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
|
|
//console.log("mtb.ColorPicker", { nodeType, nodeData, app });
|
|
const rinputs = nodeData.input?.required; // object with key/value pairs, "0" is the type
|
|
// console.log(nodeData.name, { nodeType, nodeData, app });
|
|
|
|
if (!rinputs) return;
|
|
|
|
|
|
let has_color = false;
|
|
for (const [key, input] of Object.entries(rinputs)) {
|
|
if (input[0] === "COLOR") {
|
|
has_color = true;
|
|
// input[1] = { default: "#ff0000" };
|
|
|
|
}}
|
|
|
|
if (!has_color) return;
|
|
|
|
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
|
|
this.serialize_widgets = true;
|
|
// if (rinputs[0] === "COLOR") {
|
|
// console.log(nodeData.name, { nodeType, nodeData, app });
|
|
|
|
// loop through the inputs to find the color inputs
|
|
for (const [key, input] of Object.entries(rinputs)) {
|
|
if (input[0] === "COLOR") {
|
|
this.addCustomWidget(custom(key,input[1]))
|
|
}
|
|
// }
|
|
}
|
|
|
|
this.onRemoved = function () {
|
|
// When removing this node we need to remove the input from the DOM
|
|
for (let y in this.widgets) {
|
|
if (this.widgets[y].canvas) {
|
|
this.widgets[y].canvas.remove();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
});
|