From 49347dbb7cadaa6465e12dda61614f889768e4f8 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 4 May 2024 09:02:27 +1000 Subject: [PATCH 1/6] fix(ui): do not run HRO if using an initial image --- .../nodes/util/graph/addInitialImageToLinearGraph.ts | 9 +++++++-- .../features/nodes/util/graph/buildGenerationTabGraph.ts | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/addInitialImageToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/addInitialImageToLinearGraph.ts index 603708f15b6..eae45acc5be 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/addInitialImageToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/addInitialImageToLinearGraph.ts @@ -6,11 +6,14 @@ import { assert } from 'tsafe'; import { IMAGE_TO_LATENTS, NOISE, RESIZE } from './constants'; +/** + * Returns true if an initial image was added, false if not. + */ export const addInitialImageToLinearGraph = ( state: RootState, graph: NonNullableGraph, denoiseNodeId: string -): void => { +): boolean => { // Remove Existing UNet Connections const { img2imgStrength, vaePrecision, model } = state.generation; const { refinerModel, refinerStart } = state.sdxl; @@ -19,7 +22,7 @@ export const addInitialImageToLinearGraph = ( const initialImage = initialImageLayer?.isEnabled ? initialImageLayer?.image : null; if (!initialImage) { - return; + return false; } const isSDXL = model?.base === 'sdxl'; @@ -122,4 +125,6 @@ export const addInitialImageToLinearGraph = ( strength: img2imgStrength, init_image: initialImage.imageName, }); + + return true; }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildGenerationTabGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildGenerationTabGraph.ts index 6c04b25770d..41f9f4f7487 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildGenerationTabGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildGenerationTabGraph.ts @@ -232,7 +232,7 @@ export const buildGenerationTabGraph = async (state: RootState): Promise Date: Sat, 4 May 2024 09:07:24 +1000 Subject: [PATCH 2/6] fix(ui): invalidate mask cache when moving layer --- .../web/src/features/controlLayers/store/controlLayersSlice.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/invokeai/frontend/web/src/features/controlLayers/store/controlLayersSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/controlLayersSlice.ts index 50023b1399b..8adbae6d804 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/controlLayersSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/controlLayersSlice.ts @@ -164,6 +164,9 @@ export const controlLayersSlice = createSlice({ layer.x = x; layer.y = y; } + if (isRegionalGuidanceLayer(layer)) { + layer.uploadedMaskImage = null; + } }, layerBboxChanged: (state, action: PayloadAction<{ layerId: string; bbox: IRect | null }>) => { const { layerId, bbox } = action.payload; From 31c6762071425e01d28ac3b201293fcdc49cf24b Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 4 May 2024 09:08:45 +1000 Subject: [PATCH 3/6] tidy(ui): clean up layer reset logic --- .../controlLayers/components/ToolChooser.tsx | 10 +++++-- .../controlLayers/store/controlLayersSlice.ts | 28 ++++++------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/invokeai/frontend/web/src/features/controlLayers/components/ToolChooser.tsx b/invokeai/frontend/web/src/features/controlLayers/components/ToolChooser.tsx index 53535b42481..f97a0f35e52 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/ToolChooser.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/ToolChooser.tsx @@ -4,9 +4,9 @@ import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { $tool, + layerReset, selectControlLayersSlice, selectedLayerDeleted, - selectedLayerReset, } from 'features/controlLayers/store/controlLayersSlice'; import { useCallback } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; @@ -22,6 +22,7 @@ export const ToolChooser: React.FC = () => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const isDisabled = useAppSelector(selectIsDisabled); + const selectedLayerId = useAppSelector((s) => s.controlLayers.present.selectedLayerId); const tool = useStore($tool); const setToolToBrush = useCallback(() => { @@ -42,8 +43,11 @@ export const ToolChooser: React.FC = () => { useHotkeys('v', setToolToMove, { enabled: !isDisabled }, [isDisabled]); const resetSelectedLayer = useCallback(() => { - dispatch(selectedLayerReset()); - }, [dispatch]); + if (selectedLayerId === null) { + return; + } + dispatch(layerReset(selectedLayerId)); + }, [dispatch, selectedLayerId]); useHotkeys('shift+c', resetSelectedLayer); const deleteSelectedLayer = useCallback(() => { diff --git a/invokeai/frontend/web/src/features/controlLayers/store/controlLayersSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/controlLayersSlice.ts index 8adbae6d804..f6a6f0b38db 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/controlLayersSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/controlLayersSlice.ts @@ -79,17 +79,6 @@ export const isRenderableLayer = ( layer?.type === 'regional_guidance_layer' || layer?.type === 'control_adapter_layer' || layer?.type === 'initial_image_layer'; -const resetLayer = (layer: Layer) => { - if (layer.type === 'regional_guidance_layer') { - layer.maskObjects = []; - layer.bbox = null; - layer.isEnabled = true; - layer.needsPixelBbox = false; - layer.bboxNeedsUpdate = false; - layer.uploadedMaskImage = null; - return; - } -}; export const selectCALayerOrThrow = (state: ControlLayersState, layerId: string): ControlAdapterLayer => { const layer = state.layers.find((l) => l.id === layerId); @@ -184,8 +173,14 @@ export const controlLayersSlice = createSlice({ }, layerReset: (state, action: PayloadAction) => { const layer = state.layers.find((l) => l.id === action.payload); - if (layer) { - resetLayer(layer); + // TODO(psyche): Should other layer types also have reset functionality? + if (isRegionalGuidanceLayer(layer)) { + layer.maskObjects = []; + layer.bbox = null; + layer.isEnabled = true; + layer.needsPixelBbox = false; + layer.bboxNeedsUpdate = false; + layer.uploadedMaskImage = null; } }, layerDeleted: (state, action: PayloadAction) => { @@ -218,12 +213,6 @@ export const controlLayersSlice = createSlice({ moveToFront(renderableLayers, cb); state.layers = [...ipAdapterLayers, ...renderableLayers]; }, - selectedLayerReset: (state) => { - const layer = state.layers.find((l) => l.id === state.selectedLayerId); - if (layer) { - resetLayer(layer); - } - }, selectedLayerDeleted: (state) => { state.layers = state.layers.filter((l) => l.id !== state.selectedLayerId); state.selectedLayerId = state.layers[0]?.id ?? null; @@ -806,7 +795,6 @@ export const { layerMovedToFront, layerMovedBackward, layerMovedToBack, - selectedLayerReset, selectedLayerDeleted, allLayersDeleted, // CA Layers From 8a366a65333934530e5051a26fcb938a73ae3f31 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 4 May 2024 09:52:41 +1000 Subject: [PATCH 4/6] feat(ui): close viewer when user switches tabs --- .../frontend/web/src/features/gallery/store/gallerySlice.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts index 373d9464692..60ed692ba2d 100644 --- a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts +++ b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts @@ -1,6 +1,7 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice, isAnyOf } from '@reduxjs/toolkit'; import type { PersistConfig, RootState } from 'app/store/store'; +import { setActiveTab } from 'features/ui/store/uiSlice'; import { uniqBy } from 'lodash-es'; import { boardsApi } from 'services/api/endpoints/boards'; import { imagesApi } from 'services/api/endpoints/images'; @@ -83,6 +84,9 @@ export const gallerySlice = createSlice({ }, }, extraReducers: (builder) => { + builder.addCase(setActiveTab, (state) => { + state.isImageViewerOpen = false; + }); builder.addMatcher(isAnyBoardDeleted, (state, action) => { const deletedBoardId = action.meta.arg.originalArgs; if (deletedBoardId === state.selectedBoardId) { From aff446f1113e337010ac20288aa4ef77cc01b615 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 4 May 2024 10:05:42 +1000 Subject: [PATCH 5/6] fix(ui): do not auto-hide next/prev image buttons --- .../components/ImageViewer/CurrentImagePreview.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx index 37fada0b789..35abf07965f 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx @@ -52,17 +52,20 @@ const CurrentImagePreview = () => { // Show and hide the next/prev buttons on mouse move const [shouldShowNextPrevButtons, setShouldShowNextPrevButtons] = useState(false); const timeoutId = useRef(0); - const onMouseMove = useCallback(() => { + const onMouseOver = useCallback(() => { setShouldShowNextPrevButtons(true); window.clearTimeout(timeoutId.current); + }, []); + const onMouseOut = useCallback(() => { timeoutId.current = window.setTimeout(() => { setShouldShowNextPrevButtons(false); - }, 1000); + }, 500); }, []); return ( Date: Sat, 4 May 2024 10:16:00 +1000 Subject: [PATCH 6/6] fix(ui): save upscaled images to gallery on canvas tab --- .../src/features/nodes/util/graph/buildAdHocUpscaleGraph.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocUpscaleGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocUpscaleGraph.ts index 52c09b1db06..6c90dafd25f 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocUpscaleGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocUpscaleGraph.ts @@ -1,5 +1,5 @@ import type { RootState } from 'app/store/store'; -import { getBoardField, getIsIntermediate } from 'features/nodes/util/graph/graphBuilderUtils'; +import { getBoardField } from 'features/nodes/util/graph/graphBuilderUtils'; import type { ESRGANInvocation, Graph, NonNullableGraph } from 'services/api/types'; import { ESRGAN } from './constants'; @@ -18,7 +18,7 @@ export const buildAdHocUpscaleGraph = ({ image_name, state }: Arg): Graph => { type: 'esrgan', image: { image_name }, model_name: esrganModelName, - is_intermediate: getIsIntermediate(state), + is_intermediate: false, board: getBoardField(state), };