Adds hotkeys and refactors sharing of konva instances

Adds hotkeys to canvas. As part of this change, the access to konva instance objects was refactored:

Previously closure'd refs were used to indirectly get access to the konva instances outside of react components.

Now, a  getter and setter function are used to provide access directly to the konva objects.
This commit is contained in:
psychedelicious 2022-11-18 15:08:09 +11:00 committed by blessedcoolant
parent e28599cadb
commit aa96a457b6
11 changed files with 312 additions and 125 deletions

View File

@ -5,10 +5,13 @@ import { SystemState } from 'features/system/systemSlice';
import { stringToSeedWeightsArray } from './seedWeightPairs'; import { stringToSeedWeightsArray } from './seedWeightPairs';
import randomInt from './randomInt'; import randomInt from './randomInt';
import { InvokeTabName } from 'features/tabs/InvokeTabs'; import { InvokeTabName } from 'features/tabs/InvokeTabs';
import { CanvasState, isCanvasMaskLine } from 'features/canvas/store/canvasTypes'; import {
CanvasState,
isCanvasMaskLine,
} from 'features/canvas/store/canvasTypes';
import generateMask from 'features/canvas/util/generateMask'; import generateMask from 'features/canvas/util/generateMask';
import { canvasImageLayerRef } from 'features/canvas/components/IAICanvas';
import openBase64ImageInTab from './openBase64ImageInTab'; import openBase64ImageInTab from './openBase64ImageInTab';
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
export type FrontendToBackendParametersConfig = { export type FrontendToBackendParametersConfig = {
generationMode: InvokeTabName; generationMode: InvokeTabName;
@ -25,6 +28,8 @@ export type FrontendToBackendParametersConfig = {
export const frontendToBackendParameters = ( export const frontendToBackendParameters = (
config: FrontendToBackendParametersConfig config: FrontendToBackendParametersConfig
): { [key: string]: any } => { ): { [key: string]: any } => {
const canvasBaseLayer = getCanvasBaseLayer();
const { const {
generationMode, generationMode,
optionsState, optionsState,
@ -106,7 +111,7 @@ export const frontendToBackendParameters = (
} }
// inpainting exclusive parameters // inpainting exclusive parameters
if (generationMode === 'unifiedCanvas' && canvasImageLayerRef.current) { if (generationMode === 'unifiedCanvas' && canvasBaseLayer) {
const { const {
layerState: { objects }, layerState: { objects },
boundingBoxCoordinates, boundingBoxCoordinates,
@ -143,16 +148,16 @@ export const frontendToBackendParameters = (
generationParameters.bounding_box = boundingBox; generationParameters.bounding_box = boundingBox;
const tempScale = canvasImageLayerRef.current.scale(); const tempScale = canvasBaseLayer.scale();
canvasImageLayerRef.current.scale({ canvasBaseLayer.scale({
x: 1 / stageScale, x: 1 / stageScale,
y: 1 / stageScale, y: 1 / stageScale,
}); });
const absPos = canvasImageLayerRef.current.getAbsolutePosition(); const absPos = canvasBaseLayer.getAbsolutePosition();
const imageDataURL = canvasImageLayerRef.current.toDataURL({ const imageDataURL = canvasBaseLayer.toDataURL({
x: boundingBox.x + absPos.x, x: boundingBox.x + absPos.x,
y: boundingBox.y + absPos.y, y: boundingBox.y + absPos.y,
width: boundingBox.width, width: boundingBox.width,
@ -166,7 +171,7 @@ export const frontendToBackendParameters = (
]); ]);
} }
canvasImageLayerRef.current.scale(tempScale); canvasBaseLayer.scale(tempScale);
generationParameters.init_img = imageDataURL; generationParameters.init_img = imageDataURL;

View File

@ -1,7 +1,6 @@
import { MutableRefObject, useRef } from 'react'; import { useCallback, useRef } from 'react';
import Konva from 'konva'; import Konva from 'konva';
import { Layer, Stage } from 'react-konva'; import { Layer, Stage } from 'react-konva';
import { Stage as StageType } from 'konva/lib/Stage';
import { useAppSelector } from 'app/store'; import { useAppSelector } from 'app/store';
import { import {
canvasSelector, canvasSelector,
@ -28,6 +27,10 @@ import IAICanvasIntermediateImage from './IAICanvasIntermediateImage';
import IAICanvasStatusText from './IAICanvasStatusText'; import IAICanvasStatusText from './IAICanvasStatusText';
import IAICanvasStagingArea from './IAICanvasStagingArea'; import IAICanvasStagingArea from './IAICanvasStagingArea';
import IAICanvasStagingAreaToolbar from './IAICanvasStagingAreaToolbar'; import IAICanvasStagingAreaToolbar from './IAICanvasStagingAreaToolbar';
import {
setCanvasBaseLayer,
setCanvasStage,
} from '../util/konvaInstanceProvider';
const selector = createSelector( const selector = createSelector(
[canvasSelector, isStagingSelector], [canvasSelector, isStagingSelector],
@ -84,10 +87,6 @@ const selector = createSelector(
} }
); );
// Use a closure allow other components to use these things... not ideal...
export let stageRef: MutableRefObject<StageType | null>;
export let canvasImageLayerRef: MutableRefObject<Konva.Layer | null>;
const IAICanvas = () => { const IAICanvas = () => {
const { const {
isMaskEnabled, isMaskEnabled,
@ -104,9 +103,18 @@ const IAICanvas = () => {
} = useAppSelector(selector); } = useAppSelector(selector);
useCanvasHotkeys(); useCanvasHotkeys();
// set the closure'd refs const stageRef = useRef<Konva.Stage | null>(null);
stageRef = useRef<StageType>(null); const canvasBaseLayerRef = useRef<Konva.Layer | null>(null);
canvasImageLayerRef = useRef<Konva.Layer>(null);
const canvasStageRefCallback = useCallback((el: Konva.Stage) => {
setCanvasStage(el as Konva.Stage);
stageRef.current = el;
}, []);
const canvasBaseLayerRefCallback = useCallback((el: Konva.Layer) => {
setCanvasBaseLayer(el as Konva.Layer);
canvasBaseLayerRef.current = el;
}, []);
const lastCursorPositionRef = useRef<Vector2d>({ x: 0, y: 0 }); const lastCursorPositionRef = useRef<Vector2d>({ x: 0, y: 0 });
@ -131,7 +139,7 @@ const IAICanvas = () => {
<div className="inpainting-canvas-wrapper"> <div className="inpainting-canvas-wrapper">
<Stage <Stage
tabIndex={-1} tabIndex={-1}
ref={stageRef} ref={canvasStageRefCallback}
className={'inpainting-canvas-stage'} className={'inpainting-canvas-stage'}
style={{ style={{
...(stageCursor ? { cursor: stageCursor } : {}), ...(stageCursor ? { cursor: stageCursor } : {}),
@ -160,7 +168,7 @@ const IAICanvas = () => {
<Layer <Layer
id={'base'} id={'base'}
ref={canvasImageLayerRef} ref={canvasBaseLayerRefCallback}
listening={false} listening={false}
imageSmoothingEnabled={false} imageSmoothingEnabled={false}
> >

View File

@ -1,5 +1,9 @@
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { setBrushColor, setBrushSize, setTool } from 'features/canvas/store/canvasSlice'; import {
setBrushColor,
setBrushSize,
setTool,
} from 'features/canvas/store/canvasSlice';
import { useAppDispatch, useAppSelector } from 'app/store'; import { useAppDispatch, useAppSelector } from 'app/store';
import _ from 'lodash'; import _ from 'lodash';
import IAIIconButton from 'common/components/IAIIconButton'; import IAIIconButton from 'common/components/IAIIconButton';
@ -8,7 +12,11 @@ import IAIPopover from 'common/components/IAIPopover';
import IAIColorPicker from 'common/components/IAIColorPicker'; import IAIColorPicker from 'common/components/IAIColorPicker';
import IAISlider from 'common/components/IAISlider'; import IAISlider from 'common/components/IAISlider';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { canvasSelector, isStagingSelector } from 'features/canvas/store/canvasSelectors'; import {
canvasSelector,
isStagingSelector,
} from 'features/canvas/store/canvasSelectors';
import { useHotkeys } from 'react-hotkeys-hook';
export const selector = createSelector( export const selector = createSelector(
[canvasSelector, isStagingSelector], [canvasSelector, isStagingSelector],
@ -33,6 +41,44 @@ const IAICanvasBrushButtonPopover = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { tool, brushColor, brushSize, isStaging } = useAppSelector(selector); const { tool, brushColor, brushSize, isStaging } = useAppSelector(selector);
useHotkeys(
['b'],
() => {
handleSelectBrushTool();
},
{
enabled: () => true,
preventDefault: true,
},
[]
);
useHotkeys(
['['],
() => {
dispatch(setBrushSize(Math.max(brushSize - 5, 5)));
},
{
enabled: () => true,
preventDefault: true,
},
[brushSize]
);
useHotkeys(
[']'],
() => {
dispatch(setBrushSize(Math.min(brushSize + 5, 500)));
},
{
enabled: () => true,
preventDefault: true,
},
[brushSize]
);
const handleSelectBrushTool = () => dispatch(setTool('brush'));
return ( return (
<IAIPopover <IAIPopover
trigger="hover" trigger="hover"
@ -42,7 +88,7 @@ const IAICanvasBrushButtonPopover = () => {
tooltip="Brush (B)" tooltip="Brush (B)"
icon={<FaPaintBrush />} icon={<FaPaintBrush />}
data-selected={tool === 'brush' && !isStaging} data-selected={tool === 'brush' && !isStaging}
onClick={() => dispatch(setTool('brush'))} onClick={handleSelectBrushTool}
isDisabled={isStaging} isDisabled={isStaging}
/> />
} }

View File

@ -1,8 +1,5 @@
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { import { setEraserSize, setTool } from 'features/canvas/store/canvasSlice';
setEraserSize,
setTool,
} from 'features/canvas/store/canvasSlice';
import { useAppDispatch, useAppSelector } from 'app/store'; import { useAppDispatch, useAppSelector } from 'app/store';
import _ from 'lodash'; import _ from 'lodash';
import IAIIconButton from 'common/components/IAIIconButton'; import IAIIconButton from 'common/components/IAIIconButton';
@ -11,7 +8,10 @@ import IAIPopover from 'common/components/IAIPopover';
import IAISlider from 'common/components/IAISlider'; import IAISlider from 'common/components/IAISlider';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { canvasSelector, isStagingSelector } from 'features/canvas/store/canvasSelectors'; import {
canvasSelector,
isStagingSelector,
} from 'features/canvas/store/canvasSelectors';
export const selector = createSelector( export const selector = createSelector(
[canvasSelector, isStagingSelector], [canvasSelector, isStagingSelector],
@ -37,17 +37,41 @@ const IAICanvasEraserButtonPopover = () => {
const handleSelectEraserTool = () => dispatch(setTool('eraser')); const handleSelectEraserTool = () => dispatch(setTool('eraser'));
useHotkeys( useHotkeys(
'e', ['e'],
(e: KeyboardEvent) => { () => {
e.preventDefault();
handleSelectEraserTool(); handleSelectEraserTool();
}, },
{ {
enabled: true, enabled: () => true,
preventDefault: true,
}, },
[tool] [tool]
); );
useHotkeys(
['['],
() => {
dispatch(setEraserSize(Math.max(eraserSize - 5, 5)));
},
{
enabled: () => true,
preventDefault: true,
},
[eraserSize]
);
useHotkeys(
[']'],
() => {
dispatch(setEraserSize(Math.min(eraserSize + 5, 500)));
},
{
enabled: () => true,
preventDefault: true,
},
[eraserSize]
);
return ( return (
<IAIPopover <IAIPopover
trigger="hover" trigger="hover"

View File

@ -16,6 +16,7 @@ import IAICheckbox from 'common/components/IAICheckbox';
import IAIColorPicker from 'common/components/IAIColorPicker'; import IAIColorPicker from 'common/components/IAIColorPicker';
import IAIButton from 'common/components/IAIButton'; import IAIButton from 'common/components/IAIButton';
import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { useHotkeys } from 'react-hotkeys-hook';
export const selector = createSelector( export const selector = createSelector(
[canvasSelector], [canvasSelector],
@ -41,6 +42,22 @@ const IAICanvasMaskButtonPopover = () => {
const { layer, maskColor, isMaskEnabled, shouldPreserveMaskedArea } = const { layer, maskColor, isMaskEnabled, shouldPreserveMaskedArea } =
useAppSelector(selector); useAppSelector(selector);
useHotkeys(
['q'],
() => {
handleToggleMaskLayer();
},
{
enabled: () => true,
preventDefault: true,
},
[layer]
);
const handleToggleMaskLayer = () => {
dispatch(setLayer(layer === 'mask' ? 'base' : 'mask'));
};
return ( return (
<IAIPopover <IAIPopover
trigger="hover" trigger="hover"
@ -49,7 +66,7 @@ const IAICanvasMaskButtonPopover = () => {
aria-label="Select Mask Layer" aria-label="Select Mask Layer"
tooltip="Select Mask Layer" tooltip="Select Mask Layer"
data-alert={layer === 'mask'} data-alert={layer === 'mask'}
onClick={() => dispatch(setLayer(layer === 'mask' ? 'base' : 'mask'))} onClick={handleToggleMaskLayer}
icon={<FaMask />} icon={<FaMask />}
/> />
} }

View File

@ -1,15 +1,12 @@
import { ButtonGroup } from '@chakra-ui/react'; import { ButtonGroup } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { import {
resizeAndScaleCanvas,
resetCanvas, resetCanvas,
resetCanvasView, resetCanvasView,
setTool, setTool,
fitBoundingBoxToStage,
} from 'features/canvas/store/canvasSlice'; } from 'features/canvas/store/canvasSlice';
import { useAppDispatch, useAppSelector } from 'app/store'; import { useAppDispatch, useAppSelector } from 'app/store';
import _ from 'lodash'; import _ from 'lodash';
import { canvasImageLayerRef, stageRef } from '../IAICanvas';
import IAIIconButton from 'common/components/IAIIconButton'; import IAIIconButton from 'common/components/IAIIconButton';
import { import {
FaArrowsAlt, FaArrowsAlt,
@ -28,12 +25,15 @@ import IAICanvasEraserButtonPopover from './IAICanvasEraserButtonPopover';
import IAICanvasBrushButtonPopover from './IAICanvasBrushButtonPopover'; import IAICanvasBrushButtonPopover from './IAICanvasBrushButtonPopover';
import IAICanvasMaskButtonPopover from './IAICanvasMaskButtonPopover'; import IAICanvasMaskButtonPopover from './IAICanvasMaskButtonPopover';
import { mergeAndUploadCanvas } from 'features/canvas/util/mergeAndUploadCanvas'; import { mergeAndUploadCanvas } from 'features/canvas/util/mergeAndUploadCanvas';
import IAICheckbox from 'common/components/IAICheckbox';
import { ChangeEvent } from 'react';
import { import {
canvasSelector, canvasSelector,
isStagingSelector, isStagingSelector,
} from 'features/canvas/store/canvasSelectors'; } from 'features/canvas/store/canvasSelectors';
import { useHotkeys } from 'react-hotkeys-hook';
import {
getCanvasBaseLayer,
getCanvasStage,
} from 'features/canvas/util/konvaInstanceProvider';
export const selector = createSelector( export const selector = createSelector(
[canvasSelector, isStagingSelector], [canvasSelector, isStagingSelector],
@ -54,6 +54,138 @@ export const selector = createSelector(
const IAICanvasOutpaintingControls = () => { const IAICanvasOutpaintingControls = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { tool, isStaging } = useAppSelector(selector); const { tool, isStaging } = useAppSelector(selector);
const canvasBaseLayer = getCanvasBaseLayer();
useHotkeys(
['m'],
() => {
handleSelectMoveTool();
},
{
enabled: () => true,
preventDefault: true,
},
[]
);
useHotkeys(
['shift+r'],
() => {
handleResetCanvasView();
},
{
enabled: () => true,
preventDefault: true,
},
[canvasBaseLayer]
);
useHotkeys(
['shift+c'],
() => {
handleResetCanvas();
},
{
enabled: () => true,
preventDefault: true,
},
[canvasBaseLayer]
);
useHotkeys(
['shift+m'],
() => {
handleMergeVisible();
},
{
enabled: () => true,
preventDefault: true,
},
[canvasBaseLayer]
);
useHotkeys(
['shift+s'],
() => {
handleSaveToGallery();
},
{
enabled: () => true,
preventDefault: true,
},
[canvasBaseLayer]
);
useHotkeys(
['meta+c', 'ctrl+c'],
() => {
handleCopyImageToClipboard();
},
{
enabled: () => true,
preventDefault: true,
},
[canvasBaseLayer]
);
useHotkeys(
['shift+d'],
() => {
handleDownloadAsImage();
},
{
enabled: () => true,
preventDefault: true,
},
[canvasBaseLayer]
);
const handleSelectMoveTool = () => dispatch(setTool('move'));
const handleResetCanvasView = () => {
if (!canvasBaseLayer) return;
const clientRect = canvasBaseLayer.getClientRect({
skipTransform: true,
});
dispatch(
resetCanvasView({
contentRect: clientRect,
})
);
};
const handleResetCanvas = () => dispatch(resetCanvas());
const handleMergeVisible = () => {
dispatch(mergeAndUploadCanvas({}));
};
const handleSaveToGallery = () => {
dispatch(
mergeAndUploadCanvas({
cropVisible: true,
saveToGallery: true,
})
);
};
const handleCopyImageToClipboard = () => {
dispatch(
mergeAndUploadCanvas({
cropVisible: true,
copyAfterSaving: true,
})
);
};
const handleDownloadAsImage = () => {
dispatch(
mergeAndUploadCanvas({
cropVisible: true,
downloadAfterSaving: true,
})
);
};
return ( return (
<div className="inpainting-settings"> <div className="inpainting-settings">
@ -66,63 +198,33 @@ const IAICanvasOutpaintingControls = () => {
tooltip="Move (M)" tooltip="Move (M)"
icon={<FaArrowsAlt />} icon={<FaArrowsAlt />}
data-selected={tool === 'move' || isStaging} data-selected={tool === 'move' || isStaging}
onClick={() => dispatch(setTool('move'))} onClick={handleSelectMoveTool}
/> />
</ButtonGroup> </ButtonGroup>
<ButtonGroup isAttached> <ButtonGroup isAttached>
<IAIIconButton <IAIIconButton
aria-label="Merge Visible" aria-label="Merge Visible (Shift + M)"
tooltip="Merge Visible" tooltip="Merge Visible (Shift + M)"
icon={<FaLayerGroup />} icon={<FaLayerGroup />}
onClick={() => { onClick={handleMergeVisible}
dispatch(
mergeAndUploadCanvas({
canvasImageLayerRef,
})
);
}}
/> />
<IAIIconButton <IAIIconButton
aria-label="Save to Gallery" aria-label="Save to Gallery (Shift + S)"
tooltip="Save to Gallery" tooltip="Save to Gallery (Shift + S)"
icon={<FaSave />} icon={<FaSave />}
onClick={() => { onClick={handleSaveToGallery}
dispatch(
mergeAndUploadCanvas({
canvasImageLayerRef,
cropVisible: true,
saveToGallery: true,
})
);
}}
/> />
<IAIIconButton <IAIIconButton
aria-label="Copy Selection" aria-label="Copy to Clipboard (Cmd/Ctrl + C)"
tooltip="Copy Selection" tooltip="Copy to Clipboard (Cmd/Ctrl + C)"
icon={<FaCopy />} icon={<FaCopy />}
onClick={() => { onClick={handleCopyImageToClipboard}
dispatch(
mergeAndUploadCanvas({
canvasImageLayerRef,
cropVisible: true,
copyAfterSaving: true,
})
);
}}
/> />
<IAIIconButton <IAIIconButton
aria-label="Download Selection" aria-label="Download as Image (Shift + D)"
tooltip="Download Selection" tooltip="Download as Image (Shift + D)"
icon={<FaDownload />} icon={<FaDownload />}
onClick={() => { onClick={handleDownloadAsImage}
dispatch(
mergeAndUploadCanvas({
canvasImageLayerRef,
cropVisible: true,
downloadAfterSaving: true,
})
);
}}
/> />
</ButtonGroup> </ButtonGroup>
<ButtonGroup isAttached> <ButtonGroup isAttached>
@ -142,23 +244,13 @@ const IAICanvasOutpaintingControls = () => {
aria-label="Reset Canvas View" aria-label="Reset Canvas View"
tooltip="Reset Canvas View" tooltip="Reset Canvas View"
icon={<FaCrosshairs />} icon={<FaCrosshairs />}
onClick={() => { onClick={handleResetCanvasView}
if (!stageRef.current || !canvasImageLayerRef.current) return;
const clientRect = canvasImageLayerRef.current.getClientRect({
skipTransform: true,
});
dispatch(
resetCanvasView({
contentRect: clientRect,
})
);
}}
/> />
<IAIIconButton <IAIIconButton
aria-label="Reset Canvas" aria-label="Reset Canvas"
tooltip="Reset Canvas" tooltip="Reset Canvas"
icon={<FaTrash />} icon={<FaTrash />}
onClick={() => dispatch(resetCanvas())} onClick={handleResetCanvas}
/> />
</ButtonGroup> </ButtonGroup>
</div> </div>

View File

@ -9,9 +9,9 @@ import {
} from 'features/canvas/store/canvasSlice'; } from 'features/canvas/store/canvasSlice';
import { useAppDispatch, useAppSelector } from 'app/store'; import { useAppDispatch, useAppSelector } from 'app/store';
import { useRef } from 'react'; import { useRef } from 'react';
import { stageRef } from '../components/IAICanvas';
import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { CanvasTool } from '../store/canvasTypes'; import { CanvasTool } from '../store/canvasTypes';
import { getCanvasStage } from '../util/konvaInstanceProvider';
const selector = createSelector( const selector = createSelector(
[canvasSelector, activeTabNameSelector], [canvasSelector, activeTabNameSelector],
@ -44,6 +44,9 @@ const useInpaintingCanvasHotkeys = () => {
useAppSelector(selector); useAppSelector(selector);
const previousToolRef = useRef<CanvasTool | null>(null); const previousToolRef = useRef<CanvasTool | null>(null);
const canvasStage = getCanvasStage();
// Toggle lock bounding box // Toggle lock bounding box
useHotkeys( useHotkeys(
'shift+w', 'shift+w',
@ -72,7 +75,7 @@ const useInpaintingCanvasHotkeys = () => {
(e: KeyboardEvent) => { (e: KeyboardEvent) => {
if (e.repeat) return; if (e.repeat) return;
stageRef.current?.container().focus(); canvasStage?.container().focus();
if (tool !== 'move') { if (tool !== 'move') {
previousToolRef.current = tool; previousToolRef.current = tool;

View File

@ -0,0 +1,16 @@
import Konva from 'konva';
let canvasBaseLayer: Konva.Layer | null = null;
let canvasStage: Konva.Stage | null = null;
export const setCanvasBaseLayer = (layer: Konva.Layer) => {
canvasBaseLayer = layer;
};
export const getCanvasBaseLayer = () => canvasBaseLayer;
export const setCanvasStage = (stage: Konva.Stage) => {
canvasStage = stage;
};
export const getCanvasStage = () => canvasStage;

View File

@ -1,18 +1,16 @@
import { createAsyncThunk } from '@reduxjs/toolkit'; import { createAsyncThunk } from '@reduxjs/toolkit';
import { RootState } from 'app/store'; import { RootState } from 'app/store';
import Konva from 'konva';
import { MutableRefObject } from 'react';
import * as InvokeAI from 'app/invokeai'; import * as InvokeAI from 'app/invokeai';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import layerToDataURL from './layerToDataURL'; import layerToDataURL from './layerToDataURL';
import downloadFile from './downloadFile'; import downloadFile from './downloadFile';
import copyImage from './copyImage'; import copyImage from './copyImage';
import { getCanvasBaseLayer } from './konvaInstanceProvider';
export const mergeAndUploadCanvas = createAsyncThunk( export const mergeAndUploadCanvas = createAsyncThunk(
'canvas/mergeAndUploadCanvas', 'canvas/mergeAndUploadCanvas',
async ( async (
args: { args: {
canvasImageLayerRef: MutableRefObject<Konva.Layer | null>;
cropVisible?: boolean; cropVisible?: boolean;
saveToGallery?: boolean; saveToGallery?: boolean;
downloadAfterSaving?: boolean; downloadAfterSaving?: boolean;
@ -20,13 +18,8 @@ export const mergeAndUploadCanvas = createAsyncThunk(
}, },
thunkAPI thunkAPI
) => { ) => {
const { const { saveToGallery, downloadAfterSaving, cropVisible, copyAfterSaving } =
canvasImageLayerRef, args;
saveToGallery,
downloadAfterSaving,
cropVisible,
copyAfterSaving,
} = args;
const { getState } = thunkAPI; const { getState } = thunkAPI;
@ -34,10 +27,12 @@ export const mergeAndUploadCanvas = createAsyncThunk(
const stageScale = state.canvas.stageScale; const stageScale = state.canvas.stageScale;
if (!canvasImageLayerRef.current) return; const canvasBaseLayer = getCanvasBaseLayer();
if (!canvasBaseLayer) return;
const { dataURL, boundingBox: originalBoundingBox } = layerToDataURL( const { dataURL, boundingBox: originalBoundingBox } = layerToDataURL(
canvasImageLayerRef.current, canvasBaseLayer,
stageScale stageScale
); );

View File

@ -246,20 +246,6 @@ export default function ImageGallery() {
[galleryImageMinimumWidth] [galleryImageMinimumWidth]
); );
useHotkeys(
'shift+r',
() => {
dispatch(setGalleryImageMinimumWidth(64));
toast({
title: `Reset Gallery Image Size`,
status: 'success',
duration: 2500,
isClosable: true,
});
},
[galleryImageMinimumWidth]
);
// set gallery scroll position // set gallery scroll position
useEffect(() => { useEffect(() => {
if (!galleryContainerRef.current) return; if (!galleryContainerRef.current) return;

View File

@ -135,11 +135,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
desc: 'Decreases gallery thumbnails size', desc: 'Decreases gallery thumbnails size',
hotkey: 'Shift+Down', hotkey: 'Shift+Down',
}, },
{
title: 'Reset Gallery Image Size',
desc: 'Resets image gallery size',
hotkey: 'Shift+R',
},
]; ];
const unifiedCanvasHotkeys = [ const unifiedCanvasHotkeys = [