feat(ui): restore aspect ratio preview component

This commit is contained in:
psychedelicious
2024-09-06 17:45:12 +10:00
parent 63a2b6cdfe
commit 8cb1584379
21 changed files with 153 additions and 88 deletions

View File

@@ -13,7 +13,7 @@ import { loraDeleted } from 'features/controlLayers/store/lorasSlice';
import { modelChanged, refinerModelChanged, vaeSelected } from 'features/controlLayers/store/paramsSlice';
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import { getEntityIdentifier } from 'features/controlLayers/store/types';
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
import { calculateNewSize } from 'features/parameters/components/Bbox/calculateNewSize';
import { postProcessingModelChanged, upscaleModelChanged } from 'features/parameters/store/upscaleSlice';
import { zParameterModel, zParameterVAEModel } from 'features/parameters/types/parameterSchemas';
import { getIsSizeOptimal, getOptimalDimension } from 'features/parameters/util/optimalDimension';

View File

@@ -9,7 +9,7 @@ import { bboxHeightChanged, bboxWidthChanged } from 'features/controlLayers/stor
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
import type { ImageWithDims } from 'features/controlLayers/store/types';
import type { ImageDraggableData, TypesafeDroppableData } from 'features/dnd/types';
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
import { calculateNewSize } from 'features/parameters/components/Bbox/calculateNewSize';
import { memo, useCallback, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiArrowCounterClockwiseBold, PiRulerBold } from 'react-icons/pi';

View File

@@ -21,9 +21,9 @@ import type {
import { getScaledBoundingBoxDimensions } from 'features/controlLayers/util/getScaledBoundingBoxDimensions';
import { simplifyFlatNumbersArray } from 'features/controlLayers/util/simplify';
import { zModelIdentifierField } from 'features/nodes/types/common';
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
import { ASPECT_RATIO_MAP, initialAspectRatioState } from 'features/parameters/components/DocumentSize/constants';
import type { AspectRatioID } from 'features/parameters/components/DocumentSize/types';
import { calculateNewSize } from 'features/parameters/components/Bbox/calculateNewSize';
import { ASPECT_RATIO_MAP, initialAspectRatioState } from 'features/parameters/components/Bbox/constants';
import type { AspectRatioID } from 'features/parameters/components/Bbox/types';
import { getIsSizeOptimal, getOptimalDimension } from 'features/parameters/util/optimalDimension';
import type { IRect } from 'konva/lib/types';
import { isEqual, merge, omit } from 'lodash-es';

View File

@@ -230,3 +230,8 @@ export const getIsHiddenSelector = (type: CanvasEntityType) => {
assert(false, 'Unhandled entity type');
}
};
export const selectWidth = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect.width);
export const selectHeight = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect.height);
export const selectAspectRatioID = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.aspectRatio.id);
export const selectAspectRatioValue = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.aspectRatio.value);

View File

@@ -1,7 +1,7 @@
import type { SerializableObject } from 'common/types';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import { zModelIdentifierField } from 'features/nodes/types/common';
import type { AspectRatioState } from 'features/parameters/components/DocumentSize/types';
import type { AspectRatioState } from 'features/parameters/components/Bbox/types';
import type { ParameterHeight, ParameterLoRAModel, ParameterWidth } from 'features/parameters/types/parameterSchemas';
import { zParameterNegativePrompt, zParameterPositivePrompt } from 'features/parameters/types/parameterSchemas';
import type { AnyInvocation, BaseModelType, ImageDTO, S } from 'services/api/types';

View File

