mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Fixes inpainting + code cleanup
This commit is contained in:
parent
00385240e7
commit
e21e901fa2
@ -698,22 +698,24 @@ class InvokeAIWebServer:
|
|||||||
|
|
||||||
So we need to convert each into a PIL Image.
|
So we need to convert each into a PIL Image.
|
||||||
"""
|
"""
|
||||||
init_img_url = generation_parameters["init_img"]
|
|
||||||
truncated_outpaint_mask_b64 = generation_parameters["init_mask"][:64]
|
truncated_outpaint_mask_b64 = generation_parameters["init_mask"][:64]
|
||||||
|
|
||||||
init_img_url = generation_parameters["init_img"]
|
init_img_url = generation_parameters["init_img"]
|
||||||
|
|
||||||
|
init_img_url = generation_parameters["init_img"]
|
||||||
|
|
||||||
init_img_path = self.get_image_path_from_url(init_img_url)
|
init_img_path = self.get_image_path_from_url(init_img_url)
|
||||||
|
|
||||||
original_image = Image.open(init_img_path)
|
original_image = Image.open(init_img_path)
|
||||||
|
|
||||||
rgba_image = original_image.convert("RGBA")
|
rgba_image = original_image.convert("RGBA")
|
||||||
|
|
||||||
# copy a region from it which we will inpaint
|
# copy a region from it which we will inpaint
|
||||||
cropped_init_image = copy_image_from_bounding_box(
|
cropped_init_image = copy_image_from_bounding_box(
|
||||||
rgba_image, **generation_parameters["bounding_box"]
|
rgba_image, **generation_parameters["bounding_box"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
original_bounding_box = generation_parameters["bounding_box"].copy()
|
||||||
|
|
||||||
generation_parameters["init_img"] = cropped_init_image
|
generation_parameters["init_img"] = cropped_init_image
|
||||||
|
|
||||||
# Convert mask dataURL to an image and convert to greyscale
|
# Convert mask dataURL to an image and convert to greyscale
|
||||||
|
515
frontend/dist/assets/index.a06633cf.js
vendored
515
frontend/dist/assets/index.a06633cf.js
vendored
File diff suppressed because one or more lines are too long
593
frontend/dist/assets/index.ece4fb83.js
vendored
Normal file
593
frontend/dist/assets/index.ece4fb83.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
frontend/dist/index.html
vendored
4
frontend/dist/index.html
vendored
@ -7,6 +7,7 @@
|
|||||||
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
||||||
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
|
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
|
||||||
<<<<<<< refs/remotes/upstream/development
|
<<<<<<< refs/remotes/upstream/development
|
||||||
|
<<<<<<< refs/remotes/upstream/development
|
||||||
<<<<<<< refs/remotes/upstream/development
|
<<<<<<< refs/remotes/upstream/development
|
||||||
<script type="module" crossorigin src="./assets/index.a8ba2a6c.js"></script>
|
<script type="module" crossorigin src="./assets/index.a8ba2a6c.js"></script>
|
||||||
<link rel="stylesheet" href="./assets/index.40a72c80.css">
|
<link rel="stylesheet" href="./assets/index.40a72c80.css">
|
||||||
@ -15,6 +16,9 @@
|
|||||||
=======
|
=======
|
||||||
<script type="module" crossorigin src="./assets/index.a06633cf.js"></script>
|
<script type="module" crossorigin src="./assets/index.a06633cf.js"></script>
|
||||||
>>>>>>> Builds fresh bundle
|
>>>>>>> Builds fresh bundle
|
||||||
|
=======
|
||||||
|
<script type="module" crossorigin src="./assets/index.ece4fb83.js"></script>
|
||||||
|
>>>>>>> Fixes inpainting + code cleanup
|
||||||
<link rel="stylesheet" href="./assets/index.a44a1287.css">
|
<link rel="stylesheet" href="./assets/index.a44a1287.css">
|
||||||
>>>>>>> Builds fresh bundle
|
>>>>>>> Builds fresh bundle
|
||||||
</head>
|
</head>
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import { useEffect } from 'react';
|
|
||||||
import ProgressBar from 'features/system/ProgressBar';
|
import ProgressBar from 'features/system/ProgressBar';
|
||||||
import SiteHeader from 'features/system/SiteHeader';
|
import SiteHeader from 'features/system/SiteHeader';
|
||||||
import Console from 'features/system/Console';
|
import Console from 'features/system/Console';
|
||||||
import { useAppDispatch } from './store';
|
|
||||||
import { requestSystemConfig } from './socketio/actions';
|
|
||||||
import { keepGUIAlive } from './utils';
|
import { keepGUIAlive } from './utils';
|
||||||
import InvokeTabs from 'features/tabs/InvokeTabs';
|
import InvokeTabs from 'features/tabs/InvokeTabs';
|
||||||
import ImageUploader from 'common/components/ImageUploader';
|
import ImageUploader from 'common/components/ImageUploader';
|
||||||
@ -80,8 +77,6 @@ const appSelector = createSelector(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const { shouldShowGalleryButton, shouldShowOptionsPanelButton } =
|
const { shouldShowGalleryButton, shouldShowOptionsPanelButton } =
|
||||||
useAppSelector(appSelector);
|
useAppSelector(appSelector);
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import {
|
|||||||
modelChangeRequested,
|
modelChangeRequested,
|
||||||
setIsProcessing,
|
setIsProcessing,
|
||||||
} from 'features/system/systemSlice';
|
} from 'features/system/systemSlice';
|
||||||
import { inpaintingImageElementRef } from 'features/canvas/IAICanvas';
|
|
||||||
import { InvokeTabName } from 'features/tabs/InvokeTabs';
|
import { InvokeTabName } from 'features/tabs/InvokeTabs';
|
||||||
import * as InvokeAI from 'app/invokeai';
|
import * as InvokeAI from 'app/invokeai';
|
||||||
import { RootState } from 'app/store';
|
import { RootState } from 'app/store';
|
||||||
@ -57,9 +56,9 @@ const makeSocketIOEmitters = (
|
|||||||
|
|
||||||
if (['inpainting', 'outpainting'].includes(generationMode)) {
|
if (['inpainting', 'outpainting'].includes(generationMode)) {
|
||||||
const baseCanvasImage = baseCanvasImageSelector(getState());
|
const baseCanvasImage = baseCanvasImageSelector(getState());
|
||||||
const imageUrl = baseCanvasImage?.url;
|
const imageUrl = baseCanvasImage?.image.url;
|
||||||
|
|
||||||
if (!inpaintingImageElementRef.current || !imageUrl) {
|
if (!imageUrl) {
|
||||||
dispatch(
|
dispatch(
|
||||||
addLogEntry({
|
addLogEntry({
|
||||||
timestamp: dateFormat(new Date(), 'isoDateTime'),
|
timestamp: dateFormat(new Date(), 'isoDateTime'),
|
||||||
@ -72,9 +71,6 @@ const makeSocketIOEmitters = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
frontendToBackendParametersConfig.imageToProcessUrl = imageUrl;
|
frontendToBackendParametersConfig.imageToProcessUrl = imageUrl;
|
||||||
|
|
||||||
// frontendToBackendParametersConfig.maskImageElement =
|
|
||||||
// inpaintingImageElementRef.current;
|
|
||||||
} else if (!['txt2img', 'img2img'].includes(generationMode)) {
|
} else if (!['txt2img', 'img2img'].includes(generationMode)) {
|
||||||
if (!galleryState.currentImage?.url) return;
|
if (!galleryState.currentImage?.url) return;
|
||||||
|
|
||||||
|
@ -32,12 +32,14 @@ import {
|
|||||||
setInitialImage,
|
setInitialImage,
|
||||||
setMaskPath,
|
setMaskPath,
|
||||||
} from 'features/options/optionsSlice';
|
} from 'features/options/optionsSlice';
|
||||||
import { requestImages, requestNewImages, requestSystemConfig } from './actions';
|
import {
|
||||||
|
requestImages,
|
||||||
|
requestNewImages,
|
||||||
|
requestSystemConfig,
|
||||||
|
} from './actions';
|
||||||
import {
|
import {
|
||||||
addImageToOutpaintingSesion,
|
addImageToOutpaintingSesion,
|
||||||
clearImageToInpaint,
|
|
||||||
setImageToInpaint,
|
setImageToInpaint,
|
||||||
setImageToOutpaint,
|
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
import { tabMap } from 'features/tabs/InvokeTabs';
|
import { tabMap } from 'features/tabs/InvokeTabs';
|
||||||
|
|
||||||
@ -312,16 +314,11 @@ const makeSocketIOListeners = (
|
|||||||
|
|
||||||
// remove references to image in options
|
// remove references to image in options
|
||||||
const { initialImage, maskPath } = getState().options;
|
const { initialImage, maskPath } = getState().options;
|
||||||
const { inpainting, outpainting } = getState().canvas;
|
|
||||||
|
|
||||||
if (initialImage?.url === url || initialImage === url) {
|
if (initialImage?.url === url || initialImage === url) {
|
||||||
dispatch(clearInitialImage());
|
dispatch(clearInitialImage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (imageToInpaint?.url === url) {
|
|
||||||
// dispatch(clearImageToInpaint());
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (maskPath === url) {
|
if (maskPath === url) {
|
||||||
dispatch(setMaskPath(''));
|
dispatch(setMaskPath(''));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Heading } from '@chakra-ui/react';
|
import { Heading } from '@chakra-ui/react';
|
||||||
import { KeyboardEvent } from 'react';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
|
||||||
type ImageUploadOverlayProps = {
|
type ImageUploadOverlayProps = {
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
// lib
|
// lib
|
||||||
import { MutableRefObject, useEffect, useRef, useState } from 'react';
|
import { MutableRefObject, useRef } from 'react';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
import { Layer, Stage } from 'react-konva';
|
import { Layer, Stage } from 'react-konva';
|
||||||
import { Image as KonvaImage } from 'react-konva';
|
|
||||||
import { Stage as StageType } from 'konva/lib/Stage';
|
import { Stage as StageType } from 'konva/lib/Stage';
|
||||||
|
|
||||||
// app
|
// app
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
import { useAppSelector } from 'app/store';
|
||||||
import {
|
import {
|
||||||
baseCanvasImageSelector,
|
baseCanvasImageSelector,
|
||||||
clearImageToInpaint,
|
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
outpaintingCanvasSelector,
|
outpaintingCanvasSelector,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
@ -18,8 +16,7 @@ import {
|
|||||||
import IAICanvasMaskLines from './IAICanvasMaskLines';
|
import IAICanvasMaskLines from './IAICanvasMaskLines';
|
||||||
import IAICanvasBrushPreview from './IAICanvasBrushPreview';
|
import IAICanvasBrushPreview from './IAICanvasBrushPreview';
|
||||||
import { Vector2d } from 'konva/lib/types';
|
import { Vector2d } from 'konva/lib/types';
|
||||||
import IAICanvasBoundingBoxPreview from './IAICanvasBoundingBoxPreview';
|
import IAICanvasBoundingBox from './IAICanvasBoundingBox';
|
||||||
import { useToast } from '@chakra-ui/react';
|
|
||||||
import useCanvasHotkeys from './hooks/useCanvasHotkeys';
|
import useCanvasHotkeys from './hooks/useCanvasHotkeys';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
@ -32,7 +29,7 @@ import useCanvasMouseMove from './hooks/useCanvasMouseMove';
|
|||||||
import useCanvasMouseEnter from './hooks/useCanvasMouseEnter';
|
import useCanvasMouseEnter from './hooks/useCanvasMouseEnter';
|
||||||
import useCanvasMouseOut from './hooks/useCanvasMouseOut';
|
import useCanvasMouseOut from './hooks/useCanvasMouseOut';
|
||||||
import useCanvasDragMove from './hooks/useCanvasDragMove';
|
import useCanvasDragMove from './hooks/useCanvasDragMove';
|
||||||
import IAICanvasOutpaintingObjects from './IAICanvasOutpaintingObjects';
|
import IAICanvasObjectRenderer from './IAICanvasObjectRenderer';
|
||||||
import IAICanvasGrid from './IAICanvasGrid';
|
import IAICanvasGrid from './IAICanvasGrid';
|
||||||
import IAICanvasIntermediateImage from './IAICanvasIntermediateImage';
|
import IAICanvasIntermediateImage from './IAICanvasIntermediateImage';
|
||||||
import IAICanvasStatusText from './IAICanvasStatusText';
|
import IAICanvasStatusText from './IAICanvasStatusText';
|
||||||
@ -46,18 +43,14 @@ const canvasSelector = createSelector(
|
|||||||
],
|
],
|
||||||
(currentCanvas, outpaintingCanvas, baseCanvasImage, activeTabName) => {
|
(currentCanvas, outpaintingCanvas, baseCanvasImage, activeTabName) => {
|
||||||
const {
|
const {
|
||||||
shouldInvertMask,
|
|
||||||
isMaskEnabled,
|
isMaskEnabled,
|
||||||
shouldShowCheckboardTransparency,
|
|
||||||
stageScale,
|
stageScale,
|
||||||
shouldShowBoundingBox,
|
shouldShowBoundingBox,
|
||||||
shouldLockBoundingBox,
|
|
||||||
isTransformingBoundingBox,
|
isTransformingBoundingBox,
|
||||||
isMouseOverBoundingBox,
|
isMouseOverBoundingBox,
|
||||||
isMovingBoundingBox,
|
isMovingBoundingBox,
|
||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageCoordinates,
|
stageCoordinates,
|
||||||
isMoveStageKeyHeld,
|
|
||||||
tool,
|
tool,
|
||||||
isMovingStage,
|
isMovingStage,
|
||||||
} = currentCanvas;
|
} = currentCanvas;
|
||||||
@ -71,7 +64,7 @@ const canvasSelector = createSelector(
|
|||||||
stageCursor = undefined;
|
stageCursor = undefined;
|
||||||
} else if (isMouseOverBoundingBox) {
|
} else if (isMouseOverBoundingBox) {
|
||||||
stageCursor = 'move';
|
stageCursor = 'move';
|
||||||
} else {
|
} else if (activeTabName === 'outpainting') {
|
||||||
if (isMovingStage) {
|
if (isMovingStage) {
|
||||||
stageCursor = 'grabbing';
|
stageCursor = 'grabbing';
|
||||||
} else {
|
} else {
|
||||||
@ -83,22 +76,15 @@ const canvasSelector = createSelector(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
shouldInvertMask,
|
|
||||||
isMaskEnabled,
|
|
||||||
shouldShowCheckboardTransparency,
|
|
||||||
stageScale,
|
|
||||||
shouldShowBoundingBox,
|
|
||||||
shouldLockBoundingBox,
|
|
||||||
shouldShowGrid,
|
|
||||||
isTransformingBoundingBox,
|
|
||||||
isModifyingBoundingBox: isTransformingBoundingBox || isMovingBoundingBox,
|
|
||||||
stageCursor,
|
|
||||||
isMouseOverBoundingBox,
|
|
||||||
stageDimensions,
|
|
||||||
stageCoordinates,
|
|
||||||
isMoveStageKeyHeld,
|
|
||||||
activeTabName,
|
activeTabName,
|
||||||
baseCanvasImage,
|
isMaskEnabled,
|
||||||
|
isModifyingBoundingBox: isTransformingBoundingBox || isMovingBoundingBox,
|
||||||
|
shouldShowBoundingBox,
|
||||||
|
shouldShowGrid,
|
||||||
|
stageCoordinates,
|
||||||
|
stageCursor,
|
||||||
|
stageDimensions,
|
||||||
|
stageScale,
|
||||||
tool,
|
tool,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -112,45 +98,32 @@ const canvasSelector = createSelector(
|
|||||||
// Use a closure allow other components to use these things... not ideal...
|
// Use a closure allow other components to use these things... not ideal...
|
||||||
export let stageRef: MutableRefObject<StageType | null>;
|
export let stageRef: MutableRefObject<StageType | null>;
|
||||||
export let canvasImageLayerRef: MutableRefObject<Konva.Layer | null>;
|
export let canvasImageLayerRef: MutableRefObject<Konva.Layer | null>;
|
||||||
export let inpaintingImageElementRef: MutableRefObject<HTMLImageElement | null>;
|
|
||||||
|
|
||||||
const IAICanvas = () => {
|
const IAICanvas = () => {
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
shouldInvertMask,
|
activeTabName,
|
||||||
isMaskEnabled,
|
isMaskEnabled,
|
||||||
shouldShowCheckboardTransparency,
|
|
||||||
stageScale,
|
|
||||||
shouldShowBoundingBox,
|
|
||||||
isModifyingBoundingBox,
|
isModifyingBoundingBox,
|
||||||
|
shouldShowBoundingBox,
|
||||||
|
shouldShowGrid,
|
||||||
|
stageCoordinates,
|
||||||
stageCursor,
|
stageCursor,
|
||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageCoordinates,
|
stageScale,
|
||||||
shouldShowGrid,
|
|
||||||
activeTabName,
|
|
||||||
baseCanvasImage,
|
|
||||||
tool,
|
tool,
|
||||||
} = useAppSelector(canvasSelector);
|
} = useAppSelector(canvasSelector);
|
||||||
|
|
||||||
useCanvasHotkeys();
|
useCanvasHotkeys();
|
||||||
|
|
||||||
const toast = useToast();
|
|
||||||
// set the closure'd refs
|
// set the closure'd refs
|
||||||
stageRef = useRef<StageType>(null);
|
stageRef = useRef<StageType>(null);
|
||||||
canvasImageLayerRef = useRef<Konva.Layer>(null);
|
canvasImageLayerRef = useRef<Konva.Layer>(null);
|
||||||
inpaintingImageElementRef = useRef<HTMLImageElement>(null);
|
|
||||||
|
|
||||||
const lastCursorPositionRef = useRef<Vector2d>({ x: 0, y: 0 });
|
const lastCursorPositionRef = useRef<Vector2d>({ x: 0, y: 0 });
|
||||||
|
|
||||||
// Use refs for values that do not affect rendering, other values in redux
|
// Use refs for values that do not affect rendering, other values in redux
|
||||||
const didMouseMoveRef = useRef<boolean>(false);
|
const didMouseMoveRef = useRef<boolean>(false);
|
||||||
|
|
||||||
// Load the image into this
|
|
||||||
const [canvasBgImage, setCanvasBgImage] = useState<HTMLImageElement | null>(
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleWheel = useCanvasWheel(stageRef);
|
const handleWheel = useCanvasWheel(stageRef);
|
||||||
const handleMouseDown = useCanvasMouseDown(stageRef);
|
const handleMouseDown = useCanvasMouseDown(stageRef);
|
||||||
const handleMouseUp = useCanvasMouseUp(stageRef, didMouseMoveRef);
|
const handleMouseUp = useCanvasMouseUp(stageRef, didMouseMoveRef);
|
||||||
@ -164,29 +137,6 @@ const IAICanvas = () => {
|
|||||||
const { handleDragStart, handleDragMove, handleDragEnd } =
|
const { handleDragStart, handleDragMove, handleDragEnd } =
|
||||||
useCanvasDragMove();
|
useCanvasDragMove();
|
||||||
|
|
||||||
// Load the image and set the options panel width & height
|
|
||||||
useEffect(() => {
|
|
||||||
if (baseCanvasImage) {
|
|
||||||
const image = new Image();
|
|
||||||
image.onload = () => {
|
|
||||||
inpaintingImageElementRef.current = image;
|
|
||||||
setCanvasBgImage(image);
|
|
||||||
};
|
|
||||||
image.onerror = () => {
|
|
||||||
toast({
|
|
||||||
title: 'Unable to Load Image',
|
|
||||||
description: `Image ${baseCanvasImage.url} failed to load`,
|
|
||||||
status: 'error',
|
|
||||||
isClosable: true,
|
|
||||||
});
|
|
||||||
dispatch(clearImageToInpaint());
|
|
||||||
};
|
|
||||||
image.src = baseCanvasImage.url;
|
|
||||||
} else {
|
|
||||||
setCanvasBgImage(null);
|
|
||||||
}
|
|
||||||
}, [baseCanvasImage, dispatch, stageScale, toast]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inpainting-canvas-container">
|
<div className="inpainting-canvas-container">
|
||||||
<div className="inpainting-canvas-wrapper">
|
<div className="inpainting-canvas-wrapper">
|
||||||
@ -209,36 +159,31 @@ const IAICanvas = () => {
|
|||||||
onDragMove={handleDragMove}
|
onDragMove={handleDragMove}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
onWheel={handleWheel}
|
onWheel={handleWheel}
|
||||||
listening={
|
listening={tool === 'move' && !isModifyingBoundingBox}
|
||||||
tool === 'move' &&
|
|
||||||
!isModifyingBoundingBox &&
|
|
||||||
activeTabName === 'outpainting'
|
|
||||||
}
|
|
||||||
draggable={
|
draggable={
|
||||||
tool === 'move' &&
|
tool === 'move' &&
|
||||||
!isModifyingBoundingBox &&
|
!isModifyingBoundingBox &&
|
||||||
activeTabName === 'outpainting'
|
activeTabName === 'outpainting'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Layer visible={shouldShowGrid}>
|
<Layer id={'grid'} visible={shouldShowGrid}>
|
||||||
<IAICanvasGrid />
|
<IAICanvasGrid />
|
||||||
</Layer>
|
</Layer>
|
||||||
|
|
||||||
<Layer
|
<Layer
|
||||||
id={'image-layer'}
|
id={'image'}
|
||||||
ref={canvasImageLayerRef}
|
ref={canvasImageLayerRef}
|
||||||
listening={false}
|
listening={false}
|
||||||
imageSmoothingEnabled={false}
|
imageSmoothingEnabled={false}
|
||||||
>
|
>
|
||||||
<IAICanvasOutpaintingObjects />
|
<IAICanvasObjectRenderer />
|
||||||
<IAICanvasIntermediateImage />
|
<IAICanvasIntermediateImage />
|
||||||
</Layer>
|
</Layer>
|
||||||
<Layer id={'mask-layer'} visible={isMaskEnabled} listening={false}>
|
<Layer id={'mask'} visible={isMaskEnabled} listening={false}>
|
||||||
<IAICanvasMaskLines visible={true} listening={false} />
|
<IAICanvasMaskLines visible={true} listening={false} />
|
||||||
|
|
||||||
<IAICanvasMaskCompositer listening={false} />
|
<IAICanvasMaskCompositer listening={false} />
|
||||||
|
|
||||||
{canvasBgImage && (
|
{/* {canvasBgImage && (
|
||||||
<>
|
<>
|
||||||
<KonvaImage
|
<KonvaImage
|
||||||
image={canvasBgImage}
|
image={canvasBgImage}
|
||||||
@ -256,10 +201,10 @@ const IAICanvas = () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)} */}
|
||||||
</Layer>
|
</Layer>
|
||||||
<Layer id={'preview-layer'}>
|
<Layer id={'tool'}>
|
||||||
<IAICanvasBoundingBoxPreview visible={shouldShowBoundingBox} />
|
<IAICanvasBoundingBox visible={shouldShowBoundingBox} />
|
||||||
<IAICanvasBrushPreview
|
<IAICanvasBrushPreview
|
||||||
visible={tool !== 'move'}
|
visible={tool !== 'move'}
|
||||||
listening={false}
|
listening={false}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
import { Context } from 'konva/lib/Context';
|
|
||||||
import { KonvaEventObject } from 'konva/lib/Node';
|
import { KonvaEventObject } from 'konva/lib/Node';
|
||||||
import { Box } from 'konva/lib/shapes/Transformer';
|
import { Box } from 'konva/lib/shapes/Transformer';
|
||||||
import { Vector2d } from 'konva/lib/types';
|
import { Vector2d } from 'konva/lib/types';
|
||||||
@ -33,7 +32,6 @@ const boundingBoxPreviewSelector = createSelector(
|
|||||||
boundingBoxDimensions,
|
boundingBoxDimensions,
|
||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageScale,
|
stageScale,
|
||||||
shouldLockBoundingBox,
|
|
||||||
isDrawing,
|
isDrawing,
|
||||||
isTransformingBoundingBox,
|
isTransformingBoundingBox,
|
||||||
isMovingBoundingBox,
|
isMovingBoundingBox,
|
||||||
@ -52,7 +50,6 @@ const boundingBoxPreviewSelector = createSelector(
|
|||||||
shouldDarkenOutsideBoundingBox,
|
shouldDarkenOutsideBoundingBox,
|
||||||
isMovingBoundingBox,
|
isMovingBoundingBox,
|
||||||
isTransformingBoundingBox,
|
isTransformingBoundingBox,
|
||||||
shouldLockBoundingBox,
|
|
||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageScale,
|
stageScale,
|
||||||
baseCanvasImage,
|
baseCanvasImage,
|
||||||
@ -72,9 +69,7 @@ const boundingBoxPreviewSelector = createSelector(
|
|||||||
|
|
||||||
type IAICanvasBoundingBoxPreviewProps = GroupConfig;
|
type IAICanvasBoundingBoxPreviewProps = GroupConfig;
|
||||||
|
|
||||||
const IAICanvasBoundingBoxPreview = (
|
const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
||||||
props: IAICanvasBoundingBoxPreviewProps
|
|
||||||
) => {
|
|
||||||
const { ...rest } = props;
|
const { ...rest } = props;
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
@ -86,7 +81,6 @@ const IAICanvasBoundingBoxPreview = (
|
|||||||
shouldDarkenOutsideBoundingBox,
|
shouldDarkenOutsideBoundingBox,
|
||||||
isMovingBoundingBox,
|
isMovingBoundingBox,
|
||||||
isTransformingBoundingBox,
|
isTransformingBoundingBox,
|
||||||
shouldLockBoundingBox,
|
|
||||||
stageCoordinates,
|
stageCoordinates,
|
||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageScale,
|
stageScale,
|
||||||
@ -104,7 +98,7 @@ const IAICanvasBoundingBoxPreview = (
|
|||||||
if (!transformerRef.current || !shapeRef.current) return;
|
if (!transformerRef.current || !shapeRef.current) return;
|
||||||
transformerRef.current.nodes([shapeRef.current]);
|
transformerRef.current.nodes([shapeRef.current]);
|
||||||
transformerRef.current.getLayer()?.batchDraw();
|
transformerRef.current.getLayer()?.batchDraw();
|
||||||
}, [shouldLockBoundingBox]);
|
}, []);
|
||||||
|
|
||||||
const scaledStep = 64 * stageScale;
|
const scaledStep = 64 * stageScale;
|
||||||
|
|
||||||
@ -264,7 +258,6 @@ const IAICanvasBoundingBoxPreview = (
|
|||||||
[scaledStep]
|
[scaledStep]
|
||||||
);
|
);
|
||||||
|
|
||||||
// OK
|
|
||||||
const boundBoxFunc = useCallback(
|
const boundBoxFunc = useCallback(
|
||||||
(oldBoundBox: Box, newBoundBox: Box) => {
|
(oldBoundBox: Box, newBoundBox: Box) => {
|
||||||
/**
|
/**
|
||||||
@ -341,10 +334,10 @@ const IAICanvasBoundingBoxPreview = (
|
|||||||
dragBoundFunc={
|
dragBoundFunc={
|
||||||
activeTabName === 'inpainting' ? dragBoundFunc : undefined
|
activeTabName === 'inpainting' ? dragBoundFunc : undefined
|
||||||
}
|
}
|
||||||
|
listening={!isDrawing && tool === 'move'}
|
||||||
draggable={true}
|
draggable={true}
|
||||||
fillEnabled={tool === 'move'}
|
fillEnabled={tool === 'move'}
|
||||||
height={boundingBoxDimensions.height}
|
height={boundingBoxDimensions.height}
|
||||||
listening={!isDrawing && tool === 'move'}
|
|
||||||
onDragEnd={handleEndedModifying}
|
onDragEnd={handleEndedModifying}
|
||||||
onDragMove={handleOnDragMove}
|
onDragMove={handleOnDragMove}
|
||||||
onMouseDown={handleStartedMoving}
|
onMouseDown={handleStartedMoving}
|
||||||
@ -387,4 +380,4 @@ const IAICanvasBoundingBoxPreview = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default IAICanvasBoundingBoxPreview;
|
export default IAICanvasBoundingBox;
|
@ -15,7 +15,6 @@ 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 IAINumberInput from 'common/components/IAINumberInput';
|
|
||||||
|
|
||||||
export const selector = createSelector(
|
export const selector = createSelector(
|
||||||
[currentCanvasSelector, outpaintingCanvasSelector, activeTabNameSelector],
|
[currentCanvasSelector, outpaintingCanvasSelector, activeTabNameSelector],
|
||||||
|
@ -2,7 +2,7 @@ import IAICanvasBrushControl from './IAICanvasControls/IAICanvasBrushControl';
|
|||||||
import IAICanvasEraserControl from './IAICanvasControls/IAICanvasEraserControl';
|
import IAICanvasEraserControl from './IAICanvasControls/IAICanvasEraserControl';
|
||||||
import IAICanvasUndoControl from './IAICanvasControls/IAICanvasUndoButton';
|
import IAICanvasUndoControl from './IAICanvasControls/IAICanvasUndoButton';
|
||||||
import IAICanvasRedoControl from './IAICanvasControls/IAICanvasRedoButton';
|
import IAICanvasRedoControl from './IAICanvasControls/IAICanvasRedoButton';
|
||||||
import { Button, ButtonGroup } from '@chakra-ui/react';
|
import { ButtonGroup } from '@chakra-ui/react';
|
||||||
import IAICanvasMaskClear from './IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskClear';
|
import IAICanvasMaskClear from './IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskClear';
|
||||||
import IAICanvasMaskVisibilityControl from './IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskVisibilityControl';
|
import IAICanvasMaskVisibilityControl from './IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskVisibilityControl';
|
||||||
import IAICanvasMaskInvertControl from './IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskInvertControl';
|
import IAICanvasMaskInvertControl from './IAICanvasControls/IAICanvasMaskControls/IAICanvasMaskInvertControl';
|
||||||
@ -11,8 +11,6 @@ import IAICanvasShowHideBoundingBoxControl from './IAICanvasControls/IAICanvasSh
|
|||||||
import ImageUploaderIconButton from 'common/components/ImageUploaderIconButton';
|
import ImageUploaderIconButton from 'common/components/ImageUploaderIconButton';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import {
|
import {
|
||||||
currentCanvasSelector,
|
|
||||||
GenericCanvasState,
|
|
||||||
outpaintingCanvasSelector,
|
outpaintingCanvasSelector,
|
||||||
OutpaintingCanvasState,
|
OutpaintingCanvasState,
|
||||||
uploadOutpaintingMergedImage,
|
uploadOutpaintingMergedImage,
|
||||||
@ -23,7 +21,6 @@ import { OptionsState } from 'features/options/optionsSlice';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import IAICanvasImageEraserControl from './IAICanvasControls/IAICanvasImageEraserControl';
|
import IAICanvasImageEraserControl from './IAICanvasControls/IAICanvasImageEraserControl';
|
||||||
import { canvasImageLayerRef } from './IAICanvas';
|
import { canvasImageLayerRef } from './IAICanvas';
|
||||||
import { uploadImage } from 'app/socketio/actions';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import { FaSave } from 'react-icons/fa';
|
import { FaSave } from 'react-icons/fa';
|
||||||
|
|
||||||
@ -56,12 +53,7 @@ export const canvasControlsSelector = createSelector(
|
|||||||
|
|
||||||
const IAICanvasControls = () => {
|
const IAICanvasControls = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const {
|
const { activeTabName } = useAppSelector(canvasControlsSelector);
|
||||||
activeTabName,
|
|
||||||
boundingBoxCoordinates,
|
|
||||||
boundingBoxDimensions,
|
|
||||||
stageScale,
|
|
||||||
} = useAppSelector(canvasControlsSelector);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inpainting-settings">
|
<div className="inpainting-settings">
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store';
|
import { useAppSelector } from 'app/store';
|
||||||
import { RectConfig } from 'konva/lib/shapes/Rect';
|
import { RectConfig } from 'konva/lib/shapes/Rect';
|
||||||
import _ from 'lodash';
|
|
||||||
import { Rect } from 'react-konva';
|
import { Rect } from 'react-konva';
|
||||||
import {
|
import {
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
@ -24,7 +23,6 @@ export const canvasMaskCompositerSelector = createSelector(
|
|||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageScale,
|
stageScale,
|
||||||
maskColorString: rgbaColorToString(maskColor),
|
maskColorString: rgbaColorToString(maskColor),
|
||||||
maskOpacity: maskColor.a,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -116,13 +114,8 @@ const getColoredSVG = (color: string) => {
|
|||||||
const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
|
const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
|
||||||
const { ...rest } = props;
|
const { ...rest } = props;
|
||||||
|
|
||||||
const {
|
const { maskColorString, stageCoordinates, stageDimensions, stageScale } =
|
||||||
maskColorString,
|
useAppSelector(canvasMaskCompositerSelector);
|
||||||
maskOpacity,
|
|
||||||
stageCoordinates,
|
|
||||||
stageDimensions,
|
|
||||||
stageScale,
|
|
||||||
} = useAppSelector(canvasMaskCompositerSelector);
|
|
||||||
|
|
||||||
const [fillPatternImage, setFillPatternImage] =
|
const [fillPatternImage, setFillPatternImage] =
|
||||||
useState<HTMLImageElement | null>(null);
|
useState<HTMLImageElement | null>(null);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { RootState, useAppSelector } from 'app/store';
|
import { useAppSelector } from 'app/store';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { Group, Line } from 'react-konva';
|
import { Group, Line } from 'react-konva';
|
||||||
import {
|
import {
|
||||||
CanvasState,
|
currentCanvasSelector,
|
||||||
isCanvasBaseImage,
|
isCanvasBaseImage,
|
||||||
isCanvasBaseLine,
|
isCanvasBaseLine,
|
||||||
} from './canvasSlice';
|
} from './canvasSlice';
|
||||||
@ -11,14 +11,9 @@ import IAICanvasImage from './IAICanvasImage';
|
|||||||
import { rgbaColorToString } from './util/colorToString';
|
import { rgbaColorToString } from './util/colorToString';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[(state: RootState) => state.canvas],
|
[currentCanvasSelector],
|
||||||
(canvas: CanvasState) => {
|
(currentCanvas) => {
|
||||||
return {
|
return currentCanvas.objects;
|
||||||
objects:
|
|
||||||
canvas.currentCanvas === 'outpainting'
|
|
||||||
? canvas.outpainting.objects
|
|
||||||
: undefined,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
memoizeOptions: {
|
memoizeOptions: {
|
||||||
@ -27,8 +22,8 @@ const selector = createSelector(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const IAICanvasOutpaintingObjects = () => {
|
const IAICanvasObjectRenderer = () => {
|
||||||
const { objects } = useAppSelector(selector);
|
const objects = useAppSelector(selector);
|
||||||
|
|
||||||
if (!objects) return null;
|
if (!objects) return null;
|
||||||
|
|
||||||
@ -62,4 +57,4 @@ const IAICanvasOutpaintingObjects = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default IAICanvasOutpaintingObjects;
|
export default IAICanvasObjectRenderer;
|
@ -5,14 +5,10 @@ import { activeTabNameSelector } from 'features/options/optionsSelectors';
|
|||||||
import {
|
import {
|
||||||
baseCanvasImageSelector,
|
baseCanvasImageSelector,
|
||||||
CanvasState,
|
CanvasState,
|
||||||
currentCanvasSelector,
|
|
||||||
GenericCanvasState,
|
|
||||||
setStageDimensions,
|
setStageDimensions,
|
||||||
setStageScale,
|
setStageScale,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import * as InvokeAI from 'app/invokeai';
|
|
||||||
import { first } from 'lodash';
|
|
||||||
|
|
||||||
const canvasResizerSelector = createSelector(
|
const canvasResizerSelector = createSelector(
|
||||||
(state: RootState) => state.canvas,
|
(state: RootState) => state.canvas,
|
||||||
@ -39,13 +35,12 @@ const IAICanvasResizer = () => {
|
|||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
if (!ref.current || !baseCanvasImage) return;
|
if (!ref.current || !baseCanvasImage) return;
|
||||||
|
const { width: imageWidth, height: imageHeight } = baseCanvasImage.image;
|
||||||
const width = ref.current.clientWidth;
|
const { clientWidth, clientHeight } = ref.current;
|
||||||
const height = ref.current.clientHeight;
|
|
||||||
|
|
||||||
const scale = Math.min(
|
const scale = Math.min(
|
||||||
1,
|
1,
|
||||||
Math.min(width / baseCanvasImage.width, height / baseCanvasImage.height)
|
Math.min(clientWidth / imageWidth, clientHeight / imageHeight)
|
||||||
);
|
);
|
||||||
|
|
||||||
dispatch(setStageScale(scale));
|
dispatch(setStageScale(scale));
|
||||||
@ -53,15 +48,15 @@ const IAICanvasResizer = () => {
|
|||||||
if (activeTabName === 'inpainting') {
|
if (activeTabName === 'inpainting') {
|
||||||
dispatch(
|
dispatch(
|
||||||
setStageDimensions({
|
setStageDimensions({
|
||||||
width: Math.floor(baseCanvasImage.width * scale),
|
width: Math.floor(imageWidth * scale),
|
||||||
height: Math.floor(baseCanvasImage.height * scale),
|
height: Math.floor(imageHeight * scale),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else if (activeTabName === 'outpainting') {
|
} else if (activeTabName === 'outpainting') {
|
||||||
dispatch(
|
dispatch(
|
||||||
setStageDimensions({
|
setStageDimensions({
|
||||||
width: Math.floor(width),
|
width: Math.floor(clientWidth),
|
||||||
height: Math.floor(height),
|
height: Math.floor(clientHeight),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import * as InvokeAI from 'app/invokeai';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
|
import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
import { RootState } from 'app/store';
|
import { RootState } from 'app/store';
|
||||||
import { activeTabNameSelector } from 'features/options/optionsSelectors';
|
|
||||||
import { MutableRefObject } from 'react';
|
import { MutableRefObject } from 'react';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
|
|
||||||
@ -137,7 +136,7 @@ const initialGenericCanvasState: GenericCanvasState = {
|
|||||||
tool: 'brush',
|
tool: 'brush',
|
||||||
brushColor: { r: 90, g: 90, b: 255, a: 1 },
|
brushColor: { r: 90, g: 90, b: 255, a: 1 },
|
||||||
brushSize: 50,
|
brushSize: 50,
|
||||||
maskColor: { r: 255, g: 90, b: 90, a: 0.5 },
|
maskColor: { r: 255, g: 90, b: 90, a: 1 },
|
||||||
eraserSize: 50,
|
eraserSize: 50,
|
||||||
stageDimensions: { width: 0, height: 0 },
|
stageDimensions: { width: 0, height: 0 },
|
||||||
stageCoordinates: { x: 0, y: 0 },
|
stageCoordinates: { x: 0, y: 0 },
|
||||||
@ -351,7 +350,16 @@ export const canvasSlice = createSlice({
|
|||||||
state.inpainting.boundingBoxDimensions = newDimensions;
|
state.inpainting.boundingBoxDimensions = newDimensions;
|
||||||
state.inpainting.boundingBoxCoordinates = newCoordinates;
|
state.inpainting.boundingBoxCoordinates = newCoordinates;
|
||||||
|
|
||||||
state.inpainting.imageToInpaint = action.payload;
|
// state.inpainting.imageToInpaint = action.payload;
|
||||||
|
state.inpainting.objects = [
|
||||||
|
{
|
||||||
|
kind: 'image',
|
||||||
|
layer: 'base',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
image: action.payload,
|
||||||
|
},
|
||||||
|
];
|
||||||
state.doesCanvasNeedScaling = true;
|
state.doesCanvasNeedScaling = true;
|
||||||
},
|
},
|
||||||
setStageDimensions: (state, action: PayloadAction<Dimensions>) => {
|
setStageDimensions: (state, action: PayloadAction<Dimensions>) => {
|
||||||
@ -567,19 +575,19 @@ export const canvasSlice = createSlice({
|
|||||||
lastLine.points.push(...action.payload);
|
lastLine.points.push(...action.payload);
|
||||||
},
|
},
|
||||||
undo: (state) => {
|
undo: (state) => {
|
||||||
if (state.outpainting.objects.length === 0) return;
|
if (state[state.currentCanvas].objects.length === 0) return;
|
||||||
|
|
||||||
const newObjects = state.outpainting.pastObjects.pop();
|
const newObjects = state[state.currentCanvas].pastObjects.pop();
|
||||||
if (!newObjects) return;
|
if (!newObjects) return;
|
||||||
state.outpainting.futureObjects.unshift(state.outpainting.objects);
|
state[state.currentCanvas].futureObjects.unshift(state[state.currentCanvas].objects);
|
||||||
state.outpainting.objects = newObjects;
|
state[state.currentCanvas].objects = newObjects;
|
||||||
},
|
},
|
||||||
redo: (state) => {
|
redo: (state) => {
|
||||||
if (state.outpainting.futureObjects.length === 0) return;
|
if (state[state.currentCanvas].futureObjects.length === 0) return;
|
||||||
const newObjects = state.outpainting.futureObjects.shift();
|
const newObjects = state[state.currentCanvas].futureObjects.shift();
|
||||||
if (!newObjects) return;
|
if (!newObjects) return;
|
||||||
state.outpainting.pastObjects.push(state.outpainting.objects);
|
state[state.currentCanvas].pastObjects.push(state[state.currentCanvas].objects);
|
||||||
state.outpainting.objects = newObjects;
|
state[state.currentCanvas].objects = newObjects;
|
||||||
},
|
},
|
||||||
setShouldShowGrid: (state, action: PayloadAction<boolean>) => {
|
setShouldShowGrid: (state, action: PayloadAction<boolean>) => {
|
||||||
state.outpainting.shouldShowGrid = action.payload;
|
state.outpainting.shouldShowGrid = action.payload;
|
||||||
@ -748,17 +756,8 @@ export const inpaintingCanvasSelector = (
|
|||||||
): InpaintingCanvasState => state.canvas.inpainting;
|
): InpaintingCanvasState => state.canvas.inpainting;
|
||||||
|
|
||||||
export const baseCanvasImageSelector = createSelector(
|
export const baseCanvasImageSelector = createSelector(
|
||||||
[(state: RootState) => state.canvas, activeTabNameSelector],
|
[currentCanvasSelector],
|
||||||
(canvas: CanvasState, activeTabName) => {
|
(currentCanvas) => {
|
||||||
if (activeTabName === 'inpainting') {
|
return currentCanvas.objects.find(isCanvasBaseImage);
|
||||||
return canvas.inpainting.imageToInpaint;
|
|
||||||
} else if (activeTabName === 'outpainting') {
|
|
||||||
const firstImageObject = canvas.outpainting.objects.find(
|
|
||||||
(obj) => obj.kind === 'image'
|
|
||||||
);
|
|
||||||
if (firstImageObject && firstImageObject.kind === 'image') {
|
|
||||||
return firstImageObject.image;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -2,26 +2,20 @@ import { createSelector } from '@reduxjs/toolkit';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { activeTabNameSelector } from 'features/options/optionsSelectors';
|
import { activeTabNameSelector } from 'features/options/optionsSelectors';
|
||||||
import { OptionsState } from 'features/options/optionsSlice';
|
|
||||||
import {
|
import {
|
||||||
CanvasTool,
|
CanvasTool,
|
||||||
setShouldShowBoundingBox,
|
setShouldShowBoundingBox,
|
||||||
setTool,
|
setTool,
|
||||||
toggleShouldLockBoundingBox,
|
toggleShouldLockBoundingBox,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import { currentCanvasSelector, GenericCanvasState } from '../canvasSlice';
|
import { currentCanvasSelector } from '../canvasSlice';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
|
||||||
const inpaintingCanvasHotkeysSelector = createSelector(
|
const inpaintingCanvasHotkeysSelector = createSelector(
|
||||||
[
|
[currentCanvasSelector, activeTabNameSelector],
|
||||||
(state: RootState) => state.options,
|
(currentCanvas, activeTabName) => {
|
||||||
currentCanvasSelector,
|
|
||||||
activeTabNameSelector,
|
|
||||||
],
|
|
||||||
(options: OptionsState, currentCanvas: GenericCanvasState, activeTabName) => {
|
|
||||||
const {
|
const {
|
||||||
isMaskEnabled,
|
|
||||||
cursorPosition,
|
cursorPosition,
|
||||||
shouldLockBoundingBox,
|
shouldLockBoundingBox,
|
||||||
shouldShowBoundingBox,
|
shouldShowBoundingBox,
|
||||||
@ -30,7 +24,6 @@ const inpaintingCanvasHotkeysSelector = createSelector(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
activeTabName,
|
activeTabName,
|
||||||
isMaskEnabled,
|
|
||||||
isCursorOnCanvas: Boolean(cursorPosition),
|
isCursorOnCanvas: Boolean(cursorPosition),
|
||||||
shouldLockBoundingBox,
|
shouldLockBoundingBox,
|
||||||
shouldShowBoundingBox,
|
shouldShowBoundingBox,
|
||||||
@ -46,8 +39,9 @@ const inpaintingCanvasHotkeysSelector = createSelector(
|
|||||||
|
|
||||||
const useInpaintingCanvasHotkeys = () => {
|
const useInpaintingCanvasHotkeys = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { isMaskEnabled, activeTabName, shouldShowBoundingBox, tool } =
|
const { activeTabName, shouldShowBoundingBox, tool } = useAppSelector(
|
||||||
useAppSelector(inpaintingCanvasHotkeysSelector);
|
inpaintingCanvasHotkeysSelector
|
||||||
|
);
|
||||||
|
|
||||||
const previousToolRef = useRef<CanvasTool | null>(null);
|
const previousToolRef = useRef<CanvasTool | null>(null);
|
||||||
// Toggle lock bounding box
|
// Toggle lock bounding box
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { useAppDispatch } from 'app/store';
|
import { useAppDispatch } from 'app/store';
|
||||||
import _ from 'lodash';
|
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { setCursorPosition, setIsDrawing } from '../canvasSlice';
|
import { setCursorPosition, setIsDrawing } from '../canvasSlice';
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import IAIIconButton from 'common/components/IAIIconButton';
|
|||||||
import UpscaleOptions from 'features/options/AdvancedOptions/Upscale/UpscaleOptions';
|
import UpscaleOptions from 'features/options/AdvancedOptions/Upscale/UpscaleOptions';
|
||||||
import FaceRestoreOptions from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions';
|
import FaceRestoreOptions from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { ButtonGroup, Link, useClipboard, useToast } from '@chakra-ui/react';
|
import { ButtonGroup, Link, useToast } from '@chakra-ui/react';
|
||||||
import {
|
import {
|
||||||
FaAsterisk,
|
FaAsterisk,
|
||||||
FaCode,
|
FaCode,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IconButton, Image, Spinner } from '@chakra-ui/react';
|
import { IconButton, Image } from '@chakra-ui/react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
|
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
|
||||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import IAICheckbox from 'common/components/IAICheckbox';
|
import IAICheckbox from 'common/components/IAICheckbox';
|
||||||
import {
|
import {
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
|
|
||||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import {
|
import {
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
GenericCanvasState,
|
|
||||||
// InpaintingState,
|
|
||||||
setBoundingBoxDimensions,
|
setBoundingBoxDimensions,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
|
|
||||||
@ -15,7 +13,7 @@ import _ from 'lodash';
|
|||||||
|
|
||||||
const boundingBoxDimensionsSelector = createSelector(
|
const boundingBoxDimensionsSelector = createSelector(
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
(currentCanvas: GenericCanvasState) => {
|
(currentCanvas) => {
|
||||||
const { stageDimensions, boundingBoxDimensions, shouldLockBoundingBox } =
|
const { stageDimensions, boundingBoxDimensions, shouldLockBoundingBox } =
|
||||||
currentCanvas;
|
currentCanvas;
|
||||||
return {
|
return {
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import IAICheckbox from 'common/components/IAICheckbox';
|
import IAICheckbox from 'common/components/IAICheckbox';
|
||||||
import {
|
import {
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
GenericCanvasState,
|
|
||||||
setShouldLockBoundingBox,
|
setShouldLockBoundingBox,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
const boundingBoxLockSelector = createSelector(
|
const boundingBoxLockSelector = createSelector(
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
(currentCanvas: GenericCanvasState) => currentCanvas.shouldLockBoundingBox
|
(currentCanvas) => currentCanvas.shouldLockBoundingBox
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function BoundingBoxLock() {
|
export default function BoundingBoxLock() {
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { BiHide, BiShow } from 'react-icons/bi';
|
import { BiHide, BiShow } from 'react-icons/bi';
|
||||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import {
|
import {
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
GenericCanvasState,
|
|
||||||
setShouldShowBoundingBox,
|
setShouldShowBoundingBox,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
const boundingBoxVisibilitySelector = createSelector(
|
const boundingBoxVisibilitySelector = createSelector(
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
(currentCanvas: GenericCanvasState) => currentCanvas.shouldShowBoundingBox
|
(currentCanvas) => currentCanvas.shouldShowBoundingBox
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function BoundingBoxVisibility() {
|
export default function BoundingBoxVisibility() {
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import React, { ChangeEvent } from 'react';
|
import React, { ChangeEvent } from 'react';
|
||||||
import {
|
import { useAppDispatch, useAppSelector } from '../../../../app/store';
|
||||||
RootState,
|
|
||||||
useAppDispatch,
|
|
||||||
useAppSelector,
|
|
||||||
} from '../../../../app/store';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import IAISwitch from '../../../../common/components/IAISwitch';
|
import IAISwitch from '../../../../common/components/IAISwitch';
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Image, useToast } from '@chakra-ui/react';
|
import { Image, useToast } from '@chakra-ui/react';
|
||||||
import { SyntheticEvent } from 'react';
|
|
||||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import ImageUploaderIconButton from 'common/components/ImageUploaderIconButton';
|
import ImageUploaderIconButton from 'common/components/ImageUploaderIconButton';
|
||||||
import { clearInitialImage } from 'features/options/optionsSlice';
|
import { clearInitialImage } from 'features/options/optionsSlice';
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
// import IAICanvas from 'features/canvas/IAICanvas';
|
|
||||||
import IAICanvasControls from 'features/canvas/IAICanvasControls';
|
import IAICanvasControls from 'features/canvas/IAICanvasControls';
|
||||||
import IAICanvasResizer from 'features/canvas/IAICanvasResizer';
|
import IAICanvasResizer from 'features/canvas/IAICanvasResizer';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@ -9,23 +8,25 @@ import ImageUploadButton from 'common/components/ImageUploaderButton';
|
|||||||
import CurrentImageDisplay from 'features/gallery/CurrentImageDisplay';
|
import CurrentImageDisplay from 'features/gallery/CurrentImageDisplay';
|
||||||
import { OptionsState } from 'features/options/optionsSlice';
|
import { OptionsState } from 'features/options/optionsSlice';
|
||||||
import {
|
import {
|
||||||
|
baseCanvasImageSelector,
|
||||||
CanvasState,
|
CanvasState,
|
||||||
setDoesCanvasNeedScaling,
|
setDoesCanvasNeedScaling,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
import IAICanvas from 'features/canvas/IAICanvas';
|
import IAICanvas from 'features/canvas/IAICanvas';
|
||||||
|
|
||||||
const inpaintingDisplaySelector = createSelector(
|
const inpaintingDisplaySelector = createSelector(
|
||||||
[(state: RootState) => state.canvas, (state: RootState) => state.options],
|
[
|
||||||
(canvas: CanvasState, options: OptionsState) => {
|
baseCanvasImageSelector,
|
||||||
const {
|
(state: RootState) => state.canvas,
|
||||||
doesCanvasNeedScaling,
|
(state: RootState) => state.options,
|
||||||
inpainting: { imageToInpaint },
|
],
|
||||||
} = canvas;
|
(baseCanvasImage, canvas: CanvasState, options: OptionsState) => {
|
||||||
|
const { doesCanvasNeedScaling } = canvas;
|
||||||
const { showDualDisplay } = options;
|
const { showDualDisplay } = options;
|
||||||
return {
|
return {
|
||||||
doesCanvasNeedScaling,
|
doesCanvasNeedScaling,
|
||||||
showDualDisplay,
|
showDualDisplay,
|
||||||
imageToInpaint,
|
baseCanvasImage,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -37,7 +38,7 @@ const inpaintingDisplaySelector = createSelector(
|
|||||||
|
|
||||||
const InpaintingDisplay = () => {
|
const InpaintingDisplay = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { showDualDisplay, doesCanvasNeedScaling, imageToInpaint } =
|
const { showDualDisplay, doesCanvasNeedScaling, baseCanvasImage } =
|
||||||
useAppSelector(inpaintingDisplaySelector);
|
useAppSelector(inpaintingDisplaySelector);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@ -49,7 +50,7 @@ const InpaintingDisplay = () => {
|
|||||||
return () => window.removeEventListener('resize', resizeCallback);
|
return () => window.removeEventListener('resize', resizeCallback);
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const inpaintingComponent = imageToInpaint ? (
|
const inpaintingComponent = baseCanvasImage ? (
|
||||||
<div className="inpainting-main-area">
|
<div className="inpainting-main-area">
|
||||||
<IAICanvasControls />
|
<IAICanvasControls />
|
||||||
<div className="inpainting-canvas-area">
|
<div className="inpainting-canvas-area">
|
||||||
|
@ -4,7 +4,6 @@ import React, { ReactElement } from 'react';
|
|||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import NodesWIP from 'common/components/WorkInProgress/NodesWIP';
|
import NodesWIP from 'common/components/WorkInProgress/NodesWIP';
|
||||||
import OutpaintingWIP from 'common/components/WorkInProgress/OutpaintingWIP';
|
|
||||||
import { PostProcessingWIP } from 'common/components/WorkInProgress/PostProcessingWIP';
|
import { PostProcessingWIP } from 'common/components/WorkInProgress/PostProcessingWIP';
|
||||||
import ImageToImageIcon from 'common/icons/ImageToImageIcon';
|
import ImageToImageIcon from 'common/icons/ImageToImageIcon';
|
||||||
import InpaintIcon from 'common/icons/InpaintIcon';
|
import InpaintIcon from 'common/icons/InpaintIcon';
|
||||||
@ -19,13 +18,9 @@ import {
|
|||||||
} from 'features/options/optionsSlice';
|
} from 'features/options/optionsSlice';
|
||||||
import ImageToImageWorkarea from './ImageToImage';
|
import ImageToImageWorkarea from './ImageToImage';
|
||||||
import InpaintingWorkarea from './Inpainting/InpaintingWorkarea';
|
import InpaintingWorkarea from './Inpainting/InpaintingWorkarea';
|
||||||
// import { setDoesCanvasNeedScaling } from './Inpainting/inpaintingSlice';
|
|
||||||
import TextToImageWorkarea from './TextToImage';
|
import TextToImageWorkarea from './TextToImage';
|
||||||
import Lightbox from 'features/lightbox/Lightbox';
|
import Lightbox from 'features/lightbox/Lightbox';
|
||||||
import {
|
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
|
||||||
setCurrentCanvas,
|
|
||||||
setDoesCanvasNeedScaling,
|
|
||||||
} from 'features/canvas/canvasSlice';
|
|
||||||
import OutpaintingWorkarea from './Outpainting/OutpaintingWorkarea';
|
import OutpaintingWorkarea from './Outpainting/OutpaintingWorkarea';
|
||||||
import { setShouldShowGallery } from 'features/gallery/gallerySlice';
|
import { setShouldShowGallery } from 'features/gallery/gallerySlice';
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ const workareaSelector = createSelector(
|
|||||||
return {
|
return {
|
||||||
showDualDisplay,
|
showDualDisplay,
|
||||||
shouldPinOptionsPanel,
|
shouldPinOptionsPanel,
|
||||||
activeTabName,
|
|
||||||
isLightBoxOpen,
|
isLightBoxOpen,
|
||||||
shouldShowDualDisplayButton: ['inpainting'].includes(activeTabName),
|
shouldShowDualDisplayButton: ['inpainting'].includes(activeTabName),
|
||||||
};
|
};
|
||||||
@ -37,7 +36,6 @@ const InvokeWorkarea = (props: InvokeWorkareaProps) => {
|
|||||||
const { optionsPanel, children, styleClass } = props;
|
const { optionsPanel, children, styleClass } = props;
|
||||||
const {
|
const {
|
||||||
showDualDisplay,
|
showDualDisplay,
|
||||||
activeTabName,
|
|
||||||
isLightBoxOpen,
|
isLightBoxOpen,
|
||||||
shouldShowDualDisplayButton,
|
shouldShowDualDisplayButton,
|
||||||
} = useAppSelector(workareaSelector);
|
} = useAppSelector(workareaSelector);
|
||||||
|
@ -1,34 +1,26 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
// import IAICanvas from 'features/canvas/IAICanvas';
|
// import IAICanvas from 'features/canvas/IAICanvas';
|
||||||
import IAICanvasControls from 'features/canvas/IAICanvasControls';
|
|
||||||
import IAICanvasResizer from 'features/canvas/IAICanvasResizer';
|
import IAICanvasResizer from 'features/canvas/IAICanvasResizer';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useLayoutEffect } from 'react';
|
import { useLayoutEffect } from 'react';
|
||||||
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import ImageUploadButton from 'common/components/ImageUploaderButton';
|
import ImageUploadButton from 'common/components/ImageUploaderButton';
|
||||||
import CurrentImageDisplay from 'features/gallery/CurrentImageDisplay';
|
|
||||||
import { OptionsState } from 'features/options/optionsSlice';
|
|
||||||
import {
|
import {
|
||||||
CanvasState,
|
CanvasState,
|
||||||
currentCanvasSelector,
|
|
||||||
GenericCanvasState,
|
|
||||||
OutpaintingCanvasState,
|
|
||||||
setDoesCanvasNeedScaling,
|
setDoesCanvasNeedScaling,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
import IAICanvas from 'features/canvas/IAICanvas';
|
import IAICanvas from 'features/canvas/IAICanvas';
|
||||||
import IAICanvasOutpaintingControls from 'features/canvas/IAICanvasOutpaintingControls';
|
import IAICanvasOutpaintingControls from 'features/canvas/IAICanvasOutpaintingControls';
|
||||||
|
|
||||||
const outpaintingDisplaySelector = createSelector(
|
const outpaintingDisplaySelector = createSelector(
|
||||||
[(state: RootState) => state.canvas, (state: RootState) => state.options],
|
[(state: RootState) => state.canvas],
|
||||||
(canvas: CanvasState, options: OptionsState) => {
|
(canvas: CanvasState) => {
|
||||||
const {
|
const {
|
||||||
doesCanvasNeedScaling,
|
doesCanvasNeedScaling,
|
||||||
outpainting: { objects },
|
outpainting: { objects },
|
||||||
} = canvas;
|
} = canvas;
|
||||||
const { showDualDisplay } = options;
|
|
||||||
return {
|
return {
|
||||||
doesCanvasNeedScaling,
|
doesCanvasNeedScaling,
|
||||||
showDualDisplay,
|
|
||||||
doesOutpaintingHaveObjects: objects.length > 0,
|
doesOutpaintingHaveObjects: objects.length > 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -41,8 +33,9 @@ const outpaintingDisplaySelector = createSelector(
|
|||||||
|
|
||||||
const OutpaintingDisplay = () => {
|
const OutpaintingDisplay = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { showDualDisplay, doesCanvasNeedScaling, doesOutpaintingHaveObjects } =
|
const { doesCanvasNeedScaling, doesOutpaintingHaveObjects } = useAppSelector(
|
||||||
useAppSelector(outpaintingDisplaySelector);
|
outpaintingDisplaySelector
|
||||||
|
);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const resizeCallback = _.debounce(
|
const resizeCallback = _.debounce(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user