mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): consolidate isolated preview settings
`isolatedFilteringPreview` and `isolatedTransformingPreview` are merged into `isolatedLayerPreview`. This is also used for segment anything.
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { FormControl, FormLabel, Switch, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectIsolatedLayerPreview,
|
||||
settingsIsolatedLayerPreviewToggled,
|
||||
} from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const CanvasOperationIsolatedLayerPreviewSwitch = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isolatedLayerPreview = useAppSelector(selectIsolatedLayerPreview);
|
||||
const onChangeIsolatedPreview = useCallback(() => {
|
||||
dispatch(settingsIsolatedLayerPreviewToggled());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<Tooltip label={t('controlLayers.settings.isolatedLayerPreviewDesc')}>
|
||||
<FormControl w="min-content">
|
||||
<FormLabel m={0}>{t('controlLayers.settings.isolatedLayerPreview')}</FormLabel>
|
||||
<Switch size="sm" isChecked={isolatedLayerPreview} onChange={onChangeIsolatedPreview} />
|
||||
</FormControl>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
|
||||
CanvasOperationIsolatedLayerPreviewSwitch.displayName = 'CanvasOperationIsolatedLayerPreviewSwitch';
|
||||
@@ -2,6 +2,7 @@ import { Button, ButtonGroup, Flex, FormControl, FormLabel, Heading, Spacer, Swi
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useFocusRegion, useIsRegionFocused } from 'common/hooks/focus';
|
||||
import { CanvasOperationIsolatedLayerPreviewSwitch } from 'features/controlLayers/components/CanvasOperationIsolatedLayerPreviewSwitch';
|
||||
import { FilterSettings } from 'features/controlLayers/components/Filters/FilterSettings';
|
||||
import { FilterTypeSelect } from 'features/controlLayers/components/Filters/FilterTypeSelect';
|
||||
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
@@ -9,9 +10,7 @@ import type { CanvasEntityAdapterControlLayer } from 'features/controlLayers/kon
|
||||
import type { CanvasEntityAdapterRasterLayer } from 'features/controlLayers/konva/CanvasEntity/CanvasEntityAdapterRasterLayer';
|
||||
import {
|
||||
selectAutoProcessFilter,
|
||||
selectIsolatedFilteringPreview,
|
||||
settingsAutoProcessFilterToggled,
|
||||
settingsIsolatedFilteringPreviewToggled,
|
||||
} from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import type { FilterConfig } from 'features/controlLayers/store/filters';
|
||||
import { IMAGE_FILTERS } from 'features/controlLayers/store/filters';
|
||||
@@ -26,16 +25,11 @@ const FilterContent = memo(
|
||||
const dispatch = useAppDispatch();
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
useFocusRegion('canvas', ref, { focusOnMount: true });
|
||||
|
||||
const config = useStore(adapter.filterer.$filterConfig);
|
||||
const isCanvasFocused = useIsRegionFocused('canvas');
|
||||
const isProcessing = useStore(adapter.filterer.$isProcessing);
|
||||
const hasProcessed = useStore(adapter.filterer.$hasProcessed);
|
||||
const autoProcessFilter = useAppSelector(selectAutoProcessFilter);
|
||||
const isolatedFilteringPreview = useAppSelector(selectIsolatedFilteringPreview);
|
||||
const onChangeIsolatedPreview = useCallback(() => {
|
||||
dispatch(settingsIsolatedFilteringPreviewToggled());
|
||||
}, [dispatch]);
|
||||
|
||||
const onChangeFilterConfig = useCallback(
|
||||
(filterConfig: FilterConfig) => {
|
||||
@@ -98,10 +92,7 @@ const FilterContent = memo(
|
||||
<FormLabel m={0}>{t('controlLayers.filter.autoProcess')}</FormLabel>
|
||||
<Switch size="sm" isChecked={autoProcessFilter} onChange={onChangeAutoProcessFilter} />
|
||||
</FormControl>
|
||||
<FormControl w="min-content">
|
||||
<FormLabel m={0}>{t('controlLayers.settings.isolatedPreview')}</FormLabel>
|
||||
<Switch size="sm" isChecked={isolatedFilteringPreview} onChange={onChangeIsolatedPreview} />
|
||||
</FormControl>
|
||||
<CanvasOperationIsolatedLayerPreviewSwitch />
|
||||
</Flex>
|
||||
<FilterTypeSelect filterType={config.type} onChange={onChangeFilterType} />
|
||||
<FilterSettings filterConfig={config} onChange={onChangeFilterConfig} />
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Button, ButtonGroup, Flex, Heading, Spacer } from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useFocusRegion, useIsRegionFocused } from 'common/hooks/focus';
|
||||
import { CanvasOperationIsolatedLayerPreviewSwitch } from 'features/controlLayers/components/CanvasOperationIsolatedLayerPreviewSwitch';
|
||||
import { SegmentAnythingPointType } from 'features/controlLayers/components/SegmentAnything/SegmentAnythingPointType';
|
||||
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import type { CanvasEntityAdapterControlLayer } from 'features/controlLayers/konva/CanvasEntity/CanvasEntityAdapterControlLayer';
|
||||
@@ -52,6 +53,8 @@ const SegmentAnythingContent = memo(
|
||||
<Heading size="md" color="base.300" userSelect="none">
|
||||
{t('controlLayers.segment.segment')}
|
||||
</Heading>
|
||||
<Spacer />
|
||||
<CanvasOperationIsolatedLayerPreviewSwitch />
|
||||
</Flex>
|
||||
|
||||
<SegmentAnythingPointType adapter={adapter} />
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectIsolatedFilteringPreview,
|
||||
settingsIsolatedFilteringPreviewToggled,
|
||||
selectIsolatedLayerPreview,
|
||||
settingsIsolatedLayerPreviewToggled,
|
||||
} from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const CanvasSettingsIsolatedFilteringPreviewSwitch = memo(() => {
|
||||
export const CanvasSettingsIsolatedLayerPreviewSwitch = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isolatedFilteringPreview = useAppSelector(selectIsolatedFilteringPreview);
|
||||
const isolatedLayerPreview = useAppSelector(selectIsolatedLayerPreview);
|
||||
const onChange = useCallback(() => {
|
||||
dispatch(settingsIsolatedFilteringPreviewToggled());
|
||||
dispatch(settingsIsolatedLayerPreviewToggled());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<FormLabel m={0} flexGrow={1}>
|
||||
{t('controlLayers.settings.isolatedFilteringPreview')}
|
||||
{t('controlLayers.settings.isolatedLayerPreview')}
|
||||
</FormLabel>
|
||||
<Switch size="sm" isChecked={isolatedFilteringPreview} onChange={onChange} />
|
||||
<Switch size="sm" isChecked={isolatedLayerPreview} onChange={onChange} />
|
||||
</FormControl>
|
||||
);
|
||||
});
|
||||
|
||||
CanvasSettingsIsolatedFilteringPreviewSwitch.displayName = 'CanvasSettingsIsolatedFilteringPreviewSwitch';
|
||||
CanvasSettingsIsolatedLayerPreviewSwitch.displayName = 'CanvasSettingsIsolatedLayerPreviewSwitch';
|
||||
@@ -1,28 +0,0 @@
|
||||
import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectIsolatedTransformingPreview,
|
||||
settingsIsolatedTransformingPreviewToggled,
|
||||
} from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const CanvasSettingsIsolatedTransformingPreviewSwitch = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isolatedTransformingPreview = useAppSelector(selectIsolatedTransformingPreview);
|
||||
const onChange = useCallback(() => {
|
||||
dispatch(settingsIsolatedTransformingPreviewToggled());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<FormLabel m={0} flexGrow={1}>
|
||||
{t('controlLayers.settings.isolatedTransformingPreview')}
|
||||
</FormLabel>
|
||||
<Switch size="sm" isChecked={isolatedTransformingPreview} onChange={onChange} />
|
||||
</FormControl>
|
||||
);
|
||||
});
|
||||
|
||||
CanvasSettingsIsolatedTransformingPreviewSwitch.displayName = 'CanvasSettingsIsolatedTransformingPreviewSwitch';
|
||||
@@ -16,9 +16,8 @@ import { CanvasSettingsClipToBboxCheckbox } from 'features/controlLayers/compone
|
||||
import { CanvasSettingsDynamicGridSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsDynamicGridSwitch';
|
||||
import { CanvasSettingsSnapToGridCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsGridSize';
|
||||
import { CanvasSettingsInvertScrollCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsInvertScrollCheckbox';
|
||||
import { CanvasSettingsIsolatedFilteringPreviewSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsIsolatedFilteringPreviewSwitch';
|
||||
import { CanvasSettingsIsolatedLayerPreviewSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsIsolatedLayerPreviewSwitch';
|
||||
import { CanvasSettingsIsolatedStagingPreviewSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsIsolatedStagingPreviewSwitch';
|
||||
import { CanvasSettingsIsolatedTransformingPreviewSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsIsolatedTransformingPreviewSwitch';
|
||||
import { CanvasSettingsLogDebugInfoButton } from 'features/controlLayers/components/Settings/CanvasSettingsLogDebugInfo';
|
||||
import { CanvasSettingsOutputOnlyMaskedRegionsCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsOutputOnlyMaskedRegionsCheckbox';
|
||||
import { CanvasSettingsPreserveMaskCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsPreserveMaskCheckbox';
|
||||
@@ -54,8 +53,7 @@ export const CanvasSettingsPopover = memo(() => {
|
||||
<CanvasSettingsPressureSensitivityCheckbox />
|
||||
<CanvasSettingsShowProgressOnCanvas />
|
||||
<CanvasSettingsIsolatedStagingPreviewSwitch />
|
||||
<CanvasSettingsIsolatedFilteringPreviewSwitch />
|
||||
<CanvasSettingsIsolatedTransformingPreviewSwitch />
|
||||
<CanvasSettingsIsolatedLayerPreviewSwitch />
|
||||
<CanvasSettingsDynamicGridSwitch />
|
||||
<CanvasSettingsBboxOverlaySwitch />
|
||||
<CanvasSettingsShowHUDSwitch />
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
import { Button, ButtonGroup, Flex, FormControl, FormLabel, Heading, Spacer, Switch } from '@invoke-ai/ui-library';
|
||||
import { Button, ButtonGroup, Flex, Heading, Spacer } from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useFocusRegion, useIsRegionFocused } from 'common/hooks/focus';
|
||||
import { CanvasOperationIsolatedLayerPreviewSwitch } from 'features/controlLayers/components/CanvasOperationIsolatedLayerPreviewSwitch';
|
||||
import { TransformFitToBboxButtons } from 'features/controlLayers/components/Transform/TransformFitToBboxButtons';
|
||||
import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import type { CanvasEntityAdapter } from 'features/controlLayers/konva/CanvasEntity/types';
|
||||
import {
|
||||
selectIsolatedTransformingPreview,
|
||||
settingsIsolatedTransformingPreviewToggled,
|
||||
} from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import { memo, useCallback, useRef } from 'react';
|
||||
import { memo, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiArrowsCounterClockwiseBold, PiCheckBold, PiXBold } from 'react-icons/pi';
|
||||
|
||||
const TransformContent = memo(({ adapter }: { adapter: CanvasEntityAdapter }) => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
useFocusRegion('canvas', ref, { focusOnMount: true });
|
||||
const isCanvasFocused = useIsRegionFocused('canvas');
|
||||
const isProcessing = useStore(adapter.transformer.$isProcessing);
|
||||
const isolatedTransformingPreview = useAppSelector(selectIsolatedTransformingPreview);
|
||||
const onChangeIsolatedPreview = useCallback(() => {
|
||||
dispatch(settingsIsolatedTransformingPreviewToggled());
|
||||
}, [dispatch]);
|
||||
const silentTransform = useStore(adapter.transformer.$silentTransform);
|
||||
|
||||
useRegisteredHotkeys({
|
||||
@@ -66,10 +57,7 @@ const TransformContent = memo(({ adapter }: { adapter: CanvasEntityAdapter }) =>
|
||||
{t('controlLayers.transform.transform')}
|
||||
</Heading>
|
||||
<Spacer />
|
||||
<FormControl w="min-content">
|
||||
<FormLabel m={0}>{t('controlLayers.settings.isolatedPreview')}</FormLabel>
|
||||
<Switch size="sm" isChecked={isolatedTransformingPreview} onChange={onChangeIsolatedPreview} />
|
||||
</FormControl>
|
||||
<CanvasOperationIsolatedLayerPreviewSwitch />
|
||||
</Flex>
|
||||
|
||||
<TransformFitToBboxButtons adapter={adapter} />
|
||||
|
||||
@@ -12,10 +12,7 @@ import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||
import { CanvasModuleBase } from 'features/controlLayers/konva/CanvasModuleBase';
|
||||
import type { CanvasSegmentAnythingModule } from 'features/controlLayers/konva/CanvasSegmentAnythingModule';
|
||||
import { getKonvaNodeDebugAttrs, getRectIntersection } from 'features/controlLayers/konva/util';
|
||||
import {
|
||||
selectIsolatedFilteringPreview,
|
||||
selectIsolatedTransformingPreview,
|
||||
} from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import { selectIsolatedLayerPreview } from 'features/controlLayers/store/canvasSettingsSlice';
|
||||
import {
|
||||
buildSelectIsHidden,
|
||||
buildSelectIsSelected,
|
||||
@@ -274,13 +271,11 @@ export abstract class CanvasEntityAdapterBase<
|
||||
*/
|
||||
this.subscriptions.add(this.manager.stateApi.createStoreSubscription(this.selectIsHidden, this.syncVisibility));
|
||||
this.subscriptions.add(
|
||||
this.manager.stateApi.createStoreSubscription(selectIsolatedFilteringPreview, this.syncVisibility)
|
||||
this.manager.stateApi.createStoreSubscription(selectIsolatedLayerPreview, this.syncVisibility)
|
||||
);
|
||||
this.subscriptions.add(this.manager.stateApi.$filteringAdapter.listen(this.syncVisibility));
|
||||
this.subscriptions.add(
|
||||
this.manager.stateApi.createStoreSubscription(selectIsolatedTransformingPreview, this.syncVisibility)
|
||||
);
|
||||
this.subscriptions.add(this.manager.stateApi.$transformingAdapter.listen(this.syncVisibility));
|
||||
this.subscriptions.add(this.manager.stateApi.$segmentingAdapter.listen(this.syncVisibility));
|
||||
this.subscriptions.add(this.manager.stateApi.createStoreSubscription(this.selectIsSelected, this.syncVisibility));
|
||||
|
||||
/**
|
||||
@@ -445,8 +440,10 @@ export abstract class CanvasEntityAdapterBase<
|
||||
return;
|
||||
}
|
||||
|
||||
const isolatedLayerPreview = this.manager.stateApi.runSelector(selectIsolatedLayerPreview);
|
||||
|
||||
// Handle isolated preview modes - if another entity is filtering or transforming, we may need to hide this entity.
|
||||
if (this.manager.stateApi.runSelector(selectIsolatedFilteringPreview)) {
|
||||
if (isolatedLayerPreview) {
|
||||
const filteringEntityIdentifier = this.manager.stateApi.$filteringAdapter.get()?.entityIdentifier;
|
||||
if (filteringEntityIdentifier && filteringEntityIdentifier.id !== this.id) {
|
||||
this.setVisibility(false);
|
||||
@@ -454,7 +451,7 @@ export abstract class CanvasEntityAdapterBase<
|
||||
}
|
||||
}
|
||||
|
||||
if (this.manager.stateApi.runSelector(selectIsolatedTransformingPreview)) {
|
||||
if (isolatedLayerPreview) {
|
||||
const transformingEntity = this.manager.stateApi.$transformingAdapter.get();
|
||||
if (
|
||||
transformingEntity &&
|
||||
@@ -467,6 +464,14 @@ export abstract class CanvasEntityAdapterBase<
|
||||
}
|
||||
}
|
||||
|
||||
if (isolatedLayerPreview) {
|
||||
const segmentingEntity = this.manager.stateApi.$segmentingAdapter.get();
|
||||
if (segmentingEntity && segmentingEntity.entityIdentifier.id !== this.id) {
|
||||
this.setVisibility(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the entity is not selected and offscreen, we can hide it
|
||||
if (!this.$isOnScreen.get() && !this.manager.stateApi.getIsSelected(this.entityIdentifier.id)) {
|
||||
this.setVisibility(false);
|
||||
|
||||
@@ -72,13 +72,9 @@ type CanvasSettingsState = {
|
||||
*/
|
||||
isolatedStagingPreview: boolean;
|
||||
/**
|
||||
* Whether to show only the selected layer while filtering.
|
||||
* Whether to show only the selected layer while filtering, transforming, or doing other operations.
|
||||
*/
|
||||
isolatedFilteringPreview: boolean;
|
||||
/**
|
||||
* Whether to show only the selected layer while transforming.
|
||||
*/
|
||||
isolatedTransformingPreview: boolean;
|
||||
isolatedLayerPreview: boolean;
|
||||
/**
|
||||
* Whether to use pressure sensitivity for the brush and eraser tool when a pen device is used.
|
||||
*/
|
||||
@@ -101,8 +97,7 @@ const initialState: CanvasSettingsState = {
|
||||
bboxOverlay: false,
|
||||
preserveMask: false,
|
||||
isolatedStagingPreview: true,
|
||||
isolatedFilteringPreview: true,
|
||||
isolatedTransformingPreview: true,
|
||||
isolatedLayerPreview: true,
|
||||
pressureSensitivity: true,
|
||||
};
|
||||
|
||||
@@ -155,11 +150,8 @@ export const canvasSettingsSlice = createSlice({
|
||||
settingsIsolatedStagingPreviewToggled: (state) => {
|
||||
state.isolatedStagingPreview = !state.isolatedStagingPreview;
|
||||
},
|
||||
settingsIsolatedFilteringPreviewToggled: (state) => {
|
||||
state.isolatedFilteringPreview = !state.isolatedFilteringPreview;
|
||||
},
|
||||
settingsIsolatedTransformingPreviewToggled: (state) => {
|
||||
state.isolatedTransformingPreview = !state.isolatedTransformingPreview;
|
||||
settingsIsolatedLayerPreviewToggled: (state) => {
|
||||
state.isolatedLayerPreview = !state.isolatedLayerPreview;
|
||||
},
|
||||
settingsPressureSensitivityToggled: (state) => {
|
||||
state.pressureSensitivity = !state.pressureSensitivity;
|
||||
@@ -191,8 +183,7 @@ export const {
|
||||
settingsBboxOverlayToggled,
|
||||
settingsPreserveMaskToggled,
|
||||
settingsIsolatedStagingPreviewToggled,
|
||||
settingsIsolatedFilteringPreviewToggled,
|
||||
settingsIsolatedTransformingPreviewToggled,
|
||||
settingsIsolatedLayerPreviewToggled,
|
||||
settingsPressureSensitivityToggled,
|
||||
} = canvasSettingsSlice.actions;
|
||||
|
||||
@@ -226,10 +217,5 @@ export const selectShowProgressOnCanvas = createCanvasSettingsSelector(
|
||||
(canvasSettings) => canvasSettings.showProgressOnCanvas
|
||||
);
|
||||
export const selectIsolatedStagingPreview = createCanvasSettingsSelector((settings) => settings.isolatedStagingPreview);
|
||||
export const selectIsolatedFilteringPreview = createCanvasSettingsSelector(
|
||||
(settings) => settings.isolatedFilteringPreview
|
||||
);
|
||||
export const selectIsolatedTransformingPreview = createCanvasSettingsSelector(
|
||||
(settings) => settings.isolatedTransformingPreview
|
||||
);
|
||||
export const selectIsolatedLayerPreview = createCanvasSettingsSelector((settings) => settings.isolatedLayerPreview);
|
||||
export const selectPressureSensitivity = createCanvasSettingsSelector((settings) => settings.pressureSensitivity);
|
||||
|
||||
Reference in New Issue
Block a user