From 65acdfb09b2ca0ccb310538dadc33957484d32f4 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 27 Oct 2022 18:33:34 +1100 Subject: [PATCH] Fixes edge cases with bounding box --- .../tabs/Inpainting/InpaintingCanvas.tsx | 30 ++++++++++------- .../tabs/Inpainting/components/Cacher.tsx | 2 ++ .../InpaintingBoundingBoxPreview.tsx | 23 ++++++++++++- .../InpaintingCanvasBrushPreview.tsx | 7 +++- .../InpaintingCanvasBrushPreviewOutline.tsx | 32 +++++++++++++------ .../components/KeyboardEventManager.tsx | 23 +++++++++---- .../tabs/Inpainting/inpaintingSlice.ts | 6 ++++ .../Inpainting/inpaintingSliceSelectors.ts | 4 +++ 8 files changed, 98 insertions(+), 29 deletions(-) diff --git a/frontend/src/features/tabs/Inpainting/InpaintingCanvas.tsx b/frontend/src/features/tabs/Inpainting/InpaintingCanvas.tsx index 840da4d446..1c383bf605 100644 --- a/frontend/src/features/tabs/Inpainting/InpaintingCanvas.tsx +++ b/frontend/src/features/tabs/Inpainting/InpaintingCanvas.tsx @@ -18,6 +18,7 @@ import { addPointToCurrentLine, setBoundingBoxCoordinate, setCursorPosition, + setIsDrawing, setIsMovingBoundingBox, } from './inpaintingSlice'; import { inpaintingCanvasSelector } from './inpaintingSliceSelectors'; @@ -58,6 +59,8 @@ const InpaintingCanvas = () => { boundingBoxCoordinate, stageScale, shouldShowBoundingBoxFill, + isDrawing, + isBoundingBoxTransforming, } = useAppSelector(inpaintingCanvasSelector); // set the closure'd refs @@ -69,7 +72,6 @@ const InpaintingCanvas = () => { // Use refs for values that do not affect rendering, other values in redux const didMouseMoveRef = useRef(false); - const isDrawing = useRef(false); // Load the image into this const [canvasBgImage, setCanvasBgImage] = useState( @@ -95,7 +97,7 @@ const InpaintingCanvas = () => { if (!scaledCursorPosition || !maskLayerRef.current) return; - isDrawing.current = true; + dispatch(setIsDrawing(true)); // Add a new line starting from the current cursor position. dispatch( @@ -147,8 +149,7 @@ const InpaintingCanvas = () => { return; } - - if (!isDrawing.current) return; + if (!isDrawing) return; didMouseMoveRef.current = true; // Extend the current line @@ -161,10 +162,11 @@ const InpaintingCanvas = () => { boundingBoxDimensions, canvasDimensions, boundingBoxCoordinate, + isDrawing, ]); const handleMouseUp = useCallback(() => { - if (!didMouseMoveRef.current && isDrawing.current && stageRef.current) { + if (!didMouseMoveRef.current && isDrawing && stageRef.current) { const scaledCursorPosition = getScaledCursorPosition(stageRef.current); if (!scaledCursorPosition || !maskLayerRef.current) return; @@ -181,13 +183,13 @@ const InpaintingCanvas = () => { } else { didMouseMoveRef.current = false; } - isDrawing.current = false; - }, [dispatch]); + dispatch(setIsDrawing(false)); + }, [dispatch, isDrawing]); const handleMouseOutCanvas = useCallback(() => { dispatch(setCursorPosition(null)); dispatch(setIsMovingBoundingBox(false)); - isDrawing.current = false; + dispatch(setIsDrawing(false)); }, [dispatch]); const handleMouseEnter = useCallback( @@ -197,9 +199,15 @@ const InpaintingCanvas = () => { const scaledCursorPosition = getScaledCursorPosition(stageRef.current); - if (!scaledCursorPosition || !maskLayerRef.current) return; + if ( + !scaledCursorPosition || + !maskLayerRef.current || + isMovingBoundingBox || + isBoundingBoxTransforming + ) + return; - isDrawing.current = true; + dispatch(setIsDrawing(true)); // Add a new line starting from the current cursor position. dispatch( @@ -211,7 +219,7 @@ const InpaintingCanvas = () => { ); } }, - [dispatch, brushSize, tool] + [dispatch, brushSize, tool, isMovingBoundingBox, isBoundingBoxTransforming] ); return ( diff --git a/frontend/src/features/tabs/Inpainting/components/Cacher.tsx b/frontend/src/features/tabs/Inpainting/components/Cacher.tsx index bf4ccb72a4..65300ac1d6 100644 --- a/frontend/src/features/tabs/Inpainting/components/Cacher.tsx +++ b/frontend/src/features/tabs/Inpainting/components/Cacher.tsx @@ -25,6 +25,7 @@ const Cacher = () => { shouldShowBrushPreview, shouldShowCheckboardTransparency, imageToInpaint, + shouldShowBrush, } = useAppSelector((state: RootState) => state.inpainting); useLayoutEffect(() => { @@ -48,6 +49,7 @@ const Cacher = () => { shouldShowBrushPreview, shouldShowCheckboardTransparency, imageToInpaint, + shouldShowBrush, ]); return null; diff --git a/frontend/src/features/tabs/Inpainting/components/InpaintingBoundingBoxPreview.tsx b/frontend/src/features/tabs/Inpainting/components/InpaintingBoundingBoxPreview.tsx index d469542c6e..e585a810f5 100644 --- a/frontend/src/features/tabs/Inpainting/components/InpaintingBoundingBoxPreview.tsx +++ b/frontend/src/features/tabs/Inpainting/components/InpaintingBoundingBoxPreview.tsx @@ -1,5 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; import Konva from 'konva'; +import { KonvaEventObject } from 'konva/lib/Node'; import { Vector2d } from 'konva/lib/types'; import _ from 'lodash'; import { useEffect, useRef } from 'react'; @@ -14,6 +15,10 @@ import { InpaintingState, setBoundingBoxCoordinate, setBoundingBoxDimensions, + setIsBoundingBoxTransforming, + setIsDrawing, + setIsMovingBoundingBox, + setShouldShowBrush, } from '../inpaintingSlice'; import { rgbaColorToString } from '../util/colorToString'; import { @@ -32,6 +37,7 @@ const boundingBoxPreviewSelector = createSelector( canvasDimensions, stageScale, imageToInpaint, + isMovingBoundingBox, } = inpainting; return { boundingBoxCoordinate, @@ -43,6 +49,7 @@ const boundingBoxPreviewSelector = createSelector( dash: DASH_WIDTH / stageScale, // scale dash lengths strokeWidth: 1 / stageScale, // scale stroke thickness anchorSize: TRANSFORMER_ANCHOR_SIZE, + isMovingBoundingBox, }; }, { @@ -154,6 +161,7 @@ const InpaintingBoundingBoxPreview = () => { anchorSize, stageScale, imageToInpaint, + isMovingBoundingBox, } = useAppSelector(boundingBoxPreviewSelector); const transformerRef = useRef(null); @@ -176,12 +184,22 @@ const InpaintingBoundingBoxPreview = () => { stroke={'white'} strokeWidth={strokeWidth} listening={false} + onTransformStart={() => { + dispatch(setIsDrawing(false)); + dispatch(setShouldShowBrush(false)); + dispatch(setIsBoundingBoxTransforming(true)); + }} + onTransformEnd={() => { + dispatch(setShouldShowBrush(true)); + dispatch(setIsBoundingBoxTransforming(false)); + }} onTransform={() => { /** * The Konva Transformer changes the object's anchor point and scale factor, * not its width and height. We need to un-scale the width and height before * setting the values. */ + console.log(isMovingBoundingBox) if (!shapeRef.current) return; const rect = shapeRef.current; @@ -227,11 +245,14 @@ const InpaintingBoundingBoxPreview = () => { ignoreStroke={true} keepRatio={false} flipEnabled={false} + onMouseDown={(e: KonvaEventObject) => { + e.cancelBubble = true; + }} anchorDragBoundFunc={( oldPos: Vector2d, // old absolute position of anchor point newPos: Vector2d, // new absolute position (potentially) of anchor point // eslint-disable-next-line @typescript-eslint/no-unused-vars - _event: MouseEvent + _e: MouseEvent ) => { /** * Konva does not transform with width or height. It transforms the anchor point diff --git a/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreview.tsx b/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreview.tsx index 37fc8c8920..f88150d794 100644 --- a/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreview.tsx +++ b/frontend/src/features/tabs/Inpainting/components/InpaintingCanvasBrushPreview.tsx @@ -15,6 +15,7 @@ const inpaintingCanvasBrushPreviewSelector = createSelector( brushSize, maskColor, tool, + shouldShowBrush, } = inpainting; return { @@ -25,6 +26,7 @@ const inpaintingCanvasBrushPreviewSelector = createSelector( brushSize, maskColorString: rgbaColorToRgbString(maskColor), tool, + shouldShowBrush, }; }, { @@ -46,9 +48,12 @@ const InpaintingCanvasBrushPreview = () => { brushSize, maskColorString, tool, + shouldShowBrush, } = useAppSelector(inpaintingCanvasBrushPreviewSelector); - if (!(cursorPosition || shouldShowBrushPreview)) return null; + if (!shouldShowBrush || !(cursorPosition || shouldShowBrushPreview)) { + return null; + } return ( { shouldShowBrushPreview, brushSize, strokeWidth, + shouldShowBrush, } = useAppSelector(inpaintingCanvasBrushPreviewSelector); - if (!((cursorPosition || shouldShowBrushPreview) && width && height)) + if (!shouldShowBrush || !(cursorPosition || shouldShowBrushPreview)) return null; return ( - + <> + + + ); }; export default InpaintingCanvasBrushPreviewOutline; diff --git a/frontend/src/features/tabs/Inpainting/components/KeyboardEventManager.tsx b/frontend/src/features/tabs/Inpainting/components/KeyboardEventManager.tsx index 4c20af3197..bf26065837 100644 --- a/frontend/src/features/tabs/Inpainting/components/KeyboardEventManager.tsx +++ b/frontend/src/features/tabs/Inpainting/components/KeyboardEventManager.tsx @@ -10,6 +10,7 @@ import { OptionsState } from '../../../options/optionsSlice'; import { tabMap } from '../../InvokeTabs'; import { InpaintingState, + setIsMovingBoundingBox, toggleIsMovingBoundingBox, toggleTool, } from '../inpaintingSlice'; @@ -17,11 +18,12 @@ import { const keyboardEventManagerSelector = createSelector( [(state: RootState) => state.options, (state: RootState) => state.inpainting], (options: OptionsState, inpainting: InpaintingState) => { - const { shouldShowMask, cursorPosition } = inpainting; + const { shouldShowMask, cursorPosition, isMovingBoundingBox } = inpainting; return { activeTabName: tabMap[options.activeTab], shouldShowMask, isCursorOnCanvas: Boolean(cursorPosition), + isMovingBoundingBox, }; }, { @@ -33,9 +35,12 @@ const keyboardEventManagerSelector = createSelector( const KeyboardEventManager = () => { const dispatch = useAppDispatch(); - const { shouldShowMask, activeTabName, isCursorOnCanvas } = useAppSelector( - keyboardEventManagerSelector - ); + const { + shouldShowMask, + activeTabName, + isCursorOnCanvas, + isMovingBoundingBox, + } = useAppSelector(keyboardEventManagerSelector); const isFirstEvent = useRef(true); const wasLastEventOverCanvas = useRef(false); @@ -84,7 +89,7 @@ const KeyboardEventManager = () => { break; } case ' ': { - dispatch(toggleIsMovingBoundingBox()); + dispatch(setIsMovingBoundingBox(e.type === 'keydown' ? true : false)); break; } } @@ -100,7 +105,13 @@ const KeyboardEventManager = () => { document.removeEventListener('keydown', listener); document.removeEventListener('keyup', listener); }; - }, [dispatch, activeTabName, shouldShowMask, isCursorOnCanvas]); + }, [ + dispatch, + activeTabName, + shouldShowMask, + isCursorOnCanvas, + isMovingBoundingBox, + ]); return null; }; diff --git a/frontend/src/features/tabs/Inpainting/inpaintingSlice.ts b/frontend/src/features/tabs/Inpainting/inpaintingSlice.ts index 967a90e098..d6e7b07d44 100644 --- a/frontend/src/features/tabs/Inpainting/inpaintingSlice.ts +++ b/frontend/src/features/tabs/Inpainting/inpaintingSlice.ts @@ -46,6 +46,7 @@ export interface InpaintingState { shouldShowMask: boolean; shouldInvertMask: boolean; shouldShowCheckboardTransparency: boolean; + shouldShowBrush: boolean; shouldShowBrushPreview: boolean; imageToInpaint?: InvokeAI.Image; needsRepaint: boolean; @@ -70,6 +71,7 @@ const initialInpaintingState: InpaintingState = { shouldShowMask: true, shouldInvertMask: false, shouldShowCheckboardTransparency: false, + shouldShowBrush: true, shouldShowBrushPreview: false, isMovingBoundingBox: false, needsRepaint: false, @@ -144,6 +146,9 @@ export const inpaintingSlice = createSlice({ setShouldShowBrushPreview: (state, action: PayloadAction) => { state.shouldShowBrushPreview = action.payload; }, + setShouldShowBrush: (state, action: PayloadAction) => { + state.shouldShowBrush = action.payload; + }, setMaskColor: (state, action: PayloadAction) => { state.maskColor = action.payload; }, @@ -335,6 +340,7 @@ export const { setShouldShowBoundingBoxFill, setIsBoundingBoxTransforming, setIsDrawing, + setShouldShowBrush } = inpaintingSlice.actions; export default inpaintingSlice.reducer; diff --git a/frontend/src/features/tabs/Inpainting/inpaintingSliceSelectors.ts b/frontend/src/features/tabs/Inpainting/inpaintingSliceSelectors.ts index 8eba6b922b..50c17ef540 100644 --- a/frontend/src/features/tabs/Inpainting/inpaintingSliceSelectors.ts +++ b/frontend/src/features/tabs/Inpainting/inpaintingSliceSelectors.ts @@ -77,6 +77,8 @@ export const inpaintingCanvasSelector = createSelector( boundingBoxCoordinate, stageScale, shouldShowBoundingBoxFill, + isDrawing, + isBoundingBoxTransforming, } = inpainting; return { tool, @@ -93,6 +95,8 @@ export const inpaintingCanvasSelector = createSelector( boundingBoxCoordinate, stageScale, shouldShowBoundingBoxFill, + isDrawing, + isBoundingBoxTransforming, }; }, {