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