mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): drop image on layer to replace it
This commit is contained in:
committed by
Kent Keirsey
parent
5b8707a74f
commit
5a89bf841f
@@ -1781,6 +1781,7 @@
|
||||
"flipHorizontal": "Flip Horizontal",
|
||||
"flipVertical": "Flip Vertical",
|
||||
"stagingOnCanvas": "Staging images on",
|
||||
"replaceLayer": "Replace Layer",
|
||||
"fill": {
|
||||
"fillColor": "Fill Color",
|
||||
"fillStyle": "Fill Style",
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'
|
||||
import { selectDefaultControlAdapter } from 'features/controlLayers/hooks/addLayerHooks';
|
||||
import {
|
||||
controlLayerAdded,
|
||||
entityRasterized,
|
||||
ipaImageChanged,
|
||||
rasterLayerAdded,
|
||||
rgIPAdapterImageChanged,
|
||||
@@ -117,6 +118,18 @@ export const addImageDroppedListener = (startAppListening: AppStartListening) =>
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image dropped on Raster layer
|
||||
*/
|
||||
if (overData.actionType === 'REPLACE_LAYER_WITH_IMAGE' && activeData.payloadType === 'IMAGE_DTO') {
|
||||
const state = getState();
|
||||
const { entityIdentifier } = overData.context;
|
||||
const imageObject = imageDTOToImageObject(activeData.payload.imageDTO);
|
||||
const { x, y } = selectCanvasSlice(state).bbox.rect;
|
||||
dispatch(entityRasterized({ entityIdentifier, imageObject, position: { x, y }, replaceObjects: true }));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image dropped on node image field
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Spacer } from '@invoke-ai/ui-library';
|
||||
import IAIDroppable from 'common/components/IAIDroppable';
|
||||
import { CanvasEntityContainer } from 'features/controlLayers/components/common/CanvasEntityContainer';
|
||||
import { CanvasEntityHeader } from 'features/controlLayers/components/common/CanvasEntityHeader';
|
||||
import { CanvasEntityHeaderCommonActions } from 'features/controlLayers/components/common/CanvasEntityHeaderCommonActions';
|
||||
@@ -10,15 +11,24 @@ import { ControlLayerControlAdapter } from 'features/controlLayers/components/Co
|
||||
import { ControlLayerAdapterGate } from 'features/controlLayers/contexts/EntityAdapterContext';
|
||||
import { EntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
|
||||
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import type { ReplaceLayerImageDropData } from 'features/dnd/types';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const ControlLayer = memo(({ id }: Props) => {
|
||||
const entityIdentifier = useMemo<CanvasEntityIdentifier>(() => ({ id, type: 'control_layer' }), [id]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const entityIdentifier = useMemo<CanvasEntityIdentifier<'control_layer'>>(
|
||||
() => ({ id, type: 'control_layer' }),
|
||||
[id]
|
||||
);
|
||||
const dropData = useMemo<ReplaceLayerImageDropData>(
|
||||
() => ({ id, actionType: 'REPLACE_LAYER_WITH_IMAGE', context: { entityIdentifier } }),
|
||||
[id, entityIdentifier]
|
||||
);
|
||||
return (
|
||||
<EntityIdentifierContext.Provider value={entityIdentifier}>
|
||||
<ControlLayerAdapterGate>
|
||||
@@ -33,6 +43,7 @@ export const ControlLayer = memo(({ id }: Props) => {
|
||||
<CanvasEntitySettingsWrapper>
|
||||
<ControlLayerControlAdapter />
|
||||
</CanvasEntitySettingsWrapper>
|
||||
<IAIDroppable data={dropData} dropLabel={t('controlLayers.replaceLayer')} />
|
||||
</CanvasEntityContainer>
|
||||
</ControlLayerAdapterGate>
|
||||
</EntityIdentifierContext.Provider>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Spacer } from '@invoke-ai/ui-library';
|
||||
import IAIDroppable from 'common/components/IAIDroppable';
|
||||
import { CanvasEntityContainer } from 'features/controlLayers/components/common/CanvasEntityContainer';
|
||||
import { CanvasEntityHeader } from 'features/controlLayers/components/common/CanvasEntityHeader';
|
||||
import { CanvasEntityHeaderCommonActions } from 'features/controlLayers/components/common/CanvasEntityHeaderCommonActions';
|
||||
@@ -7,14 +8,21 @@ import { CanvasEntityEditableTitle } from 'features/controlLayers/components/com
|
||||
import { RasterLayerAdapterGate } from 'features/controlLayers/contexts/EntityAdapterContext';
|
||||
import { EntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
|
||||
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import type { ReplaceLayerImageDropData } from 'features/dnd/types';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const RasterLayer = memo(({ id }: Props) => {
|
||||
const entityIdentifier = useMemo<CanvasEntityIdentifier>(() => ({ id, type: 'raster_layer' }), [id]);
|
||||
const { t } = useTranslation();
|
||||
const entityIdentifier = useMemo<CanvasEntityIdentifier<'raster_layer'>>(() => ({ id, type: 'raster_layer' }), [id]);
|
||||
const dropData = useMemo<ReplaceLayerImageDropData>(
|
||||
() => ({ id, actionType: 'REPLACE_LAYER_WITH_IMAGE', context: { entityIdentifier } }),
|
||||
[id, entityIdentifier]
|
||||
);
|
||||
|
||||
return (
|
||||
<EntityIdentifierContext.Provider value={entityIdentifier}>
|
||||
@@ -26,6 +34,7 @@ export const RasterLayer = memo(({ id }: Props) => {
|
||||
<Spacer />
|
||||
<CanvasEntityHeaderCommonActions />
|
||||
</CanvasEntityHeader>
|
||||
<IAIDroppable data={dropData} dropLabel={t('controlLayers.replaceLayer')} />
|
||||
</CanvasEntityContainer>
|
||||
</RasterLayerAdapterGate>
|
||||
</EntityIdentifierContext.Provider>
|
||||
|
||||
@@ -21,6 +21,7 @@ export const CanvasEntityContainer = memo((props: PropsWithChildren) => {
|
||||
|
||||
return (
|
||||
<Flex
|
||||
position="relative"
|
||||
flexDir="column"
|
||||
w="full"
|
||||
bg={isSelected ? 'base.800' : 'base.850'}
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
useDroppable as useOriginalDroppable,
|
||||
UseDroppableArguments,
|
||||
} from '@dnd-kit/core';
|
||||
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import type { BoardId } from 'features/gallery/store/types';
|
||||
import type { FieldInputInstance, FieldInputTemplate } from 'features/nodes/types/field';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
@@ -41,6 +42,13 @@ export type AddControlLayerFromImageDropData = BaseDropData & {
|
||||
actionType: 'ADD_CONTROL_LAYER_FROM_IMAGE';
|
||||
};
|
||||
|
||||
export type ReplaceLayerImageDropData = BaseDropData & {
|
||||
actionType: 'REPLACE_LAYER_WITH_IMAGE';
|
||||
context: {
|
||||
entityIdentifier: CanvasEntityIdentifier<'control_layer' | 'raster_layer'>;
|
||||
};
|
||||
};
|
||||
|
||||
type UpscaleInitialImageDropData = BaseDropData & {
|
||||
actionType: 'SET_UPSCALE_INITIAL_IMAGE';
|
||||
};
|
||||
@@ -79,7 +87,8 @@ export type TypesafeDroppableData =
|
||||
| SelectForCompareDropData
|
||||
| UpscaleInitialImageDropData
|
||||
| AddRasterLayerFromImageDropData
|
||||
| AddControlLayerFromImageDropData;
|
||||
| AddControlLayerFromImageDropData
|
||||
| ReplaceLayerImageDropData;
|
||||
|
||||
type BaseDragData = {
|
||||
id: string;
|
||||
|
||||
@@ -20,6 +20,7 @@ export const isValidDrop = (overData?: TypesafeDroppableData | null, activeData?
|
||||
case 'SET_UPSCALE_INITIAL_IMAGE':
|
||||
case 'SET_NODES_IMAGE':
|
||||
case 'SELECT_FOR_COMPARE':
|
||||
case 'REPLACE_LAYER_WITH_IMAGE':
|
||||
return payloadType === 'IMAGE_DTO';
|
||||
case 'ADD_TO_BOARD': {
|
||||
// If the board is the same, don't allow the drop
|
||||
|
||||
Reference in New Issue
Block a user