mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Address bounding box feedback
- Adds back toggle to hide bounding box - Box quick toggle = q, normal toggle = shift + q - Styles canvas alert icons
This commit is contained in:
parent
423ae32097
commit
0eef74bc00
@ -113,7 +113,7 @@ const BoundingBoxSettings = () => {
|
||||
<div className="inpainting-bounding-box-settings">
|
||||
<div className="inpainting-bounding-box-header">
|
||||
<p>Inpaint Box</p>
|
||||
{/* <IAIIconButton
|
||||
<IAIIconButton
|
||||
aria-label="Toggle Bounding Box Visibility"
|
||||
icon={
|
||||
shouldShowBoundingBox ? <BiShow size={22} /> : <BiHide size={22} />
|
||||
@ -121,7 +121,7 @@ const BoundingBoxSettings = () => {
|
||||
onClick={handleShowBoundingBox}
|
||||
background={'none'}
|
||||
padding={0}
|
||||
/> */}
|
||||
/>
|
||||
</div>
|
||||
<div className="inpainting-bounding-box-settings-items">
|
||||
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
|
||||
|
@ -194,12 +194,12 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
||||
{
|
||||
title: 'Lock Bounding Box',
|
||||
desc: 'Locks the bounding box',
|
||||
hotkey: 'M',
|
||||
hotkey: 'Shift+Q',
|
||||
},
|
||||
{
|
||||
title: 'Quick Toggle Lock Bounding Box',
|
||||
desc: 'Hold to toggle locking the bounding box',
|
||||
hotkey: 'Space',
|
||||
hotkey: 'Q',
|
||||
},
|
||||
{
|
||||
title: 'Expand Inpainting Area',
|
||||
|
@ -38,6 +38,7 @@ import { Icon, IconButton, Tooltip, useToast } from '@chakra-ui/react';
|
||||
import { FaLock, FaUnlock } from 'react-icons/fa';
|
||||
import { MdInvertColors, MdInvertColorsOff } from 'react-icons/md';
|
||||
import { BiHide, BiShow } from 'react-icons/bi';
|
||||
import InpaintingCanvasStatusIcons from './InpaintingCanvasStatusIcons';
|
||||
|
||||
// Use a closure allow other components to use these things... not ideal...
|
||||
export let stageRef: MutableRefObject<StageType | null>;
|
||||
@ -243,39 +244,7 @@ const InpaintingCanvas = () => {
|
||||
return (
|
||||
<div className="inpainting-canvas-container" tabIndex={1}>
|
||||
<div className="inpainting-canvas-wrapper">
|
||||
<div className="inpainting-alerts">
|
||||
<div style={{ pointerEvents: 'none' }}>
|
||||
<IconButton
|
||||
aria-label="Show/HideMask"
|
||||
size="xs"
|
||||
variant={'ghost'}
|
||||
fontSize={'1rem'}
|
||||
data-selected={!shouldShowMask}
|
||||
icon={shouldShowMask ? <BiShow /> : <BiHide />}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ pointerEvents: 'none' }}>
|
||||
<IconButton
|
||||
aria-label="Invert Mask"
|
||||
size="xs"
|
||||
variant={'ghost'}
|
||||
fontSize={'1rem'}
|
||||
data-selected={shouldInvertMask}
|
||||
icon={
|
||||
shouldInvertMask ? <MdInvertColors /> : <MdInvertColorsOff />
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ pointerEvents: 'none' }}>
|
||||
<IconButton
|
||||
aria-label="Bounding Box Lock"
|
||||
size="xs"
|
||||
variant={'ghost'}
|
||||
data-selected={shouldLockBoundingBox}
|
||||
icon={shouldLockBoundingBox ? <FaLock /> : <FaUnlock />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<InpaintingCanvasStatusIcons />
|
||||
|
||||
{canvasBgImage && (
|
||||
<Stage
|
||||
@ -330,17 +299,16 @@ const InpaintingCanvas = () => {
|
||||
/>
|
||||
)}
|
||||
</Layer>
|
||||
{shouldShowMask && (
|
||||
<Layer>
|
||||
{shouldShowBoundingBoxFill && shouldShowBoundingBox && (
|
||||
<InpaintingBoundingBoxPreviewOverlay />
|
||||
)}
|
||||
<InpaintingBoundingBoxPreview />
|
||||
{!isMouseOverBoundingBox && !isModifyingBoundingBox && (
|
||||
<InpaintingCanvasBrushPreviewOutline />
|
||||
)}
|
||||
</Layer>
|
||||
)}
|
||||
<Layer>
|
||||
{shouldShowBoundingBoxFill && shouldShowBoundingBox && (
|
||||
<InpaintingBoundingBoxPreviewOverlay />
|
||||
)}
|
||||
{shouldShowBoundingBox && <InpaintingBoundingBoxPreview />}
|
||||
|
||||
{!isMouseOverBoundingBox && !isModifyingBoundingBox && (
|
||||
<InpaintingCanvasBrushPreviewOutline />
|
||||
)}
|
||||
</Layer>
|
||||
</>
|
||||
)}
|
||||
</Stage>
|
||||
|
@ -0,0 +1,31 @@
|
||||
.inpainting-alerts {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
z-index: 2;
|
||||
margin: 0.25rem;
|
||||
padding: 0.25rem;
|
||||
pointer-events: none;
|
||||
background-color: var(--text-color);
|
||||
opacity: 0.7;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
button {
|
||||
svg {
|
||||
fill: var(--background-color);
|
||||
}
|
||||
|
||||
&[data-selected='true'] {
|
||||
svg {
|
||||
fill: var(--accent-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-alert='true'] {
|
||||
svg {
|
||||
fill: var(--destructive-color-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
const inpaintingCanvasStatusIconsSelector = createSelector(
|
||||
(state: RootState) => state.inpainting,
|
||||
(inpainting: InpaintingState) => {
|
||||
const {
|
||||
shouldShowMask,
|
||||
shouldInvertMask,
|
||||
shouldLockBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
} = inpainting;
|
||||
|
||||
return {
|
||||
shouldShowMask,
|
||||
shouldInvertMask,
|
||||
shouldLockBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
import { IconButton } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { BiHide, BiShow } from 'react-icons/bi';
|
||||
import { BsBoundingBox } from 'react-icons/bs';
|
||||
import { FaLock, FaUnlock } from 'react-icons/fa';
|
||||
import { MdInvertColors, MdInvertColorsOff } from 'react-icons/md';
|
||||
import { RootState, useAppSelector } from '../../../app/store';
|
||||
import { InpaintingState } from './inpaintingSlice';
|
||||
|
||||
const InpaintingCanvasStatusIcons = () => {
|
||||
const {
|
||||
shouldShowMask,
|
||||
shouldInvertMask,
|
||||
shouldLockBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
} = useAppSelector(inpaintingCanvasStatusIconsSelector);
|
||||
|
||||
return (
|
||||
<div className="inpainting-alerts">
|
||||
<div style={{ pointerEvents: 'none' }}>
|
||||
<IconButton
|
||||
aria-label="Show/HideMask"
|
||||
size="xs"
|
||||
variant={'ghost'}
|
||||
fontSize={'1rem'}
|
||||
data-selected={!shouldShowMask}
|
||||
icon={shouldShowMask ? <BiShow /> : <BiHide />}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ pointerEvents: 'none' }}>
|
||||
<IconButton
|
||||
aria-label="Invert Mask"
|
||||
variant={'ghost'}
|
||||
size="xs"
|
||||
fontSize={'1rem'}
|
||||
data-selected={shouldInvertMask}
|
||||
icon={shouldInvertMask ? <MdInvertColors /> : <MdInvertColorsOff />}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ pointerEvents: 'none' }}>
|
||||
<IconButton
|
||||
aria-label="Bounding Box Lock"
|
||||
size="xs"
|
||||
variant={'ghost'}
|
||||
data-selected={shouldLockBoundingBox}
|
||||
icon={shouldLockBoundingBox ? <FaLock /> : <FaUnlock />}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ pointerEvents: 'none' }}>
|
||||
<IconButton
|
||||
aria-label="Bounding Box Lock"
|
||||
size="xs"
|
||||
variant={'ghost'}
|
||||
data-alert={!shouldShowBoundingBox}
|
||||
icon={<BsBoundingBox />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InpaintingCanvasStatusIcons;
|
@ -154,7 +154,7 @@ const InpaintingControls = () => {
|
||||
|
||||
// Toggle lock bounding box
|
||||
useHotkeys(
|
||||
'm',
|
||||
'shift+q',
|
||||
(e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
dispatch(toggleShouldLockBoundingBox());
|
||||
|
@ -24,13 +24,18 @@ const keyboardEventManagerSelector = createSelector(
|
||||
activeTabNameSelector,
|
||||
],
|
||||
(options: OptionsState, inpainting: InpaintingState, activeTabName) => {
|
||||
const { shouldShowMask, cursorPosition, shouldLockBoundingBox } =
|
||||
inpainting;
|
||||
const {
|
||||
shouldShowMask,
|
||||
cursorPosition,
|
||||
shouldLockBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
} = inpainting;
|
||||
return {
|
||||
activeTabName,
|
||||
shouldShowMask,
|
||||
isCursorOnCanvas: Boolean(cursorPosition),
|
||||
shouldLockBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
};
|
||||
},
|
||||
{
|
||||
@ -47,6 +52,7 @@ const KeyboardEventManager = () => {
|
||||
activeTabName,
|
||||
isCursorOnCanvas,
|
||||
shouldLockBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
} = useAppSelector(keyboardEventManagerSelector);
|
||||
|
||||
const wasLastEventOverCanvas = useRef<boolean>(false);
|
||||
@ -55,7 +61,7 @@ const KeyboardEventManager = () => {
|
||||
useEffect(() => {
|
||||
const listener = (e: KeyboardEvent) => {
|
||||
if (
|
||||
!['x', ' '].includes(e.key) ||
|
||||
!['x', 'q'].includes(e.key) ||
|
||||
activeTabName !== 'inpainting' ||
|
||||
!shouldShowMask
|
||||
) {
|
||||
@ -93,8 +99,8 @@ const KeyboardEventManager = () => {
|
||||
dispatch(toggleTool());
|
||||
break;
|
||||
}
|
||||
case ' ': {
|
||||
if (!shouldShowMask) break;
|
||||
case 'q': {
|
||||
if (!shouldShowMask || !shouldShowBoundingBox) break;
|
||||
dispatch(setIsSpacebarHeld(e.type === 'keydown'));
|
||||
dispatch(setShouldLockBoundingBox(e.type !== 'keydown'));
|
||||
break;
|
||||
@ -118,6 +124,7 @@ const KeyboardEventManager = () => {
|
||||
shouldShowMask,
|
||||
isCursorOnCanvas,
|
||||
shouldLockBoundingBox,
|
||||
shouldShowBoundingBox,
|
||||
]);
|
||||
|
||||
return null;
|
||||
|
@ -39,8 +39,9 @@
|
||||
@use '../features/tabs/InvokeOptionsPanel.scss';
|
||||
@use '../features/tabs/TextToImage/TextToImage.scss';
|
||||
@use '../features/tabs/ImageToImage/ImageToImage.scss';
|
||||
@use '../features/tabs/Inpainting/Inpainting.scss';
|
||||
@use '../features/tabs/FloatingButton.scss';
|
||||
@use '../features/tabs/Inpainting/Inpainting.scss';
|
||||
@use '../features/tabs/Inpainting/InpaintingCanvasStatusIcons.scss';
|
||||
|
||||
// Component Shared
|
||||
@use '../common/components/IAINumberInput.scss';
|
||||
|
Loading…
Reference in New Issue
Block a user