Drag and drop

This commit is contained in:
space-nuko
2023-04-05 02:14:32 -05:00
parent d464538c93
commit dbe65fa98c
4 changed files with 177 additions and 76 deletions

View File

@@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
import { Pane, Splitpanes } from 'svelte-splitpanes'; import { Pane, Splitpanes } from 'svelte-splitpanes';
import { Button } from "@gradio/button";
import { Backpack, Gear } from 'radix-icons-svelte'; import { Backpack, Gear } from 'radix-icons-svelte';
import ComfyUIPane from "./ComfyUIPane.svelte"; import ComfyUIPane from "./ComfyUIPane.svelte";
import ComfyApp from "./ComfyApp"; import ComfyApp from "./ComfyApp";
@@ -14,6 +15,24 @@
app.resizeCanvas(); app.resizeCanvas();
} }
function queuePrompt() {
const state = uiPane.getState();
console.log("Queuing!", state);
app.queuePrompt(0, 1, state);
}
let graphSize = null;
function toggleGraph() {
if (graphSize == 0) {
graphSize = 100;
app.resizeCanvas();
}
else {
graphSize = 0;
}
}
onMount(async () => { onMount(async () => {
app = new ComfyApp(); app = new ComfyApp();
@@ -53,13 +72,21 @@
<Pane minSize={15}> <Pane minSize={15}>
<ComfyUIPane bind:this={uiPane} {app} /> <ComfyUIPane bind:this={uiPane} {app} />
</Pane> </Pane>
<Pane minSize={10}> <Pane snapSize={10} bind:size={graphSize}>
<canvas id="graph-canvas" /> <canvas id="graph-canvas" />
</Pane> </Pane>
</Splitpanes> </Splitpanes>
</Pane> </Pane>
</Splitpanes> </Splitpanes>
</div> </div>
<div id="bottombar">
<Button variant="primary" on:click={queuePrompt}>
Run
</Button>
<Button variant="secondary" on:click={toggleGraph}>
Show/Hide Graph
</Button>
</div>
<style> <style>
#container { #container {
@@ -84,6 +111,10 @@
height: 100%; height: 100%;
} }
#bottombar {
margin: 10px;
}
.dropzone { .dropzone {
box-sizing: border-box; box-sizing: border-box;
display: none; display: none;

View File

@@ -0,0 +1,119 @@
<script lang="ts">
import { Button } from "@gradio/button";
import { Block, BlockTitle } from "@gradio/atoms";
import { Dropdown, Range, TextBox } from "@gradio/form";
import { dndzone } from 'svelte-dnd-action';
import { flip } from 'svelte/animate';
export let state: Record<number, any[]> = {};
export let items: Record<number, { node: LGraphNode, widget: IWidget }[]> = {};
export let dragItems = [];
let dragDisabled = true;
const flipDurationMs = 200;
const handleConsider = evt => {
dragItems = evt.detail.items;
// console.log(dragItems);
};
const handleFinalize = evt => {
dragItems = evt.detail.items;
// Ensure dragging is stopped on drag finish
dragDisabled = true;
};
const startDrag = () => {
dragDisabled = false;
};
const stopDrag = () => {
dragDisabled = true;
};
</script>
<div class="v-pane"
use:dndzone="{{ items: dragItems, dragDisabled, flipDurationMs }}"
on:consider="{handleConsider}"
on:finalize="{handleFinalize}"
>
{#each dragItems as dragItem(dragItem.id)}
{@const node = dragItem.node}
{@const id = node.id}
<Block>
<div class="handle" on:mousedown={startDrag} on:touchstart={startDrag} on:mouseup={stopDrag} on:touchend={stopDrag}/>
<label for={id}>
<BlockTitle>{node.title}</BlockTitle>
</label>
{#each items[id] as item, i}
{#if item.widget.type == "combo"}
<div class="wrapper">
<Dropdown
bind:value={state[id][i]}
choices={item.widget.options.values}
multiselect={false}
max_choices={1},
label={item.widget.name}
show_label={true}
disabled={item.widget.options.values.length === 0}
on:change
on:select
on:blur
/>
</div>
{:else if item.widget.type == "number"}
<div class="wrapper">
<Range
bind:value={state[id][i]}
minimum={item.widget.options.min}
maximum={item.widget.options.max}
step={item.widget.options.step}
label={item.widget.name}
show_label={true}
on:change
on:release
/>
</div>
{:else if item.widget.type == "text"}
<div class="wrapper">
<TextBox
bind:value={state[id][i]}
label={item.widget.name}
lines={item.widget.options.multiline ? 5 : 1}
show_label={true}
on:change
on:submit
on:blur
on:select
/>
</div>
{/if}
{/each}
</Block>
{/each}
</div>
<style>
.v-pane {
border: 1px solid grey;
float: left;
height: 100%;
overflow: auto;
position: relative;
width: 33%;
}
.handle {
cursor: grab;
position: absolute;
right: 0;
width: 1em;
height: 0.5em;
background-color: grey;
}
.wrapper {
padding: 10px;
width: 100%;
}
</style>

View File

@@ -1,22 +1,26 @@
<script lang="ts"> <script lang="ts">
import { Button } from "@gradio/button";
import { Block, BlockTitle } from "@gradio/atoms";
import { Dropdown, Range, TextBox } from "@gradio/form";
import { LGraphNode, LGraph } from "litegraph.js"; import { LGraphNode, LGraph } from "litegraph.js";
import type { IWidget } from "litegraph.js"; import type { IWidget } from "litegraph.js";
import ComfyApp from "./ComfyApp"; import ComfyApp from "./ComfyApp";
import ComfyPane from "./ComfyPane.svelte";
export let app: ComfyApp; export let app: ComfyApp;
let dragItems = [];
export function clear() { export function clear() {
nodes = {}; nodes = {};
items = {}; items = {};
state = {}; state = {};
dragItems = []
} }
export function addNodeUI(node: LGraphNode) { export function addNodeUI(node: LGraphNode) {
if (node.widgets) { if (node.widgets) {
for (const [i, widget] of node.widgets.entries()) { for (const [i, widget] of node.widgets.entries()) {
if (!nodes[node.id]) {
dragItems.push({ id: node.id, node: node })
}
nodes[node.id] = node; nodes[node.id] = node;
node.onPropertyChanged = (k, v) => { node.onPropertyChanged = (k, v) => {
@@ -45,6 +49,9 @@
delete state[node.id] delete state[node.id]
delete items[node.id] delete items[node.id]
dragItems = Array.from(dragItems.filter(e => e.id != node.id));
console.log("REM", node.id, dragItems)
nodes = nodes; nodes = nodes;
items = items; items = items;
state = state; state = state;
@@ -63,13 +70,8 @@
state = state; state = state;
} }
function getState() { export function getState() {
return state;
}
function queuePrompt() {
console.log("Queuing!", state);
app.queuePrompt(0, 1, state);
} }
let nodes: Record<number, LGraphNode> = {}; let nodes: Record<number, LGraphNode> = {};
@@ -77,70 +79,10 @@
let state: Record<number, any[]> = {}; let state: Record<number, any[]> = {};
</script> </script>
<div id="comfy-ui-panes"> <div id="comfy-ui-panes" >
<div class="v-pane"> <ComfyPane {dragItems} {items} {state} />
{#each Object.keys(items) as id} <ComfyPane {items} {state} />
{@const node = nodes[id]} <ComfyPane {items} {state} />
<Block>
<label for={id}>
<BlockTitle>{node.title}</BlockTitle>
</label>
{#each items[id] as item, i}
{#if item.widget.type == "combo"}
<div class="wrapper">
<Dropdown
bind:value={state[id][i]}
choices={item.widget.options.values}
multiselect={false}
max_choices={1},
label={item.widget.name}
show_label={true}
disabled={item.widget.options.values.length === 0}
on:change
on:select
on:blur
/>
</div>
{:else if item.widget.type == "number"}
<div class="wrapper">
<Range
bind:value={state[id][i]}
minimum={item.widget.options.min}
maximum={item.widget.options.max}
step={item.widget.options.step}
label={item.widget.name}
show_label={true}
on:change
on:release
/>
</div>
{:else if item.widget.type == "text"}
<div class="wrapper">
<TextBox
bind:value={state[id][i]}
label={item.widget.name}
lines={item.widget.options.multiline ? 5 : 1}
show_label={true}
on:change
on:submit
on:blur
on:select
/>
</div>
{/if}
{/each}
</Block>
{/each}
</div>
<div class="v-pane">
</div>
<div class="v-pane">
<div class="wrapper">
<Button variant="primary" on:click={queuePrompt}>
Run
</Button>
</div>
</div>
</div> </div>
<style> <style>
@@ -158,6 +100,15 @@
width: 33%; width: 33%;
} }
.handle {
cursor: grab;
position: absolute;
right: 0;
width: 1em;
height: 0.5em;
background-color: grey;
}
.wrapper { .wrapper {
padding: 10px; padding: 10px;
width: 100%; width: 100%;

View File

@@ -5,7 +5,7 @@ import FullReload from 'vite-plugin-full-reload'
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
sveltekit() sveltekit()
// FullReload(["src/**/*.{js,ts,svelte}"]) FullReload(["src/**/*.{js,ts,svelte}"])
], ],
build: { build: {
sourcemap: true, sourcemap: true,