This commit is contained in:
Kent Keirsey
2025-07-01 23:53:35 -04:00
parent adbcc191d9
commit 1335377fb1
3 changed files with 77 additions and 6 deletions

View File

@@ -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(() => {
<Text fontWeight="semibold" sx={textSx} data-is-error={!entity.config.image}>
Reference Image #{refImageNumber}
</Text>
<Flex>
<Flex alignItems="center" gap={1}>
{!entity.isEnabled && (
<Text fontSize="xs" fontStyle="italic" color="base.400">
Disabled
</Text>
)}
<IconButton
tooltip={entity.isEnabled ? 'Disable Reference Image' : 'Enable Reference Image'}
size="xs"
@@ -49,8 +54,7 @@ export const RefImageHeader = memo(() => {
alignSelf="stretch"
aria-label={entity.isEnabled ? 'Disable ref image' : 'Enable ref image'}
onClick={toggleIsEnabled}
icon={entity.isEnabled ? <PiEyeBold /> : <PiEyeSlashBold />}
colorScheme={entity.isEnabled ? 'base' : 'warning'}
icon={entity.isEnabled ? <PiCircleFill /> : <PiCircleBold />}
/>
<IconButton
tooltip="Delete Reference Image"

View File

@@ -12,7 +12,7 @@ import {
} from 'features/controlLayers/store/refImagesSlice';
import { isIPAdapterConfig } from 'features/controlLayers/store/types';
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
import { PiExclamationMarkBold, PiImageBold } from 'react-icons/pi';
import { PiExclamationMarkBold, PiEyeSlashBold, PiImageBold } from 'react-icons/pi';
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
const baseSx: SystemStyleObject = {
@@ -160,10 +160,22 @@ export const RefImagePreview = memo(() => {
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 && (
<Icon
position="absolute"
top="50%"
left="50%"
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="base.100"
boxSize={6}
as={PiEyeSlashBold}
/>
)}
</Flex>
);
});

View File

@@ -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],
});
};