diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts index 5645567613..9238c5ddb1 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts @@ -79,15 +79,15 @@ const handleMainModels: ModelHandler = (models, state, dispatch, log) => { const optimalDimension = getOptimalDimension(defaultModelInList); if ( getIsSizeOptimal( - state.canvasV2.size.width, - state.canvasV2.size.height, + state.canvasV2.document.width, + state.canvasV2.document.height, optimalDimension ) ) { return; } const { width, height } = calculateNewSize( - state.canvasV2.size.aspectRatio.value, + state.canvasV2.document.aspectRatio.value, optimalDimension * optimalDimension ); diff --git a/invokeai/frontend/web/src/common/hooks/useIsReadyToEnqueue.ts b/invokeai/frontend/web/src/common/hooks/useIsReadyToEnqueue.ts index 2f2847f058..d61e316745 100644 --- a/invokeai/frontend/web/src/common/hooks/useIsReadyToEnqueue.ts +++ b/invokeai/frontend/web/src/common/hooks/useIsReadyToEnqueue.ts @@ -1,11 +1,7 @@ import { useStore } from '@nanostores/react'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { useAppSelector } from 'app/store/storeHooks'; -import { selectControlAdaptersV2Slice } from 'features/controlLayers/store/controlAdaptersSlice'; import { selectCanvasV2Slice } from 'features/controlLayers/store/canvasV2Slice'; -import { selectIPAdaptersSlice } from 'features/controlLayers/store/ipAdaptersSlice'; -import { selectLayersSlice } from 'features/controlLayers/store/layersSlice'; -import { selectRegionalGuidanceSlice } from 'features/controlLayers/store/regionalGuidanceSlice'; import type { CanvasEntity } from 'features/controlLayers/store/types'; import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice'; import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt'; @@ -40,32 +36,13 @@ const createSelector = (templates: Templates) => selectWorkflowSettingsSlice, selectDynamicPromptsSlice, selectCanvasV2Slice, - selectLayersSlice, - selectControlAdaptersV2Slice, - selectRegionalGuidanceSlice, - selectIPAdaptersSlice, - activeTabNameSelector, selectUpscalelice, selectConfigSlice, + activeTabNameSelector, ], - ( - generation, - system, - nodes, - workflowSettings, - dynamicPrompts, - canvasV2, - layersState, - controlAdaptersState, - regionalGuidanceState, - ipAdaptersState, - activeTabName, - upscale, - config - ) => { - const { model } = generation; - const { size } = canvasV2; - const { positivePrompt } = canvasV2.prompts; + (generation, system, nodes, workflowSettings, dynamicPrompts, canvasV2, upscale, config, activeTabName) => { + const { model, positivePrompt } = generation; + const { bbox } = canvasV2; const { isConnected } = system; @@ -149,7 +126,7 @@ const createSelector = (templates: Templates) => reasons.push({ content: i18n.t('parameters.invoke.noModelSelected') }); } - controlAdaptersState.controlAdapters + canvasV2.controlAdapters .filter((ca) => ca.isEnabled) .forEach((ca, i) => { const layerLiteral = i18n.t('controlLayers.layers_one'); @@ -174,7 +151,7 @@ const createSelector = (templates: Templates) => // T2I Adapters require images have dimensions that are multiples of 64 (SD1.5) or 32 (SDXL) if (!ca.controlMode) { const multiple = model?.base === 'sdxl' ? 32 : 64; - if (size.width % multiple !== 0 || size.height % multiple !== 0) { + if (bbox.width % multiple !== 0 || bbox.height % multiple !== 0) { problems.push(i18n.t('parameters.invoke.layer.t2iAdapterIncompatibleDimensions', { multiple })); } } @@ -185,7 +162,7 @@ const createSelector = (templates: Templates) => } }); - ipAdaptersState.ipAdapters + canvasV2.ipAdapters .filter((ipa) => ipa.isEnabled) .forEach((ipa, i) => { const layerLiteral = i18n.t('controlLayers.layers_one'); @@ -213,7 +190,7 @@ const createSelector = (templates: Templates) => } }); - regionalGuidanceState.regions + canvasV2.regions .filter((rg) => rg.isEnabled) .forEach((rg, i) => { const layerLiteral = i18n.t('controlLayers.layers_one'); @@ -250,7 +227,7 @@ const createSelector = (templates: Templates) => } }); - layersState.layers + canvasV2.layers .filter((l) => l.isEnabled) .forEach((l, i) => { const layerLiteral = i18n.t('controlLayers.layers_one'); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StageComponent.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StageComponent.tsx index 3dd7b1df35..055070717d 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StageComponent.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StageComponent.tsx @@ -35,7 +35,6 @@ import { rgLinePointAdded, rgRectAdded, rgTranslated, - selectCanvasV2Slice, toolBufferChanged, toolChanged, } from 'features/controlLayers/store/canvasV2Slice'; @@ -65,50 +64,51 @@ const log = logger('controlLayers'); const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null, asPreview: boolean) => { const dispatch = useAppDispatch(); - const canvasV2State = useAppSelector(selectCanvasV2Slice); + const controlAdapters = useAppSelector((s) => s.canvasV2.controlAdapters); + const ipAdapters = useAppSelector((s) => s.canvasV2.ipAdapters); + const layers = useAppSelector((s) => s.canvasV2.layers); + const regions = useAppSelector((s) => s.canvasV2.regions); + const tool = useAppSelector((s) => s.canvasV2.tool); + const selectedEntityIdentifier = useAppSelector((s) => s.canvasV2.selectedEntityIdentifier); + const maskFillOpacity = useAppSelector((s) => s.canvasV2.maskFillOpacity); + const bbox = useAppSelector((s) => s.canvasV2.bbox); const lastCursorPos = useStore($lastCursorPos); const lastMouseDownPos = useStore($lastMouseDownPos); const isMouseDown = useStore($isMouseDown); const isDrawing = useStore($isDrawing); const selectedEntity = useMemo(() => { - const identifier = canvasV2State.selectedEntityIdentifier; + const identifier = selectedEntityIdentifier; if (!identifier) { return null; } else if (identifier.type === 'layer') { - return canvasV2State.layers.find((i) => i.id === identifier.id) ?? null; + return layers.find((i) => i.id === identifier.id) ?? null; } else if (identifier.type === 'control_adapter') { - return canvasV2State.controlAdapters.find((i) => i.id === identifier.id) ?? null; + return controlAdapters.find((i) => i.id === identifier.id) ?? null; } else if (identifier.type === 'ip_adapter') { - return canvasV2State.ipAdapters.find((i) => i.id === identifier.id) ?? null; + return ipAdapters.find((i) => i.id === identifier.id) ?? null; } else if (identifier.type === 'regional_guidance') { - return canvasV2State.regions.find((i) => i.id === identifier.id) ?? null; + return regions.find((i) => i.id === identifier.id) ?? null; } else { return null; } - }, [ - canvasV2State.controlAdapters, - canvasV2State.ipAdapters, - canvasV2State.layers, - canvasV2State.regions, - canvasV2State.selectedEntityIdentifier, - ]); + }, [controlAdapters, ipAdapters, layers, regions, selectedEntityIdentifier]); const currentFill = useMemo(() => { if (selectedEntity && selectedEntity.type === 'regional_guidance') { - return { ...selectedEntity.fill, a: canvasV2State.maskFillOpacity }; + return { ...selectedEntity.fill, a: maskFillOpacity }; } - return canvasV2State.tool.fill; - }, [canvasV2State.maskFillOpacity, canvasV2State.tool.fill, selectedEntity]); + return tool.fill; + }, [maskFillOpacity, selectedEntity, tool.fill]); const renderers = useMemo(() => (asPreview ? debouncedRenderers : normalRenderers), [asPreview]); const dpr = useDevicePixelRatio({ round: false }); useLayoutEffect(() => { - $toolState.set(canvasV2State.tool); + $toolState.set(tool); $selectedEntity.set(selectedEntity); - $bbox.set(canvasV2State.bbox); + $bbox.set(bbox); $currentFill.set(currentFill); - }, [selectedEntity, canvasV2State.tool, canvasV2State.bbox, currentFill]); + }, [selectedEntity, tool, bbox, currentFill]); const onPosChanged = useCallback( (arg: PosChangedArg, entityType: CanvasEntity['type']) => { @@ -305,7 +305,7 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null, log.trace('Rendering tool preview'); renderers.renderToolPreview( stage, - canvasV2State.tool, + tool, currentFill, selectedEntity, lastCursorPos, @@ -315,7 +315,6 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null, ); }, [ asPreview, - canvasV2State.tool, currentFill, isDrawing, isMouseDown, @@ -324,6 +323,7 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null, renderers, selectedEntity, stage, + tool, ]); useLayoutEffect(() => { @@ -334,8 +334,8 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null, log.trace('Rendering bbox preview'); renderers.renderBboxPreview( stage, - canvasV2State.bbox, - canvasV2State.tool.selected, + bbox, + tool.selected, $bbox.get, onBboxTransformed, $shift.get, @@ -343,31 +343,31 @@ const useStageRenderer = (stage: Konva.Stage, container: HTMLDivElement | null, $meta.get, $alt.get ); - }, [asPreview, canvasV2State.bbox, canvasV2State.tool.selected, onBboxTransformed, renderers, stage]); + }, [asPreview, bbox, onBboxTransformed, renderers, stage, tool.selected]); useLayoutEffect(() => { log.trace('Rendering layers'); renderers.renderLayers( stage, - canvasV2State.layers, - canvasV2State.controlAdapters, - canvasV2State.regions, - canvasV2State.maskFillOpacity, - canvasV2State.tool.selected, + layers, + controlAdapters, + regions, + maskFillOpacity, + tool.selected, selectedEntity, getImageDTO, onPosChanged ); }, [ - stage, - renderers, + controlAdapters, + layers, + maskFillOpacity, onPosChanged, - canvasV2State.tool.selected, + regions, + renderers, selectedEntity, - canvasV2State.layers, - canvasV2State.controlAdapters, - canvasV2State.regions, - canvasV2State.maskFillOpacity, + stage, + tool.selected, ]); // useLayoutEffect(() => { diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts index 206ac47da6..3cf24a0fa5 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts @@ -21,13 +21,6 @@ import { DEFAULT_RGBA_COLOR } from './types'; const initialState: CanvasV2State = { _version: 3, selectedEntityIdentifier: null, - prompts: { - positivePrompt: '', - negativePrompt: '', - positivePrompt2: '', - negativePrompt2: '', - shouldConcatPrompts: true, - }, tool: { selected: 'bbox', selectedBuffer: null, @@ -40,7 +33,7 @@ const initialState: CanvasV2State = { width: 50, }, }, - size: { + document: { width: 512, height: 512, aspectRatio: deepClone(initialAspectRatioState), @@ -66,41 +59,26 @@ export const canvasV2Slice = createSlice({ ...ipAdaptersReducers, ...controlAdaptersReducers, ...regionsReducers, - positivePromptChanged: (state, action: PayloadAction) => { - state.prompts.positivePrompt = action.payload; - }, - negativePromptChanged: (state, action: PayloadAction) => { - state.prompts.negativePrompt = action.payload; - }, - positivePrompt2Changed: (state, action: PayloadAction) => { - state.prompts.positivePrompt2 = action.payload; - }, - negativePrompt2Changed: (state, action: PayloadAction) => { - state.prompts.negativePrompt2 = action.payload; - }, - shouldConcatPromptsChanged: (state, action: PayloadAction) => { - state.prompts.shouldConcatPrompts = action.payload; - }, widthChanged: (state, action: PayloadAction<{ width: number; updateAspectRatio?: boolean; clamp?: boolean }>) => { const { width, updateAspectRatio, clamp } = action.payload; - state.size.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width; + state.document.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width; if (updateAspectRatio) { - state.size.aspectRatio.value = state.size.width / state.size.height; - state.size.aspectRatio.id = 'Free'; - state.size.aspectRatio.isLocked = false; + state.document.aspectRatio.value = state.document.width / state.document.height; + state.document.aspectRatio.id = 'Free'; + state.document.aspectRatio.isLocked = false; } }, heightChanged: (state, action: PayloadAction<{ height: number; updateAspectRatio?: boolean; clamp?: boolean }>) => { const { height, updateAspectRatio, clamp } = action.payload; - state.size.height = clamp ? Math.max(roundDownToMultiple(height, 8), 64) : height; + state.document.height = clamp ? Math.max(roundDownToMultiple(height, 8), 64) : height; if (updateAspectRatio) { - state.size.aspectRatio.value = state.size.width / state.size.height; - state.size.aspectRatio.id = 'Free'; - state.size.aspectRatio.isLocked = false; + state.document.aspectRatio.value = state.document.width / state.document.height; + state.document.aspectRatio.id = 'Free'; + state.document.aspectRatio.isLocked = false; } }, aspectRatioChanged: (state, action: PayloadAction) => { - state.size.aspectRatio = action.payload; + state.document.aspectRatio = action.payload; }, bboxChanged: (state, action: PayloadAction) => { state.bbox = action.payload; @@ -144,22 +122,17 @@ export const canvasV2Slice = createSlice({ return; } const optimalDimension = getOptimalDimension(newModel); - if (getIsSizeOptimal(state.size.width, state.size.height, optimalDimension)) { + if (getIsSizeOptimal(state.document.width, state.document.height, optimalDimension)) { return; } - const { width, height } = calculateNewSize(state.size.aspectRatio.value, optimalDimension * optimalDimension); - state.size.width = width; - state.size.height = height; + const { width, height } = calculateNewSize(state.document.aspectRatio.value, optimalDimension * optimalDimension); + state.document.width = width; + state.document.height = height; }); }, }); export const { - positivePromptChanged, - negativePromptChanged, - positivePrompt2Changed, - negativePrompt2Changed, - shouldConcatPromptsChanged, widthChanged, heightChanged, aspectRatioChanged, diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index da1610559b..a38b6500ec 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -3,10 +3,6 @@ import { zModelIdentifierField } from 'features/nodes/types/common'; import type { AspectRatioState } from 'features/parameters/components/ImageSize/types'; import type { ParameterHeight, - ParameterNegativePrompt, - ParameterNegativeStylePromptSDXL, - ParameterPositivePrompt, - ParameterPositiveStylePromptSDXL, ParameterWidth, } from 'features/parameters/types/parameterSchemas'; import { @@ -758,13 +754,6 @@ export type CanvasEntityIdentifier = Pick; export type CanvasV2State = { _version: 3; selectedEntityIdentifier: CanvasEntityIdentifier | null; - prompts: { - positivePrompt: ParameterPositivePrompt; - negativePrompt: ParameterNegativePrompt; - positivePrompt2: ParameterPositiveStylePromptSDXL; - negativePrompt2: ParameterNegativeStylePromptSDXL; - shouldConcatPrompts: boolean; - }; tool: { selected: Tool; selectedBuffer: Tool | null; @@ -777,7 +766,7 @@ export type CanvasV2State = { }; fill: RgbaColor; }; - size: { + document: { width: ParameterWidth; height: ParameterHeight; aspectRatio: AspectRatioState; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addControlLayers.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addControlLayers.ts index 78702fccfe..e740660bca 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addControlLayers.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addControlLayers.ts @@ -421,7 +421,7 @@ const addInitialImageLayerToGraph = ( ) => { const { vaePrecision } = state.generation; const { refinerModel, refinerStart } = state.sdxl; - const { width, height } = state.canvasV2.size; + const { width, height } = state.canvasV2.document; assert(layer.isEnabled, 'Initial image layer is not enabled'); assert(layer.image, 'Initial image layer has no image'); @@ -568,7 +568,7 @@ const buildControlImage = ( const getRGLayerBlobs = async (layerIds?: string[], preview: boolean = false): Promise> => { const state = getStore().getState(); const { layers } = state.canvasV2; - const { width, height } = state.canvasV2.size; + const { width, height } = state.canvasV2.document; const reduxLayers = layers.filter(isRegionalGuidanceLayer); const container = document.createElement('div'); const stage = new Konva.Stage({ container, width, height }); diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addHRF.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addHRF.ts index e03d54ebc2..4b38fc20c6 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addHRF.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addHRF.ts @@ -74,7 +74,7 @@ export const addHRF = ( vaeSource: Invocation<'vae_loader'> | Invocation<'main_model_loader'> | Invocation<'seamless'> ): Invocation<'l2i'> => { const { hrfStrength, hrfEnabled, hrfMethod } = state.hrf; - const { width, height } = state.canvasV2.size; + const { width, height } = state.canvasV2.document; const optimalDimension = selectOptimalDimension(state); const { newWidth: hrfWidth, newHeight: hrfHeight } = calculateHrfRes(optimalDimension, width, height); diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabGraph.ts index 288f0a944f..f22d0e3f8d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabGraph.ts @@ -40,7 +40,7 @@ export const buildGenerationTabGraph = async (state: RootState): Promise { const { positivePrompt, negativePrompt, positivePrompt2, negativePrompt2, shouldConcatPrompts } = - state.canvasV2.prompts; + state.generation; const { activeStylePresetId } = state.stylePreset; if (activeStylePresetId) { diff --git a/invokeai/frontend/web/src/features/parameters/components/Core/ParamNegativePrompt.tsx b/invokeai/frontend/web/src/features/parameters/components/Core/ParamNegativePrompt.tsx index e415c2d5fa..eabcfcd911 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Core/ParamNegativePrompt.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Core/ParamNegativePrompt.tsx @@ -1,9 +1,9 @@ import { Box, Textarea } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { negativePromptChanged } from 'features/controlLayers/store/canvasV2Slice'; import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel'; import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper'; import { ViewModePrompt } from 'features/parameters/components/Prompts/ViewModePrompt'; +import { negativePromptChanged } from 'features/parameters/store/generationSlice'; import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton'; import { PromptPopover } from 'features/prompt/PromptPopover'; import { usePrompt } from 'features/prompt/usePrompt'; @@ -13,7 +13,7 @@ import { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets'; export const ParamNegativePrompt = memo(() => { const dispatch = useAppDispatch(); - const prompt = useAppSelector((s) => s.canvasV2.prompts.negativePrompt); + const prompt = useAppSelector((s) => s.generation.negativePrompt); const viewMode = useAppSelector((s) => s.stylePreset.viewMode); const activeStylePresetId = useAppSelector((s) => s.stylePreset.activeStylePresetId); diff --git a/invokeai/frontend/web/src/features/parameters/components/Core/ParamPositivePrompt.tsx b/invokeai/frontend/web/src/features/parameters/components/Core/ParamPositivePrompt.tsx index f7c2c285ff..c39bf050cd 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Core/ParamPositivePrompt.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Core/ParamPositivePrompt.tsx @@ -1,10 +1,10 @@ import { Box, Textarea } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { positivePromptChanged } from 'features/controlLayers/store/canvasV2Slice'; import { ShowDynamicPromptsPreviewButton } from 'features/dynamicPrompts/components/ShowDynamicPromptsPreviewButton'; import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel'; import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper'; import { ViewModePrompt } from 'features/parameters/components/Prompts/ViewModePrompt'; +import { positivePromptChanged } from 'features/parameters/store/generationSlice'; import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton'; import { PromptPopover } from 'features/prompt/PromptPopover'; import { usePrompt } from 'features/prompt/usePrompt'; @@ -17,7 +17,7 @@ import { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets'; export const ParamPositivePrompt = memo(() => { const dispatch = useAppDispatch(); - const prompt = useAppSelector((s) => s.canvasV2.positivePrompt); + const prompt = useAppSelector((s) => s.generation.positivePrompt); const baseModel = useAppSelector((s) => s.generation.model)?.base; const viewMode = useAppSelector((s) => s.stylePreset.viewMode); const activeStylePresetId = useAppSelector((s) => s.stylePreset.activeStylePresetId); diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index 573e9c1bbe..47f33b2f96 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -24,14 +24,8 @@ const initialGenerationState: GenerationState = { cfgScale: 7.5, cfgRescaleMultiplier: 0, img2imgStrength: 0.75, - infillMethod: 'patchmatch', iterations: 1, scheduler: 'euler', - maskBlur: 16, - maskBlurMethod: 'box', - canvasCoherenceMode: 'Gaussian Blur', - canvasCoherenceMinDenoise: 0, - canvasCoherenceEdgeSize: 16, seed: 0, shouldRandomizeSeed: true, steps: 50, @@ -43,6 +37,12 @@ const initialGenerationState: GenerationState = { clipSkip: 0, shouldUseCpuNoise: true, shouldShowAdvancedOptions: false, + maskBlur: 16, + maskBlurMethod: 'box', + canvasCoherenceMode: 'Gaussian Blur', + canvasCoherenceMinDenoise: 0, + canvasCoherenceEdgeSize: 16, + infillMethod: 'patchmatch', infillTileSize: 32, infillPatchmatchDownscaleSize: 1, infillMosaicTileWidth: 64, @@ -50,6 +50,11 @@ const initialGenerationState: GenerationState = { infillMosaicMinColor: { r: 0, g: 0, b: 0, a: 1 }, infillMosaicMaxColor: { r: 255, g: 255, b: 255, a: 1 }, infillColorValue: { r: 0, g: 0, b: 0, a: 1 }, + positivePrompt: '', + negativePrompt: '', + positivePrompt2: '', + negativePrompt2: '', + shouldConcatPrompts: true, }; export const generationSlice = createSlice({ @@ -166,6 +171,21 @@ export const generationSlice = createSlice({ setInfillColorValue: (state, action: PayloadAction) => { state.infillColorValue = action.payload; }, + positivePromptChanged: (state, action: PayloadAction) => { + state.positivePrompt = action.payload; + }, + negativePromptChanged: (state, action: PayloadAction) => { + state.negativePrompt = action.payload; + }, + positivePrompt2Changed: (state, action: PayloadAction) => { + state.positivePrompt2 = action.payload; + }, + negativePrompt2Changed: (state, action: PayloadAction) => { + state.negativePrompt2 = action.payload; + }, + shouldConcatPromptsChanged: (state, action: PayloadAction) => { + state.shouldConcatPrompts = action.payload; + }, }, extraReducers: (builder) => { builder.addCase(configChanged, (state, action) => { @@ -210,6 +230,11 @@ export const { setInfillMosaicMinColor, setInfillMosaicMaxColor, setInfillColorValue, + positivePromptChanged, + negativePromptChanged, + positivePrompt2Changed, + negativePrompt2Changed, + shouldConcatPromptsChanged, } = generationSlice.actions; export const { selectOptimalDimension } = generationSlice.selectors; diff --git a/invokeai/frontend/web/src/features/parameters/store/types.ts b/invokeai/frontend/web/src/features/parameters/store/types.ts index 51ab6146cf..0d0c6e4b8b 100644 --- a/invokeai/frontend/web/src/features/parameters/store/types.ts +++ b/invokeai/frontend/web/src/features/parameters/store/types.ts @@ -5,6 +5,10 @@ import type { ParameterCFGScale, ParameterMaskBlurMethod, ParameterModel, + ParameterNegativePrompt, + ParameterNegativeStylePromptSDXL, + ParameterPositivePrompt, + ParameterPositiveStylePromptSDXL, ParameterPrecision, ParameterScheduler, ParameterSeed, @@ -45,6 +49,11 @@ export interface GenerationState { infillMosaicMinColor: RgbaColor; infillMosaicMaxColor: RgbaColor; infillColorValue: RgbaColor; + positivePrompt: ParameterPositivePrompt; + negativePrompt: ParameterNegativePrompt; + positivePrompt2: ParameterPositiveStylePromptSDXL; + negativePrompt2: ParameterNegativeStylePromptSDXL; + shouldConcatPrompts: boolean; } export type PayloadActionWithOptimalDimension = PayloadAction; diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/ParamSDXLNegativeStylePrompt.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/ParamSDXLNegativeStylePrompt.tsx index f295ffd32f..a087df8368 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/ParamSDXLNegativeStylePrompt.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/ParamSDXLNegativeStylePrompt.tsx @@ -1,8 +1,8 @@ import { Box, Textarea } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { negativePrompt2Changed } from 'features/controlLayers/store/canvasV2Slice'; import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel'; import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper'; +import { negativePrompt2Changed } from 'features/parameters/store/generationSlice'; import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton'; import { PromptPopover } from 'features/prompt/PromptPopover'; import { usePrompt } from 'features/prompt/usePrompt'; @@ -12,7 +12,7 @@ import { useTranslation } from 'react-i18next'; export const ParamSDXLNegativeStylePrompt = memo(() => { const dispatch = useAppDispatch(); - const prompt = useAppSelector((s) => s.canvasV2.negativePrompt2); + const prompt = useAppSelector((s) => s.generation.negativePrompt2); const textareaRef = useRef(null); const { t } = useTranslation(); const handleChange = useCallback( diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/ParamSDXLPositiveStylePrompt.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/ParamSDXLPositiveStylePrompt.tsx index 8e31185345..f076e6e176 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/ParamSDXLPositiveStylePrompt.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/ParamSDXLPositiveStylePrompt.tsx @@ -1,8 +1,8 @@ import { Box, Textarea } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { positivePrompt2Changed } from 'features/controlLayers/store/canvasV2Slice'; import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel'; import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper'; +import { positivePrompt2Changed } from 'features/parameters/store/generationSlice'; import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton'; import { PromptPopover } from 'features/prompt/PromptPopover'; import { usePrompt } from 'features/prompt/usePrompt'; @@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next'; export const ParamSDXLPositiveStylePrompt = memo(() => { const dispatch = useAppDispatch(); - const prompt = useAppSelector((s) => s.canvasV2.positivePrompt2); + const prompt = useAppSelector((s) => s.generation.positivePrompt2); const textareaRef = useRef(null); const { t } = useTranslation(); const handleChange = useCallback( diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/SDXLConcatButton.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/SDXLConcatButton.tsx index 9048437e3a..62dd12a696 100644 --- a/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/SDXLConcatButton.tsx +++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLPrompts/SDXLConcatButton.tsx @@ -1,12 +1,12 @@ import { IconButton, Tooltip } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { shouldConcatPromptsChanged } from 'features/controlLayers/store/canvasV2Slice'; +import { shouldConcatPromptsChanged } from 'features/parameters/store/generationSlice'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { PiLinkSimpleBold, PiLinkSimpleBreakBold } from 'react-icons/pi'; export const SDXLConcatButton = memo(() => { - const shouldConcatPrompts = useAppSelector((s) => s.canvasV2.shouldConcatPrompts); + const shouldConcatPrompts = useAppSelector((s) => s.generation.shouldConcatPrompts); const dispatch = useAppDispatch(); const { t } = useTranslation(); diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/ImageSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/ImageSettingsAccordion.tsx index 52278cfd60..1d18292da3 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/ImageSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/ImageSettingsAccordion.tsx @@ -29,7 +29,7 @@ const selector = createMemoizedSelector( const badges: string[] = []; const isSDXL = model?.base === 'sdxl'; - const { aspectRatio, width, height } = canvasV2.size; + const { aspectRatio, width, height } = canvasV2.document; badges.push(`${width}×${height}`); badges.push(aspectRatio.id); diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/ImageSizeLinear.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/ImageSizeLinear.tsx index 13670c674f..7c24c3d79b 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/ImageSizeLinear.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/ImageSizeLinear.tsx @@ -9,9 +9,9 @@ import { memo, useCallback } from 'react'; export const ImageSizeLinear = memo(() => { const dispatch = useAppDispatch(); - const width = useAppSelector((s) => s.canvasV2.size.width); - const height = useAppSelector((s) => s.canvasV2.size.height); - const aspectRatioState = useAppSelector((s) => s.canvasV2.size.aspectRatio); + const width = useAppSelector((s) => s.canvasV2.document.width); + const height = useAppSelector((s) => s.canvasV2.document.height); + const aspectRatioState = useAppSelector((s) => s.canvasV2.document.aspectRatio); const onChangeWidth = useCallback( (width: number) => {