mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): move canvas interaction state to nanostores
This drastically reduces the computation needed when moving the cursor. It also correctly separates ephemeral interaction state from redux, where it is not needed. Also removed some unused canvas state.
This commit is contained in:
parent
2a38606342
commit
7c548c5bf3
@ -1,4 +1,5 @@
|
||||
import { Box, chakra, Flex } from '@chakra-ui/react';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
@ -9,6 +10,12 @@ import useCanvasMouseMove from 'features/canvas/hooks/useCanvasMouseMove';
|
||||
import useCanvasMouseOut from 'features/canvas/hooks/useCanvasMouseOut';
|
||||
import useCanvasMouseUp from 'features/canvas/hooks/useCanvasMouseUp';
|
||||
import useCanvasWheel from 'features/canvas/hooks/useCanvasZoom';
|
||||
import {
|
||||
$isModifyingBoundingBox,
|
||||
$isMouseOverBoundingBox,
|
||||
$isMovingStage,
|
||||
$isTransformingBoundingBox,
|
||||
} from 'features/canvas/store/canvasNanostore';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { canvasResized } from 'features/canvas/store/canvasSlice';
|
||||
import {
|
||||
@ -40,46 +47,27 @@ const selector = createMemoizedSelector(
|
||||
isMaskEnabled,
|
||||
stageScale,
|
||||
shouldShowBoundingBox,
|
||||
isTransformingBoundingBox,
|
||||
isMouseOverBoundingBox,
|
||||
isMovingBoundingBox,
|
||||
stageDimensions,
|
||||
stageCoordinates,
|
||||
tool,
|
||||
isMovingStage,
|
||||
shouldShowIntermediates,
|
||||
shouldShowGrid,
|
||||
shouldRestrictStrokesToBox,
|
||||
shouldShowGrid,
|
||||
shouldAntialias,
|
||||
} = canvas;
|
||||
|
||||
let stageCursor: string | undefined = 'none';
|
||||
|
||||
if (tool === 'move' || isStaging) {
|
||||
if (isMovingStage) {
|
||||
stageCursor = 'grabbing';
|
||||
} else {
|
||||
stageCursor = 'grab';
|
||||
}
|
||||
} else if (isTransformingBoundingBox) {
|
||||
stageCursor = undefined;
|
||||
} else if (shouldRestrictStrokesToBox && !isMouseOverBoundingBox) {
|
||||
stageCursor = 'default';
|
||||
}
|
||||
|
||||
return {
|
||||
isMaskEnabled,
|
||||
isModifyingBoundingBox: isTransformingBoundingBox || isMovingBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
shouldShowGrid,
|
||||
stageCoordinates,
|
||||
stageCursor,
|
||||
stageDimensions,
|
||||
stageScale,
|
||||
tool,
|
||||
isStaging,
|
||||
shouldShowIntermediates,
|
||||
shouldAntialias,
|
||||
shouldRestrictStrokesToBox,
|
||||
};
|
||||
}
|
||||
);
|
||||
@ -91,29 +79,51 @@ const ChakraStage = chakra(Stage, {
|
||||
const IAICanvas = () => {
|
||||
const {
|
||||
isMaskEnabled,
|
||||
isModifyingBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
shouldShowGrid,
|
||||
stageCoordinates,
|
||||
stageCursor,
|
||||
stageDimensions,
|
||||
stageScale,
|
||||
tool,
|
||||
isStaging,
|
||||
shouldShowIntermediates,
|
||||
shouldAntialias,
|
||||
shouldRestrictStrokesToBox,
|
||||
} = useAppSelector(selector);
|
||||
useCanvasHotkeys();
|
||||
const dispatch = useAppDispatch();
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const stageRef = useRef<Konva.Stage | null>(null);
|
||||
const canvasBaseLayerRef = useRef<Konva.Layer | null>(null);
|
||||
|
||||
const isModifyingBoundingBox = useStore($isModifyingBoundingBox);
|
||||
const isMovingStage = useStore($isMovingStage);
|
||||
const isTransformingBoundingBox = useStore($isTransformingBoundingBox);
|
||||
const isMouseOverBoundingBox = useStore($isMouseOverBoundingBox);
|
||||
const canvasStageRefCallback = useCallback((el: Konva.Stage) => {
|
||||
setCanvasStage(el as Konva.Stage);
|
||||
stageRef.current = el;
|
||||
}, []);
|
||||
|
||||
const stageCursor = useMemo(() => {
|
||||
if (tool === 'move' || isStaging) {
|
||||
if (isMovingStage) {
|
||||
return 'grabbing';
|
||||
} else {
|
||||
return 'grab';
|
||||
}
|
||||
} else if (isTransformingBoundingBox) {
|
||||
return undefined;
|
||||
} else if (shouldRestrictStrokesToBox && !isMouseOverBoundingBox) {
|
||||
return 'default';
|
||||
}
|
||||
return 'none';
|
||||
}, [
|
||||
isMouseOverBoundingBox,
|
||||
isMovingStage,
|
||||
isStaging,
|
||||
isTransformingBoundingBox,
|
||||
shouldRestrictStrokesToBox,
|
||||
tool,
|
||||
]);
|
||||
const canvasBaseLayerRefCallback = useCallback((el: Konva.Layer) => {
|
||||
setCanvasBaseLayer(el as Konva.Layer);
|
||||
canvasBaseLayerRef.current = el;
|
||||
@ -132,10 +142,9 @@ const IAICanvas = () => {
|
||||
didMouseMoveRef,
|
||||
lastCursorPositionRef
|
||||
);
|
||||
const handleMouseOut = useCanvasMouseOut();
|
||||
const { handleDragStart, handleDragMove, handleDragEnd } =
|
||||
useCanvasDragMove();
|
||||
|
||||
const handleMouseOut = useCanvasMouseOut();
|
||||
const handleContextMenu = useCallback(
|
||||
(e: KonvaEventObject<MouseEvent>) => e.evt.preventDefault(),
|
||||
[]
|
||||
|
@ -1,24 +1,18 @@
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { $cursorPosition } from 'features/canvas/store/canvasNanostore';
|
||||
import roundToHundreth from 'features/canvas/util/roundToHundreth';
|
||||
import { memo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const cursorPositionSelector = createSelector([stateSelector], ({ canvas }) => {
|
||||
const { cursorPosition } = canvas;
|
||||
|
||||
const { cursorX, cursorY } = cursorPosition
|
||||
? { cursorX: cursorPosition.x, cursorY: cursorPosition.y }
|
||||
: { cursorX: -1, cursorY: -1 };
|
||||
|
||||
return `(${roundToHundreth(cursorX)}, ${roundToHundreth(cursorY)})`;
|
||||
});
|
||||
|
||||
const IAICanvasStatusTextCursorPos = () => {
|
||||
const cursorCoordinatesString = useAppSelector(cursorPositionSelector);
|
||||
const { t } = useTranslation();
|
||||
const cursorPosition = useStore($cursorPosition);
|
||||
const cursorCoordinatesString = useMemo(() => {
|
||||
const x = cursorPosition?.x ?? -1;
|
||||
const y = cursorPosition?.y ?? -1;
|
||||
return `(${roundToHundreth(x)}, ${roundToHundreth(y)})`;
|
||||
}, [cursorPosition?.x, cursorPosition?.y]);
|
||||
|
||||
return (
|
||||
<Box>{`${t(
|
||||
|
@ -1,29 +1,31 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
$cursorPosition,
|
||||
$isMovingBoundingBox,
|
||||
$isTransformingBoundingBox,
|
||||
} from 'features/canvas/store/canvasNanostore';
|
||||
import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
||||
import {
|
||||
COLOR_PICKER_SIZE,
|
||||
COLOR_PICKER_STROKE_RADIUS,
|
||||
} from 'features/canvas/util/constants';
|
||||
import type { GroupConfig } from 'konva/lib/Group';
|
||||
import { memo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { Circle, Group } from 'react-konva';
|
||||
|
||||
const canvasBrushPreviewSelector = createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ canvas }) => {
|
||||
const {
|
||||
cursorPosition,
|
||||
brushSize,
|
||||
colorPickerColor,
|
||||
maskColor,
|
||||
brushColor,
|
||||
tool,
|
||||
layer,
|
||||
shouldShowBrush,
|
||||
isMovingBoundingBox,
|
||||
isTransformingBoundingBox,
|
||||
stageScale,
|
||||
stageDimensions,
|
||||
boundingBoxCoordinates,
|
||||
@ -80,9 +82,6 @@ const canvasBrushPreviewSelector = createMemoizedSelector(
|
||||
// : undefined;
|
||||
|
||||
return {
|
||||
cursorPosition,
|
||||
brushX: cursorPosition ? cursorPosition.x : stageDimensions.width / 2,
|
||||
brushY: cursorPosition ? cursorPosition.y : stageDimensions.height / 2,
|
||||
radius: brushSize / 2,
|
||||
colorPickerOuterRadius: COLOR_PICKER_SIZE / stageScale,
|
||||
colorPickerInnerRadius:
|
||||
@ -92,16 +91,10 @@ const canvasBrushPreviewSelector = createMemoizedSelector(
|
||||
colorPickerColorString: rgbaColorToString(colorPickerColor),
|
||||
tool,
|
||||
layer,
|
||||
shouldShowBrush,
|
||||
shouldDrawBrushPreview:
|
||||
!(
|
||||
isMovingBoundingBox ||
|
||||
isTransformingBoundingBox ||
|
||||
!cursorPosition
|
||||
) && shouldShowBrush,
|
||||
strokeWidth: 1.5 / stageScale,
|
||||
dotRadius: 1.5 / stageScale,
|
||||
clip,
|
||||
stageDimensions,
|
||||
};
|
||||
}
|
||||
);
|
||||
@ -111,13 +104,10 @@ const canvasBrushPreviewSelector = createMemoizedSelector(
|
||||
*/
|
||||
const IAICanvasToolPreview = (props: GroupConfig) => {
|
||||
const {
|
||||
brushX,
|
||||
brushY,
|
||||
radius,
|
||||
maskColorString,
|
||||
tool,
|
||||
layer,
|
||||
shouldDrawBrushPreview,
|
||||
dotRadius,
|
||||
strokeWidth,
|
||||
brushColorString,
|
||||
@ -125,8 +115,28 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
|
||||
colorPickerInnerRadius,
|
||||
colorPickerOuterRadius,
|
||||
clip,
|
||||
stageDimensions,
|
||||
} = useAppSelector(canvasBrushPreviewSelector);
|
||||
|
||||
const cursorPosition = useStore($cursorPosition);
|
||||
const isMovingBoundingBox = useStore($isMovingBoundingBox);
|
||||
const isTransformingBoundingBox = useStore($isTransformingBoundingBox);
|
||||
|
||||
const brushX = useMemo<number>(
|
||||
() => (cursorPosition ? cursorPosition.x : stageDimensions.width / 2),
|
||||
[cursorPosition, stageDimensions]
|
||||
);
|
||||
const brushY = useMemo<number>(
|
||||
() => (cursorPosition ? cursorPosition.y : stageDimensions.height / 2),
|
||||
[cursorPosition, stageDimensions]
|
||||
);
|
||||
|
||||
const shouldDrawBrushPreview = useMemo(
|
||||
() =>
|
||||
!(isMovingBoundingBox || isTransformingBoundingBox || !cursorPosition),
|
||||
[cursorPosition, isMovingBoundingBox, isTransformingBoundingBox]
|
||||
);
|
||||
|
||||
if (!shouldDrawBrushPreview) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
@ -6,11 +7,16 @@ import {
|
||||
roundToMultiple,
|
||||
} from 'common/util/roundDownToMultiple';
|
||||
import {
|
||||
setBoundingBoxCoordinates,
|
||||
setBoundingBoxDimensions,
|
||||
$isDrawing,
|
||||
$isMovingBoundingBox,
|
||||
$isTransformingBoundingBox,
|
||||
setIsMouseOverBoundingBox,
|
||||
setIsMovingBoundingBox,
|
||||
setIsTransformingBoundingBox,
|
||||
} from 'features/canvas/store/canvasNanostore';
|
||||
import {
|
||||
setBoundingBoxCoordinates,
|
||||
setBoundingBoxDimensions,
|
||||
setShouldSnapToGrid,
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
import type Konva from 'konva';
|
||||
@ -30,9 +36,6 @@ const boundingBoxPreviewSelector = createMemoizedSelector(
|
||||
boundingBoxCoordinates,
|
||||
boundingBoxDimensions,
|
||||
stageScale,
|
||||
isDrawing,
|
||||
isTransformingBoundingBox,
|
||||
isMovingBoundingBox,
|
||||
tool,
|
||||
shouldSnapToGrid,
|
||||
} = canvas;
|
||||
@ -42,9 +45,6 @@ const boundingBoxPreviewSelector = createMemoizedSelector(
|
||||
return {
|
||||
boundingBoxCoordinates,
|
||||
boundingBoxDimensions,
|
||||
isDrawing,
|
||||
isMovingBoundingBox,
|
||||
isTransformingBoundingBox,
|
||||
stageScale,
|
||||
shouldSnapToGrid,
|
||||
tool,
|
||||
@ -63,9 +63,7 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
||||
const {
|
||||
boundingBoxCoordinates,
|
||||
boundingBoxDimensions,
|
||||
isDrawing,
|
||||
isMovingBoundingBox,
|
||||
isTransformingBoundingBox,
|
||||
|
||||
stageScale,
|
||||
shouldSnapToGrid,
|
||||
tool,
|
||||
@ -75,7 +73,9 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
||||
|
||||
const transformerRef = useRef<Konva.Transformer>(null);
|
||||
const shapeRef = useRef<Konva.Rect>(null);
|
||||
|
||||
const isDrawing = useStore($isDrawing);
|
||||
const isMovingBoundingBox = useStore($isMovingBoundingBox);
|
||||
const isTransformingBoundingBox = useStore($isTransformingBoundingBox);
|
||||
const [isMouseOverBoundingBoxOutline, setIsMouseOverBoundingBoxOutline] =
|
||||
useState(false);
|
||||
|
||||
@ -209,26 +209,26 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
||||
);
|
||||
|
||||
const handleStartedTransforming = useCallback(() => {
|
||||
dispatch(setIsTransformingBoundingBox(true));
|
||||
}, [dispatch]);
|
||||
setIsTransformingBoundingBox(true);
|
||||
}, []);
|
||||
|
||||
const handleEndedTransforming = useCallback(() => {
|
||||
dispatch(setIsTransformingBoundingBox(false));
|
||||
dispatch(setIsMovingBoundingBox(false));
|
||||
dispatch(setIsMouseOverBoundingBox(false));
|
||||
setIsTransformingBoundingBox(false);
|
||||
setIsMovingBoundingBox(false);
|
||||
setIsMouseOverBoundingBox(false);
|
||||
setIsMouseOverBoundingBoxOutline(false);
|
||||
}, [dispatch]);
|
||||
}, []);
|
||||
|
||||
const handleStartedMoving = useCallback(() => {
|
||||
dispatch(setIsMovingBoundingBox(true));
|
||||
}, [dispatch]);
|
||||
setIsMovingBoundingBox(true);
|
||||
}, []);
|
||||
|
||||
const handleEndedModifying = useCallback(() => {
|
||||
dispatch(setIsTransformingBoundingBox(false));
|
||||
dispatch(setIsMovingBoundingBox(false));
|
||||
dispatch(setIsMouseOverBoundingBox(false));
|
||||
setIsTransformingBoundingBox(false);
|
||||
setIsMovingBoundingBox(false);
|
||||
setIsMouseOverBoundingBox(false);
|
||||
setIsMouseOverBoundingBoxOutline(false);
|
||||
}, [dispatch]);
|
||||
}, []);
|
||||
|
||||
const handleMouseOver = useCallback(() => {
|
||||
setIsMouseOverBoundingBoxOutline(true);
|
||||
@ -241,12 +241,12 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
||||
}, [isMovingBoundingBox, isTransformingBoundingBox]);
|
||||
|
||||
const handleMouseEnterBoundingBox = useCallback(() => {
|
||||
dispatch(setIsMouseOverBoundingBox(true));
|
||||
}, [dispatch]);
|
||||
setIsMouseOverBoundingBox(true);
|
||||
}, []);
|
||||
|
||||
const handleMouseLeaveBoundingBox = useCallback(() => {
|
||||
dispatch(setIsMouseOverBoundingBox(false));
|
||||
}, [dispatch]);
|
||||
setIsMouseOverBoundingBox(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Group {...rest}>
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
InvPopoverTrigger,
|
||||
} from 'common/components/InvPopover/wrapper';
|
||||
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
||||
import { resetToolInteractionState } from 'features/canvas/store/canvasNanostore';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import {
|
||||
addEraseRect,
|
||||
@ -176,12 +177,15 @@ const IAICanvasToolChooserOptions = () => {
|
||||
|
||||
const handleSelectBrushTool = useCallback(() => {
|
||||
dispatch(setTool('brush'));
|
||||
resetToolInteractionState();
|
||||
}, [dispatch]);
|
||||
const handleSelectEraserTool = useCallback(() => {
|
||||
dispatch(setTool('eraser'));
|
||||
resetToolInteractionState();
|
||||
}, [dispatch]);
|
||||
const handleSelectColorPickerTool = useCallback(() => {
|
||||
dispatch(setTool('colorPicker'));
|
||||
resetToolInteractionState();
|
||||
}, [dispatch]);
|
||||
const handleFillRect = useCallback(() => {
|
||||
dispatch(addFillRect());
|
||||
|
@ -1,26 +1,25 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import {
|
||||
$isMovingBoundingBox,
|
||||
setIsMovingStage,
|
||||
setStageCoordinates,
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
} from 'features/canvas/store/canvasNanostore';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { setStageCoordinates } from 'features/canvas/store/canvasSlice';
|
||||
import type { KonvaEventObject } from 'konva/lib/Node';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const useCanvasDrag = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const tool = useAppSelector((state) => state.canvas.tool);
|
||||
const isMovingBoundingBox = useAppSelector(
|
||||
(state) => state.canvas.isMovingBoundingBox
|
||||
);
|
||||
const isStaging = useAppSelector(isStagingSelector);
|
||||
|
||||
const tool = useAppSelector((state) => state.canvas.tool);
|
||||
const isMovingBoundingBox = useStore($isMovingBoundingBox);
|
||||
const handleDragStart = useCallback(() => {
|
||||
if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
|
||||
return;
|
||||
}
|
||||
dispatch(setIsMovingStage(true));
|
||||
}, [dispatch, isMovingBoundingBox, isStaging, tool]);
|
||||
setIsMovingStage(true);
|
||||
}, [isMovingBoundingBox, isStaging, tool]);
|
||||
|
||||
const handleDragMove = useCallback(
|
||||
(e: KonvaEventObject<MouseEvent>) => {
|
||||
@ -39,10 +38,14 @@ const useCanvasDrag = () => {
|
||||
if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
|
||||
return;
|
||||
}
|
||||
dispatch(setIsMovingStage(false));
|
||||
}, [dispatch, isMovingBoundingBox, isStaging, tool]);
|
||||
setIsMovingStage(false);
|
||||
}, [isMovingBoundingBox, isStaging, tool]);
|
||||
|
||||
return { handleDragStart, handleDragMove, handleDragEnd };
|
||||
return {
|
||||
handleDragStart,
|
||||
handleDragMove,
|
||||
handleDragEnd,
|
||||
};
|
||||
};
|
||||
|
||||
export default useCanvasDrag;
|
||||
|
@ -1,10 +1,13 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
resetCanvasInteractionState,
|
||||
resetToolInteractionState,
|
||||
} from 'features/canvas/store/canvasNanostore';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import {
|
||||
clearMask,
|
||||
resetCanvasInteractionState,
|
||||
setIsMaskEnabled,
|
||||
setShouldShowBoundingBox,
|
||||
setShouldSnapToGrid,
|
||||
@ -20,7 +23,6 @@ const selector = createMemoizedSelector(
|
||||
[stateSelector, activeTabNameSelector, isStagingSelector],
|
||||
({ canvas }, activeTabName, isStaging) => {
|
||||
const {
|
||||
cursorPosition,
|
||||
shouldLockBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
tool,
|
||||
@ -30,7 +32,6 @@ const selector = createMemoizedSelector(
|
||||
|
||||
return {
|
||||
activeTabName,
|
||||
isCursorOnCanvas: Boolean(cursorPosition),
|
||||
shouldLockBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
tool,
|
||||
@ -102,7 +103,7 @@ const useInpaintingCanvasHotkeys = () => {
|
||||
useHotkeys(
|
||||
'esc',
|
||||
() => {
|
||||
dispatch(resetCanvasInteractionState());
|
||||
resetCanvasInteractionState();
|
||||
},
|
||||
{
|
||||
enabled: () => true,
|
||||
@ -134,6 +135,7 @@ const useInpaintingCanvasHotkeys = () => {
|
||||
if (tool !== 'move') {
|
||||
previousToolRef.current = tool;
|
||||
dispatch(setTool('move'));
|
||||
resetToolInteractionState();
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import {
|
||||
addLine,
|
||||
setIsDrawing,
|
||||
setIsMovingStage,
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
} from 'features/canvas/store/canvasNanostore';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { addLine } from 'features/canvas/store/canvasSlice';
|
||||
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import type Konva from 'konva';
|
||||
@ -42,7 +42,7 @@ const useCanvasMouseDown = (stageRef: MutableRefObject<Konva.Stage | null>) => {
|
||||
stageRef.current.container().focus();
|
||||
|
||||
if (tool === 'move' || isStaging) {
|
||||
dispatch(setIsMovingStage(true));
|
||||
setIsMovingStage(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ const useCanvasMouseDown = (stageRef: MutableRefObject<Konva.Stage | null>) => {
|
||||
|
||||
e.evt.preventDefault();
|
||||
|
||||
dispatch(setIsDrawing(true));
|
||||
setIsDrawing(true);
|
||||
|
||||
// Add a new line starting from the current cursor position.
|
||||
dispatch(addLine([scaledCursorPosition.x, scaledCursorPosition.y]));
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import {
|
||||
addPointToCurrentLine,
|
||||
$isDrawing,
|
||||
setCursorPosition,
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
} from 'features/canvas/store/canvasNanostore';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { addPointToCurrentLine } from 'features/canvas/store/canvasSlice';
|
||||
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import type Konva from 'konva';
|
||||
@ -18,10 +20,9 @@ import useColorPicker from './useColorUnderCursor';
|
||||
const selector = createMemoizedSelector(
|
||||
[activeTabNameSelector, stateSelector, isStagingSelector],
|
||||
(activeTabName, { canvas }, isStaging) => {
|
||||
const { tool, isDrawing } = canvas;
|
||||
const { tool } = canvas;
|
||||
return {
|
||||
tool,
|
||||
isDrawing,
|
||||
activeTabName,
|
||||
isStaging,
|
||||
};
|
||||
@ -34,7 +35,8 @@ const useCanvasMouseMove = (
|
||||
lastCursorPositionRef: MutableRefObject<Vector2d>
|
||||
) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { isDrawing, tool, isStaging } = useAppSelector(selector);
|
||||
const isDrawing = useStore($isDrawing);
|
||||
const { tool, isStaging } = useAppSelector(selector);
|
||||
const { updateColorUnderCursor } = useColorPicker();
|
||||
|
||||
return useCallback(() => {
|
||||
@ -48,7 +50,7 @@ const useCanvasMouseMove = (
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(setCursorPosition(scaledCursorPosition));
|
||||
setCursorPosition(scaledCursorPosition);
|
||||
|
||||
lastCursorPositionRef.current = scaledCursorPosition;
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { mouseLeftCanvas } from 'features/canvas/store/canvasSlice';
|
||||
import { setCanvasInteractionStateMouseOut } from 'features/canvas/store/canvasNanostore';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const useCanvasMouseOut = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const onMouseOut = useCallback(() => {
|
||||
setCanvasInteractionStateMouseOut();
|
||||
}, []);
|
||||
|
||||
return useCallback(() => {
|
||||
dispatch(mouseLeftCanvas());
|
||||
}, [dispatch]);
|
||||
return onMouseOut;
|
||||
};
|
||||
|
||||
export default useCanvasMouseOut;
|
||||
|
@ -1,27 +1,27 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
$isDrawing,
|
||||
setIsDrawing,
|
||||
setIsMovingStage,
|
||||
} from 'features/canvas/store/canvasNanostore';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import {
|
||||
// addPointToCurrentEraserLine,
|
||||
addPointToCurrentLine,
|
||||
setIsDrawing,
|
||||
setIsMovingStage,
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import type Konva from 'konva';
|
||||
import type { MutableRefObject } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const selector = createMemoizedSelector(
|
||||
[activeTabNameSelector, stateSelector, isStagingSelector],
|
||||
(activeTabName, { canvas }, isStaging) => {
|
||||
const { tool, isDrawing } = canvas;
|
||||
[stateSelector, isStagingSelector],
|
||||
({ canvas }, isStaging) => {
|
||||
return {
|
||||
tool,
|
||||
isDrawing,
|
||||
activeTabName,
|
||||
tool: canvas.tool,
|
||||
isStaging,
|
||||
};
|
||||
}
|
||||
@ -32,11 +32,12 @@ const useCanvasMouseUp = (
|
||||
didMouseMoveRef: MutableRefObject<boolean>
|
||||
) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { tool, isDrawing, isStaging } = useAppSelector(selector);
|
||||
const isDrawing = useStore($isDrawing);
|
||||
const { tool, isStaging } = useAppSelector(selector);
|
||||
|
||||
return useCallback(() => {
|
||||
if (tool === 'move' || isStaging) {
|
||||
dispatch(setIsMovingStage(false));
|
||||
setIsMovingStage(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -59,7 +60,7 @@ const useCanvasMouseUp = (
|
||||
} else {
|
||||
didMouseMoveRef.current = false;
|
||||
}
|
||||
dispatch(setIsDrawing(false));
|
||||
setIsDrawing(false);
|
||||
}, [didMouseMoveRef, dispatch, isDrawing, isStaging, stageRef, tool]);
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { $isMoveStageKeyHeld } from 'features/canvas/store/canvasNanostore';
|
||||
import {
|
||||
setStageCoordinates,
|
||||
setStageScale,
|
||||
@ -16,17 +18,15 @@ import { clamp } from 'lodash-es';
|
||||
import type { MutableRefObject } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
||||
const { isMoveStageKeyHeld, stageScale } = canvas;
|
||||
return {
|
||||
isMoveStageKeyHeld,
|
||||
stageScale,
|
||||
};
|
||||
});
|
||||
const selector = createMemoizedSelector(
|
||||
[stateSelector],
|
||||
(state) => state.canvas.stageScale
|
||||
);
|
||||
|
||||
const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { isMoveStageKeyHeld, stageScale } = useAppSelector(selector);
|
||||
const stageScale = useAppSelector(selector);
|
||||
const isMoveStageKeyHeld = useStore($isMoveStageKeyHeld);
|
||||
|
||||
return useCallback(
|
||||
(e: KonvaEventObject<WheelEvent>) => {
|
||||
|
@ -0,0 +1,77 @@
|
||||
import type { Vector2d } from 'konva/lib/types';
|
||||
import { atom, computed } from 'nanostores';
|
||||
|
||||
export const $cursorPosition = atom<Vector2d | null>(null);
|
||||
export const $isDrawing = atom<boolean>(false);
|
||||
export const $isMouseOverBoundingBox = atom<boolean>(false);
|
||||
export const $isMoveBoundingBoxKeyHeld = atom<boolean>(false);
|
||||
export const $isMoveStageKeyHeld = atom<boolean>(false);
|
||||
export const $isMovingBoundingBox = atom<boolean>(false);
|
||||
export const $isMovingStage = atom<boolean>(false);
|
||||
export const $isTransformingBoundingBox = atom<boolean>(false);
|
||||
export const $isModifyingBoundingBox = computed(
|
||||
[$isTransformingBoundingBox, $isMovingBoundingBox],
|
||||
(isTransformingBoundingBox, isMovingBoundingBox) =>
|
||||
isTransformingBoundingBox || isMovingBoundingBox
|
||||
);
|
||||
|
||||
export const resetCanvasInteractionState = () => {
|
||||
$cursorPosition.set(null);
|
||||
$isDrawing.set(false);
|
||||
$isMouseOverBoundingBox.set(false);
|
||||
$isMoveBoundingBoxKeyHeld.set(false);
|
||||
$isMoveStageKeyHeld.set(false);
|
||||
$isMovingBoundingBox.set(false);
|
||||
$isMovingStage.set(false);
|
||||
};
|
||||
|
||||
export const setCursorPosition = (cursorPosition: Vector2d | null) => {
|
||||
$cursorPosition.set(cursorPosition);
|
||||
};
|
||||
|
||||
export const setIsDrawing = (isDrawing: boolean) => {
|
||||
$isDrawing.set(isDrawing);
|
||||
};
|
||||
|
||||
export const setIsMouseOverBoundingBox = (isMouseOverBoundingBox: boolean) => {
|
||||
$isMouseOverBoundingBox.set(isMouseOverBoundingBox);
|
||||
};
|
||||
|
||||
export const setIsMoveBoundingBoxKeyHeld = (
|
||||
isMoveBoundingBoxKeyHeld: boolean
|
||||
) => {
|
||||
$isMoveBoundingBoxKeyHeld.set(isMoveBoundingBoxKeyHeld);
|
||||
};
|
||||
|
||||
export const setIsMoveStageKeyHeld = (isMoveStageKeyHeld: boolean) => {
|
||||
$isMoveStageKeyHeld.set(isMoveStageKeyHeld);
|
||||
};
|
||||
|
||||
export const setIsMovingBoundingBox = (isMovingBoundingBox: boolean) => {
|
||||
$isMovingBoundingBox.set(isMovingBoundingBox);
|
||||
};
|
||||
|
||||
export const setIsMovingStage = (isMovingStage: boolean) => {
|
||||
$isMovingStage.set(isMovingStage);
|
||||
};
|
||||
|
||||
export const setIsTransformingBoundingBox = (
|
||||
isTransformingBoundingBox: boolean
|
||||
) => {
|
||||
$isTransformingBoundingBox.set(isTransformingBoundingBox);
|
||||
};
|
||||
|
||||
export const resetToolInteractionState = () => {
|
||||
setIsTransformingBoundingBox(false);
|
||||
setIsMouseOverBoundingBox(false);
|
||||
setIsMovingBoundingBox(false);
|
||||
setIsMovingStage(false);
|
||||
};
|
||||
|
||||
export const setCanvasInteractionStateMouseOut = () => {
|
||||
setCursorPosition(null);
|
||||
setIsDrawing(false);
|
||||
setIsMouseOverBoundingBox(false);
|
||||
setIsMovingBoundingBox(false);
|
||||
setIsTransformingBoundingBox(false);
|
||||
};
|
@ -3,4 +3,4 @@ import type { CanvasState } from './canvasTypes';
|
||||
/**
|
||||
* Canvas slice persist denylist
|
||||
*/
|
||||
export const canvasPersistDenylist: (keyof CanvasState)[] = ['cursorPosition'];
|
||||
export const canvasPersistDenylist: (keyof CanvasState)[] = [];
|
||||
|
@ -36,6 +36,11 @@ import {
|
||||
isCanvasMaskLine,
|
||||
} from './canvasTypes';
|
||||
|
||||
/**
|
||||
* The maximum history length to keep in the past/future layer states.
|
||||
*/
|
||||
const MAX_HISTORY = 128;
|
||||
|
||||
export const initialLayerState: CanvasLayerState = {
|
||||
objects: [],
|
||||
stagingArea: {
|
||||
@ -52,21 +57,11 @@ export const initialCanvasState: CanvasState = {
|
||||
brushColor: { r: 90, g: 90, b: 255, a: 1 },
|
||||
brushSize: 50,
|
||||
colorPickerColor: { r: 90, g: 90, b: 255, a: 1 },
|
||||
cursorPosition: null,
|
||||
futureLayerStates: [],
|
||||
isDrawing: false,
|
||||
isMaskEnabled: true,
|
||||
isMouseOverBoundingBox: false,
|
||||
isMoveBoundingBoxKeyHeld: false,
|
||||
isMoveStageKeyHeld: false,
|
||||
isMovingBoundingBox: false,
|
||||
isMovingStage: false,
|
||||
isTransformingBoundingBox: false,
|
||||
layer: 'base',
|
||||
layerState: initialLayerState,
|
||||
maskColor: { r: 255, g: 90, b: 90, a: 1 },
|
||||
maxHistory: 128,
|
||||
minimumStageScale: 1,
|
||||
pastLayerStates: [],
|
||||
scaledBoundingBoxDimensions: { width: 512, height: 512 },
|
||||
shouldAntialias: true,
|
||||
@ -77,10 +72,7 @@ export const initialCanvasState: CanvasState = {
|
||||
shouldPreserveMaskedArea: false,
|
||||
shouldRestrictStrokesToBox: true,
|
||||
shouldShowBoundingBox: true,
|
||||
shouldShowBrush: true,
|
||||
shouldShowBrushPreview: false,
|
||||
shouldShowCanvasDebugInfo: false,
|
||||
shouldShowCheckboardTransparency: false,
|
||||
shouldShowGrid: true,
|
||||
shouldShowIntermediates: true,
|
||||
shouldShowStagingImage: true,
|
||||
@ -98,14 +90,7 @@ export const canvasSlice = createSlice({
|
||||
initialState: initialCanvasState,
|
||||
reducers: {
|
||||
setTool: (state, action: PayloadAction<CanvasTool>) => {
|
||||
const tool = action.payload;
|
||||
state.tool = action.payload;
|
||||
if (tool !== 'move') {
|
||||
state.isTransformingBoundingBox = false;
|
||||
state.isMouseOverBoundingBox = false;
|
||||
state.isMovingBoundingBox = false;
|
||||
state.isMovingStage = false;
|
||||
}
|
||||
},
|
||||
setLayer: (state, action: PayloadAction<CanvasLayer>) => {
|
||||
state.layer = action.payload;
|
||||
@ -146,21 +131,6 @@ export const canvasSlice = createSlice({
|
||||
state.isMaskEnabled = action.payload;
|
||||
state.layer = action.payload ? 'mask' : 'base';
|
||||
},
|
||||
setShouldShowCheckboardTransparency: (
|
||||
state,
|
||||
action: PayloadAction<boolean>
|
||||
) => {
|
||||
state.shouldShowCheckboardTransparency = action.payload;
|
||||
},
|
||||
setShouldShowBrushPreview: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldShowBrushPreview = action.payload;
|
||||
},
|
||||
setShouldShowBrush: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldShowBrush = action.payload;
|
||||
},
|
||||
setCursorPosition: (state, action: PayloadAction<Vector2d | null>) => {
|
||||
state.cursorPosition = action.payload;
|
||||
},
|
||||
setInitialCanvasImage: (state, action: PayloadAction<ImageDTO>) => {
|
||||
const image = action.payload;
|
||||
const { width, height } = image;
|
||||
@ -273,9 +243,6 @@ export const canvasSlice = createSlice({
|
||||
) => {
|
||||
state.shouldDarkenOutsideBoundingBox = action.payload;
|
||||
},
|
||||
setIsDrawing: (state, action: PayloadAction<boolean>) => {
|
||||
state.isDrawing = action.payload;
|
||||
},
|
||||
clearCanvasHistory: (state) => {
|
||||
state.pastLayerStates = [];
|
||||
state.futureLayerStates = [];
|
||||
@ -289,21 +256,6 @@ export const canvasSlice = 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;
|
||||
},
|
||||
setIsMoveBoundingBoxKeyHeld: (state, action: PayloadAction<boolean>) => {
|
||||
state.isMoveBoundingBoxKeyHeld = action.payload;
|
||||
},
|
||||
setIsMoveStageKeyHeld: (state, action: PayloadAction<boolean>) => {
|
||||
state.isMoveStageKeyHeld = action.payload;
|
||||
},
|
||||
canvasBatchIdAdded: (state, action: PayloadAction<string>) => {
|
||||
state.batchIds.push(action.payload);
|
||||
},
|
||||
@ -333,7 +285,7 @@ export const canvasSlice = createSlice({
|
||||
|
||||
state.pastLayerStates.push(cloneDeep(state.layerState));
|
||||
|
||||
if (state.pastLayerStates.length > state.maxHistory) {
|
||||
if (state.pastLayerStates.length > MAX_HISTORY) {
|
||||
state.pastLayerStates.shift();
|
||||
}
|
||||
|
||||
@ -352,7 +304,7 @@ export const canvasSlice = createSlice({
|
||||
discardStagedImages: (state) => {
|
||||
state.pastLayerStates.push(cloneDeep(state.layerState));
|
||||
|
||||
if (state.pastLayerStates.length > state.maxHistory) {
|
||||
if (state.pastLayerStates.length > MAX_HISTORY) {
|
||||
state.pastLayerStates.shift();
|
||||
}
|
||||
|
||||
@ -371,7 +323,7 @@ export const canvasSlice = createSlice({
|
||||
|
||||
state.pastLayerStates.push(cloneDeep(state.layerState));
|
||||
|
||||
if (state.pastLayerStates.length > state.maxHistory) {
|
||||
if (state.pastLayerStates.length > MAX_HISTORY) {
|
||||
state.pastLayerStates.shift();
|
||||
}
|
||||
|
||||
@ -390,7 +342,7 @@ export const canvasSlice = createSlice({
|
||||
|
||||
state.pastLayerStates.push(cloneDeep(state.layerState));
|
||||
|
||||
if (state.pastLayerStates.length > state.maxHistory) {
|
||||
if (state.pastLayerStates.length > MAX_HISTORY) {
|
||||
state.pastLayerStates.shift();
|
||||
}
|
||||
|
||||
@ -419,7 +371,7 @@ export const canvasSlice = createSlice({
|
||||
|
||||
state.pastLayerStates.push(cloneDeep(state.layerState));
|
||||
|
||||
if (state.pastLayerStates.length > state.maxHistory) {
|
||||
if (state.pastLayerStates.length > MAX_HISTORY) {
|
||||
state.pastLayerStates.shift();
|
||||
}
|
||||
|
||||
@ -461,7 +413,7 @@ export const canvasSlice = createSlice({
|
||||
|
||||
state.futureLayerStates.unshift(cloneDeep(state.layerState));
|
||||
|
||||
if (state.futureLayerStates.length > state.maxHistory) {
|
||||
if (state.futureLayerStates.length > MAX_HISTORY) {
|
||||
state.futureLayerStates.pop();
|
||||
}
|
||||
|
||||
@ -476,7 +428,7 @@ export const canvasSlice = createSlice({
|
||||
|
||||
state.pastLayerStates.push(cloneDeep(state.layerState));
|
||||
|
||||
if (state.pastLayerStates.length > state.maxHistory) {
|
||||
if (state.pastLayerStates.length > MAX_HISTORY) {
|
||||
state.pastLayerStates.shift();
|
||||
}
|
||||
|
||||
@ -485,9 +437,6 @@ export const canvasSlice = createSlice({
|
||||
setShouldShowGrid: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldShowGrid = action.payload;
|
||||
},
|
||||
setIsMovingStage: (state, action: PayloadAction<boolean>) => {
|
||||
state.isMovingStage = action.payload;
|
||||
},
|
||||
setShouldSnapToGrid: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldSnapToGrid = action.payload;
|
||||
},
|
||||
@ -653,7 +602,7 @@ export const canvasSlice = createSlice({
|
||||
|
||||
state.pastLayerStates.push(cloneDeep(state.layerState));
|
||||
|
||||
if (state.pastLayerStates.length > state.maxHistory) {
|
||||
if (state.pastLayerStates.length > MAX_HISTORY) {
|
||||
state.pastLayerStates.shift();
|
||||
}
|
||||
|
||||
@ -773,23 +722,6 @@ export const canvasSlice = createSlice({
|
||||
|
||||
state.layerState.objects = [action.payload];
|
||||
},
|
||||
resetCanvasInteractionState: (state) => {
|
||||
state.cursorPosition = null;
|
||||
state.isDrawing = false;
|
||||
state.isMouseOverBoundingBox = false;
|
||||
state.isMoveBoundingBoxKeyHeld = false;
|
||||
state.isMoveStageKeyHeld = false;
|
||||
state.isMovingBoundingBox = false;
|
||||
state.isMovingStage = false;
|
||||
state.isTransformingBoundingBox = false;
|
||||
},
|
||||
mouseLeftCanvas: (state) => {
|
||||
state.cursorPosition = null;
|
||||
state.isDrawing = false;
|
||||
state.isMouseOverBoundingBox = false;
|
||||
state.isMovingBoundingBox = false;
|
||||
state.isTransformingBoundingBox = false;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(appSocketQueueItemStatusChanged, (state, action) => {
|
||||
@ -848,12 +780,10 @@ export const {
|
||||
commitStagingAreaImage,
|
||||
discardStagedImages,
|
||||
fitBoundingBoxToStage,
|
||||
mouseLeftCanvas,
|
||||
nextStagingAreaImage,
|
||||
prevStagingAreaImage,
|
||||
redo,
|
||||
resetCanvas,
|
||||
resetCanvasInteractionState,
|
||||
resetCanvasView,
|
||||
setBoundingBoxCoordinates,
|
||||
setBoundingBoxDimensions,
|
||||
@ -863,16 +793,8 @@ export const {
|
||||
setBrushColor,
|
||||
setBrushSize,
|
||||
setColorPickerColor,
|
||||
setCursorPosition,
|
||||
setInitialCanvasImage,
|
||||
setIsDrawing,
|
||||
setIsMaskEnabled,
|
||||
setIsMouseOverBoundingBox,
|
||||
setIsMoveBoundingBoxKeyHeld,
|
||||
setIsMoveStageKeyHeld,
|
||||
setIsMovingBoundingBox,
|
||||
setIsMovingStage,
|
||||
setIsTransformingBoundingBox,
|
||||
setLayer,
|
||||
setMaskColor,
|
||||
setMergedCanvas,
|
||||
@ -882,10 +804,7 @@ export const {
|
||||
setShouldLockBoundingBox,
|
||||
setShouldPreserveMaskedArea,
|
||||
setShouldShowBoundingBox,
|
||||
setShouldShowBrush,
|
||||
setShouldShowBrushPreview,
|
||||
setShouldShowCanvasDebugInfo,
|
||||
setShouldShowCheckboardTransparency,
|
||||
setShouldShowGrid,
|
||||
setShouldShowIntermediates,
|
||||
setShouldShowStagingImage,
|
||||
|
@ -123,21 +123,11 @@ export interface CanvasState {
|
||||
brushColor: RgbaColor;
|
||||
brushSize: number;
|
||||
colorPickerColor: RgbaColor;
|
||||
cursorPosition: Vector2d | null;
|
||||
futureLayerStates: CanvasLayerState[];
|
||||
isDrawing: boolean;
|
||||
isMaskEnabled: boolean;
|
||||
isMouseOverBoundingBox: boolean;
|
||||
isMoveBoundingBoxKeyHeld: boolean;
|
||||
isMoveStageKeyHeld: boolean;
|
||||
isMovingBoundingBox: boolean;
|
||||
isMovingStage: boolean;
|
||||
isTransformingBoundingBox: boolean;
|
||||
layer: CanvasLayer;
|
||||
layerState: CanvasLayerState;
|
||||
maskColor: RgbaColor;
|
||||
maxHistory: number;
|
||||
minimumStageScale: number;
|
||||
pastLayerStates: CanvasLayerState[];
|
||||
scaledBoundingBoxDimensions: Dimensions;
|
||||
shouldAntialias: boolean;
|
||||
@ -148,10 +138,7 @@ export interface CanvasState {
|
||||
shouldPreserveMaskedArea: boolean;
|
||||
shouldRestrictStrokesToBox: boolean;
|
||||
shouldShowBoundingBox: boolean;
|
||||
shouldShowBrush: boolean;
|
||||
shouldShowBrushPreview: boolean;
|
||||
shouldShowCanvasDebugInfo: boolean;
|
||||
shouldShowCheckboardTransparency: boolean;
|
||||
shouldShowGrid: boolean;
|
||||
shouldShowIntermediates: boolean;
|
||||
shouldShowStagingImage: boolean;
|
||||
|
Loading…
Reference in New Issue
Block a user