Merge branch 'main' into lstein/config-management-fixes

This commit is contained in:
Lincoln Stein 2023-06-05 15:10:33 -07:00 committed by GitHub
commit 9bcf0b2251
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 202 additions and 207 deletions
invokeai/frontend/web/src
app/components/ImageDnd
common/components
features
canvas/store
controlNet/components
gallery/components
parameters/components/Parameters/ImageToImage
ui/components/tabs/UnifiedCanvas

@ -46,9 +46,12 @@ const ImageDndContext = (props: ImageDndContextProps) => {
const touchSensor = useSensor(TouchSensor, {
activationConstraint: { distance: 15 },
});
const keyboardSensor = useSensor(KeyboardSensor);
// TODO: Use KeyboardSensor - needs composition of multiple collisionDetection algos
// Alternatively, fix `rectIntersection` collection detection to work with the drag overlay
// (currently the drag element collision rect is not correctly calculated)
// const keyboardSensor = useSensor(KeyboardSensor);
const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
const sensors = useSensors(mouseSensor, touchSensor);
return (
<DndContext

@ -1,23 +1,17 @@
import {
Box,
Flex,
Icon,
IconButtonProps,
Image,
Text,
} from '@chakra-ui/react';
import { Box, Flex, Icon, IconButtonProps, Image } from '@chakra-ui/react';
import { useDraggable, useDroppable } from '@dnd-kit/core';
import { useCombinedRefs } from '@dnd-kit/utilities';
import IAIIconButton from 'common/components/IAIIconButton';
import { IAIImageFallback } from 'common/components/IAIImageFallback';
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
import { useGetUrl } from 'common/util/getUrl';
import { AnimatePresence, motion } from 'framer-motion';
import { AnimatePresence } from 'framer-motion';
import { ReactElement, SyntheticEvent } from 'react';
import { memo, useRef } from 'react';
import { FaImage, FaTimes } from 'react-icons/fa';
import { ImageDTO } from 'services/api';
import { v4 as uuidv4 } from 'uuid';
import IAIDropOverlay from './IAIDropOverlay';
type IAIDndImageProps = {
image: ImageDTO | null | undefined;
@ -138,7 +132,7 @@ const IAIDndImage = (props: IAIDndImageProps) => {
</Box>
)}
<AnimatePresence>
{active && <DropOverlay isOver={isOver} />}
{active && <IAIDropOverlay isOver={isOver} />}
</AnimatePresence>
</Flex>
)}
@ -164,7 +158,7 @@ const IAIDndImage = (props: IAIDndImageProps) => {
/>
</Flex>
<AnimatePresence>
{active && <DropOverlay isOver={isOver} />}
{active && <IAIDropOverlay isOver={isOver} />}
</AnimatePresence>
</>
)}
@ -173,86 +167,3 @@ const IAIDndImage = (props: IAIDndImageProps) => {
};
export default memo(IAIDndImage);
type DropOverlayProps = {
isOver: boolean;
};
const DropOverlay = (props: DropOverlayProps) => {
const { isOver } = props;
return (
<motion.div
key="statusText"
initial={{
opacity: 0,
}}
animate={{
opacity: 1,
transition: { duration: 0.1 },
}}
exit={{
opacity: 0,
transition: { duration: 0.1 },
}}
>
<Flex
sx={{
position: 'absolute',
top: 0,
left: 0,
w: 'full',
h: 'full',
}}
>
<Flex
sx={{
position: 'absolute',
top: 0,
left: 0,
w: 'full',
h: 'full',
bg: 'base.900',
opacity: 0.7,
borderRadius: 'base',
alignItems: 'center',
justifyContent: 'center',
transitionProperty: 'common',
transitionDuration: '0.1s',
}}
/>
<Flex
sx={{
position: 'absolute',
top: 0,
left: 0,
w: 'full',
h: 'full',
opacity: 1,
borderWidth: 2,
borderColor: isOver ? 'base.200' : 'base.500',
borderRadius: 'base',
borderStyle: 'dashed',
transitionProperty: 'common',
transitionDuration: '0.1s',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text
sx={{
fontSize: '2xl',
fontWeight: 600,
transform: isOver ? 'scale(1.1)' : 'scale(1)',
color: isOver ? 'base.100' : 'base.500',
transitionProperty: 'common',
transitionDuration: '0.1s',
}}
>
Drop
</Text>
</Flex>
</Flex>
</motion.div>
);
};

@ -0,0 +1,91 @@
import { Flex, Text } from '@chakra-ui/react';
import { motion } from 'framer-motion';
import { memo, useRef } from 'react';
import { v4 as uuidv4 } from 'uuid';
type Props = {
isOver: boolean;
label?: string;
};
export const IAIDropOverlay = (props: Props) => {
const { isOver, label = 'Drop' } = props;
const motionId = useRef(uuidv4());
return (
<motion.div
key={motionId.current}
initial={{
opacity: 0,
}}
animate={{
opacity: 1,
transition: { duration: 0.1 },
}}
exit={{
opacity: 0,
transition: { duration: 0.1 },
}}
>
<Flex
sx={{
position: 'absolute',
top: 0,
left: 0,
w: 'full',
h: 'full',
}}
>
<Flex
sx={{
position: 'absolute',
top: 0,
left: 0,
w: 'full',
h: 'full',
bg: 'base.900',
opacity: 0.7,
borderRadius: 'base',
alignItems: 'center',
justifyContent: 'center',
transitionProperty: 'common',
transitionDuration: '0.1s',
}}
/>
<Flex
sx={{
position: 'absolute',
top: 0,
left: 0,
w: 'full',
h: 'full',
opacity: 1,
borderWidth: 2,
borderColor: isOver ? 'base.200' : 'base.500',
borderRadius: 'base',
borderStyle: 'dashed',
transitionProperty: 'common',
transitionDuration: '0.1s',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text
sx={{
fontSize: '2xl',
fontWeight: 600,
transform: isOver ? 'scale(1.1)' : 'scale(1)',
color: isOver ? 'base.100' : 'base.500',
transitionProperty: 'common',
transitionDuration: '0.1s',
}}
>
{label}
</Text>
</Flex>
</Flex>
</motion.div>
);
};
export default memo(IAIDropOverlay);

@ -30,6 +30,7 @@ import {
} from './canvasTypes';
import { ImageDTO } from 'services/api';
import { sessionCanceled } from 'services/thunks/session';
import { setShouldUseCanvasBetaLayout } from 'features/ui/store/uiSlice';
export const initialLayerState: CanvasLayerState = {
objects: [],
@ -851,6 +852,10 @@ export const canvasSlice = createSlice({
state.layerState.stagingArea = initialLayerState.stagingArea;
}
});
builder.addCase(setShouldUseCanvasBetaLayout, (state, action) => {
state.doesCanvasNeedScaling = true;
});
},
});

@ -60,7 +60,10 @@ const ControlNetImagePreview = (props: Props) => {
processorType !== 'none';
return (
<Box ref={containerRef} sx={{ position: 'relative', w: 'full', h: 'full' }}>
<Box
ref={containerRef}
sx={{ position: 'relative', w: 'full', h: 'full', aspectRatio: '1/1' }}
>
<IAIDndImage
image={controlImage}
onDrop={handleDrop}

@ -51,6 +51,7 @@ const CurrentImageDisplay = () => {
alignItems: 'center',
justifyContent: 'center',
gap: 4,
position: 'absolute',
}}
>
<CurrentImagePreview />

@ -72,9 +72,10 @@ const InitialImagePreview = () => {
sx={{
width: 'full',
height: 'full',
position: 'relative',
position: 'absolute',
alignItems: 'center',
justifyContent: 'center',
p: 4,
}}
>
<IAIDndImage

@ -1,72 +0,0 @@
import { createSelector } from '@reduxjs/toolkit';
// import IAICanvas from 'features/canvas/components/IAICanvas';
import { Box, Flex } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAICanvas from 'features/canvas/components/IAICanvas';
import IAICanvasResizer from 'features/canvas/components/IAICanvasResizer';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { isEqual } from 'lodash-es';
import { useLayoutEffect } from 'react';
import UnifiedCanvasToolbarBeta from './UnifiedCanvasToolbarBeta';
import UnifiedCanvasToolSettingsBeta from './UnifiedCanvasToolSettingsBeta';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
const selector = createSelector(
[canvasSelector],
(canvas) => {
const { doesCanvasNeedScaling } = canvas;
return {
doesCanvasNeedScaling,
};
},
{
memoizeOptions: {
resultEqualityCheck: isEqual,
},
}
);
const UnifiedCanvasContentBeta = () => {
const dispatch = useAppDispatch();
const { doesCanvasNeedScaling } = useAppSelector(selector);
useLayoutEffect(() => {
dispatch(requestCanvasRescale());
const resizeCallback = () => {
dispatch(requestCanvasRescale());
};
window.addEventListener('resize', resizeCallback);
return () => window.removeEventListener('resize', resizeCallback);
}, [dispatch]);
return (
<Box
sx={{
width: '100%',
height: '100%',
borderRadius: 'base',
bg: 'base.850',
}}
>
<Flex
flexDirection="row"
width="100%"
height="100%"
columnGap={4}
padding={4}
>
<UnifiedCanvasToolbarBeta />
<Flex width="100%" height="100%" flexDirection="column" rowGap={4}>
<UnifiedCanvasToolSettingsBeta />
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
</Flex>
</Flex>
</Box>
);
};
export default UnifiedCanvasContentBeta;

@ -1,34 +1,58 @@
import { Box, Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAICanvas from 'features/canvas/components/IAICanvas';
import IAICanvasResizer from 'features/canvas/components/IAICanvasResizer';
import IAICanvasToolbar from 'features/canvas/components/IAICanvasToolbar/IAICanvasToolbar';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import { isEqual } from 'lodash-es';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { memo, useLayoutEffect } from 'react';
import { memo, useCallback, useLayoutEffect } from 'react';
import UnifiedCanvasToolbarBeta from './UnifiedCanvasBeta/UnifiedCanvasToolbarBeta';
import UnifiedCanvasToolSettingsBeta from './UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta';
import { ImageDTO } from 'services/api';
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
import { useDroppable } from '@dnd-kit/core';
import IAIDropOverlay from 'common/components/IAIDropOverlay';
const selector = createSelector(
[canvasSelector],
(canvas) => {
[canvasSelector, uiSelector],
(canvas, ui) => {
const { doesCanvasNeedScaling } = canvas;
const { shouldUseCanvasBetaLayout } = ui;
return {
doesCanvasNeedScaling,
shouldUseCanvasBetaLayout,
};
},
{
memoizeOptions: {
resultEqualityCheck: isEqual,
},
}
defaultSelectorOptions
);
const UnifiedCanvasContent = () => {
const dispatch = useAppDispatch();
const { doesCanvasNeedScaling } = useAppSelector(selector);
const { doesCanvasNeedScaling, shouldUseCanvasBetaLayout } =
useAppSelector(selector);
const onDrop = useCallback(
(droppedImage: ImageDTO) => {
dispatch(setInitialCanvasImage(droppedImage));
},
[dispatch]
);
const {
isOver,
setNodeRef: setDroppableRef,
active,
} = useDroppable({
id: 'unifiedCanvas',
data: {
handleDrop: onDrop,
},
});
useLayoutEffect(() => {
dispatch(requestCanvasRescale());
@ -42,14 +66,57 @@ const UnifiedCanvasContent = () => {
return () => window.removeEventListener('resize', resizeCallback);
}, [dispatch]);
if (shouldUseCanvasBetaLayout) {
return (
<Box
ref={setDroppableRef}
tabIndex={0}
sx={{
w: 'full',
h: 'full',
borderRadius: 'base',
bg: 'base.850',
p: 4,
}}
>
<Flex
sx={{
w: 'full',
h: 'full',
gap: 4,
}}
>
<UnifiedCanvasToolbarBeta />
<Flex
sx={{
flexDir: 'column',
w: 'full',
h: 'full',
gap: 4,
position: 'relative',
}}
>
<UnifiedCanvasToolSettingsBeta />
<Box sx={{ w: 'full', h: 'full', position: 'relative' }}>
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
{active && <IAIDropOverlay isOver={isOver} />}
</Box>
</Flex>
</Flex>
</Box>
);
}
return (
<Box
ref={setDroppableRef}
tabIndex={-1}
sx={{
width: '100%',
height: '100%',
padding: 4,
w: 'full',
h: 'full',
borderRadius: 'base',
bg: 'base.850',
p: 4,
}}
>
<Flex
@ -57,8 +124,8 @@ const UnifiedCanvasContent = () => {
flexDirection: 'column',
alignItems: 'center',
gap: 4,
width: '100%',
height: '100%',
w: 'full',
h: 'full',
}}
>
<IAICanvasToolbar />
@ -68,11 +135,14 @@ const UnifiedCanvasContent = () => {
alignItems: 'center',
justifyContent: 'center',
gap: 4,
width: '100%',
height: '100%',
w: 'full',
h: 'full',
}}
>
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
<Box sx={{ w: 'full', h: 'full', position: 'relative' }}>
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
{active && <IAIDropOverlay isOver={isOver} />}
</Box>
</Flex>
</Flex>
</Box>

@ -1,34 +1,16 @@
import { Flex } from '@chakra-ui/react';
import { memo } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { useAppSelector } from 'app/store/storeHooks';
import UnifiedCanvasContent from './UnifiedCanvasContent';
import UnifiedCanvasParameters from './UnifiedCanvasParameters';
import UnifiedCanvasContentBeta from './UnifiedCanvasBeta/UnifiedCanvasContentBeta';
import ParametersPinnedWrapper from '../../ParametersPinnedWrapper';
const selector = createSelector(uiSelector, (ui) => {
const { shouldUseCanvasBetaLayout } = ui;
return {
shouldUseCanvasBetaLayout,
};
});
const UnifiedCanvasTab = () => {
const { shouldUseCanvasBetaLayout } = useAppSelector(selector);
return (
<Flex sx={{ gap: 4, w: 'full', h: 'full' }}>
<ParametersPinnedWrapper>
<UnifiedCanvasParameters />
</ParametersPinnedWrapper>
{shouldUseCanvasBetaLayout ? (
<UnifiedCanvasContentBeta />
) : (
<UnifiedCanvasContent />
)}
<UnifiedCanvasContent />
</Flex>
);
};