feat(ui): fix layer arranging

This commit is contained in:
psychedelicious 2024-04-30 11:23:11 +10:00 committed by Kent Keirsey
parent d884c15d0c
commit e5ec529f0f
3 changed files with 54 additions and 45 deletions
invokeai/frontend/web/src/features/regionalPrompts

@ -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 (
<Flex flexDir="column" gap={4} w="full" h="full">
<Flex justifyContent="space-around">
@ -49,14 +26,8 @@ export const RegionalPromptsPanelContent = memo(() => {
</Flex>
<ScrollableContent>
<Flex flexDir="column" gap={4}>
{maskedGuidanceLayerIds.map((id) => (
<MaskedGuidanceLayerListItem key={id} layerId={id} />
))}
{controlNetLayerIds.map((id) => (
<ControlAdapterLayerListItem key={id} layerId={id} />
))}
{ipAdapterLayerIds.map((id) => (
<IPAdapterLayerListItem key={id} layerId={id} />
{layerIdTypePairs.map(({ id, type }) => (
<LayerWrapper key={id} id={id} type={type} />
))}
</Flex>
</ScrollableContent>
@ -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 <MaskedGuidanceLayerListItem key={id} layerId={id} />;
}
if (type === 'control_adapter_layer') {
return <ControlAdapterLayerListItem key={id} layerId={id} />;
}
if (type === 'ip_adapter_layer') {
return <IPAdapterLayerListItem key={id} layerId={id} />;
}
});
LayerWrapper.displayName = 'LayerWrapper';

@ -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;
};

@ -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<string>) => {
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<string>) => {
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<string>) => {
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<string>) => {
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);