mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): background and staging area modules have own store subscription and render themselves
This commit is contained in:
@@ -28,6 +28,8 @@ export class CanvasBackgroundModule extends CanvasModuleBase {
|
||||
readonly manager: CanvasManager;
|
||||
readonly log: Logger;
|
||||
|
||||
private _dynamicGrid: boolean | null = null;
|
||||
|
||||
subscriptions = new Set<() => void>();
|
||||
config: CanvasBackgroundModuleConfig = DEFAULT_CONFIG;
|
||||
|
||||
@@ -60,15 +62,33 @@ export class CanvasBackgroundModule extends CanvasModuleBase {
|
||||
* - size
|
||||
*/
|
||||
this.subscriptions.add(this.manager.stage.$stageAttrs.listen(this.render));
|
||||
this.subscriptions.add(this.manager.stateApi.store.subscribe(this.sync));
|
||||
}
|
||||
|
||||
sync = (): boolean => {
|
||||
this._dynamicGrid = this.manager.stateApi.getSettings().dynamicGrid;
|
||||
return this._dynamicGrid;
|
||||
};
|
||||
|
||||
get dynamicGrid(): boolean {
|
||||
if (this._dynamicGrid === null) {
|
||||
return this.sync();
|
||||
}
|
||||
return this._dynamicGrid;
|
||||
}
|
||||
|
||||
set dynamicGrid(dynamicGrid: boolean) {
|
||||
if (this._dynamicGrid !== dynamicGrid) {
|
||||
this._dynamicGrid = dynamicGrid;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the background grid.
|
||||
*/
|
||||
render = () => {
|
||||
const settings = this.manager.stateApi.getSettings();
|
||||
|
||||
if (!settings.dynamicGrid) {
|
||||
if (!this.dynamicGrid) {
|
||||
this.konva.layer.visible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6,23 +6,20 @@ import { CanvasRasterLayerAdapter } from 'features/controlLayers/konva/CanvasRas
|
||||
import { CanvasRegionalGuidanceAdapter } from 'features/controlLayers/konva/CanvasRegionalGuidanceAdapter';
|
||||
import { getPrefixedId } from 'features/controlLayers/konva/util';
|
||||
import type { CanvasSessionState } from 'features/controlLayers/store/canvasSessionSlice';
|
||||
import type { CanvasSettingsState } from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { type CanvasState, getEntityIdentifier } from 'features/controlLayers/store/types';
|
||||
import type { Logger } from 'roarr';
|
||||
|
||||
export class CanvasRenderingModule extends CanvasModuleBase {
|
||||
readonly type = 'canvas_renderer';
|
||||
export class CanvasEntityRendererModule extends CanvasModuleBase {
|
||||
readonly type = 'entity_renderer';
|
||||
readonly id: string;
|
||||
readonly path: string[];
|
||||
readonly log: Logger;
|
||||
readonly parent: CanvasManager;
|
||||
readonly manager: CanvasManager;
|
||||
|
||||
state: CanvasState | null = null;
|
||||
settings: CanvasSettingsState | null = null;
|
||||
session: CanvasSessionState | null = null;
|
||||
private _state: CanvasState | null = null;
|
||||
|
||||
isFirstRender = true;
|
||||
subscriptions = new Set<() => void>();
|
||||
|
||||
constructor(manager: CanvasManager) {
|
||||
super();
|
||||
@@ -33,29 +30,15 @@ export class CanvasRenderingModule extends CanvasModuleBase {
|
||||
this.log = this.manager.buildLogger(this);
|
||||
|
||||
this.log.debug('Creating module');
|
||||
|
||||
this.subscriptions.add(this.manager.stateApi.store.subscribe(this.render));
|
||||
}
|
||||
|
||||
render = () => {
|
||||
if (!this.state || !this.settings || !this.session) {
|
||||
this.log.trace('First render');
|
||||
}
|
||||
|
||||
this.renderCanvas();
|
||||
this.renderSettings();
|
||||
this.renderSession();
|
||||
|
||||
// We have no prev state for the first render
|
||||
if (this.isFirstRender) {
|
||||
this.isFirstRender = false;
|
||||
this.manager.setCanvasManager();
|
||||
}
|
||||
};
|
||||
|
||||
renderCanvas = () => {
|
||||
const state = this.manager.stateApi.getCanvasState();
|
||||
|
||||
const prevState = this.state;
|
||||
this.state = state;
|
||||
const prevState = this._state;
|
||||
this._state = state;
|
||||
|
||||
this.manager.stateApi.$settingsState.set(this.manager.stateApi.getSettings());
|
||||
this.manager.stateApi.$selectedEntityIdentifier.set(state.selectedEntityIdentifier);
|
||||
@@ -76,48 +59,6 @@ export class CanvasRenderingModule extends CanvasModuleBase {
|
||||
this.manager.tool.syncCursorStyle();
|
||||
};
|
||||
|
||||
renderSettings = () => {
|
||||
const settings = this.manager.stateApi.getSettings();
|
||||
|
||||
if (!this.settings) {
|
||||
this.log.trace('First settings render');
|
||||
}
|
||||
|
||||
const prevSettings = this.settings;
|
||||
this.settings = settings;
|
||||
|
||||
if (prevSettings === settings) {
|
||||
// No changes to state - no need to render
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderBackground(settings, prevSettings);
|
||||
};
|
||||
|
||||
renderSession = async () => {
|
||||
const session = this.manager.stateApi.getSession();
|
||||
|
||||
if (!this.session) {
|
||||
this.log.trace('First session render');
|
||||
}
|
||||
|
||||
const prevSession = this.session;
|
||||
this.session = session;
|
||||
|
||||
if (prevSession === session) {
|
||||
// No changes to state - no need to render
|
||||
return;
|
||||
}
|
||||
|
||||
await this.renderStagingArea(session, prevSession);
|
||||
};
|
||||
|
||||
renderBackground = (settings: CanvasSettingsState, prevSettings: CanvasSettingsState | null) => {
|
||||
if (!prevSettings || settings.dynamicGrid !== prevSettings.dynamicGrid) {
|
||||
this.manager.background.render();
|
||||
}
|
||||
};
|
||||
|
||||
renderRasterLayers = async (state: CanvasState, prevState: CanvasState | null) => {
|
||||
const adapterMap = this.manager.adapters.rasterLayers;
|
||||
|
||||
@@ -298,4 +239,10 @@ export class CanvasRenderingModule extends CanvasModuleBase {
|
||||
this.manager.konva.previewLayer.zIndex(++zIndex);
|
||||
}
|
||||
};
|
||||
|
||||
destroy = () => {
|
||||
this.log.trace('Destroying module');
|
||||
this.subscriptions.forEach((unsubscribe) => unsubscribe());
|
||||
this.subscriptions.clear();
|
||||
};
|
||||
}
|
||||
@@ -7,13 +7,13 @@ import { CanvasBboxModule } from 'features/controlLayers/konva/CanvasBboxModule'
|
||||
import { CanvasCacheModule } from 'features/controlLayers/konva/CanvasCacheModule';
|
||||
import { CanvasCompositorModule } from 'features/controlLayers/konva/CanvasCompositorModule';
|
||||
import type { CanvasControlLayerAdapter } from 'features/controlLayers/konva/CanvasControlLayerAdapter';
|
||||
import { CanvasEntityRendererModule } from 'features/controlLayers/konva/CanvasEntityRendererModule';
|
||||
import { CanvasFilterModule } from 'features/controlLayers/konva/CanvasFilterModule';
|
||||
import type { CanvasInpaintMaskAdapter } from 'features/controlLayers/konva/CanvasInpaintMaskAdapter';
|
||||
import { CanvasModuleBase } from 'features/controlLayers/konva/CanvasModuleBase';
|
||||
import { CanvasProgressImageModule } from 'features/controlLayers/konva/CanvasProgressImageModule';
|
||||
import type { CanvasRasterLayerAdapter } from 'features/controlLayers/konva/CanvasRasterLayerAdapter';
|
||||
import type { CanvasRegionalGuidanceAdapter } from 'features/controlLayers/konva/CanvasRegionalGuidanceAdapter';
|
||||
import { CanvasRenderingModule } from 'features/controlLayers/konva/CanvasRenderingModule';
|
||||
import { CanvasStageModule } from 'features/controlLayers/konva/CanvasStageModule';
|
||||
import { CanvasStagingAreaModule } from 'features/controlLayers/konva/CanvasStagingAreaModule';
|
||||
import { CanvasToolModule } from 'features/controlLayers/konva/CanvasToolModule';
|
||||
@@ -40,8 +40,6 @@ export class CanvasManager extends CanvasModuleBase {
|
||||
store: AppStore;
|
||||
socket: AppSocket;
|
||||
|
||||
subscriptions = new Set<() => void>();
|
||||
|
||||
adapters = {
|
||||
rasterLayers: new SyncableMap<string, CanvasRasterLayerAdapter>(),
|
||||
controlLayers: new SyncableMap<string, CanvasControlLayerAdapter>(),
|
||||
@@ -68,7 +66,7 @@ export class CanvasManager extends CanvasModuleBase {
|
||||
stage: CanvasStageModule;
|
||||
worker: CanvasWorkerModule;
|
||||
cache: CanvasCacheModule;
|
||||
renderer: CanvasRenderingModule;
|
||||
entityRenderer: CanvasEntityRendererModule;
|
||||
compositor: CanvasCompositorModule;
|
||||
tool: CanvasToolModule;
|
||||
bbox: CanvasBboxModule;
|
||||
@@ -110,7 +108,7 @@ export class CanvasManager extends CanvasModuleBase {
|
||||
this.stage = new CanvasStageModule(stage, container, this);
|
||||
this.worker = new CanvasWorkerModule(this);
|
||||
this.cache = new CanvasCacheModule(this);
|
||||
this.renderer = new CanvasRenderingModule(this);
|
||||
this.entityRenderer = new CanvasEntityRendererModule(this);
|
||||
this.filter = new CanvasFilterModule(this);
|
||||
|
||||
this.compositor = new CanvasCompositorModule(this);
|
||||
@@ -158,15 +156,13 @@ export class CanvasManager extends CanvasModuleBase {
|
||||
this.stateApi.$currentFill.set(this.stateApi.getCurrentColor());
|
||||
this.stateApi.$selectedEntity.set(this.stateApi.getSelectedEntity());
|
||||
|
||||
this.subscriptions.add(this.store.subscribe(this.renderer.render));
|
||||
this.stage.initialize();
|
||||
$canvasManager.set(this);
|
||||
};
|
||||
|
||||
destroy = () => {
|
||||
this.log.debug('Destroying module');
|
||||
|
||||
this.subscriptions.forEach((unsubscribe) => unsubscribe());
|
||||
|
||||
for (const adapter of this.adapters.getAll()) {
|
||||
adapter.destroy();
|
||||
}
|
||||
@@ -181,18 +177,13 @@ export class CanvasManager extends CanvasModuleBase {
|
||||
this.background.destroy();
|
||||
this.filter.destroy();
|
||||
this.worker.destroy();
|
||||
this.renderer.destroy();
|
||||
this.entityRenderer.destroy();
|
||||
this.compositor.destroy();
|
||||
this.stage.destroy();
|
||||
|
||||
$canvasManager.set(null);
|
||||
};
|
||||
|
||||
setCanvasManager = () => {
|
||||
this.log.debug('Setting canvas manager global');
|
||||
$canvasManager.set(this);
|
||||
};
|
||||
|
||||
repr = () => {
|
||||
return {
|
||||
id: this.id,
|
||||
@@ -210,7 +201,7 @@ export class CanvasManager extends CanvasModuleBase {
|
||||
background: this.background.repr(),
|
||||
filter: this.filter.repr(),
|
||||
worker: this.worker.repr(),
|
||||
renderer: this.renderer.repr(),
|
||||
entityRenderer: this.entityRenderer.repr(),
|
||||
compositor: this.compositor.repr(),
|
||||
stage: this.stage.repr(),
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||
import { CanvasModuleBase } from 'features/controlLayers/konva/CanvasModuleBase';
|
||||
import { CanvasObjectImage } from 'features/controlLayers/konva/CanvasObjectImage';
|
||||
import { getPrefixedId } from 'features/controlLayers/konva/util';
|
||||
import type { CanvasSessionState } from 'features/controlLayers/store/canvasSessionSlice';
|
||||
import { imageDTOToImageWithDims, type StagingAreaImage } from 'features/controlLayers/store/types';
|
||||
import Konva from 'konva';
|
||||
import { atom } from 'nanostores';
|
||||
@@ -15,6 +16,8 @@ export class CanvasStagingAreaModule extends CanvasModuleBase {
|
||||
readonly manager: CanvasManager;
|
||||
readonly log: Logger;
|
||||
|
||||
private _state: CanvasSessionState | null = null;
|
||||
|
||||
subscriptions: Set<() => void> = new Set();
|
||||
konva: { group: Konva.Group };
|
||||
image: CanvasObjectImage | null;
|
||||
@@ -37,15 +40,34 @@ export class CanvasStagingAreaModule extends CanvasModuleBase {
|
||||
this.selectedImage = null;
|
||||
|
||||
this.subscriptions.add(this.$shouldShowStagedImage.listen(this.render));
|
||||
this.subscriptions.add(this.manager.stateApi.store.subscribe(this.sync));
|
||||
}
|
||||
|
||||
sync = (): CanvasSessionState => {
|
||||
this.state = this.manager.stateApi.getSession();
|
||||
return this.state;
|
||||
};
|
||||
|
||||
get state(): CanvasSessionState {
|
||||
if (!this._state) {
|
||||
return this.manager.stateApi.getSession();
|
||||
}
|
||||
return this._state;
|
||||
}
|
||||
|
||||
set state(state: CanvasSessionState) {
|
||||
if (this._state !== state) {
|
||||
this._state = state;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
render = async () => {
|
||||
this.log.trace('Rendering staging area');
|
||||
const session = this.manager.stateApi.getSession();
|
||||
const { x, y, width, height } = this.manager.stateApi.getBbox().rect;
|
||||
const shouldShowStagedImage = this.$shouldShowStagedImage.get();
|
||||
|
||||
this.selectedImage = session.stagedImages[session.selectedStagedImageIndex] ?? null;
|
||||
this.selectedImage = this.state.stagedImages[this.state.selectedStagedImageIndex] ?? null;
|
||||
this.konva.group.position({ x, y });
|
||||
|
||||
if (this.selectedImage) {
|
||||
|
||||
Reference in New Issue
Block a user