feat(ui): implement interaction locking on layers

This commit is contained in:
psychedelicious 2024-08-27 19:27:38 +10:00
parent 377db3f726
commit e470eaf8f3
4 changed files with 39 additions and 26 deletions

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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');

View File

@ -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)) {