feat(ui): add hooks for new layer/canvas from image & use them

This commit is contained in:
psychedelicious
2024-10-10 19:17:16 +10:00
committed by Kent Keirsey
parent 8522129639
commit 9e6fb3bd3f
3 changed files with 61 additions and 41 deletions

View File

@@ -3,6 +3,7 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { deepClone } from 'common/util/deepClone';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import { canvasReset } from 'features/controlLayers/store/actions';
import {
controlLayerAdded,
inpaintMaskAdded,
@@ -14,19 +15,25 @@ import {
rgPositivePromptChanged,
} from 'features/controlLayers/store/canvasSlice';
import { selectBase } from 'features/controlLayers/store/paramsSlice';
import { selectCanvasSlice, selectEntityOrThrow } from 'features/controlLayers/store/selectors';
import { selectBboxRect, selectCanvasSlice, selectEntityOrThrow } from 'features/controlLayers/store/selectors';
import type {
CanvasEntityIdentifier,
CanvasRasterLayerState,
CanvasRegionalGuidanceState,
ControlNetConfig,
IPAdapterConfig,
T2IAdapterConfig,
} from 'features/controlLayers/store/types';
import { initialControlNet, initialIPAdapter, initialT2IAdapter } from 'features/controlLayers/store/util';
import {
imageDTOToImageObject,
initialControlNet,
initialIPAdapter,
initialT2IAdapter,
} from 'features/controlLayers/store/util';
import { zModelIdentifierField } from 'features/nodes/types/common';
import { useCallback } from 'react';
import { modelConfigsAdapterSelectors, selectModelConfigsQuery } from 'services/api/endpoints/models';
import type { ControlNetModelConfig, IPAdapterModelConfig, T2IAdapterModelConfig } from 'services/api/types';
import type { ControlNetModelConfig, ImageDTO, IPAdapterModelConfig, T2IAdapterModelConfig } from 'services/api/types';
import { isControlNetOrT2IAdapterModelConfig, isIPAdapterModelConfig } from 'services/api/types';
export const selectDefaultControlAdapter = createSelector(
@@ -90,6 +97,43 @@ export const useAddRasterLayer = () => {
return func;
};
export const useNewRasterLayerFromImage = () => {
const dispatch = useAppDispatch();
const bboxRect = useAppSelector(selectBboxRect);
const func = useCallback(
(imageDTO: ImageDTO) => {
const imageObject = imageDTOToImageObject(imageDTO);
const overrides: Partial<CanvasRasterLayerState> = {
position: { x: bboxRect.x, y: bboxRect.y },
objects: [imageObject],
};
dispatch(rasterLayerAdded({ overrides, isSelected: true }));
},
[bboxRect.x, bboxRect.y, dispatch]
);
return func;
};
export const useNewCanvasFromImage = () => {
const dispatch = useAppDispatch();
const bboxRect = useAppSelector(selectBboxRect);
const func = useCallback(
(imageDTO: ImageDTO) => {
const imageObject = imageDTOToImageObject(imageDTO);
const overrides: Partial<CanvasRasterLayerState> = {
position: { x: bboxRect.x, y: bboxRect.y },
objects: [imageObject],
};
dispatch(canvasReset());
dispatch(rasterLayerAdded({ overrides, isSelected: true }));
},
[bboxRect.x, bboxRect.y, dispatch]
);
return func;
};
export const useAddInpaintMask = () => {
const dispatch = useAppDispatch();
const func = useCallback(() => {

View File

@@ -1,11 +1,6 @@
import { MenuItem } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { canvasReset } from 'features/controlLayers/store/actions';
import { rasterLayerAdded } from 'features/controlLayers/store/canvasSlice';
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import type { CanvasRasterLayerState } from 'features/controlLayers/store/types';
import { imageDTOToImageObject } from 'features/controlLayers/store/util';
import { useAppDispatch } from 'app/store/storeHooks';
import { useNewCanvasFromImage } from 'features/controlLayers/hooks/addLayerHooks';
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
import { useImageDTOContext } from 'features/gallery/contexts/ImageDTOContext';
import { toast } from 'features/toast/toast';
@@ -14,23 +9,15 @@ import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiFileBold } from 'react-icons/pi';
const selectBboxRect = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect);
export const ImageMenuItemNewCanvasFromImage = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const imageDTO = useImageDTOContext();
const bboxRect = useAppSelector(selectBboxRect);
const imageViewer = useImageViewer();
const newCanvasFromImage = useNewCanvasFromImage();
const handleSendToCanvas = useCallback(() => {
const imageObject = imageDTOToImageObject(imageDTO);
const overrides: Partial<CanvasRasterLayerState> = {
position: { x: bboxRect.x, y: bboxRect.y },
objects: [imageObject],
};
dispatch(canvasReset());
dispatch(rasterLayerAdded({ overrides, isSelected: true }));
const onClick = useCallback(() => {
newCanvasFromImage(imageDTO);
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({
@@ -38,10 +25,10 @@ export const ImageMenuItemNewCanvasFromImage = memo(() => {
title: t('toast.sentToCanvas'),
status: 'success',
});
}, [bboxRect.x, bboxRect.y, dispatch, imageDTO, imageViewer, t]);
}, [dispatch, imageDTO, imageViewer, newCanvasFromImage, t]);
return (
<MenuItem icon={<PiFileBold />} onClickCapture={handleSendToCanvas}>
<MenuItem icon={<PiFileBold />} onClickCapture={onClick}>
{t('controlLayers.newCanvasFromImage')}
</MenuItem>
);

View File

@@ -1,11 +1,7 @@
import { MenuItem } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useAppDispatch } from 'app/store/storeHooks';
import { NewLayerIcon } from 'features/controlLayers/components/common/icons';
import { rasterLayerAdded } from 'features/controlLayers/store/canvasSlice';
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import type { CanvasRasterLayerState } from 'features/controlLayers/store/types';
import { imageDTOToImageObject } from 'features/controlLayers/store/util';
import { useNewRasterLayerFromImage } from 'features/controlLayers/hooks/addLayerHooks';
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
import { useImageDTOContext } from 'features/gallery/contexts/ImageDTOContext';
import { sentImageToCanvas } from 'features/gallery/store/actions';
@@ -14,23 +10,16 @@ import { setActiveTab } from 'features/ui/store/uiSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
const selectBboxRect = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect);
export const ImageMenuItemNewLayerFromImage = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const imageDTO = useImageDTOContext();
const bboxRect = useAppSelector(selectBboxRect);
const imageViewer = useImageViewer();
const newRasterLayerFromImage = useNewRasterLayerFromImage();
const handleSendToCanvas = useCallback(() => {
const imageObject = imageDTOToImageObject(imageDTO);
const overrides: Partial<CanvasRasterLayerState> = {
position: { x: bboxRect.x, y: bboxRect.y },
objects: [imageObject],
};
const onClick = useCallback(() => {
dispatch(sentImageToCanvas());
dispatch(rasterLayerAdded({ overrides, isSelected: true }));
newRasterLayerFromImage(imageDTO);
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({
@@ -38,10 +27,10 @@ export const ImageMenuItemNewLayerFromImage = memo(() => {
title: t('toast.sentToCanvas'),
status: 'success',
});
}, [bboxRect.x, bboxRect.y, dispatch, imageDTO, imageViewer, t]);
}, [dispatch, imageDTO, imageViewer, newRasterLayerFromImage, t]);
return (
<MenuItem icon={<NewLayerIcon />} onClickCapture={handleSendToCanvas}>
<MenuItem icon={<NewLayerIcon />} onClickCapture={onClick}>
{t('controlLayers.newLayerFromImage')}
</MenuItem>
);