feat(ui): revise internal state for RCC

This commit is contained in:
psychedelicious 2024-04-26 16:56:07 +10:00 committed by Kent Keirsey
parent 2f6fec8c6c
commit 6f5f3381f9
42 changed files with 170 additions and 155 deletions

View File

@ -28,7 +28,7 @@ export const addDynamicPromptsListener = (startAppListening: AppStartListening)
effect: async (action, { dispatch, getState, cancelActiveListeners, delay }) => {
cancelActiveListeners();
const state = getState();
const { positivePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt } = state.regionalPrompts.present;
const { maxPrompts } = state.dynamicPrompts;
if (state.config.disabledFeatures.includes('dynamicPrompting')) {

View File

@ -29,7 +29,7 @@ const selector = createMemoizedSelector(
],
(controlAdapters, generation, system, nodes, dynamicPrompts, regionalPrompts, activeTabName) => {
const { initialImage, model } = generation;
const { positivePrompt } = regionalPrompts.present.baseLayer;
const { positivePrompt } = regionalPrompts.present;
const { isConnected } = system;

View File

@ -2,7 +2,7 @@ import type { RootState } from 'app/store/store';
import { selectValidIPAdapters } from 'features/controlAdapters/store/controlAdaptersSlice';
import type { IPAdapterConfig } from 'features/controlAdapters/store/types';
import type { ImageField } from 'features/nodes/types/common';
import { isVectorMaskLayer } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { isMaskedGuidanceLayer } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { differenceBy } from 'lodash-es';
import type {
CollectInvocation,
@ -29,7 +29,7 @@ export const addIPAdapterToLinearGraph = async (
});
const regionalIPAdapterIds = state.regionalPrompts.present.layers
.filter(isVectorMaskLayer)
.filter(isMaskedGuidanceLayer)
.map((l) => l.ipAdapterIds)
.flat();

View File

@ -13,7 +13,7 @@ import {
PROMPT_REGION_POSITIVE_COND_INVERTED_PREFIX,
PROMPT_REGION_POSITIVE_COND_PREFIX,
} from 'features/nodes/util/graph/constants';
import { isVectorMaskLayer } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { isMaskedGuidanceLayer } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { getRegionalPromptLayerBlobs } from 'features/regionalPrompts/util/getLayerBlobs';
import { size } from 'lodash-es';
import { imagesApi } from 'services/api/endpoints/images';
@ -29,7 +29,7 @@ export const addRegionalPromptsToGraph = async (state: RootState, graph: NonNull
const layers = state.regionalPrompts.present.layers
// Only support vector mask layers now
// TODO: Image masks
.filter(isVectorMaskLayer)
.filter(isMaskedGuidanceLayer)
// Only visible layers are rendered on the canvas
.filter((l) => l.isVisible)
// Only layers with prompts get added to the graph

View File

@ -55,7 +55,7 @@ export const buildCanvasImageToImageGraph = async (
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
// The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions;

View File

@ -64,7 +64,7 @@ export const buildCanvasInpaintGraph = async (
canvasCoherenceEdgeSize,
maskBlur,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
if (!model) {
log.error('No model found in state');

View File

@ -76,7 +76,7 @@ export const buildCanvasOutpaintGraph = async (
canvasCoherenceEdgeSize,
maskBlur,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
if (!model) {
log.error('No model found in state');

View File

@ -55,7 +55,7 @@ export const buildCanvasSDXLImageToImageGraph = async (
seamlessYAxis,
img2imgStrength: strength,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
const { refinerModel, refinerStart } = state.sdxl;

View File

@ -64,7 +64,7 @@ export const buildCanvasSDXLInpaintGraph = async (
canvasCoherenceEdgeSize,
maskBlur,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
const { refinerModel, refinerStart } = state.sdxl;

View File

@ -76,7 +76,7 @@ export const buildCanvasSDXLOutpaintGraph = async (
canvasCoherenceEdgeSize,
maskBlur,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
const { refinerModel, refinerStart } = state.sdxl;

View File

@ -44,7 +44,7 @@ export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
// The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions;

View File

@ -44,7 +44,7 @@ export const buildCanvasTextToImageGraph = async (state: RootState): Promise<Non
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
// The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions;

View File

@ -10,7 +10,7 @@ import { getHasMetadata, removeMetadata } from './metadata';
export const prepareLinearUIBatch = (state: RootState, graph: NonNullableGraph, prepend: boolean): BatchConfig => {
const { iterations, model, shouldRandomizeSeed, seed } = state.generation;
const { shouldConcatPrompts } = state.regionalPrompts.present.baseLayer;
const { shouldConcatPrompts } = state.regionalPrompts.present;
const { prompts, seedBehaviour } = state.dynamicPrompts;
const data: Batch['data'] = [];

View File

@ -53,7 +53,7 @@ export const buildLinearImageToImageGraph = async (state: RootState): Promise<No
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
const { width, height } = state.regionalPrompts.present.size;
/**

View File

@ -53,7 +53,7 @@ export const buildLinearSDXLImageToImageGraph = async (state: RootState): Promis
seamlessYAxis,
img2imgStrength: strength,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
const { width, height } = state.regionalPrompts.present.size;
const { refinerModel, refinerStart } = state.sdxl;

View File

@ -41,7 +41,7 @@ export const buildLinearSDXLTextToImageGraph = async (state: RootState): Promise
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
const { width, height } = state.regionalPrompts.present.size;
const { refinerModel, refinerStart } = state.sdxl;

View File

@ -42,7 +42,7 @@ export const buildLinearTextToImageGraph = async (state: RootState): Promise<Non
seamlessYAxis,
seed,
} = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present;
const { width, height } = state.regionalPrompts.present.size;
const use_cpu = shouldUseCpuNoise;

View File

@ -18,7 +18,7 @@ export const getBoardField = (state: RootState): BoardField | undefined => {
*/
export const getSDXLStylePrompts = (state: RootState): { positiveStylePrompt: string; negativeStylePrompt: string } => {
const { positivePrompt, negativePrompt, positivePrompt2, negativePrompt2, shouldConcatPrompts } =
state.regionalPrompts.present.baseLayer;
state.regionalPrompts.present;
return {
positiveStylePrompt: shouldConcatPrompts ? positivePrompt : positivePrompt2,

View File

@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next';
export const ParamNegativePrompt = memo(() => {
const dispatch = useAppDispatch();
const prompt = useAppSelector((s) => s.regionalPrompts.present.baseLayer.negativePrompt);
const prompt = useAppSelector((s) => s.regionalPrompts.present.negativePrompt);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const { t } = useTranslation();
const _onChange = useCallback(

View File

@ -14,7 +14,7 @@ import { useTranslation } from 'react-i18next';
export const ParamPositivePrompt = memo(() => {
const dispatch = useAppDispatch();
const prompt = useAppSelector((s) => s.regionalPrompts.present.baseLayer.positivePrompt);
const prompt = useAppSelector((s) => s.regionalPrompts.present.positivePrompt);
const baseModel = useAppSelector((s) => s.generation.model)?.base;
const textareaRef = useRef<HTMLTextAreaElement>(null);

View File

@ -14,7 +14,7 @@ const selectPromptsCount = createSelector(
selectRegionalPromptsSlice,
selectDynamicPromptsSlice,
(regionalPrompts, dynamicPrompts) =>
getShouldProcessPrompt(regionalPrompts.present.baseLayer.positivePrompt) ? dynamicPrompts.prompts.length : 1
getShouldProcessPrompt(regionalPrompts.present.positivePrompt) ? dynamicPrompts.prompts.length : 1
);
type Props = {

View File

@ -9,7 +9,7 @@ export const AddLayerButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const onClick = useCallback(() => {
dispatch(layerAdded('vector_mask_layer'));
dispatch(layerAdded('masked_guidance_layer'));
}, [dispatch]);
return (

View File

@ -2,7 +2,7 @@ import { Button, Flex } from '@invoke-ai/ui-library';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import {
isVectorMaskLayer,
isMaskedGuidanceLayer,
maskLayerIPAdapterAdded,
maskLayerNegativePromptChanged,
maskLayerPositivePromptChanged,
@ -23,7 +23,7 @@ export const AddPromptButtons = ({ layerId }: AddPromptButtonProps) => {
() =>
createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
assert(isVectorMaskLayer(layer), `Layer ${layerId} not found or not an RP layer`);
assert(isMaskedGuidanceLayer(layer), `Layer ${layerId} not found or not an RP layer`);
return {
canAddPositivePrompt: layer.positivePrompt === null,
canAddNegativePrompt: layer.negativePrompt === null,

View File

@ -2,7 +2,7 @@ import { Checkbox, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import {
isVectorMaskLayer,
isMaskedGuidanceLayer,
maskLayerAutoNegativeChanged,
selectRegionalPromptsSlice,
} from 'features/regionalPrompts/store/regionalPromptsSlice';
@ -20,7 +20,7 @@ const useAutoNegative = (layerId: string) => {
() =>
createSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
assert(isVectorMaskLayer(layer), `Layer ${layerId} not found or not an RP layer`);
assert(isMaskedGuidanceLayer(layer), `Layer ${layerId} not found or not an RP layer`);
return layer.autoNegative;
}),
[layerId]

View File

@ -4,7 +4,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import RgbColorPicker from 'common/components/RgbColorPicker';
import { rgbColorToString } from 'features/canvas/util/colorToString';
import {
isVectorMaskLayer,
isMaskedGuidanceLayer,
maskLayerPreviewColorChanged,
selectRegionalPromptsSlice,
} from 'features/regionalPrompts/store/regionalPromptsSlice';
@ -23,7 +23,7 @@ export const RPLayerColorPicker = memo(({ layerId }: Props) => {
() =>
createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
assert(isVectorMaskLayer(layer), `Layer ${layerId} not found or not an vector mask layer`);
assert(isMaskedGuidanceLayer(layer), `Layer ${layerId} not found or not an vector mask layer`);
return layer.previewColor;
}),
[layerId]

View File

@ -2,7 +2,7 @@ import { Flex } from '@invoke-ai/ui-library';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppSelector } from 'app/store/storeHooks';
import ControlAdapterConfig from 'features/controlAdapters/components/ControlAdapterConfig';
import { isVectorMaskLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { isMaskedGuidanceLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { memo, useMemo } from 'react';
import { assert } from 'tsafe';
@ -14,7 +14,7 @@ export const RPLayerIPAdapterList = memo(({ layerId }: Props) => {
const selectIPAdapterIds = useMemo(
() =>
createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
const layer = regionalPrompts.present.layers.filter(isVectorMaskLayer).find((l) => l.id === layerId);
const layer = regionalPrompts.present.layers.filter(isMaskedGuidanceLayer).find((l) => l.id === layerId);
assert(layer, `Layer ${layerId} not found`);
return layer.ipAdapterIds;
}),

View File

@ -11,7 +11,7 @@ import { RPLayerPositivePrompt } from 'features/regionalPrompts/components/RPLay
import RPLayerSettingsPopover from 'features/regionalPrompts/components/RPLayerSettingsPopover';
import { RPLayerVisibilityToggle } from 'features/regionalPrompts/components/RPLayerVisibilityToggle';
import {
isVectorMaskLayer,
isMaskedGuidanceLayer,
layerSelected,
selectRegionalPromptsSlice,
} from 'features/regionalPrompts/store/regionalPromptsSlice';
@ -32,7 +32,7 @@ export const RPLayerListItem = memo(({ layerId }: Props) => {
() =>
createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
assert(isVectorMaskLayer(layer), `Layer ${layerId} not found or not an RP layer`);
assert(isMaskedGuidanceLayer(layer), `Layer ${layerId} not found or not an RP layer`);
return {
color: rgbColorToString(layer.previewColor),
hasPositivePrompt: layer.positivePrompt !== null,

View File

@ -2,7 +2,7 @@ import { IconButton, Menu, MenuButton, MenuDivider, MenuItem, MenuList } from '@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import {
isVectorMaskLayer,
isMaskedGuidanceLayer,
layerDeleted,
layerMovedBackward,
layerMovedForward,
@ -37,7 +37,7 @@ export const RPLayerMenu = memo(({ layerId }: Props) => {
() =>
createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
assert(isVectorMaskLayer(layer), `Layer ${layerId} not found or not an RP layer`);
assert(isMaskedGuidanceLayer(layer), `Layer ${layerId} not found or not an RP layer`);
const layerIndex = regionalPrompts.present.layers.findIndex((l) => l.id === layerId);
const layerCount = regionalPrompts.present.layers.length;
return {

View File

@ -6,12 +6,12 @@ import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableCon
import { AddLayerButton } from 'features/regionalPrompts/components/AddLayerButton';
import { DeleteAllLayersButton } from 'features/regionalPrompts/components/DeleteAllLayersButton';
import { RPLayerListItem } from 'features/regionalPrompts/components/RPLayerListItem';
import { isVectorMaskLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { isMaskedGuidanceLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { memo } from 'react';
const selectRPLayerIdsReversed = createMemoizedSelector(selectRegionalPromptsSlice, (regionalPrompts) =>
regionalPrompts.present.layers
.filter(isVectorMaskLayer)
.filter(isMaskedGuidanceLayer)
.map((l) => l.id)
.reverse()
);

View File

@ -9,7 +9,7 @@ import {
$isMouseOver,
$lastMouseDownPos,
$tool,
isVectorMaskLayer,
isMaskedGuidanceLayer,
layerBboxChanged,
layerSelected,
layerTranslated,
@ -32,7 +32,7 @@ const selectSelectedLayerColor = createMemoizedSelector(selectRegionalPromptsSli
if (!layer) {
return null;
}
assert(isVectorMaskLayer(layer), `Layer ${regionalPrompts.present.selectedLayerId} is not an RP layer`);
assert(isMaskedGuidanceLayer(layer), `Layer ${regionalPrompts.present.selectedLayerId} is not an RP layer`);
return layer.previewColor;
});

View File

@ -41,7 +41,7 @@ export const ToolChooser: React.FC = () => {
useHotkeys('shift+c', resetSelectedLayer);
const addLayer = useCallback(() => {
dispatch(layerAdded('vector_mask_layer'));
dispatch(layerAdded('masked_guidance_layer'));
}, [dispatch]);
useHotkeys('shift+a', addLayer);

View File

@ -1,6 +1,6 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { isVectorMaskLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { isMaskedGuidanceLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { useMemo } from 'react';
import { assert } from 'tsafe';
@ -9,7 +9,7 @@ export const useLayerPositivePrompt = (layerId: string) => {
() =>
createSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
assert(isVectorMaskLayer(layer), `Layer ${layerId} not found or not an RP layer`);
assert(isMaskedGuidanceLayer(layer), `Layer ${layerId} not found or not an RP layer`);
assert(layer.positivePrompt !== null, `Layer ${layerId} does not have a positive prompt`);
return layer.positivePrompt;
}),
@ -24,7 +24,7 @@ export const useLayerNegativePrompt = (layerId: string) => {
() =>
createSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
assert(isVectorMaskLayer(layer), `Layer ${layerId} not found or not an RP layer`);
assert(isMaskedGuidanceLayer(layer), `Layer ${layerId} not found or not an RP layer`);
assert(layer.negativePrompt !== null, `Layer ${layerId} does not have a negative prompt`);
return layer.negativePrompt;
}),
@ -39,7 +39,7 @@ export const useLayerIsVisible = (layerId: string) => {
() =>
createSelector(selectRegionalPromptsSlice, (regionalPrompts) => {
const layer = regionalPrompts.present.layers.find((l) => l.id === layerId);
assert(isVectorMaskLayer(layer), `Layer ${layerId} not found or not an RP layer`);
assert(isMaskedGuidanceLayer(layer), `Layer ${layerId} not found or not an RP layer`);
return layer.isVisible;
}),
[layerId]

View File

@ -1,6 +1,6 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { isVectorMaskLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { isMaskedGuidanceLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@ -9,7 +9,7 @@ const selectValidLayerCount = createSelector(selectRegionalPromptsSlice, (region
return 0;
}
const validLayers = regionalPrompts.present.layers
.filter(isVectorMaskLayer)
.filter(isMaskedGuidanceLayer)
.filter((l) => l.isVisible)
.filter((l) => {
const hasTextPrompt = Boolean(l.positivePrompt || l.negativePrompt);

View File

@ -5,7 +5,6 @@ import { moveBackward, moveForward, moveToBack, moveToFront } from 'common/util/
import { deepClone } from 'common/util/deepClone';
import { roundToMultiple } from 'common/util/roundDownToMultiple';
import { controlAdapterRemoved, isAnyControlAdapterAdded } from 'features/controlAdapters/store/controlAdaptersSlice';
import type { ControlAdapterConfig } from 'features/controlAdapters/store/types';
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
import { initialAspectRatioState } from 'features/parameters/components/ImageSize/constants';
import type { AspectRatioState } from 'features/parameters/components/ImageSize/types';
@ -51,41 +50,38 @@ export type VectorMaskRect = {
type LayerBase = {
id: string;
isVisible: boolean;
};
type RenderableLayerBase = LayerBase & {
x: number;
y: number;
bbox: IRect | null;
bboxNeedsUpdate: boolean;
isVisible: boolean;
};
type ControlLayer = LayerBase & {
type: 'control_layer';
controlAdapter: ControlAdapterConfig;
type ControlAdapterLayer = RenderableLayerBase & {
type: 'controlnet_layer'; // technically, also t2i adapter layer
controlAdapterId: string;
};
type MaskLayerBase = LayerBase & {
positivePrompt: string | null;
negativePrompt: string | null; // Up to one text prompt per mask
type IPAdapterLayer = LayerBase & {
type: 'ip_adapter_layer'; // technically, also t2i adapter layer
ipAdapterId: string;
};
export type MaskedGuidanceLayer = RenderableLayerBase & {
type: 'masked_guidance_layer';
maskObjects: (VectorMaskLine | VectorMaskRect)[];
positivePrompt: ParameterPositivePrompt | null;
negativePrompt: ParameterNegativePrompt | null; // Up to one text prompt per mask
ipAdapterIds: string[]; // Any number of image prompts
previewColor: RgbColor;
autoNegative: ParameterAutoNegative;
needsPixelBbox: boolean; // Needs the slower pixel-based bbox calculation - set to true when an there is an eraser object
};
export type VectorMaskLayer = MaskLayerBase & {
type: 'vector_mask_layer';
objects: (VectorMaskLine | VectorMaskRect)[];
};
export type Layer = VectorMaskLayer | ControlLayer;
type BaseLayerState = {
positivePrompt: ParameterPositivePrompt;
negativePrompt: ParameterNegativePrompt;
positivePrompt2: ParameterPositiveStylePromptSDXL;
negativePrompt2: ParameterNegativeStylePromptSDXL;
shouldConcatPrompts: boolean;
};
export type Layer = MaskedGuidanceLayer | ControlAdapterLayer | IPAdapterLayer;
type RegionalPromptsState = {
_version: 1;
@ -94,7 +90,12 @@ type RegionalPromptsState = {
brushSize: number;
globalMaskLayerOpacity: number;
isEnabled: boolean;
baseLayer: BaseLayerState;
positivePrompt: ParameterPositivePrompt;
negativePrompt: ParameterNegativePrompt;
positivePrompt2: ParameterPositiveStylePromptSDXL;
negativePrompt2: ParameterNegativeStylePromptSDXL;
shouldConcatPrompts: boolean;
initialImage: string | null;
size: {
width: ParameterWidth;
height: ParameterHeight;
@ -109,13 +110,12 @@ export const initialRegionalPromptsState: RegionalPromptsState = {
layers: [],
globalMaskLayerOpacity: 0.5, // this globally changes all mask layers' opacity
isEnabled: true,
baseLayer: {
positivePrompt: '',
negativePrompt: '',
positivePrompt2: '',
negativePrompt2: '',
shouldConcatPrompts: true,
},
positivePrompt: '',
negativePrompt: '',
positivePrompt2: '',
negativePrompt2: '',
shouldConcatPrompts: true,
initialImage: null,
size: {
width: 512,
height: 512,
@ -124,10 +124,13 @@ export const initialRegionalPromptsState: RegionalPromptsState = {
};
const isLine = (obj: VectorMaskLine | VectorMaskRect): obj is VectorMaskLine => obj.type === 'vector_mask_line';
export const isVectorMaskLayer = (layer?: Layer): layer is VectorMaskLayer => layer?.type === 'vector_mask_layer';
export const isMaskedGuidanceLayer = (layer?: Layer): layer is MaskedGuidanceLayer =>
layer?.type === 'masked_guidance_layer';
export const isRenderableLayer = (layer?: Layer): layer is MaskedGuidanceLayer =>
layer?.type === 'masked_guidance_layer' || layer?.type === 'controlnet_layer';
const resetLayer = (layer: Layer) => {
if (layer.type === 'vector_mask_layer') {
layer.objects = [];
if (layer.type === 'masked_guidance_layer') {
layer.maskObjects = [];
layer.bbox = null;
layer.isVisible = true;
layer.needsPixelBbox = false;
@ -135,12 +138,12 @@ const resetLayer = (layer: Layer) => {
return;
}
if (layer.type === 'control_layer') {
if (layer.type === 'controlnet_layer') {
// TODO
}
};
const getVectorMaskPreviewColor = (state: RegionalPromptsState): RgbColor => {
const vmLayers = state.layers.filter(isVectorMaskLayer);
const vmLayers = state.layers.filter(isMaskedGuidanceLayer);
const lastColor = vmLayers[vmLayers.length - 1]?.previewColor;
return LayerColors.next(lastColor);
};
@ -153,14 +156,14 @@ export const regionalPromptsSlice = createSlice({
layerAdded: {
reducer: (state, action: PayloadAction<Layer['type'], string, { uuid: string }>) => {
const type = action.payload;
if (type === 'vector_mask_layer') {
const layer: VectorMaskLayer = {
id: getVectorMaskLayerId(action.meta.uuid),
type,
if (type === 'masked_guidance_layer') {
const layer: MaskedGuidanceLayer = {
id: getMaskedGuidanceLayerId(action.meta.uuid),
type: 'masked_guidance_layer',
isVisible: true,
bbox: null,
bboxNeedsUpdate: false,
objects: [],
maskObjects: [],
previewColor: getVectorMaskPreviewColor(state),
x: 0,
y: 0,
@ -175,8 +178,19 @@ export const regionalPromptsSlice = createSlice({
return;
}
if (type === 'control_layer') {
// TODO
if (type === 'controlnet_layer') {
const layer: ControlAdapterLayer = {
id: getControlLayerId(action.meta.uuid),
type: 'controlnet_layer',
controlAdapterId: action.meta.uuid,
x: 0,
y: 0,
bbox: null,
bboxNeedsUpdate: false,
isVisible: true,
};
state.layers.push(layer);
state.selectedLayerId = layer.id;
return;
}
},
@ -197,7 +211,7 @@ export const regionalPromptsSlice = createSlice({
layerTranslated: (state, action: PayloadAction<{ layerId: string; x: number; y: number }>) => {
const { layerId, x, y } = action.payload;
const layer = state.layers.find((l) => l.id === layerId);
if (layer) {
if (isRenderableLayer(layer)) {
layer.x = x;
layer.y = y;
}
@ -205,7 +219,7 @@ export const regionalPromptsSlice = createSlice({
layerBboxChanged: (state, action: PayloadAction<{ layerId: string; bbox: IRect | null }>) => {
const { layerId, bbox } = action.payload;
const layer = state.layers.find((l) => l.id === layerId);
if (layer) {
if (isRenderableLayer(layer)) {
layer.bbox = bbox;
layer.bboxNeedsUpdate = false;
}
@ -258,21 +272,21 @@ export const regionalPromptsSlice = createSlice({
maskLayerPositivePromptChanged: (state, action: PayloadAction<{ layerId: string; prompt: string | null }>) => {
const { layerId, prompt } = action.payload;
const layer = state.layers.find((l) => l.id === layerId);
if (layer?.type === 'vector_mask_layer') {
if (layer?.type === 'masked_guidance_layer') {
layer.positivePrompt = prompt;
}
},
maskLayerNegativePromptChanged: (state, action: PayloadAction<{ layerId: string; prompt: string | null }>) => {
const { layerId, prompt } = action.payload;
const layer = state.layers.find((l) => l.id === layerId);
if (layer?.type === 'vector_mask_layer') {
if (layer?.type === 'masked_guidance_layer') {
layer.negativePrompt = prompt;
}
},
maskLayerIPAdapterAdded: {
reducer: (state, action: PayloadAction<string, string, { uuid: string }>) => {
const layer = state.layers.find((l) => l.id === action.payload);
if (layer?.type === 'vector_mask_layer') {
if (layer?.type === 'masked_guidance_layer') {
layer.ipAdapterIds.push(action.meta.uuid);
}
},
@ -281,7 +295,7 @@ export const regionalPromptsSlice = createSlice({
maskLayerPreviewColorChanged: (state, action: PayloadAction<{ layerId: string; color: RgbColor }>) => {
const { layerId, color } = action.payload;
const layer = state.layers.find((l) => l.id === layerId);
if (layer?.type === 'vector_mask_layer') {
if (layer?.type === 'masked_guidance_layer') {
layer.previewColor = color;
}
},
@ -296,9 +310,9 @@ export const regionalPromptsSlice = createSlice({
) => {
const { layerId, points, tool } = action.payload;
const layer = state.layers.find((l) => l.id === layerId);
if (layer?.type === 'vector_mask_layer') {
const lineId = getVectorMaskLayerLineId(layer.id, action.meta.uuid);
layer.objects.push({
if (layer?.type === 'masked_guidance_layer') {
const lineId = getMaskedGuidanceLayerLineId(layer.id, action.meta.uuid);
layer.maskObjects.push({
type: 'vector_mask_line',
tool: tool,
id: lineId,
@ -321,8 +335,8 @@ export const regionalPromptsSlice = createSlice({
maskLayerPointsAdded: (state, action: PayloadAction<{ layerId: string; point: [number, number] }>) => {
const { layerId, point } = action.payload;
const layer = state.layers.find((l) => l.id === layerId);
if (layer?.type === 'vector_mask_layer') {
const lastLine = layer.objects.findLast(isLine);
if (layer?.type === 'masked_guidance_layer') {
const lastLine = layer.maskObjects.findLast(isLine);
if (!lastLine) {
return;
}
@ -340,9 +354,9 @@ export const regionalPromptsSlice = createSlice({
return;
}
const layer = state.layers.find((l) => l.id === layerId);
if (layer?.type === 'vector_mask_layer') {
const id = getVectorMaskLayerRectId(layer.id, action.meta.uuid);
layer.objects.push({
if (layer?.type === 'masked_guidance_layer') {
const id = getMaskedGuidnaceLayerRectId(layer.id, action.meta.uuid);
layer.maskObjects.push({
type: 'vector_mask_rect',
id,
x: rect.x - layer.x,
@ -361,7 +375,7 @@ export const regionalPromptsSlice = createSlice({
) => {
const { layerId, autoNegative } = action.payload;
const layer = state.layers.find((l) => l.id === layerId);
if (layer?.type === 'vector_mask_layer') {
if (layer?.type === 'masked_guidance_layer') {
layer.autoNegative = autoNegative;
}
},
@ -369,19 +383,19 @@ export const regionalPromptsSlice = createSlice({
//#region Base Layer
positivePromptChanged: (state, action: PayloadAction<string>) => {
state.baseLayer.positivePrompt = action.payload;
state.positivePrompt = action.payload;
},
negativePromptChanged: (state, action: PayloadAction<string>) => {
state.baseLayer.negativePrompt = action.payload;
state.negativePrompt = action.payload;
},
positivePrompt2Changed: (state, action: PayloadAction<string>) => {
state.baseLayer.positivePrompt2 = action.payload;
state.positivePrompt2 = action.payload;
},
negativePrompt2Changed: (state, action: PayloadAction<string>) => {
state.baseLayer.negativePrompt2 = action.payload;
state.negativePrompt2 = action.payload;
},
shouldConcatPromptsChanged: (state, action: PayloadAction<boolean>) => {
state.baseLayer.shouldConcatPrompts = action.payload;
state.shouldConcatPrompts = action.payload;
},
widthChanged: (state, action: PayloadAction<{ width: number; updateAspectRatio?: boolean }>) => {
const { width, updateAspectRatio } = action.payload;
@ -418,13 +432,13 @@ export const regionalPromptsSlice = createSlice({
},
undo: (state) => {
// Invalidate the bbox for all layers to prevent stale bboxes
for (const layer of state.layers) {
for (const layer of state.layers.filter(isRenderableLayer)) {
layer.bboxNeedsUpdate = true;
}
},
redo: (state) => {
// Invalidate the bbox for all layers to prevent stale bboxes
for (const layer of state.layers) {
for (const layer of state.layers.filter(isRenderableLayer)) {
layer.bboxNeedsUpdate = true;
}
},
@ -432,7 +446,7 @@ export const regionalPromptsSlice = createSlice({
},
extraReducers(builder) {
builder.addCase(controlAdapterRemoved, (state, action) => {
state.layers.filter(isVectorMaskLayer).forEach((layer) => {
state.layers.filter(isMaskedGuidanceLayer).forEach((layer) => {
layer.ipAdapterIds = layer.ipAdapterIds.filter((id) => id !== action.payload.id);
});
});
@ -559,19 +573,20 @@ export const BACKGROUND_LAYER_ID = 'background_layer';
export const BACKGROUND_RECT_ID = 'background_layer.rect';
// Names (aka classes) for Konva layers and objects
export const VECTOR_MASK_LAYER_NAME = 'vector_mask_layer';
export const VECTOR_MASK_LAYER_LINE_NAME = 'vector_mask_layer.line';
export const VECTOR_MASK_LAYER_OBJECT_GROUP_NAME = 'vector_mask_layer.object_group';
export const VECTOR_MASK_LAYER_RECT_NAME = 'vector_mask_layer.rect';
export const MASKED_GUIDANCE_LAYER_NAME = 'masked_guidance_layer';
export const MASKED_GUIDANCE_LAYER_LINE_NAME = 'masked_guidance_layer.line';
export const MASKED_GUIDANCE_LAYER_OBJECT_GROUP_NAME = 'masked_guidance_layer.object_group';
export const MASKED_GUIDANCE_LAYER_RECT_NAME = 'masked_guidance_layer.rect';
export const LAYER_BBOX_NAME = 'layer.bbox';
// Getters for non-singleton layer and object IDs
const getVectorMaskLayerId = (layerId: string) => `${VECTOR_MASK_LAYER_NAME}_${layerId}`;
const getVectorMaskLayerLineId = (layerId: string, lineId: string) => `${layerId}.line_${lineId}`;
const getVectorMaskLayerRectId = (layerId: string, lineId: string) => `${layerId}.rect_${lineId}`;
export const getVectorMaskLayerObjectGroupId = (layerId: string, groupId: string) =>
const getMaskedGuidanceLayerId = (layerId: string) => `${MASKED_GUIDANCE_LAYER_NAME}_${layerId}`;
const getMaskedGuidanceLayerLineId = (layerId: string, lineId: string) => `${layerId}.line_${lineId}`;
const getMaskedGuidnaceLayerRectId = (layerId: string, lineId: string) => `${layerId}.rect_${lineId}`;
export const getMaskedGuidanceLayerObjectGroupId = (layerId: string, groupId: string) =>
`${layerId}.objectGroup_${groupId}`;
export const getLayerBboxId = (layerId: string) => `${layerId}.bbox`;
const getControlLayerId = (layerId: string) => `control_layer_${layerId}`;
export const regionalPromptsPersistConfig: PersistConfig<RegionalPromptsState> = {
name: regionalPromptsSlice.name,

View File

@ -1,6 +1,6 @@
import openBase64ImageInTab from 'common/util/openBase64ImageInTab';
import { imageDataToDataURL } from 'features/canvas/util/blobToDataURL';
import { VECTOR_MASK_LAYER_OBJECT_GROUP_NAME } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { MASKED_GUIDANCE_LAYER_OBJECT_GROUP_NAME } from 'features/regionalPrompts/store/regionalPromptsSlice';
import Konva from 'konva';
import type { Layer as KonvaLayerType } from 'konva/lib/Layer';
import type { IRect } from 'konva/lib/types';
@ -81,7 +81,7 @@ export const getLayerBboxPixels = (layer: KonvaLayerType, preview: boolean = fal
offscreenStage.add(layerClone);
for (const child of layerClone.getChildren()) {
if (child.name() === VECTOR_MASK_LAYER_OBJECT_GROUP_NAME) {
if (child.name() === MASKED_GUIDANCE_LAYER_OBJECT_GROUP_NAME) {
// We need to cache the group to ensure it composites out eraser strokes correctly
child.opacity(1);
child.cache();

View File

@ -1,7 +1,7 @@
import { getStore } from 'app/store/nanostores/store';
import openBase64ImageInTab from 'common/util/openBase64ImageInTab';
import { blobToDataURL } from 'features/canvas/util/blobToDataURL';
import { isVectorMaskLayer, VECTOR_MASK_LAYER_NAME } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { isMaskedGuidanceLayer, MASKED_GUIDANCE_LAYER_NAME } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { renderers } from 'features/regionalPrompts/util/renderers';
import Konva from 'konva';
import { assert } from 'tsafe';
@ -19,12 +19,12 @@ export const getRegionalPromptLayerBlobs = async (
const state = getStore().getState();
const { layers } = state.regionalPrompts.present;
const { width, height } = state.regionalPrompts.present.size;
const reduxLayers = layers.filter(isVectorMaskLayer);
const reduxLayers = layers.filter(isMaskedGuidanceLayer);
const container = document.createElement('div');
const stage = new Konva.Stage({ container, width, height });
renderers.renderLayers(stage, reduxLayers, 1, 'brush');
const konvaLayers = stage.find<Konva.Layer>(`.${VECTOR_MASK_LAYER_NAME}`);
const konvaLayers = stage.find<Konva.Layer>(`.${MASKED_GUIDANCE_LAYER_NAME}`);
const blobs: Record<string, Blob> = {};
// First remove all layers

View File

@ -3,8 +3,8 @@ import { rgbaColorToString, rgbColorToString } from 'features/canvas/util/colorT
import { getScaledFlooredCursorPosition } from 'features/regionalPrompts/hooks/mouseEventHooks';
import type {
Layer,
MaskedGuidanceLayer,
Tool,
VectorMaskLayer,
VectorMaskLine,
VectorMaskRect,
} from 'features/regionalPrompts/store/regionalPromptsSlice';
@ -13,19 +13,19 @@ import {
BACKGROUND_LAYER_ID,
BACKGROUND_RECT_ID,
getLayerBboxId,
getVectorMaskLayerObjectGroupId,
isVectorMaskLayer,
getMaskedGuidanceLayerObjectGroupId,
isMaskedGuidanceLayer,
LAYER_BBOX_NAME,
MASKED_GUIDANCE_LAYER_LINE_NAME,
MASKED_GUIDANCE_LAYER_NAME,
MASKED_GUIDANCE_LAYER_OBJECT_GROUP_NAME,
MASKED_GUIDANCE_LAYER_RECT_NAME,
TOOL_PREVIEW_BRUSH_BORDER_INNER_ID,
TOOL_PREVIEW_BRUSH_BORDER_OUTER_ID,
TOOL_PREVIEW_BRUSH_FILL_ID,
TOOL_PREVIEW_BRUSH_GROUP_ID,
TOOL_PREVIEW_LAYER_ID,
TOOL_PREVIEW_RECT_ID,
VECTOR_MASK_LAYER_LINE_NAME,
VECTOR_MASK_LAYER_NAME,
VECTOR_MASK_LAYER_OBJECT_GROUP_NAME,
VECTOR_MASK_LAYER_RECT_NAME,
} from 'features/regionalPrompts/store/regionalPromptsSlice';
import { getLayerBboxFast, getLayerBboxPixels } from 'features/regionalPrompts/util/bbox';
import Konva from 'konva';
@ -54,7 +54,7 @@ const getIsSelected = (layerId?: string | null) => {
};
const selectVectorMaskObjects = (node: Konva.Node) => {
return node.name() === VECTOR_MASK_LAYER_LINE_NAME || node.name() === VECTOR_MASK_LAYER_RECT_NAME;
return node.name() === MASKED_GUIDANCE_LAYER_LINE_NAME || node.name() === MASKED_GUIDANCE_LAYER_RECT_NAME;
};
/**
@ -138,7 +138,7 @@ const renderToolPreview = (
isMouseOver: boolean,
brushSize: number
) => {
const layerCount = stage.find(`.${VECTOR_MASK_LAYER_NAME}`).length;
const layerCount = stage.find(`.${MASKED_GUIDANCE_LAYER_NAME}`).length;
// Update the stage's pointer style
if (layerCount === 0) {
// We have no layers, so we should not render any tool
@ -221,13 +221,13 @@ const renderToolPreview = (
*/
const createVectorMaskLayer = (
stage: Konva.Stage,
reduxLayer: VectorMaskLayer,
reduxLayer: MaskedGuidanceLayer,
onLayerPosChanged?: (layerId: string, x: number, y: number) => void
) => {
// This layer hasn't been added to the konva state yet
const konvaLayer = new Konva.Layer({
id: reduxLayer.id,
name: VECTOR_MASK_LAYER_NAME,
name: MASKED_GUIDANCE_LAYER_NAME,
draggable: true,
dragDistance: 0,
});
@ -259,8 +259,8 @@ const createVectorMaskLayer = (
// The object group holds all of the layer's objects (e.g. lines and rects)
const konvaObjectGroup = new Konva.Group({
id: getVectorMaskLayerObjectGroupId(reduxLayer.id, uuidv4()),
name: VECTOR_MASK_LAYER_OBJECT_GROUP_NAME,
id: getMaskedGuidanceLayerObjectGroupId(reduxLayer.id, uuidv4()),
name: MASKED_GUIDANCE_LAYER_OBJECT_GROUP_NAME,
listening: false,
});
konvaLayer.add(konvaObjectGroup);
@ -279,7 +279,7 @@ const createVectorMaskLine = (reduxObject: VectorMaskLine, konvaGroup: Konva.Gro
const vectorMaskLine = new Konva.Line({
id: reduxObject.id,
key: reduxObject.id,
name: VECTOR_MASK_LAYER_LINE_NAME,
name: MASKED_GUIDANCE_LAYER_LINE_NAME,
strokeWidth: reduxObject.strokeWidth,
tension: 0,
lineCap: 'round',
@ -301,7 +301,7 @@ const createVectorMaskRect = (reduxObject: VectorMaskRect, konvaGroup: Konva.Gro
const vectorMaskRect = new Konva.Rect({
id: reduxObject.id,
key: reduxObject.id,
name: VECTOR_MASK_LAYER_RECT_NAME,
name: MASKED_GUIDANCE_LAYER_RECT_NAME,
x: reduxObject.x,
y: reduxObject.y,
width: reduxObject.width,
@ -322,7 +322,7 @@ const createVectorMaskRect = (reduxObject: VectorMaskRect, konvaGroup: Konva.Gro
*/
const renderVectorMaskLayer = (
stage: Konva.Stage,
reduxLayer: VectorMaskLayer,
reduxLayer: MaskedGuidanceLayer,
globalMaskLayerOpacity: number,
tool: Tool,
onLayerPosChanged?: (layerId: string, x: number, y: number) => void
@ -340,13 +340,13 @@ const renderVectorMaskLayer = (
// Convert the color to a string, stripping the alpha - the object group will handle opacity.
const rgbColor = rgbColorToString(reduxLayer.previewColor);
const konvaObjectGroup = konvaLayer.findOne<Konva.Group>(`.${VECTOR_MASK_LAYER_OBJECT_GROUP_NAME}`);
const konvaObjectGroup = konvaLayer.findOne<Konva.Group>(`.${MASKED_GUIDANCE_LAYER_OBJECT_GROUP_NAME}`);
assert(konvaObjectGroup, `Object group not found for layer ${reduxLayer.id}`);
// We use caching to handle "global" layer opacity, but caching is expensive and we should only do it when required.
let groupNeedsCache = false;
const objectIds = reduxLayer.objects.map(mapId);
const objectIds = reduxLayer.maskObjects.map(mapId);
for (const objectNode of konvaObjectGroup.find(selectVectorMaskObjects)) {
if (!objectIds.includes(objectNode.id())) {
objectNode.destroy();
@ -354,7 +354,7 @@ const renderVectorMaskLayer = (
}
}
for (const reduxObject of reduxLayer.objects) {
for (const reduxObject of reduxLayer.maskObjects) {
if (reduxObject.type === 'vector_mask_line') {
const vectorMaskLine =
stage.findOne<Konva.Line>(`#${reduxObject.id}`) ?? createVectorMaskLine(reduxObject, konvaObjectGroup);
@ -419,14 +419,14 @@ const renderLayers = (
const reduxLayerIds = reduxLayers.map(mapId);
// Remove un-rendered layers
for (const konvaLayer of stage.find<Konva.Layer>(`.${VECTOR_MASK_LAYER_NAME}`)) {
for (const konvaLayer of stage.find<Konva.Layer>(`.${MASKED_GUIDANCE_LAYER_NAME}`)) {
if (!reduxLayerIds.includes(konvaLayer.id())) {
konvaLayer.destroy();
}
}
for (const reduxLayer of reduxLayers) {
if (isVectorMaskLayer(reduxLayer)) {
if (isMaskedGuidanceLayer(reduxLayer)) {
renderVectorMaskLayer(stage, reduxLayer, globalMaskLayerOpacity, tool, onLayerPosChanged);
}
}
@ -494,14 +494,14 @@ const renderBbox = (
}
for (const reduxLayer of reduxLayers) {
if (reduxLayer.type === 'vector_mask_layer') {
if (reduxLayer.type === 'masked_guidance_layer') {
const konvaLayer = stage.findOne<Konva.Layer>(`#${reduxLayer.id}`);
assert(konvaLayer, `Layer ${reduxLayer.id} not found in stage`);
let bbox = reduxLayer.bbox;
// We only need to recalculate the bbox if the layer has changed and it has objects
if (reduxLayer.bboxNeedsUpdate && reduxLayer.objects.length) {
if (reduxLayer.bboxNeedsUpdate && reduxLayer.maskObjects.length) {
// We only need to use the pixel-perfect bounding box if the layer has eraser strokes
bbox = reduxLayer.needsPixelBbox ? getLayerBboxPixels(konvaLayer) : getLayerBboxFast(konvaLayer);
// Update the layer's bbox in the redux store

View File

@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
export const ParamSDXLNegativeStylePrompt = memo(() => {
const dispatch = useAppDispatch();
const prompt = useAppSelector((s) => s.regionalPrompts.present.baseLayer.negativePrompt2);
const prompt = useAppSelector((s) => s.regionalPrompts.present.negativePrompt2);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const { t } = useTranslation();
const handleChange = useCallback(

View File

@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next';
export const ParamSDXLPositiveStylePrompt = memo(() => {
const dispatch = useAppDispatch();
const prompt = useAppSelector((s) => s.regionalPrompts.present.baseLayer.positivePrompt2);
const prompt = useAppSelector((s) => s.regionalPrompts.present.positivePrompt2);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const { t } = useTranslation();
const handleChange = useCallback(

View File

@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
import { PiLinkSimpleBold, PiLinkSimpleBreakBold } from 'react-icons/pi';
export const SDXLConcatButton = memo(() => {
const shouldConcatPrompts = useAppSelector((s) => s.regionalPrompts.present.baseLayer.shouldConcatPrompts);
const shouldConcatPrompts = useAppSelector((s) => s.regionalPrompts.present.shouldConcatPrompts);
const dispatch = useAppDispatch();
const { t } = useTranslation();

View File

@ -8,7 +8,7 @@ import { ParamSDXLNegativeStylePrompt } from './ParamSDXLNegativeStylePrompt';
import { ParamSDXLPositiveStylePrompt } from './ParamSDXLPositiveStylePrompt';
export const SDXLPrompts = memo(() => {
const shouldConcatPrompts = useAppSelector((s) => s.regionalPrompts.present.baseLayer.shouldConcatPrompts);
const shouldConcatPrompts = useAppSelector((s) => s.regionalPrompts.present.shouldConcatPrompts);
return (
<Flex flexDir="column" gap={2} pos="relative">
<ParamPositivePrompt />

View File

@ -13,7 +13,7 @@ import {
selectValidIPAdapters,
selectValidT2IAdapters,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { isVectorMaskLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { isMaskedGuidanceLayer, selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { Fragment, memo } from 'react';
@ -28,7 +28,7 @@ const selector = createMemoizedSelector(
const enabledNonRegionalIPAdapterCount = selectAllIPAdapters(controlAdapters)
.filter(
(ca) => !regionalPrompts.present.layers.filter(isVectorMaskLayer).some((l) => l.ipAdapterIds.includes(ca.id))
(ca) => !regionalPrompts.present.layers.filter(isMaskedGuidanceLayer).some((l) => l.ipAdapterIds.includes(ca.id))
)
.filter((ca) => ca.isEnabled).length;
@ -59,7 +59,7 @@ const selector = createMemoizedSelector(
}
const controlAdapterIds = selectControlAdapterIds(controlAdapters).filter(
(id) => !regionalPrompts.present.layers.filter(isVectorMaskLayer).some((l) => l.ipAdapterIds.includes(id))
(id) => !regionalPrompts.present.layers.filter(isMaskedGuidanceLayer).some((l) => l.ipAdapterIds.includes(id))
);
return {