More region widget fixes

This commit is contained in:
space-nuko
2023-05-23 17:29:33 -05:00
parent e3c73ce18a
commit a3d4e4bca7
8 changed files with 68 additions and 23 deletions

View File

@@ -11,7 +11,7 @@ import type { ComfyComboNode, ComfyWidgetNode } from "./nodes/widgets";
import selectionState from "./stores/selectionState"; import selectionState from "./stores/selectionState";
import type { WritableLayoutStateStore } from "./stores/layoutStates"; import type { WritableLayoutStateStore } from "./stores/layoutStates";
import layoutStates from "./stores/layoutStates"; import layoutStates from "./stores/layoutStates";
import type { ComfyWorkflow } from "./stores/workflowState"; import type { ComfyWorkflow, WorkflowInstID } from "./stores/workflowState";
import workflowState from "./stores/workflowState"; import workflowState from "./stores/workflowState";
type ComfyGraphEvents = { type ComfyGraphEvents = {
@@ -163,7 +163,7 @@ export default class ComfyGraph extends LGraph {
// case node was cloned // case node was cloned
const reg = LiteGraph.registered_node_types[node.type] const reg = LiteGraph.registered_node_types[node.type]
layoutState.groupItems(dragItemIDs, { title: reg.title }) layoutState.groupItems(dragItemIDs, { title: reg.title, variant: "accordion", openOnStartup: true })
} }
} }

View File

