mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): rough out undo/redo on canvas UNDO ME?
This commit is contained in:
parent
217b2759c3
commit
35b483b83a
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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) {
|
||||
|
@ -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 },
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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 (
|
||||
|
@ -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) {
|
||||
|
@ -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}>
|
||||
|
@ -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) {
|
||||
|
@ -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]) => {
|
||||
|
@ -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) {
|
||||
|
@ -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) => {
|
||||
|
@ -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) {
|
||||
|
@ -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 (
|
||||
<>
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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 }));
|
||||
|
@ -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]);
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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>
|
||||
|
@ -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(() => {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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(() => {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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]);
|
||||
|
@ -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));
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
() => [
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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>) => {
|
||||
|
@ -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]);
|
||||
|
@ -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),
|
||||
|
Loading…
x
Reference in New Issue
Block a user