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

View File

@ -20,7 +20,7 @@ import {
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';
import { baseCanvasImageSelector } from 'features/canvas/canvasSlice'; import { initialCanvasImageSelector } from 'features/canvas/canvasSlice';
/** /**
* Returns an object containing all functions which use `socketio.emit()`. * Returns an object containing all functions which use `socketio.emit()`.
@ -55,8 +55,8 @@ const makeSocketIOEmitters = (
}; };
if (generationMode === 'inpainting') { if (generationMode === 'inpainting') {
const baseCanvasImage = baseCanvasImageSelector(getState()); const initialCanvasImage = initialCanvasImageSelector(getState());
const imageUrl = baseCanvasImage?.image.url; const imageUrl = initialCanvasImage?.image.url;
if (!imageUrl) { if (!imageUrl) {
dispatch( dispatch(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,17 +2,16 @@ import { FaLock, FaUnlock } from 'react-icons/fa';
import { 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, canvasSelector,
GenericCanvasState,
setShouldLockBoundingBox, setShouldLockBoundingBox,
} from 'features/canvas/canvasSlice'; } from 'features/canvas/canvasSlice';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import _ from 'lodash'; import _ from 'lodash';
const canvasLockBoundingBoxSelector = createSelector( const canvasLockBoundingBoxSelector = createSelector(
currentCanvasSelector, canvasSelector,
(currentCanvas: GenericCanvasState) => { (canvas) => {
const { shouldLockBoundingBox } = currentCanvas; const { shouldLockBoundingBox } = canvas;
return { return {
shouldLockBoundingBox, shouldLockBoundingBox,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,17 +2,16 @@ import { FaVectorSquare } from 'react-icons/fa';
import { 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, canvasSelector,
GenericCanvasState,
setShouldShowBoundingBox, setShouldShowBoundingBox,
} from 'features/canvas/canvasSlice'; } from 'features/canvas/canvasSlice';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import _ from 'lodash'; import _ from 'lodash';
const canvasShowHideBoundingBoxControlSelector = createSelector( const canvasShowHideBoundingBoxControlSelector = createSelector(
currentCanvasSelector, canvasSelector,
(currentCanvas: GenericCanvasState) => { (canvas) => {
const { shouldShowBoundingBox } = currentCanvas; const { shouldShowBoundingBox } = canvas;
return { return {
shouldShowBoundingBox, shouldShowBoundingBox,

View File

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

View File

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

View File

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

View File

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

View File

@ -2,21 +2,16 @@ 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 { Rect } from 'react-konva'; import { Rect } from 'react-konva';
import { import { canvasSelector } from './canvasSlice';
currentCanvasSelector,
InpaintingCanvasState,
OutpaintingCanvasState,
} from './canvasSlice';
import { rgbaColorToString } from './util/colorToString'; import { rgbaColorToString } from './util/colorToString';
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import Konva from 'konva'; import Konva from 'konva';
export const canvasMaskCompositerSelector = createSelector( export const canvasMaskCompositerSelector = createSelector(
currentCanvasSelector, canvasSelector,
(currentCanvas) => { (canvas) => {
const { maskColor, stageCoordinates, stageDimensions, stageScale } = const { maskColor, stageCoordinates, stageDimensions, stageScale } = canvas;
currentCanvas as InpaintingCanvasState | OutpaintingCanvasState;
return { return {
stageCoordinates, stageCoordinates,

View File

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

View File

@ -1,12 +1,9 @@
import { createSelector, current } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { 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 {
baseCanvasImageSelector, canvasSelector,
// canvasClipSelector,
// canvasModeSelector,
currentCanvasSelector,
isCanvasBaseImage, isCanvasBaseImage,
isCanvasBaseLine, isCanvasBaseLine,
} from './canvasSlice'; } from './canvasSlice';
@ -14,9 +11,9 @@ import IAICanvasImage from './IAICanvasImage';
import { rgbaColorToString } from './util/colorToString'; import { rgbaColorToString } from './util/colorToString';
const selector = createSelector( const selector = createSelector(
[currentCanvasSelector], [canvasSelector],
(currentCanvas) => { (canvas) => {
const { objects } = currentCanvas.layerState; const { objects } = canvas.layerState;
return { return {
objects, objects,

View File

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

View File

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

View File

@ -1,8 +1,7 @@
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { import {
currentCanvasSelector, canvasSelector,
outpaintingCanvasSelector,
setShouldAutoSave, setShouldAutoSave,
setShouldDarkenOutsideBoundingBox, setShouldDarkenOutsideBoundingBox,
setShouldShowGrid, setShouldShowGrid,
@ -17,13 +16,15 @@ import IAIPopover from 'common/components/IAIPopover';
import IAICheckbox from 'common/components/IAICheckbox'; import IAICheckbox from 'common/components/IAICheckbox';
export const canvasControlsSelector = createSelector( export const canvasControlsSelector = createSelector(
[currentCanvasSelector, outpaintingCanvasSelector], [canvasSelector],
(currentCanvas, outpaintingCanvas) => { (canvas) => {
const { shouldDarkenOutsideBoundingBox, shouldShowIntermediates } = const {
currentCanvas; shouldDarkenOutsideBoundingBox,
shouldShowIntermediates,
const { shouldShowGrid, shouldSnapToGrid, shouldAutoSave } = shouldShowGrid,
outpaintingCanvas; shouldSnapToGrid,
shouldAutoSave,
} = canvas;
return { return {
shouldShowGrid, 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 { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store'; 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 { GroupConfig } from 'konva/lib/Group';
import _ from 'lodash'; import _ from 'lodash';
import { emotionCache } from 'main';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import {
FaArrowLeft,
FaArrowRight,
FaCheck,
FaEye,
FaEyeSlash,
FaTrash,
} from 'react-icons/fa';
import { Group, Rect } from 'react-konva'; import { Group, Rect } from 'react-konva';
import { Html } from 'react-konva-utils'; import { canvasSelector } from './canvasSlice';
import {
commitStagingAreaImage,
currentCanvasSelector,
discardStagedImages,
nextStagingAreaImage,
prevStagingAreaImage,
} from './canvasSlice';
import IAICanvasImage from './IAICanvasImage'; import IAICanvasImage from './IAICanvasImage';
const selector = createSelector( const selector = createSelector(
[currentCanvasSelector], [canvasSelector],
(currentCanvas) => { (canvas) => {
const { const {
layerState: { layerState: {
stagingArea: { images, selectedImageIndex }, stagingArea: { images, selectedImageIndex },
}, },
} = currentCanvas; } = canvas;
return { return {
currentStagingAreaImage: currentStagingAreaImage:
@ -54,9 +34,7 @@ type Props = GroupConfig;
const IAICanvasStagingArea = (props: Props) => { const IAICanvasStagingArea = (props: Props) => {
const { ...rest } = props; const { ...rest } = props;
const dispatch = useAppDispatch(); const { currentStagingAreaImage } = useAppSelector(selector);
const { isOnFirstImage, isOnLastImage, currentStagingAreaImage } =
useAppSelector(selector);
const [shouldShowStagedImage, setShouldShowStagedImage] = const [shouldShowStagedImage, setShouldShowStagedImage] =
useState<boolean>(true); useState<boolean>(true);
@ -64,14 +42,6 @@ const IAICanvasStagingArea = (props: Props) => {
const [shouldShowStagingAreaOutline, setShouldShowStagingAreaOutline] = const [shouldShowStagingAreaOutline, setShouldShowStagingAreaOutline] =
useState<boolean>(true); useState<boolean>(true);
const handleMouseOver = useCallback(() => {
setShouldShowStagingAreaOutline(false);
}, []);
const handleMouseOut = useCallback(() => {
setShouldShowStagingAreaOutline(true);
}, []);
if (!currentStagingAreaImage) return null; if (!currentStagingAreaImage) return null;
const { const {
@ -106,73 +76,6 @@ const IAICanvasStagingArea = (props: Props) => {
/> />
</Group> </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> </Group>
); );
}; };

View File

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

View File

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

View File

@ -1,71 +1,11 @@
import * as InvokeAI from 'app/invokeai'; import * as InvokeAI from 'app/invokeai';
import { PayloadAction } from '@reduxjs/toolkit'; import { CanvasState, initialLayerState } from './canvasSlice';
import { CanvasState, Dimensions, initialLayerState } from './canvasSlice';
import { Vector2d } from 'konva/lib/types';
import { import {
roundDownToMultiple, roundDownToMultiple,
roundToMultiple, roundToMultiple,
} from 'common/util/roundDownToMultiple'; } from 'common/util/roundDownToMultiple';
import _ from 'lodash'; 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 = ( export const setInitialCanvasImage = (
state: CanvasState, state: CanvasState,
image: InvokeAI.Image 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.pastLayerStates.push(state.layerState);
state.outpainting.layerState = { state.layerState = {
...initialLayerState, ...initialLayerState,
objects: [ objects: [
{ {
@ -105,7 +45,7 @@ export const setInitialCanvasImage = (
}, },
], ],
}; };
state.outpainting.futureLayerStates = []; state.futureLayerStates = [];
state.isCanvasInitialized = false; state.isCanvasInitialized = false;
state.doesCanvasNeedScaling = true; state.doesCanvasNeedScaling = true;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,16 +2,14 @@ import React from 'react';
import { 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, canvasSelector,
GenericCanvasState,
setShouldDarkenOutsideBoundingBox, setShouldDarkenOutsideBoundingBox,
} from 'features/canvas/canvasSlice'; } from 'features/canvas/canvasSlice';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
const selector = createSelector( const selector = createSelector(
currentCanvasSelector, canvasSelector,
(currentCanvas: GenericCanvasState) => (canvas) => canvas.shouldDarkenOutsideBoundingBox
currentCanvas.shouldDarkenOutsideBoundingBox
); );
export default function BoundingBoxDarkenOutside() { export default function BoundingBoxDarkenOutside() {

View File

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

View File

@ -2,14 +2,14 @@ import React from 'react';
import { 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, canvasSelector,
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, canvasSelector,
(currentCanvas) => currentCanvas.shouldLockBoundingBox (canvas) => canvas.shouldLockBoundingBox
); );
export default function BoundingBoxLock() { export default function BoundingBoxLock() {

View File

@ -3,14 +3,14 @@ import { BiHide, BiShow } from 'react-icons/bi';
import { 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, canvasSelector,
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, canvasSelector,
(currentCanvas) => currentCanvas.shouldShowBoundingBox (canvas) => canvas.shouldShowBoundingBox
); );
export default function BoundingBoxVisibility() { export default function BoundingBoxVisibility() {

View File

@ -3,22 +3,20 @@ import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store'; import { useAppDispatch, useAppSelector } from 'app/store';
import IAIButton from 'common/components/IAIButton'; import IAIButton from 'common/components/IAIButton';
import { import {
currentCanvasSelector, canvasSelector,
InpaintingCanvasState,
OutpaintingCanvasState,
setClearBrushHistory, setClearBrushHistory,
} from 'features/canvas/canvasSlice'; } from 'features/canvas/canvasSlice';
import _ from 'lodash'; import _ from 'lodash';
const clearBrushHistorySelector = createSelector( const clearBrushHistorySelector = createSelector(
currentCanvasSelector, canvasSelector,
(currentCanvas) => { (canvas) => {
const { pastLayerStates, futureLayerStates } = currentCanvas as const { pastLayerStates, futureLayerStates } = canvas;
| InpaintingCanvasState
| OutpaintingCanvasState;
return { return {
mayClearBrushHistory: 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 IAISlider from '../../../../common/components/IAISlider';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { import {
currentCanvasSelector, canvasSelector,
GenericCanvasState,
setInpaintReplace, setInpaintReplace,
setShouldUseInpaintReplace, setShouldUseInpaintReplace,
} from 'features/canvas/canvasSlice'; } from 'features/canvas/canvasSlice';
const canvasInpaintReplaceSelector = createSelector( const canvasInpaintReplaceSelector = createSelector(
currentCanvasSelector, canvasSelector,
(currentCanvas: GenericCanvasState) => { (canvas) => {
const { inpaintReplace, shouldUseInpaintReplace } = currentCanvas; const { inpaintReplace, shouldUseInpaintReplace } = canvas;
return { return {
inpaintReplace, inpaintReplace,
shouldUseInpaintReplace, shouldUseInpaintReplace,

View File

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

View File

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

View File

@ -3,23 +3,21 @@ import { createSelector } from '@reduxjs/toolkit';
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 { useAppDispatch, useAppSelector } from 'app/store';
import ImageUploadButton from 'common/components/ImageUploaderButton'; import ImageUploadButton from 'common/components/ImageUploaderButton';
import { import {
CanvasState, canvasSelector,
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], [canvasSelector],
(canvas: CanvasState) => { (canvas) => {
const { const {
doesCanvasNeedScaling, doesCanvasNeedScaling,
outpainting: {
layerState: { objects }, layerState: { objects },
},
} = canvas; } = canvas;
return { return {
doesCanvasNeedScaling, doesCanvasNeedScaling,

View File

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