mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): move selected tool and tool buffer out of redux
This ephemeral state can live in the canvas classes.
This commit is contained in:
parent
9c1732e2bb
commit
17e76981bb
@ -1,14 +1,12 @@
|
||||
/* eslint-disable i18next/no-literal-string */
|
||||
import { Flex, Spacer } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { CanvasModeSwitcher } from 'features/controlLayers/components/CanvasModeSwitcher';
|
||||
import { CanvasResetViewButton } from 'features/controlLayers/components/CanvasResetViewButton';
|
||||
import { CanvasScale } from 'features/controlLayers/components/CanvasScale';
|
||||
import { CanvasSettingsPopover } from 'features/controlLayers/components/Settings/CanvasSettingsPopover';
|
||||
import { ToolBrushWidth } from 'features/controlLayers/components/Tool/ToolBrushWidth';
|
||||
import { ToolChooser } from 'features/controlLayers/components/Tool/ToolChooser';
|
||||
import { ToolEraserWidth } from 'features/controlLayers/components/Tool/ToolEraserWidth';
|
||||
import { ToolFillColorPicker } from 'features/controlLayers/components/Tool/ToolFillColorPicker';
|
||||
import { ToolSettings } from 'features/controlLayers/components/Tool/ToolSettings';
|
||||
import { UndoRedoButtonGroup } from 'features/controlLayers/components/UndoRedoButtonGroup';
|
||||
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import { ToggleProgressButton } from 'features/gallery/components/ImageViewer/ToggleProgressButton';
|
||||
@ -16,15 +14,13 @@ import { ViewerToggleMenu } from 'features/gallery/components/ImageViewer/Viewer
|
||||
import { memo } from 'react';
|
||||
|
||||
export const ControlLayersToolbar = memo(() => {
|
||||
const tool = useAppSelector((s) => s.canvasV2.tool.selected);
|
||||
return (
|
||||
<CanvasManagerProviderGate>
|
||||
<Flex w="full" gap={2} alignItems="center">
|
||||
<ToggleProgressButton />
|
||||
<ToolChooser />
|
||||
<Spacer />
|
||||
{tool === 'brush' && <ToolBrushWidth />}
|
||||
{tool === 'eraser' && <ToolEraserWidth />}
|
||||
<ToolSettings />
|
||||
<Spacer />
|
||||
<CanvasScale />
|
||||
<CanvasResetViewButton />
|
||||
|
@ -1,29 +1,25 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useIsFiltering } from 'features/controlLayers/hooks/useIsFiltering';
|
||||
import { useIsTransforming } from 'features/controlLayers/hooks/useIsTransforming';
|
||||
import { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiBoundingBoxBold } from 'react-icons/pi';
|
||||
|
||||
export const ToolBboxButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const selectBbox = useSelectTool('bbox');
|
||||
const isSelected = useToolIsSelected('bbox');
|
||||
const isFiltering = useIsFiltering();
|
||||
const isTransforming = useIsTransforming();
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'bbox');
|
||||
const isDisabled = useMemo(() => {
|
||||
return isTransforming || isFiltering || isStaging;
|
||||
}, [isFiltering, isStaging, isTransforming]);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(toolChanged('bbox'));
|
||||
}, [dispatch]);
|
||||
|
||||
useHotkeys('q', onClick, { enabled: !isDisabled || isSelected }, [onClick, isSelected, isDisabled]);
|
||||
useHotkeys('q', selectBbox, { enabled: !isDisabled || isSelected }, [selectBbox, isSelected, isDisabled]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
@ -32,7 +28,7 @@ export const ToolBboxButton = memo(() => {
|
||||
icon={<PiBoundingBoxBold />}
|
||||
colorScheme={isSelected ? 'invokeBlue' : 'base'}
|
||||
variant="outline"
|
||||
onClick={onClick}
|
||||
onClick={selectBbox}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
|
@ -1,21 +1,21 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useIsFiltering } from 'features/controlLayers/hooks/useIsFiltering';
|
||||
import { useIsTransforming } from 'features/controlLayers/hooks/useIsTransforming';
|
||||
import { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { isDrawableEntityType } from 'features/controlLayers/store/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiPaintBrushBold } from 'react-icons/pi';
|
||||
|
||||
export const ToolBrushButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isFiltering = useIsFiltering();
|
||||
const isTransforming = useIsTransforming();
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'brush');
|
||||
const selectBrush = useSelectTool('brush');
|
||||
const isSelected = useToolIsSelected('brush');
|
||||
const isDrawingToolAllowed = useAppSelector((s) => {
|
||||
if (!s.canvasV2.selectedEntityIdentifier?.type) {
|
||||
return false;
|
||||
@ -27,11 +27,7 @@ export const ToolBrushButton = memo(() => {
|
||||
return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;
|
||||
}, [isDrawingToolAllowed, isFiltering, isStaging, isTransforming]);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(toolChanged('brush'));
|
||||
}, [dispatch]);
|
||||
|
||||
useHotkeys('b', onClick, { enabled: !isDisabled || isSelected }, [isDisabled, isSelected, onClick]);
|
||||
useHotkeys('b', selectBrush, { enabled: !isDisabled || isSelected }, [isDisabled, isSelected, selectBrush]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
@ -40,7 +36,7 @@ export const ToolBrushButton = memo(() => {
|
||||
icon={<PiPaintBrushBold />}
|
||||
colorScheme={isSelected ? 'invokeBlue' : 'base'}
|
||||
variant="outline"
|
||||
onClick={onClick}
|
||||
onClick={selectBrush}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
|
@ -1,30 +1,30 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useIsFiltering } from 'features/controlLayers/hooks/useIsFiltering';
|
||||
import { useIsTransforming } from 'features/controlLayers/hooks/useIsTransforming';
|
||||
import { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiEyedropperBold } from 'react-icons/pi';
|
||||
|
||||
export const ToolColorPickerButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isFiltering = useIsFiltering();
|
||||
const isTransforming = useIsTransforming();
|
||||
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'colorPicker');
|
||||
const selectColorPicker = useSelectTool('colorPicker');
|
||||
const isSelected = useToolIsSelected('colorPicker');
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
|
||||
const isDisabled = useMemo(() => {
|
||||
return isTransforming || isFiltering || isStaging;
|
||||
}, [isFiltering, isStaging, isTransforming]);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(toolChanged('colorPicker'));
|
||||
}, [dispatch]);
|
||||
|
||||
useHotkeys('i', onClick, { enabled: !isDisabled || isSelected }, [onClick, isSelected, isDisabled]);
|
||||
useHotkeys('i', selectColorPicker, { enabled: !isDisabled || isSelected }, [
|
||||
selectColorPicker,
|
||||
isSelected,
|
||||
isDisabled,
|
||||
]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
@ -33,7 +33,7 @@ export const ToolColorPickerButton = memo(() => {
|
||||
icon={<PiEyedropperBold />}
|
||||
colorScheme={isSelected ? 'invokeBlue' : 'base'}
|
||||
variant="outline"
|
||||
onClick={onClick}
|
||||
onClick={selectColorPicker}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
|
@ -1,21 +1,21 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useIsFiltering } from 'features/controlLayers/hooks/useIsFiltering';
|
||||
import { useIsTransforming } from 'features/controlLayers/hooks/useIsTransforming';
|
||||
import { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { isDrawableEntityType } from 'features/controlLayers/store/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiEraserBold } from 'react-icons/pi';
|
||||
|
||||
export const ToolEraserButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isFiltering = useIsFiltering();
|
||||
const isTransforming = useIsTransforming();
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'eraser');
|
||||
const selectEraser = useSelectTool('eraser');
|
||||
const isSelected = useToolIsSelected('eraser');
|
||||
const isDrawingToolAllowed = useAppSelector((s) => {
|
||||
if (!s.canvasV2.selectedEntityIdentifier?.type) {
|
||||
return false;
|
||||
@ -26,11 +26,7 @@ export const ToolEraserButton = memo(() => {
|
||||
return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;
|
||||
}, [isDrawingToolAllowed, isFiltering, isStaging, isTransforming]);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(toolChanged('eraser'));
|
||||
}, [dispatch]);
|
||||
|
||||
useHotkeys('e', onClick, { enabled: !isDisabled || isSelected }, [isDisabled, isSelected, onClick]);
|
||||
useHotkeys('e', selectEraser, { enabled: !isDisabled || isSelected }, [isDisabled, isSelected, selectEraser]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
@ -39,7 +35,7 @@ export const ToolEraserButton = memo(() => {
|
||||
icon={<PiEraserBold />}
|
||||
colorScheme={isSelected ? 'invokeBlue' : 'base'}
|
||||
variant="outline"
|
||||
onClick={onClick}
|
||||
onClick={selectEraser}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
|
@ -1,20 +1,20 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useIsFiltering } from 'features/controlLayers/hooks/useIsFiltering';
|
||||
import { useIsTransforming } from 'features/controlLayers/hooks/useIsTransforming';
|
||||
import { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { isDrawableEntityType } from 'features/controlLayers/store/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiCursorBold } from 'react-icons/pi';
|
||||
|
||||
export const ToolMoveButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isFiltering = useIsFiltering();
|
||||
const isTransforming = useIsTransforming();
|
||||
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'move');
|
||||
const selectMove = useSelectTool('move');
|
||||
const isSelected = useToolIsSelected('move');
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
const isDrawingToolAllowed = useAppSelector((s) => {
|
||||
if (!s.canvasV2.selectedEntityIdentifier?.type) {
|
||||
@ -26,11 +26,7 @@ export const ToolMoveButton = memo(() => {
|
||||
return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;
|
||||
}, [isDrawingToolAllowed, isFiltering, isStaging, isTransforming]);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(toolChanged('move'));
|
||||
}, [dispatch]);
|
||||
|
||||
useHotkeys('v', onClick, { enabled: !isDisabled || isSelected }, [isDisabled, isSelected, onClick]);
|
||||
useHotkeys('v', selectMove, { enabled: !isDisabled || isSelected }, [isDisabled, isSelected, selectMove]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
@ -39,7 +35,7 @@ export const ToolMoveButton = memo(() => {
|
||||
icon={<PiCursorBold />}
|
||||
colorScheme={isSelected ? 'invokeBlue' : 'base'}
|
||||
variant="outline"
|
||||
onClick={onClick}
|
||||
onClick={selectMove}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useIsFiltering } from 'features/controlLayers/hooks/useIsFiltering';
|
||||
import { useIsTransforming } from 'features/controlLayers/hooks/useIsTransforming';
|
||||
import { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { isDrawableEntityType } from 'features/controlLayers/store/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiRectangleBold } from 'react-icons/pi';
|
||||
|
||||
export const ToolRectButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'rect');
|
||||
const selectRect = useSelectTool('rect');
|
||||
const isSelected = useToolIsSelected('rect');
|
||||
const isFiltering = useIsFiltering();
|
||||
const isTransforming = useIsTransforming();
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
@ -27,11 +27,7 @@ export const ToolRectButton = memo(() => {
|
||||
return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;
|
||||
}, [isDrawingToolAllowed, isFiltering, isStaging, isTransforming]);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(toolChanged('rect'));
|
||||
}, [dispatch]);
|
||||
|
||||
useHotkeys('u', onClick, { enabled: !isDisabled || isSelected }, [isDisabled, isSelected, onClick]);
|
||||
useHotkeys('u', selectRect, { enabled: !isDisabled || isSelected }, [isDisabled, isSelected, selectRect]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
@ -40,7 +36,7 @@ export const ToolRectButton = memo(() => {
|
||||
icon={<PiRectangleBold />}
|
||||
colorScheme={isSelected ? 'invokeBlue' : 'base'}
|
||||
variant="outline"
|
||||
onClick={onClick}
|
||||
onClick={selectRect}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
|
@ -0,0 +1,19 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { ToolBrushWidth } from 'features/controlLayers/components/Tool/ToolBrushWidth';
|
||||
import { ToolEraserWidth } from 'features/controlLayers/components/Tool/ToolEraserWidth';
|
||||
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import { memo } from 'react';
|
||||
|
||||
export const ToolSettings = memo(() => {
|
||||
const canvasManager = useCanvasManager();
|
||||
const tool = useStore(canvasManager.stateApi.$tool);
|
||||
if (tool === 'brush') {
|
||||
return <ToolBrushWidth />;
|
||||
}
|
||||
if (tool === 'eraser') {
|
||||
return <ToolEraserWidth />;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
ToolSettings.displayName = 'ToolSettings';
|
@ -1,28 +1,25 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useSelectTool, useToolIsSelected } from 'features/controlLayers/components/Tool/hooks';
|
||||
import { useIsFiltering } from 'features/controlLayers/hooks/useIsFiltering';
|
||||
import { useIsTransforming } from 'features/controlLayers/hooks/useIsTransforming';
|
||||
import { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiHandBold } from 'react-icons/pi';
|
||||
|
||||
export const ToolViewButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isTransforming = useIsTransforming();
|
||||
const isFiltering = useIsFiltering();
|
||||
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
|
||||
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'view');
|
||||
const selectView = useSelectTool('view');
|
||||
const isSelected = useToolIsSelected('view');
|
||||
const isDisabled = useMemo(() => {
|
||||
return isTransforming || isFiltering || isStaging;
|
||||
}, [isFiltering, isStaging, isTransforming]);
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(toolChanged('view'));
|
||||
}, [dispatch]);
|
||||
|
||||
useHotkeys('h', onClick, { enabled: !isDisabled || isSelected }, [onClick, isSelected, isDisabled]);
|
||||
useHotkeys('h', selectView, { enabled: !isDisabled || isSelected }, [selectView, isSelected, isDisabled]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
@ -31,7 +28,7 @@ export const ToolViewButton = memo(() => {
|
||||
icon={<PiHandBold />}
|
||||
colorScheme={isSelected ? 'invokeBlue' : 'base'}
|
||||
variant="outline"
|
||||
onClick={onClick}
|
||||
onClick={selectView}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
|
@ -0,0 +1,19 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import type { Tool } from 'features/controlLayers/store/types';
|
||||
import { computed } from 'nanostores';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useToolIsSelected = (tool: Tool) => {
|
||||
const canvasManager = useCanvasManager();
|
||||
const isSelected = useStore(computed(canvasManager.stateApi.$tool, (t) => t === tool));
|
||||
return isSelected;
|
||||
};
|
||||
|
||||
export const useSelectTool = (tool: Tool) => {
|
||||
const canvasManager = useCanvasManager();
|
||||
const setTool = useCallback(() => {
|
||||
canvasManager.stateApi.$tool.set(tool);
|
||||
}, [canvasManager.stateApi.$tool, tool]);
|
||||
return setTool;
|
||||
};
|
@ -31,6 +31,11 @@ export class CanvasBboxModule {
|
||||
manager: CanvasManager;
|
||||
log: Logger;
|
||||
|
||||
/**
|
||||
* A set of subscriptions that should be cleaned up when the transformer is destroyed.
|
||||
*/
|
||||
subscriptions: Set<() => void> = new Set();
|
||||
|
||||
konva: {
|
||||
group: Konva.Group;
|
||||
rect: Konva.Rect;
|
||||
@ -228,17 +233,19 @@ export class CanvasBboxModule {
|
||||
this.konva.transformer.nodes([this.konva.rect]);
|
||||
this.konva.group.add(this.konva.rect);
|
||||
this.konva.group.add(this.konva.transformer);
|
||||
|
||||
this.subscriptions.add(this.manager.stateApi.$tool.listen(this.render));
|
||||
}
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
this.log.trace('Rendering generation bbox');
|
||||
|
||||
const bbox = this.manager.stateApi.getBbox();
|
||||
const toolState = this.manager.stateApi.getToolState();
|
||||
const tool = this.manager.stateApi.$tool.get();
|
||||
|
||||
this.konva.group.visible(true);
|
||||
this.parent.getLayer().listening(toolState.selected === 'bbox');
|
||||
this.konva.group.listening(toolState.selected === 'bbox');
|
||||
this.parent.getLayer().listening(tool === 'bbox');
|
||||
this.konva.group.listening(tool === 'bbox');
|
||||
this.konva.rect.setAttrs({
|
||||
x: bbox.rect.x,
|
||||
y: bbox.rect.y,
|
||||
@ -246,13 +253,21 @@ export class CanvasBboxModule {
|
||||
height: bbox.rect.height,
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
listening: toolState.selected === 'bbox',
|
||||
listening: tool === 'bbox',
|
||||
});
|
||||
this.konva.transformer.setAttrs({
|
||||
listening: toolState.selected === 'bbox',
|
||||
enabledAnchors: toolState.selected === 'bbox' ? ALL_ANCHORS : NO_ANCHORS,
|
||||
listening: tool === 'bbox',
|
||||
enabledAnchors: tool === 'bbox' ? ALL_ANCHORS : NO_ANCHORS,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
destroy = () => {
|
||||
this.log.trace('Destroying generation bbox');
|
||||
for (const unsubscribe of this.subscriptions) {
|
||||
unsubscribe();
|
||||
}
|
||||
this.konva.group.destroy();
|
||||
};
|
||||
|
||||
getLoggingContext = (): SerializableObject => {
|
||||
return { ...this.manager.getLoggingContext(), path: this.path.join('.') };
|
||||
|
@ -47,7 +47,7 @@ export class CanvasFilterModule {
|
||||
return;
|
||||
}
|
||||
this.$adapter.set(entity.adapter);
|
||||
this.manager.stateApi.setTool('view');
|
||||
this.manager.stateApi.$tool.set('view');
|
||||
};
|
||||
|
||||
previewFilter = async () => {
|
||||
|
@ -156,11 +156,12 @@ export class CanvasObjectRenderer {
|
||||
this.parent.konva.layer.add(this.konva.compositing.group);
|
||||
}
|
||||
|
||||
// When switching tool, commit the buffer. This is necessary to prevent the buffer from being lost when the
|
||||
// user switches tool mid-drawing, for example by pressing space to pan the stage. It's easy to press space
|
||||
// to pan _before_ releasing the mouse button, which would cause the buffer to be lost if we didn't commit it.
|
||||
this.subscriptions.add(
|
||||
this.manager.stateApi.$toolState.listen((newVal, oldVal) => {
|
||||
if (newVal.selected !== oldVal.selected) {
|
||||
this.commitBuffer();
|
||||
}
|
||||
this.manager.stateApi.$tool.listen(() => {
|
||||
this.commitBuffer();
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -145,7 +145,6 @@ export class CanvasRenderingModule {
|
||||
if (
|
||||
!prevState ||
|
||||
state.regions.entities !== prevState.regions.entities ||
|
||||
state.tool.selected !== prevState.tool.selected ||
|
||||
state.selectedEntityIdentifier?.id !== prevState.selectedEntityIdentifier?.id
|
||||
) {
|
||||
// Destroy the konva nodes for nonexistent entities
|
||||
@ -184,7 +183,6 @@ export class CanvasRenderingModule {
|
||||
if (
|
||||
!prevState ||
|
||||
state.inpaintMasks.entities !== prevState.inpaintMasks.entities ||
|
||||
state.tool.selected !== prevState.tool.selected ||
|
||||
state.selectedEntityIdentifier?.id !== prevState.selectedEntityIdentifier?.id
|
||||
) {
|
||||
// Destroy the konva nodes for nonexistent entities
|
||||
@ -212,7 +210,7 @@ export class CanvasRenderingModule {
|
||||
};
|
||||
|
||||
renderBbox = (state: CanvasV2State, prevState: CanvasV2State | null) => {
|
||||
if (!prevState || state.bbox !== prevState.bbox || state.tool.selected !== prevState.tool.selected) {
|
||||
if (!prevState || state.bbox !== prevState.bbox) {
|
||||
this.manager.preview.bbox.render();
|
||||
}
|
||||
};
|
||||
|
@ -15,8 +15,6 @@ import {
|
||||
entitySelected,
|
||||
eraserWidthChanged,
|
||||
fillChanged,
|
||||
toolBufferChanged,
|
||||
toolChanged,
|
||||
} from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { selectAllRenderableEntities } from 'features/controlLayers/store/selectors';
|
||||
import type {
|
||||
@ -115,12 +113,6 @@ export class CanvasStateApiModule {
|
||||
setEraserWidth = (width: number) => {
|
||||
this.store.dispatch(eraserWidthChanged(width));
|
||||
};
|
||||
setTool = (tool: Tool) => {
|
||||
this.store.dispatch(toolChanged(tool));
|
||||
};
|
||||
setToolBuffer = (toolBuffer: Tool | null) => {
|
||||
this.store.dispatch(toolBufferChanged(toolBuffer));
|
||||
};
|
||||
setFill = (fill: RgbaColor) => {
|
||||
return this.store.dispatch(fillChanged(fill));
|
||||
};
|
||||
@ -245,6 +237,8 @@ export class CanvasStateApiModule {
|
||||
$colorUnderCursor: WritableAtom<RgbColor> = atom(RGBA_BLACK);
|
||||
|
||||
// Read-write state, ephemeral interaction state
|
||||
$tool = atom<Tool>('brush');
|
||||
$toolBuffer = atom<Tool | null>(null);
|
||||
$isDrawing = atom<boolean>(false);
|
||||
$isMouseDown = atom<boolean>(false);
|
||||
$lastAddedPoint = atom<Coordinate | null>(null);
|
||||
|
@ -231,17 +231,9 @@ export class CanvasToolModule {
|
||||
);
|
||||
this.konva.group.add(this.konva.colorPicker.group);
|
||||
|
||||
this.subscriptions.add(
|
||||
this.manager.stateApi.$stageAttrs.listen(() => {
|
||||
this.render();
|
||||
})
|
||||
);
|
||||
|
||||
this.subscriptions.add(
|
||||
this.manager.stateApi.$toolState.listen(() => {
|
||||
this.render();
|
||||
})
|
||||
);
|
||||
this.subscriptions.add(this.manager.stateApi.$stageAttrs.listen(this.render));
|
||||
this.subscriptions.add(this.manager.stateApi.$toolState.listen(this.render));
|
||||
this.subscriptions.add(this.manager.stateApi.$tool.listen(this.render));
|
||||
|
||||
const cleanupListeners = this.setEventListeners();
|
||||
|
||||
@ -261,15 +253,14 @@ export class CanvasToolModule {
|
||||
this.konva.colorPicker.group.visible(tool === 'colorPicker');
|
||||
};
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
const stage = this.manager.stage;
|
||||
const renderedEntityCount = this.manager.stateApi.getRenderedEntityCount();
|
||||
const toolState = this.manager.stateApi.getToolState();
|
||||
const selectedEntity = this.manager.stateApi.getSelectedEntity();
|
||||
const cursorPos = this.manager.stateApi.$lastCursorPos.get();
|
||||
const isMouseDown = this.manager.stateApi.$isMouseDown.get();
|
||||
|
||||
const tool = toolState.selected;
|
||||
const tool = this.manager.stateApi.$tool.get();
|
||||
|
||||
const isDrawable = selectedEntity && selectedEntity.state.isEnabled && isDrawableEntity(selectedEntity.state);
|
||||
|
||||
@ -447,7 +438,7 @@ export class CanvasToolModule {
|
||||
|
||||
this.setToolVisibility(tool);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
syncLastCursorPos = (): Coordinate | null => {
|
||||
const pos = getScaledCursorPosition(this.konva.stage);
|
||||
@ -480,9 +471,9 @@ export class CanvasToolModule {
|
||||
return { r, g, b };
|
||||
};
|
||||
|
||||
getClip(
|
||||
getClip = (
|
||||
entity: CanvasRegionalGuidanceState | CanvasControlLayerState | CanvasRasterLayerState | CanvasInpaintMaskState
|
||||
) {
|
||||
) => {
|
||||
const settings = this.manager.stateApi.getSettings();
|
||||
|
||||
if (settings.clipToBbox) {
|
||||
@ -504,7 +495,7 @@ export class CanvasToolModule {
|
||||
height: height / scale,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setEventListeners = (): (() => void) => {
|
||||
this.konva.stage.on('mouseenter', this.onStageMouseEnter);
|
||||
@ -537,10 +528,11 @@ export class CanvasToolModule {
|
||||
onStageMouseDown = async (e: KonvaEventObject<MouseEvent>) => {
|
||||
this.manager.stateApi.$isMouseDown.set(true);
|
||||
const toolState = this.manager.stateApi.getToolState();
|
||||
const tool = this.manager.stateApi.$tool.get();
|
||||
const pos = this.syncLastCursorPos();
|
||||
const selectedEntity = this.manager.stateApi.getSelectedEntity();
|
||||
|
||||
if (toolState.selected === 'colorPicker') {
|
||||
if (tool === 'colorPicker') {
|
||||
const color = this.getColorUnderCursor();
|
||||
if (color) {
|
||||
this.manager.stateApi.$colorUnderCursor.set(color);
|
||||
@ -555,7 +547,7 @@ export class CanvasToolModule {
|
||||
this.manager.stateApi.$lastMouseDownPos.set(pos);
|
||||
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
|
||||
|
||||
if (toolState.selected === 'brush') {
|
||||
if (tool === 'brush') {
|
||||
const lastLinePoint = selectedEntity.adapter.getLastPointOfLastLine('brush_line');
|
||||
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.brush.width);
|
||||
if (e.evt.shiftKey && lastLinePoint) {
|
||||
@ -594,7 +586,7 @@ export class CanvasToolModule {
|
||||
this.manager.stateApi.$lastAddedPoint.set(alignedPoint);
|
||||
}
|
||||
|
||||
if (toolState.selected === 'eraser') {
|
||||
if (tool === 'eraser') {
|
||||
const lastLinePoint = selectedEntity.adapter.getLastPointOfLastLine('eraser_line');
|
||||
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.eraser.width);
|
||||
if (e.evt.shiftKey && lastLinePoint) {
|
||||
@ -630,7 +622,7 @@ export class CanvasToolModule {
|
||||
this.manager.stateApi.$lastAddedPoint.set(alignedPoint);
|
||||
}
|
||||
|
||||
if (toolState.selected === 'rect') {
|
||||
if (tool === 'rect') {
|
||||
if (selectedEntity.adapter.renderer.bufferState) {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
}
|
||||
@ -650,11 +642,10 @@ export class CanvasToolModule {
|
||||
const pos = this.manager.stateApi.$lastCursorPos.get();
|
||||
const selectedEntity = this.manager.stateApi.getSelectedEntity();
|
||||
const isDrawable = selectedEntity?.state.isEnabled;
|
||||
const tool = this.manager.stateApi.$tool.get();
|
||||
|
||||
if (pos && isDrawable && !this.manager.stateApi.$spaceKey.get()) {
|
||||
const toolState = this.manager.stateApi.getToolState();
|
||||
|
||||
if (toolState.selected === 'brush') {
|
||||
if (tool === 'brush') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer?.type === 'brush_line') {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
@ -663,7 +654,7 @@ export class CanvasToolModule {
|
||||
}
|
||||
}
|
||||
|
||||
if (toolState.selected === 'eraser') {
|
||||
if (tool === 'eraser') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer?.type === 'eraser_line') {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
@ -672,7 +663,7 @@ export class CanvasToolModule {
|
||||
}
|
||||
}
|
||||
|
||||
if (toolState.selected === 'rect') {
|
||||
if (tool === 'rect') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer?.type === 'rect') {
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
@ -690,8 +681,9 @@ export class CanvasToolModule {
|
||||
const toolState = this.manager.stateApi.getToolState();
|
||||
const pos = this.syncLastCursorPos();
|
||||
const selectedEntity = this.manager.stateApi.getSelectedEntity();
|
||||
const tool = this.manager.stateApi.$tool.get();
|
||||
|
||||
if (toolState.selected === 'colorPicker') {
|
||||
if (tool === 'colorPicker') {
|
||||
const color = this.getColorUnderCursor();
|
||||
if (color) {
|
||||
this.manager.stateApi.$colorUnderCursor.set(color);
|
||||
@ -699,7 +691,7 @@ export class CanvasToolModule {
|
||||
} else {
|
||||
const isDrawable = selectedEntity?.state.isEnabled;
|
||||
if (pos && isDrawable && !this.manager.stateApi.$spaceKey.get() && getIsPrimaryMouseDown(e)) {
|
||||
if (toolState.selected === 'brush') {
|
||||
if (tool === 'brush') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer) {
|
||||
if (drawingBuffer.type === 'brush_line') {
|
||||
@ -736,7 +728,7 @@ export class CanvasToolModule {
|
||||
}
|
||||
}
|
||||
|
||||
if (toolState.selected === 'eraser') {
|
||||
if (tool === 'eraser') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer) {
|
||||
if (drawingBuffer.type === 'eraser_line') {
|
||||
@ -772,7 +764,7 @@ export class CanvasToolModule {
|
||||
}
|
||||
}
|
||||
|
||||
if (toolState.selected === 'rect') {
|
||||
if (tool === 'rect') {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
if (drawingBuffer) {
|
||||
if (drawingBuffer.type === 'rect') {
|
||||
@ -798,21 +790,22 @@ export class CanvasToolModule {
|
||||
const selectedEntity = this.manager.stateApi.getSelectedEntity();
|
||||
const toolState = this.manager.stateApi.getToolState();
|
||||
const isDrawable = selectedEntity?.state.isEnabled;
|
||||
const tool = this.manager.stateApi.$tool.get();
|
||||
|
||||
if (pos && isDrawable && !this.manager.stateApi.$spaceKey.get() && getIsPrimaryMouseDown(e)) {
|
||||
const drawingBuffer = selectedEntity.adapter.renderer.bufferState;
|
||||
const normalizedPoint = offsetCoord(pos, selectedEntity.state.position);
|
||||
if (toolState.selected === 'brush' && drawingBuffer?.type === 'brush_line') {
|
||||
if (tool === 'brush' && drawingBuffer?.type === 'brush_line') {
|
||||
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.brush.width);
|
||||
drawingBuffer.points.push(alignedPoint.x, alignedPoint.y);
|
||||
await selectedEntity.adapter.renderer.setBuffer(drawingBuffer);
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
} else if (toolState.selected === 'eraser' && drawingBuffer?.type === 'eraser_line') {
|
||||
} else if (tool === 'eraser' && drawingBuffer?.type === 'eraser_line') {
|
||||
const alignedPoint = alignCoordForTool(normalizedPoint, toolState.eraser.width);
|
||||
drawingBuffer.points.push(alignedPoint.x, alignedPoint.y);
|
||||
await selectedEntity.adapter.renderer.setBuffer(drawingBuffer);
|
||||
selectedEntity.adapter.renderer.commitBuffer();
|
||||
} else if (toolState.selected === 'rect' && drawingBuffer?.type === 'rect') {
|
||||
} else if (tool === 'rect' && drawingBuffer?.type === 'rect') {
|
||||
drawingBuffer.rect.width = Math.round(normalizedPoint.x - drawingBuffer.rect.x);
|
||||
drawingBuffer.rect.height = Math.round(normalizedPoint.y - drawingBuffer.rect.y);
|
||||
await selectedEntity.adapter.renderer.setBuffer(drawingBuffer);
|
||||
@ -831,6 +824,7 @@ export class CanvasToolModule {
|
||||
}
|
||||
|
||||
const toolState = this.manager.stateApi.getToolState();
|
||||
const tool = this.manager.stateApi.$tool.get();
|
||||
|
||||
let delta = e.evt.deltaY;
|
||||
|
||||
@ -839,9 +833,9 @@ export class CanvasToolModule {
|
||||
}
|
||||
|
||||
// Holding ctrl or meta while scrolling changes the brush size
|
||||
if (toolState.selected === 'brush') {
|
||||
if (tool === 'brush') {
|
||||
this.manager.stateApi.setBrushWidth(calculateNewBrushSizeFromWheelDelta(toolState.brush.width, delta));
|
||||
} else if (toolState.selected === 'eraser') {
|
||||
} else if (tool === 'eraser') {
|
||||
this.manager.stateApi.setEraserWidth(calculateNewBrushSizeFromWheelDelta(toolState.eraser.width, delta));
|
||||
}
|
||||
|
||||
@ -864,8 +858,8 @@ export class CanvasToolModule {
|
||||
}
|
||||
} else if (e.key === ' ') {
|
||||
// Select the view tool on space key down
|
||||
this.manager.stateApi.setToolBuffer(this.manager.stateApi.getToolState().selected);
|
||||
this.manager.stateApi.setTool('view');
|
||||
this.manager.stateApi.$toolBuffer.set(this.manager.stateApi.$tool.get());
|
||||
this.manager.stateApi.$tool.set('view');
|
||||
this.manager.stateApi.$spaceKey.set(true);
|
||||
this.manager.stateApi.$lastCursorPos.set(null);
|
||||
this.manager.stateApi.$lastMouseDownPos.set(null);
|
||||
@ -881,9 +875,9 @@ export class CanvasToolModule {
|
||||
}
|
||||
if (e.key === ' ') {
|
||||
// Revert the tool to the previous tool on space key up
|
||||
const toolBuffer = this.manager.stateApi.getToolState().selectedBuffer;
|
||||
this.manager.stateApi.setTool(toolBuffer ?? 'move');
|
||||
this.manager.stateApi.setToolBuffer(null);
|
||||
const toolBuffer = this.manager.stateApi.$toolBuffer.get();
|
||||
this.manager.stateApi.$tool.set(toolBuffer ?? 'move');
|
||||
this.manager.stateApi.$toolBuffer.set(null);
|
||||
this.manager.stateApi.$spaceKey.set(false);
|
||||
}
|
||||
};
|
||||
|
@ -381,20 +381,10 @@ export class CanvasTransformer {
|
||||
);
|
||||
|
||||
// When the selected tool changes, we need to update the transformer's interaction state.
|
||||
this.subscriptions.add(
|
||||
this.manager.stateApi.$toolState.listen((newVal, oldVal) => {
|
||||
if (newVal.selected !== oldVal.selected) {
|
||||
this.syncInteractionState();
|
||||
}
|
||||
})
|
||||
);
|
||||
this.subscriptions.add(this.manager.stateApi.$tool.listen(this.syncInteractionState));
|
||||
|
||||
// When the selected entity changes, we need to update the transformer's interaction state.
|
||||
this.subscriptions.add(
|
||||
this.manager.stateApi.$selectedEntityIdentifier.listen(() => {
|
||||
this.syncInteractionState();
|
||||
})
|
||||
);
|
||||
this.subscriptions.add(this.manager.stateApi.$selectedEntityIdentifier.listen(this.syncInteractionState));
|
||||
|
||||
this.parent.konva.layer.add(this.konva.outlineRect);
|
||||
this.parent.konva.layer.add(this.konva.proxyRect);
|
||||
@ -439,7 +429,7 @@ export class CanvasTransformer {
|
||||
return;
|
||||
}
|
||||
|
||||
const toolState = this.manager.stateApi.getToolState();
|
||||
const tool = this.manager.stateApi.$tool.get();
|
||||
const isSelected = this.manager.stateApi.getIsSelected(this.parent.id);
|
||||
|
||||
if (!this.parent.renderer.hasObjects()) {
|
||||
@ -449,14 +439,14 @@ export class CanvasTransformer {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSelected && !this.isTransforming && toolState.selected === 'move') {
|
||||
if (isSelected && !this.isTransforming && tool === 'move') {
|
||||
// We are moving this layer, it must be listening
|
||||
this.parent.konva.layer.listening(true);
|
||||
this.setInteractionMode('drag');
|
||||
} else if (isSelected && this.isTransforming) {
|
||||
// When transforming, we want the stage to still be movable if the view tool is selected. If the transformer is
|
||||
// active, it will interrupt the stage drag events. So we should disable listening when the view tool is selected.
|
||||
if (toolState.selected !== 'view') {
|
||||
if (tool !== 'view') {
|
||||
this.parent.konva.layer.listening(true);
|
||||
this.setInteractionMode('all');
|
||||
} else {
|
||||
@ -493,11 +483,12 @@ export class CanvasTransformer {
|
||||
startTransform = () => {
|
||||
this.log.debug('Starting transform');
|
||||
this.isTransforming = true;
|
||||
this.manager.stateApi.setTool('move');
|
||||
this.manager.stateApi.$tool.set('move');
|
||||
// When transforming, we want the stage to still be movable if the view tool is selected. If the transformer or
|
||||
// interaction rect are listening, it will interrupt the stage's drag events. So we should disable listening
|
||||
// when the view tool is selected
|
||||
const shouldListen = this.manager.stateApi.getToolState().selected !== 'view';
|
||||
// TODO(psyche): We just set the tool to 'move', why would it be 'view'? Investigate and figure out if this is needed
|
||||
const shouldListen = this.manager.stateApi.$tool.get() !== 'view';
|
||||
this.parent.konva.layer.listening(shouldListen);
|
||||
this.setInteractionMode('all');
|
||||
this.manager.stateApi.$transformingEntity.set(this.parent.getEntityIdentifier());
|
||||
|
@ -58,8 +58,6 @@ const initialState: CanvasV2State = {
|
||||
loras: [],
|
||||
ipAdapters: { entities: [] },
|
||||
tool: {
|
||||
selected: 'view',
|
||||
selectedBuffer: null,
|
||||
invertScroll: false,
|
||||
fill: { r: 31, g: 160, b: 224, a: 1 }, // invokeBlue.500
|
||||
brush: {
|
||||
@ -140,17 +138,19 @@ export const canvasV2Slice = createSlice({
|
||||
name: 'canvasV2',
|
||||
initialState,
|
||||
reducers: {
|
||||
// undoable canvas state
|
||||
...rasterLayersReducers,
|
||||
...controlLayersReducers,
|
||||
...ipAdaptersReducers,
|
||||
...regionsReducers,
|
||||
...inpaintMaskReducers,
|
||||
...bboxReducers,
|
||||
// move out
|
||||
...lorasReducers,
|
||||
...paramsReducers,
|
||||
...compositingReducers,
|
||||
...settingsReducers,
|
||||
...toolReducers,
|
||||
...bboxReducers,
|
||||
...inpaintMaskReducers,
|
||||
...sessionReducers,
|
||||
entitySelected: (state, action: PayloadAction<EntityIdentifierPayload>) => {
|
||||
const { entityIdentifier } = action.payload;
|
||||
@ -424,8 +424,6 @@ export const {
|
||||
eraserWidthChanged,
|
||||
fillChanged,
|
||||
invertScrollChanged,
|
||||
toolChanged,
|
||||
toolBufferChanged,
|
||||
clipToBboxChanged,
|
||||
canvasReset,
|
||||
settingsDynamicGridToggled,
|
||||
|
@ -5,10 +5,6 @@ export const sessionReducers = {
|
||||
sessionStartedStaging: (state) => {
|
||||
state.session.isStaging = true;
|
||||
state.session.selectedStagedImageIndex = 0;
|
||||
// When we start staging, the user should not be interacting with the stage except to move it around. Set the tool
|
||||
// to view.
|
||||
state.tool.selectedBuffer = state.tool.selected;
|
||||
state.tool.selected = 'view';
|
||||
},
|
||||
sessionImageStaged: (state, action: PayloadAction<{ stagingAreaImage: StagingAreaImage }>) => {
|
||||
const { stagingAreaImage } = action.payload;
|
||||
@ -39,11 +35,6 @@ export const sessionReducers = {
|
||||
state.session.isStaging = false;
|
||||
state.session.stagedImages = [];
|
||||
state.session.selectedStagedImageIndex = 0;
|
||||
// When we finish staging, reset the tool back to the previous selection.
|
||||
if (state.tool.selectedBuffer) {
|
||||
state.tool.selected = state.tool.selectedBuffer;
|
||||
state.tool.selectedBuffer = null;
|
||||
}
|
||||
},
|
||||
sessionModeChanged: (state, action: PayloadAction<{ mode: SessionMode }>) => {
|
||||
const { mode } = action.payload;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
||||
import type { CanvasV2State, RgbaColor, Tool } from 'features/controlLayers/store/types';
|
||||
import type { CanvasV2State, RgbaColor } from 'features/controlLayers/store/types';
|
||||
|
||||
export const toolReducers = {
|
||||
brushWidthChanged: (state, action: PayloadAction<number>) => {
|
||||
@ -14,10 +14,4 @@ export const toolReducers = {
|
||||
invertScrollChanged: (state, action: PayloadAction<boolean>) => {
|
||||
state.tool.invertScroll = action.payload;
|
||||
},
|
||||
toolChanged: (state, action: PayloadAction<Tool>) => {
|
||||
state.tool.selected = action.payload;
|
||||
},
|
||||
toolBufferChanged: (state, action: PayloadAction<Tool | null>) => {
|
||||
state.tool.selectedBuffer = action.payload;
|
||||
},
|
||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
||||
|
@ -736,8 +736,6 @@ export type CanvasV2State = {
|
||||
};
|
||||
loras: LoRA[];
|
||||
tool: {
|
||||
selected: Tool;
|
||||
selectedBuffer: Tool | null;
|
||||
invertScroll: boolean;
|
||||
brush: { width: number };
|
||||
eraser: { width: number };
|
||||
|
Loading…
Reference in New Issue
Block a user