mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
refactor(ui): divvy up canvas state a bit
This commit is contained in:
parent
0c9cf73702
commit
14d0bfbef6
@ -124,7 +124,7 @@ const createSelector = (templates: Templates) =>
|
||||
reasons.push({ content: i18n.t('parameters.invoke.noModelSelected') });
|
||||
}
|
||||
|
||||
canvasV2.controlAdapters
|
||||
canvasV2.controlAdapters.entities
|
||||
.filter((ca) => ca.isEnabled)
|
||||
.forEach((ca, i) => {
|
||||
const layerLiteral = i18n.t('controlLayers.layers_one');
|
||||
@ -160,7 +160,7 @@ const createSelector = (templates: Templates) =>
|
||||
}
|
||||
});
|
||||
|
||||
canvasV2.ipAdapters
|
||||
canvasV2.ipAdapters.entities
|
||||
.filter((ipa) => ipa.isEnabled)
|
||||
.forEach((ipa, i) => {
|
||||
const layerLiteral = i18n.t('controlLayers.layers_one');
|
||||
@ -188,7 +188,7 @@ const createSelector = (templates: Templates) =>
|
||||
}
|
||||
});
|
||||
|
||||
canvasV2.regions
|
||||
canvasV2.regions.entities
|
||||
.filter((rg) => rg.isEnabled)
|
||||
.forEach((rg, i) => {
|
||||
const layerLiteral = i18n.t('controlLayers.layers_one');
|
||||
@ -225,7 +225,7 @@ const createSelector = (templates: Templates) =>
|
||||
}
|
||||
});
|
||||
|
||||
canvasV2.layers
|
||||
canvasV2.layers.entities
|
||||
.filter((l) => l.isEnabled)
|
||||
.forEach((l, i) => {
|
||||
const layerLiteral = i18n.t('controlLayers.layers_one');
|
||||
@ -234,13 +234,6 @@ const createSelector = (templates: Templates) =>
|
||||
const prefix = `${layerLiteral} #${layerNumber} (${layerType})`;
|
||||
const problems: string[] = [];
|
||||
|
||||
// if (l.type === 'initial_image_layer') {
|
||||
// // Must have an image
|
||||
// if (!l.image) {
|
||||
// problems.push(i18n.t('parameters.invoke.layer.initialImageNoImageSelected'));
|
||||
// }
|
||||
// }
|
||||
|
||||
if (problems.length) {
|
||||
const content = upperFirst(problems.join(', '));
|
||||
reasons.push({ prefix, content });
|
||||
|
@ -21,8 +21,8 @@ export const AddPromptButtons = ({ id }: AddPromptButtonProps) => {
|
||||
const [addIPAdapter, isAddIPAdapterDisabled] = useAddIPAdapterToRGLayer(id);
|
||||
const selectValidActions = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectCanvasV2Slice, (caState) => {
|
||||
const rg = caState.regions.find((rg) => rg.id === id);
|
||||
createMemoizedSelector(selectCanvasV2Slice, (canvasV2) => {
|
||||
const rg = canvasV2.regions.entities.find((rg) => rg.id === id);
|
||||
return {
|
||||
canAddPositivePrompt: rg?.positivePrompt === null,
|
||||
canAddNegativePrompt: rg?.negativePrompt === null,
|
||||
|
@ -32,8 +32,8 @@ export const CAActionsMenu = memo(({ id }: Props) => {
|
||||
() =>
|
||||
createMemoizedSelector(selectCanvasV2Slice, (canvasV2) => {
|
||||
const ca = selectCAOrThrow(canvasV2, id);
|
||||
const caIndex = canvasV2.controlAdapters.indexOf(ca);
|
||||
const caCount = canvasV2.controlAdapters.length;
|
||||
const caIndex = canvasV2.controlAdapters.entities.indexOf(ca);
|
||||
const caCount = canvasV2.controlAdapters.entities.length;
|
||||
return {
|
||||
canMoveForward: caIndex < caCount - 1,
|
||||
canMoveBackward: caIndex > 0,
|
||||
|
@ -15,11 +15,11 @@ import { selectCanvasV2Slice } from 'features/controlLayers/store/canvasV2Slice'
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selectEntityIds = createMemoizedSelector(selectCanvasV2Slice, (canvasV2State) => {
|
||||
const rgIds = canvasV2State.regions.map(mapId).reverse();
|
||||
const caIds = canvasV2State.controlAdapters.map(mapId).reverse();
|
||||
const ipaIds = canvasV2State.ipAdapters.map(mapId).reverse();
|
||||
const layerIds = canvasV2State.layers.map(mapId).reverse();
|
||||
const selectEntityIds = createMemoizedSelector(selectCanvasV2Slice, (canvasV2) => {
|
||||
const rgIds = canvasV2.regions.entities.map(mapId).reverse();
|
||||
const caIds = canvasV2.controlAdapters.entities.map(mapId).reverse();
|
||||
const ipaIds = canvasV2.ipAdapters.entities.map(mapId).reverse();
|
||||
const layerIds = canvasV2.layers.entities.map(mapId).reverse();
|
||||
const entityCount = rgIds.length + caIds.length + ipaIds.length + layerIds.length;
|
||||
return { rgIds, caIds, ipaIds, layerIds, entityCount };
|
||||
});
|
||||
|
@ -10,10 +10,10 @@ export const DeleteAllLayersButton = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const entityCount = useAppSelector((s) => {
|
||||
return (
|
||||
s.canvasV2.regions.length +
|
||||
s.canvasV2.controlAdapters.length +
|
||||
s.canvasV2.ipAdapters.length +
|
||||
s.canvasV2.layers.length
|
||||
s.canvasV2.regions.entities.length +
|
||||
s.canvasV2.controlAdapters.entities.length +
|
||||
s.canvasV2.ipAdapters.entities.length +
|
||||
s.canvasV2.layers.entities.length
|
||||
);
|
||||
});
|
||||
const onClick = useCallback(() => {
|
||||
|
@ -32,8 +32,8 @@ export const LayerActionsMenu = memo(({ id }: Props) => {
|
||||
() =>
|
||||
createMemoizedSelector(selectCanvasV2Slice, (canvasV2) => {
|
||||
const layer = selectLayerOrThrow(canvasV2, id);
|
||||
const layerIndex = canvasV2.layers.indexOf(layer);
|
||||
const layerCount = canvasV2.layers.length;
|
||||
const layerIndex = canvasV2.layers.entities.indexOf(layer);
|
||||
const layerCount = canvasV2.layers.entities.length;
|
||||
return {
|
||||
canMoveForward: layerIndex < layerCount - 1,
|
||||
canMoveBackward: layerIndex > 0,
|
||||
|
@ -39,8 +39,8 @@ export const RGActionsMenu = memo(({ id }: Props) => {
|
||||
() =>
|
||||
createMemoizedSelector(selectCanvasV2Slice, (canvasV2) => {
|
||||
const rg = selectRGOrThrow(canvasV2, id);
|
||||
const rgIndex = canvasV2.regions.indexOf(rg);
|
||||
const rgCount = canvasV2.regions.length;
|
||||
const rgIndex = canvasV2.regions.entities.indexOf(rg);
|
||||
const rgCount = canvasV2.regions.entities.length;
|
||||
return {
|
||||
isMoveForwardOneDisabled: rgIndex < rgCount - 1,
|
||||
isMoveBackardOneDisabled: rgIndex > 0,
|
||||
|
@ -170,13 +170,13 @@ export const initializeRenderer = (
|
||||
if (!identifier) {
|
||||
selectedEntity = null;
|
||||
} else if (identifier.type === 'layer') {
|
||||
selectedEntity = canvasV2.layers.find((i) => i.id === identifier.id) ?? null;
|
||||
selectedEntity = canvasV2.layers.entities.find((i) => i.id === identifier.id) ?? null;
|
||||
} else if (identifier.type === 'control_adapter') {
|
||||
selectedEntity = canvasV2.controlAdapters.find((i) => i.id === identifier.id) ?? null;
|
||||
selectedEntity = canvasV2.controlAdapters.entities.find((i) => i.id === identifier.id) ?? null;
|
||||
} else if (identifier.type === 'ip_adapter') {
|
||||
selectedEntity = canvasV2.ipAdapters.find((i) => i.id === identifier.id) ?? null;
|
||||
selectedEntity = canvasV2.ipAdapters.entities.find((i) => i.id === identifier.id) ?? null;
|
||||
} else if (identifier.type === 'regional_guidance') {
|
||||
selectedEntity = canvasV2.regions.find((i) => i.id === identifier.id) ?? null;
|
||||
selectedEntity = canvasV2.regions.entities.find((i) => i.id === identifier.id) ?? null;
|
||||
} else {
|
||||
selectedEntity = null;
|
||||
}
|
||||
@ -304,23 +304,23 @@ export const initializeRenderer = (
|
||||
|
||||
if (
|
||||
isFirstRender ||
|
||||
canvasV2.layers !== prevCanvasV2.layers ||
|
||||
canvasV2.layers.entities !== prevCanvasV2.layers.entities ||
|
||||
canvasV2.tool.selected !== prevCanvasV2.tool.selected
|
||||
) {
|
||||
logIfDebugging('Rendering layers');
|
||||
renderLayers(manager, canvasV2.layers, canvasV2.tool.selected, onPosChanged);
|
||||
renderLayers(manager, canvasV2.layers.entities, canvasV2.tool.selected, onPosChanged);
|
||||
}
|
||||
|
||||
if (
|
||||
isFirstRender ||
|
||||
canvasV2.regions !== prevCanvasV2.regions ||
|
||||
canvasV2.regions.entities !== prevCanvasV2.regions.entities ||
|
||||
canvasV2.settings.maskOpacity !== prevCanvasV2.settings.maskOpacity ||
|
||||
canvasV2.tool.selected !== prevCanvasV2.tool.selected
|
||||
) {
|
||||
logIfDebugging('Rendering regions');
|
||||
renderRegions(
|
||||
manager,
|
||||
canvasV2.regions,
|
||||
canvasV2.regions.entities,
|
||||
canvasV2.settings.maskOpacity,
|
||||
canvasV2.tool.selected,
|
||||
canvasV2.selectedEntityIdentifier,
|
||||
@ -328,9 +328,9 @@ export const initializeRenderer = (
|
||||
);
|
||||
}
|
||||
|
||||
if (isFirstRender || canvasV2.controlAdapters !== prevCanvasV2.controlAdapters) {
|
||||
if (isFirstRender || canvasV2.controlAdapters.entities !== prevCanvasV2.controlAdapters.entities) {
|
||||
logIfDebugging('Rendering control adapters');
|
||||
renderControlAdapters(manager, canvasV2.controlAdapters);
|
||||
renderControlAdapters(manager, canvasV2.controlAdapters.entities);
|
||||
}
|
||||
|
||||
if (isFirstRender || canvasV2.document !== prevCanvasV2.document) {
|
||||
@ -355,12 +355,12 @@ export const initializeRenderer = (
|
||||
|
||||
if (
|
||||
isFirstRender ||
|
||||
canvasV2.layers !== prevCanvasV2.layers ||
|
||||
canvasV2.controlAdapters !== prevCanvasV2.controlAdapters ||
|
||||
canvasV2.regions !== prevCanvasV2.regions
|
||||
canvasV2.layers.entities !== prevCanvasV2.layers.entities ||
|
||||
canvasV2.controlAdapters.entities !== prevCanvasV2.controlAdapters.entities ||
|
||||
canvasV2.regions.entities !== prevCanvasV2.regions.entities
|
||||
) {
|
||||
logIfDebugging('Arranging entities');
|
||||
arrangeEntities(manager, canvasV2.layers, canvasV2.controlAdapters, canvasV2.regions);
|
||||
arrangeEntities(manager, canvasV2.layers.entities, canvasV2.controlAdapters.entities, canvasV2.regions.entities);
|
||||
}
|
||||
|
||||
prevCanvasV2 = canvasV2;
|
||||
|
@ -16,18 +16,17 @@ import { toolReducers } from 'features/controlLayers/store/toolReducers';
|
||||
import { initialAspectRatioState } from 'features/parameters/components/ImageSize/constants';
|
||||
import type { AspectRatioState } from 'features/parameters/components/ImageSize/types';
|
||||
import { atom } from 'nanostores';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
|
||||
import type { CanvasEntityIdentifier, CanvasV2State, StageAttrs } from './types';
|
||||
import { DEFAULT_RGBA_COLOR, imageDTOToImageWithDims } from './types';
|
||||
import { DEFAULT_RGBA_COLOR } from './types';
|
||||
|
||||
const initialState: CanvasV2State = {
|
||||
_version: 3,
|
||||
selectedEntityIdentifier: null,
|
||||
layers: [],
|
||||
controlAdapters: [],
|
||||
ipAdapters: [],
|
||||
regions: [],
|
||||
layers: { entities: [], baseLayerImageCache: null },
|
||||
controlAdapters: { entities: [] },
|
||||
ipAdapters: { entities: [] },
|
||||
regions: { entities: [] },
|
||||
loras: [],
|
||||
inpaintMask: {
|
||||
bbox: null,
|
||||
@ -120,7 +119,6 @@ const initialState: CanvasV2State = {
|
||||
refinerNegativeAestheticScore: 2.5,
|
||||
refinerStart: 0.8,
|
||||
},
|
||||
baseLayerImageCache: null,
|
||||
};
|
||||
|
||||
export const canvasV2Slice = createSlice({
|
||||
@ -162,14 +160,11 @@ export const canvasV2Slice = createSlice({
|
||||
state.selectedEntityIdentifier = action.payload;
|
||||
},
|
||||
allEntitiesDeleted: (state) => {
|
||||
state.regions = [];
|
||||
state.layers = [];
|
||||
state.ipAdapters = [];
|
||||
state.controlAdapters = [];
|
||||
state.baseLayerImageCache = null;
|
||||
},
|
||||
baseLayerImageCacheChanged: (state, action: PayloadAction<ImageDTO | null>) => {
|
||||
state.baseLayerImageCache = action.payload ? imageDTOToImageWithDims(action.payload) : null;
|
||||
state.regions.entities = [];
|
||||
state.layers.entities = [];
|
||||
state.layers.baseLayerImageCache = null;
|
||||
state.ipAdapters.entities = [];
|
||||
state.controlAdapters.entities = [];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ import type {
|
||||
} from './types';
|
||||
import { buildControlAdapterProcessorV2, imageDTOToImageObject } from './types';
|
||||
|
||||
export const selectCA = (state: CanvasV2State, id: string) => state.controlAdapters.find((ca) => ca.id === id);
|
||||
export const selectCA = (state: CanvasV2State, id: string) => state.controlAdapters.entities.find((ca) => ca.id === id);
|
||||
export const selectCAOrThrow = (state: CanvasV2State, id: string) => {
|
||||
const ca = selectCA(state, id);
|
||||
assert(ca, `Control Adapter with id ${id} not found`);
|
||||
@ -31,7 +31,7 @@ export const controlAdaptersReducers = {
|
||||
caAdded: {
|
||||
reducer: (state, action: PayloadAction<{ id: string; config: ControlNetConfig | T2IAdapterConfig }>) => {
|
||||
const { id, config } = action.payload;
|
||||
state.controlAdapters.push({
|
||||
state.controlAdapters.entities.push({
|
||||
id,
|
||||
type: 'control_adapter',
|
||||
x: 0,
|
||||
@ -52,7 +52,7 @@ export const controlAdaptersReducers = {
|
||||
},
|
||||
caRecalled: (state, action: PayloadAction<{ data: ControlAdapterEntity }>) => {
|
||||
const { data } = action.payload;
|
||||
state.controlAdapters.push(data);
|
||||
state.controlAdapters.entities.push(data);
|
||||
state.selectedEntityIdentifier = { type: 'control_adapter', id: data.id };
|
||||
},
|
||||
caIsEnabledToggled: (state, action: PayloadAction<{ id: string }>) => {
|
||||
@ -83,10 +83,10 @@ export const controlAdaptersReducers = {
|
||||
},
|
||||
caDeleted: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
state.controlAdapters = state.controlAdapters.filter((ca) => ca.id !== id);
|
||||
state.controlAdapters.entities = state.controlAdapters.entities.filter((ca) => ca.id !== id);
|
||||
},
|
||||
caAllDeleted: (state) => {
|
||||
state.controlAdapters = [];
|
||||
state.controlAdapters.entities = [];
|
||||
},
|
||||
caOpacityChanged: (state, action: PayloadAction<{ id: string; opacity: number }>) => {
|
||||
const { id, opacity } = action.payload;
|
||||
@ -102,7 +102,7 @@ export const controlAdaptersReducers = {
|
||||
if (!ca) {
|
||||
return;
|
||||
}
|
||||
moveOneToEnd(state.controlAdapters, ca);
|
||||
moveOneToEnd(state.controlAdapters.entities, ca);
|
||||
},
|
||||
caMovedToFront: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -110,7 +110,7 @@ export const controlAdaptersReducers = {
|
||||
if (!ca) {
|
||||
return;
|
||||
}
|
||||
moveToEnd(state.controlAdapters, ca);
|
||||
moveToEnd(state.controlAdapters.entities, ca);
|
||||
},
|
||||
caMovedBackwardOne: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -118,7 +118,7 @@ export const controlAdaptersReducers = {
|
||||
if (!ca) {
|
||||
return;
|
||||
}
|
||||
moveOneToStart(state.controlAdapters, ca);
|
||||
moveOneToStart(state.controlAdapters.entities, ca);
|
||||
},
|
||||
caMovedToBack: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -126,7 +126,7 @@ export const controlAdaptersReducers = {
|
||||
if (!ca) {
|
||||
return;
|
||||
}
|
||||
moveToStart(state.controlAdapters, ca);
|
||||
moveToStart(state.controlAdapters.entities, ca);
|
||||
},
|
||||
caImageChanged: {
|
||||
reducer: (state, action: PayloadAction<{ id: string; imageDTO: ImageDTO | null; objectId: string }>) => {
|
||||
@ -195,11 +195,11 @@ export const controlAdaptersReducers = {
|
||||
// We may need to convert the CA to match the model
|
||||
if (ca.adapterType === 't2i_adapter' && ca.model.type === 'controlnet') {
|
||||
const convertedCA: ControlNetData = { ...ca, adapterType: 'controlnet', controlMode: 'balanced' };
|
||||
state.controlAdapters.splice(state.controlAdapters.indexOf(ca), 1, convertedCA);
|
||||
state.controlAdapters.entities.splice(state.controlAdapters.entities.indexOf(ca), 1, convertedCA);
|
||||
} else if (ca.adapterType === 'controlnet' && ca.model.type === 't2i_adapter') {
|
||||
const { controlMode: _, ...rest } = ca;
|
||||
const convertedCA: T2IAdapterData = { ...rest, adapterType: 't2i_adapter' };
|
||||
state.controlAdapters.splice(state.controlAdapters.indexOf(ca), 1, convertedCA);
|
||||
state.controlAdapters.entities.splice(state.controlAdapters.entities.indexOf(ca), 1, convertedCA);
|
||||
}
|
||||
},
|
||||
caControlModeChanged: (state, action: PayloadAction<{ id: string; controlMode: ControlModeV2 }>) => {
|
||||
|
@ -13,7 +13,7 @@ import type {
|
||||
} from './types';
|
||||
import { imageDTOToImageObject } from './types';
|
||||
|
||||
export const selectIPA = (state: CanvasV2State, id: string) => state.ipAdapters.find((ipa) => ipa.id === id);
|
||||
export const selectIPA = (state: CanvasV2State, id: string) => state.ipAdapters.entities.find((ipa) => ipa.id === id);
|
||||
export const selectIPAOrThrow = (state: CanvasV2State, id: string) => {
|
||||
const ipa = selectIPA(state, id);
|
||||
assert(ipa, `IP Adapter with id ${id} not found`);
|
||||
@ -30,14 +30,14 @@ export const ipAdaptersReducers = {
|
||||
isEnabled: true,
|
||||
...config,
|
||||
};
|
||||
state.ipAdapters.push(layer);
|
||||
state.ipAdapters.entities.push(layer);
|
||||
state.selectedEntityIdentifier = { type: 'ip_adapter', id };
|
||||
},
|
||||
prepare: (payload: { config: IPAdapterConfig }) => ({ payload: { id: uuidv4(), ...payload } }),
|
||||
},
|
||||
ipaRecalled: (state, action: PayloadAction<{ data: IPAdapterEntity }>) => {
|
||||
const { data } = action.payload;
|
||||
state.ipAdapters.push(data);
|
||||
state.ipAdapters.entities.push(data);
|
||||
state.selectedEntityIdentifier = { type: 'ip_adapter', id: data.id };
|
||||
},
|
||||
ipaIsEnabledToggled: (state, action: PayloadAction<{ id: string }>) => {
|
||||
@ -49,10 +49,10 @@ export const ipAdaptersReducers = {
|
||||
},
|
||||
ipaDeleted: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
state.ipAdapters = state.ipAdapters.filter((ipa) => ipa.id !== id);
|
||||
state.ipAdapters.entities = state.ipAdapters.entities.filter((ipa) => ipa.id !== id);
|
||||
},
|
||||
ipaAllDeleted: (state) => {
|
||||
state.ipAdapters = [];
|
||||
state.ipAdapters.entities = [];
|
||||
},
|
||||
ipaImageChanged: {
|
||||
reducer: (state, action: PayloadAction<{ id: string; imageDTO: ImageDTO | null; objectId: string }>) => {
|
||||
|
@ -2,6 +2,7 @@ import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
||||
import { moveOneToEnd, moveOneToStart, moveToEnd, moveToStart } from 'common/util/arrayUtils';
|
||||
import { getBrushLineId, getEraserLineId, getRectShapeId } from 'features/controlLayers/konva/naming';
|
||||
import type { IRect } from 'konva/lib/types';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
import { assert } from 'tsafe';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
@ -14,9 +15,9 @@ import type {
|
||||
PointAddedToLineArg,
|
||||
RectShapeAddedArg,
|
||||
} from './types';
|
||||
import { imageDTOToImageObject, isLine } from './types';
|
||||
import { imageDTOToImageObject, imageDTOToImageWithDims, isLine } from './types';
|
||||
|
||||
export const selectLayer = (state: CanvasV2State, id: string) => state.layers.find((layer) => layer.id === id);
|
||||
export const selectLayer = (state: CanvasV2State, id: string) => state.layers.entities.find((layer) => layer.id === id);
|
||||
export const selectLayerOrThrow = (state: CanvasV2State, id: string) => {
|
||||
const layer = selectLayer(state, id);
|
||||
assert(layer, `Layer with id ${id} not found`);
|
||||
@ -27,7 +28,7 @@ export const layersReducers = {
|
||||
layerAdded: {
|
||||
reducer: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
state.layers.push({
|
||||
state.layers.entities.push({
|
||||
id,
|
||||
type: 'layer',
|
||||
isEnabled: true,
|
||||
@ -39,15 +40,15 @@ export const layersReducers = {
|
||||
y: 0,
|
||||
});
|
||||
state.selectedEntityIdentifier = { type: 'layer', id };
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
prepare: () => ({ payload: { id: uuidv4() } }),
|
||||
},
|
||||
layerRecalled: (state, action: PayloadAction<{ data: LayerEntity }>) => {
|
||||
const { data } = action.payload;
|
||||
state.layers.push(data);
|
||||
state.layers.entities.push(data);
|
||||
state.selectedEntityIdentifier = { type: 'layer', id: data.id };
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerIsEnabledToggled: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -56,7 +57,7 @@ export const layersReducers = {
|
||||
return;
|
||||
}
|
||||
layer.isEnabled = !layer.isEnabled;
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerTranslated: (state, action: PayloadAction<{ id: string; x: number; y: number }>) => {
|
||||
const { id, x, y } = action.payload;
|
||||
@ -66,7 +67,7 @@ export const layersReducers = {
|
||||
}
|
||||
layer.x = x;
|
||||
layer.y = y;
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerBboxChanged: (state, action: PayloadAction<{ id: string; bbox: IRect | null }>) => {
|
||||
const { id, bbox } = action.payload;
|
||||
@ -92,16 +93,16 @@ export const layersReducers = {
|
||||
layer.objects = [];
|
||||
layer.bbox = null;
|
||||
layer.bboxNeedsUpdate = false;
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerDeleted: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
state.layers = state.layers.filter((l) => l.id !== id);
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.entities = state.layers.entities.filter((l) => l.id !== id);
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerAllDeleted: (state) => {
|
||||
state.layers = [];
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.entities = [];
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerOpacityChanged: (state, action: PayloadAction<{ id: string; opacity: number }>) => {
|
||||
const { id, opacity } = action.payload;
|
||||
@ -110,7 +111,7 @@ export const layersReducers = {
|
||||
return;
|
||||
}
|
||||
layer.opacity = opacity;
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerMovedForwardOne: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -118,8 +119,8 @@ export const layersReducers = {
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
moveOneToEnd(state.layers, layer);
|
||||
state.baseLayerImageCache = null;
|
||||
moveOneToEnd(state.layers.entities, layer);
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerMovedToFront: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -127,8 +128,8 @@ export const layersReducers = {
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
moveToEnd(state.layers, layer);
|
||||
state.baseLayerImageCache = null;
|
||||
moveToEnd(state.layers.entities, layer);
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerMovedBackwardOne: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -136,8 +137,8 @@ export const layersReducers = {
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
moveOneToStart(state.layers, layer);
|
||||
state.baseLayerImageCache = null;
|
||||
moveOneToStart(state.layers.entities, layer);
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerMovedToBack: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -145,8 +146,8 @@ export const layersReducers = {
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
moveToStart(state.layers, layer);
|
||||
state.baseLayerImageCache = null;
|
||||
moveToStart(state.layers.entities, layer);
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerBrushLineAdded: {
|
||||
reducer: (state, action: PayloadAction<BrushLineAddedArg & { lineId: string }>) => {
|
||||
@ -165,7 +166,7 @@ export const layersReducers = {
|
||||
clip,
|
||||
});
|
||||
layer.bboxNeedsUpdate = true;
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
prepare: (payload: BrushLineAddedArg) => ({
|
||||
payload: { ...payload, lineId: uuidv4() },
|
||||
@ -187,7 +188,7 @@ export const layersReducers = {
|
||||
clip,
|
||||
});
|
||||
layer.bboxNeedsUpdate = true;
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
prepare: (payload: EraserLineAddedArg) => ({
|
||||
payload: { ...payload, lineId: uuidv4() },
|
||||
@ -205,7 +206,7 @@ export const layersReducers = {
|
||||
}
|
||||
lastObject.points.push(...point);
|
||||
layer.bboxNeedsUpdate = true;
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
layerRectAdded: {
|
||||
reducer: (state, action: PayloadAction<RectShapeAddedArg & { rectId: string }>) => {
|
||||
@ -225,7 +226,7 @@ export const layersReducers = {
|
||||
color,
|
||||
});
|
||||
layer.bboxNeedsUpdate = true;
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
prepare: (payload: RectShapeAddedArg) => ({ payload: { ...payload, rectId: uuidv4() } }),
|
||||
},
|
||||
@ -238,8 +239,11 @@ export const layersReducers = {
|
||||
}
|
||||
layer.objects.push(imageDTOToImageObject(id, objectId, imageDTO));
|
||||
layer.bboxNeedsUpdate = true;
|
||||
state.baseLayerImageCache = null;
|
||||
state.layers.baseLayerImageCache = null;
|
||||
},
|
||||
prepare: (payload: ImageObjectAddedArg) => ({ payload: { ...payload, objectId: uuidv4() } }),
|
||||
},
|
||||
baseLayerImageCacheChanged: (state, action: PayloadAction<ImageDTO | null>) => {
|
||||
state.layers.baseLayerImageCache = action.payload ? imageDTOToImageWithDims(action.payload) : null;
|
||||
},
|
||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
||||
|
@ -26,7 +26,7 @@ import type {
|
||||
} from './types';
|
||||
import { isLine } from './types';
|
||||
|
||||
export const selectRG = (state: CanvasV2State, id: string) => state.regions.find((rg) => rg.id === id);
|
||||
export const selectRG = (state: CanvasV2State, id: string) => state.regions.entities.find((rg) => rg.id === id);
|
||||
export const selectRGOrThrow = (state: CanvasV2State, id: string) => {
|
||||
const rg = selectRG(state, id);
|
||||
assert(rg, `Region with id ${id} not found`);
|
||||
@ -44,7 +44,7 @@ const DEFAULT_MASK_COLORS: RgbColor[] = [
|
||||
];
|
||||
|
||||
const getRGMaskFill = (state: CanvasV2State): RgbColor => {
|
||||
const lastFill = state.regions.slice(-1)[0]?.fill;
|
||||
const lastFill = state.regions.entities.slice(-1)[0]?.fill;
|
||||
let i = DEFAULT_MASK_COLORS.findIndex((c) => isEqual(c, lastFill));
|
||||
if (i === -1) {
|
||||
i = 0;
|
||||
@ -75,7 +75,7 @@ export const regionsReducers = {
|
||||
ipAdapters: [],
|
||||
imageCache: null,
|
||||
};
|
||||
state.regions.push(rg);
|
||||
state.regions.entities.push(rg);
|
||||
state.selectedEntityIdentifier = { type: 'regional_guidance', id };
|
||||
},
|
||||
prepare: () => ({ payload: { id: uuidv4() } }),
|
||||
@ -93,7 +93,7 @@ export const regionsReducers = {
|
||||
},
|
||||
rgRecalled: (state, action: PayloadAction<{ data: RegionEntity }>) => {
|
||||
const { data } = action.payload;
|
||||
state.regions.push(data);
|
||||
state.regions.entities.push(data);
|
||||
state.selectedEntityIdentifier = { type: 'regional_guidance', id: data.id };
|
||||
},
|
||||
rgIsEnabledToggled: (state, action: PayloadAction<{ id: string }>) => {
|
||||
@ -121,10 +121,10 @@ export const regionsReducers = {
|
||||
},
|
||||
rgDeleted: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
state.regions = state.regions.filter((ca) => ca.id !== id);
|
||||
state.regions.entities = state.regions.entities.filter((ca) => ca.id !== id);
|
||||
},
|
||||
rgAllDeleted: (state) => {
|
||||
state.regions = [];
|
||||
state.regions.entities = [];
|
||||
},
|
||||
rgMovedForwardOne: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -132,7 +132,7 @@ export const regionsReducers = {
|
||||
if (!rg) {
|
||||
return;
|
||||
}
|
||||
moveOneToEnd(state.regions, rg);
|
||||
moveOneToEnd(state.regions.entities, rg);
|
||||
},
|
||||
rgMovedToFront: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -140,7 +140,7 @@ export const regionsReducers = {
|
||||
if (!rg) {
|
||||
return;
|
||||
}
|
||||
moveToEnd(state.regions, rg);
|
||||
moveToEnd(state.regions.entities, rg);
|
||||
},
|
||||
rgMovedBackwardOne: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -148,7 +148,7 @@ export const regionsReducers = {
|
||||
if (!rg) {
|
||||
return;
|
||||
}
|
||||
moveOneToStart(state.regions, rg);
|
||||
moveOneToStart(state.regions.entities, rg);
|
||||
},
|
||||
rgMovedToBack: (state, action: PayloadAction<{ id: string }>) => {
|
||||
const { id } = action.payload;
|
||||
@ -156,7 +156,7 @@ export const regionsReducers = {
|
||||
if (!rg) {
|
||||
return;
|
||||
}
|
||||
moveToStart(state.regions, rg);
|
||||
moveToStart(state.regions.entities, rg);
|
||||
},
|
||||
rgPositivePromptChanged: (state, action: PayloadAction<{ id: string; prompt: string | null }>) => {
|
||||
const { id, prompt } = action.payload;
|
||||
|
@ -4,7 +4,10 @@ import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
||||
|
||||
export const selectEntityCount = createSelector(selectCanvasV2Slice, (canvasV2) => {
|
||||
return (
|
||||
canvasV2.regions.length + canvasV2.controlAdapters.length + canvasV2.ipAdapters.length + canvasV2.layers.length
|
||||
canvasV2.regions.entities.length +
|
||||
canvasV2.controlAdapters.entities.length +
|
||||
canvasV2.ipAdapters.entities.length +
|
||||
canvasV2.layers.entities.length
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -796,10 +796,13 @@ export type CanvasV2State = {
|
||||
_version: 3;
|
||||
selectedEntityIdentifier: CanvasEntityIdentifier | null;
|
||||
inpaintMask: InpaintMaskEntity;
|
||||
layers: LayerEntity[];
|
||||
controlAdapters: ControlAdapterEntity[];
|
||||
ipAdapters: IPAdapterEntity[];
|
||||
regions: RegionEntity[];
|
||||
layers: {
|
||||
baseLayerImageCache: ImageWithDims | null;
|
||||
entities: LayerEntity[];
|
||||
};
|
||||
controlAdapters: { entities: ControlAdapterEntity[] };
|
||||
ipAdapters: { entities: IPAdapterEntity[] };
|
||||
regions: { entities: RegionEntity[] };
|
||||
loras: LoRA[];
|
||||
tool: {
|
||||
selected: Tool;
|
||||
@ -872,7 +875,6 @@ export type CanvasV2State = {
|
||||
refinerNegativeAestheticScore: number;
|
||||
refinerStart: number;
|
||||
};
|
||||
baseLayerImageCache: ImageWithDims | null;
|
||||
};
|
||||
|
||||
export type StageAttrs = { x: number; y: number; width: number; height: number; scale: number };
|
||||
|
@ -11,7 +11,7 @@ import { some } from 'lodash-es';
|
||||
import type { ImageUsage } from './types';
|
||||
|
||||
export const getImageUsage = (nodes: NodesState, canvasV2: CanvasV2State, image_name: string) => {
|
||||
const isLayerImage = canvasV2.layers.some((layer) =>
|
||||
const isLayerImage = canvasV2.layers.entities.some((layer) =>
|
||||
layer.objects.some((obj) => obj.type === 'image' && obj.image.name === image_name)
|
||||
);
|
||||
|
||||
@ -21,11 +21,11 @@ export const getImageUsage = (nodes: NodesState, canvasV2: CanvasV2State, image_
|
||||
some(node.data.inputs, (input) => isImageFieldInputInstance(input) && input.value?.image_name === image_name)
|
||||
);
|
||||
|
||||
const isControlAdapterImage = canvasV2.controlAdapters.some(
|
||||
(ca) => ca.image?.name === image_name || ca.processedImage?.name === image_name
|
||||
const isControlAdapterImage = canvasV2.controlAdapters.entities.some(
|
||||
(ca) => ca.imageObject?.image.name === image_name || ca.processedImageObject?.image.name === image_name
|
||||
);
|
||||
|
||||
const isIPAdapterImage = canvasV2.ipAdapters.some((ipa) => ipa.imageObject?.name === image_name);
|
||||
const isIPAdapterImage = canvasV2.ipAdapters.entities.some((ipa) => ipa.imageObject?.image.name === image_name);
|
||||
|
||||
const imageUsage: ImageUsage = {
|
||||
isLayerImage,
|
||||
|
@ -78,13 +78,13 @@ const getBaseLayer = async (layers: LayerEntity[], bbox: IRect, preview: boolean
|
||||
export const getBaseLayerImage = async (): Promise<ImageDTO> => {
|
||||
const { dispatch, getState } = getStore();
|
||||
const state = getState();
|
||||
if (state.canvasV2.baseLayerImageCache) {
|
||||
const imageDTO = await getImageDTO(state.canvasV2.baseLayerImageCache.name);
|
||||
if (state.canvasV2.layers.baseLayerImageCache) {
|
||||
const imageDTO = await getImageDTO(state.canvasV2.layers.baseLayerImageCache.name);
|
||||
if (imageDTO) {
|
||||
return imageDTO;
|
||||
}
|
||||
}
|
||||
const blob = await getBaseLayer(state.canvasV2.layers, state.canvasV2.bbox, true);
|
||||
const blob = await getBaseLayer(state.canvasV2.layers.entities, state.canvasV2.bbox, true);
|
||||
const file = new File([blob], 'image.png', { type: 'image/png' });
|
||||
const req = dispatch(
|
||||
imagesApi.endpoints.uploadImage.initiate({ file, image_category: 'general', is_intermediate: true })
|
||||
|
@ -156,10 +156,10 @@ export const buildGenerationTabGraph = async (state: RootState): Promise<GraphTy
|
||||
const vaeSource = seamless ?? vaeLoader ?? modelLoader;
|
||||
g.addEdge(vaeSource, 'vae', l2i, 'vae');
|
||||
|
||||
const _addedCAs = addControlAdapters(state.canvasV2.controlAdapters, g, denoise, modelConfig.base);
|
||||
const _addedIPAs = addIPAdapters(state.canvasV2.ipAdapters, g, denoise, modelConfig.base);
|
||||
const _addedCAs = addControlAdapters(state.canvasV2.controlAdapters.entities, g, denoise, modelConfig.base);
|
||||
const _addedIPAs = addIPAdapters(state.canvasV2.ipAdapters.entities, g, denoise, modelConfig.base);
|
||||
const _addedRegions = await addRegions(
|
||||
state.canvasV2.regions,
|
||||
state.canvasV2.regions.entities,
|
||||
g,
|
||||
state.canvasV2.document,
|
||||
state.canvasV2.bbox,
|
||||
|
@ -152,10 +152,10 @@ export const buildGenerationTabSDXLGraph = async (state: RootState): Promise<Non
|
||||
await addSDXLRefiner(state, g, denoise, seamless, posCond, negCond, l2i);
|
||||
}
|
||||
|
||||
const _addedCAs = addControlAdapters(state.canvasV2.controlAdapters, g, denoise, modelConfig.base);
|
||||
const _addedIPAs = addIPAdapters(state.canvasV2.ipAdapters, g, denoise, modelConfig.base);
|
||||
const _addedCAs = addControlAdapters(state.canvasV2.controlAdapters.entities, g, denoise, modelConfig.base);
|
||||
const _addedIPAs = addIPAdapters(state.canvasV2.ipAdapters.entities, g, denoise, modelConfig.base);
|
||||
const _addedRegions = await addRegions(
|
||||
state.canvasV2.regions,
|
||||
state.canvasV2.regions.entities,
|
||||
g,
|
||||
state.canvasV2.document,
|
||||
state.canvasV2.bbox,
|
||||
|
@ -5,6 +5,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
||||
import { ControlLayersPanelContent } from 'features/controlLayers/components/ControlLayersPanelContent';
|
||||
import { $isPreviewVisible } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { selectEntityCount } from 'features/controlLayers/store/selectors';
|
||||
import { isImageViewerOpenChanged } from 'features/gallery/store/gallerySlice';
|
||||
import { Prompts } from 'features/parameters/components/Prompts/Prompts';
|
||||
import QueueControls from 'features/queue/components/QueueControls';
|
||||
@ -41,7 +42,7 @@ const selectedStyles: ChakraProps['sx'] = {
|
||||
const ParametersPanelTextToImage = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const controlLayersCount = useAppSelector((s) => s.canvasV2.layers.length);
|
||||
const controlLayersCount = useAppSelector(selectEntityCount);
|
||||
const controlLayersTitle = useMemo(() => {
|
||||
if (controlLayersCount === 0) {
|
||||
return t('controlLayers.controlLayers');
|
||||
|
Loading…
Reference in New Issue
Block a user