Improves bounding box interactions

- Bounding box can now be moved by dragging any of its edges
- Bounding box does not affect drawing if already drawing a stroke
- Can lock bounding box to draw directly on the bounding box edges
- Removes spacebar-hold behaviour due to technical issues
This commit is contained in:
psychedelicious 2022-11-01 16:28:30 +11:00 committed by Lincoln Stein
parent d43bd4625d
commit 82dcbac28f
8 changed files with 258 additions and 135 deletions

View File

@ -113,7 +113,7 @@ const BoundingBoxSettings = () => {
<div className="inpainting-bounding-box-settings"> <div className="inpainting-bounding-box-settings">
<div className="inpainting-bounding-box-header"> <div className="inpainting-bounding-box-header">
<p>Inpaint Box</p> <p>Inpaint Box</p>
<IAIIconButton {/* <IAIIconButton
aria-label="Toggle Bounding Box Visibility" aria-label="Toggle Bounding Box Visibility"
icon={ icon={
shouldShowBoundingBox ? <BiShow size={22} /> : <BiHide size={22} /> shouldShowBoundingBox ? <BiShow size={22} /> : <BiHide size={22} />
@ -121,11 +121,12 @@ const BoundingBoxSettings = () => {
onClick={handleShowBoundingBox} onClick={handleShowBoundingBox}
background={'none'} background={'none'}
padding={0} padding={0}
/> /> */}
</div> </div>
<div className="inpainting-bounding-box-settings-items"> <div className="inpainting-bounding-box-settings-items">
<div className="inpainting-bounding-box-dimensions-slider-numberinput"> <div className="inpainting-bounding-box-dimensions-slider-numberinput">
<IAISlider <IAISlider
isDisabled={shouldLockBoundingBox}
label="Box W" label="Box W"
min={64} min={64}
max={roundDownToMultiple(canvasDimensions.width, 64)} max={roundDownToMultiple(canvasDimensions.width, 64)}
@ -135,6 +136,7 @@ const BoundingBoxSettings = () => {
width={'5rem'} width={'5rem'}
/> />
<IAINumberInput <IAINumberInput
isDisabled={shouldLockBoundingBox}
value={boundingBoxDimensions.width} value={boundingBoxDimensions.width}
onChange={handleChangeBoundingBoxWidth} onChange={handleChangeBoundingBoxWidth}
min={64} min={64}
@ -143,6 +145,7 @@ const BoundingBoxSettings = () => {
width={'5rem'} width={'5rem'}
/> />
<IAIIconButton <IAIIconButton
isDisabled={shouldLockBoundingBox}
size={'sm'} size={'sm'}
aria-label={'Reset Width'} aria-label={'Reset Width'}
tooltip={'Reset Width'} tooltip={'Reset Width'}
@ -154,6 +157,7 @@ const BoundingBoxSettings = () => {
</div> </div>
<div className="inpainting-bounding-box-dimensions-slider-numberinput"> <div className="inpainting-bounding-box-dimensions-slider-numberinput">
<IAISlider <IAISlider
isDisabled={shouldLockBoundingBox}
label="Box H" label="Box H"
min={64} min={64}
max={roundDownToMultiple(canvasDimensions.height, 64)} max={roundDownToMultiple(canvasDimensions.height, 64)}
@ -163,6 +167,7 @@ const BoundingBoxSettings = () => {
width={'5rem'} width={'5rem'}
/> />
<IAINumberInput <IAINumberInput
isDisabled={shouldLockBoundingBox}
value={boundingBoxDimensions.height} value={boundingBoxDimensions.height}
onChange={handleChangeBoundingBoxHeight} onChange={handleChangeBoundingBoxHeight}
min={64} min={64}
@ -172,6 +177,7 @@ const BoundingBoxSettings = () => {
width={'5rem'} width={'5rem'}
/> />
<IAIIconButton <IAIIconButton
isDisabled={shouldLockBoundingBox}
size={'sm'} size={'sm'}
aria-label={'Reset Height'} aria-label={'Reset Height'}
tooltip={'Reset Height'} tooltip={'Reset Height'}

View File

@ -45,32 +45,40 @@
height: 100%; height: 100%;
} }
.inpainting-canvas-wrapper { .inpainting-canvas-spiner {
display: flex;
align-items: center;
width: 100%;
height: 100%;
}
.inpainting-canvas-container {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: relative;
height: 100%; height: 100%;
width: 100%; width: 100%;
border-radius: 0.5rem; border-radius: 0.5rem;
.inpainting-canvas-wrapper {
position: relative;
}
.inpainting-alerts { .inpainting-alerts {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
display: flex; display: flex;
column-gap: 0.5rem;
z-index: 2; z-index: 2;
padding: 0.5rem; padding: 0.25rem;
pointer-events: none; pointer-events: none;
font-size: 0.9rem;
font-weight: bold;
div { button {
background-color: var(--accent-color); &[data-selected='true'] {
color: var(--text-color); svg {
padding: 0.2rem 0.6rem; fill: var(--accent-color);
border-radius: 0.25rem; }
}
} }
} }

View File

@ -34,7 +34,10 @@ import InpaintingBoundingBoxPreview, {
} from './components/InpaintingBoundingBoxPreview'; } from './components/InpaintingBoundingBoxPreview';
import { KonvaEventObject } from 'konva/lib/Node'; import { KonvaEventObject } from 'konva/lib/Node';
import KeyboardEventManager from './components/KeyboardEventManager'; import KeyboardEventManager from './components/KeyboardEventManager';
import { useToast } from '@chakra-ui/react'; import { Icon, IconButton, Tooltip, useToast } from '@chakra-ui/react';
import { FaLock, FaUnlock } from 'react-icons/fa';
import { MdInvertColors, MdInvertColorsOff } from 'react-icons/md';
import { BiHide, BiShow } from 'react-icons/bi';
// Use a closure allow other components to use these things... not ideal... // Use a closure allow other components to use these things... not ideal...
export let stageRef: MutableRefObject<StageType | null>; export let stageRef: MutableRefObject<StageType | null>;
@ -58,6 +61,10 @@ const InpaintingCanvas = () => {
isDrawing, isDrawing,
shouldLockBoundingBox, shouldLockBoundingBox,
boundingBoxDimensions, boundingBoxDimensions,
// isTransformingBoundingBox,
isMouseOverBoundingBox,
isModifyingBoundingBox,
stageCursor,
} = useAppSelector(inpaintingCanvasSelector); } = useAppSelector(inpaintingCanvasSelector);
const toast = useToast(); const toast = useToast();
@ -113,7 +120,7 @@ const InpaintingCanvas = () => {
if ( if (
!scaledCursorPosition || !scaledCursorPosition ||
!maskLayerRef.current || !maskLayerRef.current ||
!shouldLockBoundingBox isModifyingBoundingBox
) )
return; return;
@ -127,7 +134,7 @@ const InpaintingCanvas = () => {
points: [scaledCursorPosition.x, scaledCursorPosition.y], points: [scaledCursorPosition.x, scaledCursorPosition.y],
}) })
); );
}, [dispatch, brushSize, tool, shouldLockBoundingBox]); }, [dispatch, brushSize, tool, isModifyingBoundingBox]);
/** /**
* *
@ -143,20 +150,20 @@ const InpaintingCanvas = () => {
dispatch(setCursorPosition(scaledCursorPosition)); dispatch(setCursorPosition(scaledCursorPosition));
if (!maskLayerRef.current || !shouldLockBoundingBox) { if (!maskLayerRef.current) {
return; return;
} }
lastCursorPosition.current = scaledCursorPosition; lastCursorPosition.current = scaledCursorPosition;
if (!isDrawing) return; if (!isDrawing || isModifyingBoundingBox) return;
didMouseMoveRef.current = true; didMouseMoveRef.current = true;
// Extend the current line // Extend the current line
dispatch( dispatch(
addPointToCurrentLine([scaledCursorPosition.x, scaledCursorPosition.y]) addPointToCurrentLine([scaledCursorPosition.x, scaledCursorPosition.y])
); );
}, [dispatch, isDrawing, shouldLockBoundingBox]); }, [dispatch, isDrawing, isModifyingBoundingBox]);
/** /**
* *
@ -170,7 +177,7 @@ const InpaintingCanvas = () => {
if ( if (
!scaledCursorPosition || !scaledCursorPosition ||
!maskLayerRef.current || !maskLayerRef.current ||
!shouldLockBoundingBox isModifyingBoundingBox
) )
return; return;
@ -187,7 +194,7 @@ const InpaintingCanvas = () => {
didMouseMoveRef.current = false; didMouseMoveRef.current = false;
} }
dispatch(setIsDrawing(false)); dispatch(setIsDrawing(false));
}, [dispatch, isDrawing, shouldLockBoundingBox]); }, [dispatch, isDrawing, isModifyingBoundingBox]);
/** /**
* *
@ -214,7 +221,7 @@ const InpaintingCanvas = () => {
if ( if (
!scaledCursorPosition || !scaledCursorPosition ||
!maskLayerRef.current || !maskLayerRef.current ||
!shouldLockBoundingBox isModifyingBoundingBox
) )
return; return;
@ -230,23 +237,44 @@ const InpaintingCanvas = () => {
); );
} }
}, },
[dispatch, brushSize, tool, shouldLockBoundingBox] [dispatch, brushSize, tool, isModifyingBoundingBox]
); );
return ( return (
<div className="inpainting-canvas-wrapper" tabIndex={1}> <div className="inpainting-canvas-container" tabIndex={1}>
<div className="inpainting-canvas-wrapper">
<div className="inpainting-alerts"> <div className="inpainting-alerts">
{!shouldShowMask && (
<div style={{ pointerEvents: 'none' }}>Mask Hidden (H)</div>
)}
{shouldInvertMask && (
<div style={{ pointerEvents: 'none' }}>Mask Inverted (Shift+M)</div>
)}
{!shouldLockBoundingBox && (
<div style={{ pointerEvents: 'none' }}> <div style={{ pointerEvents: 'none' }}>
{`Transforming Bounding Box ${boundingBoxDimensions.width}x${boundingBoxDimensions.height} (M)`} <IconButton
aria-label="Show/HideMask"
size="xs"
variant={'ghost'}
fontSize={'1rem'}
data-selected={!shouldShowMask}
icon={shouldShowMask ? <BiShow /> : <BiHide />}
/>
</div>
<div style={{ pointerEvents: 'none' }}>
<IconButton
aria-label="Invert Mask"
size="xs"
variant={'ghost'}
fontSize={'1rem'}
data-selected={shouldInvertMask}
icon={
shouldInvertMask ? <MdInvertColors /> : <MdInvertColorsOff />
}
/>
</div>
<div style={{ pointerEvents: 'none' }}>
<IconButton
aria-label="Bounding Box Lock"
size="xs"
variant={'ghost'}
data-selected={shouldLockBoundingBox}
icon={shouldLockBoundingBox ? <FaLock /> : <FaUnlock />}
/>
</div> </div>
)}
</div> </div>
{canvasBgImage && ( {canvasBgImage && (
@ -260,7 +288,7 @@ const InpaintingCanvas = () => {
onMouseUp={handleMouseUp} onMouseUp={handleMouseUp}
onMouseOut={handleMouseOutCanvas} onMouseOut={handleMouseOutCanvas}
onMouseLeave={handleMouseOutCanvas} onMouseLeave={handleMouseOutCanvas}
style={{ cursor: shouldShowMask ? 'none' : 'default' }} style={{ ...(stageCursor ? { cursor: stageCursor } : {}) }}
className="inpainting-canvas-stage checkerboard" className="inpainting-canvas-stage checkerboard"
ref={stageRef} ref={stageRef}
> >
@ -283,7 +311,9 @@ const InpaintingCanvas = () => {
> >
<InpaintingCanvasLines /> <InpaintingCanvasLines />
{shouldLockBoundingBox && <InpaintingCanvasBrushPreview />} {!isMouseOverBoundingBox && !isModifyingBoundingBox && (
<InpaintingCanvasBrushPreview />
)}
{shouldInvertMask && ( {shouldInvertMask && (
<KonvaImage <KonvaImage
@ -305,8 +335,8 @@ const InpaintingCanvas = () => {
{shouldShowBoundingBoxFill && shouldShowBoundingBox && ( {shouldShowBoundingBoxFill && shouldShowBoundingBox && (
<InpaintingBoundingBoxPreviewOverlay /> <InpaintingBoundingBoxPreviewOverlay />
)} )}
{shouldShowBoundingBox && <InpaintingBoundingBoxPreview />} <InpaintingBoundingBoxPreview />
{shouldLockBoundingBox && ( {!isMouseOverBoundingBox && !isModifyingBoundingBox && (
<InpaintingCanvasBrushPreviewOutline /> <InpaintingCanvasBrushPreviewOutline />
)} )}
</Layer> </Layer>
@ -318,6 +348,7 @@ const InpaintingCanvas = () => {
<Cacher /> <Cacher />
<KeyboardEventManager /> <KeyboardEventManager />
</div> </div>
</div>
); );
}; };

View File

@ -33,6 +33,8 @@ const Cacher = () => {
futureLines, futureLines,
needsCache, needsCache,
isDrawing, isDrawing,
isTransformingBoundingBox,
isMovingBoundingBox,
} = useAppSelector((state: RootState) => state.inpainting); } = useAppSelector((state: RootState) => state.inpainting);
useLayoutEffect(() => { useLayoutEffect(() => {
@ -64,6 +66,8 @@ const Cacher = () => {
futureLines, futureLines,
needsCache, needsCache,
isDrawing, isDrawing,
isTransformingBoundingBox,
isMovingBoundingBox,
]); ]);
/** /**

View File

@ -4,7 +4,7 @@ import { KonvaEventObject } from 'konva/lib/Node';
import { Box } from 'konva/lib/shapes/Transformer'; import { Box } from 'konva/lib/shapes/Transformer';
import { Vector2d } from 'konva/lib/types'; import { Vector2d } from 'konva/lib/types';
import _ from 'lodash'; import _ from 'lodash';
import { useCallback, useEffect, useRef } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { Group, Rect, Transformer } from 'react-konva'; import { Group, Rect, Transformer } from 'react-konva';
import { import {
RootState, RootState,
@ -17,6 +17,9 @@ import {
InpaintingState, InpaintingState,
setBoundingBoxCoordinate, setBoundingBoxCoordinate,
setBoundingBoxDimensions, setBoundingBoxDimensions,
setIsMouseOverBoundingBox,
setIsMovingBoundingBox,
setIsTransformingBoundingBox,
} from '../inpaintingSlice'; } from '../inpaintingSlice';
import { rgbaColorToString } from '../util/colorToString'; import { rgbaColorToString } from '../util/colorToString';
import { import {
@ -35,6 +38,10 @@ const boundingBoxPreviewSelector = createSelector(
stageScale, stageScale,
imageToInpaint, imageToInpaint,
shouldLockBoundingBox, shouldLockBoundingBox,
isDrawing,
isTransformingBoundingBox,
isMovingBoundingBox,
isMouseOverBoundingBox,
} = inpainting; } = inpainting;
return { return {
boundingBoxCoordinate, boundingBoxCoordinate,
@ -46,6 +53,10 @@ const boundingBoxPreviewSelector = createSelector(
dash: DASH_WIDTH / stageScale, // scale dash lengths dash: DASH_WIDTH / stageScale, // scale dash lengths
strokeWidth: 1 / stageScale, // scale stroke thickness strokeWidth: 1 / stageScale, // scale stroke thickness
shouldLockBoundingBox, shouldLockBoundingBox,
isDrawing,
isTransformingBoundingBox,
isMouseOverBoundingBox,
isMovingBoundingBox,
}; };
}, },
{ {
@ -93,10 +104,13 @@ const InpaintingBoundingBoxPreview = () => {
const { const {
boundingBoxCoordinate, boundingBoxCoordinate,
boundingBoxDimensions, boundingBoxDimensions,
strokeWidth,
stageScale, stageScale,
imageToInpaint, imageToInpaint,
shouldLockBoundingBox, shouldLockBoundingBox,
isDrawing,
isTransformingBoundingBox,
isMovingBoundingBox,
isMouseOverBoundingBox,
} = useAppSelector(boundingBoxPreviewSelector); } = useAppSelector(boundingBoxPreviewSelector);
const transformerRef = useRef<Konva.Transformer>(null); const transformerRef = useRef<Konva.Transformer>(null);
@ -108,15 +122,6 @@ const InpaintingBoundingBoxPreview = () => {
transformerRef.current.getLayer()?.batchDraw(); transformerRef.current.getLayer()?.batchDraw();
}, [shouldLockBoundingBox]); }, [shouldLockBoundingBox]);
useEffect(
() => () => {
const container = stageRef.current?.container();
if (!container) return;
container.style.cursor = 'unset';
},
[shouldLockBoundingBox]
);
const scaledStep = 64 * stageScale; const scaledStep = 64 * stageScale;
const handleOnDragMove = useCallback( const handleOnDragMove = useCallback(
@ -269,6 +274,29 @@ const InpaintingBoundingBoxPreview = () => {
[imageToInpaint, stageScale] [imageToInpaint, stageScale]
); );
const handleStartedTransforming = (e: KonvaEventObject<MouseEvent>) => {
e.cancelBubble = true;
e.evt.stopImmediatePropagation();
dispatch(setIsTransformingBoundingBox(true));
};
const handleEndedTransforming = (e: KonvaEventObject<MouseEvent>) => {
dispatch(setIsTransformingBoundingBox(false));
dispatch(setIsMouseOverBoundingBox(false));
};
const handleStartedMoving = (e: KonvaEventObject<MouseEvent>) => {
e.cancelBubble = true;
e.evt.stopImmediatePropagation();
dispatch(setIsMovingBoundingBox(true));
};
const handleEndedModifying = (e: KonvaEventObject<MouseEvent>) => {
dispatch(setIsTransformingBoundingBox(false));
dispatch(setIsMovingBoundingBox(false));
dispatch(setIsMouseOverBoundingBox(false));
};
return ( return (
<> <>
<Rect <Rect
@ -277,23 +305,27 @@ const InpaintingBoundingBoxPreview = () => {
width={boundingBoxDimensions.width} width={boundingBoxDimensions.width}
height={boundingBoxDimensions.height} height={boundingBoxDimensions.height}
ref={shapeRef} ref={shapeRef}
stroke={'white'} stroke={isMouseOverBoundingBox ? 'rgba(255,255,255,0.3)' : 'white'}
strokeWidth={strokeWidth} strokeWidth={Math.floor((isMouseOverBoundingBox ? 8 : 1) / stageScale)}
listening={!shouldLockBoundingBox} fillEnabled={false}
onMouseEnter={(e) => { hitStrokeWidth={Math.floor(13 / stageScale)}
const container = e?.target?.getStage()?.container(); listening={!isDrawing && !shouldLockBoundingBox}
if (!container) return; onMouseOver={() => {
container.style.cursor = shouldLockBoundingBox ? 'none' : 'move'; dispatch(setIsMouseOverBoundingBox(true));
}} }}
onMouseLeave={(e) => { onMouseOut={() => {
const container = e?.target?.getStage()?.container(); !isTransformingBoundingBox &&
if (!container) return; !isMovingBoundingBox &&
container.style.cursor = shouldLockBoundingBox ? 'none' : 'default'; dispatch(setIsMouseOverBoundingBox(false));
}} }}
draggable={!shouldLockBoundingBox} onMouseDown={handleStartedMoving}
onMouseUp={handleEndedModifying}
draggable={true}
onDragMove={handleOnDragMove} onDragMove={handleOnDragMove}
dragBoundFunc={dragBoundFunc} dragBoundFunc={dragBoundFunc}
onTransform={handleOnTransform} onTransform={handleOnTransform}
onDragEnd={handleEndedModifying}
onTransformEnd={handleEndedTransforming}
/> />
<Transformer <Transformer
ref={transformerRef} ref={transformerRef}
@ -308,10 +340,22 @@ const InpaintingBoundingBoxPreview = () => {
flipEnabled={false} flipEnabled={false}
ignoreStroke={true} ignoreStroke={true}
keepRatio={false} keepRatio={false}
listening={!shouldLockBoundingBox} listening={!isDrawing && !shouldLockBoundingBox}
onMouseDown={handleStartedTransforming}
onMouseUp={handleEndedTransforming}
enabledAnchors={shouldLockBoundingBox ? [] : undefined} enabledAnchors={shouldLockBoundingBox ? [] : undefined}
boundBoxFunc={boundBoxFunc} boundBoxFunc={boundBoxFunc}
anchorDragBoundFunc={anchorDragBoundFunc} anchorDragBoundFunc={anchorDragBoundFunc}
onDragEnd={handleEndedModifying}
onTransformEnd={handleEndedTransforming}
onMouseOver={() => {
dispatch(setIsMouseOverBoundingBox(true));
}}
onMouseOut={() => {
!isTransformingBoundingBox &&
!isMovingBoundingBox &&
dispatch(setIsMouseOverBoundingBox(false));
}}
/> />
</> </>
); );

View File

@ -40,18 +40,10 @@ const inpaintingCanvasBrushPreviewSelector = createSelector(
* Draws a black circle around the canvas brush preview. * Draws a black circle around the canvas brush preview.
*/ */
const InpaintingCanvasBrushPreview = () => { const InpaintingCanvasBrushPreview = () => {
const { const { cursorPosition, width, height, brushSize, maskColorString, tool } =
cursorPosition, useAppSelector(inpaintingCanvasBrushPreviewSelector);
width,
height,
shouldShowBrushPreview,
brushSize,
maskColorString,
tool,
shouldShowBrush,
} = useAppSelector(inpaintingCanvasBrushPreviewSelector);
if (!shouldShowBrush || !(cursorPosition || shouldShowBrushPreview)) { if (!cursorPosition) {
return null; return null;
} }

View File

@ -51,6 +51,9 @@ export interface InpaintingState {
needsCache: boolean; needsCache: boolean;
stageScale: number; stageScale: number;
isDrawing: boolean; isDrawing: boolean;
isTransformingBoundingBox: boolean;
isMouseOverBoundingBox: boolean;
isMovingBoundingBox: boolean;
shouldUseInpaintReplace: boolean; shouldUseInpaintReplace: boolean;
inpaintReplace: number; inpaintReplace: number;
shouldLockBoundingBox: boolean; shouldLockBoundingBox: boolean;
@ -63,7 +66,7 @@ const initialInpaintingState: InpaintingState = {
canvasDimensions: { width: 0, height: 0 }, canvasDimensions: { width: 0, height: 0 },
boundingBoxDimensions: { width: 512, height: 512 }, boundingBoxDimensions: { width: 512, height: 512 },
boundingBoxCoordinate: { x: 0, y: 0 }, boundingBoxCoordinate: { x: 0, y: 0 },
boundingBoxPreviewFill: { r: 0, g: 0, b: 0, a: 0.7 }, boundingBoxPreviewFill: { r: 0, g: 0, b: 0, a: 0.5 },
shouldShowBoundingBox: true, shouldShowBoundingBox: true,
shouldShowBoundingBoxFill: true, shouldShowBoundingBoxFill: true,
cursorPosition: null, cursorPosition: null,
@ -77,6 +80,9 @@ const initialInpaintingState: InpaintingState = {
shouldShowBrushPreview: false, shouldShowBrushPreview: false,
needsCache: false, needsCache: false,
isDrawing: false, isDrawing: false,
isTransformingBoundingBox: false,
isMouseOverBoundingBox: false,
isMovingBoundingBox: false,
stageScale: 1, stageScale: 1,
shouldUseInpaintReplace: false, shouldUseInpaintReplace: false,
inpaintReplace: 1, inpaintReplace: 1,
@ -319,6 +325,15 @@ export const inpaintingSlice = createSlice({
setShouldShowBoundingBox: (state, action: PayloadAction<boolean>) => { setShouldShowBoundingBox: (state, action: PayloadAction<boolean>) => {
state.shouldShowBoundingBox = action.payload; state.shouldShowBoundingBox = action.payload;
}, },
setIsTransformingBoundingBox: (state, action: PayloadAction<boolean>) => {
state.isTransformingBoundingBox = action.payload;
},
setIsMovingBoundingBox: (state, action: PayloadAction<boolean>) => {
state.isMovingBoundingBox = action.payload;
},
setIsMouseOverBoundingBox: (state, action: PayloadAction<boolean>) => {
state.isMouseOverBoundingBox = action.payload;
},
}, },
}); });
@ -354,6 +369,9 @@ export const {
setInpaintReplace, setInpaintReplace,
setShouldLockBoundingBox, setShouldLockBoundingBox,
toggleShouldLockBoundingBox, toggleShouldLockBoundingBox,
setIsMovingBoundingBox,
setIsTransformingBoundingBox,
setIsMouseOverBoundingBox,
} = inpaintingSlice.actions; } = inpaintingSlice.actions;
export default inpaintingSlice.reducer; export default inpaintingSlice.reducer;

View File

@ -78,7 +78,23 @@ export const inpaintingCanvasSelector = createSelector(
isDrawing, isDrawing,
shouldLockBoundingBox, shouldLockBoundingBox,
boundingBoxDimensions, boundingBoxDimensions,
isTransformingBoundingBox,
isMouseOverBoundingBox,
isMovingBoundingBox,
} = inpainting; } = inpainting;
let stageCursor: string | undefined = '';
if (isTransformingBoundingBox) {
stageCursor = undefined;
} else if (isMovingBoundingBox || isMouseOverBoundingBox) {
stageCursor = 'move';
} else if (shouldShowMask) {
stageCursor = 'none';
} else {
stageCursor = 'default';
}
return { return {
tool, tool,
brushSize, brushSize,
@ -93,6 +109,10 @@ export const inpaintingCanvasSelector = createSelector(
isDrawing, isDrawing,
shouldLockBoundingBox, shouldLockBoundingBox,
boundingBoxDimensions, boundingBoxDimensions,
isTransformingBoundingBox,
isModifyingBoundingBox: isTransformingBoundingBox || isMovingBoundingBox,
stageCursor,
isMouseOverBoundingBox,
}; };
}, },
{ {