diff --git a/frontend/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx b/frontend/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx index efafa05d0f..2bf3ea9091 100644 --- a/frontend/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx +++ b/frontend/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx @@ -6,6 +6,7 @@ import { resetCanvasView, setShouldLockToInitialImage, setTool, + fitBoundingBoxToStage, } from 'features/canvas/store/canvasSlice'; import { useAppDispatch, useAppSelector } from 'app/store'; import _ from 'lodash'; @@ -30,7 +31,10 @@ import IAICanvasMaskButtonPopover from './IAICanvasMaskButtonPopover'; import { mergeAndUploadCanvas } from 'features/canvas/util/mergeAndUploadCanvas'; import IAICheckbox from 'common/components/IAICheckbox'; import { ChangeEvent } from 'react'; -import { canvasSelector, isStagingSelector } from 'features/canvas/store/canvasSelectors'; +import { + canvasSelector, + isStagingSelector, +} from 'features/canvas/store/canvasSelectors'; export const selector = createSelector( [canvasSelector, isStagingSelector], @@ -59,6 +63,7 @@ const IAICanvasOutpaintingControls = () => { ) => { dispatch(setShouldLockToInitialImage(e.target.checked)); dispatch(resizeAndScaleCanvas()); + dispatch(fitBoundingBoxToStage()); }; return ( diff --git a/frontend/src/features/canvas/store/canvasSlice.ts b/frontend/src/features/canvas/store/canvasSlice.ts index 22b7dc9334..b252a1b2e4 100644 --- a/frontend/src/features/canvas/store/canvasSlice.ts +++ b/frontend/src/features/canvas/store/canvasSlice.ts @@ -4,7 +4,10 @@ import { IRect, Vector2d } from 'konva/lib/types'; import { RgbaColor } from 'react-colorful'; import * as InvokeAI from 'app/invokeai'; import _ from 'lodash'; -import { roundDownToMultiple } from 'common/util/roundDownToMultiple'; +import { + roundDownToMultiple, + roundToMultiple, +} from 'common/util/roundDownToMultiple'; import { canvasExtraReducers, setInitialCanvasImage_reducer, @@ -498,6 +501,44 @@ export const canvasSlice = createSlice({ setShouldLockToInitialImage: (state, action: PayloadAction) => { state.shouldLockToInitialImage = action.payload; }, + fitBoundingBoxToStage: (state) => { + const { boundingBoxDimensions, boundingBoxCoordinates, stageDimensions } = + state; + + if ( + boundingBoxCoordinates.x < 0 || + boundingBoxCoordinates.x + boundingBoxDimensions.width > + stageDimensions.width || + boundingBoxCoordinates.y < 0 || + boundingBoxCoordinates.y + boundingBoxDimensions.height > + stageDimensions.height + ) { + const newBoundingBoxDimensions = { + width: roundDownToMultiple( + _.clamp(stageDimensions.width, 64, 512), + 64 + ), + height: roundDownToMultiple( + _.clamp(stageDimensions.height, 64, 512), + 64 + ), + }; + + const newBoundingBoxCoordinates = { + x: roundToMultiple( + stageDimensions.width / 2 - newBoundingBoxDimensions.width / 2, + 64 + ), + y: roundToMultiple( + stageDimensions.height / 2 - newBoundingBoxDimensions.height / 2, + 64 + ), + }; + + state.boundingBoxDimensions = newBoundingBoxDimensions; + state.boundingBoxCoordinates = newBoundingBoxCoordinates; + } + }, }, extraReducers: canvasExtraReducers, }); @@ -558,6 +599,7 @@ export const { resizeCanvas, resetCanvasView, setCanvasContainerDimensions, + fitBoundingBoxToStage, } = canvasSlice.actions; export default canvasSlice.reducer;