mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): move ephemeral tool state out of redux
This commit is contained in:
parent
14c722c265
commit
9528287d56
@ -6,6 +6,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { useMouseEvents } from 'features/regionalPrompts/hooks/mouseEventHooks';
|
import { useMouseEvents } from 'features/regionalPrompts/hooks/mouseEventHooks';
|
||||||
import {
|
import {
|
||||||
$cursorPosition,
|
$cursorPosition,
|
||||||
|
$tool,
|
||||||
isRPLayer,
|
isRPLayer,
|
||||||
rpLayerBboxChanged,
|
rpLayerBboxChanged,
|
||||||
rpLayerTranslated,
|
rpLayerTranslated,
|
||||||
@ -35,6 +36,7 @@ const useStageRenderer = (container: HTMLDivElement | null, wrapper: HTMLDivElem
|
|||||||
const height = useAppSelector((s) => s.generation.height);
|
const height = useAppSelector((s) => s.generation.height);
|
||||||
const state = useAppSelector((s) => s.regionalPrompts.present);
|
const state = useAppSelector((s) => s.regionalPrompts.present);
|
||||||
const stage = useStore($stage);
|
const stage = useStore($stage);
|
||||||
|
const tool = useStore($tool);
|
||||||
const { onMouseDown, onMouseUp, onMouseMove, onMouseEnter, onMouseLeave } = useMouseEvents();
|
const { onMouseDown, onMouseUp, onMouseMove, onMouseEnter, onMouseLeave } = useMouseEvents();
|
||||||
const cursorPosition = useStore($cursorPosition);
|
const cursorPosition = useStore($cursorPosition);
|
||||||
const selectedLayerColor = useAppSelector(selectSelectedLayerColor);
|
const selectedLayerColor = useAppSelector(selectSelectedLayerColor);
|
||||||
@ -116,27 +118,28 @@ const useStageRenderer = (container: HTMLDivElement | null, wrapper: HTMLDivElem
|
|||||||
}, [stage, width, height, wrapper]);
|
}, [stage, width, height, wrapper]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
log.trace('Rendering brush preview');
|
||||||
if (!stage) {
|
if (!stage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderBrushPreview(stage, state.tool, selectedLayerColor, cursorPosition, state.brushSize);
|
renderBrushPreview(stage, tool, selectedLayerColor, cursorPosition, state.brushSize);
|
||||||
}, [stage, state.tool, cursorPosition, state.brushSize, selectedLayerColor]);
|
}, [stage, tool, cursorPosition, state.brushSize, selectedLayerColor]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
log.trace('Rendering layers');
|
log.trace('Rendering layers');
|
||||||
if (!stage) {
|
if (!stage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderLayers(stage, state.layers, state.selectedLayer, state.promptLayerOpacity, state.tool, onLayerPosChanged);
|
renderLayers(stage, state.layers, state.selectedLayer, state.promptLayerOpacity, tool, onLayerPosChanged);
|
||||||
}, [onLayerPosChanged, stage, state.layers, state.promptLayerOpacity, state.tool, state.selectedLayer]);
|
}, [onLayerPosChanged, stage, state.layers, state.promptLayerOpacity, tool, state.selectedLayer]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
log.trace('Rendering bbox');
|
log.trace('Rendering bbox');
|
||||||
if (!stage) {
|
if (!stage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderBbox(stage, state.tool, state.selectedLayer, onBboxChanged);
|
renderBbox(stage, tool, state.selectedLayer, onBboxChanged);
|
||||||
}, [dispatch, stage, state.tool, state.selectedLayer, onBboxChanged]);
|
}, [dispatch, stage, tool, state.selectedLayer, onBboxChanged]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const $container = atom<HTMLDivElement | null>(null);
|
const $container = atom<HTMLDivElement | null>(null);
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
import { ButtonGroup, IconButton } from '@invoke-ai/ui-library';
|
import { ButtonGroup, IconButton } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useStore } from '@nanostores/react';
|
||||||
import { toolChanged } from 'features/regionalPrompts/store/regionalPromptsSlice';
|
import { $tool } from 'features/regionalPrompts/store/regionalPromptsSlice';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { PiArrowsOutCardinalBold, PiEraserBold, PiPaintBrushBold } from 'react-icons/pi';
|
import { PiArrowsOutCardinalBold, PiEraserBold, PiPaintBrushBold } from 'react-icons/pi';
|
||||||
|
|
||||||
export const ToolChooser: React.FC = () => {
|
export const ToolChooser: React.FC = () => {
|
||||||
const tool = useAppSelector((s) => s.regionalPrompts.present.tool);
|
const tool = useStore($tool);
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const setToolToBrush = useCallback(() => {
|
const setToolToBrush = useCallback(() => {
|
||||||
dispatch(toolChanged('brush'));
|
$tool.set('brush');
|
||||||
}, [dispatch]);
|
}, []);
|
||||||
const setToolToEraser = useCallback(() => {
|
const setToolToEraser = useCallback(() => {
|
||||||
dispatch(toolChanged('eraser'));
|
$tool.set('eraser');
|
||||||
}, [dispatch]);
|
}, []);
|
||||||
const setToolToMove = useCallback(() => {
|
const setToolToMove = useCallback(() => {
|
||||||
dispatch(toolChanged('move'));
|
$tool.set('move');
|
||||||
}, [dispatch]);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonGroup isAttached>
|
<ButtonGroup isAttached>
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { getStore } from 'app/store/nanostores/store';
|
import { useStore } from '@nanostores/react';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
||||||
import {
|
import {
|
||||||
$cursorPosition,
|
$cursorPosition,
|
||||||
$isMouseDown,
|
$isMouseDown,
|
||||||
$isMouseOver,
|
$isMouseOver,
|
||||||
|
$tool,
|
||||||
rpLayerLineAdded,
|
rpLayerLineAdded,
|
||||||
rpLayerPointsAdded,
|
rpLayerPointsAdded,
|
||||||
} from 'features/regionalPrompts/store/regionalPromptsSlice';
|
} from 'features/regionalPrompts/store/regionalPromptsSlice';
|
||||||
@ -12,8 +13,6 @@ import type Konva from 'konva';
|
|||||||
import type { KonvaEventObject } from 'konva/lib/Node';
|
import type { KonvaEventObject } from 'konva/lib/Node';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
const getTool = () => getStore().getState().regionalPrompts.present.tool;
|
|
||||||
|
|
||||||
const getIsFocused = (stage: Konva.Stage) => {
|
const getIsFocused = (stage: Konva.Stage) => {
|
||||||
return stage.container().contains(document.activeElement);
|
return stage.container().contains(document.activeElement);
|
||||||
};
|
};
|
||||||
@ -29,6 +28,8 @@ const syncCursorPos = (stage: Konva.Stage) => {
|
|||||||
|
|
||||||
export const useMouseEvents = () => {
|
export const useMouseEvents = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
const selectedLayer = useAppSelector((s) => s.regionalPrompts.present.selectedLayer);
|
||||||
|
const tool = useStore($tool);
|
||||||
|
|
||||||
const onMouseDown = useCallback(
|
const onMouseDown = useCallback(
|
||||||
(e: KonvaEventObject<MouseEvent | TouchEvent>) => {
|
(e: KonvaEventObject<MouseEvent | TouchEvent>) => {
|
||||||
@ -41,12 +42,15 @@ export const useMouseEvents = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$isMouseDown.set(true);
|
$isMouseDown.set(true);
|
||||||
const tool = getTool();
|
if (!selectedLayer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// const tool = getTool();
|
||||||
if (tool === 'brush' || tool === 'eraser') {
|
if (tool === 'brush' || tool === 'eraser') {
|
||||||
dispatch(rpLayerLineAdded([pos.x, pos.y, pos.x, pos.y]));
|
dispatch(rpLayerLineAdded({ layerId: selectedLayer, points: [pos.x, pos.y, pos.x, pos.y], tool }));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch, selectedLayer, tool]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onMouseUp = useCallback(
|
const onMouseUp = useCallback(
|
||||||
@ -55,12 +59,12 @@ export const useMouseEvents = () => {
|
|||||||
if (!stage) {
|
if (!stage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tool = getTool();
|
// const tool = getTool();
|
||||||
if ((tool === 'brush' || tool === 'eraser') && $isMouseDown.get()) {
|
if ((tool === 'brush' || tool === 'eraser') && $isMouseDown.get()) {
|
||||||
$isMouseDown.set(false);
|
$isMouseDown.set(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[]
|
[tool]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onMouseMove = useCallback(
|
const onMouseMove = useCallback(
|
||||||
@ -70,15 +74,15 @@ export const useMouseEvents = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const pos = syncCursorPos(stage);
|
const pos = syncCursorPos(stage);
|
||||||
if (!pos) {
|
if (!pos || !selectedLayer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tool = getTool();
|
// const tool = getTool();
|
||||||
if (getIsFocused(stage) && $isMouseOver.get() && $isMouseDown.get() && (tool === 'brush' || tool === 'eraser')) {
|
if (getIsFocused(stage) && $isMouseOver.get() && $isMouseDown.get() && (tool === 'brush' || tool === 'eraser')) {
|
||||||
dispatch(rpLayerPointsAdded([pos.x, pos.y]));
|
dispatch(rpLayerPointsAdded({ layerId: selectedLayer, point: [pos.x, pos.y] }));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch, selectedLayer, tool]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onMouseLeave = useCallback((e: KonvaEventObject<MouseEvent | TouchEvent>) => {
|
const onMouseLeave = useCallback((e: KonvaEventObject<MouseEvent | TouchEvent>) => {
|
||||||
@ -109,13 +113,15 @@ export const useMouseEvents = () => {
|
|||||||
$isMouseDown.set(false);
|
$isMouseDown.set(false);
|
||||||
} else {
|
} else {
|
||||||
$isMouseDown.set(true);
|
$isMouseDown.set(true);
|
||||||
const tool = getTool();
|
if (!selectedLayer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (tool === 'brush' || tool === 'eraser') {
|
if (tool === 'brush' || tool === 'eraser') {
|
||||||
dispatch(rpLayerLineAdded([pos.x, pos.y, pos.x, pos.y]));
|
dispatch(rpLayerLineAdded({ layerId: selectedLayer, points: [pos.x, pos.y, pos.x, pos.y], tool }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch, selectedLayer, tool]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { onMouseDown, onMouseUp, onMouseMove, onMouseEnter, onMouseLeave };
|
return { onMouseDown, onMouseUp, onMouseMove, onMouseEnter, onMouseLeave };
|
||||||
|
@ -10,7 +10,9 @@ import type { UndoableOptions } from 'redux-undo';
|
|||||||
import { assert } from 'tsafe';
|
import { assert } from 'tsafe';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
export type Tool = 'brush' | 'eraser' | 'move';
|
export type DrawingTool = 'brush' | 'eraser';
|
||||||
|
|
||||||
|
export type RPTool = DrawingTool | 'move';
|
||||||
|
|
||||||
type LayerObjectBase = {
|
type LayerObjectBase = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -27,7 +29,7 @@ type ImageObject = LayerObjectBase & {
|
|||||||
|
|
||||||
type LineObject = LayerObjectBase & {
|
type LineObject = LayerObjectBase & {
|
||||||
kind: 'line';
|
kind: 'line';
|
||||||
tool: Tool;
|
tool: DrawingTool;
|
||||||
strokeWidth: number;
|
strokeWidth: number;
|
||||||
points: number[];
|
points: number[];
|
||||||
};
|
};
|
||||||
@ -63,7 +65,6 @@ export type Layer = RegionalPromptLayer;
|
|||||||
|
|
||||||
type RegionalPromptsState = {
|
type RegionalPromptsState = {
|
||||||
_version: 1;
|
_version: 1;
|
||||||
tool: Tool;
|
|
||||||
selectedLayer: string | null;
|
selectedLayer: string | null;
|
||||||
layers: Layer[];
|
layers: Layer[];
|
||||||
brushSize: number;
|
brushSize: number;
|
||||||
@ -73,7 +74,6 @@ type RegionalPromptsState = {
|
|||||||
|
|
||||||
export const initialRegionalPromptsState: RegionalPromptsState = {
|
export const initialRegionalPromptsState: RegionalPromptsState = {
|
||||||
_version: 1,
|
_version: 1,
|
||||||
tool: 'brush',
|
|
||||||
selectedLayer: null,
|
selectedLayer: null,
|
||||||
brushSize: 40,
|
brushSize: 40,
|
||||||
layers: [],
|
layers: [],
|
||||||
@ -197,34 +197,45 @@ export const regionalPromptsSlice = createSlice({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
rpLayerLineAdded: {
|
rpLayerLineAdded: {
|
||||||
reducer: (state, action: PayloadAction<[number, number, number, number], string, { uuid: string }>) => {
|
reducer: (
|
||||||
const layer = state.layers.find((l) => l.id === state.selectedLayer);
|
state,
|
||||||
|
action: PayloadAction<
|
||||||
|
{ layerId: string; points: [number, number, number, number]; tool: DrawingTool },
|
||||||
|
string,
|
||||||
|
{ uuid: string }
|
||||||
|
>
|
||||||
|
) => {
|
||||||
|
const { layerId, points, tool } = action.payload;
|
||||||
|
const layer = state.layers.find((l) => l.id === layerId);
|
||||||
if (isRPLayer(layer)) {
|
if (isRPLayer(layer)) {
|
||||||
const lineId = getRPLayerLineId(layer.id, action.meta.uuid);
|
const lineId = getRPLayerLineId(layer.id, action.meta.uuid);
|
||||||
layer.objects.push({
|
layer.objects.push({
|
||||||
kind: 'line',
|
kind: 'line',
|
||||||
tool: state.tool,
|
tool: tool,
|
||||||
id: lineId,
|
id: lineId,
|
||||||
points: [
|
// Points must be offset by the layer's x and y coordinates
|
||||||
action.payload[0] - layer.x,
|
// TODO: Handle this in the event listener
|
||||||
action.payload[1] - layer.y,
|
points: [points[0] - layer.x, points[1] - layer.y, points[2] - layer.x, points[3] - layer.y],
|
||||||
action.payload[2] - layer.x,
|
|
||||||
action.payload[3] - layer.y,
|
|
||||||
],
|
|
||||||
strokeWidth: state.brushSize,
|
strokeWidth: state.brushSize,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
prepare: (payload: [number, number, number, number]) => ({ payload, meta: { uuid: uuidv4() } }),
|
prepare: (payload: { layerId: string; points: [number, number, number, number]; tool: DrawingTool }) => ({
|
||||||
|
payload,
|
||||||
|
meta: { uuid: uuidv4() },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
rpLayerPointsAdded: (state, action: PayloadAction<[number, number]>) => {
|
rpLayerPointsAdded: (state, action: PayloadAction<{ layerId: string; point: [number, number] }>) => {
|
||||||
const layer = state.layers.find((l) => l.id === state.selectedLayer);
|
const { layerId, point } = action.payload;
|
||||||
|
const layer = state.layers.find((l) => l.id === layerId);
|
||||||
if (isRPLayer(layer)) {
|
if (isRPLayer(layer)) {
|
||||||
const lastLine = layer.objects.findLast(isLine);
|
const lastLine = layer.objects.findLast(isLine);
|
||||||
if (!lastLine) {
|
if (!lastLine) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastLine.points.push(action.payload[0] - layer.x, action.payload[1] - layer.y);
|
// Points must be offset by the layer's x and y coordinates
|
||||||
|
// TODO: Handle this in the event listener
|
||||||
|
lastLine.points.push(point[0] - layer.x, point[1] - layer.y);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rpLayerAutoNegativeChanged: (
|
rpLayerAutoNegativeChanged: (
|
||||||
@ -242,9 +253,6 @@ export const regionalPromptsSlice = createSlice({
|
|||||||
brushSizeChanged: (state, action: PayloadAction<number>) => {
|
brushSizeChanged: (state, action: PayloadAction<number>) => {
|
||||||
state.brushSize = action.payload;
|
state.brushSize = action.payload;
|
||||||
},
|
},
|
||||||
toolChanged: (state, action: PayloadAction<Tool>) => {
|
|
||||||
state.tool = action.payload;
|
|
||||||
},
|
|
||||||
promptLayerOpacityChanged: (state, action: PayloadAction<number>) => {
|
promptLayerOpacityChanged: (state, action: PayloadAction<number>) => {
|
||||||
state.promptLayerOpacity = action.payload;
|
state.promptLayerOpacity = action.payload;
|
||||||
},
|
},
|
||||||
@ -304,7 +312,6 @@ export const {
|
|||||||
isEnabledChanged,
|
isEnabledChanged,
|
||||||
brushSizeChanged,
|
brushSizeChanged,
|
||||||
promptLayerOpacityChanged,
|
promptLayerOpacityChanged,
|
||||||
toolChanged,
|
|
||||||
} = regionalPromptsSlice.actions;
|
} = regionalPromptsSlice.actions;
|
||||||
|
|
||||||
export const selectRegionalPromptsSlice = (state: RootState) => state.regionalPrompts;
|
export const selectRegionalPromptsSlice = (state: RootState) => state.regionalPrompts;
|
||||||
@ -316,6 +323,7 @@ const migrateRegionalPromptsState = (state: any): any => {
|
|||||||
|
|
||||||
export const $isMouseDown = atom(false);
|
export const $isMouseDown = atom(false);
|
||||||
export const $isMouseOver = atom(false);
|
export const $isMouseOver = atom(false);
|
||||||
|
export const $tool = atom<RPTool>('brush');
|
||||||
export const $cursorPosition = atom<Vector2d | null>(null);
|
export const $cursorPosition = atom<Vector2d | null>(null);
|
||||||
|
|
||||||
// IDs for singleton layers and objects
|
// IDs for singleton layers and objects
|
||||||
@ -394,10 +402,6 @@ export const regionalPromptsUndoableConfig: UndoableOptions<RegionalPromptsState
|
|||||||
if (rpLayerBboxChanged.match(action)) {
|
if (rpLayerBboxChanged.match(action)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// We don't want to record tool changes in the undo history
|
|
||||||
if (toolChanged.match(action)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { rgbColorToString } from 'features/canvas/util/colorToString';
|
import { rgbColorToString } from 'features/canvas/util/colorToString';
|
||||||
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
|
||||||
import type { Layer, RegionalPromptLayer, Tool } from 'features/regionalPrompts/store/regionalPromptsSlice';
|
import type { Layer, RegionalPromptLayer, RPTool } from 'features/regionalPrompts/store/regionalPromptsSlice';
|
||||||
import {
|
import {
|
||||||
BRUSH_PREVIEW_BORDER_INNER_ID,
|
BRUSH_PREVIEW_BORDER_INNER_ID,
|
||||||
BRUSH_PREVIEW_BORDER_OUTER_ID,
|
BRUSH_PREVIEW_BORDER_OUTER_ID,
|
||||||
@ -36,7 +36,7 @@ const mapId = (object: { id: string }) => object.id;
|
|||||||
*/
|
*/
|
||||||
export const renderBrushPreview = (
|
export const renderBrushPreview = (
|
||||||
stage: Konva.Stage,
|
stage: Konva.Stage,
|
||||||
tool: Tool,
|
tool: RPTool,
|
||||||
color: RgbColor | null,
|
color: RgbColor | null,
|
||||||
cursorPos: Vector2d | null,
|
cursorPos: Vector2d | null,
|
||||||
brushSize: number
|
brushSize: number
|
||||||
@ -130,7 +130,7 @@ const renderRPLayer = (
|
|||||||
rpLayer: RegionalPromptLayer,
|
rpLayer: RegionalPromptLayer,
|
||||||
rpLayerIndex: number,
|
rpLayerIndex: number,
|
||||||
selectedLayerId: string | null,
|
selectedLayerId: string | null,
|
||||||
tool: Tool,
|
tool: RPTool,
|
||||||
layerOpacity: number,
|
layerOpacity: number,
|
||||||
onLayerPosChanged?: (layerId: string, x: number, y: number) => void
|
onLayerPosChanged?: (layerId: string, x: number, y: number) => void
|
||||||
) => {
|
) => {
|
||||||
@ -278,7 +278,7 @@ export const renderLayers = (
|
|||||||
reduxLayers: Layer[],
|
reduxLayers: Layer[],
|
||||||
selectedLayerId: string | null,
|
selectedLayerId: string | null,
|
||||||
layerOpacity: number,
|
layerOpacity: number,
|
||||||
tool: Tool,
|
tool: RPTool,
|
||||||
onLayerPosChanged?: (layerId: string, x: number, y: number) => void
|
onLayerPosChanged?: (layerId: string, x: number, y: number) => void
|
||||||
) => {
|
) => {
|
||||||
const reduxLayerIds = reduxLayers.map(mapId);
|
const reduxLayerIds = reduxLayers.map(mapId);
|
||||||
@ -312,7 +312,7 @@ const selectPromptLayerObjectGroup = (item: Node<NodeConfig>) =>
|
|||||||
*/
|
*/
|
||||||
export const renderBbox = (
|
export const renderBbox = (
|
||||||
stage: Konva.Stage,
|
stage: Konva.Stage,
|
||||||
tool: Tool,
|
tool: RPTool,
|
||||||
selectedLayerId: string | null,
|
selectedLayerId: string | null,
|
||||||
onBboxChanged: (layerId: string, bbox: IRect) => void
|
onBboxChanged: (layerId: string, bbox: IRect) => void
|
||||||
) => {
|
) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user