mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
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:
parent
d43bd4625d
commit
82dcbac28f
@ -113,7 +113,7 @@ const BoundingBoxSettings = () => {
|
||||
<div className="inpainting-bounding-box-settings">
|
||||
<div className="inpainting-bounding-box-header">
|
||||
<p>Inpaint Box</p>
|
||||
<IAIIconButton
|
||||
{/* <IAIIconButton
|
||||
aria-label="Toggle Bounding Box Visibility"
|
||||
icon={
|
||||
shouldShowBoundingBox ? <BiShow size={22} /> : <BiHide size={22} />
|
||||
@ -121,11 +121,12 @@ const BoundingBoxSettings = () => {
|
||||
onClick={handleShowBoundingBox}
|
||||
background={'none'}
|
||||
padding={0}
|
||||
/>
|
||||
/> */}
|
||||
</div>
|
||||
<div className="inpainting-bounding-box-settings-items">
|
||||
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
|
||||
<IAISlider
|
||||
isDisabled={shouldLockBoundingBox}
|
||||
label="Box W"
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.width, 64)}
|
||||
@ -135,6 +136,7 @@ const BoundingBoxSettings = () => {
|
||||
width={'5rem'}
|
||||
/>
|
||||
<IAINumberInput
|
||||
isDisabled={shouldLockBoundingBox}
|
||||
value={boundingBoxDimensions.width}
|
||||
onChange={handleChangeBoundingBoxWidth}
|
||||
min={64}
|
||||
@ -143,6 +145,7 @@ const BoundingBoxSettings = () => {
|
||||
width={'5rem'}
|
||||
/>
|
||||
<IAIIconButton
|
||||
isDisabled={shouldLockBoundingBox}
|
||||
size={'sm'}
|
||||
aria-label={'Reset Width'}
|
||||
tooltip={'Reset Width'}
|
||||
@ -154,6 +157,7 @@ const BoundingBoxSettings = () => {
|
||||
</div>
|
||||
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
|
||||
<IAISlider
|
||||
isDisabled={shouldLockBoundingBox}
|
||||
label="Box H"
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.height, 64)}
|
||||
@ -163,6 +167,7 @@ const BoundingBoxSettings = () => {
|
||||
width={'5rem'}
|
||||
/>
|
||||
<IAINumberInput
|
||||
isDisabled={shouldLockBoundingBox}
|
||||
value={boundingBoxDimensions.height}
|
||||
onChange={handleChangeBoundingBoxHeight}
|
||||
min={64}
|
||||
@ -172,6 +177,7 @@ const BoundingBoxSettings = () => {
|
||||
width={'5rem'}
|
||||
/>
|
||||
<IAIIconButton
|
||||
isDisabled={shouldLockBoundingBox}
|
||||
size={'sm'}
|
||||
aria-label={'Reset Height'}
|
||||
tooltip={'Reset Height'}
|
||||
|
@ -45,32 +45,40 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.inpainting-canvas-wrapper {
|
||||
.inpainting-canvas-spiner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.inpainting-canvas-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
.inpainting-canvas-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.inpainting-alerts {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
column-gap: 0.5rem;
|
||||
z-index: 2;
|
||||
padding: 0.5rem;
|
||||
padding: 0.25rem;
|
||||
pointer-events: none;
|
||||
font-size: 0.9rem;
|
||||
font-weight: bold;
|
||||
|
||||
div {
|
||||
background-color: var(--accent-color);
|
||||
color: var(--text-color);
|
||||
padding: 0.2rem 0.6rem;
|
||||
border-radius: 0.25rem;
|
||||
button {
|
||||
&[data-selected='true'] {
|
||||
svg {
|
||||
fill: var(--accent-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,10 @@ import InpaintingBoundingBoxPreview, {
|
||||
} from './components/InpaintingBoundingBoxPreview';
|
||||
import { KonvaEventObject } from 'konva/lib/Node';
|
||||
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...
|
||||
export let stageRef: MutableRefObject<StageType | null>;
|
||||
@ -58,6 +61,10 @@ const InpaintingCanvas = () => {
|
||||
isDrawing,
|
||||
shouldLockBoundingBox,
|
||||
boundingBoxDimensions,
|
||||
// isTransformingBoundingBox,
|
||||
isMouseOverBoundingBox,
|
||||
isModifyingBoundingBox,
|
||||
stageCursor,
|
||||
} = useAppSelector(inpaintingCanvasSelector);
|
||||
|
||||
const toast = useToast();
|
||||
@ -113,7 +120,7 @@ const InpaintingCanvas = () => {
|
||||
if (
|
||||
!scaledCursorPosition ||
|
||||
!maskLayerRef.current ||
|
||||
!shouldLockBoundingBox
|
||||
isModifyingBoundingBox
|
||||
)
|
||||
return;
|
||||
|
||||
@ -127,7 +134,7 @@ const InpaintingCanvas = () => {
|
||||
points: [scaledCursorPosition.x, scaledCursorPosition.y],
|
||||
})
|
||||
);
|
||||
}, [dispatch, brushSize, tool, shouldLockBoundingBox]);
|
||||
}, [dispatch, brushSize, tool, isModifyingBoundingBox]);
|
||||
|
||||
/**
|
||||
*
|
||||
@ -143,20 +150,20 @@ const InpaintingCanvas = () => {
|
||||
|
||||
dispatch(setCursorPosition(scaledCursorPosition));
|
||||
|
||||
if (!maskLayerRef.current || !shouldLockBoundingBox) {
|
||||
if (!maskLayerRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastCursorPosition.current = scaledCursorPosition;
|
||||
|
||||
if (!isDrawing) return;
|
||||
if (!isDrawing || isModifyingBoundingBox) return;
|
||||
|
||||
didMouseMoveRef.current = true;
|
||||
// Extend the current line
|
||||
dispatch(
|
||||
addPointToCurrentLine([scaledCursorPosition.x, scaledCursorPosition.y])
|
||||
);
|
||||
}, [dispatch, isDrawing, shouldLockBoundingBox]);
|
||||
}, [dispatch, isDrawing, isModifyingBoundingBox]);
|
||||
|
||||
/**
|
||||
*
|
||||
@ -170,7 +177,7 @@ const InpaintingCanvas = () => {
|
||||
if (
|
||||
!scaledCursorPosition ||
|
||||
!maskLayerRef.current ||
|
||||
!shouldLockBoundingBox
|
||||
isModifyingBoundingBox
|
||||
)
|
||||
return;
|
||||
|
||||
@ -187,7 +194,7 @@ const InpaintingCanvas = () => {
|
||||
didMouseMoveRef.current = false;
|
||||
}
|
||||
dispatch(setIsDrawing(false));
|
||||
}, [dispatch, isDrawing, shouldLockBoundingBox]);
|
||||
}, [dispatch, isDrawing, isModifyingBoundingBox]);
|
||||
|
||||
/**
|
||||
*
|
||||
@ -214,7 +221,7 @@ const InpaintingCanvas = () => {
|
||||
if (
|
||||
!scaledCursorPosition ||
|
||||
!maskLayerRef.current ||
|
||||
!shouldLockBoundingBox
|
||||
isModifyingBoundingBox
|
||||
)
|
||||
return;
|
||||
|
||||
@ -230,93 +237,117 @@ const InpaintingCanvas = () => {
|
||||
);
|
||||
}
|
||||
},
|
||||
[dispatch, brushSize, tool, shouldLockBoundingBox]
|
||||
[dispatch, brushSize, tool, isModifyingBoundingBox]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="inpainting-canvas-wrapper" tabIndex={1}>
|
||||
<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 className="inpainting-canvas-container" tabIndex={1}>
|
||||
<div className="inpainting-canvas-wrapper">
|
||||
<div className="inpainting-alerts">
|
||||
<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>
|
||||
<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>
|
||||
|
||||
{canvasBgImage && (
|
||||
<Stage
|
||||
width={Math.floor(canvasBgImage.width * stageScale)}
|
||||
height={Math.floor(canvasBgImage.height * stageScale)}
|
||||
scale={{ x: stageScale, y: stageScale }}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseUp={handleMouseUp}
|
||||
onMouseOut={handleMouseOutCanvas}
|
||||
onMouseLeave={handleMouseOutCanvas}
|
||||
style={{ cursor: shouldShowMask ? 'none' : 'default' }}
|
||||
className="inpainting-canvas-stage checkerboard"
|
||||
ref={stageRef}
|
||||
>
|
||||
{!shouldInvertMask && !shouldShowCheckboardTransparency && (
|
||||
<Layer name={'image-layer'} listening={false}>
|
||||
<KonvaImage listening={false} image={canvasBgImage} />
|
||||
</Layer>
|
||||
)}
|
||||
{shouldShowMask && (
|
||||
<>
|
||||
<Layer
|
||||
name={'mask-layer'}
|
||||
listening={false}
|
||||
opacity={
|
||||
shouldShowCheckboardTransparency || shouldInvertMask
|
||||
? 1
|
||||
: maskColor.a
|
||||
}
|
||||
ref={maskLayerRef}
|
||||
>
|
||||
<InpaintingCanvasLines />
|
||||
|
||||
{shouldLockBoundingBox && <InpaintingCanvasBrushPreview />}
|
||||
|
||||
{shouldInvertMask && (
|
||||
<KonvaImage
|
||||
image={canvasBgImage}
|
||||
listening={false}
|
||||
globalCompositeOperation="source-in"
|
||||
/>
|
||||
)}
|
||||
{!shouldInvertMask && shouldShowCheckboardTransparency && (
|
||||
<KonvaImage
|
||||
image={canvasBgImage}
|
||||
listening={false}
|
||||
globalCompositeOperation="source-out"
|
||||
/>
|
||||
)}
|
||||
{canvasBgImage && (
|
||||
<Stage
|
||||
width={Math.floor(canvasBgImage.width * stageScale)}
|
||||
height={Math.floor(canvasBgImage.height * stageScale)}
|
||||
scale={{ x: stageScale, y: stageScale }}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseUp={handleMouseUp}
|
||||
onMouseOut={handleMouseOutCanvas}
|
||||
onMouseLeave={handleMouseOutCanvas}
|
||||
style={{ ...(stageCursor ? { cursor: stageCursor } : {}) }}
|
||||
className="inpainting-canvas-stage checkerboard"
|
||||
ref={stageRef}
|
||||
>
|
||||
{!shouldInvertMask && !shouldShowCheckboardTransparency && (
|
||||
<Layer name={'image-layer'} listening={false}>
|
||||
<KonvaImage listening={false} image={canvasBgImage} />
|
||||
</Layer>
|
||||
{shouldShowMask && (
|
||||
<Layer>
|
||||
{shouldShowBoundingBoxFill && shouldShowBoundingBox && (
|
||||
<InpaintingBoundingBoxPreviewOverlay />
|
||||
)}
|
||||
{shouldShowMask && (
|
||||
<>
|
||||
<Layer
|
||||
name={'mask-layer'}
|
||||
listening={false}
|
||||
opacity={
|
||||
shouldShowCheckboardTransparency || shouldInvertMask
|
||||
? 1
|
||||
: maskColor.a
|
||||
}
|
||||
ref={maskLayerRef}
|
||||
>
|
||||
<InpaintingCanvasLines />
|
||||
|
||||
{!isMouseOverBoundingBox && !isModifyingBoundingBox && (
|
||||
<InpaintingCanvasBrushPreview />
|
||||
)}
|
||||
{shouldShowBoundingBox && <InpaintingBoundingBoxPreview />}
|
||||
{shouldLockBoundingBox && (
|
||||
<InpaintingCanvasBrushPreviewOutline />
|
||||
|
||||
{shouldInvertMask && (
|
||||
<KonvaImage
|
||||
image={canvasBgImage}
|
||||
listening={false}
|
||||
globalCompositeOperation="source-in"
|
||||
/>
|
||||
)}
|
||||
{!shouldInvertMask && shouldShowCheckboardTransparency && (
|
||||
<KonvaImage
|
||||
image={canvasBgImage}
|
||||
listening={false}
|
||||
globalCompositeOperation="source-out"
|
||||
/>
|
||||
)}
|
||||
</Layer>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Stage>
|
||||
)}
|
||||
<Cacher />
|
||||
<KeyboardEventManager />
|
||||
{shouldShowMask && (
|
||||
<Layer>
|
||||
{shouldShowBoundingBoxFill && shouldShowBoundingBox && (
|
||||
<InpaintingBoundingBoxPreviewOverlay />
|
||||
)}
|
||||
<InpaintingBoundingBoxPreview />
|
||||
{!isMouseOverBoundingBox && !isModifyingBoundingBox && (
|
||||
<InpaintingCanvasBrushPreviewOutline />
|
||||
)}
|
||||
</Layer>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Stage>
|
||||
)}
|
||||
<Cacher />
|
||||
<KeyboardEventManager />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -33,6 +33,8 @@ const Cacher = () => {
|
||||
futureLines,
|
||||
needsCache,
|
||||
isDrawing,
|
||||
isTransformingBoundingBox,
|
||||
isMovingBoundingBox,
|
||||
} = useAppSelector((state: RootState) => state.inpainting);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
@ -64,6 +66,8 @@ const Cacher = () => {
|
||||
futureLines,
|
||||
needsCache,
|
||||
isDrawing,
|
||||
isTransformingBoundingBox,
|
||||
isMovingBoundingBox,
|
||||
]);
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@ import { KonvaEventObject } from 'konva/lib/Node';
|
||||
import { Box } from 'konva/lib/shapes/Transformer';
|
||||
import { Vector2d } from 'konva/lib/types';
|
||||
import _ from 'lodash';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Group, Rect, Transformer } from 'react-konva';
|
||||
import {
|
||||
RootState,
|
||||
@ -17,6 +17,9 @@ import {
|
||||
InpaintingState,
|
||||
setBoundingBoxCoordinate,
|
||||
setBoundingBoxDimensions,
|
||||
setIsMouseOverBoundingBox,
|
||||
setIsMovingBoundingBox,
|
||||
setIsTransformingBoundingBox,
|
||||
} from '../inpaintingSlice';
|
||||
import { rgbaColorToString } from '../util/colorToString';
|
||||
import {
|
||||
@ -35,6 +38,10 @@ const boundingBoxPreviewSelector = createSelector(
|
||||
stageScale,
|
||||
imageToInpaint,
|
||||
shouldLockBoundingBox,
|
||||
isDrawing,
|
||||
isTransformingBoundingBox,
|
||||
isMovingBoundingBox,
|
||||
isMouseOverBoundingBox,
|
||||
} = inpainting;
|
||||
return {
|
||||
boundingBoxCoordinate,
|
||||
@ -46,6 +53,10 @@ const boundingBoxPreviewSelector = createSelector(
|
||||
dash: DASH_WIDTH / stageScale, // scale dash lengths
|
||||
strokeWidth: 1 / stageScale, // scale stroke thickness
|
||||
shouldLockBoundingBox,
|
||||
isDrawing,
|
||||
isTransformingBoundingBox,
|
||||
isMouseOverBoundingBox,
|
||||
isMovingBoundingBox,
|
||||
};
|
||||
},
|
||||
{
|
||||
@ -93,10 +104,13 @@ const InpaintingBoundingBoxPreview = () => {
|
||||
const {
|
||||
boundingBoxCoordinate,
|
||||
boundingBoxDimensions,
|
||||
strokeWidth,
|
||||
stageScale,
|
||||
imageToInpaint,
|
||||
shouldLockBoundingBox,
|
||||
isDrawing,
|
||||
isTransformingBoundingBox,
|
||||
isMovingBoundingBox,
|
||||
isMouseOverBoundingBox,
|
||||
} = useAppSelector(boundingBoxPreviewSelector);
|
||||
|
||||
const transformerRef = useRef<Konva.Transformer>(null);
|
||||
@ -108,15 +122,6 @@ const InpaintingBoundingBoxPreview = () => {
|
||||
transformerRef.current.getLayer()?.batchDraw();
|
||||
}, [shouldLockBoundingBox]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
const container = stageRef.current?.container();
|
||||
if (!container) return;
|
||||
container.style.cursor = 'unset';
|
||||
},
|
||||
[shouldLockBoundingBox]
|
||||
);
|
||||
|
||||
const scaledStep = 64 * stageScale;
|
||||
|
||||
const handleOnDragMove = useCallback(
|
||||
@ -269,6 +274,29 @@ const InpaintingBoundingBoxPreview = () => {
|
||||
[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 (
|
||||
<>
|
||||
<Rect
|
||||
@ -277,23 +305,27 @@ const InpaintingBoundingBoxPreview = () => {
|
||||
width={boundingBoxDimensions.width}
|
||||
height={boundingBoxDimensions.height}
|
||||
ref={shapeRef}
|
||||
stroke={'white'}
|
||||
strokeWidth={strokeWidth}
|
||||
listening={!shouldLockBoundingBox}
|
||||
onMouseEnter={(e) => {
|
||||
const container = e?.target?.getStage()?.container();
|
||||
if (!container) return;
|
||||
container.style.cursor = shouldLockBoundingBox ? 'none' : 'move';
|
||||
stroke={isMouseOverBoundingBox ? 'rgba(255,255,255,0.3)' : 'white'}
|
||||
strokeWidth={Math.floor((isMouseOverBoundingBox ? 8 : 1) / stageScale)}
|
||||
fillEnabled={false}
|
||||
hitStrokeWidth={Math.floor(13 / stageScale)}
|
||||
listening={!isDrawing && !shouldLockBoundingBox}
|
||||
onMouseOver={() => {
|
||||
dispatch(setIsMouseOverBoundingBox(true));
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
const container = e?.target?.getStage()?.container();
|
||||
if (!container) return;
|
||||
container.style.cursor = shouldLockBoundingBox ? 'none' : 'default';
|
||||
onMouseOut={() => {
|
||||
!isTransformingBoundingBox &&
|
||||
!isMovingBoundingBox &&
|
||||
dispatch(setIsMouseOverBoundingBox(false));
|
||||
}}
|
||||
draggable={!shouldLockBoundingBox}
|
||||
onMouseDown={handleStartedMoving}
|
||||
onMouseUp={handleEndedModifying}
|
||||
draggable={true}
|
||||
onDragMove={handleOnDragMove}
|
||||
dragBoundFunc={dragBoundFunc}
|
||||
onTransform={handleOnTransform}
|
||||
onDragEnd={handleEndedModifying}
|
||||
onTransformEnd={handleEndedTransforming}
|
||||
/>
|
||||
<Transformer
|
||||
ref={transformerRef}
|
||||
@ -308,10 +340,22 @@ const InpaintingBoundingBoxPreview = () => {
|
||||
flipEnabled={false}
|
||||
ignoreStroke={true}
|
||||
keepRatio={false}
|
||||
listening={!shouldLockBoundingBox}
|
||||
listening={!isDrawing && !shouldLockBoundingBox}
|
||||
onMouseDown={handleStartedTransforming}
|
||||
onMouseUp={handleEndedTransforming}
|
||||
enabledAnchors={shouldLockBoundingBox ? [] : undefined}
|
||||
boundBoxFunc={boundBoxFunc}
|
||||
anchorDragBoundFunc={anchorDragBoundFunc}
|
||||
onDragEnd={handleEndedModifying}
|
||||
onTransformEnd={handleEndedTransforming}
|
||||
onMouseOver={() => {
|
||||
dispatch(setIsMouseOverBoundingBox(true));
|
||||
}}
|
||||
onMouseOut={() => {
|
||||
!isTransformingBoundingBox &&
|
||||
!isMovingBoundingBox &&
|
||||
dispatch(setIsMouseOverBoundingBox(false));
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -40,18 +40,10 @@ const inpaintingCanvasBrushPreviewSelector = createSelector(
|
||||
* Draws a black circle around the canvas brush preview.
|
||||
*/
|
||||
const InpaintingCanvasBrushPreview = () => {
|
||||
const {
|
||||
cursorPosition,
|
||||
width,
|
||||
height,
|
||||
shouldShowBrushPreview,
|
||||
brushSize,
|
||||
maskColorString,
|
||||
tool,
|
||||
shouldShowBrush,
|
||||
} = useAppSelector(inpaintingCanvasBrushPreviewSelector);
|
||||
const { cursorPosition, width, height, brushSize, maskColorString, tool } =
|
||||
useAppSelector(inpaintingCanvasBrushPreviewSelector);
|
||||
|
||||
if (!shouldShowBrush || !(cursorPosition || shouldShowBrushPreview)) {
|
||||
if (!cursorPosition) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,9 @@ export interface InpaintingState {
|
||||
needsCache: boolean;
|
||||
stageScale: number;
|
||||
isDrawing: boolean;
|
||||
isTransformingBoundingBox: boolean;
|
||||
isMouseOverBoundingBox: boolean;
|
||||
isMovingBoundingBox: boolean;
|
||||
shouldUseInpaintReplace: boolean;
|
||||
inpaintReplace: number;
|
||||
shouldLockBoundingBox: boolean;
|
||||
@ -63,7 +66,7 @@ const initialInpaintingState: InpaintingState = {
|
||||
canvasDimensions: { width: 0, height: 0 },
|
||||
boundingBoxDimensions: { width: 512, height: 512 },
|
||||
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,
|
||||
shouldShowBoundingBoxFill: true,
|
||||
cursorPosition: null,
|
||||
@ -77,6 +80,9 @@ const initialInpaintingState: InpaintingState = {
|
||||
shouldShowBrushPreview: false,
|
||||
needsCache: false,
|
||||
isDrawing: false,
|
||||
isTransformingBoundingBox: false,
|
||||
isMouseOverBoundingBox: false,
|
||||
isMovingBoundingBox: false,
|
||||
stageScale: 1,
|
||||
shouldUseInpaintReplace: false,
|
||||
inpaintReplace: 1,
|
||||
@ -319,6 +325,15 @@ export const inpaintingSlice = createSlice({
|
||||
setShouldShowBoundingBox: (state, action: PayloadAction<boolean>) => {
|
||||
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,
|
||||
setShouldLockBoundingBox,
|
||||
toggleShouldLockBoundingBox,
|
||||
setIsMovingBoundingBox,
|
||||
setIsTransformingBoundingBox,
|
||||
setIsMouseOverBoundingBox,
|
||||
} = inpaintingSlice.actions;
|
||||
|
||||
export default inpaintingSlice.reducer;
|
||||
|
@ -78,7 +78,23 @@ export const inpaintingCanvasSelector = createSelector(
|
||||
isDrawing,
|
||||
shouldLockBoundingBox,
|
||||
boundingBoxDimensions,
|
||||
isTransformingBoundingBox,
|
||||
isMouseOverBoundingBox,
|
||||
isMovingBoundingBox,
|
||||
} = inpainting;
|
||||
|
||||
let stageCursor: string | undefined = '';
|
||||
|
||||
if (isTransformingBoundingBox) {
|
||||
stageCursor = undefined;
|
||||
} else if (isMovingBoundingBox || isMouseOverBoundingBox) {
|
||||
stageCursor = 'move';
|
||||
} else if (shouldShowMask) {
|
||||
stageCursor = 'none';
|
||||
} else {
|
||||
stageCursor = 'default';
|
||||
}
|
||||
|
||||
return {
|
||||
tool,
|
||||
brushSize,
|
||||
@ -93,6 +109,10 @@ export const inpaintingCanvasSelector = createSelector(
|
||||
isDrawing,
|
||||
shouldLockBoundingBox,
|
||||
boundingBoxDimensions,
|
||||
isTransformingBoundingBox,
|
||||
isModifyingBoundingBox: isTransformingBoundingBox || isMovingBoundingBox,
|
||||
stageCursor,
|
||||
isMouseOverBoundingBox,
|
||||
};
|
||||
},
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user