feat(ui): staging area barely works

This commit is contained in:
psychedelicious 2024-06-26 18:27:18 +10:00
parent 9807a896f4
commit 7824cb7a1a
5 changed files with 60 additions and 39 deletions

View File

@ -1,7 +1,7 @@
import { enqueueRequested } from 'app/store/actions'; import { enqueueRequested } from 'app/store/actions';
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'; import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
import { getNodeManager } from 'features/controlLayers/konva/nodeManager'; import { getNodeManager } from 'features/controlLayers/konva/nodeManager';
import { stagingAreaInitialized } from 'features/controlLayers/store/canvasV2Slice'; import { stagingAreaBatchIdAdded, stagingAreaInitialized } from 'features/controlLayers/store/canvasV2Slice';
import { isImageViewerOpenChanged } from 'features/gallery/store/gallerySlice'; import { isImageViewerOpenChanged } from 'features/gallery/store/gallerySlice';
import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig'; import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig';
import { buildSD1Graph } from 'features/nodes/util/graph/generation/buildSD1Graph'; import { buildSD1Graph } from 'features/nodes/util/graph/generation/buildSD1Graph';
@ -48,12 +48,16 @@ export const addEnqueueRequestedLinear = (startAppListening: AppStartListening)
// TODO(psyche): update the backend schema, this is always provided // TODO(psyche): update the backend schema, this is always provided
const batchId = enqueueResult.batch.batch_id; const batchId = enqueueResult.batch.batch_id;
assert(batchId, 'No batch ID found in enqueue result'); assert(batchId, 'No batch ID found in enqueue result');
dispatch( if (!state.canvasV2.stagingArea) {
stagingAreaInitialized({ dispatch(
batchIds: [batchId], stagingAreaInitialized({
bbox: getState().canvasV2.bbox, batchIds: [batchId],
}) bbox: state.canvasV2.bbox,
); })
);
} else {
dispatch(stagingAreaBatchIdAdded({ batchId }));
}
} finally { } finally {
req.reset(); req.reset();
} }

View File

