From 1335377fb1b99bd381d0291b1a9ec39722b4c467 Mon Sep 17 00:00:00 2001
From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com>
Date: Tue, 1 Jul 2025 23:53:35 -0400
Subject: [PATCH] Fixes
---
.../components/RefImage/RefImageHeader.tsx | 12 ++--
.../components/RefImage/RefImagePreview.tsx | 16 +++++-
.../hooks/useCanvasInvertMaskHotkey.ts | 55 +++++++++++++++++++
3 files changed, 77 insertions(+), 6 deletions(-)
create mode 100644 invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasInvertMaskHotkey.ts
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageHeader.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageHeader.tsx
index e366d0cad9..392580e3a1 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageHeader.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageHeader.tsx
@@ -10,7 +10,7 @@ import {
selectRefImageEntityIds,
} from 'features/controlLayers/store/refImagesSlice';
import { memo, useCallback, useMemo } from 'react';
-import { PiEyeBold, PiEyeSlashBold, PiTrashBold } from 'react-icons/pi';
+import { PiCircleBold, PiCircleFill, PiTrashBold } from 'react-icons/pi';
const textSx: SystemStyleObject = {
color: 'base.300',
@@ -41,7 +41,12 @@ export const RefImageHeader = memo(() => {
Reference Image #{refImageNumber}
-
+
+ {!entity.isEnabled && (
+
+ Disabled
+
+ )}
{
alignSelf="stretch"
aria-label={entity.isEnabled ? 'Disable ref image' : 'Enable ref image'}
onClick={toggleIsEnabled}
- icon={entity.isEnabled ? : }
- colorScheme={entity.isEnabled ? 'base' : 'warning'}
+ icon={entity.isEnabled ? : }
/>
{
transform="translateX(-50%) translateY(-50%)"
filter="drop-shadow(0px 0px 4px rgb(0, 0, 0)) drop-shadow(0px 0px 2px rgba(0, 0, 0, 1))"
color="error.500"
- boxSize={16}
+ boxSize={6}
as={PiExclamationMarkBold}
/>
)}
+ {!entity.isEnabled && (
+
+ )}
);
});
diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasInvertMaskHotkey.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasInvertMaskHotkey.ts
new file mode 100644
index 0000000000..01698062e2
--- /dev/null
+++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useCanvasInvertMaskHotkey.ts
@@ -0,0 +1,55 @@
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
+import { useCanvasIsBusy } from 'features/controlLayers/hooks/useCanvasIsBusy';
+import { inpaintMaskInverted } from 'features/controlLayers/store/canvasSlice';
+import { selectCanvasSlice, selectSelectedEntityIdentifier } from 'features/controlLayers/store/selectors';
+import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
+import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
+import { useCallback, useMemo } from 'react';
+
+export const useCanvasInvertMaskHotkey = () => {
+ useAssertSingleton('useCanvasInvertMaskHotkey');
+ const dispatch = useAppDispatch();
+ const selectedEntityIdentifier = useAppSelector(selectSelectedEntityIdentifier);
+ const canvasSlice = useAppSelector(selectCanvasSlice);
+ const isBusy = useCanvasIsBusy();
+
+ const handleInvertMask = useCallback(() => {
+ if (!selectedEntityIdentifier || selectedEntityIdentifier.type !== 'inpaint_mask') {
+ return;
+ }
+
+ // Check if the selected entity has objects and there's a valid bounding box
+ const entity = canvasSlice.inpaintMasks.entities.find((entity) => entity.id === selectedEntityIdentifier.id);
+ const hasObjects = entity?.objects && entity.objects.length > 0;
+ const hasBbox = canvasSlice.bbox.rect.width > 0 && canvasSlice.bbox.rect.height > 0;
+
+ if (!hasObjects || !hasBbox) {
+ return;
+ }
+
+ dispatch(
+ inpaintMaskInverted({ entityIdentifier: selectedEntityIdentifier as CanvasEntityIdentifier<'inpaint_mask'> })
+ );
+ }, [dispatch, selectedEntityIdentifier, canvasSlice]);
+
+ const isInvertMaskAllowed = useMemo(() => {
+ if (!selectedEntityIdentifier || selectedEntityIdentifier.type !== 'inpaint_mask') {
+ return false;
+ }
+
+ const entity = canvasSlice.inpaintMasks.entities.find((entity) => entity.id === selectedEntityIdentifier.id);
+ const hasObjects = entity?.objects && entity.objects.length > 0;
+ const hasBbox = canvasSlice.bbox.rect.width > 0 && canvasSlice.bbox.rect.height > 0;
+
+ return hasObjects && hasBbox;
+ }, [selectedEntityIdentifier, canvasSlice]);
+
+ useRegisteredHotkeys({
+ id: 'invertMask',
+ category: 'canvas',
+ callback: handleInvertMask,
+ options: { enabled: isInvertMaskAllowed && !isBusy, preventDefault: true },
+ dependencies: [isInvertMaskAllowed, isBusy, handleInvertMask],
+ });
+};