mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix(ui): restore OG aspect ratio preview for non-t2i tabs
This commit is contained in:
parent
260e24733f
commit
ca989c54b0
@ -51,6 +51,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@chakra-ui/react-use-size": "^2.1.0",
|
||||
"@dagrejs/dagre": "^1.1.1",
|
||||
"@dagrejs/graphlib": "^2.2.1",
|
||||
"@dnd-kit/core": "^6.1.0",
|
||||
|
@ -8,6 +8,9 @@ dependencies:
|
||||
'@chakra-ui/react':
|
||||
specifier: ^2.8.2
|
||||
version: 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.59)(framer-motion@11.0.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@chakra-ui/react-use-size':
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0(react@18.2.0)
|
||||
'@dagrejs/dagre':
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
|
@ -2,7 +2,7 @@ import { Flex } from '@invoke-ai/ui-library';
|
||||
import { StageComponent } from 'features/regionalPrompts/components/StageComponent';
|
||||
import { memo } from 'react';
|
||||
|
||||
export const AspectRatioPreview = memo(() => {
|
||||
export const AspectRatioCanvasPreview = memo(() => {
|
||||
return (
|
||||
<Flex w="full" h="full" alignItems="center" justifyContent="center" position="relative">
|
||||
<StageComponent asPreview />
|
||||
@ -10,4 +10,4 @@ export const AspectRatioPreview = memo(() => {
|
||||
);
|
||||
});
|
||||
|
||||
AspectRatioPreview.displayName = 'AspectRatioPreview';
|
||||
AspectRatioCanvasPreview.displayName = 'AspectRatioCanvasPreview';
|
@ -0,0 +1,75 @@
|
||||
import { useSize } from '@chakra-ui/react-use-size';
|
||||
import { Flex, Icon } from '@invoke-ai/ui-library';
|
||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { memo, useMemo, useRef } from 'react';
|
||||
import { PiFrameCorners } from 'react-icons/pi';
|
||||
|
||||
import {
|
||||
BOX_SIZE_CSS_CALC,
|
||||
ICON_CONTAINER_STYLES,
|
||||
ICON_HIGH_CUTOFF,
|
||||
ICON_LOW_CUTOFF,
|
||||
MOTION_ICON_ANIMATE,
|
||||
MOTION_ICON_EXIT,
|
||||
MOTION_ICON_INITIAL,
|
||||
} from './constants';
|
||||
|
||||
export const AspectRatioIconPreview = memo(() => {
|
||||
const ctx = useImageSizeContext();
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const containerSize = useSize(containerRef);
|
||||
|
||||
const shouldShowIcon = useMemo(
|
||||
() => ctx.aspectRatioState.value < ICON_HIGH_CUTOFF && ctx.aspectRatioState.value > ICON_LOW_CUTOFF,
|
||||
[ctx.aspectRatioState.value]
|
||||
);
|
||||
|
||||
const { width, height } = useMemo(() => {
|
||||
if (!containerSize) {
|
||||
return { width: 0, height: 0 };
|
||||
}
|
||||
|
||||
let width = ctx.width;
|
||||
let height = ctx.height;
|
||||
|
||||
if (ctx.width > ctx.height) {
|
||||
width = containerSize.width;
|
||||
height = width / ctx.aspectRatioState.value;
|
||||
} else {
|
||||
height = containerSize.height;
|
||||
width = height * ctx.aspectRatioState.value;
|
||||
}
|
||||
|
||||
return { width, height };
|
||||
}, [containerSize, ctx.width, ctx.height, ctx.aspectRatioState.value]);
|
||||
|
||||
return (
|
||||
<Flex w="full" h="full" alignItems="center" justifyContent="center" ref={containerRef}>
|
||||
<Flex
|
||||
bg="blackAlpha.400"
|
||||
borderRadius="base"
|
||||
width={`${width}px`}
|
||||
height={`${height}px`}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<AnimatePresence>
|
||||
{shouldShowIcon && (
|
||||
<Flex
|
||||
as={motion.div}
|
||||
initial={MOTION_ICON_INITIAL}
|
||||
animate={MOTION_ICON_ANIMATE}
|
||||
exit={MOTION_ICON_EXIT}
|
||||
style={ICON_CONTAINER_STYLES}
|
||||
>
|
||||
<Icon as={PiFrameCorners} color="base.700" boxSize={BOX_SIZE_CSS_CALC} />
|
||||
</Flex>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
|
||||
AspectRatioIconPreview.displayName = 'AspectRatioIconPreview';
|
@ -1,6 +1,5 @@
|
||||
import type { FormLabelProps } from '@invoke-ai/ui-library';
|
||||
import { Flex, FormControlGroup } from '@invoke-ai/ui-library';
|
||||
import { AspectRatioPreview } from 'features/parameters/components/ImageSize/AspectRatioPreview';
|
||||
import { AspectRatioSelect } from 'features/parameters/components/ImageSize/AspectRatioSelect';
|
||||
import type { ImageSizeContextInnerValue } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||
import { ImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||
@ -13,10 +12,11 @@ import { memo } from 'react';
|
||||
type ImageSizeProps = ImageSizeContextInnerValue & {
|
||||
widthComponent: ReactNode;
|
||||
heightComponent: ReactNode;
|
||||
previewComponent: ReactNode;
|
||||
};
|
||||
|
||||
export const ImageSize = memo((props: ImageSizeProps) => {
|
||||
const { widthComponent, heightComponent, ...ctx } = props;
|
||||
const { widthComponent, heightComponent, previewComponent, ...ctx } = props;
|
||||
return (
|
||||
<ImageSizeContext.Provider value={ctx}>
|
||||
<Flex gap={4} alignItems="center">
|
||||
@ -33,7 +33,7 @@ export const ImageSize = memo((props: ImageSizeProps) => {
|
||||
</FormControlGroup>
|
||||
</Flex>
|
||||
<Flex w="108px" h="108px" flexShrink={0} flexGrow={0}>
|
||||
<AspectRatioPreview />
|
||||
{previewComponent}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</ImageSizeContext.Provider>
|
||||
|
@ -1,7 +1,29 @@
|
||||
import type { ComboboxOption } from '@invoke-ai/ui-library';
|
||||
|
||||
import type { AspectRatioID, AspectRatioState } from './types';
|
||||
|
||||
// When the aspect ratio is between these two values, we show the icon (experimentally determined)
|
||||
export const ICON_LOW_CUTOFF = 0.23;
|
||||
export const ICON_HIGH_CUTOFF = 1 / ICON_LOW_CUTOFF;
|
||||
export const ICON_SIZE_PX = 64;
|
||||
export const ICON_PADDING_PX = 16;
|
||||
export const BOX_SIZE_CSS_CALC = `min(${ICON_SIZE_PX}px, calc(100% - ${ICON_PADDING_PX}px))`;
|
||||
export const MOTION_ICON_INITIAL = {
|
||||
opacity: 0,
|
||||
};
|
||||
export const MOTION_ICON_ANIMATE = {
|
||||
opacity: 1,
|
||||
transition: { duration: 0.1 },
|
||||
};
|
||||
export const MOTION_ICON_EXIT = {
|
||||
opacity: 0,
|
||||
transition: { duration: 0.1 },
|
||||
};
|
||||
export const ICON_CONTAINER_STYLES = {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
};
|
||||
export const ASPECT_RATIO_OPTIONS: ComboboxOption[] = [
|
||||
{ label: 'Free' as const, value: 'Free' },
|
||||
{ label: '16:9' as const, value: '16:9' },
|
||||
|
@ -2,6 +2,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { aspectRatioChanged, setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||
import ParamBoundingBoxHeight from 'features/parameters/components/Canvas/BoundingBox/ParamBoundingBoxHeight';
|
||||
import ParamBoundingBoxWidth from 'features/parameters/components/Canvas/BoundingBox/ParamBoundingBoxWidth';
|
||||
import { AspectRatioIconPreview } from 'features/parameters/components/ImageSize/AspectRatioIconPreview';
|
||||
import { ImageSize } from 'features/parameters/components/ImageSize/ImageSize';
|
||||
import type { AspectRatioState } from 'features/parameters/components/ImageSize/types';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
@ -41,6 +42,7 @@ export const ImageSizeCanvas = memo(() => {
|
||||
aspectRatioState={aspectRatioState}
|
||||
heightComponent={<ParamBoundingBoxHeight />}
|
||||
widthComponent={<ParamBoundingBoxWidth />}
|
||||
previewComponent={<AspectRatioIconPreview />}
|
||||
onChangeAspectRatioState={onChangeAspectRatioState}
|
||||
onChangeWidth={onChangeWidth}
|
||||
onChangeHeight={onChangeHeight}
|
||||
|
@ -1,13 +1,17 @@
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { ParamHeight } from 'features/parameters/components/Core/ParamHeight';
|
||||
import { ParamWidth } from 'features/parameters/components/Core/ParamWidth';
|
||||
import { AspectRatioCanvasPreview } from 'features/parameters/components/ImageSize/AspectRatioCanvasPreview';
|
||||
import { AspectRatioIconPreview } from 'features/parameters/components/ImageSize/AspectRatioIconPreview';
|
||||
import { ImageSize } from 'features/parameters/components/ImageSize/ImageSize';
|
||||
import type { AspectRatioState } from 'features/parameters/components/ImageSize/types';
|
||||
import { aspectRatioChanged, heightChanged, widthChanged } from 'features/parameters/store/generationSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { memo, useCallback } from 'react';
|
||||
|
||||
export const ImageSizeLinear = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const tab = useAppSelector(activeTabNameSelector);
|
||||
const width = useAppSelector((s) => s.generation.width);
|
||||
const height = useAppSelector((s) => s.generation.height);
|
||||
const aspectRatioState = useAppSelector((s) => s.generation.aspectRatio);
|
||||
@ -40,6 +44,7 @@ export const ImageSizeLinear = memo(() => {
|
||||
aspectRatioState={aspectRatioState}
|
||||
heightComponent={<ParamHeight />}
|
||||
widthComponent={<ParamWidth />}
|
||||
previewComponent={tab === 'txt2img' ? <AspectRatioCanvasPreview /> : <AspectRatioIconPreview />}
|
||||
onChangeAspectRatioState={onChangeAspectRatioState}
|
||||
onChangeWidth={onChangeWidth}
|
||||
onChangeHeight={onChangeHeight}
|
||||
|
Loading…
Reference in New Issue
Block a user