feat(ui): remove select layer on click in canvas

It's very easy to end up in a spot where you cannot select a layer at all to move it around. Too tricky to handle otherwise.
This commit is contained in:
psychedelicious 2024-04-30 12:18:54 +10:00 committed by Kent Keirsey
parent 22f160bfcc
commit a357a1ac9d
3 changed files with 11 additions and 47 deletions

View File

@ -11,7 +11,6 @@ import {
$tool, $tool,
isMaskedGuidanceLayer, isMaskedGuidanceLayer,
layerBboxChanged, layerBboxChanged,
layerSelected,
layerTranslated, layerTranslated,
selectRegionalPromptsSlice, selectRegionalPromptsSlice,
} from 'features/regionalPrompts/store/regionalPromptsSlice'; } from 'features/regionalPrompts/store/regionalPromptsSlice';
@ -66,13 +65,6 @@ const useStageRenderer = (
[dispatch] [dispatch]
); );
const onBboxMouseDown = useCallback(
(layerId: string) => {
dispatch(layerSelected(layerId));
},
[dispatch]
);
useLayoutEffect(() => { useLayoutEffect(() => {
log.trace('Initializing stage'); log.trace('Initializing stage');
if (!container) { if (!container) {
@ -182,8 +174,8 @@ const useStageRenderer = (
// Preview should not display bboxes // Preview should not display bboxes
return; return;
} }
renderers.renderBbox(stage, state.layers, state.selectedLayerId, tool, onBboxChanged, onBboxMouseDown); renderers.renderBbox(stage, state.layers, tool, onBboxChanged);
}, [stage, asPreview, state.layers, state.selectedLayerId, tool, onBboxChanged, onBboxMouseDown, renderers]); }, [stage, asPreview, state.layers, tool, onBboxChanged, renderers]);
useLayoutEffect(() => { useLayoutEffect(() => {
log.trace('Rendering background'); log.trace('Rendering background');

View File

@ -142,10 +142,12 @@ export const regionalPromptsSlice = createSlice({
return; return;
}, },
layerSelected: (state, action: PayloadAction<string>) => { layerSelected: (state, action: PayloadAction<string>) => {
for (const layer of state.layers) { for (const layer of state.layers.filter(isRenderableLayer)) {
if (isRenderableLayer(layer) && layer.id === action.payload) { if (layer.id === action.payload) {
layer.isSelected = true; layer.isSelected = true;
state.selectedLayerId = action.payload; state.selectedLayerId = action.payload;
} else {
layer.isSelected = false;
} }
} }
}, },

View File

@ -43,8 +43,6 @@ import { assert } from 'tsafe';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
const BBOX_SELECTED_STROKE = 'rgba(78, 190, 255, 1)'; const BBOX_SELECTED_STROKE = 'rgba(78, 190, 255, 1)';
const BBOX_NOT_SELECTED_STROKE = 'rgba(255, 255, 255, 0.353)';
const BBOX_NOT_SELECTED_MOUSEOVER_STROKE = 'rgba(255, 255, 255, 0.661)';
const BRUSH_BORDER_INNER_COLOR = 'rgba(0,0,0,1)'; const BRUSH_BORDER_INNER_COLOR = 'rgba(0,0,0,1)';
const BRUSH_BORDER_OUTER_COLOR = 'rgba(255,255,255,0.8)'; const BRUSH_BORDER_OUTER_COLOR = 'rgba(255,255,255,0.8)';
// This is invokeai/frontend/web/public/assets/images/transparent_bg.png as a dataURL // This is invokeai/frontend/web/public/assets/images/transparent_bg.png as a dataURL
@ -53,13 +51,6 @@ const STAGE_BG_DATAURL =
const mapId = (object: { id: string }) => object.id; const mapId = (object: { id: string }) => object.id;
const getIsSelected = (layerId?: string | null) => {
if (!layerId) {
return false;
}
return layerId === getStore().getState().regionalPrompts.present.selectedLayerId;
};
const selectRenderableLayers = (n: Konva.Node) => const selectRenderableLayers = (n: Konva.Node) =>
n.name() === MASKED_GUIDANCE_LAYER_NAME || n.name() === CONTROLNET_LAYER_NAME; n.name() === MASKED_GUIDANCE_LAYER_NAME || n.name() === CONTROLNET_LAYER_NAME;
@ -560,29 +551,12 @@ const renderLayers = (
* @param konvaLayer The konva layer to attach the bounding box to. * @param konvaLayer The konva layer to attach the bounding box to.
* @param onBboxMouseDown Callback for when the bounding box is clicked. * @param onBboxMouseDown Callback for when the bounding box is clicked.
*/ */
const createBboxRect = (reduxLayer: Layer, konvaLayer: Konva.Layer, onBboxMouseDown: (layerId: string) => void) => { const createBboxRect = (reduxLayer: Layer, konvaLayer: Konva.Layer) => {
const rect = new Konva.Rect({ const rect = new Konva.Rect({
id: getLayerBboxId(reduxLayer.id), id: getLayerBboxId(reduxLayer.id),
name: LAYER_BBOX_NAME, name: LAYER_BBOX_NAME,
strokeWidth: 1, strokeWidth: 1,
}); });
rect.on('mousedown', function () {
onBboxMouseDown(reduxLayer.id);
});
rect.on('mouseover', function (e) {
if (getIsSelected(e.target.getLayer()?.id())) {
this.stroke(BBOX_SELECTED_STROKE);
} else {
this.stroke(BBOX_NOT_SELECTED_MOUSEOVER_STROKE);
}
});
rect.on('mouseout', function (e) {
if (getIsSelected(e.target.getLayer()?.id())) {
this.stroke(BBOX_SELECTED_STROKE);
} else {
this.stroke(BBOX_NOT_SELECTED_STROKE);
}
});
konvaLayer.add(rect); konvaLayer.add(rect);
return rect; return rect;
}; };
@ -600,10 +574,8 @@ const createBboxRect = (reduxLayer: Layer, konvaLayer: Konva.Layer, onBboxMouseD
const renderBbox = ( const renderBbox = (
stage: Konva.Stage, stage: Konva.Stage,
reduxLayers: Layer[], reduxLayers: Layer[],
selectedLayerId: string | null,
tool: Tool, tool: Tool,
onBboxChanged: (layerId: string, bbox: IRect | null) => void, onBboxChanged: (layerId: string, bbox: IRect | null) => void
onBboxMouseDown: (layerId: string) => void
) => { ) => {
// Hide all bboxes so they don't interfere with getClientRect // Hide all bboxes so they don't interfere with getClientRect
for (const bboxRect of stage.find<Konva.Rect>(`.${LAYER_BBOX_NAME}`)) { for (const bboxRect of stage.find<Konva.Rect>(`.${LAYER_BBOX_NAME}`)) {
@ -634,18 +606,16 @@ const renderBbox = (
continue; continue;
} }
const rect = const rect = konvaLayer.findOne<Konva.Rect>(`.${LAYER_BBOX_NAME}`) ?? createBboxRect(reduxLayer, konvaLayer);
konvaLayer.findOne<Konva.Rect>(`.${LAYER_BBOX_NAME}`) ??
createBboxRect(reduxLayer, konvaLayer, onBboxMouseDown);
rect.setAttrs({ rect.setAttrs({
visible: true, visible: true,
listening: true, listening: reduxLayer.isSelected,
x: bbox.x, x: bbox.x,
y: bbox.y, y: bbox.y,
width: bbox.width, width: bbox.width,
height: bbox.height, height: bbox.height,
stroke: reduxLayer.id === selectedLayerId ? BBOX_SELECTED_STROKE : BBOX_NOT_SELECTED_STROKE, stroke: reduxLayer.isSelected ? BBOX_SELECTED_STROKE : '',
}); });
} }
} }