diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityLayerAdapter.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityLayerAdapter.ts index 3f59044bbc..36740ba630 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityLayerAdapter.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityLayerAdapter.ts @@ -85,24 +85,30 @@ export class CanvasEntityLayerAdapter extends CanvasModuleABC { update = async (arg?: { state: CanvasEntityLayerAdapter['state'] }) => { const state = get(arg, 'state', this.state); - if (!this.isFirstRender && state === this.state) { + const prevState = this.state; + this.state = state; + + if (!this.isFirstRender && prevState === state) { this.log.trace('State unchanged, skipping update'); return; } this.log.debug('Updating'); - const { position, objects, opacity, isEnabled } = state; + const { position, objects, opacity, isEnabled, isLocked } = state; - if (this.isFirstRender || isEnabled !== this.state.isEnabled) { + if (this.isFirstRender || isEnabled !== prevState.isEnabled) { this.updateVisibility({ isEnabled }); } - if (this.isFirstRender || objects !== this.state.objects) { + if (this.isFirstRender || isLocked !== prevState.isLocked) { + this.transformer.syncInteractionState(); + } + if (this.isFirstRender || objects !== prevState.objects) { await this.updateObjects({ objects }); } - if (this.isFirstRender || position !== this.state.position) { + if (this.isFirstRender || position !== prevState.position) { this.transformer.updatePosition({ position }); } - if (this.isFirstRender || opacity !== this.state.opacity) { + if (this.isFirstRender || opacity !== prevState.opacity) { this.renderer.updateOpacity(opacity); } @@ -117,7 +123,6 @@ export class CanvasEntityLayerAdapter extends CanvasModuleABC { this.transformer.updateBbox(); } - this.state = state; this.isFirstRender = false; }; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityMaskAdapter.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityMaskAdapter.ts index 45a5cd3bba..ee77abd292 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityMaskAdapter.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityMaskAdapter.ts @@ -85,28 +85,33 @@ export class CanvasEntityMaskAdapter extends CanvasModuleABC { update = async (arg?: { state: CanvasEntityMaskAdapter['state'] }) => { const state = get(arg, 'state', this.state); - if (!this.isFirstRender && state === this.state && state.fill === this.state.fill) { + const prevState = this.state; + this.state = state; + + if (!this.isFirstRender && prevState === state && prevState.fill === state.fill) { this.log.trace('State unchanged, skipping update'); return; } this.log.debug('Updating'); - const { position, objects, isEnabled, opacity } = state; + const { position, objects, isEnabled, isLocked, opacity } = state; - if (this.isFirstRender || objects !== this.state.objects) { + if (this.isFirstRender || objects !== prevState.objects) { await this.updateObjects({ objects }); } - if (this.isFirstRender || position !== this.state.position) { + if (this.isFirstRender || position !== prevState.position) { this.transformer.updatePosition({ position }); } - if (this.isFirstRender || opacity !== this.state.opacity) { + if (this.isFirstRender || opacity !== prevState.opacity) { this.renderer.updateOpacity(opacity); } - if (this.isFirstRender || isEnabled !== this.state.isEnabled) { + if (this.isFirstRender || isEnabled !== prevState.isEnabled) { this.updateVisibility({ isEnabled }); } - - if (this.isFirstRender || state.fill !== this.state.fill) { + if (this.isFirstRender || isLocked !== prevState.isLocked) { + this.transformer.syncInteractionState(); + } + if (this.isFirstRender || state.fill !== prevState.fill) { this.renderer.updateCompositingRectFill(state.fill); } @@ -118,7 +123,6 @@ export class CanvasEntityMaskAdapter extends CanvasModuleABC { this.transformer.updateBbox(); } - this.state = state; this.isFirstRender = false; }; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityTransformer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityTransformer.ts index f49b4b2f0e..846b9c5915 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityTransformer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntityTransformer.ts @@ -436,7 +436,7 @@ export class CanvasEntityTransformer extends CanvasModuleABC { const tool = this.manager.stateApi.$tool.get(); const isSelected = this.manager.stateApi.getIsSelected(this.parent.id); - if (!this.parent.renderer.hasObjects()) { + if (!this.parent.renderer.hasObjects() || this.parent.state.isLocked || !this.parent.state.isEnabled) { // The layer is totally empty, we can just disable the layer this.parent.konva.layer.listening(false); this.setInteractionMode('off'); diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasToolModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasToolModule.ts index d9b06749f4..2c9eba8b07 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasToolModule.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasToolModule.ts @@ -244,9 +244,9 @@ export class CanvasToolModule extends CanvasModuleABC { this.subscriptions.add(cleanupListeners); } - setToolVisibility = (tool: Tool) => { - this.konva.brush.group.visible(tool === 'brush'); - this.konva.eraser.group.visible(tool === 'eraser'); + setToolVisibility = (tool: Tool, isDrawable: boolean) => { + this.konva.brush.group.visible(isDrawable && tool === 'brush'); + this.konva.eraser.group.visible(isDrawable && tool === 'eraser'); this.konva.colorPicker.group.visible(tool === 'colorPicker'); }; @@ -259,7 +259,11 @@ export class CanvasToolModule extends CanvasModuleABC { const isMouseDown = this.manager.stateApi.$isMouseDown.get(); const tool = this.manager.stateApi.$tool.get(); - const isDrawable = selectedEntity && selectedEntity.state.isEnabled && isDrawableEntity(selectedEntity.state); + const isDrawable = + !!selectedEntity && + selectedEntity.state.isEnabled && + !selectedEntity.state.isLocked && + isDrawableEntity(selectedEntity.state); // Update the stage's pointer style if (Boolean(this.manager.stateApi.$transformingEntity.get()) || renderedEntityCount === 0) { @@ -433,7 +437,7 @@ export class CanvasToolModule extends CanvasModuleABC { }); } - this.setToolVisibility(tool); + this.setToolVisibility(tool, isDrawable); } }; @@ -539,7 +543,7 @@ export class CanvasToolModule extends CanvasModuleABC { } this.render(); } else { - const isDrawable = selectedEntity?.state.isEnabled; + const isDrawable = selectedEntity?.state.isEnabled && !selectedEntity.state.isLocked; if (pos && isDrawable && !this.manager.stateApi.$spaceKey.get() && getIsPrimaryMouseDown(e)) { this.manager.stateApi.$lastMouseDownPos.set(pos); const normalizedPoint = offsetCoord(pos, selectedEntity.state.position); @@ -638,7 +642,7 @@ export class CanvasToolModule extends CanvasModuleABC { this.manager.stateApi.$isMouseDown.set(false); const pos = this.manager.stateApi.$lastCursorPos.get(); const selectedEntity = this.manager.stateApi.getSelectedEntity(); - const isDrawable = selectedEntity?.state.isEnabled; + const isDrawable = selectedEntity?.state.isEnabled && !selectedEntity.state.isLocked; const tool = this.manager.stateApi.$tool.get(); if (pos && isDrawable && !this.manager.stateApi.$spaceKey.get()) { @@ -686,7 +690,7 @@ export class CanvasToolModule extends CanvasModuleABC { this.manager.stateApi.$colorUnderCursor.set(color); } } else { - const isDrawable = selectedEntity?.state.isEnabled; + const isDrawable = selectedEntity?.state.isEnabled && !selectedEntity.state.isLocked; if (pos && isDrawable && !this.manager.stateApi.$spaceKey.get() && getIsPrimaryMouseDown(e)) { if (tool === 'brush') { const drawingBuffer = selectedEntity.adapter.renderer.bufferState; @@ -786,7 +790,7 @@ export class CanvasToolModule extends CanvasModuleABC { this.manager.stateApi.$lastMouseDownPos.set(null); const selectedEntity = this.manager.stateApi.getSelectedEntity(); const toolState = this.manager.stateApi.getToolState(); - const isDrawable = selectedEntity?.state.isEnabled; + const isDrawable = selectedEntity?.state.isEnabled && !selectedEntity.state.isLocked; const tool = this.manager.stateApi.$tool.get(); if (pos && isDrawable && !this.manager.stateApi.$spaceKey.get() && getIsPrimaryMouseDown(e)) {