mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): display canvas generation mode in status text
- use the existing logic to determine if generation is txt2img, img2img, inpaint or outpaint - technically `outpaint` and `inpaint` are the same, just display "Inpaint" if its either - debounce this by 1s to prevent jank
This commit is contained in:
parent
00d3cd4aed
commit
28031ead70
@ -40,7 +40,7 @@ export const addUserInvokedCanvasListener = () => {
|
|||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
// Build canvas blobs
|
// Build canvas blobs
|
||||||
const canvasBlobsAndImageData = await getCanvasData(state);
|
const canvasBlobsAndImageData = await getCanvasData(state.canvas);
|
||||||
|
|
||||||
if (!canvasBlobsAndImageData) {
|
if (!canvasBlobsAndImageData) {
|
||||||
log.error('Unable to create canvas data');
|
log.error('Unable to create canvas data');
|
||||||
|
@ -2,8 +2,8 @@ import { Box, Flex } from '@chakra-ui/react';
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
|
import GenerationModeStatusText from 'features/parameters/components/Parameters/Canvas/GenerationModeStatusText';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import roundToHundreth from '../util/roundToHundreth';
|
import roundToHundreth from '../util/roundToHundreth';
|
||||||
import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusTextCursorPos';
|
import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusTextCursorPos';
|
||||||
@ -110,6 +110,7 @@ const IAICanvasStatusText = () => {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<GenerationModeStatusText />
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
color: activeLayerColor,
|
color: activeLayerColor,
|
||||||
|
@ -2,7 +2,15 @@ import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||||
|
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||||
import { useSingleAndDoubleClick } from 'common/hooks/useSingleAndDoubleClick';
|
import { useSingleAndDoubleClick } from 'common/hooks/useSingleAndDoubleClick';
|
||||||
|
import {
|
||||||
|
canvasCopiedToClipboard,
|
||||||
|
canvasDownloadedAsImage,
|
||||||
|
canvasMerged,
|
||||||
|
canvasSavedToGallery,
|
||||||
|
} from 'features/canvas/store/actions';
|
||||||
import {
|
import {
|
||||||
canvasSelector,
|
canvasSelector,
|
||||||
isStagingSelector,
|
isStagingSelector,
|
||||||
@ -21,16 +29,8 @@ import {
|
|||||||
} from 'features/canvas/store/canvasTypes';
|
} from 'features/canvas/store/canvasTypes';
|
||||||
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
||||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||||
|
import { useCopyImageToClipboard } from 'features/ui/hooks/useCopyImageToClipboard';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
|
||||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
|
||||||
import {
|
|
||||||
canvasCopiedToClipboard,
|
|
||||||
canvasDownloadedAsImage,
|
|
||||||
canvasMerged,
|
|
||||||
canvasSavedToGallery,
|
|
||||||
} from 'features/canvas/store/actions';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
@ -48,7 +48,6 @@ import IAICanvasRedoButton from './IAICanvasRedoButton';
|
|||||||
import IAICanvasSettingsButtonPopover from './IAICanvasSettingsButtonPopover';
|
import IAICanvasSettingsButtonPopover from './IAICanvasSettingsButtonPopover';
|
||||||
import IAICanvasToolChooserOptions from './IAICanvasToolChooserOptions';
|
import IAICanvasToolChooserOptions from './IAICanvasToolChooserOptions';
|
||||||
import IAICanvasUndoButton from './IAICanvasUndoButton';
|
import IAICanvasUndoButton from './IAICanvasUndoButton';
|
||||||
import { useCopyImageToClipboard } from 'features/ui/hooks/useCopyImageToClipboard';
|
|
||||||
|
|
||||||
export const selector = createSelector(
|
export const selector = createSelector(
|
||||||
[systemSelector, canvasSelector, isStagingSelector],
|
[systemSelector, canvasSelector, isStagingSelector],
|
||||||
@ -220,7 +219,7 @@ const IAICanvasToolbar = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box w={24}>
|
<Box w={24}>
|
||||||
<IAIMantineSearchableSelect
|
<IAIMantineSelect
|
||||||
tooltip={`${t('unifiedCanvas.layer')} (Q)`}
|
tooltip={`${t('unifiedCanvas.layer')} (Q)`}
|
||||||
value={layer}
|
value={layer}
|
||||||
data={LAYER_NAMES_DICT}
|
data={LAYER_NAMES_DICT}
|
||||||
|
@ -30,6 +30,7 @@ import {
|
|||||||
CanvasState,
|
CanvasState,
|
||||||
CanvasTool,
|
CanvasTool,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
|
GenerationMode,
|
||||||
isCanvasAnyLine,
|
isCanvasAnyLine,
|
||||||
isCanvasBaseImage,
|
isCanvasBaseImage,
|
||||||
isCanvasMaskLine,
|
isCanvasMaskLine,
|
||||||
@ -858,6 +859,9 @@ export const canvasSlice = createSlice({
|
|||||||
state.isMovingBoundingBox = false;
|
state.isMovingBoundingBox = false;
|
||||||
state.isTransformingBoundingBox = false;
|
state.isTransformingBoundingBox = false;
|
||||||
},
|
},
|
||||||
|
generationModeChanged: (state, action: PayloadAction<GenerationMode>) => {
|
||||||
|
state.generationMode = action.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder.addCase(sessionCanceled.pending, (state) => {
|
builder.addCase(sessionCanceled.pending, (state) => {
|
||||||
@ -955,6 +959,7 @@ export const {
|
|||||||
stagingAreaInitialized,
|
stagingAreaInitialized,
|
||||||
canvasSessionIdChanged,
|
canvasSessionIdChanged,
|
||||||
setShouldAntialias,
|
setShouldAntialias,
|
||||||
|
generationModeChanged,
|
||||||
} = canvasSlice.actions;
|
} = canvasSlice.actions;
|
||||||
|
|
||||||
export default canvasSlice.reducer;
|
export default canvasSlice.reducer;
|
||||||
|
@ -168,4 +168,7 @@ export interface CanvasState {
|
|||||||
stageDimensions: Dimensions;
|
stageDimensions: Dimensions;
|
||||||
stageScale: number;
|
stageScale: number;
|
||||||
tool: CanvasTool;
|
tool: CanvasTool;
|
||||||
|
generationMode?: GenerationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GenerationMode = 'txt2img' | 'img2img' | 'inpaint' | 'outpaint';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
import { RootState } from 'app/store/store';
|
import { CanvasState, isCanvasMaskLine } from '../store/canvasTypes';
|
||||||
import { isCanvasMaskLine } from '../store/canvasTypes';
|
|
||||||
import createMaskStage from './createMaskStage';
|
import createMaskStage from './createMaskStage';
|
||||||
import { getCanvasBaseLayer, getCanvasStage } from './konvaInstanceProvider';
|
import { getCanvasBaseLayer, getCanvasStage } from './konvaInstanceProvider';
|
||||||
import { konvaNodeToBlob } from './konvaNodeToBlob';
|
import { konvaNodeToBlob } from './konvaNodeToBlob';
|
||||||
@ -9,7 +8,7 @@ import { konvaNodeToImageData } from './konvaNodeToImageData';
|
|||||||
/**
|
/**
|
||||||
* Gets Blob and ImageData objects for the base and mask layers
|
* Gets Blob and ImageData objects for the base and mask layers
|
||||||
*/
|
*/
|
||||||
export const getCanvasData = async (state: RootState) => {
|
export const getCanvasData = async (canvasState: CanvasState) => {
|
||||||
const log = logger('canvas');
|
const log = logger('canvas');
|
||||||
|
|
||||||
const canvasBaseLayer = getCanvasBaseLayer();
|
const canvasBaseLayer = getCanvasBaseLayer();
|
||||||
@ -26,7 +25,7 @@ export const getCanvasData = async (state: RootState) => {
|
|||||||
boundingBoxDimensions,
|
boundingBoxDimensions,
|
||||||
isMaskEnabled,
|
isMaskEnabled,
|
||||||
shouldPreserveMaskedArea,
|
shouldPreserveMaskedArea,
|
||||||
} = state.canvas;
|
} = canvasState;
|
||||||
|
|
||||||
const boundingBox = {
|
const boundingBox = {
|
||||||
...boundingBoxCoordinates,
|
...boundingBoxCoordinates,
|
||||||
|
@ -2,11 +2,12 @@ import {
|
|||||||
areAnyPixelsBlack,
|
areAnyPixelsBlack,
|
||||||
getImageDataTransparency,
|
getImageDataTransparency,
|
||||||
} from 'common/util/arrayBuffer';
|
} from 'common/util/arrayBuffer';
|
||||||
|
import { GenerationMode } from '../store/canvasTypes';
|
||||||
|
|
||||||
export const getCanvasGenerationMode = (
|
export const getCanvasGenerationMode = (
|
||||||
baseImageData: ImageData,
|
baseImageData: ImageData,
|
||||||
maskImageData: ImageData
|
maskImageData: ImageData
|
||||||
) => {
|
): GenerationMode => {
|
||||||
const {
|
const {
|
||||||
isPartiallyTransparent: baseIsPartiallyTransparent,
|
isPartiallyTransparent: baseIsPartiallyTransparent,
|
||||||
isFullyTransparent: baseIsFullyTransparent,
|
isFullyTransparent: baseIsFullyTransparent,
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { generationModeChanged } from 'features/canvas/store/canvasSlice';
|
||||||
|
import { getCanvasData } from 'features/canvas/util/getCanvasData';
|
||||||
|
import { getCanvasGenerationMode } from 'features/canvas/util/getCanvasGenerationMode';
|
||||||
|
import { useDebounce } from 'react-use';
|
||||||
|
|
||||||
|
const GENERATION_MODE_NAME_MAP = {
|
||||||
|
txt2img: 'Text to Image',
|
||||||
|
img2img: 'Image to Image',
|
||||||
|
inpaint: 'Inpaint',
|
||||||
|
outpaint: 'Inpaint',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGenerationMode = () => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const canvasState = useAppSelector((state) => state.canvas);
|
||||||
|
|
||||||
|
useDebounce(
|
||||||
|
async () => {
|
||||||
|
// Build canvas blobs
|
||||||
|
const canvasBlobsAndImageData = await getCanvasData(canvasState);
|
||||||
|
|
||||||
|
if (!canvasBlobsAndImageData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { baseImageData, maskImageData } = canvasBlobsAndImageData;
|
||||||
|
|
||||||
|
// Determine the generation mode
|
||||||
|
const generationMode = getCanvasGenerationMode(
|
||||||
|
baseImageData,
|
||||||
|
maskImageData
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(generationModeChanged(generationMode));
|
||||||
|
},
|
||||||
|
1000,
|
||||||
|
[dispatch, canvasState, generationModeChanged]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const GenerationModeStatusText = () => {
|
||||||
|
const generationMode = useAppSelector((state) => state.canvas.generationMode);
|
||||||
|
|
||||||
|
useGenerationMode();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
Mode: {generationMode ? GENERATION_MODE_NAME_MAP[generationMode] : '...'}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GenerationModeStatusText;
|
Loading…
Reference in New Issue
Block a user