diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasInpaintMask.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasInpaintMask.ts index dcfd9f63d2..cede2c9928 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasInpaintMask.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasInpaintMask.ts @@ -112,11 +112,11 @@ export class CanvasInpaintMask { return; } if (this.drawingBuffer.type === 'brush_line') { - this.manager.stateApi.onBrushLineAdded({ id: this.id, brushLine: this.drawingBuffer }, 'inpaint_mask'); + this.manager.stateApi.addBrushLine({ id: this.id, brushLine: this.drawingBuffer }, 'inpaint_mask'); } else if (this.drawingBuffer.type === 'eraser_line') { this.manager.stateApi.addEraserLine({ id: this.id, eraserLine: this.drawingBuffer }, 'inpaint_mask'); } else if (this.drawingBuffer.type === 'rect') { - this.manager.stateApi.addRect({ id: this.id, rectShape: this.drawingBuffer }, 'inpaint_mask'); + this.manager.stateApi.addRect({ id: this.id, rect: this.drawingBuffer }, 'inpaint_mask'); } this.setDrawingBuffer(null); } diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasLayer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasLayer.ts index 70fe8d4107..c2e0a344ec 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasLayer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasLayer.ts @@ -1,10 +1,8 @@ -import { getStore } from 'app/store/nanostores/store'; import { deepClone } from 'common/util/deepClone'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import { CanvasObjectRenderer } from 'features/controlLayers/konva/CanvasObjectRenderer'; import { CanvasTransformer } from 'features/controlLayers/konva/CanvasTransformer'; import { konvaNodeToBlob, previewBlob } from 'features/controlLayers/konva/util'; -import { layerRasterized } from 'features/controlLayers/store/canvasV2Slice'; import type { CanvasLayerState, CanvasV2State, @@ -169,11 +167,13 @@ export class CanvasLayer { previewBlob(blob, 'Rasterized layer'); } const imageDTO = await uploadImage(blob, `${this.id}_rasterized.png`, 'other', true); - const { dispatch } = getStore(); const imageObject = imageDTOToImageObject(imageDTO); await this.renderer.renderObject(imageObject, true); this.resetScale(); - dispatch(layerRasterized({ id: this.id, imageObject, position: { x: Math.round(rect.x), y: Math.round(rect.y) } })); + this.manager.stateApi.rasterizeEntity( + { id: this.id, imageObject, position: { x: Math.round(rect.x), y: Math.round(rect.y) } }, + this.type + ); }; repr = () => { diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObjectRenderer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObjectRenderer.ts index af0963baf1..7e6f7ac34a 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObjectRenderer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObjectRenderer.ts @@ -204,11 +204,11 @@ export class CanvasObjectRenderer { this.buffer.id = getPrefixedId(this.buffer.type); if (this.buffer.type === 'brush_line') { - this.manager.stateApi.onBrushLineAdded({ id: this.parent.id, brushLine: this.buffer }, 'layer'); + this.manager.stateApi.addBrushLine({ id: this.parent.id, brushLine: this.buffer }, 'layer'); } else if (this.buffer.type === 'eraser_line') { this.manager.stateApi.addEraserLine({ id: this.parent.id, eraserLine: this.buffer }, 'layer'); } else if (this.buffer.type === 'rect') { - this.manager.stateApi.addRect({ id: this.parent.id, rectShape: this.buffer }, 'layer'); + this.manager.stateApi.addRect({ id: this.parent.id, rect: this.buffer }, 'layer'); } else { this.log.warn({ buffer: this.buffer }, 'Invalid buffer object type'); } diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasRegion.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasRegion.ts index 927ee87c91..74a0cdd6de 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasRegion.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasRegion.ts @@ -112,11 +112,11 @@ export class CanvasRegion { return; } if (this.drawingBuffer.type === 'brush_line') { - this.manager.stateApi.onBrushLineAdded({ id: this.id, brushLine: this.drawingBuffer }, 'regional_guidance'); + this.manager.stateApi.addBrushLine({ id: this.id, brushLine: this.drawingBuffer }, 'regional_guidance'); } else if (this.drawingBuffer.type === 'eraser_line') { this.manager.stateApi.addEraserLine({ id: this.id, eraserLine: this.drawingBuffer }, 'regional_guidance'); } else if (this.drawingBuffer.type === 'rect') { - this.manager.stateApi.addRect({ id: this.id, rectShape: this.drawingBuffer }, 'regional_guidance'); + this.manager.stateApi.addRect({ id: this.id, rect: this.drawingBuffer }, 'regional_guidance'); } this.setDrawingBuffer(null); } diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts index b1e615f041..0ed2359aad 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts @@ -21,32 +21,36 @@ import { imBrushLineAdded, imEraserLineAdded, imImageCacheChanged, - imRectShapeAdded, + imRectAdded, imTranslated, layerBrushLineAdded, layerEraserLineAdded, layerImageCacheChanged, - layerRectShapeAdded, + layerRasterized, + layerRectAdded, layerReset, layerTranslated, rgBrushLineAdded, rgEraserLineAdded, rgImageCacheChanged, - rgRectShapeAdded, + rgRectAdded, rgTranslated, toolBufferChanged, toolChanged, } from 'features/controlLayers/store/canvasV2Slice'; import type { CanvasBrushLineState, + CanvasEntityIdentifier, CanvasEntityState, CanvasEraserLineState, CanvasRectState, + EntityRasterizedArg, PositionChangedArg, Rect, Tool, } from 'features/controlLayers/store/types'; import type { ImageDTO } from 'services/api/types'; +import { assert } from 'tsafe'; const log = logger('canvas'); @@ -101,17 +105,25 @@ export class CanvasStateApi { this._store.dispatch(imEraserLineAdded(arg)); } }; - addRect = (arg: { id: string; rectShape: CanvasRectState }, entityType: CanvasEntityState['type']) => { + addRect = (arg: { id: string; rect: CanvasRectState }, entityType: CanvasEntityState['type']) => { log.trace({ arg, entityType }, 'Adding rect'); if (entityType === 'layer') { - this._store.dispatch(layerRectShapeAdded(arg)); + this._store.dispatch(layerRectAdded(arg)); } else if (entityType === 'regional_guidance') { - this._store.dispatch(rgRectShapeAdded(arg)); + this._store.dispatch(rgRectAdded(arg)); } else if (entityType === 'inpaint_mask') { - this._store.dispatch(imRectShapeAdded(arg)); + this._store.dispatch(imRectAdded(arg)); } }; - setSelectedEntity = (arg: { id: string; type: CanvasEntityState['type'] }) => { + rasterizeEntity = (arg: EntityRasterizedArg, entityType: CanvasEntityState['type']) => { + log.trace({ arg, entityType }, 'Rasterizing entity'); + if (entityType === 'layer') { + this._store.dispatch(layerRasterized(arg)); + } else { + assert(false, 'Rasterizing not supported for this entity type'); + } + }; + setSelectedEntity = (arg: CanvasEntityIdentifier) => { log.trace({ arg }, 'Setting selected entity'); this._store.dispatch(entitySelected(arg)); }; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts index 9435358d92..c217ed06ac 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts @@ -222,7 +222,7 @@ export const { layerImageCacheChanged, layerBrushLineAdded, layerEraserLineAdded, - layerRectShapeAdded, + layerRectAdded, layerRasterized, // IP Adapters ipaAdded, @@ -288,7 +288,7 @@ export const { rgScaled, rgBrushLineAdded, rgEraserLineAdded, - rgRectShapeAdded, + rgRectAdded, // Compositing setInfillMethod, setInfillTileSize, @@ -344,7 +344,7 @@ export const { imScaled, imBrushLineAdded, imEraserLineAdded, - imRectShapeAdded, + imRectAdded, // Staging sessionStarted, sessionStartedStaging, diff --git a/invokeai/frontend/web/src/features/controlLayers/store/inpaintMaskReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/inpaintMaskReducers.ts index ac12068505..8a94e523d8 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/inpaintMaskReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/inpaintMaskReducers.ts @@ -1,11 +1,11 @@ import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit'; import type { CanvasBrushLineState, - CanvasV2State, - Coordinate, CanvasEraserLineState, CanvasInpaintMaskState, CanvasRectState, + CanvasV2State, + Coordinate, ScaleChangedArg, } from 'features/controlLayers/store/types'; import { imageDTOToImageWithDims } from 'features/controlLayers/store/types'; @@ -78,9 +78,9 @@ export const inpaintMaskReducers = { state.inpaintMask.bboxNeedsUpdate = true; state.layers.imageCache = null; }, - imRectShapeAdded: (state, action: PayloadAction<{ rectShape: CanvasRectState }>) => { - const { rectShape } = action.payload; - state.inpaintMask.objects.push(rectShape); + imRectAdded: (state, action: PayloadAction<{ rect: CanvasRectState }>) => { + const { rect } = action.payload; + state.inpaintMask.objects.push(rect); state.inpaintMask.bboxNeedsUpdate = true; state.layers.imageCache = null; }, diff --git a/invokeai/frontend/web/src/features/controlLayers/store/layersReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/layersReducers.ts index e1253e726a..4a00aa821f 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/layersReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/layersReducers.ts @@ -8,14 +8,13 @@ import { assert } from 'tsafe'; import type { CanvasBrushLineState, - CanvasV2State, - Coordinate, CanvasEraserLineState, - CanvasImageState, - ImageObjectAddedArg, CanvasLayerState, - PositionChangedArg, CanvasRectState, + CanvasV2State, + EntityRasterizedArg, + ImageObjectAddedArg, + PositionChangedArg, } from './types'; import { imageDTOToImageObject, imageDTOToImageWithDims } from './types'; @@ -168,14 +167,14 @@ export const layersReducers = { layer.objects.push(eraserLine); state.layers.imageCache = null; }, - layerRectShapeAdded: (state, action: PayloadAction<{ id: string; rectShape: CanvasRectState }>) => { - const { id, rectShape } = action.payload; + layerRectAdded: (state, action: PayloadAction<{ id: string; rect: CanvasRectState }>) => { + const { id, rect } = action.payload; const layer = selectLayer(state, id); if (!layer) { return; } - layer.objects.push(rectShape); + layer.objects.push(rect); state.layers.imageCache = null; }, layerImageAdded: ( @@ -199,7 +198,7 @@ export const layersReducers = { const { imageDTO } = action.payload; state.layers.imageCache = imageDTO ? imageDTOToImageWithDims(imageDTO) : null; }, - layerRasterized: (state, action: PayloadAction<{ id: string; imageObject: CanvasImageState; position: Coordinate }>) => { + layerRasterized: (state, action: PayloadAction) => { const { id, imageObject, position } = action.payload; const layer = selectLayer(state, id); if (!layer) { diff --git a/invokeai/frontend/web/src/features/controlLayers/store/regionsReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/regionsReducers.ts index 4a82f586c4..b847a24e86 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/regionsReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/regionsReducers.ts @@ -2,12 +2,12 @@ import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit'; import { moveOneToEnd, moveOneToStart, moveToEnd, moveToStart } from 'common/util/arrayUtils'; import type { CanvasBrushLineState, + CanvasEraserLineState, + CanvasRectState, CanvasV2State, CLIPVisionModelV2, - CanvasEraserLineState, IPMethodV2, PositionChangedArg, - CanvasRectState, ScaleChangedArg, } from 'features/controlLayers/store/types'; import { imageDTOToImageObject, imageDTOToImageWithDims } from 'features/controlLayers/store/types'; @@ -350,14 +350,14 @@ export const regionsReducers = { rg.bboxNeedsUpdate = true; state.layers.imageCache = null; }, - rgRectShapeAdded: (state, action: PayloadAction<{ id: string; rectShape: CanvasRectState }>) => { - const { id, rectShape } = action.payload; + rgRectAdded: (state, action: PayloadAction<{ id: string; rect: CanvasRectState }>) => { + const { id, rect } = action.payload; const rg = selectRG(state, id); if (!rg) { return; } - rg.objects.push(rectShape); + rg.objects.push(rect); rg.bboxNeedsUpdate = true; state.layers.imageCache = null; }, diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 00a1bbaf6a..54e046c5e0 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -32,7 +32,6 @@ import { zParameterNegativePrompt, zParameterPositivePrompt, } from 'features/parameters/types/parameterSchemas'; -import type { IRect } from 'konva/lib/types'; import type { AnyInvocation, BaseModelType, @@ -937,16 +936,12 @@ export type StageAttrs = { position: Coordinate; dimensions: Dimensions; scale: export type PositionChangedArg = { id: string; position: Coordinate }; export type ScaleChangedArg = { id: string; scale: Coordinate; position: Coordinate }; export type BboxChangedArg = { id: string; bbox: Rect | null }; -export type EraserLineAddedArg = { - id: string; - points: [number, number, number, number]; - width: number; - clip: Rect | null; -}; -export type BrushLineAddedArg = EraserLineAddedArg & { color: RgbaColor }; -export type PointAddedToLineArg = { id: string; point: [number, number] }; -export type RectShapeAddedArg = { id: string; rect: IRect; color: RgbaColor }; + +export type BrushLineAddedArg = { id: string; brushLine: CanvasBrushLineState }; +export type EraserLineAddedArg = { id: string; eraserLine: CanvasEraserLineState }; +export type RectAddedArg = { id: string; rect: CanvasRectState }; export type ImageObjectAddedArg = { id: string; imageDTO: ImageDTO; position?: Coordinate }; +export type EntityRasterizedArg = { id: string; imageObject: CanvasImageState; position: Coordinate }; //#region Type guards export const isLine = (obj: CanvasObjectState): obj is CanvasBrushLineState | CanvasEraserLineState => {