@@ -356,6 +356,24 @@ export default class ComfyApp {
ComfyApp.registerDefaultSlotHandlers(nodeId, nodeDef) ComfyApp.registerDefaultSlotHandlers(nodeId, nodeDef)
} }
ComfyApp.registerComfyBoxSlotTypes()
}
static registerComfyBoxSlotTypes() {
const reg = (type: string) => {
const lowerType = type.toLowerCase();
if (!LiteGraph.slot_types_in.includes(lowerType)) {
LiteGraph.slot_types_in.push(lowerType);
}
if (!LiteGraph.slot_types_out.includes(type)) {
LiteGraph.slot_types_out.push(type);
}
}
reg("COMFYBOX_IMAGE")
reg("COMFYBOX_IMAGES")
reg("COMFYBOX_REGION")
} }
static registerDefaultSlotHandlers(nodeId: string, nodeDef: ComfyNodeDef) { static registerDefaultSlotHandlers(nodeId: string, nodeDef: ComfyNodeDef) {
@@ -771,7 +789,9 @@ export default class ComfyApp {
const promptFilename = get(configState).promptForWorkflowName; const promptFilename = get(configState).promptForWorkflowName;
let filename = "workflow.json"; const title = workflow.attrs.title.trim() || "workflow"
let filename = `${title}.json`;
if (promptFilename) { if (promptFilename) {
filename = prompt("Save workflow as:", filename); filename = prompt("Save workflow as:", filename);
if (!filename) return; if (!filename) return;
@@ -782,7 +802,7 @@ export default class ComfyApp {
else { else {
const date = new Date(); const date = new Date();
const formattedDate = date.toISOString().replace(/:/g, '-').replace(/\.\d{3}/g, '').replace('T', '_').replace("Z", ""); const formattedDate = date.toISOString().replace(/:/g, '-').replace(/\.\d{3}/g, '').replace('T', '_').replace("Z", "");
filename = `workflow - ${formattedDate}.json` filename = `${title} - ${formattedDate}.json`
} }
const indent = 2 const indent = 2

View File

@@ -150,7 +150,7 @@
let submessage = `Nodes: ${Object.keys(entry.prompt).length}` let submessage = `Nodes: ${Object.keys(entry.prompt).length}`
if (Object.keys(entry.outputs).length > 0) { if (Object.keys(entry.outputs).length > 0) {
const imageCount = Object.values(entry.outputs).flatMap(o => o.images).length const imageCount = Object.values(entry.outputs).filter(o => o.images).flatMap(o => o.images).length
submessage = `Images: ${imageCount}` submessage = `Images: ${imageCount}`
} }
@@ -172,14 +172,24 @@
result.images = thumbnails.map(convertComfyOutputToComfyURL); result.images = thumbnails.map(convertComfyOutputToComfyURL);
} }
const outputs = Object.values(entry.outputs)
.filter(o => o.images)
.flatMap(o => o.images)
.map(convertComfyOutputToComfyURL);
if (outputs) {
result.images = result.images.concat(outputs)
}
return result; return result;
} }
function convertCompletedEntry(entry: CompletedQueueEntry): QueueUIEntry { function convertCompletedEntry(entry: CompletedQueueEntry): QueueUIEntry {
const result = convertEntry(entry.entry, entry.status); const result = convertEntry(entry.entry, entry.status);
const images = Object.values(entry.entry.outputs).flatMap(o => o.images) const images = Object.values(entry.entry.outputs)
.map(convertComfyOutputToComfyURL); .filter(o => o.images)
.flatMap(o => o.images)
.map(convertComfyOutputToComfyURL);
result.images = images result.images = images
if (entry.message) if (entry.message)

View File

@@ -15,6 +15,7 @@
export let label: string; export let label: string;
export let root: string = ""; export let root: string = "";
export let root_url: null | string = null; export let root_url: null | string = null;
export let scrollOnUpdate = false;
export let value: Array<string> | Array<FileData> | null = null; export let value: Array<string> | Array<FileData> | null = null;
export let style: Styles = { export let style: Styles = {
grid_cols: [2], grid_cols: [2],
@@ -120,6 +121,7 @@
let container: HTMLDivElement; let container: HTMLDivElement;
async function scroll_to_img(index: number | null) { async function scroll_to_img(index: number | null) {
if (!scrollOnUpdate) return;
if (typeof index !== "number") return; if (typeof index !== "number") return;
await tick(); await tick();

View File

@@ -7,10 +7,11 @@ export default class ComfyRegionToCoordsNode extends ComfyGraphNode {
{ name: "in", type: "COMFYBOX_REGION" }, { name: "in", type: "COMFYBOX_REGION" },
], ],
outputs: [ outputs: [
{ name: "x", type: "number" }, // same order as conditioning nodes
{ name: "y", type: "number" },
{ name: "width", type: "number" }, { name: "width", type: "number" },
{ name: "height", type: "number" }, { name: "height", type: "number" },
{ name: "x", type: "number" },
{ name: "y", type: "number" },
], ],
} }
@@ -19,16 +20,16 @@ export default class ComfyRegionToCoordsNode extends ComfyGraphNode {
if (!Array.isArray(value)) if (!Array.isArray(value))
return; return;
this.setOutputData(0, value[0]) this.setOutputData(0, value[2])
this.setOutputData(1, value[1]) this.setOutputData(1, value[3])
this.setOutputData(2, value[2]) this.setOutputData(2, value[0])
this.setOutputData(3, value[3]) this.setOutputData(3, value[1])
} }
} }
LiteGraph.registerNodeType({ LiteGraph.registerNodeType({
class: ComfyRegionToCoordsNode, class: ComfyRegionToCoordsNode,
title: "Comfy.RegionToCoords", title: "Comfy.RegionToCoords",
desc: "Converts a COMFYBOX_REGION to four outputs of [x, y, width, height]", desc: "Converts a COMFYBOX_REGION to four outputs of [width, height, x, y]",
type: "utils/region_to_coords" type: "utils/region_to_coords"
}) })

View File

@@ -41,7 +41,7 @@ export default class ComfyMultiRegionNode extends ComfyWidgetNode<BoundingBox[]>
{ name: "changed", type: BuiltInSlotType.EVENT }, { name: "changed", type: BuiltInSlotType.EVENT },
// dynamic outputs, may be removed later // dynamic outputs, may be removed later
{ name: "region1", type: "COMFYBOX_REGION" }, { name: "region_1", type: "COMFYBOX_REGION" },
] ]
} }
@@ -145,7 +145,7 @@ export default class ComfyMultiRegionNode extends ComfyWidgetNode<BoundingBox[]>
} }
for (let index = this.outputs.length - 1; index < this.properties.regionCount; index++) { for (let index = this.outputs.length - 1; index < this.properties.regionCount; index++) {
this.addOutput(`region${index + 1}`, "COMFYBOX_REGION") this.addOutput(`region_${index + 1}`, "COMFYBOX_REGION")
} }
this.regionsChanged.set(true); this.regionsChanged.set(true);
@@ -165,10 +165,10 @@ export default class ComfyMultiRegionNode extends ComfyWidgetNode<BoundingBox[]>
value ||= this.getValue(); value ||= this.getValue();
for (const bbox of value) { for (const bbox of value) {
bbox[0] = clamp(bbox[0], 0, 1 - bbox[2]); bbox[0] = clamp(bbox[0], 0, 1);
bbox[1] = clamp(bbox[1], 0, 1 - bbox[3]); bbox[1] = clamp(bbox[1], 0, 1);
bbox[2] = clamp(bbox[2], 0, 1 - bbox[1]) bbox[2] = clamp(bbox[2], 0, 1)
bbox[3] = clamp(bbox[3], 0, 1 - bbox[2]) bbox[3] = clamp(bbox[3], 0, 1)
} }
const sizeChanged = this.properties.canvasWidth != this._prevWidth const sizeChanged = this.properties.canvasWidth != this._prevWidth

