More control over how gallery selects images from events
This commit is contained in:
Submodule litegraph updated: 3ce3a47871...1a77c461ad
@@ -85,6 +85,13 @@
|
|||||||
changed = false;
|
changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: if (mode === "queue" && !$queuePending && !$queueRunning) {
|
||||||
|
_queuedEntries = []
|
||||||
|
_runningEntries = []
|
||||||
|
_entries = [];
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
async function deleteEntry(entry: QueueUIEntry, event: MouseEvent) {
|
async function deleteEntry(entry: QueueUIEntry, event: MouseEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation()
|
event.stopImmediatePropagation()
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
<div id="dropzone"
|
<div id="dropzone"
|
||||||
class="dropzone"
|
class="dropzone"
|
||||||
bind:this={dropZone}
|
bind:this={dropZone}
|
||||||
|
on:pointerdown={hideDropZone}
|
||||||
on:dragover={allowDrag}
|
on:dragover={allowDrag}
|
||||||
on:dragleave={hideDropZone}
|
on:dragleave={hideDropZone}
|
||||||
on:drop={handleDrop}
|
on:drop={handleDrop}
|
||||||
|
|||||||
@@ -200,12 +200,14 @@
|
|||||||
elem_id="comfy-image-upload-block"
|
elem_id="comfy-image-upload-block"
|
||||||
{elem_classes}
|
{elem_classes}
|
||||||
>
|
>
|
||||||
|
{#if label != ""}
|
||||||
<BlockLabel
|
<BlockLabel
|
||||||
label={label}
|
label={label}
|
||||||
show_label={label != ""}
|
show_label={label != ""}
|
||||||
Icon={FileIcon}
|
Icon={FileIcon}
|
||||||
float={label != ""}
|
float={label != ""}
|
||||||
/>
|
/>
|
||||||
|
{/if}
|
||||||
{#if value && value.length > 0 && !pending_upload}
|
{#if value && value.length > 0 && !pending_upload}
|
||||||
{@const firstImage = value[0]}
|
{@const firstImage = value[0]}
|
||||||
<ModifyUpload on:clear={handle_clear} absolute />
|
<ModifyUpload on:clear={handle_clear} absolute />
|
||||||
|
|||||||
@@ -51,12 +51,20 @@
|
|||||||
let prevValue: string[] | FileData[] | null = value;
|
let prevValue: string[] | FileData[] | null = value;
|
||||||
export let selected_image: number | null = null;
|
export let selected_image: number | null = null;
|
||||||
let old_selected_image: number | null = null;
|
let old_selected_image: number | null = null;
|
||||||
|
export let forceSelectImage: boolean | null = null;
|
||||||
|
|
||||||
$: if (prevValue !== value) {
|
$: if (prevValue !== value) {
|
||||||
// When value is falsy (clear button or first load),
|
// When value is falsy (clear button or first load),
|
||||||
// style.preview determines the selected image
|
// style.preview determines the selected image
|
||||||
if (was_reset) {
|
if (was_reset) {
|
||||||
selected_image = style.preview && value?.length ? 0 : null;
|
let selectImage: boolean = Boolean(style.preview && value?.length)
|
||||||
|
let selectedIndex = 0;
|
||||||
|
if (forceSelectImage != null) {
|
||||||
|
selectImage = forceSelectImage
|
||||||
|
selectedIndex = selected_image;
|
||||||
|
forceSelectImage = null;
|
||||||
|
}
|
||||||
|
selected_image = selectImage ? selectedIndex : null;
|
||||||
was_reset = false;
|
was_reset = false;
|
||||||
// Otherwise we keep the selected_image the same if the
|
// Otherwise we keep the selected_image the same if the
|
||||||
// gallery has at least as many elements as it did before
|
// gallery has at least as many elements as it did before
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
{#if receiveTargets.length > 0}
|
{#if receiveTargets.length > 0}
|
||||||
{#each receiveTargets as { workflow, targetNodes }}
|
{#each receiveTargets as { workflow, targetNodes }}
|
||||||
<Block>
|
<Block>
|
||||||
<BlockTitle>{workflow.attrs.title}</BlockTitle>
|
<BlockTitle>Workflow: <b>{workflow.attrs.title}</b></BlockTitle>
|
||||||
{#each targetNodes as targetNode}
|
{#each targetNodes as targetNode}
|
||||||
<Block>
|
<Block>
|
||||||
<div class="target">
|
<div class="target">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default class ComfyNoChangeEvent extends ComfyGraphNode {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
param = {
|
param = {
|
||||||
value: param,
|
__widgetValue__: param,
|
||||||
noChangedEvent: true
|
noChangedEvent: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,13 @@ export default class ComfyExecuteSubgraphAction extends ComfyGraphNode {
|
|||||||
this.setProperty("tag", tag)
|
this.setProperty("tag", tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override getTitle(): string {
|
||||||
|
if (this.flags.collapsed) {
|
||||||
|
return "Execute: " + String(this.properties.targetTag);
|
||||||
|
}
|
||||||
|
return this.title;
|
||||||
|
}
|
||||||
|
|
||||||
override onAction(action: any, param: any) {
|
override onAction(action: any, param: any) {
|
||||||
const tag = this.getInputData(1) || this.properties.targetTag;
|
const tag = this.getInputData(1) || this.properties.targetTag;
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default class ComfyReceiveOutputNode extends ComfyGraphNode {
|
|||||||
|
|
||||||
static slotLayout: SlotLayout = {
|
static slotLayout: SlotLayout = {
|
||||||
outputs: [
|
outputs: [
|
||||||
{ name: "received", type: BuiltInSlotType.EVENT }
|
{ name: "received", type: BuiltInSlotType.EVENT, options: { color_off: "fuchsia", color_on: "fuchsia" } }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { parseWhateverIntoImageMetadata, type ComfyBoxImageMetadata, type ComfyUploadImageType } from "$lib/utils";
|
import { parseWhateverIntoImageMetadata, type ComfyBoxImageMetadata, type ComfyUploadImageType } from "$lib/utils";
|
||||||
import { BuiltInSlotType, LiteGraph, type IComboWidget, type ITextWidget, type PropertyLayout, type SlotLayout, type INumberWidget } from "@litegraph-ts/core";
|
import { BuiltInSlotType, LiteGraph, type IComboWidget, type ITextWidget, type PropertyLayout, type SlotLayout, type INumberWidget, clamp } from "@litegraph-ts/core";
|
||||||
import { get, writable, type Writable } from "svelte/store";
|
import { get, writable, type Writable } from "svelte/store";
|
||||||
|
|
||||||
import GalleryWidget from "$lib/widgets/GalleryWidget.svelte";
|
import GalleryWidget from "$lib/widgets/GalleryWidget.svelte";
|
||||||
@@ -9,6 +9,7 @@ import ComfyWidgetNode from "./ComfyWidgetNode";
|
|||||||
export interface ComfyGalleryProperties extends ComfyWidgetProperties {
|
export interface ComfyGalleryProperties extends ComfyWidgetProperties {
|
||||||
index: number | null,
|
index: number | null,
|
||||||
updateMode: "replace" | "append",
|
updateMode: "replace" | "append",
|
||||||
|
autoSelectOnUpdate: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetadata[]> {
|
export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetadata[]> {
|
||||||
@@ -17,6 +18,7 @@ export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetad
|
|||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
index: 0,
|
index: 0,
|
||||||
updateMode: "replace",
|
updateMode: "replace",
|
||||||
|
autoSelectOnUpdate: true
|
||||||
}
|
}
|
||||||
|
|
||||||
static slotLayout: SlotLayout = {
|
static slotLayout: SlotLayout = {
|
||||||
@@ -42,17 +44,18 @@ export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetad
|
|||||||
|
|
||||||
selectedFilename: string | null = null;
|
selectedFilename: string | null = null;
|
||||||
|
|
||||||
selectedIndexWidget: INumberWidget;
|
selectedIndexWidget: ITextWidget;
|
||||||
modeWidget: IComboWidget;
|
modeWidget: IComboWidget;
|
||||||
|
|
||||||
imageWidth: Writable<number> = writable(0);
|
imageWidth: Writable<number> = writable(0);
|
||||||
imageHeight: Writable<number> = writable(0);
|
imageHeight: Writable<number> = writable(0);
|
||||||
|
|
||||||
selectedImage: Writable<number | null> = writable(null);
|
selectedImage: Writable<number | null> = writable(null);
|
||||||
|
forceSelectImage: Writable<boolean | null> = writable(null);
|
||||||
|
|
||||||
constructor(name?: string) {
|
constructor(name?: string) {
|
||||||
super(name, [])
|
super(name, [])
|
||||||
this.selectedIndexWidget = this.addWidget("number", "Selected", get(this.selectedImage))
|
this.selectedIndexWidget = this.addWidget("text", "Selected", String(get(this.selectedImage)))
|
||||||
this.selectedIndexWidget.disabled = true;
|
this.selectedIndexWidget.disabled = true;
|
||||||
this.modeWidget = this.addWidget("combo", "Mode", this.properties.updateMode, null, { property: "updateMode", values: ["replace", "append"] })
|
this.modeWidget = this.addWidget("combo", "Mode", this.properties.updateMode, null, { property: "updateMode", values: ["replace", "append"] })
|
||||||
}
|
}
|
||||||
@@ -69,7 +72,7 @@ export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetad
|
|||||||
this.setOutputData(0, value)
|
this.setOutputData(0, value)
|
||||||
this.setOutputData(1, index)
|
this.setOutputData(1, index)
|
||||||
|
|
||||||
this.selectedIndexWidget.value = index;
|
this.selectedIndexWidget.value = String(index);
|
||||||
|
|
||||||
if (index != null && value && value[index] != null) {
|
if (index != null && value && value[index] != null) {
|
||||||
const image = value[index];
|
const image = value[index];
|
||||||
@@ -86,29 +89,58 @@ export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetad
|
|||||||
return `Images: ${value?.length || 0}`
|
return `Images: ${value?.length || 0}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override setValue(value: ComfyBoxImageMetadata[], noChangedEvent: boolean = false) {
|
||||||
|
super.setValue(value, noChangedEvent)
|
||||||
|
|
||||||
|
const newIndex = this._newSelectedIndex;
|
||||||
|
this._newSelectedIndex = null;
|
||||||
|
|
||||||
|
if (newIndex != null) {
|
||||||
|
this.selectedImage.set(newIndex)
|
||||||
|
this.forceSelectImage.set(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _newSelectedIndex: number | null = null;
|
||||||
|
|
||||||
override parseValue(param: any): ComfyBoxImageMetadata[] {
|
override parseValue(param: any): ComfyBoxImageMetadata[] {
|
||||||
if (param == null)
|
if (param == null)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
let updateMode = this.properties.updateMode;
|
||||||
|
let selectedIndex: number | null = null;
|
||||||
|
if (typeof param === "object" && param.galleryImages != null) {
|
||||||
|
selectedIndex = param.selectedIndex;
|
||||||
|
updateMode = param.updateMode || updateMode;
|
||||||
|
param = param.galleryImages;
|
||||||
|
}
|
||||||
|
|
||||||
const meta = parseWhateverIntoImageMetadata(param) || [];
|
const meta = parseWhateverIntoImageMetadata(param) || [];
|
||||||
|
|
||||||
console.debug("[ComfyGalleryNode] Received output!", param)
|
console.debug("[ComfyGalleryNode] Received output!", param)
|
||||||
|
|
||||||
if (this.properties.updateMode === "append") {
|
if (updateMode === "append") {
|
||||||
const currentValue = get(this.value)
|
const currentValue = get(this.value)
|
||||||
if (meta.length > 0)
|
if (meta.length > 0 && (selectedIndex != null || this.properties.autoSelectOnUpdate)) {
|
||||||
this.selectedImage.set(currentValue.length);
|
let index = selectedIndex
|
||||||
|
if (index == null)
|
||||||
|
index = 0;
|
||||||
|
this._newSelectedIndex = clamp(currentValue.length + index, 0, currentValue.length + meta.length - 1)
|
||||||
|
}
|
||||||
return currentValue.concat(meta)
|
return currentValue.concat(meta)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.notifyPropsChanged();
|
this.notifyPropsChanged();
|
||||||
|
if (meta.length > 0 && (selectedIndex != null || this.properties.autoSelectOnUpdate)) {
|
||||||
|
let index = selectedIndex;
|
||||||
|
if (index == null)
|
||||||
|
index = get(this.selectedImage)
|
||||||
|
if (index != null)
|
||||||
|
this._newSelectedIndex = clamp(index, 0, meta.length - 1)
|
||||||
|
}
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override setValue(value: any, noChangedEvent: boolean = false) {
|
|
||||||
super.setValue(value, noChangedEvent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LiteGraph.registerNodeType({
|
LiteGraph.registerNodeType({
|
||||||
|
|||||||
@@ -239,8 +239,8 @@ export default abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
|||||||
if (action === this.storeActionName) {
|
if (action === this.storeActionName) {
|
||||||
let noChangedEvent = false;
|
let noChangedEvent = false;
|
||||||
let value = param;
|
let value = param;
|
||||||
if (param != null && typeof param === "object" && "value" in param) {
|
if (param != null && typeof param === "object" && "__widgetValue__" in param) {
|
||||||
value = param.value
|
value = param.__widgetValue__
|
||||||
if ("noChangedEvent" in param)
|
if ("noChangedEvent" in param)
|
||||||
noChangedEvent = Boolean(param.noChangedEvent)
|
noChangedEvent = Boolean(param.noChangedEvent)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -566,6 +566,14 @@ const ALL_ATTRIBUTES: AttributesSpecList = [
|
|||||||
values: ["replace", "append"],
|
values: ["replace", "append"],
|
||||||
defaultValue: "replace"
|
defaultValue: "replace"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "autoSelectOnUpdate",
|
||||||
|
type: "boolean",
|
||||||
|
location: "nodeProps",
|
||||||
|
editable: true,
|
||||||
|
validNodeTypes: ["ui/gallery"],
|
||||||
|
defaultValue: true
|
||||||
|
},
|
||||||
|
|
||||||
// Radio
|
// Radio
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import workflowState from "./stores/workflowState";
|
|||||||
import { ImageViewer } from "./ImageViewer";
|
import { ImageViewer } from "./ImageViewer";
|
||||||
|
|
||||||
export function clamp(n: number, min: number, max: number): number {
|
export function clamp(n: number, min: number, max: number): number {
|
||||||
|
if (max <= min)
|
||||||
|
return min;
|
||||||
return Math.min(Math.max(n, min), max)
|
return Math.min(Math.max(n, min), max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
let imageWidth: Writable<number> = writable(0);
|
let imageWidth: Writable<number> = writable(0);
|
||||||
let imageHeight: Writable<number> = writable(0);
|
let imageHeight: Writable<number> = writable(0);
|
||||||
let selected_image: Writable<number | null> = writable(null);
|
let selected_image: Writable<number | null> = writable(null);
|
||||||
|
let forceSelectImage: Writable<boolean | null> = writable(null);
|
||||||
|
|
||||||
$: widget && setNodeValue(widget);
|
$: widget && setNodeValue(widget);
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
imageWidth = node.imageWidth
|
imageWidth = node.imageWidth
|
||||||
imageHeight = node.imageHeight
|
imageHeight = node.imageHeight
|
||||||
selected_image = node.selectedImage;
|
selected_image = node.selectedImage;
|
||||||
|
forceSelectImage = node.forceSelectImage;
|
||||||
|
|
||||||
if ($nodeValue != null) {
|
if ($nodeValue != null) {
|
||||||
if (node.properties.index < 0 || node.properties.index >= $nodeValue.length) {
|
if (node.properties.index < 0 || node.properties.index >= $nodeValue.length) {
|
||||||
@@ -43,6 +45,7 @@
|
|||||||
let style: Styles = {
|
let style: Styles = {
|
||||||
grid_cols: [isMobile ? 2 : 3],
|
grid_cols: [isMobile ? 2 : 3],
|
||||||
object_fit: "cover",
|
object_fit: "cover",
|
||||||
|
// preview: true
|
||||||
}
|
}
|
||||||
let element: HTMLDivElement;
|
let element: HTMLDivElement;
|
||||||
|
|
||||||
@@ -134,6 +137,7 @@
|
|||||||
bind:imageWidth={$imageWidth}
|
bind:imageWidth={$imageWidth}
|
||||||
bind:imageHeight={$imageHeight}
|
bind:imageHeight={$imageHeight}
|
||||||
bind:selected_image={$selected_image}
|
bind:selected_image={$selected_image}
|
||||||
|
bind:forceSelectImage={$forceSelectImage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Block>
|
</Block>
|
||||||
|
|||||||
Reference in New Issue
Block a user