@ -1,6 +1,12 @@
import { getImageDataTransparency } from 'common/util/arrayBuffer'; import { getImageDataTransparency } from 'common/util/arrayBuffer';
import { CanvasBackground } from 'features/controlLayers/konva/renderers/background'; import { CanvasBackground } from 'features/controlLayers/konva/renderers/background';
import { CanvasPreview } from 'features/controlLayers/konva/renderers/preview'; import {
CanvasBbox,
CanvasDocumentSizeOverlay,
CanvasPreview,
CanvasStagingArea,
CanvasTool,
} from 'features/controlLayers/konva/renderers/preview';
import { konvaNodeToBlob, konvaNodeToImageData, previewBlob } from 'features/controlLayers/konva/util'; import { konvaNodeToBlob, konvaNodeToImageData, previewBlob } from 'features/controlLayers/konva/util';
import type { import type {
BrushLineAddedArg, BrushLineAddedArg,
@ -106,7 +112,7 @@ export class KonvaNodeManager {
controlAdapters: Map<string, CanvasControlAdapter>; controlAdapters: Map<string, CanvasControlAdapter>;
layers: Map<string, CanvasLayer>; layers: Map<string, CanvasLayer>;
regions: Map<string, CanvasRegion>; regions: Map<string, CanvasRegion>;
inpaintMask: CanvasInpaintMask | null; inpaintMask: CanvasInpaintMask;
util: Util; util: Util;
stateApi: StateApi; stateApi: StateApi;
preview: CanvasPreview; preview: CanvasPreview;
@ -134,23 +140,29 @@ export class KonvaNodeManager {
}; };
this.preview = new CanvasPreview( this.preview = new CanvasPreview(
this.stage, new CanvasBbox(
this.stateApi.getBbox, this.stateApi.getBbox,
this.stateApi.onBboxTransformed, this.stateApi.onBboxTransformed,
this.stateApi.getShiftKey, this.stateApi.getShiftKey,
this.stateApi.getCtrlKey, this.stateApi.getCtrlKey,
this.stateApi.getMetaKey, this.stateApi.getMetaKey,
this.stateApi.getAltKey this.stateApi.getAltKey
),
new CanvasTool(),
new CanvasDocumentSizeOverlay(),
new CanvasStagingArea()
); );
this.stage.add(this.preview.konvaLayer); this.stage.add(this.preview.konvaLayer);
this.background = new CanvasBackground(); this.background = new CanvasBackground();
this.stage.add(this.background.konvaLayer); this.stage.add(this.background.konvaLayer);
this.inpaintMask = new CanvasInpaintMask(this.stateApi.getInpaintMaskState(), this.stateApi.onPosChanged);
this.stage.add(this.inpaintMask.konvaLayer);
this.layers = new Map(); this.layers = new Map();
this.regions = new Map(); this.regions = new Map();
this.controlAdapters = new Map(); this.controlAdapters = new Map();
this.inpaintMask = null;
} }
renderLayers() { renderLayers() {
@ -202,10 +214,6 @@ export class KonvaNodeManager {
renderInpaintMask() { renderInpaintMask() {
const inpaintMaskState = this.stateApi.getInpaintMaskState(); const inpaintMaskState = this.stateApi.getInpaintMaskState();
if (!this.inpaintMask) {
this.inpaintMask = new CanvasInpaintMask(inpaintMaskState, this.stateApi.onPosChanged);
this.stage.add(this.inpaintMask.konvaLayer);
}
const toolState = this.stateApi.getToolState(); const toolState = this.stateApi.getToolState();
const selectedEntity = this.stateApi.getSelectedEntity(); const selectedEntity = this.stateApi.getSelectedEntity();
const maskOpacity = this.stateApi.getMaskOpacity(); const maskOpacity = this.stateApi.getMaskOpacity();
@ -280,6 +288,10 @@ export class KonvaNodeManager {
this.background.renderBackground(this.stage); this.background.renderBackground(this.stage);
} }
renderStagingArea() {
this.preview.stagingArea.render(this.stateApi.getStagingAreaState());
}
fitDocument() { fitDocument() {
this.preview.documentSizeOverlay.fitToStage(this.stage, this.stateApi.getDocument(), this.stateApi.setStageAttrs); this.preview.documentSizeOverlay.fitToStage(this.stage, this.stateApi.getDocument(), this.stateApi.setStageAttrs);
} }

View File

@ -189,8 +189,8 @@ export class KonvaImage {
image: imageEl, image: imageEl,
}); });
this.konvaImageGroup.add(this.konvaImage); this.konvaImageGroup.add(this.konvaImage);
this.imageName = imageName;
} }
this.imageName = imageName;
this.isLoading = false; this.isLoading = false;
this.isError = false; this.isError = false;
this.konvaPlaceholderGroup.visible(false); this.konvaPlaceholderGroup.visible(false);

View File

