import { app } from "../../../../scripts/app.js"; import { api } from "../../../../scripts/api.js"; import { ComfyDialog, $el } from "../../../../scripts/ui.js"; import { restart_from_here } from "./prompt.js"; import { hud, FlowState } from "./state.js"; import { send_cancel, send_message, send_onstart, skip_next_restart_message } from "./messaging.js"; import { display_preview_images, additionalDrawBackground, click_is_in_image } from "./preview.js"; import {$t} from "../common/i18n.js"; class chooserImageDialog extends ComfyDialog { constructor() { super(); this.node = null this.select_index = [] this.dialog_div = null } show(image,node){ this.select_index = [] this.node = node const images_div = image.map((img, index) => { const imgEl = $el('img', { src: img.src, onclick: _ => { if(this.select_index.includes(index)){ this.select_index = this.select_index.filter(i => i !== index) imgEl.classList.remove('selected') } else { this.select_index.push(index) imgEl.classList.add('selected') } if (node.selected.has(index)) node.selected.delete(index); else node.selected.add(index); } }) return imgEl }) super.show($el('div.easyuse-chooser-dialog',[ $el('h5.easyuse-chooser-dialog-title', $t('Choose images to continue')), $el('div.easyuse-chooser-dialog-images',images_div) ])) } createButtons() { const btns = super.createButtons(); btns[0].onclick = _ => { if (FlowState.running()) { send_cancel();} super.close() } btns.unshift($el('button', { type: 'button', textContent: $t('Choose Selected Images'), onclick: _ => { if (FlowState.paused()) { send_message(this.node.id, [...this.node.selected, -1, ...this.node.anti_selected]); } if (FlowState.idle()) { skip_next_restart_message(); restart_from_here(this.node.id).then(() => { send_message(this.node.id, [...this.node.selected, -1, ...this.node.anti_selected]); }); } super.close() } })) return btns } } function progressButtonPressed() { const node = app.graph._nodes_by_id[this.node_id]; if (node) { const selected = [...node.selected] if(selected?.length>0){ node.setProperty('values',selected) } if (FlowState.paused()) { send_message(node.id, [...node.selected, -1, ...node.anti_selected]); } if (FlowState.idle()) { skip_next_restart_message(); restart_from_here(node.id).then(() => { send_message(node.id, [...node.selected, -1, ...node.anti_selected]); }); } } } function cancelButtonPressed() { if (FlowState.running()) { send_cancel();} } function enable_disabling(button) { Object.defineProperty(button, 'clicked', { get : function() { return this._clicked; }, set : function(v) { this._clicked = (v && this.name!=''); } }) } function disable_serialize(widget) { if (!widget.options) widget.options = { }; widget.options.serialize = false; } app.registerExtension({ name:'comfy.easyuse.imageChooser', init() { window.addEventListener("beforeunload", send_cancel, true); }, setup(app) { const draw = LGraphCanvas.prototype.draw; LGraphCanvas.prototype.draw = function() { if (hud.update()) { app.graph._nodes.forEach((node)=> { if (node.update) { node.update(); } }) } draw.apply(this,arguments); } function easyuseImageChooser(event) { const {node,image,isKSampler} = display_preview_images(event); if(isKSampler) { const dialog = new chooserImageDialog(); dialog.show(image,node) } } api.addEventListener("easyuse-image-choose", easyuseImageChooser); /* If a run is interrupted, send a cancel message (unless we're doing the cancelling, to avoid infinite loop) */ const original_api_interrupt = api.interrupt; api.interrupt = function () { if (FlowState.paused() && !FlowState.cancelling) send_cancel(); original_api_interrupt.apply(this, arguments); } /* At the start of execution */ function on_execution_start() { if (send_onstart()) { app.graph._nodes.forEach((node)=> { if (node.selected || node.anti_selected) { node.selected.clear(); node.anti_selected.clear(); node.update(); } }) } } api.addEventListener("execution_start", on_execution_start); }, async nodeCreated(node, app) { if(node.comfyClass == 'easy imageChooser'){ node.setProperty('values',[]) /* A property defining the top of the image when there is just one */ if(node?.imageIndex === undefined){ Object.defineProperty(node, 'imageIndex', { get : function() { return null; }, set: function (v) {node.overIndex= v}, }) } if(node?.imagey === undefined){ Object.defineProperty(node, 'imagey', { get : function() { return null; }, set: function (v) {return node.widgets[node.widgets.length-1].last_y+LiteGraph.NODE_WIDGET_HEIGHT;}, }) } /* Capture clicks */ const org_onMouseDown = node.onMouseDown; node.onMouseDown = function( e, pos, canvas ) { if (e.isPrimary) { const i = click_is_in_image(node, pos); if (i>=0) { this.imageClicked(i); } } return (org_onMouseDown && org_onMouseDown.apply(this, arguments)); } node.send_button_widget = node.addWidget("button", "", "", progressButtonPressed); node.cancel_button_widget = node.addWidget("button", "", "", cancelButtonPressed); enable_disabling(node.cancel_button_widget); enable_disabling(node.send_button_widget); disable_serialize(node.cancel_button_widget); disable_serialize(node.send_button_widget); } }, beforeRegisterNodeDef(nodeType, nodeData, app) { if(nodeData?.name == 'easy imageChooser'){ const onDrawBackground = nodeType.prototype.onDrawBackground; nodeType.prototype.onDrawBackground = function(ctx) { onDrawBackground.apply(this, arguments); additionalDrawBackground(this, ctx); } nodeType.prototype.imageClicked = function (imageIndex) { if (nodeType?.comfyClass==="easy imageChooser") { if (this.selected.has(imageIndex)) this.selected.delete(imageIndex); else this.selected.add(imageIndex); this.update(); } } const update = nodeType.prototype.update; nodeType.prototype.update = function() { if (update) update.apply(this,arguments); if (this.send_button_widget) { this.send_button_widget.node_id = this.id; const selection = ( this.selected ? this.selected.size : 0 ) + ( this.anti_selected ? this.anti_selected.size : 0 ) const maxlength = this.imgs?.length || 0; if (FlowState.paused_here(this.id) && selection>0) { this.send_button_widget.name = (selection>1) ? "Progress selected (" + selection + '/' + maxlength +")" : "Progress selected image"; } else if (selection>0) { this.send_button_widget.name = (selection>1) ? "Progress selected (" + selection + '/' + maxlength +")" : "Progress selected image as restart"; } else { this.send_button_widget.name = ""; } } if (this.cancel_button_widget) { const isRunning = FlowState.running() this.cancel_button_widget.name = isRunning ? "Cancel current run" : ""; } this.setDirtyCanvas(true,true); } } } })