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 a7b9f82d57..87967544a8 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 @@ -3,9 +3,9 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware' import type { AppDispatch, RootState } from 'app/store/store'; import type { JSONObject } from 'common/types'; import { + bboxHeightChanged, + bboxWidthChanged, caModelChanged, - documentHeightChanged, - documentWidthChanged, ipaModelChanged, loraDeleted, modelChanged, @@ -83,16 +83,16 @@ const handleMainModels: ModelHandler = (models, state, dispatch, log) => { dispatch(modelChanged({ model: defaultModelInList, previousModel: currentModel })); const optimalDimension = getOptimalDimension(defaultModelInList); - if (getIsSizeOptimal(state.canvasV2.document.rect.width, state.canvasV2.document.rect.height, optimalDimension)) { + if (getIsSizeOptimal(state.canvasV2.bbox.rect.width, state.canvasV2.bbox.rect.height, optimalDimension)) { return; } const { width, height } = calculateNewSize( - state.canvasV2.document.aspectRatio.value, + state.canvasV2.bbox.aspectRatio.value, optimalDimension * optimalDimension ); - dispatch(documentWidthChanged({ width })); - dispatch(documentHeightChanged({ height })); + dispatch(bboxWidthChanged({ width })); + dispatch(bboxHeightChanged({ height })); return; } } diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/setDefaultSettings.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/setDefaultSettings.ts index f8ddadb488..29828c911a 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/setDefaultSettings.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/setDefaultSettings.ts @@ -1,7 +1,7 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'; import { - documentHeightChanged, - documentWidthChanged, + bboxHeightChanged, + bboxWidthChanged, setCfgRescaleMultiplier, setCfgScale, setScheduler, @@ -99,13 +99,13 @@ export const addSetDefaultSettingsListener = (startAppListening: AppStartListeni const setSizeOptions = { updateAspectRatio: true, clamp: true }; if (width) { if (isParameterWidth(width)) { - dispatch(documentWidthChanged({ width, ...setSizeOptions })); + dispatch(bboxWidthChanged({ width, ...setSizeOptions })); } } if (height) { if (isParameterHeight(height)) { - dispatch(documentHeightChanged({ height, ...setSizeOptions })); + dispatch(bboxHeightChanged({ height, ...setSizeOptions })); } } diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasResizer.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasResizer.tsx index d5fc3852d2..1d11a3d311 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasResizer.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasResizer.tsx @@ -25,7 +25,7 @@ type ResizeDirection = | 'down-right'; export const CanvasResizer = memo(() => { - const document = useAppSelector((s) => s.canvasV2.document); + const bbox = useAppSelector((s) => s.canvasV2.bbox); const [resizeDirection, setResizeDirection] = useState('center-out'); const setDirUpLeft = useCallback(() => { diff --git a/invokeai/frontend/web/src/features/controlLayers/components/ControlAdapter/CAImagePreview.tsx b/invokeai/frontend/web/src/features/controlLayers/components/ControlAdapter/CAImagePreview.tsx index 5d6d253fbf..b1c862bab1 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/ControlAdapter/CAImagePreview.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/ControlAdapter/CAImagePreview.tsx @@ -3,7 +3,7 @@ import { skipToken } from '@reduxjs/toolkit/query'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIDndImage from 'common/components/IAIDndImage'; import IAIDndImageIcon from 'common/components/IAIDndImageIcon'; -import { documentHeightChanged, documentWidthChanged } from 'features/controlLayers/store/canvasV2Slice'; +import { bboxHeightChanged, bboxWidthChanged } from 'features/controlLayers/store/canvasV2Slice'; import { selectOptimalDimension } from 'features/controlLayers/store/selectors'; import type { ControlAdapterEntity } from 'features/controlLayers/store/types'; import type { ImageDraggableData, TypesafeDroppableData } from 'features/dnd/types'; @@ -89,15 +89,15 @@ export const CAImagePreview = memo( if (shift) { const { width, height } = controlImage; - dispatch(documentWidthChanged({ width, ...options })); - dispatch(documentHeightChanged({ height, ...options })); + dispatch(bboxWidthChanged({ width, ...options })); + dispatch(bboxHeightChanged({ height, ...options })); } else { const { width, height } = calculateNewSize( controlImage.width / controlImage.height, optimalDimension * optimalDimension ); - dispatch(documentWidthChanged({ width, ...options })); - dispatch(documentHeightChanged({ height, ...options })); + dispatch(bboxWidthChanged({ width, ...options })); + dispatch(bboxHeightChanged({ height, ...options })); } }, [controlImage, dispatch, optimalDimension, shift]); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/HeadsUpDisplay.tsx b/invokeai/frontend/web/src/features/controlLayers/components/HeadsUpDisplay.tsx index 9de1876f60..5f3bcab13c 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/HeadsUpDisplay.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/HeadsUpDisplay.tsx @@ -20,12 +20,10 @@ export const HeadsUpDisplay = memo(() => { const lastMouseDownPos = useStore($lastMouseDownPos); const lastAddedPoint = useStore($lastAddedPoint); const bbox = useAppSelector((s) => s.canvasV2.bbox); - const document = useAppSelector((s) => s.canvasV2.document); return ( - { const options = { updateAspectRatio: true, clamp: true }; if (shift) { const { width, height } = imageDTO; - dispatch(documentWidthChanged({ width, ...options })); - dispatch(documentHeightChanged({ height, ...options })); + dispatch(bboxWidthChanged({ width, ...options })); + dispatch(bboxHeightChanged({ height, ...options })); } else { const { width, height } = calculateNewSize(imageDTO.width / imageDTO.height, optimalDimension * optimalDimension); - dispatch(documentWidthChanged({ width, ...options })); - dispatch(documentHeightChanged({ height, ...options })); + dispatch(bboxWidthChanged({ width, ...options })); + dispatch(bboxHeightChanged({ height, ...options })); } }, [imageDTO, dispatch, optimalDimension, shift]); diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasDocumentSizeOverlay.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasDocumentSizeOverlay.ts deleted file mode 100644 index 00e51ab6cc..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasDocumentSizeOverlay.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { getArbitraryBaseColor } from '@invoke-ai/ui-library'; -import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; -import { DOCUMENT_FIT_PADDING_PX } from 'features/controlLayers/konva/constants'; -import Konva from 'konva'; - -export class CanvasDocumentSizeOverlay { - group: Konva.Group; - outerRect: Konva.Rect; - innerRect: Konva.Rect; - padding: number; - manager: CanvasManager; - - constructor(manager: CanvasManager, padding?: number) { - this.manager = manager; - this.padding = padding ?? DOCUMENT_FIT_PADDING_PX; - this.group = new Konva.Group({ id: 'document_overlay_group', listening: false }); - this.outerRect = new Konva.Rect({ - id: 'document_overlay_outer_rect', - listening: false, - fill: getArbitraryBaseColor(10), - opacity: 0.7, - }); - this.innerRect = new Konva.Rect({ - id: 'document_overlay_inner_rect', - listening: false, - fill: 'white', - globalCompositeOperation: 'destination-out', - }); - this.group.add(this.outerRect); - this.group.add(this.innerRect); - } - - render() { - const document = this.manager.stateApi.getDocument(); - this.group.zIndex(0); - - const x = this.manager.stage.x(); - const y = this.manager.stage.y(); - const width = this.manager.stage.width(); - const height = this.manager.stage.height(); - const scale = this.manager.stage.scaleX(); - - this.outerRect.setAttrs({ - offsetX: x / scale, - offsetY: y / scale, - width: width / scale, - height: height / scale, - }); - - this.innerRect.setAttrs(document.rect); - } - - fitToStage() { - const document = this.manager.stateApi.getDocument(); - - // Fit & center the document on the stage - const width = this.manager.stage.width(); - const height = this.manager.stage.height(); - const docWidthWithBuffer = document.rect.width + this.padding * 2; - const docHeightWithBuffer = document.rect.height + this.padding * 2; - const scale = Math.min(Math.min(width / docWidthWithBuffer, height / docHeightWithBuffer), 1); - const x = (width - docWidthWithBuffer * scale) / 2 + this.padding * scale; - const y = (height - docHeightWithBuffer * scale) / 2 + this.padding * scale; - this.manager.stage.setAttrs({ x, y, width, height, scaleX: scale, scaleY: scale }); - this.manager.stateApi.setStageAttrs({ x, y, width, height, scale }); - } -} diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts index b4b347d3e5..8c89e07c67 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts @@ -22,7 +22,6 @@ import { assert } from 'tsafe'; import { CanvasBackground } from './CanvasBackground'; import { CanvasBbox } from './CanvasBbox'; import { CanvasControlAdapter } from './CanvasControlAdapter'; -import { CanvasDocumentSizeOverlay } from './CanvasDocumentSizeOverlay'; import { CanvasInpaintMask } from './CanvasInpaintMask'; import { CanvasLayer } from './CanvasLayer'; import { CanvasPreview } from './CanvasPreview'; @@ -92,7 +91,6 @@ export class CanvasManager { this.preview = new CanvasPreview( new CanvasBbox(this), new CanvasTool(this), - new CanvasDocumentSizeOverlay(this), new CanvasStagingArea(this), new CanvasProgressPreview(this) ); @@ -221,7 +219,6 @@ export class CanvasManager { scale: this.stage.scaleX(), }); this.background.render(); - this.preview.documentSizeOverlay.render(); } render = async () => { @@ -245,7 +242,7 @@ export class CanvasManager { if ( this.isFirstRender || state.initialImage !== this.prevState.initialImage || - state.document !== this.prevState.document || + state.bbox.rect !== this.prevState.bbox.rect || state.tool.selected !== this.prevState.tool.selected || state.selectedEntityIdentifier?.id !== this.prevState.selectedEntityIdentifier?.id ) { @@ -285,11 +282,6 @@ export class CanvasManager { await this.renderControlAdapters(); } - if (this.isFirstRender || state.document !== this.prevState.document) { - log.debug('Rendering document bounds overlay'); - await this.preview.documentSizeOverlay.render(); - } - if ( this.isFirstRender || state.bbox !== this.prevState.bbox || @@ -367,9 +359,6 @@ export class CanvasManager { }); log.debug('First render of konva stage'); - // On first render, the document should be fit to the stage. - this.preview.documentSizeOverlay.render(); - this.preview.documentSizeOverlay.fitToStage(); this.preview.tool.render(); this.render(); diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasPreview.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasPreview.ts index 9634586560..3e64b8a28d 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasPreview.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasPreview.ts @@ -2,7 +2,6 @@ import type { CanvasProgressPreview } from 'features/controlLayers/konva/CanvasP import Konva from 'konva'; import type { CanvasBbox } from './CanvasBbox'; -import type { CanvasDocumentSizeOverlay } from './CanvasDocumentSizeOverlay'; import type { CanvasStagingArea } from './CanvasStagingArea'; import type { CanvasTool } from './CanvasTool'; @@ -10,22 +9,17 @@ export class CanvasPreview { layer: Konva.Layer; tool: CanvasTool; bbox: CanvasBbox; - documentSizeOverlay: CanvasDocumentSizeOverlay; stagingArea: CanvasStagingArea; progressPreview: CanvasProgressPreview; constructor( bbox: CanvasBbox, tool: CanvasTool, - documentSizeOverlay: CanvasDocumentSizeOverlay, stagingArea: CanvasStagingArea, progressPreview: CanvasProgressPreview ) { this.layer = new Konva.Layer({ listening: true, imageSmoothingEnabled: false }); - this.documentSizeOverlay = documentSizeOverlay; - this.layer.add(this.documentSizeOverlay.group); - this.stagingArea = stagingArea; this.layer.add(this.stagingArea.group); diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts index cac8dcce27..d40a51c3a6 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts @@ -207,9 +207,6 @@ export class CanvasStateApi { getBbox = () => { return this.getState().bbox; }; - getDocument = () => { - return this.getState().document; - }; getToolState = () => { return this.getState().tool; }; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/events.ts b/invokeai/frontend/web/src/features/controlLayers/konva/events.ts index 53a0218ab6..daaf63c8e7 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/events.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/events.ts @@ -137,14 +137,14 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => { function getClip(entity: RegionEntity | LayerEntity | InpaintMaskEntity) { const settings = getSettings(); - const bbox = getBbox(); + const bboxRect = getBbox().rect; if (settings.clipToBbox) { return { - x: bbox.x - entity.x, - y: bbox.y - entity.y, - width: bbox.width, - height: bbox.height, + x: bboxRect.x - entity.x, + y: bboxRect.y - entity.y, + width: bboxRect.width, + height: bboxRect.height, }; } else { return { @@ -486,7 +486,6 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => { stage.position(newPos); setStageAttrs({ ...newPos, width: stage.width(), height: stage.height(), scale: newScale }); manager.background.render(); - manager.preview.documentSizeOverlay.render(); } } manager.preview.tool.render(); @@ -502,7 +501,6 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => { scale: stage.scaleX(), }); manager.background.render(); - manager.preview.documentSizeOverlay.render(); manager.preview.tool.render(); }); @@ -540,9 +538,8 @@ export const setStageEventHandlers = (manager: CanvasManager): (() => void) => { } else if (e.key === 'r') { setLastCursorPos(null); setLastMouseDownPos(null); - manager.preview.documentSizeOverlay.fitToStage(); manager.background.render(); - manager.preview.documentSizeOverlay.render(); + // TODO(psyche): restore some kind of fit } manager.preview.tool.render(); }; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/bboxReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/bboxReducers.ts index c01bdf5b1a..202ec0dda2 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/bboxReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/bboxReducers.ts @@ -1,12 +1,17 @@ import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit'; +import { deepClone } from 'common/util/deepClone'; +import { roundDownToMultiple, roundToMultiple } from 'common/util/roundDownToMultiple'; import type { BoundingBoxScaleMethod, CanvasV2State, Size } from 'features/controlLayers/store/types'; import { getScaledBoundingBoxDimensions } from 'features/controlLayers/util/getScaledBoundingBoxDimensions'; +import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize'; +import { ASPECT_RATIO_MAP, initialAspectRatioState } from 'features/parameters/components/DocumentSize/constants'; +import type { AspectRatioID } from 'features/parameters/components/DocumentSize/types'; import { getOptimalDimension } from 'features/parameters/util/optimalDimension'; import type { IRect } from 'konva/lib/types'; import { pick } from 'lodash-es'; export const bboxReducers = { - scaledBboxChanged: (state, action: PayloadAction>) => { + bboxScaledSizeChanged: (state, action: PayloadAction>) => { state.layers.imageCache = null; state.bbox.scaledSize = { ...state.bbox.scaledSize, ...action.payload }; }, @@ -30,4 +35,116 @@ export const bboxReducers = { state.bbox.scaledSize = getScaledBoundingBoxDimensions(size, optimalDimension); } }, + bboxWidthChanged: (state, action: PayloadAction<{ width: number; updateAspectRatio?: boolean; clamp?: boolean }>) => { + const { width, updateAspectRatio, clamp } = action.payload; + state.bbox.rect.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width; + + if (state.bbox.aspectRatio.isLocked) { + state.bbox.rect.height = roundToMultiple(state.bbox.rect.width / state.bbox.aspectRatio.value, 8); + } + + if (updateAspectRatio || !state.bbox.aspectRatio.isLocked) { + state.bbox.aspectRatio.value = state.bbox.rect.width / state.bbox.rect.height; + state.bbox.aspectRatio.id = 'Free'; + state.bbox.aspectRatio.isLocked = false; + } + + if (!state.session.isActive) { + if (state.initialImage.imageObject) { + state.initialImage.imageObject.width = state.bbox.rect.width; + state.initialImage.imageObject.height = state.bbox.rect.height; + } + } + }, + bboxHeightChanged: ( + state, + action: PayloadAction<{ height: number; updateAspectRatio?: boolean; clamp?: boolean }> + ) => { + const { height, updateAspectRatio, clamp } = action.payload; + + state.bbox.rect.height = clamp ? Math.max(roundDownToMultiple(height, 8), 64) : height; + + if (state.bbox.aspectRatio.isLocked) { + state.bbox.rect.width = roundToMultiple(state.bbox.rect.height * state.bbox.aspectRatio.value, 8); + } + + if (updateAspectRatio || !state.bbox.aspectRatio.isLocked) { + state.bbox.aspectRatio.value = state.bbox.rect.width / state.bbox.rect.height; + state.bbox.aspectRatio.id = 'Free'; + state.bbox.aspectRatio.isLocked = false; + } + + if (!state.session.isActive) { + if (state.initialImage.imageObject) { + state.initialImage.imageObject.width = state.bbox.rect.width; + state.initialImage.imageObject.height = state.bbox.rect.height; + } + } + }, + bboxAspectRatioLockToggled: (state) => { + state.bbox.aspectRatio.isLocked = !state.bbox.aspectRatio.isLocked; + }, + bboxAspectRatioIdChanged: (state, action: PayloadAction<{ id: AspectRatioID }>) => { + const { id } = action.payload; + state.bbox.aspectRatio.id = id; + if (id === 'Free') { + state.bbox.aspectRatio.isLocked = false; + } else { + state.bbox.aspectRatio.isLocked = true; + state.bbox.aspectRatio.value = ASPECT_RATIO_MAP[id].ratio; + const { width, height } = calculateNewSize( + state.bbox.aspectRatio.value, + state.bbox.rect.width * state.bbox.rect.height + ); + state.bbox.rect.width = width; + state.bbox.rect.height = height; + } + if (!state.session.isActive) { + if (state.initialImage.imageObject) { + state.initialImage.imageObject.width = state.bbox.rect.width; + state.initialImage.imageObject.height = state.bbox.rect.height; + } + } + }, + bboxDimensionsSwapped: (state) => { + state.bbox.aspectRatio.value = 1 / state.bbox.aspectRatio.value; + if (state.bbox.aspectRatio.id === 'Free') { + const newWidth = state.bbox.rect.height; + const newHeight = state.bbox.rect.width; + state.bbox.rect.width = newWidth; + state.bbox.rect.height = newHeight; + } else { + const { width, height } = calculateNewSize( + state.bbox.aspectRatio.value, + state.bbox.rect.width * state.bbox.rect.height + ); + state.bbox.rect.width = width; + state.bbox.rect.height = height; + state.bbox.aspectRatio.id = ASPECT_RATIO_MAP[state.bbox.aspectRatio.id].inverseID; + } + if (!state.session.isActive) { + if (state.initialImage.imageObject) { + state.initialImage.imageObject.width = state.bbox.rect.width; + state.initialImage.imageObject.height = state.bbox.rect.height; + } + } + }, + bboxSizeOptimized: (state) => { + const optimalDimension = getOptimalDimension(state.params.model); + if (state.bbox.aspectRatio.isLocked) { + const { width, height } = calculateNewSize(state.bbox.aspectRatio.value, optimalDimension ** 2); + state.bbox.rect.width = width; + state.bbox.rect.height = height; + } else { + state.bbox.aspectRatio = deepClone(initialAspectRatioState); + state.bbox.rect.width = optimalDimension; + state.bbox.rect.height = optimalDimension; + } + if (!state.session.isActive) { + if (state.initialImage.imageObject) { + state.initialImage.imageObject.width = state.bbox.rect.width; + state.initialImage.imageObject.height = state.bbox.rect.height; + } + } + }, } satisfies SliceCaseReducers; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts index 77697caf9e..22accd05c1 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts @@ -5,7 +5,6 @@ import { deepClone } from 'common/util/deepClone'; import { bboxReducers } from 'features/controlLayers/store/bboxReducers'; import { compositingReducers } from 'features/controlLayers/store/compositingReducers'; import { controlAdaptersReducers } from 'features/controlLayers/store/controlAdaptersReducers'; -import { documentReducers } from 'features/controlLayers/store/documentReducers'; import { initialImageReducers } from 'features/controlLayers/store/initialImageReducers'; import { inpaintMaskReducers } from 'features/controlLayers/store/inpaintMaskReducers'; import { ipAdaptersReducers } from 'features/controlLayers/store/ipAdaptersReducers'; @@ -63,12 +62,9 @@ const initialState: CanvasV2State = { width: 50, }, }, - document: { - rect: { x: 0, y: 0, width: 512, height: 512 }, - aspectRatio: deepClone(initialAspectRatioState), - }, bbox: { rect: { x: 0, y: 0, width: 512, height: 512 }, + aspectRatio: deepClone(initialAspectRatioState), scaleMethod: 'auto', scaledSize: { width: 512, @@ -149,7 +145,6 @@ export const canvasV2Slice = createSlice({ ...bboxReducers, ...inpaintMaskReducers, ...sessionReducers, - ...documentReducers, ...initialImageReducers, entitySelected: (state, action: PayloadAction) => { state.selectedEntityIdentifier = action.payload; @@ -164,7 +159,6 @@ export const canvasV2Slice = createSlice({ canvasReset: (state) => { state.bbox = deepClone(initialState.bbox); state.controlAdapters = deepClone(initialState.controlAdapters); - state.document = deepClone(initialState.document); state.ipAdapters = deepClone(initialState.ipAdapters); state.layers = deepClone(initialState.layers); state.regions = deepClone(initialState.regions); @@ -178,7 +172,6 @@ export const canvasV2Slice = createSlice({ }); export const { - bboxChanged, brushWidthChanged, eraserWidthChanged, fillChanged, @@ -188,17 +181,18 @@ export const { maskOpacityChanged, entitySelected, allEntitiesDeleted, - scaledBboxChanged, - bboxScaleMethodChanged, clipToBboxChanged, canvasReset, - // document - documentWidthChanged, - documentHeightChanged, - documentAspectRatioLockToggled, - documentAspectRatioIdChanged, - documentDimensionsSwapped, - documentSizeOptimized, + // bbox + bboxChanged, + bboxScaledSizeChanged, + bboxScaleMethodChanged, + bboxWidthChanged, + bboxHeightChanged, + bboxAspectRatioLockToggled, + bboxAspectRatioIdChanged, + bboxDimensionsSwapped, + bboxSizeOptimized, // layers layerAdded, layerRecalled, diff --git a/invokeai/frontend/web/src/features/controlLayers/store/documentReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/documentReducers.ts deleted file mode 100644 index a4649ca541..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/store/documentReducers.ts +++ /dev/null @@ -1,141 +0,0 @@ -import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit'; -import { deepClone } from 'common/util/deepClone'; -import { roundDownToMultiple, roundToMultiple } from 'common/util/roundDownToMultiple'; -import type { CanvasV2State } from 'features/controlLayers/store/types'; -import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize'; -import { ASPECT_RATIO_MAP, initialAspectRatioState } from 'features/parameters/components/DocumentSize/constants'; -import type { AspectRatioID } from 'features/parameters/components/DocumentSize/types'; -import { getOptimalDimension } from 'features/parameters/util/optimalDimension'; - -export const documentReducers = { - documentWidthChanged: ( - state, - action: PayloadAction<{ width: number; updateAspectRatio?: boolean; clamp?: boolean }> - ) => { - const { width, updateAspectRatio, clamp } = action.payload; - state.document.rect.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width; - - if (state.document.aspectRatio.isLocked) { - state.document.rect.height = roundToMultiple(state.document.rect.width / state.document.aspectRatio.value, 8); - } - - if (updateAspectRatio || !state.document.aspectRatio.isLocked) { - state.document.aspectRatio.value = state.document.rect.width / state.document.rect.height; - state.document.aspectRatio.id = 'Free'; - state.document.aspectRatio.isLocked = false; - } - - if (!state.session.isActive) { - state.bbox.rect.width = state.document.rect.width; - state.bbox.rect.height = state.document.rect.height; - - if (state.initialImage.imageObject) { - state.initialImage.imageObject.width = state.document.rect.width; - state.initialImage.imageObject.height = state.document.rect.height; - } - } - }, - documentHeightChanged: ( - state, - action: PayloadAction<{ height: number; updateAspectRatio?: boolean; clamp?: boolean }> - ) => { - const { height, updateAspectRatio, clamp } = action.payload; - - state.document.rect.height = clamp ? Math.max(roundDownToMultiple(height, 8), 64) : height; - - if (state.document.aspectRatio.isLocked) { - state.document.rect.width = roundToMultiple(state.document.rect.height * state.document.aspectRatio.value, 8); - } - - if (updateAspectRatio || !state.document.aspectRatio.isLocked) { - state.document.aspectRatio.value = state.document.rect.width / state.document.rect.height; - state.document.aspectRatio.id = 'Free'; - state.document.aspectRatio.isLocked = false; - } - - if (!state.session.isActive) { - state.bbox.rect.width = state.document.rect.width; - state.bbox.rect.height = state.document.rect.height; - - if (state.initialImage.imageObject) { - state.initialImage.imageObject.width = state.document.rect.width; - state.initialImage.imageObject.height = state.document.rect.height; - } - } - }, - documentAspectRatioLockToggled: (state) => { - state.document.aspectRatio.isLocked = !state.document.aspectRatio.isLocked; - }, - documentAspectRatioIdChanged: (state, action: PayloadAction<{ id: AspectRatioID }>) => { - const { id } = action.payload; - state.document.aspectRatio.id = id; - if (id === 'Free') { - state.document.aspectRatio.isLocked = false; - } else { - state.document.aspectRatio.isLocked = true; - state.document.aspectRatio.value = ASPECT_RATIO_MAP[id].ratio; - const { width, height } = calculateNewSize( - state.document.aspectRatio.value, - state.document.rect.width * state.document.rect.height - ); - state.document.rect.width = width; - state.document.rect.height = height; - } - if (!state.session.isActive) { - state.bbox.rect.width = state.document.rect.width; - state.bbox.rect.height = state.document.rect.height; - - if (state.initialImage.imageObject) { - state.initialImage.imageObject.width = state.document.rect.width; - state.initialImage.imageObject.height = state.document.rect.height; - } - } - }, - documentDimensionsSwapped: (state) => { - state.document.aspectRatio.value = 1 / state.document.aspectRatio.value; - if (state.document.aspectRatio.id === 'Free') { - const newWidth = state.document.rect.height; - const newHeight = state.document.rect.width; - state.document.rect.width = newWidth; - state.document.rect.height = newHeight; - } else { - const { width, height } = calculateNewSize( - state.document.aspectRatio.value, - state.document.rect.width * state.document.rect.height - ); - state.document.rect.width = width; - state.document.rect.height = height; - state.document.aspectRatio.id = ASPECT_RATIO_MAP[state.document.aspectRatio.id].inverseID; - } - if (!state.session.isActive) { - state.bbox.rect.width = state.document.rect.width; - state.bbox.rect.height = state.document.rect.height; - - if (state.initialImage.imageObject) { - state.initialImage.imageObject.width = state.document.rect.width; - state.initialImage.imageObject.height = state.document.rect.height; - } - } - }, - documentSizeOptimized: (state) => { - const optimalDimension = getOptimalDimension(state.params.model); - if (state.document.aspectRatio.isLocked) { - const { width, height } = calculateNewSize(state.document.aspectRatio.value, optimalDimension ** 2); - state.document.rect.width = width; - state.document.rect.height = height; - } else { - state.document.aspectRatio = deepClone(initialAspectRatioState); - state.document.rect.width = optimalDimension; - state.document.rect.height = optimalDimension; - } - if (!state.session.isActive) { - state.bbox.rect.width = state.document.rect.width; - state.bbox.rect.height = state.document.rect.height; - - if (state.initialImage.imageObject) { - state.initialImage.imageObject.width = state.document.rect.width; - state.initialImage.imageObject.height = state.document.rect.height; - } - } - }, -} satisfies SliceCaseReducers; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/paramsReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/paramsReducers.ts index 6cf8fc68c3..548833587e 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/paramsReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/paramsReducers.ts @@ -62,8 +62,8 @@ export const paramsReducers = { // Update the bbox size to match the new model's optimal size // TODO(psyche): Should we change the document size too? const optimalDimension = getOptimalDimension(model); - if (!getIsSizeOptimal(state.document.rect.width, state.document.rect.height, optimalDimension)) { - const bboxDims = calculateNewSize(state.document.aspectRatio.value, optimalDimension * optimalDimension); + if (!getIsSizeOptimal(state.bbox.rect.width, state.bbox.rect.height, optimalDimension)) { + const bboxDims = calculateNewSize(state.bbox.aspectRatio.value, optimalDimension * optimalDimension); state.bbox.rect.width = bboxDims.width; state.bbox.rect.height = bboxDims.height; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 6a1ea536f7..0a6f21c2e7 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -847,15 +847,6 @@ export type CanvasV2State = { eraser: { width: number }; fill: RgbaColor; }; - document: { - rect: { - x: number; - y: number; - width: ParameterWidth; - height: ParameterHeight; - }; - aspectRatio: AspectRatioState; - }; settings: { imageSmoothing: boolean; maskOpacity: number; @@ -872,6 +863,7 @@ export type CanvasV2State = { width: ParameterWidth; height: ParameterHeight; }; + aspectRatio: AspectRatioState; scaledSize: { width: ParameterWidth; height: ParameterHeight; diff --git a/invokeai/frontend/web/src/features/metadata/util/recallers.ts b/invokeai/frontend/web/src/features/metadata/util/recallers.ts index de9efe32ce..94d19c57a8 100644 --- a/invokeai/frontend/web/src/features/metadata/util/recallers.ts +++ b/invokeai/frontend/web/src/features/metadata/util/recallers.ts @@ -11,9 +11,9 @@ import { getRGId, } from 'features/controlLayers/konva/naming'; import { + bboxHeightChanged, + bboxWidthChanged, caRecalled, - documentHeightChanged, - documentWidthChanged, ipaRecalled, layerAllDeleted, layerRecalled, @@ -115,11 +115,11 @@ const recallScheduler: MetadataRecallFunc = (scheduler) => { const setSizeOptions = { updateAspectRatio: true, clamp: true }; const recallWidth: MetadataRecallFunc = (width) => { - getStore().dispatch(documentWidthChanged({ width, ...setSizeOptions })); + getStore().dispatch(bboxWidthChanged({ width, ...setSizeOptions })); }; const recallHeight: MetadataRecallFunc = (height) => { - getStore().dispatch(documentHeightChanged({ height, ...setSizeOptions })); + getStore().dispatch(bboxHeightChanged({ height, ...setSizeOptions })); }; const recallSteps: MetadataRecallFunc = (steps) => { diff --git a/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamScaledHeight.tsx b/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamScaledHeight.tsx index d9871bc78f..5d35387fd8 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamScaledHeight.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamScaledHeight.tsx @@ -1,6 +1,6 @@ import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { scaledBboxChanged } from 'features/controlLayers/store/canvasV2Slice'; +import { bboxScaledSizeChanged } from 'features/controlLayers/store/canvasV2Slice'; import { selectOptimalDimension } from 'features/controlLayers/store/selectors'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -20,7 +20,7 @@ const ParamScaledHeight = () => { const onChange = useCallback( (height: number) => { - dispatch(scaledBboxChanged({ height })); + dispatch(bboxScaledSizeChanged({ height })); }, [dispatch] ); diff --git a/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamScaledWidth.tsx b/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamScaledWidth.tsx index 6f5338c9ef..7c92e2a7dc 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamScaledWidth.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Canvas/InfillAndScaling/ParamScaledWidth.tsx @@ -1,6 +1,6 @@ import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { scaledBboxChanged } from 'features/controlLayers/store/canvasV2Slice'; +import { bboxScaledSizeChanged } from 'features/controlLayers/store/canvasV2Slice'; import { selectOptimalDimension } from 'features/controlLayers/store/selectors'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -19,7 +19,7 @@ const ParamScaledWidth = () => { const fineStep = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.fineStep); const onChange = useCallback( (width: number) => { - dispatch(scaledBboxChanged({ width })); + dispatch(bboxScaledSizeChanged({ width })); }, [dispatch] ); diff --git a/invokeai/frontend/web/src/features/parameters/components/Core/ParamHeight.tsx b/invokeai/frontend/web/src/features/parameters/components/Core/ParamHeight.tsx index dbf8d9346a..93fa1319b6 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Core/ParamHeight.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Core/ParamHeight.tsx @@ -1,7 +1,7 @@ import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { documentHeightChanged } from 'features/controlLayers/store/canvasV2Slice'; +import { bboxHeightChanged } from 'features/controlLayers/store/canvasV2Slice'; import { selectOptimalDimension } from 'features/controlLayers/store/selectors'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,7 +10,7 @@ export const ParamHeight = memo(() => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const optimalDimension = useAppSelector(selectOptimalDimension); - const height = useAppSelector((s) => s.canvasV2.document.rect.height); + const height = useAppSelector((s) => s.canvasV2.bbox.rect.height); const sliderMin = useAppSelector((s) => s.config.sd.height.sliderMin); const sliderMax = useAppSelector((s) => s.config.sd.height.sliderMax); const numberInputMin = useAppSelector((s) => s.config.sd.height.numberInputMin); @@ -20,7 +20,7 @@ export const ParamHeight = memo(() => { const onChange = useCallback( (v: number) => { - dispatch(documentHeightChanged({ height: v })); + dispatch(bboxHeightChanged({ height: v })); }, [dispatch] ); diff --git a/invokeai/frontend/web/src/features/parameters/components/Core/ParamWidth.tsx b/invokeai/frontend/web/src/features/parameters/components/Core/ParamWidth.tsx index ddf4975fc9..66dc071d63 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Core/ParamWidth.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Core/ParamWidth.tsx @@ -1,7 +1,7 @@ import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { documentWidthChanged } from 'features/controlLayers/store/canvasV2Slice'; +import { bboxWidthChanged } from 'features/controlLayers/store/canvasV2Slice'; import { selectOptimalDimension } from 'features/controlLayers/store/selectors'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next'; export const ParamWidth = memo(() => { const { t } = useTranslation(); const dispatch = useAppDispatch(); - const width = useAppSelector((s) => s.canvasV2.document.rect.width); + const width = useAppSelector((s) => s.canvasV2.bbox.rect.width); const optimalDimension = useAppSelector(selectOptimalDimension); const sliderMin = useAppSelector((s) => s.config.sd.width.sliderMin); const sliderMax = useAppSelector((s) => s.config.sd.width.sliderMax); @@ -20,7 +20,7 @@ export const ParamWidth = memo(() => { const onChange = useCallback( (v: number) => { - dispatch(documentWidthChanged({ width: v })); + dispatch(bboxWidthChanged({ width: v })); }, [dispatch] ); diff --git a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/AspectRatioIconPreview.tsx b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/AspectRatioIconPreview.tsx index 9b8af7e16e..df7c54c7a7 100644 --- a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/AspectRatioIconPreview.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/AspectRatioIconPreview.tsx @@ -16,13 +16,13 @@ import { } from './constants'; export const AspectRatioIconPreview = memo(() => { - const document = useAppSelector((s) => s.canvasV2.document); + const bbox = useAppSelector((s) => s.canvasV2.bbox); const containerRef = useRef(null); const containerSize = useSize(containerRef); const shouldShowIcon = useMemo( - () => document.aspectRatio.value < ICON_HIGH_CUTOFF && document.aspectRatio.value > ICON_LOW_CUTOFF, - [document.aspectRatio.value] + () => bbox.aspectRatio.value < ICON_HIGH_CUTOFF && bbox.aspectRatio.value > ICON_LOW_CUTOFF, + [bbox.aspectRatio.value] ); const { width, height } = useMemo(() => { @@ -30,19 +30,19 @@ export const AspectRatioIconPreview = memo(() => { return { width: 0, height: 0 }; } - let width = document.rect.width; - let height = document.rect.height; + let width = bbox.rect.width; + let height = bbox.rect.height; - if (document.rect.width > document.rect.height) { + if (bbox.rect.width > bbox.rect.height) { width = containerSize.width; - height = width / document.aspectRatio.value; + height = width / bbox.aspectRatio.value; } else { height = containerSize.height; - width = height * document.aspectRatio.value; + width = height * bbox.aspectRatio.value; } return { width, height }; - }, [containerSize, document.rect.width, document.rect.height, document.aspectRatio.value]); + }, [containerSize, bbox.rect.width, bbox.rect.height, bbox.aspectRatio.value]); return ( diff --git a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/AspectRatioSelect.tsx b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/AspectRatioSelect.tsx index 92256b3b3f..f2c3fc66de 100644 --- a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/AspectRatioSelect.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/AspectRatioSelect.tsx @@ -3,7 +3,7 @@ import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import type { SingleValue } from 'chakra-react-select'; import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover'; -import { documentAspectRatioIdChanged } from 'features/controlLayers/store/canvasV2Slice'; +import { bboxAspectRatioIdChanged } from 'features/controlLayers/store/canvasV2Slice'; import { ASPECT_RATIO_OPTIONS } from 'features/parameters/components/DocumentSize/constants'; import { isAspectRatioID } from 'features/parameters/components/DocumentSize/types'; import { memo, useCallback, useMemo } from 'react'; @@ -12,14 +12,14 @@ import { useTranslation } from 'react-i18next'; export const AspectRatioSelect = memo(() => { const { t } = useTranslation(); const dispatch = useAppDispatch(); - const id = useAppSelector((s) => s.canvasV2.document.aspectRatio.id); + const id = useAppSelector((s) => s.canvasV2.bbox.aspectRatio.id); const onChange = useCallback( (v: SingleValue) => { if (!v || !isAspectRatioID(v.value)) { return; } - dispatch(documentAspectRatioIdChanged({ id: v.value })); + dispatch(bboxAspectRatioIdChanged({ id: v.value })); }, [dispatch] ); diff --git a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/LockAspectRatioButton.tsx b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/LockAspectRatioButton.tsx index 1d239d201f..47846ad8a0 100644 --- a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/LockAspectRatioButton.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/LockAspectRatioButton.tsx @@ -1,6 +1,6 @@ import { IconButton } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { documentAspectRatioLockToggled } from 'features/controlLayers/store/canvasV2Slice'; +import { bboxAspectRatioLockToggled } from 'features/controlLayers/store/canvasV2Slice'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { PiLockSimpleFill, PiLockSimpleOpenBold } from 'react-icons/pi'; @@ -8,9 +8,9 @@ import { PiLockSimpleFill, PiLockSimpleOpenBold } from 'react-icons/pi'; export const LockAspectRatioButton = memo(() => { const { t } = useTranslation(); const dispatch = useAppDispatch(); - const isLocked = useAppSelector((s) => s.canvasV2.document.aspectRatio.isLocked); + const isLocked = useAppSelector((s) => s.canvasV2.bbox.aspectRatio.isLocked); const onClick = useCallback(() => { - dispatch(documentAspectRatioLockToggled()); + dispatch(bboxAspectRatioLockToggled()); }, [dispatch]); return ( diff --git a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/SetOptimalSizeButton.tsx b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/SetOptimalSizeButton.tsx index a5e88513f8..377ae4d4b2 100644 --- a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/SetOptimalSizeButton.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/SetOptimalSizeButton.tsx @@ -1,6 +1,6 @@ import { IconButton } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { documentSizeOptimized } from 'features/controlLayers/store/canvasV2Slice'; +import { bboxSizeOptimized } from 'features/controlLayers/store/canvasV2Slice'; import { selectOptimalDimension } from 'features/controlLayers/store/selectors'; import { getIsSizeTooLarge, getIsSizeTooSmall } from 'features/parameters/util/optimalDimension'; import { memo, useCallback, useMemo } from 'react'; @@ -10,8 +10,8 @@ import { RiSparklingFill } from 'react-icons/ri'; export const SetOptimalSizeButton = memo(() => { const { t } = useTranslation(); const dispatch = useAppDispatch(); - const width = useAppSelector((s) => s.canvasV2.document.rect.width); - const height = useAppSelector((s) => s.canvasV2.document.rect.height); + const width = useAppSelector((s) => s.canvasV2.bbox.rect.width); + const height = useAppSelector((s) => s.canvasV2.bbox.rect.height); const optimalDimension = useAppSelector(selectOptimalDimension); const isSizeTooSmall = useMemo( () => getIsSizeTooSmall(width, height, optimalDimension), @@ -22,7 +22,7 @@ export const SetOptimalSizeButton = memo(() => { [height, width, optimalDimension] ); const onClick = useCallback(() => { - dispatch(documentSizeOptimized()); + dispatch(bboxSizeOptimized()); }, [dispatch]); const tooltip = useMemo(() => { if (isSizeTooSmall) { diff --git a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/SwapDimensionsButton.tsx b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/SwapDimensionsButton.tsx index bc57ca3f51..f4f586c0f8 100644 --- a/invokeai/frontend/web/src/features/parameters/components/DocumentSize/SwapDimensionsButton.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/DocumentSize/SwapDimensionsButton.tsx @@ -1,6 +1,6 @@ import { IconButton } from '@invoke-ai/ui-library'; import { useAppDispatch } from 'app/store/storeHooks'; -import { documentDimensionsSwapped } from 'features/controlLayers/store/canvasV2Slice'; +import { bboxDimensionsSwapped } from 'features/controlLayers/store/canvasV2Slice'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { PiArrowsDownUpBold } from 'react-icons/pi'; @@ -9,7 +9,7 @@ export const SwapDimensionsButton = memo(() => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const onClick = useCallback(() => { - dispatch(documentDimensionsSwapped()); + dispatch(bboxDimensionsSwapped()); }, [dispatch]); return (