From e5ec529f0fcabac342d4a982eccf284ab7d91ab2 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:23:11 +1000 Subject: [PATCH] feat(ui): fix layer arranging --- .../RegionalPromptsPanelContent.tsx | 62 ++++++++----------- .../regionalPrompts/hooks/layerStateHooks.ts | 19 ++++-- .../store/regionalPromptsSlice.ts | 18 ++++-- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/invokeai/frontend/web/src/features/regionalPrompts/components/RegionalPromptsPanelContent.tsx b/invokeai/frontend/web/src/features/regionalPrompts/components/RegionalPromptsPanelContent.tsx index df422a5336..1a73202986 100644 --- a/invokeai/frontend/web/src/features/regionalPrompts/components/RegionalPromptsPanelContent.tsx +++ b/invokeai/frontend/web/src/features/regionalPrompts/components/RegionalPromptsPanelContent.tsx @@ -8,39 +8,16 @@ import { ControlAdapterLayerListItem } from 'features/regionalPrompts/components import { DeleteAllLayersButton } from 'features/regionalPrompts/components/DeleteAllLayersButton'; import { IPAdapterLayerListItem } from 'features/regionalPrompts/components/IPAdapterLayerListItem'; import { MaskedGuidanceLayerListItem } from 'features/regionalPrompts/components/MaskedGuidanceLayerListItem'; -import { - isControlAdapterLayer, - isIPAdapterLayer, - isMaskedGuidanceLayer, - selectRegionalPromptsSlice, -} from 'features/regionalPrompts/store/regionalPromptsSlice'; +import { selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice'; +import type { Layer } from 'features/regionalPrompts/store/types'; import { memo } from 'react'; -const selectMaskedGuidanceLayerIds = createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => - regionalPrompts.present.layers - .filter(isMaskedGuidanceLayer) - .map((l) => l.id) - .reverse() -); - -const selectControlNetLayerIds = createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => - regionalPrompts.present.layers - .filter(isControlAdapterLayer) - .map((l) => l.id) - .reverse() -); - -const selectIPAdapterLayerIds = createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => - regionalPrompts.present.layers - .filter(isIPAdapterLayer) - .map((l) => l.id) - .reverse() +const selectLayerIdTypePairs = createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => + regionalPrompts.present.layers.map((l) => ({ id: l.id, type: l.type })).reverse() ); export const RegionalPromptsPanelContent = memo(() => { - const maskedGuidanceLayerIds = useAppSelector(selectMaskedGuidanceLayerIds); - const controlNetLayerIds = useAppSelector(selectControlNetLayerIds); - const ipAdapterLayerIds = useAppSelector(selectIPAdapterLayerIds); + const layerIdTypePairs = useAppSelector(selectLayerIdTypePairs); return ( @@ -49,14 +26,8 @@ export const RegionalPromptsPanelContent = memo(() => { - {maskedGuidanceLayerIds.map((id) => ( - - ))} - {controlNetLayerIds.map((id) => ( - - ))} - {ipAdapterLayerIds.map((id) => ( - + {layerIdTypePairs.map(({ id, type }) => ( + ))} @@ -65,3 +36,22 @@ export const RegionalPromptsPanelContent = memo(() => { }); RegionalPromptsPanelContent.displayName = 'RegionalPromptsPanelContent'; + +type LayerWrapperProps = { + id: string; + type: Layer['type']; +}; + +const LayerWrapper = memo(({ id, type }: LayerWrapperProps) => { + if (type === 'masked_guidance_layer') { + return ; + } + if (type === 'control_adapter_layer') { + return ; + } + if (type === 'ip_adapter_layer') { + return ; + } +}); + +LayerWrapper.displayName = 'LayerWrapper'; diff --git a/invokeai/frontend/web/src/features/regionalPrompts/hooks/layerStateHooks.ts b/invokeai/frontend/web/src/features/regionalPrompts/hooks/layerStateHooks.ts index 5ef1014dcc..a8fd34d50f 100644 --- a/invokeai/frontend/web/src/features/regionalPrompts/hooks/layerStateHooks.ts +++ b/invokeai/frontend/web/src/features/regionalPrompts/hooks/layerStateHooks.ts @@ -1,9 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; import { useAppSelector } from 'app/store/storeHooks'; -import { - isMaskedGuidanceLayer, - selectRegionalPromptsSlice, -} from 'features/regionalPrompts/store/regionalPromptsSlice'; +import { isMaskedGuidanceLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice'; import { useMemo } from 'react'; import { assert } from 'tsafe'; @@ -50,3 +47,17 @@ export const useLayerIsVisible = (layerId: string) => { const isVisible = useAppSelector(selectLayer); return isVisible; }; + +export const useLayerType = (layerId: string) => { + const selectLayer = useMemo( + () => + createSelector(selectRegionalPromptsSlice, (regionalPrompts) => { + const layer = regionalPrompts.present.layers.find((l) => l.id === layerId); + assert(layer, `Layer ${layerId} not found`); + return layer.type; + }), + [layerId] + ); + const type = useAppSelector(selectLayer); + return type; +}; diff --git a/invokeai/frontend/web/src/features/regionalPrompts/store/regionalPromptsSlice.ts b/invokeai/frontend/web/src/features/regionalPrompts/store/regionalPromptsSlice.ts index 4128cad637..2c982565f9 100644 --- a/invokeai/frontend/web/src/features/regionalPrompts/store/regionalPromptsSlice.ts +++ b/invokeai/frontend/web/src/features/regionalPrompts/store/regionalPromptsSlice.ts @@ -16,7 +16,7 @@ import { modelChanged } from 'features/parameters/store/generationSlice'; import type { ParameterAutoNegative } from 'features/parameters/types/parameterSchemas'; import { getIsSizeOptimal, getOptimalDimension } from 'features/parameters/util/optimalDimension'; import type { IRect, Vector2d } from 'konva/lib/types'; -import { isEqual } from 'lodash-es'; +import { isEqual, partition } from 'lodash-es'; import { atom } from 'nanostores'; import type { RgbColor } from 'react-colorful'; import type { UndoableOptions } from 'redux-undo'; @@ -183,21 +183,29 @@ export const regionalPromptsSlice = createSlice({ }, layerMovedForward: (state, action: PayloadAction) => { const cb = (l: Layer) => l.id === action.payload; - moveForward(state.layers, cb); + const [renderableLayers, ipAdapterLayers] = partition(state.layers, isRenderableLayer); + moveForward(renderableLayers, cb); + state.layers = [...ipAdapterLayers, ...renderableLayers]; }, layerMovedToFront: (state, action: PayloadAction) => { const cb = (l: Layer) => l.id === action.payload; + const [renderableLayers, ipAdapterLayers] = partition(state.layers, isRenderableLayer); // Because the layers are in reverse order, moving to the front is equivalent to moving to the back - moveToBack(state.layers, cb); + moveToBack(renderableLayers, cb); + state.layers = [...ipAdapterLayers, ...renderableLayers]; }, layerMovedBackward: (state, action: PayloadAction) => { const cb = (l: Layer) => l.id === action.payload; - moveBackward(state.layers, cb); + const [renderableLayers, ipAdapterLayers] = partition(state.layers, isRenderableLayer); + moveBackward(renderableLayers, cb); + state.layers = [...ipAdapterLayers, ...renderableLayers]; }, layerMovedToBack: (state, action: PayloadAction) => { const cb = (l: Layer) => l.id === action.payload; + const [renderableLayers, ipAdapterLayers] = partition(state.layers, isRenderableLayer); // Because the layers are in reverse order, moving to the back is equivalent to moving to the front - moveToFront(state.layers, cb); + moveToFront(renderableLayers, cb); + state.layers = [...ipAdapterLayers, ...renderableLayers]; }, selectedLayerReset: (state) => { const layer = state.layers.find((l) => l.id === state.selectedLayerId);