feat(ui): disable most interaction while filtering

This commit is contained in:
psychedelicious 2024-08-23 20:32:49 +10:00
parent 799688514b
commit bb3ad8c2f1
11 changed files with 42 additions and 18 deletions

View File

@ -11,8 +11,8 @@ import { PiCheckBold, PiShootingStarBold, PiXBold } from 'react-icons/pi';
export const Filter = memo(() => { export const Filter = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const canvasManager = useCanvasManager(); const canvasManager = useCanvasManager();
const adapter = useStore(canvasManager.filter.$adapter);
const config = useStore(canvasManager.filter.$config); const config = useStore(canvasManager.filter.$config);
const isFiltering = useStore(canvasManager.filter.$isFiltering);
const isProcessing = useStore(canvasManager.filter.$isProcessing); const isProcessing = useStore(canvasManager.filter.$isProcessing);
const previewFilter = useCallback(() => { const previewFilter = useCallback(() => {
@ -41,7 +41,7 @@ export const Filter = memo(() => {
[canvasManager.filter.$config] [canvasManager.filter.$config]
); );
if (!adapter) { if (!isFiltering) {
return null; return null;
} }

View File

@ -1,5 +1,6 @@
import { IconButton } from '@invoke-ai/ui-library'; import { IconButton } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
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 { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
@ -10,12 +11,13 @@ import { PiBoundingBoxBold } from 'react-icons/pi';
export const ToolBboxButton = memo(() => { export const ToolBboxButton = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
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 isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'bbox');
const isDisabled = useMemo(() => { const isDisabled = useMemo(() => {
return isTransforming || isStaging; return isTransforming || isFiltering || isStaging;
}, [isStaging, isTransforming]); }, [isFiltering, isStaging, isTransforming]);
const onClick = useCallback(() => { const onClick = useCallback(() => {
dispatch(toolChanged('bbox')); dispatch(toolChanged('bbox'));

View File

@ -1,5 +1,6 @@
import { IconButton } from '@invoke-ai/ui-library'; import { IconButton } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
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 { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
import { isDrawableEntityType } from 'features/controlLayers/store/types'; import { isDrawableEntityType } from 'features/controlLayers/store/types';
@ -11,6 +12,7 @@ import { PiPaintBrushBold } from 'react-icons/pi';
export const ToolBrushButton = memo(() => { export const ToolBrushButton = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
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 isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'brush');
@ -22,8 +24,8 @@ export const ToolBrushButton = memo(() => {
}); });
const isDisabled = useMemo(() => { const isDisabled = useMemo(() => {
return isTransforming || isStaging || !isDrawingToolAllowed; return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;
}, [isDrawingToolAllowed, isStaging, isTransforming]); }, [isDrawingToolAllowed, isFiltering, isStaging, isTransforming]);
const onClick = useCallback(() => { const onClick = useCallback(() => {
dispatch(toolChanged('brush')); dispatch(toolChanged('brush'));

View File

@ -1,7 +1,7 @@
import { ButtonGroup } from '@invoke-ai/ui-library'; import { ButtonGroup } from '@invoke-ai/ui-library';
import { ToolBboxButton } from 'features/controlLayers/components/Tool/ToolBboxButton'; import { ToolBboxButton } from 'features/controlLayers/components/Tool/ToolBboxButton';
import { ToolBrushButton } from 'features/controlLayers/components/Tool/ToolBrushButton'; import { ToolBrushButton } from 'features/controlLayers/components/Tool/ToolBrushButton';
import { ToolColorPickerButton } from 'features/controlLayers/components/Tool/ToolEyeDropperButton'; import { ToolColorPickerButton } from 'features/controlLayers/components/Tool/ToolColorPickerButton';
import { ToolMoveButton } from 'features/controlLayers/components/Tool/ToolMoveButton'; import { ToolMoveButton } from 'features/controlLayers/components/Tool/ToolMoveButton';
import { ToolRectButton } from 'features/controlLayers/components/Tool/ToolRectButton'; import { ToolRectButton } from 'features/controlLayers/components/Tool/ToolRectButton';
import { useCanvasDeleteLayerHotkey } from 'features/controlLayers/hooks/useCanvasDeleteLayerHotkey'; import { useCanvasDeleteLayerHotkey } from 'features/controlLayers/hooks/useCanvasDeleteLayerHotkey';

View File

@ -1,5 +1,6 @@
import { IconButton } from '@invoke-ai/ui-library'; import { IconButton } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
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 { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
@ -10,13 +11,14 @@ import { PiEyedropperBold } from 'react-icons/pi';
export const ToolColorPickerButton = memo(() => { export const ToolColorPickerButton = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const isFiltering = useIsFiltering();
const isTransforming = useIsTransforming(); const isTransforming = useIsTransforming();
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'colorPicker'); const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === '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 || isStaging; return isTransforming || isFiltering || isStaging;
}, [isStaging, isTransforming]); }, [isFiltering, isStaging, isTransforming]);
const onClick = useCallback(() => { const onClick = useCallback(() => {
dispatch(toolChanged('colorPicker')); dispatch(toolChanged('colorPicker'));

View File

@ -1,5 +1,6 @@
import { IconButton } from '@invoke-ai/ui-library'; import { IconButton } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
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 { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
import { isDrawableEntityType } from 'features/controlLayers/store/types'; import { isDrawableEntityType } from 'features/controlLayers/store/types';
@ -11,6 +12,7 @@ import { PiEraserBold } from 'react-icons/pi';
export const ToolEraserButton = memo(() => { export const ToolEraserButton = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
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 isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'eraser');
@ -21,8 +23,8 @@ export const ToolEraserButton = memo(() => {
return isDrawableEntityType(s.canvasV2.selectedEntityIdentifier.type); return isDrawableEntityType(s.canvasV2.selectedEntityIdentifier.type);
}); });
const isDisabled = useMemo(() => { const isDisabled = useMemo(() => {
return isTransforming || isStaging || !isDrawingToolAllowed; return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;
}, [isDrawingToolAllowed, isStaging, isTransforming]); }, [isDrawingToolAllowed, isFiltering, isStaging, isTransforming]);
const onClick = useCallback(() => { const onClick = useCallback(() => {
dispatch(toolChanged('eraser')); dispatch(toolChanged('eraser'));

View File

@ -1,5 +1,6 @@
import { IconButton } from '@invoke-ai/ui-library'; import { IconButton } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
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 { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
import { isDrawableEntityType } from 'features/controlLayers/store/types'; import { isDrawableEntityType } from 'features/controlLayers/store/types';
@ -11,6 +12,7 @@ import { PiCursorBold } from 'react-icons/pi';
export const ToolMoveButton = memo(() => { export const ToolMoveButton = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const isFiltering = useIsFiltering();
const isTransforming = useIsTransforming(); const isTransforming = useIsTransforming();
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'move'); const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'move');
const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging); const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging);
@ -21,8 +23,8 @@ export const ToolMoveButton = memo(() => {
return isDrawableEntityType(s.canvasV2.selectedEntityIdentifier.type); return isDrawableEntityType(s.canvasV2.selectedEntityIdentifier.type);
}); });
const isDisabled = useMemo(() => { const isDisabled = useMemo(() => {
return isTransforming || isStaging || !isDrawingToolAllowed; return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;
}, [isDrawingToolAllowed, isStaging, isTransforming]); }, [isDrawingToolAllowed, isFiltering, isStaging, isTransforming]);
const onClick = useCallback(() => { const onClick = useCallback(() => {
dispatch(toolChanged('move')); dispatch(toolChanged('move'));

View File

@ -1,5 +1,6 @@
import { IconButton } from '@invoke-ai/ui-library'; import { IconButton } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
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 { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
import { isDrawableEntityType } from 'features/controlLayers/store/types'; import { isDrawableEntityType } from 'features/controlLayers/store/types';
@ -12,6 +13,7 @@ export const ToolRectButton = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'rect'); const isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'rect');
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 isDrawingToolAllowed = useAppSelector((s) => { const isDrawingToolAllowed = useAppSelector((s) => {
@ -22,8 +24,8 @@ export const ToolRectButton = memo(() => {
}); });
const isDisabled = useMemo(() => { const isDisabled = useMemo(() => {
return isTransforming || isStaging || !isDrawingToolAllowed; return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;
}, [isDrawingToolAllowed, isStaging, isTransforming]); }, [isDrawingToolAllowed, isFiltering, isStaging, isTransforming]);
const onClick = useCallback(() => { const onClick = useCallback(() => {
dispatch(toolChanged('rect')); dispatch(toolChanged('rect'));

View File

@ -1,5 +1,6 @@
import { IconButton } from '@invoke-ai/ui-library'; import { IconButton } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
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 { toolChanged } from 'features/controlLayers/store/canvasV2Slice';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
@ -11,11 +12,12 @@ export const ToolViewButton = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const isTransforming = useIsTransforming(); const isTransforming = useIsTransforming();
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 isSelected = useAppSelector((s) => s.canvasV2.tool.selected === 'view');
const isDisabled = useMemo(() => { const isDisabled = useMemo(() => {
return isTransforming || isStaging; return isTransforming || isFiltering || isStaging;
}, [isStaging, isTransforming]); }, [isFiltering, isStaging, isTransforming]);
const onClick = useCallback(() => { const onClick = useCallback(() => {
dispatch(toolChanged('view')); dispatch(toolChanged('view'));
}, [dispatch]); }, [dispatch]);

View File

@ -0,0 +1,8 @@
import { useStore } from '@nanostores/react';
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
export const useIsFiltering = () => {
const canvasManager = useCanvasManager();
const isFiltering = useStore(canvasManager.filter.$isFiltering);
return isFiltering;
};

View File

@ -4,7 +4,7 @@ import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import { getPrefixedId } from 'features/controlLayers/konva/util'; import { getPrefixedId } from 'features/controlLayers/konva/util';
import type { CanvasEntityIdentifier, CanvasImageState, FilterConfig } from 'features/controlLayers/store/types'; import type { CanvasEntityIdentifier, CanvasImageState, FilterConfig } from 'features/controlLayers/store/types';
import { IMAGE_FILTERS, imageDTOToImageObject } from 'features/controlLayers/store/types'; import { IMAGE_FILTERS, imageDTOToImageObject } from 'features/controlLayers/store/types';
import { atom } from 'nanostores'; import { atom, computed } from 'nanostores';
import type { Logger } from 'roarr'; import type { Logger } from 'roarr';
import { getImageDTO } from 'services/api/endpoints/images'; import { getImageDTO } from 'services/api/endpoints/images';
import type { BatchConfig, ImageDTO, S } from 'services/api/types'; import type { BatchConfig, ImageDTO, S } from 'services/api/types';
@ -23,6 +23,7 @@ export class CanvasFilterModule {
imageState: CanvasImageState | null = null; imageState: CanvasImageState | null = null;
$adapter = atom<CanvasLayerAdapter | null>(null); $adapter = atom<CanvasLayerAdapter | null>(null);
$isFiltering = computed(this.$adapter, (adapter) => Boolean(adapter));
$isProcessing = atom<boolean>(false); $isProcessing = atom<boolean>(false);
$config = atom<FilterConfig>(IMAGE_FILTERS.canny_image_processor.buildDefaults()); $config = atom<FilterConfig>(IMAGE_FILTERS.canny_image_processor.buildDefaults());
@ -46,6 +47,7 @@ export class CanvasFilterModule {
return; return;
} }
this.$adapter.set(entity.adapter); this.$adapter.set(entity.adapter);
this.manager.stateApi.setTool('view');
}; };
previewFilter = async () => { previewFilter = async () => {