From 4fd33abea3b238e4b721e336c44bfd41714b73bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ufuk=20Sarp=20Sel=C3=A7ok?= Date: Mon, 27 Apr 2026 01:10:32 +0300 Subject: [PATCH 1/2] fix(ui): unify ref panel ruler size recall with Use Size action --- .../components/RefImage/RefImageImage.tsx | 28 +++---------------- .../RegionalGuidanceRefImageImage.tsx | 28 +++---------------- .../gallery/hooks/useRecallDimensions.ts | 10 +++++-- 3 files changed, 15 insertions(+), 51 deletions(-) diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageImage.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageImage.tsx index a754f0e4da4..cc40a405445 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageImage.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageImage.tsx @@ -2,11 +2,7 @@ import { Flex } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; import { objectEquals } from '@observ33r/object-equals'; import { skipToken } from '@reduxjs/toolkit/query'; -import { useAppSelector, useAppStore } from 'app/store/storeHooks'; import { UploadImageIconButton } from 'common/hooks/useImageUploadButton'; -import { bboxSizeOptimized, bboxSizeRecalled } from 'features/controlLayers/store/canvasSlice'; -import { useCanvasIsStaging } from 'features/controlLayers/store/canvasStagingAreaSlice'; -import { sizeOptimized, sizeRecalled } from 'features/controlLayers/store/paramsSlice'; import type { CroppableImageWithDims } from 'features/controlLayers/store/types'; import { imageDTOToCroppableImage, imageDTOToImageWithDims } from 'features/controlLayers/store/util'; import { Editor } from 'features/cropper/lib/editor'; @@ -15,7 +11,7 @@ import type { setGlobalReferenceImageDndTarget, setRegionalGuidanceReferenceImag import { DndDropTarget } from 'features/dnd/DndDropTarget'; import { DndImage } from 'features/dnd/DndImage'; import { DndImageIcon } from 'features/dnd/DndImageIcon'; -import { selectActiveTab } from 'features/ui/store/uiSelectors'; +import { useRecallDimensions } from 'features/gallery/hooks/useRecallDimensions'; import { memo, useCallback, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { PiArrowCounterClockwiseBold, PiCropBold, PiRulerBold } from 'react-icons/pi'; @@ -38,10 +34,7 @@ export const RefImageImage = memo( dndTargetData, }: Props) => { const { t } = useTranslation(); - const store = useAppStore(); const isConnected = useStore($isConnected); - const tab = useAppSelector(selectActiveTab); - const isStaging = useCanvasIsStaging(); const imageWithDims = image?.crop?.image ?? image?.original.image ?? null; const croppedImageDTOReq = useGetImageDTOQuery(image?.crop?.image?.image_name ?? skipToken); const originalImageDTOReq = useGetImageDTOQuery(image?.original.image.image_name ?? skipToken); @@ -50,6 +43,7 @@ export const RefImageImage = memo( const originalImageDTO = originalImageDTOReq.currentData; const croppedImageDTO = croppedImageDTOReq.currentData; const imageDTO = croppedImageDTO ?? originalImageDTO; + const recallDimensions = useRecallDimensions(imageDTO); const handleResetControlImage = useCallback(() => { onChangeImage(null); @@ -68,20 +62,6 @@ export const RefImageImage = memo( [onChangeImage] ); - const recallSizeAndOptimize = useCallback(() => { - if (!imageDTO || (tab === 'canvas' && isStaging)) { - return; - } - const { width, height } = imageDTO; - if (tab === 'canvas') { - store.dispatch(bboxSizeRecalled({ width, height })); - store.dispatch(bboxSizeOptimized()); - } else if (tab === 'generate') { - store.dispatch(sizeRecalled({ width, height })); - store.dispatch(sizeOptimized()); - } - }, [imageDTO, isStaging, store, tab]); - const edit = useCallback(() => { if (!originalImageDTO) { return; @@ -159,10 +139,10 @@ export const RefImageImage = memo( } tooltip={t('parameters.useSize')} - isDisabled={!imageDTO || (tab === 'canvas' && isStaging)} + isDisabled={!recallDimensions.isEnabled} /> diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RegionalGuidance/RegionalGuidanceRefImageImage.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RegionalGuidance/RegionalGuidanceRefImageImage.tsx index 85285dd4ef3..88bca28df4c 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/RegionalGuidance/RegionalGuidanceRefImageImage.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/RegionalGuidance/RegionalGuidanceRefImageImage.tsx @@ -1,17 +1,13 @@ import { Flex } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; import { skipToken } from '@reduxjs/toolkit/query'; -import { useAppSelector, useAppStore } from 'app/store/storeHooks'; import { UploadImageIconButton } from 'common/hooks/useImageUploadButton'; -import { bboxSizeOptimized, bboxSizeRecalled } from 'features/controlLayers/store/canvasSlice'; -import { useCanvasIsStaging } from 'features/controlLayers/store/canvasStagingAreaSlice'; -import { sizeOptimized, sizeRecalled } from 'features/controlLayers/store/paramsSlice'; import type { ImageWithDims } from 'features/controlLayers/store/types'; import type { setRegionalGuidanceReferenceImageDndTarget } from 'features/dnd/dnd'; import { DndDropTarget } from 'features/dnd/DndDropTarget'; import { DndImage } from 'features/dnd/DndImage'; import { DndImageIcon } from 'features/dnd/DndImageIcon'; -import { selectActiveTab } from 'features/ui/store/uiSelectors'; +import { useRecallDimensions } from 'features/gallery/hooks/useRecallDimensions'; import { memo, useCallback, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { PiArrowCounterClockwiseBold, PiRulerBold } from 'react-icons/pi'; @@ -28,11 +24,9 @@ type Props = { export const RegionalGuidanceRefImageImage = memo(({ image, onChangeImage, dndTarget, dndTargetData }: Props) => { const { t } = useTranslation(); - const store = useAppStore(); const isConnected = useStore($isConnected); - const tab = useAppSelector(selectActiveTab); - const isStaging = useCanvasIsStaging(); const { currentData: imageDTO, isError } = useGetImageDTOQuery(image?.image_name ?? skipToken); + const recallDimensions = useRecallDimensions(imageDTO); const handleResetControlImage = useCallback(() => { onChangeImage(null); }, [onChangeImage]); @@ -50,20 +44,6 @@ export const RegionalGuidanceRefImageImage = memo(({ image, onChangeImage, dndTa [onChangeImage] ); - const recallSizeAndOptimize = useCallback(() => { - if (!imageDTO || (tab === 'canvas' && isStaging)) { - return; - } - const { width, height } = imageDTO; - if (tab === 'canvas') { - store.dispatch(bboxSizeRecalled({ width, height })); - store.dispatch(bboxSizeOptimized()); - } else if (tab === 'generate') { - store.dispatch(sizeRecalled({ width, height })); - store.dispatch(sizeOptimized()); - } - }, [imageDTO, isStaging, store, tab]); - return ( {!imageDTO && ( @@ -87,10 +67,10 @@ export const RegionalGuidanceRefImageImage = memo(({ image, onChangeImage, dndTa } tooltip={t('parameters.useSize')} - isDisabled={!imageDTO || (tab === 'canvas' && isStaging)} + isDisabled={!recallDimensions.isEnabled} /> diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useRecallDimensions.ts b/invokeai/frontend/web/src/features/gallery/hooks/useRecallDimensions.ts index 3feb074a35e..bcf5401fac7 100644 --- a/invokeai/frontend/web/src/features/gallery/hooks/useRecallDimensions.ts +++ b/invokeai/frontend/web/src/features/gallery/hooks/useRecallDimensions.ts @@ -5,12 +5,16 @@ import { selectActiveTab } from 'features/ui/store/uiSelectors'; import { useCallback, useMemo } from 'react'; import type { ImageDTO } from 'services/api/types'; -export const useRecallDimensions = (imageDTO: ImageDTO) => { +export const useRecallDimensions = (imageDTO: ImageDTO | null | undefined) => { const store = useAppStore(); const tab = useAppSelector(selectActiveTab); const isStaging = useCanvasIsStaging(); const isEnabled = useMemo(() => { + if (!imageDTO) { + return false; + } + if (tab !== 'canvas' && tab !== 'generate') { return false; } @@ -20,10 +24,10 @@ export const useRecallDimensions = (imageDTO: ImageDTO) => { } return true; - }, [isStaging, tab]); + }, [imageDTO, isStaging, tab]); const recall = useCallback(() => { - if (!isEnabled) { + if (!isEnabled || !imageDTO) { return; } MetadataUtils.recallImageDimensions(imageDTO, store); From edae72958610f5157bc66a7935d62ce4339e71df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ufuk=20Sarp=20Sel=C3=A7ok?= Date: Mon, 27 Apr 2026 03:27:12 +0300 Subject: [PATCH 2/2] remove unused exports --- .../frontend/web/src/features/controlLayers/store/canvasSlice.ts | 1 - .../frontend/web/src/features/controlLayers/store/paramsSlice.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasSlice.ts index dad599374ce..c7e348eead1 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/canvasSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasSlice.ts @@ -1917,7 +1917,6 @@ export const { bboxScaledWidthChanged, bboxScaledHeightChanged, bboxScaleMethodChanged, - bboxSizeRecalled, bboxWidthChanged, bboxHeightChanged, bboxAspectRatioLockToggled, diff --git a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts index 25670b28df0..30f74a67aec 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/paramsSlice.ts @@ -647,7 +647,6 @@ export const { modelChanged, // Dimensions - sizeRecalled, widthChanged, heightChanged, aspectRatioLockToggled,