@@ -1,19 +1,16 @@
import type { ComboboxOption, SystemStyleObject } from '@invoke-ai/ui-library';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import type { SingleValue } from 'chakra-react-select';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { bboxAspectRatioIdChanged } from 'features/controlLayers/store/canvasSlice';
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import { ASPECT_RATIO_OPTIONS } from 'features/parameters/components/DocumentSize/constants';
import { isAspectRatioID } from 'features/parameters/components/DocumentSize/types';
import { selectAspectRatioID } from 'features/controlLayers/store/selectors';
import { ASPECT_RATIO_OPTIONS } from 'features/parameters/components/Bbox/constants';
import { isAspectRatioID } from 'features/parameters/components/Bbox/types';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const selectAspectRatioID = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.aspectRatio.id);
export const AspectRatioSelect = memo(() => {
export const BboxAspectRatioSelect = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const id = useAppSelector(selectAspectRatioID);
@@ -40,6 +37,6 @@ export const AspectRatioSelect = memo(() => {
);
});
AspectRatioSelect.displayName = 'AspectRatioSelect';
BboxAspectRatioSelect.displayName = 'BboxAspectRatioSelect';
const selectStyles: SystemStyleObject = { minW: 24 };

View File

@@ -1,17 +1,13 @@
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { bboxHeightChanged } from 'features/controlLayers/store/canvasSlice';
import { selectCanvasSlice, selectOptimalDimension } from 'features/controlLayers/store/selectors';
import { selectConfigSlice } from 'features/system/store/configSlice';
import { selectHeight, selectOptimalDimension } from 'features/controlLayers/store/selectors';
import { selectHeightConfig } from 'features/system/store/configSlice';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const selectHeight = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect.height);
const selectHeightConfig = createSelector(selectConfigSlice, (config) => config.sd.height);
export const ParamHeight = memo(() => {
export const BboxHeight = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const optimalDimension = useAppSelector(selectOptimalDimension);
@@ -58,4 +54,4 @@ export const ParamHeight = memo(() => {
);
});
ParamHeight.displayName = 'ParamHeight';
BboxHeight.displayName = 'BboxHeight';

View File

@@ -9,7 +9,7 @@ import { PiLockSimpleFill, PiLockSimpleOpenBold } from 'react-icons/pi';
const selectAspectRatioIsLocked = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.aspectRatio.isLocked);
export const LockAspectRatioButton = memo(() => {
export const BboxLockAspectRatioButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isLocked = useAppSelector(selectAspectRatioIsLocked);
@@ -29,4 +29,4 @@ export const LockAspectRatioButton = memo(() => {
);
});
LockAspectRatioButton.displayName = 'LockAspectRatioButton';
BboxLockAspectRatioButton.displayName = 'BboxLockAspectRatioButton';

View File

@@ -0,0 +1,71 @@
import { Flex, Grid, GridItem } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { selectAspectRatioValue, selectHeight, selectWidth } from 'features/controlLayers/store/selectors';
import { memo, useMemo } from 'react';
import { useMeasure } from 'react-use';
export const BboxPreview = memo(() => {
const bboxWidth = useAppSelector(selectWidth);
const bboxHeight = useAppSelector(selectHeight);
const aspectRatioValue = useAppSelector(selectAspectRatioValue);
const [ref, dims] = useMeasure<HTMLDivElement>();
const previewBoxSize = useMemo(() => {
if (!dims) {
return { width: 0, height: 0 };
}
let width = bboxWidth;
let height = bboxHeight;
if (bboxWidth > bboxHeight) {
width = dims.width;
height = width / aspectRatioValue;
} else {
height = dims.height;
width = height * aspectRatioValue;
}
return { width, height };
}, [dims, bboxWidth, bboxHeight, aspectRatioValue]);
return (
<Flex w="full" h="full" alignItems="center" justifyContent="center" ref={ref}>
<Flex
position="relative"
borderRadius="base"
borderColor="base.600"
borderWidth="3px"
width={`${previewBoxSize.width}px`}
height={`${previewBoxSize.height}px`}
alignItems="center"
justifyContent="center"
>
<Grid
borderRadius="base"
position="absolute"
top={0}
right={0}
bottom={0}
left={0}
gridTemplateColumns="1fr 1fr 1fr"
gridTemplateRows="1fr 1fr 1fr"
gap="1px"
bg="base.700"
>
<GridItem bg="base.800" />
<GridItem bg="base.800" />
<GridItem bg="base.800" />
<GridItem bg="base.800" />
<GridItem bg="base.800" />
<GridItem bg="base.800" />
<GridItem bg="base.800" />
<GridItem bg="base.800" />
<GridItem bg="base.800" />
</Grid>
</Flex>
</Flex>
);
});
BboxPreview.displayName = 'BboxPreview';

View File

@@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
const selectScaleMethod = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.scaleMethod);
const ParamScaleBeforeProcessing = () => {
const BboxScaleMethod = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const scaleMethod = useAppSelector(selectScaleMethod);
@@ -47,4 +47,4 @@ const ParamScaleBeforeProcessing = () => {
);
};
export default memo(ParamScaleBeforeProcessing);
export default memo(BboxScaleMethod);

