diff --git a/src/lib/components/ComfyUIPane.svelte b/src/lib/components/ComfyUIPane.svelte index 88f5bac..9593381 100644 --- a/src/lib/components/ComfyUIPane.svelte +++ b/src/lib/components/ComfyUIPane.svelte @@ -47,6 +47,34 @@ console.warn($layoutState) } + function groupWidgets() { + const items = layoutState.getCurrentSelection() + $layoutState.currentSelection = [] + layoutState.groupItems(items) + } + + let canUngroup = false; + let isDeleteGroup = false; + $: canUngroup = $layoutState.currentSelection.length === 1 + && layoutState.getCurrentSelection()[0].type === "container" + $: if (canUngroup) { + const dragItem = layoutState.getCurrentSelection()[0]; + const entry = $layoutState.allItems[dragItem.id]; + isDeleteGroup = entry.children.length === 0 + } + else { + isDeleteGroup = false + } + + function ungroup() { + const item = layoutState.getCurrentSelection()[0] + if (item.type !== "container") + return; + + $layoutState.currentSelection = [] + layoutState.ungroup(item as ContainerLayout) + } + let menuPos = { x: 0, y: 0 }; let showMenu = false; @@ -78,20 +106,13 @@ {#if showMenu} + isDisabled={$layoutState.currentSelection.length === 0} + on:click={groupWidgets} + text="Group" /> - - - - - Look! An icon! - + isDisabled={!canUngroup} + on:click={ungroup} + text={isDeleteGroup ? "Delete Group" : "Ungroup"} /> {/if} diff --git a/src/lib/components/WidgetContainer.svelte b/src/lib/components/WidgetContainer.svelte index 3aa9c66..7c09386 100644 --- a/src/lib/components/WidgetContainer.svelte +++ b/src/lib/components/WidgetContainer.svelte @@ -26,7 +26,14 @@ const flipDurationMs = 100; $: if (dragItem) { - if (dragItem.type === "container") { + if (!$layoutState.allItems[dragItem.id]) { + dragItem = null; + widget = null; + widgetState = null; + children = null; + container = null; + } + else if (dragItem.type === "container") { container = dragItem as ContainerLayout; children = $layoutState.allItems[dragItem.id].children; widget = null; @@ -54,11 +61,16 @@ }; const startDrag = (evt: MouseEvent) => { - if (evt.button === 2) - return; - const dragItemId: string = evt.target.dataset["dragItemId"]; + + if (evt.button !== 0) { + if ($layoutState.currentSelection.length <= 1 && !$layoutState.isMenuOpen) + $layoutState.currentSelection = [dragItemId] + return; + } + const item = $layoutState.allItems[dragItemId].dragItem + if (evt.ctrlKey) { const index = $layoutState.currentSelection.indexOf(item.id) if (index === -1) @@ -103,7 +115,6 @@
1} - class:is-executing={$queueState.runningNodeId && $queueState.runningNodeId === container.attrs.associatedNode} use:dndzone="{{ items: children, flipDurationMs, @@ -137,6 +148,10 @@ class:selected={$uiState.uiEditMode !== "disabled" && $layoutState.currentSelection.includes(widget.id)} class:is-executing={$queueState.runningNodeId && $queueState.runningNodeId == widget.attrs.associatedNode} > + {#if widget.attrs.associatedNode} + {@const node = $nodeState[widget.attrs.associatedNode].node} + ({node.type}) + {/if}
{#if showHandles} @@ -261,12 +276,12 @@ } .edit-title-label { + z-index: 10000; position: relative; - z-index: var(--layer-1); } .edit-title { - z-index: var(--layer-1); + z-index: 10000; display: block; position: relative; outline: none !important; diff --git a/src/lib/stores/layoutState.ts b/src/lib/stores/layoutState.ts index fbf5ce8..4edd1f3 100644 --- a/src/lib/stores/layoutState.ts +++ b/src/lib/stores/layoutState.ts @@ -48,12 +48,15 @@ export interface WidgetLayout extends IDragItem { type DragItemID = string; type LayoutStateOps = { - addContainer: (parentId: DragItemID, attrs: Partial) => ContainerLayout, + addContainer: (parentId: DragItemID, attrs: Partial, index: number) => ContainerLayout, + addWidget: (parentId: DragItemID, node: LGraphNode, widget: IWidget, attrs: Partial, index: number) => WidgetLayout, findDefaultContainerForInsertion: () => ContainerLayout | null, - addWidget: (parentId: DragItemID, node: LGraphNode, widget: IWidget, attrs: Partial) => WidgetLayout, updateChildren: (parent: IDragItem, children: IDragItem[]) => IDragItem[], nodeAdded: (node: LGraphNode) => void, nodeRemoved: (node: LGraphNode) => void, + groupItems: (dragItems: IDragItem[]) => ContainerLayout, + ungroup: (container: ContainerLayout) => void, + getCurrentSelection: () => IDragItem[], clear: () => void, resetLayout: () => void, } @@ -87,7 +90,7 @@ function findDefaultContainerForInsertion(): ContainerLayout | null { return null } -function addContainer(parentId: DragItemID | null, attrs: Partial = {}): ContainerLayout { +function addContainer(parentId: DragItemID | null, attrs: Partial = {}, index: number = -1): ContainerLayout { const state = get(store); const dragItem: ContainerLayout = { type: "container", @@ -106,13 +109,16 @@ function addContainer(parentId: DragItemID | null, attrs: Partial = state.allItems[dragItem.id] = entry; if (parent) { parent.children ||= [] - parent.children.push(dragItem) + if (index) + parent.children.splice(index, 0, dragItem) + else + parent.children.push(dragItem) } store.set(state) return dragItem; } -function addWidget(parentId: DragItemID, node: LGraphNode, widget: IWidget, attrs: Partial = {}): WidgetLayout { +function addWidget(parentId: DragItemID, node: LGraphNode, widget: IWidget, attrs: Partial = {}, index: number = -1): WidgetLayout { const state = get(store); const dragItem: WidgetLayout = { type: "widget", @@ -132,21 +138,25 @@ function addWidget(parentId: DragItemID, node: LGraphNode, widget: IWidget state.allItems[id].dragItem) +} + +function groupItems(dragItems: IDragItem[]): ContainerLayout { + if (dragItems.length === 0) + return; + + const state = get(store) + const parent = state.allItems[dragItems[0].id].parent || findDefaultContainerForInsertion(); + + if (parent === null || parent.type !== "container") + return; + + let index = undefined; + if (parent) { + const indexFound = state.allItems[parent.id].children.indexOf(dragItems[0]) + if (indexFound !== -1) + index = indexFound + } + + const container = addContainer(parent.id, { title: "Group" }, index) + + for (const item of dragItems) { + moveItem(item, container) + } + + store.set(state) + return container +} + +function ungroup(container: ContainerLayout) { + const state = get(store) + + const parent = state.allItems[container.id].parent; + if (!parent || parent.type !== "container") { + console.warn("No parent to ungroup into!", container) + return; + } + + let index = undefined; + const parentChildren = state.allItems[parent.id].children; + const indexFound = parentChildren.indexOf(container) + if (indexFound !== -1) + index = indexFound + + const containerEntry = state.allItems[container.id] + console.debug("[layoutState] About to ungroup", containerEntry, parent, parentChildren, index) + + const children = [...containerEntry.children] + for (const item of children) { + moveItem(item, parent as ContainerLayout, index) + } + + removeEntry(state, container.id) + + console.debug("[layoutState] Ungrouped", containerEntry, parent, parentChildren, index) + + store.set(state) +} + function clear() { } @@ -214,7 +317,7 @@ function resetLayout() { // TODO } -const uiStateStore: WritableLayoutStateStore = +const layoutStateStore: WritableLayoutStateStore = { ...store, addContainer, @@ -223,7 +326,10 @@ const uiStateStore: WritableLayoutStateStore = updateChildren, nodeAdded, nodeRemoved, + getCurrentSelection, + groupItems, + ungroup, clear, resetLayout } -export default uiStateStore; +export default layoutStateStore;