feat(ui): rough out undo/redo on canvas UNDO ME?

This commit is contained in:
psychedelicious 2024-08-26 22:45:11 +10:00
parent 217b2759c3
commit 35b483b83a
44 changed files with 84 additions and 81 deletions

View File

@ -58,7 +58,7 @@ export const addStagingListeners = (startAppListening: AppStartListening) => {
const stagingAreaImage = state.canvasSession.stagedImages[index];
assert(stagingAreaImage, 'No staged image found to accept');
const { x, y } = state.canvasV2.bbox.rect;
const { x, y } = state.canvasV2.present.bbox.rect;
const { imageDTO, offsetX, offsetY } = stagingAreaImage;
const imageObject = imageDTOToImageObject(imageDTO);

View File

@ -16,7 +16,7 @@ export const addDeleteBoardAndImagesFulfilledListener = (startAppListening: AppS
const { nodes, canvasV2 } = getState();
deleted_images.forEach((image_name) => {
const imageUsage = getImageUsage(nodes.present, canvasV2, image_name);
const imageUsage = getImageUsage(nodes.present, canvasV2.present, image_name);
if (imageUsage.isNodesImage && !wasNodeEditorReset) {
dispatch(nodeEditorReset());

View File

@ -40,7 +40,7 @@ const deleteNodesImages = (state: RootState, dispatch: AppDispatch, imageDTO: Im
};
// const deleteControlAdapterImages = (state: RootState, dispatch: AppDispatch, imageDTO: ImageDTO) => {
// state.canvasV2.controlAdapters.entities.forEach(({ id, imageObject, processedImageObject }) => {
// state.canvasV2.present.controlAdapters.entities.forEach(({ id, imageObject, processedImageObject }) => {
// if (
// imageObject?.image.image_name === imageDTO.image_name ||
// processedImageObject?.image.image_name === imageDTO.image_name
@ -52,7 +52,7 @@ const deleteNodesImages = (state: RootState, dispatch: AppDispatch, imageDTO: Im
// };
const deleteIPAdapterImages = (state: RootState, dispatch: AppDispatch, imageDTO: ImageDTO) => {
state.canvasV2.ipAdapters.entities.forEach((entity) => {
state.canvasV2.present.ipAdapters.entities.forEach((entity) => {
if (entity.ipAdapter.image?.image_name === imageDTO.image_name) {
dispatch(ipaImageChanged({ entityIdentifier: getEntityIdentifier(entity), imageDTO: null }));
}
@ -60,7 +60,7 @@ const deleteIPAdapterImages = (state: RootState, dispatch: AppDispatch, imageDTO
};
const deleteLayerImages = (state: RootState, dispatch: AppDispatch, imageDTO: ImageDTO) => {
state.canvasV2.rasterLayers.entities.forEach(({ id, objects }) => {
state.canvasV2.present.rasterLayers.entities.forEach(({ id, objects }) => {
let shouldDelete = false;
for (const obj of objects) {
if (obj.type === 'image' && obj.image.image_name === imageDTO.image_name) {

View File

@ -85,7 +85,7 @@ export const addImageDroppedListener = (startAppListening: AppStartListening) =>
activeData.payload.imageDTO
) {
const imageObject = imageDTOToImageObject(activeData.payload.imageDTO);
const { x, y } = getState().canvasV2.bbox.rect;
const { x, y } = getState().canvasV2.present.bbox.rect;
const overrides: Partial<CanvasRasterLayerState> = {
objects: [imageObject],
position: { x, y },
@ -103,7 +103,7 @@ export const addImageDroppedListener = (startAppListening: AppStartListening) =>
activeData.payload.imageDTO
) {
const imageObject = imageDTOToImageObject(activeData.payload.imageDTO);
const { x, y } = getState().canvasV2.bbox.rect;
const { x, y } = getState().canvasV2.present.bbox.rect;
const overrides: Partial<CanvasControlLayerState> = {
objects: [imageObject],
position: { x, y },

View File

@ -46,7 +46,7 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) =
}
// handle incompatible controlnets
// state.canvasV2.controlAdapters.entities.forEach((ca) => {
// state.canvasV2.present.controlAdapters.entities.forEach((ca) => {
// if (ca.model?.base !== newBaseModel) {
// modelsCleared += 1;
// if (ca.isEnabled) {

View File

@ -83,11 +83,11 @@ const handleMainModels: ModelHandler = (models, state, dispatch, log) => {
dispatch(modelChanged({ model: defaultModelInList, previousModel: currentModel }));
const optimalDimension = getOptimalDimension(defaultModelInList);
if (getIsSizeOptimal(state.canvasV2.bbox.rect.width, state.canvasV2.bbox.rect.height, optimalDimension)) {
if (getIsSizeOptimal(state.canvasV2.present.bbox.rect.width, state.canvasV2.present.bbox.rect.height, optimalDimension)) {
return;
}
const { width, height } = calculateNewSize(
state.canvasV2.bbox.aspectRatio.value,
state.canvasV2.present.bbox.aspectRatio.value,
optimalDimension * optimalDimension
);
@ -172,7 +172,7 @@ const handleLoRAModels: ModelHandler = (models, state, dispatch, _log) => {
const handleControlAdapterModels: ModelHandler = (models, state, dispatch, _log) => {
const caModels = models.filter(isControlNetOrT2IAdapterModelConfig);
state.canvasV2.controlLayers.entities.forEach((entity) => {
state.canvasV2.present.controlLayers.entities.forEach((entity) => {
const isModelAvailable = caModels.some((m) => m.key === entity.controlAdapter.model?.key);
if (isModelAvailable) {
return;
@ -183,7 +183,7 @@ const handleControlAdapterModels: ModelHandler = (models, state, dispatch, _log)
const handleIPAdapterModels: ModelHandler = (models, state, dispatch, _log) => {
const ipaModels = models.filter(isIPAdapterModelConfig);
state.canvasV2.ipAdapters.entities.forEach((entity) => {
state.canvasV2.present.ipAdapters.entities.forEach((entity) => {
const isModelAvailable = ipaModels.some((m) => m.key === entity.ipAdapter.model?.key);
if (isModelAvailable) {
return;
@ -191,7 +191,7 @@ const handleIPAdapterModels: ModelHandler = (models, state, dispatch, _log) => {
dispatch(ipaModelChanged({ entityIdentifier: getEntityIdentifier(entity), modelConfig: null }));
});
state.canvasV2.regions.entities.forEach((entity) => {
state.canvasV2.present.regions.entities.forEach((entity) => {
entity.ipAdapters.forEach(({ id: ipAdapterId, model }) => {
const isModelAvailable = ipaModels.some((m) => m.key === model?.key);
if (isModelAvailable) {

View File

@ -58,7 +58,7 @@ const allReducers = {
[queueSlice.name]: queueSlice.reducer,
[workflowSlice.name]: workflowSlice.reducer,
[hrfSlice.name]: hrfSlice.reducer,
[canvasV2Slice.name]: canvasV2Slice.reducer,
[canvasV2Slice.name]: undoable(canvasV2Slice.reducer),
[workflowSettingsSlice.name]: workflowSettingsSlice.reducer,
[upscaleSlice.name]: upscaleSlice.reducer,
[stylePresetSlice.name]: stylePresetSlice.reducer,

View File

@ -9,7 +9,7 @@ export const ControlLayerBadges = memo(() => {
const entityIdentifier = useEntityIdentifierContext('control_layer');
const { t } = useTranslation();
const withTransparencyEffect = useAppSelector(
(s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).withTransparencyEffect
(s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).withTransparencyEffect
);
return (

View File

@ -11,7 +11,7 @@ const selectEntityIds = createMemoizedSelector(selectCanvasV2Slice, (canvasV2) =
});
export const ControlLayerEntityList = memo(() => {
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.selectedEntityIdentifier?.type === 'control_layer'));
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.present.selectedEntityIdentifier?.type === 'control_layer'));
const layerIds = useAppSelector(selectEntityIds);
if (layerIds.length === 0) {

View File

@ -13,7 +13,7 @@ export const HeadsUpDisplay = memo(() => {
const isMouseDown = useStore(canvasManager.stateApi.$isMouseDown);
const lastMouseDownPos = useStore(canvasManager.stateApi.$lastMouseDownPos);
const lastAddedPoint = useStore(canvasManager.stateApi.$lastAddedPoint);
const bbox = useAppSelector((s) => s.canvasV2.bbox);
const bbox = useAppSelector((s) => s.canvasV2.present.bbox);
return (
<Flex flexDir="column" bg="blackAlpha.400" borderBottomEndRadius="base" p={2} minW={64} gap={2}>

View File

@ -12,7 +12,7 @@ const selectEntityIds = createMemoizedSelector(selectCanvasV2Slice, (canvasV2) =
});
export const IPAdapterList = memo(() => {
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.selectedEntityIdentifier?.type === 'ip_adapter'));
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.present.selectedEntityIdentifier?.type === 'ip_adapter'));
const ipaIds = useAppSelector(selectEntityIds);
if (ipaIds.length === 0) {

View File

@ -25,7 +25,7 @@ import { IPAdapterModel } from './IPAdapterModel';
export const IPAdapterSettings = memo(() => {
const dispatch = useAppDispatch();
const entityIdentifier = useEntityIdentifierContext('ip_adapter');
const ipAdapter = useAppSelector((s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).ipAdapter);
const ipAdapter = useAppSelector((s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).ipAdapter);
const onChangeBeginEndStepPct = useCallback(
(beginEndStepPct: [number, number]) => {

View File

@ -11,7 +11,7 @@ const selectEntityIds = createMemoizedSelector(selectCanvasV2Slice, (canvasV2) =
});
export const InpaintMaskList = memo(() => {
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.selectedEntityIdentifier?.type === 'inpaint_mask'));
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.present.selectedEntityIdentifier?.type === 'inpaint_mask'));
const entityIds = useAppSelector(selectEntityIds);
if (entityIds.length === 0) {

View File

@ -14,7 +14,7 @@ export const InpaintMaskMaskFillColorPicker = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const entityIdentifier = useEntityIdentifierContext('inpaint_mask');
const fill = useAppSelector((s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).fill);
const fill = useAppSelector((s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).fill);
const onChangeFillColor = useCallback(
(color: RgbColor) => {

View File

@ -11,7 +11,7 @@ const selectEntityIds = createMemoizedSelector(selectCanvasV2Slice, (canvasV2) =
});
export const RasterLayerEntityList = memo(() => {
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.selectedEntityIdentifier?.type === 'raster_layer'));
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.present.selectedEntityIdentifier?.type === 'raster_layer'));
const layerIds = useAppSelector(selectEntityIds);
if (layerIds.length === 0) {

View File

@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
export const RegionalGuidanceBadges = memo(() => {
const entityIdentifier = useEntityIdentifierContext('regional_guidance');
const { t } = useTranslation();
const autoNegative = useAppSelector((s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).autoNegative);
const autoNegative = useAppSelector((s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).autoNegative);
return (
<>

View File

@ -11,7 +11,7 @@ const selectEntityIds = createMemoizedSelector(selectCanvasV2Slice, (canvasV2) =
});
export const RegionalGuidanceEntityList = memo(() => {
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.selectedEntityIdentifier?.type === 'regional_guidance'));
const isSelected = useAppSelector((s) => Boolean(s.canvasV2.present.selectedEntityIdentifier?.type === 'regional_guidance'));
const rgIds = useAppSelector(selectEntityIds);
if (rgIds.length === 0) {

View File

@ -35,7 +35,7 @@ export const RegionalGuidanceIPAdapterSettings = memo(({ ipAdapterId, ipAdapterN
dispatch(rgIPAdapterDeleted({ entityIdentifier, ipAdapterId }));
}, [dispatch, entityIdentifier, ipAdapterId]);
const ipAdapter = useAppSelector((s) => {
const ipa = selectRegionalGuidanceIPAdapter(s.canvasV2, entityIdentifier, ipAdapterId);
const ipa = selectRegionalGuidanceIPAdapter(s.canvasV2.present, entityIdentifier, ipAdapterId);
assert(ipa, `Regional GuidanceIP Adapter with id ${ipAdapterId} not found`);
return ipa;
});

View File

@ -14,7 +14,7 @@ export const RegionalGuidanceMaskFillColorPicker = memo(() => {
const entityIdentifier = useEntityIdentifierContext('regional_guidance');
const { t } = useTranslation();
const dispatch = useAppDispatch();
const fill = useAppSelector((s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).fill);
const fill = useAppSelector((s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).fill);
const onChangeFillColor = useCallback(
(color: RgbColor) => {
dispatch(rgFillColorChanged({ entityIdentifier, color }));

View File

@ -11,7 +11,7 @@ export const RegionalGuidanceMenuItemsAutoNegative = memo(() => {
const entityIdentifier = useEntityIdentifierContext('regional_guidance');
const { t } = useTranslation();
const dispatch = useAppDispatch();
const autoNegative = useAppSelector((s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).autoNegative);
const autoNegative = useAppSelector((s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).autoNegative);
const onClick = useCallback(() => {
dispatch(rgAutoNegativeToggled({ entityIdentifier }));
}, [dispatch, entityIdentifier]);

View File

@ -13,7 +13,7 @@ import { useTranslation } from 'react-i18next';
export const RegionalGuidanceNegativePrompt = memo(() => {
const entityIdentifier = useEntityIdentifierContext('regional_guidance');
const prompt = useAppSelector((s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).negativePrompt ?? '');
const prompt = useAppSelector((s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).negativePrompt ?? '');
const dispatch = useAppDispatch();
const textareaRef = useRef<HTMLTextAreaElement>(null);
const { t } = useTranslation();

View File

@ -13,7 +13,7 @@ import { useTranslation } from 'react-i18next';
export const RegionalGuidancePositivePrompt = memo(() => {
const entityIdentifier = useEntityIdentifierContext('regional_guidance');
const prompt = useAppSelector((s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).positivePrompt ?? '');
const prompt = useAppSelector((s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).positivePrompt ?? '');
const dispatch = useAppDispatch();
const textareaRef = useRef<HTMLTextAreaElement>(null);
const { t } = useTranslation();

View File

@ -13,12 +13,12 @@ import { RegionalGuidancePositivePrompt } from './RegionalGuidancePositivePrompt
export const RegionalGuidanceSettings = memo(() => {
const entityIdentifier = useEntityIdentifierContext('regional_guidance');
const hasPositivePrompt = useAppSelector(
(s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).positivePrompt !== null
(s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).positivePrompt !== null
);
const hasNegativePrompt = useAppSelector(
(s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).negativePrompt !== null
(s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).negativePrompt !== null
);
const hasIPAdapters = useAppSelector((s) => selectEntityOrThrow(s.canvasV2, entityIdentifier).ipAdapters.length > 0);
const hasIPAdapters = useAppSelector((s) => selectEntityOrThrow(s.canvasV2.present, entityIdentifier).ipAdapters.length > 0);
return (
<CanvasEntitySettingsWrapper>

View File

@ -17,10 +17,10 @@ export const ToolBrushButton = memo(() => {
const selectBrush = useSelectTool('brush');
const isSelected = useToolIsSelected('brush');
const isDrawingToolAllowed = useAppSelector((s) => {
if (!s.canvasV2.selectedEntityIdentifier?.type) {
if (!s.canvasV2.present.selectedEntityIdentifier?.type) {
return false;
}
return isDrawableEntityType(s.canvasV2.selectedEntityIdentifier.type);
return isDrawableEntityType(s.canvasV2.present.selectedEntityIdentifier.type);
});
const isDisabled = useMemo(() => {

View File

@ -17,10 +17,10 @@ export const ToolEraserButton = memo(() => {
const selectEraser = useSelectTool('eraser');
const isSelected = useToolIsSelected('eraser');
const isDrawingToolAllowed = useAppSelector((s) => {
if (!s.canvasV2.selectedEntityIdentifier?.type) {
if (!s.canvasV2.present.selectedEntityIdentifier?.type) {
return false;
}
return isDrawableEntityType(s.canvasV2.selectedEntityIdentifier.type);
return isDrawableEntityType(s.canvasV2.present.selectedEntityIdentifier.type);
});
const isDisabled = useMemo(() => {
return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;

View File

@ -17,10 +17,10 @@ export const ToolMoveButton = memo(() => {
const isSelected = useToolIsSelected('move');
const isStaging = useAppSelector((s) => s.canvasSession.isStaging);
const isDrawingToolAllowed = useAppSelector((s) => {
if (!s.canvasV2.selectedEntityIdentifier?.type) {
if (!s.canvasV2.present.selectedEntityIdentifier?.type) {
return false;
}
return isDrawableEntityType(s.canvasV2.selectedEntityIdentifier.type);
return isDrawableEntityType(s.canvasV2.present.selectedEntityIdentifier.type);
});
const isDisabled = useMemo(() => {
return isTransforming || isFiltering || isStaging || !isDrawingToolAllowed;

View File

@ -17,10 +17,10 @@ export const ToolRectButton = memo(() => {
const isTransforming = useIsTransforming();
const isStaging = useAppSelector((s) => s.canvasSession.isStaging);
const isDrawingToolAllowed = useAppSelector((s) => {
if (!s.canvasV2.selectedEntityIdentifier?.type) {
if (!s.canvasV2.present.selectedEntityIdentifier?.type) {
return false;
}
return isDrawableEntityType(s.canvasV2.selectedEntityIdentifier.type);
return isDrawableEntityType(s.canvasV2.present.selectedEntityIdentifier.type);
});
const isDisabled = useMemo(() => {

View File

@ -5,22 +5,25 @@ import { memo, useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { PiArrowClockwiseBold, PiArrowCounterClockwiseBold } from 'react-icons/pi';
import { useDispatch } from 'react-redux';
import { ActionCreators } from 'redux-undo';
export const UndoRedoButtonGroup = memo(() => {
const { t } = useTranslation();
const dispatch = useDispatch();
const mayUndo = useAppSelector(() => false);
const mayUndo = useAppSelector(() => true);
const handleUndo = useCallback(() => {
// TODO(psyche): Implement undo
// dispatch(undo());
}, []);
dispatch(ActionCreators.undo());
}, [dispatch]);
useHotkeys(['meta+z', 'ctrl+z'], handleUndo, { enabled: mayUndo, preventDefault: true }, [mayUndo, handleUndo]);
const mayRedo = useAppSelector(() => false);
const mayRedo = useAppSelector(() => true);
const handleRedo = useCallback(() => {
// TODO(psyche): Implement redo
// dispatch(redo());
}, []);
dispatch(ActionCreators.redo());
}, [dispatch]);
useHotkeys(['meta+shift+z', 'ctrl+shift+z'], handleRedo, { enabled: mayRedo, preventDefault: true }, [
mayRedo,
handleRedo,

View File

@ -59,13 +59,13 @@ const snapCandidates = marks.slice(1, marks.length - 1);
export const CanvasEntityOpacity = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const selectedEntityIdentifier = useAppSelector((s) => s.canvasV2.selectedEntityIdentifier);
const selectedEntityIdentifier = useAppSelector((s) => s.canvasV2.present.selectedEntityIdentifier);
const opacity = useAppSelector((s) => {
const selectedEntityIdentifier = s.canvasV2.selectedEntityIdentifier;
const selectedEntityIdentifier = s.canvasV2.present.selectedEntityIdentifier;
if (!selectedEntityIdentifier) {
return null;
}
const selectedEntity = selectEntity(s.canvasV2, selectedEntityIdentifier);
const selectedEntity = selectEntity(s.canvasV2.present, selectedEntityIdentifier);
if (!selectedEntity) {
return null;
}

View File

@ -3,7 +3,7 @@ import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'
import { useMemo } from 'react';
export const useEntityIsSelected = (entityIdentifier: CanvasEntityIdentifier) => {
const selectedEntityIdentifier = useAppSelector((s) => s.canvasV2.selectedEntityIdentifier);
const selectedEntityIdentifier = useAppSelector((s) => s.canvasV2.present.selectedEntityIdentifier);
const isSelected = useMemo(() => {
return selectedEntityIdentifier?.id === entityIdentifier.id;
}, [selectedEntityIdentifier, entityIdentifier.id]);

View File

@ -100,7 +100,7 @@ export class CanvasStateApiModule extends CanvasModuleBase {
// Reminder - use arrow functions to avoid binding issues
getCanvasState = () => {
return this.store.getState().canvasV2;
return this.store.getState().canvasV2.present;
};
resetEntity = (arg: EntityIdentifierPayload) => {
this.store.dispatch(entityReset(arg));

View File

@ -16,7 +16,7 @@ import { assert } from 'tsafe';
/**
* Selects the canvasV2 slice from the root state
*/
export const selectCanvasV2Slice = (state: RootState) => state.canvasV2;
export const selectCanvasV2Slice = (state: RootState) => state.canvasV2.present;
/**
* Selects the total canvas entity count:

View File

@ -22,7 +22,7 @@ export const addInpaint = async (
denoise.denoising_start = denoising_start;
const { params, canvasV2, canvasSession } = state;
const { bbox } = canvasV2;
const { bbox } = canvasV2.present;
const { mode } = canvasSession;
const initialImage = await manager.compositor.getCompositeRasterLayerImageDTO(bbox.rect);

View File

@ -23,7 +23,7 @@ export const addOutpaint = async (
denoise.denoising_start = denoising_start;
const { params, canvasV2, canvasSession } = state;
const { bbox } = canvasV2;
const { bbox } = canvasV2.present;
const { mode } = canvasSession;
const initialImage = await manager.compositor.getCompositeRasterLayerImageDTO(bbox.rect);

View File

@ -32,7 +32,7 @@ export const buildSD1Graph = async (
log.debug({ generationMode }, 'Building SD1/SD2 graph');
const { canvasV2, params, canvasSettings, canvasSession } = state;
const { bbox } = canvasV2;
const { bbox } = canvasV2.present;
const {
model,
@ -208,9 +208,9 @@ export const buildSD1Graph = async (
});
const controlNetResult = await addControlNets(
manager,
state.canvasV2.controlLayers.entities,
state.canvasV2.present.controlLayers.entities,
g,
state.canvasV2.bbox.rect,
state.canvasV2.present.bbox.rect,
controlNetCollector,
modelConfig.base
);
@ -226,9 +226,9 @@ export const buildSD1Graph = async (
});
const t2iAdapterResult = await addT2IAdapters(
manager,
state.canvasV2.controlLayers.entities,
state.canvasV2.present.controlLayers.entities,
g,
state.canvasV2.bbox.rect,
state.canvasV2.present.bbox.rect,
t2iAdapterCollector,
modelConfig.base
);
@ -242,13 +242,13 @@ export const buildSD1Graph = async (
type: 'collect',
id: getPrefixedId('ip_adapter_collector'),
});
const ipAdapterResult = addIPAdapters(state.canvasV2.ipAdapters.entities, g, ipAdapterCollector, modelConfig.base);
const ipAdapterResult = addIPAdapters(state.canvasV2.present.ipAdapters.entities, g, ipAdapterCollector, modelConfig.base);
const regionsResult = await addRegions(
manager,
state.canvasV2.regions.entities,
state.canvasV2.present.regions.entities,
g,
state.canvasV2.bbox.rect,
state.canvasV2.present.bbox.rect,
modelConfig.base,
denoise,
posCond,

View File

@ -32,7 +32,7 @@ export const buildSDXLGraph = async (
log.debug({ generationMode }, 'Building SDXL graph');
const { params, canvasV2, canvasSettings, canvasSession } = state;
const { bbox } = canvasV2;
const { bbox } = canvasV2.present;
const {
model,
@ -211,9 +211,9 @@ export const buildSDXLGraph = async (
});
const controlNetResult = await addControlNets(
manager,
state.canvasV2.controlLayers.entities,
state.canvasV2.present.controlLayers.entities,
g,
state.canvasV2.bbox.rect,
state.canvasV2.present.bbox.rect,
controlNetCollector,
modelConfig.base
);
@ -229,9 +229,9 @@ export const buildSDXLGraph = async (
});
const t2iAdapterResult = await addT2IAdapters(
manager,
state.canvasV2.controlLayers.entities,
state.canvasV2.present.controlLayers.entities,
g,
state.canvasV2.bbox.rect,
state.canvasV2.present.bbox.rect,
t2iAdapterCollector,
modelConfig.base
);
@ -245,13 +245,13 @@ export const buildSDXLGraph = async (
type: 'collect',
id: getPrefixedId('ip_adapter_collector'),
});
const ipAdapterResult = addIPAdapters(state.canvasV2.ipAdapters.entities, g, ipAdapterCollector, modelConfig.base);
const ipAdapterResult = addIPAdapters(state.canvasV2.present.ipAdapters.entities, g, ipAdapterCollector, modelConfig.base);
const regionsResult = await addRegions(
manager,
state.canvasV2.regions.entities,
state.canvasV2.present.regions.entities,
g,
state.canvasV2.bbox.rect,
state.canvasV2.present.bbox.rect,
modelConfig.base,
denoise,
posCond,

View File

@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next';
const ParamScaleBeforeProcessing = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const scaleMethod = useAppSelector((s) => s.canvasV2.bbox.scaleMethod);
const scaleMethod = useAppSelector((s) => s.canvasV2.present.bbox.scaleMethod);
const OPTIONS: ComboboxOption[] = useMemo(
() => [

View File

@ -9,8 +9,8 @@ const ParamScaledHeight = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const optimalDimension = useAppSelector(selectOptimalDimension);
const isManual = useAppSelector((s) => s.canvasV2.bbox.scaleMethod === 'manual');
const height = useAppSelector((s) => s.canvasV2.bbox.scaledSize.height);
const isManual = useAppSelector((s) => s.canvasV2.present.bbox.scaleMethod === 'manual');
const height = useAppSelector((s) => s.canvasV2.present.bbox.scaledSize.height);
const sliderMin = useAppSelector((s) => s.config.sd.scaledBoundingBoxHeight.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.scaledBoundingBoxHeight.sliderMax);
const numberInputMin = useAppSelector((s) => s.config.sd.scaledBoundingBoxHeight.numberInputMin);

View File

@ -9,8 +9,8 @@ const ParamScaledWidth = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const optimalDimension = useAppSelector(selectOptimalDimension);
const isManual = useAppSelector((s) => s.canvasV2.bbox.scaleMethod === 'manual');
const width = useAppSelector((s) => s.canvasV2.bbox.scaledSize.width);
const isManual = useAppSelector((s) => s.canvasV2.present.bbox.scaleMethod === 'manual');
const width = useAppSelector((s) => s.canvasV2.present.bbox.scaledSize.width);
const sliderMin = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.sliderMax);
const numberInputMin = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.numberInputMin);

View File

@ -10,7 +10,7 @@ export const ParamHeight = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const optimalDimension = useAppSelector(selectOptimalDimension);
const height = useAppSelector((s) => s.canvasV2.bbox.rect.height);
const height = useAppSelector((s) => s.canvasV2.present.bbox.rect.height);
const sliderMin = useAppSelector((s) => s.config.sd.height.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.height.sliderMax);
const numberInputMin = useAppSelector((s) => s.config.sd.height.numberInputMin);

View File

@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
export const ParamWidth = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const width = useAppSelector((s) => s.canvasV2.bbox.rect.width);
const width = useAppSelector((s) => s.canvasV2.present.bbox.rect.width);
const optimalDimension = useAppSelector(selectOptimalDimension);
const sliderMin = useAppSelector((s) => s.config.sd.width.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.width.sliderMax);

View File

@ -12,7 +12,7 @@ import { useTranslation } from 'react-i18next';
export const AspectRatioSelect = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const id = useAppSelector((s) => s.canvasV2.bbox.aspectRatio.id);
const id = useAppSelector((s) => s.canvasV2.present.bbox.aspectRatio.id);
const onChange = useCallback(
(v: SingleValue<ComboboxOption>) => {

View File

@ -8,7 +8,7 @@ import { PiLockSimpleFill, PiLockSimpleOpenBold } from 'react-icons/pi';
export const LockAspectRatioButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isLocked = useAppSelector((s) => s.canvasV2.bbox.aspectRatio.isLocked);
const isLocked = useAppSelector((s) => s.canvasV2.present.bbox.aspectRatio.isLocked);
const onClick = useCallback(() => {
dispatch(bboxAspectRatioLockToggled());
}, [dispatch]);

View File

@ -10,8 +10,8 @@ import { RiSparklingFill } from 'react-icons/ri';
export const SetOptimalSizeButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const width = useAppSelector((s) => s.canvasV2.bbox.rect.width);
const height = useAppSelector((s) => s.canvasV2.bbox.rect.height);
const width = useAppSelector((s) => s.canvasV2.present.bbox.rect.width);
const height = useAppSelector((s) => s.canvasV2.present.bbox.rect.height);
const optimalDimension = useAppSelector(selectOptimalDimension);
const isSizeTooSmall = useMemo(
() => getIsSizeTooSmall(width, height, optimalDimension),