View File

@@ -14,7 +14,7 @@ const selectScaledBoundingBoxHeightConfig = createSelector(
(config) => config.sd.scaledBoundingBoxHeight
);
const ParamScaledHeight = () => {
const BboxScaledHeight = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const optimalDimension = useAppSelector(selectOptimalDimension);
@@ -55,4 +55,4 @@ const ParamScaledHeight = () => {
);
};
export default memo(ParamScaledHeight);
export default memo(BboxScaledHeight);

View File

@@ -14,7 +14,7 @@ const selectScaledBoundingBoxWidthConfig = createSelector(
(config) => config.sd.scaledBoundingBoxWidth
);
const ParamScaledWidth = () => {
const BboxScaledWidth = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const optimalDimension = useAppSelector(selectOptimalDimension);
@@ -54,4 +54,4 @@ const ParamScaledWidth = () => {
);
};
export default memo(ParamScaledWidth);
export default memo(BboxScaledWidth);

View File

@@ -11,7 +11,7 @@ import { RiSparklingFill } from 'react-icons/ri';
const selectWidth = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect.width);
const selectHeight = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect.height);
export const SetOptimalSizeButton = memo(() => {
export const BboxSetOptimalSizeButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const width = useAppSelector(selectWidth);
@@ -51,4 +51,4 @@ export const SetOptimalSizeButton = memo(() => {
);
});
SetOptimalSizeButton.displayName = 'SetOptimalSizeButton';
BboxSetOptimalSizeButton.displayName = 'BboxSetOptimalSizeButton';

View File

@@ -0,0 +1,38 @@
import type { FormLabelProps } from '@invoke-ai/ui-library';
import { Flex, FormControlGroup } from '@invoke-ai/ui-library';
import { BboxAspectRatioSelect } from 'features/parameters/components/Bbox/BboxAspectRatioSelect';
import { BboxHeight } from 'features/parameters/components/Bbox/BboxHeight';
import { BboxLockAspectRatioButton } from 'features/parameters/components/Bbox/BboxLockAspectRatioButton';
import { BboxPreview } from 'features/parameters/components/Bbox/BboxPreview';
import { BboxSetOptimalSizeButton } from 'features/parameters/components/Bbox/BboxSetOptimalSizeButton';
import { BboxSwapDimensionsButton } from 'features/parameters/components/Bbox/BboxSwapDimensionsButton';
import { BboxWidth } from 'features/parameters/components/Bbox/BboxWidth';
import { memo } from 'react';
export const BboxSettings = memo(() => {
return (
<Flex gap={4} alignItems="center">
<Flex gap={4} flexDirection="column" width="full">
<FormControlGroup formLabelProps={formLabelProps}>
<Flex gap={4}>
<BboxAspectRatioSelect />
<BboxSwapDimensionsButton />
<BboxLockAspectRatioButton />
<BboxSetOptimalSizeButton />
</Flex>
<BboxWidth />
<BboxHeight />
</FormControlGroup>
</Flex>
<Flex w="108px" h="108px" flexShrink={0} flexGrow={0} alignItems="center" justifyContent="center">
<BboxPreview />
</Flex>
</Flex>
);
});
BboxSettings.displayName = 'BboxSettings';
const formLabelProps: FormLabelProps = {
minW: 14,
};

View File

@@ -5,7 +5,7 @@ import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiArrowsDownUpBold } from 'react-icons/pi';
export const SwapDimensionsButton = memo(() => {
export const BboxSwapDimensionsButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const onClick = useCallback(() => {
@@ -23,4 +23,4 @@ export const SwapDimensionsButton = memo(() => {
);
});
SwapDimensionsButton.displayName = 'SwapDimensionsButton';
BboxSwapDimensionsButton.displayName = 'BboxSwapDimensionsButton';

View File

@@ -1,17 +1,13 @@
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { bboxWidthChanged } from 'features/controlLayers/store/canvasSlice';
import { selectCanvasSlice, selectOptimalDimension } from 'features/controlLayers/store/selectors';
import { selectConfigSlice } from 'features/system/store/configSlice';
import { selectOptimalDimension, selectWidth } from 'features/controlLayers/store/selectors';
import { selectWidthConfig } from 'features/system/store/configSlice';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const selectWidth = createSelector(selectCanvasSlice, (canvas) => canvas.bbox.rect.width);
const selectWidthConfig = createSelector(selectConfigSlice, (config) => config.sd.width);
export const ParamWidth = memo(() => {
export const BboxWidth = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const width = useAppSelector(selectWidth);
@@ -58,4 +54,4 @@ export const ParamWidth = memo(() => {
);
});
ParamWidth.displayName = 'ParamWidth';
BboxWidth.displayName = 'BboxWidth';

View File

@@ -1,38 +0,0 @@
import type { FormLabelProps } from '@invoke-ai/ui-library';
import { Flex, FormControlGroup } from '@invoke-ai/ui-library';
import { CanvasResizer } from 'features/controlLayers/components/CanvasResizer';
import { ParamHeight } from 'features/parameters/components/Core/ParamHeight';
import { ParamWidth } from 'features/parameters/components/Core/ParamWidth';
import { AspectRatioSelect } from 'features/parameters/components/DocumentSize/AspectRatioSelect';
import { LockAspectRatioButton } from 'features/parameters/components/DocumentSize/LockAspectRatioButton';
import { SetOptimalSizeButton } from 'features/parameters/components/DocumentSize/SetOptimalSizeButton';
import { SwapDimensionsButton } from 'features/parameters/components/DocumentSize/SwapDimensionsButton';
import { memo } from 'react';
export const DocumentSize = memo(() => {
return (
<Flex gap={4} alignItems="center">
<Flex gap={4} flexDirection="column" width="full">
<FormControlGroup formLabelProps={formLabelProps}>
<Flex gap={4}>
<AspectRatioSelect />
<SwapDimensionsButton />
<LockAspectRatioButton />
<SetOptimalSizeButton />
</Flex>
<ParamWidth />
<ParamHeight />
</FormControlGroup>
</Flex>
<Flex w="108px" h="108px" flexShrink={0} flexGrow={0} bg="base.850" alignItems="center" justifyContent="center">
<CanvasResizer />
</Flex>
</Flex>
);
});
DocumentSize.displayName = 'DocumentSize';
const formLabelProps: FormLabelProps = {
minW: 14,
};

View File

@@ -6,11 +6,11 @@ import { selectParamsSlice } from 'features/controlLayers/store/paramsSlice';
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import { HrfSettings } from 'features/hrf/components/HrfSettings';
import { selectHrfSlice } from 'features/hrf/store/hrfSlice';
import ParamScaleBeforeProcessing from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaleBeforeProcessing';
import ParamScaledHeight from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaledHeight';
import ParamScaledWidth from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaledWidth';
import BboxScaledHeight from 'features/parameters/components/Bbox/BboxScaledHeight';
import BboxScaledWidth from 'features/parameters/components/Bbox/BboxScaledWidth';
import BboxScaleMethod from 'features/parameters/components/Bbox/BboxScaleMethod';
import { BboxSettings } from 'features/parameters/components/Bbox/BboxSettings';
import ParamImageToImageStrength from 'features/parameters/components/Canvas/ParamImageToImageStrength';
import { DocumentSize } from 'features/parameters/components/DocumentSize/DocumentSize';
import { ParamSeedNumberInput } from 'features/parameters/components/Seed/ParamSeedNumberInput';
import { ParamSeedRandomize } from 'features/parameters/components/Seed/ParamSeedRandomize';
import { ParamSeedShuffle } from 'features/parameters/components/Seed/ParamSeedShuffle';
@@ -73,7 +73,7 @@ export const ImageSettingsAccordion = memo(() => {
>
<Flex px={4} pt={4} w="full" h="full" flexDir="column" data-testid="image-settings-accordion">
<Flex flexDir="column" gap={4}>
<DocumentSize />
<BboxSettings />
<ParamImageToImageStrength />
</Flex>
<Expander label={t('accordions.advanced.options')} isOpen={isOpenExpander} onToggle={onToggleExpander}>
@@ -84,10 +84,10 @@ export const ImageSettingsAccordion = memo(() => {
<ParamSeedRandomize />
</Flex>
{!isSDXL && <HrfSettings />}
<ParamScaleBeforeProcessing />
<BboxScaleMethod />
<FormControlGroup formLabelProps={scalingLabelProps}>
<ParamScaledWidth />
<ParamScaledHeight />
<BboxScaledWidth />
<BboxScaledHeight />
</FormControlGroup>
</Flex>
</Expander>