Removes all references to split inpainting/outpainting canvas

This commit is contained in:
psychedelicious 2022-11-17 11:19:36 +11:00 committed by blessedcoolant
parent 15dd1339d2
commit e3efcc620c
53 changed files with 421 additions and 816 deletions

View File

@ -4,20 +4,20 @@ import { RootState } from 'app/store';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { OptionsState } from 'features/options/optionsSlice';
import { SystemState } from 'features/system/systemSlice';
import { baseCanvasImageSelector } from 'features/canvas/canvasSlice';
import { validateSeedWeights } from 'common/util/seedWeightPairs';
import { initialCanvasImageSelector } from 'features/canvas/canvasSlice';
export const readinessSelector = createSelector(
[
(state: RootState) => state.options,
(state: RootState) => state.system,
baseCanvasImageSelector,
initialCanvasImageSelector,
activeTabNameSelector,
],
(
options: OptionsState,
system: SystemState,
baseCanvasImage,
initialCanvasImage,
activeTabName
) => {
const {
@ -44,7 +44,7 @@ export const readinessSelector = createSelector(
reasonsWhyNotReady.push('No initial image selected');
}
if (activeTabName === 'inpainting' && !baseCanvasImage) {
if (activeTabName === 'inpainting' && !initialCanvasImage) {
isReady = false;
reasonsWhyNotReady.push('No inpainting image selected');
}

View File

@ -20,7 +20,7 @@ import {
import { InvokeTabName } from 'features/tabs/InvokeTabs';
import * as InvokeAI from 'app/invokeai';
import { RootState } from 'app/store';
import { baseCanvasImageSelector } from 'features/canvas/canvasSlice';
import { initialCanvasImageSelector } from 'features/canvas/canvasSlice';
/**
* Returns an object containing all functions which use `socketio.emit()`.
@ -55,8 +55,8 @@ const makeSocketIOEmitters = (
};
if (generationMode === 'inpainting') {
const baseCanvasImage = baseCanvasImageSelector(getState());
const imageUrl = baseCanvasImage?.image.url;
const initialCanvasImage = initialCanvasImageSelector(getState());
const imageUrl = initialCanvasImage?.image.url;
if (!imageUrl) {
dispatch(

View File

@ -119,7 +119,7 @@ export const frontendToBackendParameters = (
stageScale,
isMaskEnabled,
shouldPreserveMaskedArea,
} = canvasState[canvasState.currentCanvas];
} = canvasState;
const boundingBox = {
...boundingBoxCoordinates,

View File

@ -5,14 +5,11 @@ import { Layer, Stage } from 'react-konva';
import { Stage as StageType } from 'konva/lib/Stage';
// app
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
import { useAppDispatch, useAppSelector } from 'app/store';
import {
baseCanvasImageSelector,
currentCanvasSelector,
initialCanvasImageSelector,
canvasSelector,
isStagingSelector,
outpaintingCanvasSelector,
setStageCoordinates,
setStageScale,
shouldLockToInitialImageSelector,
} from 'features/canvas/canvasSlice';
@ -39,29 +36,21 @@ import IAICanvasIntermediateImage from './IAICanvasIntermediateImage';
import IAICanvasStatusText from './IAICanvasStatusText';
import IAICanvasStagingArea from './IAICanvasStagingArea';
import IAICanvasStagingAreaToolbar from './IAICanvasStagingAreaToolbar';
import { KonvaEventObject } from 'konva/lib/Node';
import {
CANVAS_SCALE_BY,
MAX_CANVAS_SCALE,
MIN_CANVAS_SCALE,
} from './util/constants';
const canvasSelector = createSelector(
const selector = createSelector(
[
shouldLockToInitialImageSelector,
currentCanvasSelector,
outpaintingCanvasSelector,
canvasSelector,
isStagingSelector,
activeTabNameSelector,
baseCanvasImageSelector,
initialCanvasImageSelector,
],
(
shouldLockToInitialImage,
currentCanvas,
outpaintingCanvas,
canvas,
isStaging,
activeTabName,
baseCanvasImage
initialCanvasImage
) => {
const {
isMaskEnabled,
@ -75,10 +64,8 @@ const canvasSelector = createSelector(
tool,
isMovingStage,
shouldShowIntermediates,
minimumStageScale,
} = currentCanvas;
const { shouldShowGrid } = outpaintingCanvas;
shouldShowGrid,
} = canvas;
let stageCursor: string | undefined = '';
@ -110,9 +97,7 @@ const canvasSelector = createSelector(
isStaging,
shouldShowIntermediates,
shouldLockToInitialImage,
activeTabName,
minimumStageScale,
baseCanvasImage,
initialCanvasImage,
};
},
{
@ -141,11 +126,8 @@ const IAICanvas = () => {
isStaging,
shouldShowIntermediates,
shouldLockToInitialImage,
activeTabName,
minimumStageScale,
baseCanvasImage,
} = useAppSelector(canvasSelector);
const dispatch = useAppDispatch();
initialCanvasImage,
} = useAppSelector(selector);
useCanvasHotkeys();
// set the closure'd refs
@ -172,17 +154,17 @@ const IAICanvas = () => {
const dragBoundFunc = useCallback(
(newCoordinates: Vector2d) => {
if (shouldLockToInitialImage && baseCanvasImage) {
if (shouldLockToInitialImage && initialCanvasImage) {
newCoordinates.x = _.clamp(
newCoordinates.x,
stageDimensions.width -
Math.floor(baseCanvasImage.width * stageScale),
Math.floor(initialCanvasImage.width * stageScale),
0
);
newCoordinates.y = _.clamp(
newCoordinates.y,
stageDimensions.height -
Math.floor(baseCanvasImage.height * stageScale),
Math.floor(initialCanvasImage.height * stageScale),
0
);
}
@ -190,7 +172,7 @@ const IAICanvas = () => {
return newCoordinates;
},
[
baseCanvasImage,
initialCanvasImage,
shouldLockToInitialImage,
stageDimensions.height,
stageDimensions.width,

View File

@ -6,15 +6,11 @@ import { Vector2d } from 'konva/lib/types';
import _ from 'lodash';
import { useCallback, useEffect, useRef } from 'react';
import { Group, Rect, Transformer } from 'react-konva';
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
import { useAppDispatch, useAppSelector } from 'app/store';
import { roundToMultiple } from 'common/util/roundDownToMultiple';
import {
roundDownToMultiple,
roundToMultiple,
} from 'common/util/roundDownToMultiple';
import {
baseCanvasImageSelector,
currentCanvasSelector,
outpaintingCanvasSelector,
initialCanvasImageSelector,
canvasSelector,
setBoundingBoxCoordinates,
setBoundingBoxDimensions,
setIsMouseOverBoundingBox,
@ -27,17 +23,10 @@ import { activeTabNameSelector } from 'features/options/optionsSelectors';
const boundingBoxPreviewSelector = createSelector(
shouldLockToInitialImageSelector,
currentCanvasSelector,
outpaintingCanvasSelector,
baseCanvasImageSelector,
canvasSelector,
initialCanvasImageSelector,
activeTabNameSelector,
(
shouldLockToInitialImage,
currentCanvas,
outpaintingCanvas,
baseCanvasImage,
activeTabName
) => {
(shouldLockToInitialImage, canvas, initialCanvasImage, activeTabName) => {
const {
boundingBoxCoordinates,
boundingBoxDimensions,
@ -50,9 +39,8 @@ const boundingBoxPreviewSelector = createSelector(
shouldDarkenOutsideBoundingBox,
tool,
stageCoordinates,
} = currentCanvas;
const { shouldSnapToGrid } = outpaintingCanvas;
shouldSnapToGrid,
} = canvas;
return {
boundingBoxCoordinates,
@ -64,7 +52,7 @@ const boundingBoxPreviewSelector = createSelector(
isTransformingBoundingBox,
stageDimensions,
stageScale,
baseCanvasImage,
initialCanvasImage,
activeTabName,
shouldSnapToGrid,
tool,
@ -98,7 +86,7 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
stageCoordinates,
stageDimensions,
stageScale,
baseCanvasImage,
initialCanvasImage,
activeTabName,
shouldSnapToGrid,
tool,

View File

@ -1,6 +1,6 @@
import { createSelector } from '@reduxjs/toolkit';
import {
currentCanvasSelector,
canvasSelector,
isStagingSelector,
setBrushColor,
setBrushSize,
@ -16,9 +16,9 @@ import IAISlider from 'common/components/IAISlider';
import { Flex } from '@chakra-ui/react';
export const selector = createSelector(
[currentCanvasSelector, isStagingSelector],
(currentCanvas, isStaging) => {
const { brushColor, brushSize, tool } = currentCanvas;
[canvasSelector, isStagingSelector],
(canvas, isStaging) => {
const { brushColor, brushSize, tool } = canvas;
return {
tool,

View File

@ -3,12 +3,12 @@ import { GroupConfig } from 'konva/lib/Group';
import _ from 'lodash';
import { Circle, Group } from 'react-konva';
import { useAppSelector } from 'app/store';
import { currentCanvasSelector } from 'features/canvas/canvasSlice';
import { canvasSelector } from 'features/canvas/canvasSlice';
import { rgbaColorToString } from './util/colorToString';
const canvasBrushPreviewSelector = createSelector(
currentCanvasSelector,
(currentCanvas) => {
canvasSelector,
(canvas) => {
const {
cursorPosition,
stageDimensions: { width, height },
@ -22,7 +22,7 @@ const canvasBrushPreviewSelector = createSelector(
isMovingBoundingBox,
isTransformingBoundingBox,
stageScale,
} = currentCanvas;
} = canvas;
return {
cursorPosition,

View File

@ -10,28 +10,17 @@ import IAICanvasLockBoundingBoxControl from './IAICanvasControls/IAICanvasLockBo
import IAICanvasShowHideBoundingBoxControl from './IAICanvasControls/IAICanvasShowHideBoundingBoxControl';
import ImageUploaderIconButton from 'common/components/ImageUploaderIconButton';
import { createSelector } from '@reduxjs/toolkit';
import {
outpaintingCanvasSelector,
OutpaintingCanvasState,
} from './canvasSlice';
import { RootState } from 'app/store';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { OptionsState } from 'features/options/optionsSlice';
import _ from 'lodash';
import { canvasSelector } from './canvasSlice';
export const canvasControlsSelector = createSelector(
[
outpaintingCanvasSelector,
(state: RootState) => state.options,
activeTabNameSelector,
],
(
outpaintingCanvas: OutpaintingCanvasState,
options: OptionsState,
activeTabName
) => {
[(state: RootState) => state.options, canvasSelector, activeTabNameSelector],
(options: OptionsState, canvas, activeTabName) => {
const { stageScale, boundingBoxCoordinates, boundingBoxDimensions } =
outpaintingCanvas;
canvas;
return {
activeTabName,
stageScale,

View File

@ -9,7 +9,7 @@ import IAISlider from 'common/components/IAISlider';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import {
currentCanvasSelector,
canvasSelector,
setBrushSize,
setShouldShowBrushPreview,
setTool,
@ -19,9 +19,9 @@ import _ from 'lodash';
import IAICanvasMaskColorPicker from './IAICanvasMaskControls/IAICanvasMaskColorPicker';
const inpaintingBrushSelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas, activeTabName) => {
const { tool, brushSize } = currentCanvas;
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { tool, brushSize } = canvas;
return {
tool,

View File

@ -3,15 +3,15 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { FaEraser } from 'react-icons/fa';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import { currentCanvasSelector, setTool } from 'features/canvas/canvasSlice';
import { canvasSelector, setTool } from 'features/canvas/canvasSlice';
import _ from 'lodash';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
const eraserSelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas, activeTabName) => {
const { tool, isMaskEnabled } = currentCanvas;
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { tool, isMaskEnabled } = canvas;
return {
tool,

View File

@ -2,16 +2,16 @@ import { createSelector } from '@reduxjs/toolkit';
import { useHotkeys } from 'react-hotkeys-hook';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import { currentCanvasSelector, setTool } from 'features/canvas/canvasSlice';
import { canvasSelector, setTool } from 'features/canvas/canvasSlice';
import _ from 'lodash';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { BsEraser } from 'react-icons/bs';
const imageEraserSelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas, activeTabName) => {
const { tool, isMaskEnabled } = currentCanvas;
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { tool, isMaskEnabled } = canvas;
return {
tool,

View File

@ -2,17 +2,16 @@ import { FaLock, FaUnlock } from 'react-icons/fa';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import {
currentCanvasSelector,
GenericCanvasState,
canvasSelector,
setShouldLockBoundingBox,
} from 'features/canvas/canvasSlice';
import { createSelector } from '@reduxjs/toolkit';
import _ from 'lodash';
const canvasLockBoundingBoxSelector = createSelector(
currentCanvasSelector,
(currentCanvas: GenericCanvasState) => {
const { shouldLockBoundingBox } = currentCanvas;
canvasSelector,
(canvas) => {
const { shouldLockBoundingBox } = canvas;
return {
shouldLockBoundingBox,

View File

@ -1,11 +1,7 @@
import { RgbaColor } from 'react-colorful';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIColorPicker from 'common/components/IAIColorPicker';
import {
currentCanvasSelector,
GenericCanvasState,
setMaskColor,
} from 'features/canvas/canvasSlice';
import { canvasSelector, setMaskColor } from 'features/canvas/canvasSlice';
import _ from 'lodash';
import { createSelector } from '@reduxjs/toolkit';
@ -13,9 +9,9 @@ import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { useHotkeys } from 'react-hotkeys-hook';
const selector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas: GenericCanvasState, activeTabName) => {
const { brushColor } = currentCanvas;
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { brushColor } = canvas;
return {
brushColor,

View File

@ -5,10 +5,8 @@ import IAIIconButton from 'common/components/IAIIconButton';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import {
clearMask,
currentCanvasSelector,
InpaintingCanvasState,
canvasSelector,
isCanvasMaskLine,
OutpaintingCanvasState,
} from 'features/canvas/canvasSlice';
import _ from 'lodash';
@ -16,12 +14,12 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { useToast } from '@chakra-ui/react';
const canvasMaskClearSelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas, activeTabName) => {
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const {
isMaskEnabled,
layerState: { objects },
} = currentCanvas as InpaintingCanvasState | OutpaintingCanvasState;
} = canvas;
return {
isMaskEnabled,

View File

@ -5,11 +5,7 @@ import { useAppDispatch, useAppSelector } from 'app/store';
import IAIColorPicker from 'common/components/IAIColorPicker';
import IAIIconButton from 'common/components/IAIIconButton';
import IAIPopover from 'common/components/IAIPopover';
import {
currentCanvasSelector,
GenericCanvasState,
setMaskColor,
} from 'features/canvas/canvasSlice';
import { canvasSelector, setMaskColor } from 'features/canvas/canvasSlice';
import _ from 'lodash';
import { createSelector } from '@reduxjs/toolkit';
@ -17,9 +13,9 @@ import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { useHotkeys } from 'react-hotkeys-hook';
const maskColorPickerSelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas: GenericCanvasState, activeTabName) => {
const { isMaskEnabled, maskColor } = currentCanvas;
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { isMaskEnabled, maskColor } = canvas;
return {
isMaskEnabled,

View File

@ -3,8 +3,7 @@ import { MdInvertColors, MdInvertColorsOff } from 'react-icons/md';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import {
currentCanvasSelector,
GenericCanvasState,
canvasSelector,
setShouldPreserveMaskedArea,
} from 'features/canvas/canvasSlice';
@ -13,9 +12,9 @@ import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { useHotkeys } from 'react-hotkeys-hook';
const canvasMaskInvertSelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas: GenericCanvasState, activeTabName) => {
const { isMaskEnabled, shouldPreserveMaskedArea } = currentCanvas;
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { isMaskEnabled, shouldPreserveMaskedArea } = canvas;
return {
shouldPreserveMaskedArea,
@ -31,9 +30,8 @@ const canvasMaskInvertSelector = createSelector(
);
export default function IAICanvasMaskInvertControl() {
const { shouldPreserveMaskedArea, isMaskEnabled, activeTabName } = useAppSelector(
canvasMaskInvertSelector
);
const { shouldPreserveMaskedArea, isMaskEnabled, activeTabName } =
useAppSelector(canvasMaskInvertSelector);
const dispatch = useAppDispatch();
const handleToggleShouldInvertMask = () =>

View File

@ -4,18 +4,14 @@ import { createSelector } from 'reselect';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import {
currentCanvasSelector,
GenericCanvasState,
setIsMaskEnabled,
} from 'features/canvas/canvasSlice';
import { canvasSelector, setIsMaskEnabled } from 'features/canvas/canvasSlice';
import _ from 'lodash';
const canvasMaskVisibilitySelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas: GenericCanvasState, activeTabName) => {
const { isMaskEnabled } = currentCanvas;
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { isMaskEnabled } = canvas;
return { isMaskEnabled, activeTabName };
},

View File

@ -4,14 +4,14 @@ import { FaRedo } from 'react-icons/fa';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { currentCanvasSelector, redo } from 'features/canvas/canvasSlice';
import { canvasSelector, redo } from 'features/canvas/canvasSlice';
import _ from 'lodash';
const canvasRedoSelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas, activeTabName) => {
const { futureLayerStates } = currentCanvas;
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { futureLayerStates } = canvas;
return {
canRedo: futureLayerStates.length > 0,

View File

@ -2,17 +2,16 @@ import { FaVectorSquare } from 'react-icons/fa';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import {
currentCanvasSelector,
GenericCanvasState,
canvasSelector,
setShouldShowBoundingBox,
} from 'features/canvas/canvasSlice';
import { createSelector } from '@reduxjs/toolkit';
import _ from 'lodash';
const canvasShowHideBoundingBoxControlSelector = createSelector(
currentCanvasSelector,
(currentCanvas: GenericCanvasState) => {
const { shouldShowBoundingBox } = currentCanvas;
canvasSelector,
(canvas) => {
const { shouldShowBoundingBox } = canvas;
return {
shouldShowBoundingBox,

View File

@ -3,13 +3,13 @@ import { useHotkeys } from 'react-hotkeys-hook';
import { FaUndo } from 'react-icons/fa';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import { currentCanvasSelector, undo } from 'features/canvas/canvasSlice';
import { canvasSelector, undo } from 'features/canvas/canvasSlice';
import _ from 'lodash';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
const canvasUndoSelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { pastLayerStates } = canvas;

View File

@ -1,6 +1,6 @@
import { createSelector } from '@reduxjs/toolkit';
import {
currentCanvasSelector,
canvasSelector,
isStagingSelector,
setEraserSize,
setTool,
@ -15,9 +15,9 @@ import { Flex } from '@chakra-ui/react';
import { useHotkeys } from 'react-hotkeys-hook';
export const selector = createSelector(
[currentCanvasSelector, isStagingSelector],
(currentCanvas, isStaging) => {
const { eraserSize, tool } = currentCanvas;
[canvasSelector, isStagingSelector],
(canvas, isStaging) => {
const { eraserSize, tool } = canvas;
return {
tool,

View File

@ -4,22 +4,14 @@ import { useColorMode } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store';
import _ from 'lodash';
import {
ReactNode,
useCallback,
useEffect,
useLayoutEffect,
useState,
} from 'react';
import { ReactNode, useCallback, useLayoutEffect, useState } from 'react';
import { Group, Line as KonvaLine } from 'react-konva';
import { currentCanvasSelector } from './canvasSlice';
import useUnscaleCanvasValue from './hooks/useUnscaleCanvasValue';
import { stageRef } from './IAICanvas';
import { canvasSelector } from './canvasSlice';
const selector = createSelector(
[currentCanvasSelector],
(currentCanvas) => {
const { stageScale, stageCoordinates, stageDimensions } = currentCanvas;
[canvasSelector],
(canvas) => {
const { stageScale, stageCoordinates, stageDimensions } = canvas;
return { stageScale, stageCoordinates, stageDimensions };
},
{
@ -31,7 +23,6 @@ const selector = createSelector(
const IAICanvasGrid = () => {
const { colorMode } = useColorMode();
// const unscale = useUnscaleCanvasValue();
const { stageScale, stageCoordinates, stageDimensions } =
useAppSelector(selector);
const [gridLines, setGridLines] = useState<ReactNode[]>([]);

View File

@ -2,7 +2,7 @@ import { Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import {
clearMask,
currentCanvasSelector,
canvasSelector,
setIsMaskEnabled,
setLayer,
setMaskColor,
@ -18,9 +18,10 @@ import IAIColorPicker from 'common/components/IAIColorPicker';
import IAIButton from 'common/components/IAIButton';
export const selector = createSelector(
[currentCanvasSelector],
(currentCanvas) => {
const { maskColor, layer, isMaskEnabled, shouldPreserveMaskedArea } = currentCanvas;
[canvasSelector],
(canvas) => {
const { maskColor, layer, isMaskEnabled, shouldPreserveMaskedArea } =
canvas;
return {
layer,
@ -63,7 +64,9 @@ const IAICanvasMaskButtonPopover = () => {
<IAICheckbox
label="Preserve Masked Area"
isChecked={shouldPreserveMaskedArea}
onChange={(e) => dispatch(setShouldPreserveMaskedArea(e.target.checked))}
onChange={(e) =>
dispatch(setShouldPreserveMaskedArea(e.target.checked))
}
/>
<IAIColorPicker
color={maskColor}

View File

@ -2,21 +2,16 @@ import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store';
import { RectConfig } from 'konva/lib/shapes/Rect';
import { Rect } from 'react-konva';
import {
currentCanvasSelector,
InpaintingCanvasState,
OutpaintingCanvasState,
} from './canvasSlice';
import { canvasSelector } from './canvasSlice';
import { rgbaColorToString } from './util/colorToString';
import { useCallback, useEffect, useRef, useState } from 'react';
import Konva from 'konva';
export const canvasMaskCompositerSelector = createSelector(
currentCanvasSelector,
(currentCanvas) => {
const { maskColor, stageCoordinates, stageDimensions, stageScale } =
currentCanvas as InpaintingCanvasState | OutpaintingCanvasState;
canvasSelector,
(canvas) => {
const { maskColor, stageCoordinates, stageDimensions, stageScale } = canvas;
return {
stageCoordinates,

View File

@ -2,13 +2,13 @@ import { GroupConfig } from 'konva/lib/Group';
import { Group, Line } from 'react-konva';
import { useAppSelector } from 'app/store';
import { createSelector } from '@reduxjs/toolkit';
import { currentCanvasSelector, isCanvasMaskLine } from './canvasSlice';
import { canvasSelector, isCanvasMaskLine } from './canvasSlice';
import _ from 'lodash';
export const canvasLinesSelector = createSelector(
[currentCanvasSelector],
(currentCanvas) => {
return { objects: currentCanvas.layerState.objects };
[canvasSelector],
(canvas) => {
return { objects: canvas.layerState.objects };
},
{
memoizeOptions: {

View File

@ -1,12 +1,9 @@
import { createSelector, current } from '@reduxjs/toolkit';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store';
import _ from 'lodash';
import { Group, Line } from 'react-konva';
import {
baseCanvasImageSelector,
// canvasClipSelector,
// canvasModeSelector,
currentCanvasSelector,
canvasSelector,
isCanvasBaseImage,
isCanvasBaseLine,
} from './canvasSlice';
@ -14,9 +11,9 @@ import IAICanvasImage from './IAICanvasImage';
import { rgbaColorToString } from './util/colorToString';
const selector = createSelector(
[currentCanvasSelector],
(currentCanvas) => {
const { objects } = currentCanvas.layerState;
[canvasSelector],
(canvas) => {
const { objects } = canvas.layerState;
return {
objects,

View File

@ -1,15 +1,15 @@
import { ButtonGroup } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import {
currentCanvasSelector,
resizeAndScaleCanvas,
isStagingSelector,
resetCanvas,
resetCanvasView,
setShouldLockToInitialImage,
setTool,
canvasSelector,
} from './canvasSlice';
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
import { useAppDispatch, useAppSelector } from 'app/store';
import _ from 'lodash';
import { canvasImageLayerRef, stageRef } from './IAICanvas';
import IAIIconButton from 'common/components/IAIIconButton';
@ -33,15 +33,10 @@ import { mergeAndUploadCanvas } from './util/mergeAndUploadCanvas';
import IAICheckbox from 'common/components/IAICheckbox';
import { ChangeEvent } from 'react';
export const canvasControlsSelector = createSelector(
[
(state: RootState) => state.canvas,
currentCanvasSelector,
isStagingSelector,
],
(canvas, currentCanvas, isStaging) => {
const { shouldLockToInitialImage } = canvas;
const { tool } = currentCanvas;
export const selector = createSelector(
[canvasSelector, isStagingSelector],
(canvas, isStaging) => {
const { tool, shouldLockToInitialImage } = canvas;
return {
tool,
isStaging,
@ -57,9 +52,8 @@ export const canvasControlsSelector = createSelector(
const IAICanvasOutpaintingControls = () => {
const dispatch = useAppDispatch();
const { tool, isStaging, shouldLockToInitialImage } = useAppSelector(
canvasControlsSelector
);
const { tool, isStaging, shouldLockToInitialImage } =
useAppSelector(selector);
const handleToggleShouldLockToInitialImage = (
e: ChangeEvent<HTMLInputElement>

View File

@ -1,10 +1,10 @@
import { Spinner } from '@chakra-ui/react';
import { useLayoutEffect, useRef } from 'react';
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
import { useAppDispatch, useAppSelector } from 'app/store';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import {
baseCanvasImageSelector,
currentCanvasSelector,
initialCanvasImageSelector,
canvasSelector,
resizeAndScaleCanvas,
resizeCanvas,
setCanvasContainerDimensions,
@ -13,11 +13,10 @@ import {
import { createSelector } from '@reduxjs/toolkit';
const canvasResizerSelector = createSelector(
(state: RootState) => state.canvas,
currentCanvasSelector,
baseCanvasImageSelector,
canvasSelector,
initialCanvasImageSelector,
activeTabNameSelector,
(canvas, currentCanvas, baseCanvasImage, activeTabName) => {
(canvas, initialCanvasImage, activeTabName) => {
const {
doesCanvasNeedScaling,
shouldLockToInitialImage,
@ -27,7 +26,7 @@ const canvasResizerSelector = createSelector(
doesCanvasNeedScaling,
shouldLockToInitialImage,
activeTabName,
baseCanvasImage,
initialCanvasImage,
isCanvasInitialized,
};
}
@ -39,7 +38,7 @@ const IAICanvasResizer = () => {
doesCanvasNeedScaling,
shouldLockToInitialImage,
activeTabName,
baseCanvasImage,
initialCanvasImage,
isCanvasInitialized,
} = useAppSelector(canvasResizerSelector);
@ -51,9 +50,10 @@ const IAICanvasResizer = () => {
const { clientWidth, clientHeight } = ref.current;
if (!baseCanvasImage?.image) return;
if (!initialCanvasImage?.image) return;
const { width: imageWidth, height: imageHeight } = baseCanvasImage.image;
const { width: imageWidth, height: imageHeight } =
initialCanvasImage.image;
dispatch(
setCanvasContainerDimensions({
@ -70,9 +70,9 @@ const IAICanvasResizer = () => {
dispatch(setDoesCanvasNeedScaling(false));
// }
// if ((activeTabName === 'inpainting') && baseCanvasImage?.image) {
// if ((activeTabName === 'inpainting') && initialCanvasImage?.image) {
// const { width: imageWidth, height: imageHeight } =
// baseCanvasImage.image;
// initialCanvasImage.image;
// const scale = Math.min(
// 1,
@ -100,7 +100,7 @@ const IAICanvasResizer = () => {
}, 0);
}, [
dispatch,
baseCanvasImage,
initialCanvasImage,
doesCanvasNeedScaling,
activeTabName,
isCanvasInitialized,

View File

@ -1,8 +1,7 @@
import { Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import {
currentCanvasSelector,
outpaintingCanvasSelector,
canvasSelector,
setShouldAutoSave,
setShouldDarkenOutsideBoundingBox,
setShouldShowGrid,
@ -17,13 +16,15 @@ import IAIPopover from 'common/components/IAIPopover';
import IAICheckbox from 'common/components/IAICheckbox';
export const canvasControlsSelector = createSelector(
[currentCanvasSelector, outpaintingCanvasSelector],
(currentCanvas, outpaintingCanvas) => {
const { shouldDarkenOutsideBoundingBox, shouldShowIntermediates } =
currentCanvas;
const { shouldShowGrid, shouldSnapToGrid, shouldAutoSave } =
outpaintingCanvas;
[canvasSelector],
(canvas) => {
const {
shouldDarkenOutsideBoundingBox,
shouldShowIntermediates,
shouldShowGrid,
shouldSnapToGrid,
shouldAutoSave,
} = canvas;
return {
shouldShowGrid,

View File

@ -1,40 +1,20 @@
import { background, ButtonGroup, ChakraProvider } from '@chakra-ui/react';
import { CacheProvider } from '@emotion/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIButton from 'common/components/IAIButton';
import IAIIconButton from 'common/components/IAIIconButton';
import { GroupConfig } from 'konva/lib/Group';
import _ from 'lodash';
import { emotionCache } from 'main';
import { useCallback, useState } from 'react';
import {
FaArrowLeft,
FaArrowRight,
FaCheck,
FaEye,
FaEyeSlash,
FaTrash,
} from 'react-icons/fa';
import { Group, Rect } from 'react-konva';
import { Html } from 'react-konva-utils';
import {
commitStagingAreaImage,
currentCanvasSelector,
discardStagedImages,
nextStagingAreaImage,
prevStagingAreaImage,
} from './canvasSlice';
import { canvasSelector } from './canvasSlice';
import IAICanvasImage from './IAICanvasImage';
const selector = createSelector(
[currentCanvasSelector],
(currentCanvas) => {
[canvasSelector],
(canvas) => {
const {
layerState: {
stagingArea: { images, selectedImageIndex },
},
} = currentCanvas;
} = canvas;
return {
currentStagingAreaImage:
@ -54,9 +34,7 @@ type Props = GroupConfig;
const IAICanvasStagingArea = (props: Props) => {
const { ...rest } = props;
const dispatch = useAppDispatch();
const { isOnFirstImage, isOnLastImage, currentStagingAreaImage } =
useAppSelector(selector);
const { currentStagingAreaImage } = useAppSelector(selector);
const [shouldShowStagedImage, setShouldShowStagedImage] =
useState<boolean>(true);
@ -64,14 +42,6 @@ const IAICanvasStagingArea = (props: Props) => {
const [shouldShowStagingAreaOutline, setShouldShowStagingAreaOutline] =
useState<boolean>(true);
const handleMouseOver = useCallback(() => {
setShouldShowStagingAreaOutline(false);
}, []);
const handleMouseOut = useCallback(() => {
setShouldShowStagingAreaOutline(true);
}, []);
if (!currentStagingAreaImage) return null;
const {
@ -106,73 +76,6 @@ const IAICanvasStagingArea = (props: Props) => {
/>
</Group>
)}
{/* <Html>
<CacheProvider value={emotionCache}>
<ChakraProvider>
<div
style={{
position: 'absolute',
top: y + height,
left: x + width / 2 - 216 / 2,
padding: '0.5rem',
filter: 'drop-shadow(0 0.5rem 1rem rgba(0,0,0))',
}}
>
<ButtonGroup isAttached>
<IAIIconButton
tooltip="Previous"
tooltipProps={{ placement: 'bottom' }}
aria-label="Previous"
icon={<FaArrowLeft />}
onClick={() => dispatch(prevStagingAreaImage())}
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
data-selected={true}
isDisabled={isOnFirstImage}
/>
<IAIIconButton
tooltip="Next"
tooltipProps={{ placement: 'bottom' }}
aria-label="Next"
icon={<FaArrowRight />}
onClick={() => dispatch(nextStagingAreaImage())}
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
data-selected={true}
isDisabled={isOnLastImage}
/>
<IAIIconButton
tooltip="Accept"
tooltipProps={{ placement: 'bottom' }}
aria-label="Accept"
icon={<FaCheck />}
onClick={() => dispatch(commitStagingAreaImage())}
data-selected={true}
/>
<IAIIconButton
tooltip="Show/Hide"
tooltipProps={{ placement: 'bottom' }}
aria-label="Show/Hide"
data-alert={!shouldShowStagedImage}
icon={shouldShowStagedImage ? <FaEye /> : <FaEyeSlash />}
onClick={() =>
setShouldShowStagedImage(!shouldShowStagedImage)
}
data-selected={true}
/>
<IAIIconButton
tooltip="Discard All"
tooltipProps={{ placement: 'bottom' }}
aria-label="Discard All"
icon={<FaTrash />}
onClick={() => dispatch(discardStagedImages())}
data-selected={true}
/>
</ButtonGroup>
</div>
</ChakraProvider>
</CacheProvider>
</Html> */}
</Group>
);
};

View File

@ -21,25 +21,22 @@ import {
FaEyeSlash,
FaTrash,
} from 'react-icons/fa';
import { Group, Rect } from 'react-konva';
import { Html } from 'react-konva-utils';
import {
commitStagingAreaImage,
currentCanvasSelector,
canvasSelector,
discardStagedImages,
nextStagingAreaImage,
prevStagingAreaImage,
} from './canvasSlice';
import IAICanvasImage from './IAICanvasImage';
const selector = createSelector(
[currentCanvasSelector],
(currentCanvas) => {
[canvasSelector],
(canvas) => {
const {
layerState: {
stagingArea: { images, selectedImageIndex },
},
} = currentCanvas;
} = canvas;
return {
currentStagingAreaImage:

View File

@ -1,15 +1,15 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store';
import _ from 'lodash';
import { currentCanvasSelector } from './canvasSlice';
import { canvasSelector } from './canvasSlice';
const roundToHundreth = (val: number): number => {
return Math.round(val * 100) / 100;
};
const selector = createSelector(
[currentCanvasSelector],
(currentCanvas) => {
[canvasSelector],
(canvas) => {
const {
stageDimensions: { width: stageWidth, height: stageHeight },
stageCoordinates: { x: stageX, y: stageY },
@ -17,7 +17,7 @@ const selector = createSelector(
boundingBoxCoordinates: { x: boxX, y: boxY },
cursorPosition,
stageScale,
} = currentCanvas;
} = canvas;
const position = cursorPosition
? { cursorX: cursorPosition.x, cursorY: cursorPosition.y }

View File

@ -1,71 +1,11 @@
import * as InvokeAI from 'app/invokeai';
import { PayloadAction } from '@reduxjs/toolkit';
import { CanvasState, Dimensions, initialLayerState } from './canvasSlice';
import { Vector2d } from 'konva/lib/types';
import { CanvasState, initialLayerState } from './canvasSlice';
import {
roundDownToMultiple,
roundToMultiple,
} from 'common/util/roundDownToMultiple';
import _ from 'lodash';
// export const setInitialInpaintingImage = (
// state: CanvasState,
// image: InvokeAI.Image
// // action: PayloadAction<InvokeAI.Image>
// ) => {
// const { width: canvasWidth, height: canvasHeight } =
// state.inpainting.stageDimensions;
// const { width, height } = state.inpainting.boundingBoxDimensions;
// const { x, y } = state.inpainting.boundingBoxCoordinates;
// const maxWidth = Math.min(image.width, canvasWidth);
// const maxHeight = Math.min(image.height, canvasHeight);
// const newCoordinates: Vector2d = { x, y };
// const newDimensions: Dimensions = { width, height };
// if (width + x > maxWidth) {
// // Bounding box at least needs to be translated
// if (width > maxWidth) {
// // Bounding box also needs to be resized
// newDimensions.width = roundDownToMultiple(maxWidth, 64);
// }
// newCoordinates.x = maxWidth - newDimensions.width;
// }
// if (height + y > maxHeight) {
// // Bounding box at least needs to be translated
// if (height > maxHeight) {
// // Bounding box also needs to be resized
// newDimensions.height = roundDownToMultiple(maxHeight, 64);
// }
// newCoordinates.y = maxHeight - newDimensions.height;
// }
// state.inpainting.boundingBoxDimensions = newDimensions;
// state.inpainting.boundingBoxCoordinates = newCoordinates;
// state.inpainting.pastLayerStates.push(state.inpainting.layerState);
// state.inpainting.layerState = {
// ...initialLayerState,
// objects: [
// {
// kind: 'image',
// layer: 'base',
// x: 0,
// y: 0,
// width: image.width,
// height: image.height,
// image: image,
// },
// ],
// };
// state.outpainting.futureLayerStates = [];
// state.doesCanvasNeedScaling = true;
// };
export const setInitialCanvasImage = (
state: CanvasState,
image: InvokeAI.Image
@ -86,12 +26,12 @@ export const setInitialCanvasImage = (
),
};
state.outpainting.boundingBoxDimensions = newBoundingBoxDimensions;
state.boundingBoxDimensions = newBoundingBoxDimensions;
state.outpainting.boundingBoxCoordinates = newBoundingBoxCoordinates;
state.boundingBoxCoordinates = newBoundingBoxCoordinates;
state.outpainting.pastLayerStates.push(state.outpainting.layerState);
state.outpainting.layerState = {
state.pastLayerStates.push(state.layerState);
state.layerState = {
...initialLayerState,
objects: [
{
@ -105,7 +45,7 @@ export const setInitialCanvasImage = (
},
],
};
state.outpainting.futureLayerStates = [];
state.futureLayerStates = [];
state.isCanvasInitialized = false;
state.doesCanvasNeedScaling = true;

View File

@ -1,10 +1,4 @@
import {
createAsyncThunk,
createSelector,
createSlice,
current,
} from '@reduxjs/toolkit';
import { v4 as uuidv4 } from 'uuid';
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
import { IRect, Vector2d } from 'konva/lib/types';
import { RgbaColor } from 'react-colorful';
@ -12,10 +6,6 @@ import * as InvokeAI from 'app/invokeai';
import _ from 'lodash';
import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
import { RootState } from 'app/store';
import { MutableRefObject } from 'react';
import Konva from 'konva';
import { tabMap } from 'features/tabs/InvokeTabs';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { mergeAndUploadCanvas } from './util/mergeAndUploadCanvas';
import { uploadImage } from 'features/gallery/util/uploadImage';
import { setInitialCanvasImage } from './canvasReducers';
@ -23,45 +13,6 @@ import calculateScale from './util/calculateScale';
import calculateCoordinates from './util/calculateCoordinates';
import floorCoordinates from './util/floorCoordinates';
export interface GenericCanvasState {
boundingBoxCoordinates: Vector2d;
boundingBoxDimensions: Dimensions;
boundingBoxPreviewFill: RgbaColor;
brushColor: RgbaColor;
brushSize: number;
cursorPosition: Vector2d | null;
eraserSize: number;
futureLayerStates: CanvasLayerState[];
inpaintReplace: number;
intermediateImage?: InvokeAI.Image;
isDrawing: boolean;
isMaskEnabled: boolean;
isMouseOverBoundingBox: boolean;
isMoveBoundingBoxKeyHeld: boolean;
isMoveStageKeyHeld: boolean;
isMovingBoundingBox: boolean;
isMovingStage: boolean;
isTransformingBoundingBox: boolean;
layerState: CanvasLayerState;
maskColor: RgbaColor;
maxHistory: number;
pastLayerStates: CanvasLayerState[];
shouldDarkenOutsideBoundingBox: boolean;
shouldLockBoundingBox: boolean;
shouldPreserveMaskedArea: boolean;
shouldShowBoundingBox: boolean;
shouldShowBrush: boolean;
shouldShowBrushPreview: boolean;
shouldShowCheckboardTransparency: boolean;
shouldShowIntermediates: boolean;
shouldUseInpaintReplace: boolean;
stageCoordinates: Vector2d;
stageDimensions: Dimensions;
stageScale: number;
tool: CanvasTool;
minimumStageScale: number;
}
export type CanvasMode = 'inpainting' | 'outpainting';
export type CanvasLayer = 'base' | 'mask';
@ -129,30 +80,51 @@ export const isCanvasAnyLine = (
obj: CanvasObject
): obj is CanvasMaskLine | CanvasLine => obj.kind === 'line';
export type OutpaintingCanvasState = GenericCanvasState & {
layer: CanvasLayer;
shouldShowGrid: boolean;
shouldSnapToGrid: boolean;
shouldAutoSave: boolean;
};
export type InpaintingCanvasState = GenericCanvasState & {
layer: 'mask';
};
export type BaseCanvasState = InpaintingCanvasState | OutpaintingCanvasState;
export type ValidCanvasName = 'inpainting' | 'outpainting';
export interface CanvasState {
doesCanvasNeedScaling: boolean;
currentCanvas: ValidCanvasName;
inpainting: InpaintingCanvasState;
outpainting: OutpaintingCanvasState;
// mode: CanvasMode;
shouldLockToInitialImage: boolean;
isCanvasInitialized: boolean;
boundingBoxCoordinates: Vector2d;
boundingBoxDimensions: Dimensions;
boundingBoxPreviewFill: RgbaColor;
brushColor: RgbaColor;
brushSize: number;
canvasContainerDimensions: Dimensions;
cursorPosition: Vector2d | null;
doesCanvasNeedScaling: boolean;
eraserSize: number;
futureLayerStates: CanvasLayerState[];
inpaintReplace: number;
intermediateImage?: InvokeAI.Image;
isCanvasInitialized: boolean;
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[];
shouldAutoSave: boolean;
shouldDarkenOutsideBoundingBox: boolean;
shouldLockBoundingBox: boolean;
shouldLockToInitialImage: boolean;
shouldPreserveMaskedArea: boolean;
shouldShowBoundingBox: boolean;
shouldShowBrush: boolean;
shouldShowBrushPreview: boolean;
shouldShowCheckboardTransparency: boolean;
shouldShowGrid: boolean;
shouldShowIntermediates: boolean;
shouldSnapToGrid: boolean;
shouldUseInpaintReplace: boolean;
stageCoordinates: Vector2d;
stageDimensions: Dimensions;
stageScale: number;
tool: CanvasTool;
}
export const initialLayerState: CanvasLayerState = {
@ -167,16 +139,19 @@ export const initialLayerState: CanvasLayerState = {
},
};
const initialGenericCanvasState: GenericCanvasState = {
const initialCanvasState: CanvasState = {
boundingBoxCoordinates: { x: 0, y: 0 },
boundingBoxDimensions: { width: 512, height: 512 },
boundingBoxPreviewFill: { r: 0, g: 0, b: 0, a: 0.5 },
brushColor: { r: 90, g: 90, b: 255, a: 1 },
brushSize: 50,
canvasContainerDimensions: { width: 0, height: 0 },
cursorPosition: null,
doesCanvasNeedScaling: false,
eraserSize: 50,
futureLayerStates: [],
inpaintReplace: 0.1,
isCanvasInitialized: false,
isDrawing: false,
isMaskEnabled: true,
isMouseOverBoundingBox: false,
@ -185,121 +160,101 @@ const initialGenericCanvasState: GenericCanvasState = {
isMovingBoundingBox: false,
isMovingStage: false,
isTransformingBoundingBox: false,
layer: 'base',
layerState: initialLayerState,
maskColor: { r: 255, g: 90, b: 90, a: 1 },
maxHistory: 128,
minimumStageScale: 1,
pastLayerStates: [],
shouldAutoSave: false,
shouldDarkenOutsideBoundingBox: false,
shouldLockBoundingBox: false,
shouldLockToInitialImage: false,
shouldPreserveMaskedArea: false,
shouldShowBoundingBox: true,
shouldShowBrush: true,
shouldShowBrushPreview: false,
shouldShowCheckboardTransparency: false,
shouldShowGrid: true,
shouldShowIntermediates: true,
shouldSnapToGrid: true,
shouldUseInpaintReplace: false,
stageCoordinates: { x: 0, y: 0 },
stageDimensions: { width: 0, height: 0 },
stageScale: 1,
minimumStageScale: 1,
tool: 'brush',
};
const initialCanvasState: CanvasState = {
currentCanvas: 'inpainting',
doesCanvasNeedScaling: false,
shouldLockToInitialImage: false,
// mode: 'outpainting',
isCanvasInitialized: false,
canvasContainerDimensions: { width: 0, height: 0 },
inpainting: {
layer: 'mask',
...initialGenericCanvasState,
},
outpainting: {
layer: 'base',
shouldShowGrid: true,
shouldSnapToGrid: true,
shouldAutoSave: false,
...initialGenericCanvasState,
},
};
export const canvasSlice = createSlice({
name: 'canvas',
initialState: initialCanvasState,
reducers: {
setTool: (state, action: PayloadAction<CanvasTool>) => {
const tool = action.payload;
state[state.currentCanvas].tool = action.payload;
state.tool = action.payload;
if (tool !== 'move') {
state[state.currentCanvas].isTransformingBoundingBox = false;
state[state.currentCanvas].isMouseOverBoundingBox = false;
state[state.currentCanvas].isMovingBoundingBox = false;
state[state.currentCanvas].isMovingStage = false;
state.isTransformingBoundingBox = false;
state.isMouseOverBoundingBox = false;
state.isMovingBoundingBox = false;
state.isMovingStage = false;
}
},
setLayer: (state, action: PayloadAction<CanvasLayer>) => {
state[state.currentCanvas].layer = action.payload;
state.layer = action.payload;
},
toggleTool: (state) => {
const currentTool = state[state.currentCanvas].tool;
const currentTool = state.tool;
if (currentTool !== 'move') {
state[state.currentCanvas].tool =
currentTool === 'brush' ? 'eraser' : 'brush';
state.tool = currentTool === 'brush' ? 'eraser' : 'brush';
}
},
setMaskColor: (state, action: PayloadAction<RgbaColor>) => {
state[state.currentCanvas].maskColor = action.payload;
state.maskColor = action.payload;
},
setBrushColor: (state, action: PayloadAction<RgbaColor>) => {
state[state.currentCanvas].brushColor = action.payload;
state.brushColor = action.payload;
},
setBrushSize: (state, action: PayloadAction<number>) => {
state[state.currentCanvas].brushSize = action.payload;
state.brushSize = action.payload;
},
setEraserSize: (state, action: PayloadAction<number>) => {
state[state.currentCanvas].eraserSize = action.payload;
state.eraserSize = action.payload;
},
clearMask: (state) => {
const currentCanvas = state[state.currentCanvas];
currentCanvas.pastLayerStates.push(currentCanvas.layerState);
currentCanvas.layerState.objects = state[
state.currentCanvas
].layerState.objects.filter((obj) => !isCanvasMaskLine(obj));
currentCanvas.futureLayerStates = [];
currentCanvas.shouldPreserveMaskedArea = false;
state.pastLayerStates.push(state.layerState);
state.layerState.objects = state.layerState.objects.filter(
(obj) => !isCanvasMaskLine(obj)
);
state.futureLayerStates = [];
state.shouldPreserveMaskedArea = false;
},
toggleShouldInvertMask: (state) => {
state[state.currentCanvas].shouldPreserveMaskedArea =
!state[state.currentCanvas].shouldPreserveMaskedArea;
state.shouldPreserveMaskedArea = !state.shouldPreserveMaskedArea;
},
toggleShouldShowMask: (state) => {
state[state.currentCanvas].isMaskEnabled =
!state[state.currentCanvas].isMaskEnabled;
state.isMaskEnabled = !state.isMaskEnabled;
},
setShouldPreserveMaskedArea: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].shouldPreserveMaskedArea = action.payload;
state.shouldPreserveMaskedArea = action.payload;
},
setIsMaskEnabled: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].isMaskEnabled = action.payload;
state[state.currentCanvas].layer = action.payload ? 'mask' : 'base';
state.isMaskEnabled = action.payload;
state.layer = action.payload ? 'mask' : 'base';
},
setShouldShowCheckboardTransparency: (
state,
action: PayloadAction<boolean>
) => {
state[state.currentCanvas].shouldShowCheckboardTransparency =
action.payload;
state.shouldShowCheckboardTransparency = action.payload;
},
setShouldShowBrushPreview: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].shouldShowBrushPreview = action.payload;
state.shouldShowBrushPreview = action.payload;
},
setShouldShowBrush: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].shouldShowBrush = action.payload;
state.shouldShowBrush = action.payload;
},
setCursorPosition: (state, action: PayloadAction<Vector2d | null>) => {
state[state.currentCanvas].cursorPosition = action.payload;
state.cursorPosition = action.payload;
},
clearImageToInpaint: (state) => {
// TODO
@ -312,102 +267,87 @@ export const canvasSlice = createSlice({
setInitialCanvasImage(state, action.payload);
},
setStageDimensions: (state, action: PayloadAction<Dimensions>) => {
state[state.currentCanvas].stageDimensions = action.payload;
state.stageDimensions = action.payload;
const { width: canvasWidth, height: canvasHeight } = action.payload;
const { width: boundingBoxWidth, height: boundingBoxHeight } =
state[state.currentCanvas].boundingBoxDimensions;
state.boundingBoxDimensions;
const newBoundingBoxWidth = roundDownToMultiple(
_.clamp(
boundingBoxWidth,
64,
canvasWidth / state[state.currentCanvas].stageScale
),
_.clamp(boundingBoxWidth, 64, canvasWidth / state.stageScale),
64
);
const newBoundingBoxHeight = roundDownToMultiple(
_.clamp(
boundingBoxHeight,
64,
canvasHeight / state[state.currentCanvas].stageScale
),
_.clamp(boundingBoxHeight, 64, canvasHeight / state.stageScale),
64
);
state[state.currentCanvas].boundingBoxDimensions = {
state.boundingBoxDimensions = {
width: newBoundingBoxWidth,
height: newBoundingBoxHeight,
};
},
setBoundingBoxDimensions: (state, action: PayloadAction<Dimensions>) => {
state[state.currentCanvas].boundingBoxDimensions = action.payload;
state.boundingBoxDimensions = action.payload;
},
setBoundingBoxCoordinates: (state, action: PayloadAction<Vector2d>) => {
state[state.currentCanvas].boundingBoxCoordinates = floorCoordinates(
action.payload
);
state.boundingBoxCoordinates = floorCoordinates(action.payload);
},
setStageCoordinates: (state, action: PayloadAction<Vector2d>) => {
state.outpainting.stageCoordinates = floorCoordinates(action.payload);
state.stageCoordinates = floorCoordinates(action.payload);
},
setBoundingBoxPreviewFill: (state, action: PayloadAction<RgbaColor>) => {
state[state.currentCanvas].boundingBoxPreviewFill = action.payload;
state.boundingBoxPreviewFill = action.payload;
},
setDoesCanvasNeedScaling: (state, action: PayloadAction<boolean>) => {
state.doesCanvasNeedScaling = action.payload;
},
setStageScale: (state, action: PayloadAction<number>) => {
state[state.currentCanvas].stageScale = action.payload;
state.stageScale = action.payload;
},
setShouldDarkenOutsideBoundingBox: (
state,
action: PayloadAction<boolean>
) => {
state[state.currentCanvas].shouldDarkenOutsideBoundingBox =
action.payload;
state.shouldDarkenOutsideBoundingBox = action.payload;
},
setIsDrawing: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].isDrawing = action.payload;
state.isDrawing = action.payload;
},
setClearBrushHistory: (state) => {
state[state.currentCanvas].pastLayerStates = [];
state[state.currentCanvas].futureLayerStates = [];
state.pastLayerStates = [];
state.futureLayerStates = [];
},
setShouldUseInpaintReplace: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].shouldUseInpaintReplace = action.payload;
state.shouldUseInpaintReplace = action.payload;
},
setInpaintReplace: (state, action: PayloadAction<number>) => {
state[state.currentCanvas].inpaintReplace = action.payload;
state.inpaintReplace = action.payload;
},
setShouldLockBoundingBox: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].shouldLockBoundingBox = action.payload;
state.shouldLockBoundingBox = action.payload;
},
toggleShouldLockBoundingBox: (state) => {
state[state.currentCanvas].shouldLockBoundingBox =
!state[state.currentCanvas].shouldLockBoundingBox;
state.shouldLockBoundingBox = !state.shouldLockBoundingBox;
},
setShouldShowBoundingBox: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].shouldShowBoundingBox = action.payload;
state.shouldShowBoundingBox = action.payload;
},
setIsTransformingBoundingBox: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].isTransformingBoundingBox = action.payload;
state.isTransformingBoundingBox = action.payload;
},
setIsMovingBoundingBox: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].isMovingBoundingBox = action.payload;
state.isMovingBoundingBox = action.payload;
},
setIsMouseOverBoundingBox: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].isMouseOverBoundingBox = action.payload;
state.isMouseOverBoundingBox = action.payload;
},
setIsMoveBoundingBoxKeyHeld: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].isMoveBoundingBoxKeyHeld = action.payload;
state.isMoveBoundingBoxKeyHeld = action.payload;
},
setIsMoveStageKeyHeld: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].isMoveStageKeyHeld = action.payload;
},
setCurrentCanvas: (state, action: PayloadAction<ValidCanvasName>) => {
state.currentCanvas = action.payload;
state.isMoveStageKeyHeld = action.payload;
},
addImageToStagingArea: (
state,
@ -420,36 +360,31 @@ export const canvasSlice = createSlice({
if (!boundingBox || !image) return;
const currentCanvas = state.outpainting;
state.pastLayerStates.push(_.cloneDeep(state.layerState));
currentCanvas.pastLayerStates.push(_.cloneDeep(currentCanvas.layerState));
if (currentCanvas.pastLayerStates.length > currentCanvas.maxHistory) {
currentCanvas.pastLayerStates.shift();
if (state.pastLayerStates.length > state.maxHistory) {
state.pastLayerStates.shift();
}
currentCanvas.layerState.stagingArea.images.push({
state.layerState.stagingArea.images.push({
kind: 'image',
layer: 'base',
...boundingBox,
image,
});
currentCanvas.layerState.stagingArea.selectedImageIndex =
currentCanvas.layerState.stagingArea.images.length - 1;
state.layerState.stagingArea.selectedImageIndex =
state.layerState.stagingArea.images.length - 1;
currentCanvas.futureLayerStates = [];
state.futureLayerStates = [];
},
discardStagedImages: (state) => {
const currentCanvas = state[state.currentCanvas];
currentCanvas.layerState.stagingArea = {
state.layerState.stagingArea = {
...initialLayerState.stagingArea,
};
},
addLine: (state, action: PayloadAction<number[]>) => {
const currentCanvas = state[state.currentCanvas];
const { tool, layer, brushColor, brushSize, eraserSize } = currentCanvas;
const { tool, layer, brushColor, brushSize, eraserSize } = state;
if (tool === 'move') return;
@ -459,13 +394,13 @@ export const canvasSlice = createSlice({
const newColor =
layer === 'base' && tool === 'brush' ? { color: brushColor } : {};
currentCanvas.pastLayerStates.push(currentCanvas.layerState);
state.pastLayerStates.push(state.layerState);
if (currentCanvas.pastLayerStates.length > currentCanvas.maxHistory) {
currentCanvas.pastLayerStates.shift();
if (state.pastLayerStates.length > state.maxHistory) {
state.pastLayerStates.shift();
}
currentCanvas.layerState.objects.push({
state.layerState.objects.push({
kind: 'line',
layer,
tool,
@ -474,68 +409,61 @@ export const canvasSlice = createSlice({
...newColor,
});
currentCanvas.futureLayerStates = [];
state.futureLayerStates = [];
},
addPointToCurrentLine: (state, action: PayloadAction<number[]>) => {
const lastLine =
state[state.currentCanvas].layerState.objects.findLast(isCanvasAnyLine);
const lastLine = state.layerState.objects.findLast(isCanvasAnyLine);
if (!lastLine) return;
lastLine.points.push(...action.payload);
},
undo: (state) => {
const currentCanvas = state[state.currentCanvas];
const targetState = currentCanvas.pastLayerStates.pop();
const targetState = state.pastLayerStates.pop();
if (!targetState) return;
currentCanvas.futureLayerStates.unshift(currentCanvas.layerState);
state.futureLayerStates.unshift(state.layerState);
if (currentCanvas.futureLayerStates.length > currentCanvas.maxHistory) {
currentCanvas.futureLayerStates.pop();
if (state.futureLayerStates.length > state.maxHistory) {
state.futureLayerStates.pop();
}
currentCanvas.layerState = targetState;
state.layerState = targetState;
},
redo: (state) => {
const currentCanvas = state[state.currentCanvas];
const targetState = currentCanvas.futureLayerStates.shift();
const targetState = state.futureLayerStates.shift();
if (!targetState) return;
currentCanvas.pastLayerStates.push(currentCanvas.layerState);
state.pastLayerStates.push(state.layerState);
if (currentCanvas.pastLayerStates.length > currentCanvas.maxHistory) {
currentCanvas.pastLayerStates.shift();
if (state.pastLayerStates.length > state.maxHistory) {
state.pastLayerStates.shift();
}
currentCanvas.layerState = targetState;
state.layerState = targetState;
},
setShouldShowGrid: (state, action: PayloadAction<boolean>) => {
state.outpainting.shouldShowGrid = action.payload;
state.shouldShowGrid = action.payload;
},
setIsMovingStage: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].isMovingStage = action.payload;
state.isMovingStage = action.payload;
},
setShouldSnapToGrid: (state, action: PayloadAction<boolean>) => {
state.outpainting.shouldSnapToGrid = action.payload;
state.shouldSnapToGrid = action.payload;
},
setShouldAutoSave: (state, action: PayloadAction<boolean>) => {
state.outpainting.shouldAutoSave = action.payload;
state.shouldAutoSave = action.payload;
},
setShouldShowIntermediates: (state, action: PayloadAction<boolean>) => {
state[state.currentCanvas].shouldShowIntermediates = action.payload;
state.shouldShowIntermediates = action.payload;
},
resetCanvas: (state) => {
state[state.currentCanvas].pastLayerStates.push(
state[state.currentCanvas].layerState
);
state.pastLayerStates.push(state.layerState);
state[state.currentCanvas].layerState = initialLayerState;
state[state.currentCanvas].futureLayerStates = [];
state.layerState = initialLayerState;
state.futureLayerStates = [];
},
setCanvasContainerDimensions: (
state,
@ -548,7 +476,7 @@ export const canvasSlice = createSlice({
state.canvasContainerDimensions;
const initialCanvasImage =
state.outpainting.layerState.objects.find(isCanvasBaseImage);
state.layerState.objects.find(isCanvasBaseImage);
if (!initialCanvasImage) return;
@ -559,8 +487,6 @@ export const canvasSlice = createSlice({
const { shouldLockToInitialImage } = state;
const currentCanvas = state[state.currentCanvas];
const padding = shouldLockToInitialImage ? 1 : 0.95;
const newScale = calculateScale(
@ -590,20 +516,18 @@ export const canvasSlice = createSlice({
newScale
);
currentCanvas.stageScale = newScale;
currentCanvas.minimumStageScale = newScale;
currentCanvas.stageCoordinates = newCoordinates;
state.stageScale = newScale;
state.minimumStageScale = newScale;
state.stageCoordinates = newCoordinates;
currentCanvas.stageDimensions = newDimensions;
state.stageDimensions = newDimensions;
state.isCanvasInitialized = true;
},
resizeCanvas: (state) => {
const { width: containerWidth, height: containerHeight } =
state.canvasContainerDimensions;
const currentCanvas = state[state.currentCanvas];
currentCanvas.stageDimensions = {
state.stageDimensions = {
width: Math.floor(containerWidth),
height: Math.floor(containerHeight),
};
@ -616,16 +540,13 @@ export const canvasSlice = createSlice({
) => {
const { contentRect } = action.payload;
const currentCanvas = state[state.currentCanvas];
const baseCanvasImage =
currentCanvas.layerState.objects.find(isCanvasBaseImage);
const baseCanvasImage = state.layerState.objects.find(isCanvasBaseImage);
const { shouldLockToInitialImage } = state;
if (!baseCanvasImage) return;
const {
stageDimensions: { width: stageWidth, height: stageHeight },
} = currentCanvas;
} = state;
const { x, y, width, height } = contentRect;
@ -648,56 +569,49 @@ export const canvasSlice = createSlice({
newScale
);
currentCanvas.stageScale = newScale;
state.stageScale = newScale;
currentCanvas.stageCoordinates = newCoordinates;
state.stageCoordinates = newCoordinates;
},
nextStagingAreaImage: (state) => {
const currentIndex =
state.outpainting.layerState.stagingArea.selectedImageIndex;
const length = state.outpainting.layerState.stagingArea.images.length;
const currentIndex = state.layerState.stagingArea.selectedImageIndex;
const length = state.layerState.stagingArea.images.length;
state.outpainting.layerState.stagingArea.selectedImageIndex = Math.min(
state.layerState.stagingArea.selectedImageIndex = Math.min(
currentIndex + 1,
length - 1
);
},
prevStagingAreaImage: (state) => {
const currentIndex =
state.outpainting.layerState.stagingArea.selectedImageIndex;
const currentIndex = state.layerState.stagingArea.selectedImageIndex;
state.outpainting.layerState.stagingArea.selectedImageIndex = Math.max(
state.layerState.stagingArea.selectedImageIndex = Math.max(
currentIndex - 1,
0
);
},
commitStagingAreaImage: (state) => {
const currentCanvas = state[state.currentCanvas];
const { images, selectedImageIndex } =
currentCanvas.layerState.stagingArea;
const { images, selectedImageIndex } = state.layerState.stagingArea;
currentCanvas.pastLayerStates.push(_.cloneDeep(currentCanvas.layerState));
state.pastLayerStates.push(_.cloneDeep(state.layerState));
if (currentCanvas.pastLayerStates.length > currentCanvas.maxHistory) {
currentCanvas.pastLayerStates.shift();
if (state.pastLayerStates.length > state.maxHistory) {
state.pastLayerStates.shift();
}
currentCanvas.layerState.objects.push({
state.layerState.objects.push({
...images[selectedImageIndex],
});
currentCanvas.layerState.stagingArea = {
state.layerState.stagingArea = {
...initialLayerState.stagingArea,
};
currentCanvas.futureLayerStates = [];
state.futureLayerStates = [];
},
setShouldLockToInitialImage: (state, action: PayloadAction<boolean>) => {
state.shouldLockToInitialImage = action.payload;
},
// setCanvasMode: (state, action: PayloadAction<CanvasMode>) => {
// state.mode = action.payload;
// },
},
extraReducers: (builder) => {
builder.addCase(mergeAndUploadCanvas.fulfilled, (state, action) => {
@ -705,13 +619,13 @@ export const canvasSlice = createSlice({
const { image, kind, originalBoundingBox } = action.payload;
if (kind === 'temp_merged_canvas') {
state.outpainting.pastLayerStates.push({
...state.outpainting.layerState,
state.pastLayerStates.push({
...state.layerState,
});
state.outpainting.futureLayerStates = [];
state.futureLayerStates = [];
state.outpainting.layerState.objects = [
state.layerState.objects = [
{
kind: 'image',
layer: 'base',
@ -779,7 +693,6 @@ export const {
setIsMoveBoundingBoxKeyHeld,
setIsMoveStageKeyHeld,
setStageCoordinates,
setCurrentCanvas,
addImageToStagingArea,
resetCanvas,
setShouldShowGrid,
@ -800,41 +713,15 @@ export const {
export default canvasSlice.reducer;
export const currentCanvasSelector = (state: RootState): BaseCanvasState =>
state.canvas[state.canvas.currentCanvas];
export const canvasSelector = (state: RootState): CanvasState => state.canvas;
export const isStagingSelector = (state: RootState): boolean =>
state.canvas[state.canvas.currentCanvas].layerState.stagingArea.images
.length > 0;
export const outpaintingCanvasSelector = (
state: RootState
): OutpaintingCanvasState => state.canvas.outpainting;
export const inpaintingCanvasSelector = (
state: RootState
): InpaintingCanvasState => state.canvas.inpainting;
state.canvas.layerState.stagingArea.images.length > 0;
export const shouldLockToInitialImageSelector = (state: RootState): boolean =>
state.canvas.shouldLockToInitialImage;
export const baseCanvasImageSelector = createSelector(
[currentCanvasSelector],
(currentCanvas) => {
return currentCanvas.layerState.objects.find(isCanvasBaseImage);
}
);
// export const canvasClipSelector = createSelector(
// [canvasModeSelector, baseCanvasImageSelector],
// (canvasMode, baseCanvasImage) => {
// return canvasMode === 'inpainting'
// ? {
// clipX: 0,
// clipY: 0,
// clipWidth: baseCanvasImage?.width,
// clipHeight: baseCanvasImage?.height,
// }
// : {};
// }
// );
export const initialCanvasImageSelector = (
state: RootState
): CanvasImage | undefined =>
state.canvas.layerState.objects.find(isCanvasBaseImage);

View File

@ -1,20 +1,17 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { KonvaEventObject } from 'konva/lib/Node';
import _ from 'lodash';
import { useCallback } from 'react';
import {
baseCanvasImageSelector,
currentCanvasSelector,
canvasSelector,
isStagingSelector,
setIsMovingStage,
setStageCoordinates,
shouldLockToInitialImageSelector,
} from '../canvasSlice';
const selector = createSelector(
[currentCanvasSelector, isStagingSelector],
[canvasSelector, isStagingSelector],
(canvas, isStaging) => {
const { tool } = canvas;
return {

View File

@ -9,19 +9,19 @@ import {
toggleShouldLockBoundingBox,
} from 'features/canvas/canvasSlice';
import { useAppDispatch, useAppSelector } from 'app/store';
import { currentCanvasSelector } from '../canvasSlice';
import { canvasSelector } from '../canvasSlice';
import { useRef } from 'react';
import { stageRef } from '../IAICanvas';
const inpaintingCanvasHotkeysSelector = createSelector(
[currentCanvasSelector, activeTabNameSelector],
(currentCanvas, activeTabName) => {
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const {
cursorPosition,
shouldLockBoundingBox,
shouldShowBoundingBox,
tool,
} = currentCanvas;
} = canvas;
return {
activeTabName,

View File

@ -7,7 +7,7 @@ import _ from 'lodash';
import { MutableRefObject, useCallback } from 'react';
import {
addLine,
currentCanvasSelector,
canvasSelector,
isStagingSelector,
setIsDrawing,
setIsMovingStage,
@ -15,9 +15,9 @@ import {
import getScaledCursorPosition from '../util/getScaledCursorPosition';
const selector = createSelector(
[activeTabNameSelector, currentCanvasSelector, isStagingSelector],
(activeTabName, currentCanvas, isStaging) => {
const { tool } = currentCanvas;
[activeTabNameSelector, canvasSelector, isStagingSelector],
(activeTabName, canvas, isStaging) => {
const { tool } = canvas;
return {
tool,
activeTabName,

View File

@ -7,16 +7,16 @@ import _ from 'lodash';
import { MutableRefObject, useCallback } from 'react';
import {
addLine,
currentCanvasSelector,
canvasSelector,
isStagingSelector,
setIsDrawing,
} from '../canvasSlice';
import getScaledCursorPosition from '../util/getScaledCursorPosition';
const selector = createSelector(
[activeTabNameSelector, currentCanvasSelector, isStagingSelector],
(activeTabName, currentCanvas, isStaging) => {
const { tool } = currentCanvas;
[activeTabNameSelector, canvasSelector, isStagingSelector],
(activeTabName, canvas, isStaging) => {
const { tool } = canvas;
return {
tool,
activeTabName,

View File

@ -7,17 +7,16 @@ import _ from 'lodash';
import { MutableRefObject, useCallback } from 'react';
import {
addPointToCurrentLine,
currentCanvasSelector,
GenericCanvasState,
canvasSelector,
isStagingSelector,
setCursorPosition,
} from '../canvasSlice';
import getScaledCursorPosition from '../util/getScaledCursorPosition';
const selector = createSelector(
[activeTabNameSelector, currentCanvasSelector, isStagingSelector],
(activeTabName, currentCanvas, isStaging) => {
const { tool, isDrawing } = currentCanvas;
[activeTabNameSelector, canvasSelector, isStagingSelector],
(activeTabName, canvas, isStaging) => {
const { tool, isDrawing } = canvas;
return {
tool,
isDrawing,

View File

@ -7,8 +7,7 @@ import { MutableRefObject, useCallback } from 'react';
import {
// addPointToCurrentEraserLine,
addPointToCurrentLine,
currentCanvasSelector,
GenericCanvasState,
canvasSelector,
isStagingSelector,
setIsDrawing,
setIsMovingStage,
@ -16,9 +15,9 @@ import {
import getScaledCursorPosition from '../util/getScaledCursorPosition';
const selector = createSelector(
[activeTabNameSelector, currentCanvasSelector, isStagingSelector],
(activeTabName, currentCanvas, isStaging) => {
const { tool, isDrawing } = currentCanvas;
[activeTabNameSelector, canvasSelector, isStagingSelector],
(activeTabName, canvas, isStaging) => {
const { tool, isDrawing } = canvas;
return {
tool,
isDrawing,

View File

@ -1,14 +1,13 @@
import { createSelector } from '@reduxjs/toolkit';
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
import { useAppDispatch, useAppSelector } from 'app/store';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
import Konva from 'konva';
import { KonvaEventObject } from 'konva/lib/Node';
import _ from 'lodash';
import { MutableRefObject, useCallback } from 'react';
import {
baseCanvasImageSelector,
currentCanvasSelector,
GenericCanvasState,
initialCanvasImageSelector,
canvasSelector,
setStageCoordinates,
setStageScale,
shouldLockToInitialImageSelector,
@ -21,30 +20,23 @@ import {
const selector = createSelector(
[
(state: RootState) => state.canvas,
activeTabNameSelector,
currentCanvasSelector,
baseCanvasImageSelector,
canvasSelector,
initialCanvasImageSelector,
shouldLockToInitialImageSelector,
],
(
canvas,
activeTabName,
currentCanvas,
baseCanvasImage,
shouldLockToInitialImage
) => {
(activeTabName, canvas, initialCanvasImage, shouldLockToInitialImage) => {
const {
isMoveStageKeyHeld,
stageScale,
stageDimensions,
minimumStageScale,
} = currentCanvas;
} = canvas;
return {
isMoveStageKeyHeld,
stageScale,
activeTabName,
baseCanvasImage,
initialCanvasImage,
shouldLockToInitialImage,
stageDimensions,
minimumStageScale,
@ -59,7 +51,7 @@ const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
isMoveStageKeyHeld,
stageScale,
activeTabName,
baseCanvasImage,
initialCanvasImage,
shouldLockToInitialImage,
stageDimensions,
minimumStageScale,
@ -72,7 +64,7 @@ const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
activeTabName !== 'outpainting' ||
!stageRef.current ||
isMoveStageKeyHeld ||
!baseCanvasImage
!initialCanvasImage
)
return;
@ -109,13 +101,14 @@ const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
if (shouldLockToInitialImage) {
newCoordinates.x = _.clamp(
newCoordinates.x,
stageDimensions.width - Math.floor(baseCanvasImage.width * newScale),
stageDimensions.width -
Math.floor(initialCanvasImage.width * newScale),
0
);
newCoordinates.y = _.clamp(
newCoordinates.y,
stageDimensions.height -
Math.floor(baseCanvasImage.height * newScale),
Math.floor(initialCanvasImage.height * newScale),
0
);
}
@ -127,7 +120,7 @@ const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
activeTabName,
stageRef,
isMoveStageKeyHeld,
baseCanvasImage,
initialCanvasImage,
stageScale,
shouldLockToInitialImage,
minimumStageScale,

View File

@ -1,23 +0,0 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store';
import _ from 'lodash';
import { currentCanvasSelector, GenericCanvasState } from '../canvasSlice';
const selector = createSelector(
[currentCanvasSelector],
(currentCanvas: GenericCanvasState) => {
return currentCanvas.stageScale;
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
},
}
);
const useUnscaleCanvasValue = () => {
const stageScale = useAppSelector(selector);
return (value: number) => value / stageScale;
};
export default useUnscaleCanvasValue;

View File

@ -21,7 +21,7 @@ export const mergeAndUploadCanvas = createAsyncThunk(
const state = getState() as RootState;
const stageScale = state.canvas[state.canvas.currentCanvas].stageScale;
const stageScale = state.canvas.stageScale;
if (!canvasImageLayerRef.current) return;

View File

@ -2,16 +2,14 @@ import React from 'react';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAICheckbox from 'common/components/IAICheckbox';
import {
currentCanvasSelector,
GenericCanvasState,
canvasSelector,
setShouldDarkenOutsideBoundingBox,
} from 'features/canvas/canvasSlice';
import { createSelector } from '@reduxjs/toolkit';
const selector = createSelector(
currentCanvasSelector,
(currentCanvas: GenericCanvasState) =>
currentCanvas.shouldDarkenOutsideBoundingBox
canvasSelector,
(canvas) => canvas.shouldDarkenOutsideBoundingBox
);
export default function BoundingBoxDarkenOutside() {

View File

@ -4,7 +4,7 @@ import IAISlider from 'common/components/IAISlider';
import { useAppDispatch, useAppSelector } from 'app/store';
import { createSelector } from '@reduxjs/toolkit';
import {
currentCanvasSelector,
canvasSelector,
setBoundingBoxDimensions,
} from 'features/canvas/canvasSlice';
@ -12,10 +12,10 @@ import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
import _ from 'lodash';
const boundingBoxDimensionsSelector = createSelector(
currentCanvasSelector,
(currentCanvas) => {
canvasSelector,
(canvas) => {
const { stageDimensions, boundingBoxDimensions, shouldLockBoundingBox } =
currentCanvas;
canvas;
return {
stageDimensions,
boundingBoxDimensions,

View File

@ -2,14 +2,14 @@ import React from 'react';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAICheckbox from 'common/components/IAICheckbox';
import {
currentCanvasSelector,
canvasSelector,
setShouldLockBoundingBox,
} from 'features/canvas/canvasSlice';
import { createSelector } from '@reduxjs/toolkit';
const boundingBoxLockSelector = createSelector(
currentCanvasSelector,
(currentCanvas) => currentCanvas.shouldLockBoundingBox
canvasSelector,
(canvas) => canvas.shouldLockBoundingBox
);
export default function BoundingBoxLock() {

View File

@ -3,14 +3,14 @@ import { BiHide, BiShow } from 'react-icons/bi';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import {
currentCanvasSelector,
canvasSelector,
setShouldShowBoundingBox,
} from 'features/canvas/canvasSlice';
import { createSelector } from '@reduxjs/toolkit';
const boundingBoxVisibilitySelector = createSelector(
currentCanvasSelector,
(currentCanvas) => currentCanvas.shouldShowBoundingBox
canvasSelector,
(canvas) => canvas.shouldShowBoundingBox
);
export default function BoundingBoxVisibility() {

View File

@ -3,22 +3,20 @@ import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store';
import IAIButton from 'common/components/IAIButton';
import {
currentCanvasSelector,
InpaintingCanvasState,
OutpaintingCanvasState,
canvasSelector,
setClearBrushHistory,
} from 'features/canvas/canvasSlice';
import _ from 'lodash';
const clearBrushHistorySelector = createSelector(
currentCanvasSelector,
(currentCanvas) => {
const { pastLayerStates, futureLayerStates } = currentCanvas as
| InpaintingCanvasState
| OutpaintingCanvasState;
canvasSelector,
(canvas) => {
const { pastLayerStates, futureLayerStates } = canvas;
return {
mayClearBrushHistory:
futureLayerStates.length > 0 || pastLayerStates.length > 0 ? false : true,
futureLayerStates.length > 0 || pastLayerStates.length > 0
? false
: true,
};
},
{

View File

@ -6,16 +6,15 @@ import IAISwitch from '../../../../common/components/IAISwitch';
import IAISlider from '../../../../common/components/IAISlider';
import { Flex } from '@chakra-ui/react';
import {
currentCanvasSelector,
GenericCanvasState,
canvasSelector,
setInpaintReplace,
setShouldUseInpaintReplace,
} from 'features/canvas/canvasSlice';
const canvasInpaintReplaceSelector = createSelector(
currentCanvasSelector,
(currentCanvas: GenericCanvasState) => {
const { inpaintReplace, shouldUseInpaintReplace } = currentCanvas;
canvasSelector,
(canvas) => {
const { inpaintReplace, shouldUseInpaintReplace } = canvas;
return {
inpaintReplace,
shouldUseInpaintReplace,

View File

@ -8,7 +8,7 @@ import ImageUploadButton from 'common/components/ImageUploaderButton';
import CurrentImageDisplay from 'features/gallery/CurrentImageDisplay';
import { OptionsState } from 'features/options/optionsSlice';
import {
baseCanvasImageSelector,
initialCanvasImageSelector,
CanvasState,
setDoesCanvasNeedScaling,
} from 'features/canvas/canvasSlice';
@ -16,17 +16,17 @@ import IAICanvas from 'features/canvas/IAICanvas';
const inpaintingDisplaySelector = createSelector(
[
baseCanvasImageSelector,
initialCanvasImageSelector,
(state: RootState) => state.canvas,
(state: RootState) => state.options,
],
(baseCanvasImage, canvas: CanvasState, options: OptionsState) => {
(initialCanvasImage, canvas: CanvasState, options: OptionsState) => {
const { doesCanvasNeedScaling } = canvas;
const { showDualDisplay } = options;
return {
doesCanvasNeedScaling,
showDualDisplay,
baseCanvasImage,
initialCanvasImage,
};
},
{
@ -38,7 +38,7 @@ const inpaintingDisplaySelector = createSelector(
const InpaintingDisplay = () => {
const dispatch = useAppDispatch();
const { showDualDisplay, doesCanvasNeedScaling, baseCanvasImage } =
const { showDualDisplay, doesCanvasNeedScaling, initialCanvasImage } =
useAppSelector(inpaintingDisplaySelector);
useLayoutEffect(() => {
@ -50,7 +50,7 @@ const InpaintingDisplay = () => {
return () => window.removeEventListener('resize', resizeCallback);
}, [dispatch]);
const inpaintingComponent = baseCanvasImage ? (
const inpaintingComponent = initialCanvasImage ? (
<div className="inpainting-main-area">
<IAICanvasControls />
<div className="inpainting-canvas-area">

View File

@ -3,12 +3,11 @@ import InpaintingDisplay from './InpaintingDisplay';
import InvokeWorkarea from 'features/tabs/InvokeWorkarea';
import { useAppDispatch } from 'app/store';
import { useEffect } from 'react';
import { setCurrentCanvas, setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
export default function InpaintingWorkarea() {
const dispatch = useAppDispatch();
useEffect(() => {
dispatch(setCurrentCanvas('inpainting'));
dispatch(setDoesCanvasNeedScaling(true));
}, [dispatch]);
return (

View File

@ -3,23 +3,21 @@ import { createSelector } from '@reduxjs/toolkit';
import IAICanvasResizer from 'features/canvas/IAICanvasResizer';
import _ from 'lodash';
import { useLayoutEffect } from 'react';
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
import { useAppDispatch, useAppSelector } from 'app/store';
import ImageUploadButton from 'common/components/ImageUploaderButton';
import {
CanvasState,
canvasSelector,
setDoesCanvasNeedScaling,
} from 'features/canvas/canvasSlice';
import IAICanvas from 'features/canvas/IAICanvas';
import IAICanvasOutpaintingControls from 'features/canvas/IAICanvasOutpaintingControls';
const outpaintingDisplaySelector = createSelector(
[(state: RootState) => state.canvas],
(canvas: CanvasState) => {
[canvasSelector],
(canvas) => {
const {
doesCanvasNeedScaling,
outpainting: {
layerState: { objects },
},
layerState: { objects },
} = canvas;
return {
doesCanvasNeedScaling,

View File

@ -3,12 +3,11 @@ import OutpaintingDisplay from './OutpaintingDisplay';
import InvokeWorkarea from 'features/tabs/InvokeWorkarea';
import { useAppDispatch } from 'app/store';
import { useEffect } from 'react';
import { setCurrentCanvas, setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
export default function OutpaintingWorkarea() {
const dispatch = useAppDispatch();
useEffect(() => {
dispatch(setCurrentCanvas('outpainting'));
dispatch(setDoesCanvasNeedScaling(true));
}, [dispatch]);
return (