mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-01-25 15:55:18 +00:00
Auto queue on change (#2542)
* Add toggle to enable auto queue when graph is changed * type fix * better * better alignment * Change undoredo to not ignore inputs when autoqueue in change mode
This commit is contained in:
parent
f9e55d8463
commit
93bbe3f4c0
@ -1,4 +1,5 @@
|
|||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
|
import { api } from "../../scripts/api.js"
|
||||||
|
|
||||||
const MAX_HISTORY = 50;
|
const MAX_HISTORY = 50;
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ function checkState() {
|
|||||||
}
|
}
|
||||||
activeState = clone(currentState);
|
activeState = clone(currentState);
|
||||||
redo.length = 0;
|
redo.length = 0;
|
||||||
|
api.dispatchEvent(new CustomEvent("graphChanged", { detail: activeState }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +94,7 @@ const undoRedo = async (e) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const bindInput = (activeEl) => {
|
const bindInput = (activeEl) => {
|
||||||
if (activeEl?.tagName !== "CANVAS" && activeEl?.tagName !== "BODY") {
|
if (activeEl && activeEl.tagName !== "CANVAS" && activeEl.tagName !== "BODY") {
|
||||||
for (const evt of ["change", "input", "blur"]) {
|
for (const evt of ["change", "input", "blur"]) {
|
||||||
if (`on${evt}` in activeEl) {
|
if (`on${evt}` in activeEl) {
|
||||||
const listener = () => {
|
const listener = () => {
|
||||||
@ -111,11 +113,15 @@ window.addEventListener(
|
|||||||
"keydown",
|
"keydown",
|
||||||
(e) => {
|
(e) => {
|
||||||
requestAnimationFrame(async () => {
|
requestAnimationFrame(async () => {
|
||||||
const activeEl = document.activeElement;
|
let activeEl;
|
||||||
|
// If we are auto queue in change mode then we do want to trigger on inputs
|
||||||
|
if (!app.ui.autoQueueEnabled || app.ui.autoQueueMode === "instant") {
|
||||||
|
activeEl = document.activeElement;
|
||||||
if (activeEl?.tagName === "INPUT" || activeEl?.type === "textarea") {
|
if (activeEl?.tagName === "INPUT" || activeEl?.type === "textarea") {
|
||||||
// Ignore events on inputs, they have their native history
|
// Ignore events on inputs, they have their native history
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
keyIgnored = e.key === "Control" || e.key === "Shift" || e.key === "Alt" || e.key === "Meta";
|
keyIgnored = e.key === "Control" || e.key === "Shift" || e.key === "Alt" || e.key === "Meta";
|
||||||
if (keyIgnored) return;
|
if (keyIgnored) return;
|
||||||
@ -143,6 +149,11 @@ window.addEventListener("mouseup", () => {
|
|||||||
checkState();
|
checkState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle prompt queue event for dynamic widget changes
|
||||||
|
api.addEventListener("promptQueued", () => {
|
||||||
|
checkState();
|
||||||
|
});
|
||||||
|
|
||||||
// Handle litegraph clicks
|
// Handle litegraph clicks
|
||||||
const processMouseUp = LGraphCanvas.prototype.processMouseUp;
|
const processMouseUp = LGraphCanvas.prototype.processMouseUp;
|
||||||
LGraphCanvas.prototype.processMouseUp = function (e) {
|
LGraphCanvas.prototype.processMouseUp = function (e) {
|
||||||
@ -156,3 +167,11 @@ LGraphCanvas.prototype.processMouseDown = function (e) {
|
|||||||
checkState();
|
checkState();
|
||||||
return v;
|
return v;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle litegraph context menu for COMBO widgets
|
||||||
|
const close = LiteGraph.ContextMenu.prototype.close;
|
||||||
|
LiteGraph.ContextMenu.prototype.close = function(e) {
|
||||||
|
const v = close.apply(this, arguments);
|
||||||
|
checkState();
|
||||||
|
return v;
|
||||||
|
}
|
@ -2068,6 +2068,7 @@ export class ComfyApp {
|
|||||||
} finally {
|
} finally {
|
||||||
this.#processingQueue = false;
|
this.#processingQueue = false;
|
||||||
}
|
}
|
||||||
|
api.dispatchEvent(new CustomEvent("promptQueued", { detail: { number, batchCount } }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { api } from "./api.js";
|
import { api } from "./api.js";
|
||||||
import { ComfyDialog as _ComfyDialog } from "./ui/dialog.js";
|
import { ComfyDialog as _ComfyDialog } from "./ui/dialog.js";
|
||||||
|
import { toggleSwitch } from "./ui/toggleSwitch.js";
|
||||||
import { ComfySettingsDialog } from "./ui/settings.js";
|
import { ComfySettingsDialog } from "./ui/settings.js";
|
||||||
|
|
||||||
export const ComfyDialog = _ComfyDialog;
|
export const ComfyDialog = _ComfyDialog;
|
||||||
@ -368,6 +369,31 @@ export class ComfyUI {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const autoQueueModeEl = toggleSwitch(
|
||||||
|
"autoQueueMode",
|
||||||
|
[
|
||||||
|
{ text: "instant", tooltip: "A new prompt will be queued as soon as the queue reaches 0" },
|
||||||
|
{ text: "change", tooltip: "A new prompt will be queued when the queue is at 0 and the graph is/has changed" },
|
||||||
|
],
|
||||||
|
{
|
||||||
|
onChange: (value) => {
|
||||||
|
this.autoQueueMode = value.item.value;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
autoQueueModeEl.style.display = "none";
|
||||||
|
|
||||||
|
api.addEventListener("graphChanged", () => {
|
||||||
|
if (this.autoQueueMode === "change") {
|
||||||
|
if (this.lastQueueSize === 0) {
|
||||||
|
this.graphHasChanged = false;
|
||||||
|
app.queuePrompt(0, this.batchCount);
|
||||||
|
} else {
|
||||||
|
this.graphHasChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.menuContainer = $el("div.comfy-menu", {parent: document.body}, [
|
this.menuContainer = $el("div.comfy-menu", {parent: document.body}, [
|
||||||
$el("div.drag-handle", {
|
$el("div.drag-handle", {
|
||||||
style: {
|
style: {
|
||||||
@ -394,6 +420,7 @@ export class ComfyUI {
|
|||||||
document.getElementById("extraOptions").style.display = i.srcElement.checked ? "block" : "none";
|
document.getElementById("extraOptions").style.display = i.srcElement.checked ? "block" : "none";
|
||||||
this.batchCount = i.srcElement.checked ? document.getElementById("batchCountInputRange").value : 1;
|
this.batchCount = i.srcElement.checked ? document.getElementById("batchCountInputRange").value : 1;
|
||||||
document.getElementById("autoQueueCheckbox").checked = false;
|
document.getElementById("autoQueueCheckbox").checked = false;
|
||||||
|
this.autoQueueEnabled = false;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
@ -425,20 +452,22 @@ export class ComfyUI {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
$el("div",[
|
$el("div",[
|
||||||
$el("label",{
|
$el("label",{
|
||||||
for:"autoQueueCheckbox",
|
for:"autoQueueCheckbox",
|
||||||
innerHTML: "Auto Queue"
|
innerHTML: "Auto Queue"
|
||||||
// textContent: "Auto Queue"
|
|
||||||
}),
|
}),
|
||||||
$el("input", {
|
$el("input", {
|
||||||
id: "autoQueueCheckbox",
|
id: "autoQueueCheckbox",
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
checked: false,
|
checked: false,
|
||||||
title: "Automatically queue prompt when the queue size hits 0",
|
title: "Automatically queue prompt when the queue size hits 0",
|
||||||
|
onchange: (e) => {
|
||||||
|
this.autoQueueEnabled = e.target.checked;
|
||||||
|
autoQueueModeEl.style.display = this.autoQueueEnabled ? "" : "none";
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
|
autoQueueModeEl
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
$el("div.comfy-menu-btns", [
|
$el("div.comfy-menu-btns", [
|
||||||
@ -572,10 +601,13 @@ export class ComfyUI {
|
|||||||
if (
|
if (
|
||||||
this.lastQueueSize != 0 &&
|
this.lastQueueSize != 0 &&
|
||||||
status.exec_info.queue_remaining == 0 &&
|
status.exec_info.queue_remaining == 0 &&
|
||||||
document.getElementById("autoQueueCheckbox").checked &&
|
this.autoQueueEnabled &&
|
||||||
|
(this.autoQueueMode === "instant" || this.graphHasChanged) &&
|
||||||
!app.lastExecutionError
|
!app.lastExecutionError
|
||||||
) {
|
) {
|
||||||
app.queuePrompt(0, this.batchCount);
|
app.queuePrompt(0, this.batchCount);
|
||||||
|
status.exec_info.queue_remaining += this.batchCount;
|
||||||
|
this.graphHasChanged = false;
|
||||||
}
|
}
|
||||||
this.lastQueueSize = status.exec_info.queue_remaining;
|
this.lastQueueSize = status.exec_info.queue_remaining;
|
||||||
}
|
}
|
||||||
|
60
web/scripts/ui/toggleSwitch.js
Normal file
60
web/scripts/ui/toggleSwitch.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { $el } from "../ui.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef { { text: string, value?: string, tooltip?: string } } ToggleSwitchItem
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Creates a toggle switch element
|
||||||
|
* @param { string } name
|
||||||
|
* @param { Array<string | ToggleSwitchItem } items
|
||||||
|
* @param { Object } [opts]
|
||||||
|
* @param { (e: { item: ToggleSwitchItem, prev?: ToggleSwitchItem }) => void } [opts.onChange]
|
||||||
|
*/
|
||||||
|
export function toggleSwitch(name, items, { onChange } = {}) {
|
||||||
|
let selectedIndex;
|
||||||
|
let elements;
|
||||||
|
|
||||||
|
function updateSelected(index) {
|
||||||
|
if (selectedIndex != null) {
|
||||||
|
elements[selectedIndex].classList.remove("comfy-toggle-selected");
|
||||||
|
}
|
||||||
|
onChange?.({ item: items[index], prev: selectedIndex == null ? undefined : items[selectedIndex] });
|
||||||
|
selectedIndex = index;
|
||||||
|
elements[selectedIndex].classList.add("comfy-toggle-selected");
|
||||||
|
}
|
||||||
|
|
||||||
|
elements = items.map((item, i) => {
|
||||||
|
if (typeof item === "string") item = { text: item };
|
||||||
|
if (!item.value) item.value = item.text;
|
||||||
|
|
||||||
|
const toggle = $el(
|
||||||
|
"label",
|
||||||
|
{
|
||||||
|
textContent: item.text,
|
||||||
|
title: item.tooltip ?? "",
|
||||||
|
},
|
||||||
|
$el("input", {
|
||||||
|
name,
|
||||||
|
type: "radio",
|
||||||
|
value: item.value ?? item.text,
|
||||||
|
checked: item.selected,
|
||||||
|
onchange: () => {
|
||||||
|
updateSelected(i);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (item.selected) {
|
||||||
|
updateSelected(i);
|
||||||
|
}
|
||||||
|
return toggle;
|
||||||
|
});
|
||||||
|
|
||||||
|
const container = $el("div.comfy-toggle-switch", elements);
|
||||||
|
|
||||||
|
if (selectedIndex == null) {
|
||||||
|
elements[0].children[0].checked = true;
|
||||||
|
updateSelected(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
@ -121,6 +121,7 @@ body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comfy-toggle-switch,
|
||||||
.comfy-btn,
|
.comfy-btn,
|
||||||
.comfy-menu > button,
|
.comfy-menu > button,
|
||||||
.comfy-menu-btns button,
|
.comfy-menu-btns button,
|
||||||
@ -434,6 +435,43 @@ dialog::backdrop {
|
|||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comfy-toggle-switch {
|
||||||
|
border-width: 2px;
|
||||||
|
display: flex;
|
||||||
|
background-color: var(--comfy-input-bg);
|
||||||
|
margin: 2px 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comfy-toggle-switch label {
|
||||||
|
padding: 2px 0px 3px 6px;
|
||||||
|
flex: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comfy-toggle-switch label:first-child {
|
||||||
|
border-top-left-radius: 8px;
|
||||||
|
border-bottom-left-radius: 8px;
|
||||||
|
}
|
||||||
|
.comfy-toggle-switch label:last-child {
|
||||||
|
border-top-right-radius: 8px;
|
||||||
|
border-bottom-right-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comfy-toggle-switch .comfy-toggle-selected {
|
||||||
|
background-color: var(--comfy-menu-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#extraOptions {
|
||||||
|
padding: 4px;
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Search box */
|
/* Search box */
|
||||||
|
|
||||||
.litegraph.litesearchbox {
|
.litegraph.litesearchbox {
|
||||||
|
Loading…
Reference in New Issue
Block a user