View File

@@ -15,7 +15,6 @@
import { generateBlankCanvas, generateImageCanvas, loadImage } from "./utils"; import { generateBlankCanvas, generateImageCanvas, loadImage } from "./utils";
import { clamp } from "$lib/utils"; import { clamp } from "$lib/utils";
import Row from "$lib/components/gradio/app/Row.svelte"; import Row from "$lib/components/gradio/app/Row.svelte";
import Column from "$lib/components/gradio/app/Column.svelte";
// ref: https://html-color.codes/ // ref: https://html-color.codes/
const COLOR_MAP: [string, string][] = [ const COLOR_MAP: [string, string][] = [
@@ -400,6 +399,10 @@ const COLOR_MAP: [string, string][] = [
displayBoxes = await recreateDisplayBoxes(); displayBoxes = await recreateDisplayBoxes();
} }
function updateSelectedIndex(newIndexPlusOne: number) {
selectedIndex = clamp(newIndexPlusOne - 1, 0, $nodeValue.length - 1);
}
function updateX(newX: number) { function updateX(newX: number) {
const bbox = $nodeValue[selectedIndex] const bbox = $nodeValue[selectedIndex]
const dbox = displayBoxes[selectedIndex] const dbox = displayBoxes[selectedIndex]
@@ -440,7 +443,7 @@ const COLOR_MAP: [string, string][] = [
displayBoxes[selectedIndex] = displayBoundingBox(bbox, selectedIndex, imageElem, dbox); displayBoxes[selectedIndex] = displayBoundingBox(bbox, selectedIndex, imageElem, dbox);
} }
function updateValue() { async function updateValue() {
// Clamp regions // Clamp regions
const bbox = $nodeValue[selectedIndex] const bbox = $nodeValue[selectedIndex]
const dbox = displayBoxes[selectedIndex] const dbox = displayBoxes[selectedIndex]
@@ -452,6 +455,8 @@ const COLOR_MAP: [string, string][] = [
displayBoxes[selectedIndex] = displayBoundingBox(bbox, selectedIndex, imageElem, dbox); displayBoxes[selectedIndex] = displayBoundingBox(bbox, selectedIndex, imageElem, dbox);
} }
await updateImageAndDBoxes();
// Force reactivity after changing a bbox's internal values // Force reactivity after changing a bbox's internal values
$nodeValue = $nodeValue $nodeValue = $nodeValue
} }
@@ -504,6 +509,13 @@ const COLOR_MAP: [string, string][] = [
</div> </div>
{#if selectedBBox} {#if selectedBBox}
<Block> <Block>
<Row>
<Range label="Region #" value={selectedIndex+1}
show_label={true} minimum={1} maximum={$nodeValue.length} step={1}
on:change={(e) => updateSelectedIndex(e.detail)}
on:release={updateValue}
/>
</Row>
<Row> <Row>
<Range label="X" value={selectedBBox[0]} <Range label="X" value={selectedBBox[0]}
show_label={true} minimum={0.0} maximum={1.0} step={0.01} show_label={true} minimum={0.0} maximum={1.0} step={0.01}