@ -101,11 +101,11 @@ export class CanvasStagingArea {
return; return;
} }
if (stagingArea.selectedImageIndex) { if (stagingArea.selectedImageIndex !== null) {
const imageDTO = stagingArea.images[stagingArea.selectedImageIndex]; const imageDTO = stagingArea.images[stagingArea.selectedImageIndex];
assert(imageDTO, 'Image must exist'); assert(imageDTO, 'Image must exist');
if (this.image) { if (this.image) {
if (this.image.imageName !== imageDTO.image_name) { if (!this.image.isLoading && !this.image.isError && this.image.imageName !== imageDTO.image_name) {
await this.image.updateImageSource(imageDTO.image_name); await this.image.updateImageSource(imageDTO.image_name);
} }
} else { } else {
@ -114,8 +114,8 @@ export class CanvasStagingArea {
imageObject: { imageObject: {
id: 'staging-area-image', id: 'staging-area-image',
type: 'image', type: 'image',
x: 0, x: stagingArea.bbox.x,
y: 0, y: stagingArea.bbox.y,
width, width,
height, height,
filters: [], filters: [],
@ -126,6 +126,8 @@ export class CanvasStagingArea {
}, },
}, },
}); });
this.group.add(this.image.konvaImageGroup);
await this.image.updateImageSource(imageDTO.image_name);
} }
} }
} }
@ -375,7 +377,6 @@ export class CanvasBbox {
NO_ANCHORS: string[] = []; NO_ANCHORS: string[] = [];
constructor( constructor(
stage: Konva.Stage,
getBbox: () => IRect, getBbox: () => IRect,
onBboxTransformed: (bbox: IRect) => void, onBboxTransformed: (bbox: IRect) => void,
getShiftKey: () => boolean, getShiftKey: () => boolean,
@ -446,6 +447,8 @@ export class CanvasBbox {
anchorDragBoundFunc: (_oldAbsPos, newAbsPos) => { anchorDragBoundFunc: (_oldAbsPos, newAbsPos) => {
// This function works with absolute position - that is, a position in "physical" pixels on the screen, as opposed // This function works with absolute position - that is, a position in "physical" pixels on the screen, as opposed
// to konva's internal coordinate system. // to konva's internal coordinate system.
const stage = this.transformer.getStage();
assert(stage, 'Stage must exist');
// We need to snap the anchors to the grid. If the user is holding ctrl/meta, we use the finer 8px grid. // We need to snap the anchors to the grid. If the user is holding ctrl/meta, we use the finer 8px grid.
const gridSize = getCtrlKey() || getMetaKey() ? 8 : 64; const gridSize = getCtrlKey() || getMetaKey() ? 8 : 64;
@ -588,26 +591,23 @@ export class CanvasPreview {
stagingArea: CanvasStagingArea; stagingArea: CanvasStagingArea;
constructor( constructor(
stage: Konva.Stage, bbox: CanvasBbox,
getBbox: () => IRect, tool: CanvasTool,
onBboxTransformed: (bbox: IRect) => void, documentSizeOverlay: CanvasDocumentSizeOverlay,
getShiftKey: () => boolean, stagingArea: CanvasStagingArea
getCtrlKey: () => boolean,
getMetaKey: () => boolean,
getAltKey: () => boolean
) { ) {
this.konvaLayer = new Konva.Layer({ listening: true }); this.konvaLayer = new Konva.Layer({ listening: true });
this.bbox = new CanvasBbox(stage, getBbox, onBboxTransformed, getShiftKey, getCtrlKey, getMetaKey, getAltKey); this.bbox = bbox;
this.konvaLayer.add(this.bbox.group); this.konvaLayer.add(this.bbox.group);
this.tool = new CanvasTool(); this.tool = tool;
this.konvaLayer.add(this.tool.group); this.konvaLayer.add(this.tool.group);
this.documentSizeOverlay = new CanvasDocumentSizeOverlay(); this.documentSizeOverlay = documentSizeOverlay;
this.konvaLayer.add(this.documentSizeOverlay.group); this.konvaLayer.add(this.documentSizeOverlay.group);
this.stagingArea = new CanvasStagingArea(); this.stagingArea = stagingArea;
this.konvaLayer.add(this.stagingArea.group); this.konvaLayer.add(this.stagingArea.group);
} }
} }

View File

@ -343,7 +343,7 @@ export const initializeRenderer = (
// the entire state over when needed. // the entire state over when needed.
const debouncedUpdateBboxes = debounce(updateBboxes, 300); const debouncedUpdateBboxes = debounce(updateBboxes, 300);
const renderCanvas = () => { const renderCanvas = async () => {
canvasV2 = store.getState().canvasV2; canvasV2 = store.getState().canvasV2;
if (prevCanvasV2 === canvasV2 && !isFirstRender) { if (prevCanvasV2 === canvasV2 && !isFirstRender) {
@ -408,6 +408,11 @@ export const initializeRenderer = (
// debouncedUpdateBboxes(stage, canvasV2.layers, canvasV2.controlAdapters, canvasV2.regions, onBboxChanged); // debouncedUpdateBboxes(stage, canvasV2.layers, canvasV2.controlAdapters, canvasV2.regions, onBboxChanged);
} }
if (isFirstRender || canvasV2.stagingArea !== prevCanvasV2.stagingArea) {
logIfDebugging('Rendering staging area');
manager.renderStagingArea();
}
if ( if (
isFirstRender || isFirstRender ||
canvasV2.layers.entities !== prevCanvasV2.layers.entities || canvasV2.layers.entities !== prevCanvasV2.layers.entities ||