mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): internal state for inpaint mask
This commit is contained in:
parent
8fc2a1d1cf
commit
712e090134
@ -6,6 +6,7 @@ import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
|
|||||||
import { bboxReducers } from 'features/controlLayers/store/bboxReducers';
|
import { bboxReducers } from 'features/controlLayers/store/bboxReducers';
|
||||||
import { compositingReducers } from 'features/controlLayers/store/compositingReducers';
|
import { compositingReducers } from 'features/controlLayers/store/compositingReducers';
|
||||||
import { controlAdaptersReducers } from 'features/controlLayers/store/controlAdaptersReducers';
|
import { controlAdaptersReducers } from 'features/controlLayers/store/controlAdaptersReducers';
|
||||||
|
import { inpaintMaskReducers } from 'features/controlLayers/store/inpaintMaskReducers';
|
||||||
import { ipAdaptersReducers } from 'features/controlLayers/store/ipAdaptersReducers';
|
import { ipAdaptersReducers } from 'features/controlLayers/store/ipAdaptersReducers';
|
||||||
import { layersReducers } from 'features/controlLayers/store/layersReducers';
|
import { layersReducers } from 'features/controlLayers/store/layersReducers';
|
||||||
import { lorasReducers } from 'features/controlLayers/store/lorasReducers';
|
import { lorasReducers } from 'features/controlLayers/store/lorasReducers';
|
||||||
@ -29,17 +30,14 @@ const initialState: CanvasV2State = {
|
|||||||
regions: { entities: [] },
|
regions: { entities: [] },
|
||||||
loras: [],
|
loras: [],
|
||||||
inpaintMask: {
|
inpaintMask: {
|
||||||
|
id: 'inpaint_mask',
|
||||||
|
type: 'inpaint_mask',
|
||||||
bbox: null,
|
bbox: null,
|
||||||
bboxNeedsUpdate: false,
|
bboxNeedsUpdate: false,
|
||||||
fill: {
|
fill: DEFAULT_RGBA_COLOR,
|
||||||
type: 'color_fill',
|
|
||||||
color: DEFAULT_RGBA_COLOR,
|
|
||||||
},
|
|
||||||
id: 'inpaint_mask',
|
|
||||||
imageCache: null,
|
imageCache: null,
|
||||||
isEnabled: false,
|
isEnabled: false,
|
||||||
maskObjects: [],
|
objects: [],
|
||||||
type: 'inpaint_mask',
|
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
},
|
},
|
||||||
@ -135,6 +133,7 @@ export const canvasV2Slice = createSlice({
|
|||||||
...settingsReducers,
|
...settingsReducers,
|
||||||
...toolReducers,
|
...toolReducers,
|
||||||
...bboxReducers,
|
...bboxReducers,
|
||||||
|
...inpaintMaskReducers,
|
||||||
widthChanged: (state, action: PayloadAction<{ width: number; updateAspectRatio?: boolean; clamp?: boolean }>) => {
|
widthChanged: (state, action: PayloadAction<{ width: number; updateAspectRatio?: boolean; clamp?: boolean }>) => {
|
||||||
const { width, updateAspectRatio, clamp } = action.payload;
|
const { width, updateAspectRatio, clamp } = action.payload;
|
||||||
state.document.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width;
|
state.document.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width;
|
||||||
@ -314,6 +313,17 @@ export const {
|
|||||||
loraWeightChanged,
|
loraWeightChanged,
|
||||||
loraIsEnabledChanged,
|
loraIsEnabledChanged,
|
||||||
loraAllDeleted,
|
loraAllDeleted,
|
||||||
|
// Inpaint mask
|
||||||
|
imReset,
|
||||||
|
imRecalled,
|
||||||
|
imIsEnabledToggled,
|
||||||
|
imTranslated,
|
||||||
|
imBboxChanged,
|
||||||
|
imImageCacheChanged,
|
||||||
|
imBrushLineAdded,
|
||||||
|
imEraserLineAdded,
|
||||||
|
imLinePointAdded,
|
||||||
|
imRectAdded,
|
||||||
} = canvasV2Slice.actions;
|
} = canvasV2Slice.actions;
|
||||||
|
|
||||||
export const selectCanvasV2Slice = (state: RootState) => state.canvasV2;
|
export const selectCanvasV2Slice = (state: RootState) => state.canvasV2;
|
||||||
|
@ -1 +1,108 @@
|
|||||||
|
import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
||||||
|
import { getBrushLineId, getEraserLineId, getRectShapeId } from 'features/controlLayers/konva/naming';
|
||||||
|
import type { CanvasV2State, InpaintMaskEntity } from 'features/controlLayers/store/types';
|
||||||
|
import { imageDTOToImageWithDims } from 'features/controlLayers/store/types';
|
||||||
|
import type { IRect } from 'konva/lib/types';
|
||||||
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
import type { BrushLineAddedArg, EraserLineAddedArg, PointAddedToLineArg, RectShapeAddedArg, RgbColor } from './types';
|
||||||
|
import { isLine } from './types';
|
||||||
|
|
||||||
|
export const inpaintMaskReducers = {
|
||||||
|
imReset: (state) => {
|
||||||
|
state.inpaintMask.objects = [];
|
||||||
|
state.inpaintMask.bbox = null;
|
||||||
|
state.inpaintMask.bboxNeedsUpdate = false;
|
||||||
|
state.inpaintMask.imageCache = null;
|
||||||
|
},
|
||||||
|
imRecalled: (state, action: PayloadAction<{ data: InpaintMaskEntity }>) => {
|
||||||
|
const { data } = action.payload;
|
||||||
|
state.inpaintMask = data;
|
||||||
|
state.selectedEntityIdentifier = { type: 'inpaint_mask', id: data.id };
|
||||||
|
},
|
||||||
|
imIsEnabledToggled: (state) => {
|
||||||
|
state.inpaintMask.isEnabled = !state.inpaintMask.isEnabled;
|
||||||
|
},
|
||||||
|
imTranslated: (state, action: PayloadAction<{ x: number; y: number }>) => {
|
||||||
|
const { x, y } = action.payload;
|
||||||
|
state.inpaintMask.x = x;
|
||||||
|
state.inpaintMask.y = y;
|
||||||
|
},
|
||||||
|
imBboxChanged: (state, action: PayloadAction<{ bbox: IRect | null }>) => {
|
||||||
|
const { bbox } = action.payload;
|
||||||
|
state.inpaintMask.bbox = bbox;
|
||||||
|
state.inpaintMask.bboxNeedsUpdate = false;
|
||||||
|
},
|
||||||
|
inpaintMaskFillChanged: (state, action: PayloadAction<{ fill: RgbColor }>) => {
|
||||||
|
const { fill } = action.payload;
|
||||||
|
state.inpaintMask.fill = fill;
|
||||||
|
},
|
||||||
|
imImageCacheChanged: (state, action: PayloadAction<{ imageDTO: ImageDTO | null }>) => {
|
||||||
|
const { imageDTO } = action.payload;
|
||||||
|
state.inpaintMask.imageCache = imageDTO ? imageDTOToImageWithDims(imageDTO) : null;
|
||||||
|
},
|
||||||
|
imBrushLineAdded: {
|
||||||
|
reducer: (state, action: PayloadAction<Omit<BrushLineAddedArg, 'id'> & { lineId: string }>) => {
|
||||||
|
const { points, lineId, color, width, clip } = action.payload;
|
||||||
|
state.inpaintMask.objects.push({
|
||||||
|
id: getBrushLineId(state.inpaintMask.id, lineId),
|
||||||
|
type: 'brush_line',
|
||||||
|
points,
|
||||||
|
strokeWidth: width,
|
||||||
|
color,
|
||||||
|
clip,
|
||||||
|
});
|
||||||
|
state.inpaintMask.bboxNeedsUpdate = true;
|
||||||
|
state.inpaintMask.imageCache = null;
|
||||||
|
},
|
||||||
|
prepare: (payload: Omit<BrushLineAddedArg, 'id'>) => ({
|
||||||
|
payload: { ...payload, lineId: uuidv4() },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
imEraserLineAdded: {
|
||||||
|
reducer: (state, action: PayloadAction<Omit<EraserLineAddedArg, 'id'> & { lineId: string }>) => {
|
||||||
|
const { points, lineId, width, clip } = action.payload;
|
||||||
|
state.inpaintMask.objects.push({
|
||||||
|
id: getEraserLineId(state.inpaintMask.id, lineId),
|
||||||
|
type: 'eraser_line',
|
||||||
|
points,
|
||||||
|
strokeWidth: width,
|
||||||
|
clip,
|
||||||
|
});
|
||||||
|
state.inpaintMask.bboxNeedsUpdate = true;
|
||||||
|
state.inpaintMask.imageCache = null;
|
||||||
|
},
|
||||||
|
prepare: (payload: Omit<EraserLineAddedArg, 'id'>) => ({
|
||||||
|
payload: { ...payload, lineId: uuidv4() },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
imLinePointAdded: (state, action: PayloadAction<Omit<PointAddedToLineArg, 'id'>>) => {
|
||||||
|
const { point } = action.payload;
|
||||||
|
const lastObject = state.inpaintMask.objects[state.inpaintMask.objects.length - 1];
|
||||||
|
if (!lastObject || !isLine(lastObject)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastObject.points.push(...point);
|
||||||
|
state.inpaintMask.bboxNeedsUpdate = true;
|
||||||
|
state.inpaintMask.imageCache = null;
|
||||||
|
},
|
||||||
|
imRectAdded: {
|
||||||
|
reducer: (state, action: PayloadAction<Omit<RectShapeAddedArg, 'id'> & { rectId: string }>) => {
|
||||||
|
const { rect, rectId, color } = action.payload;
|
||||||
|
if (rect.height === 0 || rect.width === 0) {
|
||||||
|
// Ignore zero-area rectangles
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.inpaintMask.objects.push({
|
||||||
|
type: 'rect_shape',
|
||||||
|
id: getRectShapeId(state.inpaintMask.id, rectId),
|
||||||
|
...rect,
|
||||||
|
color,
|
||||||
|
});
|
||||||
|
state.inpaintMask.bboxNeedsUpdate = true;
|
||||||
|
state.inpaintMask.imageCache = null;
|
||||||
|
},
|
||||||
|
prepare: (payload: Omit<RectShapeAddedArg, 'id'>) => ({ payload: { ...payload, rectId: uuidv4() } }),
|
||||||
|
},
|
||||||
|
} satisfies SliceCaseReducers<CanvasV2State>;
|
||||||
|
@ -655,8 +655,8 @@ const zInpaintMaskEntity = z.object({
|
|||||||
y: z.number(),
|
y: z.number(),
|
||||||
bbox: zRect.nullable(),
|
bbox: zRect.nullable(),
|
||||||
bboxNeedsUpdate: z.boolean(),
|
bboxNeedsUpdate: z.boolean(),
|
||||||
maskObjects: z.array(zMaskObject),
|
objects: z.array(zMaskObject),
|
||||||
fill: zFill,
|
fill: zRgbColor,
|
||||||
imageCache: zImageWithDims.nullable(),
|
imageCache: zImageWithDims.nullable(),
|
||||||
});
|
});
|
||||||
export type InpaintMaskEntity = z.infer<typeof zInpaintMaskEntity>;
|
export type InpaintMaskEntity = z.infer<typeof zInpaintMaskEntity>;
|
||||||
|
Loading…
Reference in New Issue
Block a user