Two-way selection
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { Block, BlockTitle } from "@gradio/atoms";
|
||||
import Accordion from "$lib/components/gradio/app/Accordion.svelte";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import selectionState from "$lib/stores/selectionState";
|
||||
import WidgetContainer from "./WidgetContainer.svelte"
|
||||
|
||||
import { dndzone, SHADOW_ITEM_MARKER_PROPERTY_NAME, SHADOW_PLACEHOLDER_ITEM_ID } from 'svelte-dnd-action';
|
||||
@@ -61,9 +62,10 @@
|
||||
</script>
|
||||
|
||||
{#if container && children}
|
||||
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(container.id)}
|
||||
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
||||
class:hide-block={container.attrs.containerVariant === "hidden"}
|
||||
class:selected={$uiState.uiUnlocked && $layoutState.currentSelection.includes(container.id)}
|
||||
class:selected
|
||||
class:root-container={zIndex === 0}
|
||||
class:is-executing={container.isNodeExecuting}
|
||||
class:edit={edit}>
|
||||
@@ -120,6 +122,10 @@
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
&.selected {
|
||||
background: var(--comfy-container-selected-background-fill) !important;
|
||||
}
|
||||
|
||||
> :global(*) {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Block, BlockTitle } from "@gradio/atoms";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import selectionState from "$lib/stores/selectionState";
|
||||
import WidgetContainer from "./WidgetContainer.svelte"
|
||||
|
||||
import { dndzone, SHADOW_ITEM_MARKER_PROPERTY_NAME, SHADOW_PLACEHOLDER_ITEM_ID } from 'svelte-dnd-action';
|
||||
@@ -49,9 +50,10 @@
|
||||
</script>
|
||||
|
||||
{#if container && children}
|
||||
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(container.id)}
|
||||
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
||||
class:hide-block={container.attrs.containerVariant === "hidden"}
|
||||
class:selected={$uiState.uiUnlocked && $layoutState.currentSelection.includes(container.id)}
|
||||
class:selected
|
||||
class:root-container={zIndex === 0}
|
||||
class:is-executing={container.isNodeExecuting}
|
||||
class:mobile={isMobile}
|
||||
@@ -154,6 +156,10 @@
|
||||
.container {
|
||||
display: flex;
|
||||
|
||||
&.selected {
|
||||
background: var(--comfy-container-selected-background-fill) !important;
|
||||
}
|
||||
|
||||
> :global(*) {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { Checkbox, TextBox } from "@gradio/form"
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import layoutState from "$lib/stores/layoutState";
|
||||
import selectionState from "$lib/stores/selectionState";
|
||||
import { ImageViewer } from "$lib/ImageViewer";
|
||||
import type { ComfyAPIStatus } from "$lib/api";
|
||||
import { SvelteToast, toast } from '@zerodevx/svelte-toast'
|
||||
@@ -54,12 +55,12 @@
|
||||
|
||||
if (!$uiState.uiUnlocked) {
|
||||
app.lCanvas.deselectAllNodes();
|
||||
$layoutState.currentSelectionNodes = []
|
||||
$selectionState.currentSelectionNodes = []
|
||||
}
|
||||
}
|
||||
|
||||
$: if ($uiState.uiEditMode)
|
||||
$layoutState.currentSelection = []
|
||||
$selectionState.currentSelection = []
|
||||
|
||||
let graphSize = 0;
|
||||
let graphTransitioning = false;
|
||||
|
||||
@@ -92,7 +92,6 @@ export default class ComfyApp {
|
||||
dropZone: HTMLElement | null = null;
|
||||
nodeOutputs: Record<string, any> = {};
|
||||
|
||||
dragOverNode: LGraphNode | null = null;
|
||||
shiftDown: boolean = false;
|
||||
selectedGroupMoving: boolean = false;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { LGraphNode } from "@litegraph-ts/core"
|
||||
import layoutState, { type IDragItem, type WidgetLayout, ALL_ATTRIBUTES, type AttributesSpec } from "$lib/stores/layoutState"
|
||||
import uiState from "$lib/stores/uiState"
|
||||
import selectionState from "$lib/stores/selectionState"
|
||||
import { get, type Writable, writable } from "svelte/store"
|
||||
import type { ComfyWidgetNode } from "$lib/nodes";
|
||||
import ComfyNumberProperty from "./ComfyNumberProperty.svelte";
|
||||
@@ -17,8 +18,8 @@
|
||||
|
||||
$: refreshPropsPanel = $layoutState.refreshPropsPanel;
|
||||
|
||||
$: if ($layoutState.currentSelection.length > 0) {
|
||||
const targetId = $layoutState.currentSelection.slice(-1)[0]
|
||||
$: if ($selectionState.currentSelection.length > 0) {
|
||||
const targetId = $selectionState.currentSelection.slice(-1)[0]
|
||||
target = $layoutState.allItems[targetId].dragItem
|
||||
attrsChanged = target.attrsChanged;
|
||||
if (target.type === "widget") {
|
||||
@@ -28,9 +29,9 @@
|
||||
node = null;
|
||||
}
|
||||
}
|
||||
else if ($layoutState.currentSelectionNodes.length > 0) {
|
||||
else if ($selectionState.currentSelectionNodes.length > 0) {
|
||||
target = null;
|
||||
node = $layoutState.currentSelectionNodes[0]
|
||||
node = $selectionState.currentSelectionNodes[0]
|
||||
attrsChanged = null;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import WidgetContainer from "./WidgetContainer.svelte";
|
||||
import layoutState, { type ContainerLayout, type DragItem, type IDragItem } from "$lib/stores/layoutState";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import selectionState from "$lib/stores/selectionState";
|
||||
|
||||
import Menu from './menu/Menu.svelte';
|
||||
import MenuOption from './menu/MenuOption.svelte';
|
||||
@@ -30,18 +31,23 @@
|
||||
}
|
||||
|
||||
function groupWidgets(horizontal: boolean) {
|
||||
const items = layoutState.getCurrentSelection()
|
||||
$layoutState.currentSelection = []
|
||||
const items = $selectionState.currentSelection
|
||||
$selectionState.currentSelection = []
|
||||
layoutState.groupItems(items, { direction: horizontal ? "horizontal" : "vertical" })
|
||||
}
|
||||
|
||||
let canUngroup = false;
|
||||
let isDeleteGroup = false;
|
||||
$: canUngroup = $layoutState.currentSelection.length === 1
|
||||
&& layoutState.getCurrentSelection()[0].type === "container"
|
||||
$: {
|
||||
canUngroup = false;
|
||||
if ($selectionState.currentSelection.length === 1) {
|
||||
const item = $layoutState.allItems[$selectionState.currentSelection[0]].dragItem;
|
||||
canUngroup = item.type === "container"
|
||||
}
|
||||
}
|
||||
$: if (canUngroup) {
|
||||
const dragItem = layoutState.getCurrentSelection()[0];
|
||||
const entry = $layoutState.allItems[dragItem.id];
|
||||
const dragItemID = $selectionState.currentSelection[0];
|
||||
const entry = $layoutState.allItems[dragItemID];
|
||||
isDeleteGroup = entry.children.length === 0
|
||||
}
|
||||
else {
|
||||
@@ -49,11 +55,15 @@
|
||||
}
|
||||
|
||||
function ungroup() {
|
||||
const item = layoutState.getCurrentSelection()[0]
|
||||
if (!item || item.type !== "container")
|
||||
const itemID = $selectionState.currentSelection[0]
|
||||
if (itemID == null)
|
||||
return;
|
||||
|
||||
$layoutState.currentSelection = []
|
||||
const item = $layoutState.allItems[$selectionState.currentSelection[0]].dragItem;
|
||||
if(item.type !== "container")
|
||||
return
|
||||
|
||||
$selectionState.currentSelection = []
|
||||
layoutState.ungroup(item as ContainerLayout)
|
||||
}
|
||||
|
||||
@@ -94,11 +104,11 @@
|
||||
{#if showMenu}
|
||||
<Menu {...menuPos} on:click={closeMenu} on:clickoutside={closeMenu}>
|
||||
<MenuOption
|
||||
isDisabled={$layoutState.currentSelection.length === 0}
|
||||
isDisabled={$selectionState.currentSelection.length === 0}
|
||||
on:click={() => groupWidgets(false)}
|
||||
text="Group" />
|
||||
<MenuOption
|
||||
isDisabled={$layoutState.currentSelection.length === 0}
|
||||
isDisabled={$selectionState.currentSelection.length === 0}
|
||||
on:click={() => groupWidgets(true)}
|
||||
text="Group Horizontally" />
|
||||
<MenuOption
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Block, BlockTitle } from "@gradio/atoms";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import selectionState from "$lib/stores/selectionState";
|
||||
import WidgetContainer from "./WidgetContainer.svelte"
|
||||
import BlockContainer from "./BlockContainer.svelte"
|
||||
import AccordionContainer from "./AccordionContainer.svelte"
|
||||
@@ -34,7 +35,7 @@
|
||||
|
||||
{#if container}
|
||||
{@const edit = $uiState.uiUnlocked && $uiState.uiEditMode === "widgets" && zIndex > 1}
|
||||
{@const dragDisabled = zIndex === 0 || $layoutState.currentSelection.length > 2 || !$uiState.uiUnlocked}
|
||||
{@const dragDisabled = zIndex === 0 || $selectionState.currentSelection.length > 2 || !$uiState.uiUnlocked}
|
||||
{#key $attrsChanged}
|
||||
{#if edit || !isHidden(container)}
|
||||
{#if container.attrs.variant === "tabs"}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Block, BlockTitle } from "@gradio/atoms";
|
||||
import { Tabs, TabItem } from "@gradio/tabs";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import selectionState from "$lib/stores/selectionState";
|
||||
import WidgetContainer from "./WidgetContainer.svelte"
|
||||
|
||||
import { dndzone, SHADOW_ITEM_MARKER_PROPERTY_NAME, SHADOW_PLACEHOLDER_ITEM_ID } from 'svelte-dnd-action';
|
||||
@@ -68,9 +69,10 @@
|
||||
</script>
|
||||
|
||||
{#if container && children}
|
||||
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(container.id)}
|
||||
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
||||
class:hide-block={container.attrs.containerVariant === "hidden"}
|
||||
class:selected={$uiState.uiUnlocked && $layoutState.currentSelection.includes(container.id)}
|
||||
class:selected
|
||||
class:root-container={zIndex === 0}
|
||||
class:is-executing={container.isNodeExecuting}
|
||||
class:edit={edit}>
|
||||
@@ -133,6 +135,10 @@
|
||||
.container {
|
||||
display: flex;
|
||||
|
||||
&.selected {
|
||||
background: var(--comfy-container-selected-background-fill) !important;
|
||||
}
|
||||
|
||||
> :global(*) {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import uiState from "$lib/stores/uiState";
|
||||
|
||||
import layoutState, { type ContainerLayout, type WidgetLayout, type IDragItem } from "$lib/stores/layoutState";
|
||||
import selectionState from "$lib/stores/selectionState";
|
||||
import { startDrag, stopDrag } from "$lib/utils"
|
||||
import Container from "./Container.svelte"
|
||||
import { type Writable } from "svelte/store"
|
||||
@@ -67,21 +68,24 @@
|
||||
{:else if widget && widget.node}
|
||||
{@const edit = $uiState.uiUnlocked && $uiState.uiEditMode === "widgets" && zIndex > 1}
|
||||
{@const hidden = isHidden(widget)}
|
||||
{@const hovered = $uiState.uiUnlocked && $selectionState.currentHovered.has(widget.id)}
|
||||
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(widget.id)}
|
||||
{#key $attrsChanged}
|
||||
{#key $propsChanged}
|
||||
<div class="widget {widget.attrs.classes} {getWidgetClass()}"
|
||||
class:edit={edit}
|
||||
class:selected={$uiState.uiUnlocked && $layoutState.currentSelection.includes(widget.id)}
|
||||
class:is-executing={$queueState.runningNodeID && $queueState.runningNodeId == widget.node.id}
|
||||
class:hidden={hidden}
|
||||
>
|
||||
class:hovered
|
||||
class:selected
|
||||
class:is-executing={$queueState.runningNodeID && $queueState.runningNodeID == widget.node.id}
|
||||
class:hidden={hidden}
|
||||
>
|
||||
<svelte:component this={widget.node.svelteComponentType} {widget} {isMobile} />
|
||||
</div>
|
||||
{#if hidden && edit}
|
||||
<div class="handle handle-hidden" class:hidden={!edit} />
|
||||
{/if}
|
||||
{#if showHandles}
|
||||
<div class="handle handle-widget" data-drag-item-id={widget.id} on:mousedown={startDrag} on:touchstart={startDrag} on:mouseup={stopDrag} on:touchend={stopDrag}/>
|
||||
{#if showHandles || hovered}
|
||||
<div class="handle handle-widget" class:hovered data-drag-item-id={widget.id} on:mousedown={startDrag} on:touchstart={startDrag} on:mouseup={stopDrag} on:touchend={stopDrag}/>
|
||||
{/if}
|
||||
{/key}
|
||||
{/key}
|
||||
@@ -92,12 +96,9 @@
|
||||
height: 100%;
|
||||
|
||||
&.selected {
|
||||
background: var(--color-yellow-200);
|
||||
background: var(--comfy-widget-selected-background-fill);
|
||||
}
|
||||
}
|
||||
.container.selected {
|
||||
background: var(--color-yellow-400);
|
||||
}
|
||||
|
||||
.is-executing {
|
||||
border: 3px dashed var(--color-green-600) !important;
|
||||
@@ -123,8 +124,10 @@
|
||||
background-color: #40404080;
|
||||
}
|
||||
|
||||
.handle-widget:hover {
|
||||
background-color: #add8e680;
|
||||
.handle-widget {
|
||||
&:hover, &.hovered {
|
||||
background-color: #add8e680;
|
||||
}
|
||||
}
|
||||
|
||||
.node-type {
|
||||
|
||||
Reference in New Issue
Block a user