Skip to content

Commit addb5c4

Browse files
feat(ui): support dnd images onto inpaint mask/rg entities
1 parent a112d2d commit addb5c4

File tree

7 files changed

+108
-5
lines changed

7 files changed

+108
-5
lines changed

invokeai/frontend/web/public/locales/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1935,6 +1935,8 @@
19351935
"newRegionalReferenceImage": "New Regional Reference Image",
19361936
"newControlLayer": "New Control Layer",
19371937
"newRasterLayer": "New Raster Layer",
1938+
"newInpaintMask": "New Inpaint Mask",
1939+
"newRegionalGuidance": "New Regional Guidance",
19381940
"cropCanvasToBbox": "Crop Canvas to Bbox"
19391941
},
19401942
"stagingArea": {

invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
controlLayerAdded,
99
entityRasterized,
1010
entitySelected,
11+
inpaintMaskAdded,
1112
rasterLayerAdded,
1213
referenceImageAdded,
1314
referenceImageIPAdapterImageChanged,
@@ -17,6 +18,7 @@ import {
1718
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
1819
import type {
1920
CanvasControlLayerState,
21+
CanvasInpaintMaskState,
2022
CanvasRasterLayerState,
2123
CanvasReferenceImageState,
2224
CanvasRegionalGuidanceState,
@@ -110,6 +112,46 @@ export const addImageDroppedListener = (startAppListening: AppStartListening) =>
110112
return;
111113
}
112114

115+
/**
116+
117+
/**
118+
* Image dropped on Inpaint Mask
119+
*/
120+
if (
121+
overData.actionType === 'ADD_INPAINT_MASK_FROM_IMAGE' &&
122+
activeData.payloadType === 'IMAGE_DTO' &&
123+
activeData.payload.imageDTO
124+
) {
125+
const imageObject = imageDTOToImageObject(activeData.payload.imageDTO);
126+
const { x, y } = selectCanvasSlice(getState()).bbox.rect;
127+
const overrides: Partial<CanvasInpaintMaskState> = {
128+
objects: [imageObject],
129+
position: { x, y },
130+
};
131+
dispatch(inpaintMaskAdded({ overrides, isSelected: true }));
132+
return;
133+
}
134+
135+
/**
136+
137+
/**
138+
* Image dropped on Regional Guidance
139+
*/
140+
if (
141+
overData.actionType === 'ADD_REGIONAL_GUIDANCE_FROM_IMAGE' &&
142+
activeData.payloadType === 'IMAGE_DTO' &&
143+
activeData.payload.imageDTO
144+
) {
145+
const imageObject = imageDTOToImageObject(activeData.payload.imageDTO);
146+
const { x, y } = selectCanvasSlice(getState()).bbox.rect;
147+
const overrides: Partial<CanvasRegionalGuidanceState> = {
148+
objects: [imageObject],
149+
position: { x, y },
150+
};
151+
dispatch(rgAdded({ overrides, isSelected: true }));
152+
return;
153+
}
154+
113155
/**
114156
* Image dropped on Raster layer
115157
*/

invokeai/frontend/web/src/features/controlLayers/components/CanvasDropArea.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import IAIDroppable from 'common/components/IAIDroppable';
33
import type {
44
AddControlLayerFromImageDropData,
55
AddGlobalReferenceImageFromImageDropData,
6+
AddInpaintMaskFromImageDropData,
67
AddRasterLayerFromImageDropData,
8+
AddRegionalGuidanceFromImageDropData,
79
AddRegionalReferenceImageFromImageDropData,
810
} from 'features/dnd/types';
911
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
@@ -20,6 +22,16 @@ const addControlLayerFromImageDropData: AddControlLayerFromImageDropData = {
2022
actionType: 'ADD_CONTROL_LAYER_FROM_IMAGE',
2123
};
2224

25+
const addInpaintMaskFromImageDropData: AddInpaintMaskFromImageDropData = {
26+
id: 'add-inpaint-mask-from-image-drop-data',
27+
actionType: 'ADD_INPAINT_MASK_FROM_IMAGE',
28+
};
29+
30+
const addRegionalGuidanceFromImageDropData: AddRegionalGuidanceFromImageDropData = {
31+
id: 'add-regional-guidance-from-image-drop-data',
32+
actionType: 'ADD_REGIONAL_GUIDANCE_FROM_IMAGE',
33+
};
34+
2335
const addRegionalReferenceImageFromImageDropData: AddRegionalReferenceImageFromImageDropData = {
2436
id: 'add-control-layer-from-image-drop-data',
2537
actionType: 'ADD_REGIONAL_REFERENCE_IMAGE_FROM_IMAGE',
@@ -41,7 +53,7 @@ export const CanvasDropArea = memo(() => {
4153
return (
4254
<>
4355
<Grid
44-
gridTemplateRows="1fr 1fr"
56+
gridTemplateRows="1fr 1fr 1fr"
4557
gridTemplateColumns="1fr 1fr"
4658
position="absolute"
4759
top={0}
@@ -62,6 +74,7 @@ export const CanvasDropArea = memo(() => {
6274
data={addControlLayerFromImageDropData}
6375
/>
6476
</GridItem>
77+
6578
<GridItem position="relative">
6679
<IAIDroppable
6780
dropLabel={t('controlLayers.canvasContextMenu.newRegionalReferenceImage')}
@@ -74,6 +87,19 @@ export const CanvasDropArea = memo(() => {
7487
data={addGlobalReferenceImageFromImageDropData}
7588
/>
7689
</GridItem>
90+
91+
<GridItem position="relative">
92+
<IAIDroppable
93+
dropLabel={t('controlLayers.canvasContextMenu.newInpaintMask')}
94+
data={addInpaintMaskFromImageDropData}
95+
/>
96+
</GridItem>
97+
<GridItem position="relative">
98+
<IAIDroppable
99+
dropLabel={t('controlLayers.canvasContextMenu.newRegionalGuidance')}
100+
data={addRegionalGuidanceFromImageDropData}
101+
/>
102+
</GridItem>
77103
</Grid>
78104
</>
79105
);

invokeai/frontend/web/src/features/controlLayers/components/InpaintMask/InpaintMask.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Spacer } from '@invoke-ai/ui-library';
2+
import IAIDroppable from 'common/components/IAIDroppable';
23
import { CanvasEntityContainer } from 'features/controlLayers/components/common/CanvasEntityContainer';
34
import { CanvasEntityHeader } from 'features/controlLayers/components/common/CanvasEntityHeader';
45
import { CanvasEntityHeaderCommonActions } from 'features/controlLayers/components/common/CanvasEntityHeaderCommonActions';
@@ -7,14 +8,21 @@ import { CanvasEntityEditableTitle } from 'features/controlLayers/components/com
78
import { InpaintMaskAdapterGate } from 'features/controlLayers/contexts/EntityAdapterContext';
89
import { EntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
910
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
11+
import type { ReplaceLayerImageDropData } from 'features/dnd/types';
1012
import { memo, useMemo } from 'react';
13+
import { useTranslation } from 'react-i18next';
1114

1215
type Props = {
1316
id: string;
1417
};
1518

1619
export const InpaintMask = memo(({ id }: Props) => {
17-
const entityIdentifier = useMemo<CanvasEntityIdentifier>(() => ({ id, type: 'inpaint_mask' }), [id]);
20+
const { t } = useTranslation();
21+
const entityIdentifier = useMemo<CanvasEntityIdentifier<'inpaint_mask'>>(() => ({ id, type: 'inpaint_mask' }), [id]);
22+
const dropData = useMemo<ReplaceLayerImageDropData>(
23+
() => ({ id, actionType: 'REPLACE_LAYER_WITH_IMAGE', context: { entityIdentifier } }),
24+
[id, entityIdentifier]
25+
);
1826

1927
return (
2028
<EntityIdentifierContext.Provider value={entityIdentifier}>
@@ -26,6 +34,7 @@ export const InpaintMask = memo(({ id }: Props) => {
2634
<Spacer />
2735
<CanvasEntityHeaderCommonActions />
2836
</CanvasEntityHeader>
37+
<IAIDroppable data={dropData} dropLabel={t('controlLayers.replaceLayer')} />
2938
</CanvasEntityContainer>
3039
</InpaintMaskAdapterGate>
3140
</EntityIdentifierContext.Provider>

invokeai/frontend/web/src/features/controlLayers/components/RegionalGuidance/RegionalGuidance.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Spacer } from '@invoke-ai/ui-library';
2+
import IAIDroppable from 'common/components/IAIDroppable';
23
import { CanvasEntityContainer } from 'features/controlLayers/components/common/CanvasEntityContainer';
34
import { CanvasEntityHeader } from 'features/controlLayers/components/common/CanvasEntityHeader';
45
import { CanvasEntityHeaderCommonActions } from 'features/controlLayers/components/common/CanvasEntityHeaderCommonActions';
@@ -9,14 +10,24 @@ import { RegionalGuidanceSettings } from 'features/controlLayers/components/Regi
910
import { RegionalGuidanceAdapterGate } from 'features/controlLayers/contexts/EntityAdapterContext';
1011
import { EntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
1112
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
13+
import type { ReplaceLayerImageDropData } from 'features/dnd/types';
1214
import { memo, useMemo } from 'react';
15+
import { useTranslation } from 'react-i18next';
1316

1417
type Props = {
1518
id: string;
1619
};
1720

1821
export const RegionalGuidance = memo(({ id }: Props) => {
19-
const entityIdentifier = useMemo<CanvasEntityIdentifier>(() => ({ id, type: 'regional_guidance' }), [id]);
22+
const { t } = useTranslation();
23+
const entityIdentifier = useMemo<CanvasEntityIdentifier<'regional_guidance'>>(
24+
() => ({ id, type: 'regional_guidance' }),
25+
[id]
26+
);
27+
const dropData = useMemo<ReplaceLayerImageDropData>(
28+
() => ({ id, actionType: 'REPLACE_LAYER_WITH_IMAGE', context: { entityIdentifier } }),
29+
[id, entityIdentifier]
30+
);
2031

2132
return (
2233
<EntityIdentifierContext.Provider value={entityIdentifier}>
@@ -30,6 +41,7 @@ export const RegionalGuidance = memo(({ id }: Props) => {
3041
<CanvasEntityHeaderCommonActions />
3142
</CanvasEntityHeader>
3243
<RegionalGuidanceSettings />
44+
<IAIDroppable data={dropData} dropLabel={t('controlLayers.replaceLayer')} />
3345
</CanvasEntityContainer>
3446
</RegionalGuidanceAdapterGate>
3547
</EntityIdentifierContext.Provider>

invokeai/frontend/web/src/features/dnd/types/index.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ export type AddControlLayerFromImageDropData = BaseDropData & {
4242
actionType: 'ADD_CONTROL_LAYER_FROM_IMAGE';
4343
};
4444

45+
export type AddInpaintMaskFromImageDropData = BaseDropData & {
46+
actionType: 'ADD_INPAINT_MASK_FROM_IMAGE';
47+
};
48+
49+
export type AddRegionalGuidanceFromImageDropData = BaseDropData & {
50+
actionType: 'ADD_REGIONAL_GUIDANCE_FROM_IMAGE';
51+
};
52+
4553
export type AddRegionalReferenceImageFromImageDropData = BaseDropData & {
4654
actionType: 'ADD_REGIONAL_REFERENCE_IMAGE_FROM_IMAGE';
4755
};
@@ -53,7 +61,7 @@ export type AddGlobalReferenceImageFromImageDropData = BaseDropData & {
5361
export type ReplaceLayerImageDropData = BaseDropData & {
5462
actionType: 'REPLACE_LAYER_WITH_IMAGE';
5563
context: {
56-
entityIdentifier: CanvasEntityIdentifier<'control_layer' | 'raster_layer'>;
64+
entityIdentifier: CanvasEntityIdentifier<'control_layer' | 'raster_layer' | 'inpaint_mask' | 'regional_guidance'>;
5765
};
5866
};
5967

@@ -98,7 +106,9 @@ export type TypesafeDroppableData =
98106
| AddControlLayerFromImageDropData
99107
| ReplaceLayerImageDropData
100108
| AddRegionalReferenceImageFromImageDropData
101-
| AddGlobalReferenceImageFromImageDropData;
109+
| AddGlobalReferenceImageFromImageDropData
110+
| AddInpaintMaskFromImageDropData
111+
| AddRegionalGuidanceFromImageDropData;
102112

103113
type BaseDragData = {
104114
id: string;

invokeai/frontend/web/src/features/dnd/util/isValidDrop.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export const isValidDrop = (overData?: TypesafeDroppableData | null, activeData?
1717
case 'SET_RG_IP_ADAPTER_IMAGE':
1818
case 'ADD_RASTER_LAYER_FROM_IMAGE':
1919
case 'ADD_CONTROL_LAYER_FROM_IMAGE':
20+
case 'ADD_INPAINT_MASK_FROM_IMAGE':
21+
case 'ADD_REGIONAL_GUIDANCE_FROM_IMAGE':
2022
case 'SET_UPSCALE_INITIAL_IMAGE':
2123
case 'SET_NODES_IMAGE':
2224
case 'SELECT_FOR_COMPARE':

0 commit comments

Comments
 (0)