Add default auto-switch mode setting for canvas sessions

Co-authored-by: kent <kent@invoke.ai>
This commit is contained in:
Cursor Agent
2025-07-08 17:19:05 +00:00
committed by Kent Keirsey
parent cc93fa270f
commit 98f78abefa
6 changed files with 60 additions and 5 deletions

View File

@@ -0,0 +1,35 @@
import { FormControl, FormLabel, Select } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import {
selectDefaultAutoSwitch,
settingsDefaultAutoSwitchChanged,
} from 'features/controlLayers/store/canvasSettingsSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
export const CanvasSettingsDefaultAutoSwitchSelect = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const defaultAutoSwitch = useAppSelector(selectDefaultAutoSwitch);
const onChange = useCallback(
(e: React.ChangeEvent<HTMLSelectElement>) => {
const value = e.target.value as 'off' | 'switch_on_start' | 'switch_on_finish';
dispatch(settingsDefaultAutoSwitchChanged(value));
},
[dispatch]
);
return (
<FormControl>
<FormLabel m={0}>{t('controlLayers.settings.defaultAutoSwitch')}</FormLabel>
<Select size="sm" value={defaultAutoSwitch} onChange={onChange}>
<option value="off">{t('controlLayers.autoSwitch.off')}</option>
<option value="switch_on_start">{t('controlLayers.autoSwitch.switchOnStart')}</option>
<option value="switch_on_finish">{t('controlLayers.autoSwitch.switchOnFinish')}</option>
</Select>
</FormControl>
);
});
CanvasSettingsDefaultAutoSwitchSelect.displayName = 'CanvasSettingsDefaultAutoSwitchSelect';

View File

@@ -15,6 +15,7 @@ import { CanvasSettingsBboxOverlaySwitch } from 'features/controlLayers/componen
import { CanvasSettingsClearCachesButton } from 'features/controlLayers/components/Settings/CanvasSettingsClearCachesButton';
import { CanvasSettingsClearHistoryButton } from 'features/controlLayers/components/Settings/CanvasSettingsClearHistoryButton';
import { CanvasSettingsClipToBboxCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsClipToBboxCheckbox';
import { CanvasSettingsDefaultAutoSwitchSelect } from 'features/controlLayers/components/Settings/CanvasSettingsDefaultAutoSwitchSelect';
import { CanvasSettingsDynamicGridSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsDynamicGridSwitch';
import { CanvasSettingsSnapToGridCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsGridSize';
import { CanvasSettingsInvertScrollCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsInvertScrollCheckbox';
@@ -57,6 +58,7 @@ export const CanvasSettingsPopover = memo(() => {
{t('hotkeys.canvas.settings.behavior')}
</Text>
</Flex>
<CanvasSettingsDefaultAutoSwitchSelect />
<CanvasSettingsInvertScrollCheckbox />
<CanvasSettingsPressureSensitivityCheckbox />
<CanvasSettingsPreserveMaskCheckbox />

View File

@@ -4,6 +4,7 @@ import { EMPTY_ARRAY } from 'app/store/constants';
import { useAppStore } from 'app/store/storeHooks';
import { buildZodTypeGuard } from 'common/util/zodUtils';
import { getOutputImageName } from 'features/controlLayers/components/SimpleSession/shared';
import { selectDefaultAutoSwitch } from 'features/controlLayers/store/canvasSettingsSlice';
import { canvasQueueItemDiscarded, selectDiscardedItems } from 'features/controlLayers/store/canvasStagingAreaSlice';
import type { ProgressImage } from 'features/nodes/types/common';
import type { Atom, MapStore, StoreValue, WritableAtom } from 'nanostores';
@@ -145,7 +146,8 @@ export const CanvasSessionContextProvider = memo(
/**
* Whether auto-switch is enabled.
*/
const $autoSwitch = useState(() => atom<AutoSwitchMode>('switch_on_start'))[0];
const defaultAutoSwitch = selectDefaultAutoSwitch(store.getState());
const $autoSwitch = useState(() => atom<AutoSwitchMode>(defaultAutoSwitch))[0];
/**
* An internal flag used to work around race conditions with auto-switch switching to queue items before their

View File

@@ -3,6 +3,8 @@ import { createSelector, createSlice } from '@reduxjs/toolkit';
import type { PersistConfig, RootState } from 'app/store/store';
import type { RgbaColor } from 'features/controlLayers/store/types';
type AutoSwitchMode = 'off' | 'switch_on_start' | 'switch_on_finish';
type CanvasSettingsState = {
/**
* Whether to show HUD (Heads-Up Display) on the canvas.
@@ -81,6 +83,10 @@ type CanvasSettingsState = {
* Whether to save all staging images to the gallery instead of keeping them as intermediate images.
*/
saveAllImagesToGallery: boolean;
/**
* The default auto-switch mode for new canvas sessions.
*/
defaultAutoSwitch: AutoSwitchMode;
};
const initialState: CanvasSettingsState = {
@@ -102,6 +108,7 @@ const initialState: CanvasSettingsState = {
pressureSensitivity: true,
ruleOfThirds: false,
saveAllImagesToGallery: false,
defaultAutoSwitch: 'switch_on_start',
};
export const canvasSettingsSlice = createSlice({
@@ -162,6 +169,9 @@ export const canvasSettingsSlice = createSlice({
settingsSaveAllImagesToGalleryToggled: (state) => {
state.saveAllImagesToGallery = !state.saveAllImagesToGallery;
},
settingsDefaultAutoSwitchChanged: (state, action: PayloadAction<AutoSwitchMode>) => {
state.defaultAutoSwitch = action.payload;
},
},
});
@@ -184,6 +194,7 @@ export const {
settingsPressureSensitivityToggled,
settingsRuleOfThirdsToggled,
settingsSaveAllImagesToGalleryToggled,
settingsDefaultAutoSwitchChanged,
} = canvasSettingsSlice.actions;
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
@@ -219,3 +230,4 @@ export const selectIsolatedLayerPreview = createCanvasSettingsSelector((settings
export const selectPressureSensitivity = createCanvasSettingsSelector((settings) => settings.pressureSensitivity);
export const selectRuleOfThirds = createCanvasSettingsSelector((settings) => settings.ruleOfThirds);
export const selectSaveAllImagesToGallery = createCanvasSettingsSelector((settings) => settings.saveAllImagesToGallery);
export const selectDefaultAutoSwitch = createCanvasSettingsSelector((settings) => settings.defaultAutoSwitch);

View File

@@ -55,9 +55,7 @@ export const ModelInstallQueue = memo(() => {
<Box layerStyle="first" p={3} borderRadius="base" w="full" h="full">
<ScrollableContent>
<Flex flexDir="column-reverse" gap="2" w="full">
{data?.map((model) => (
<ModelInstallQueueItem key={model.id} installJob={model} />
))}
{data?.map((model) => <ModelInstallQueueItem key={model.id} installJob={model} />)}
</Flex>
</ScrollableContent>
</Box>