feat: Add Lock Ratio Option

This commit is contained in:
blessedcoolant 2023-08-30 07:04:08 +12:00
parent 2469859c01
commit 171a0eaf51
5 changed files with 114 additions and 11 deletions

View File

@ -714,7 +714,8 @@
"ui": {
"showProgressImages": "Show Progress Images",
"hideProgressImages": "Hide Progress Images",
"swapSizes": "Swap Sizes"
"swapSizes": "Swap Sizes",
"lockRatio": "Lock Ratio"
},
"nodes": {
"reloadNodeTemplates": "Reload Node Templates",

View File

@ -1,17 +1,50 @@
import { Flex, Spacer, Text } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { flipBoundingBoxAxes } from 'features/canvas/store/canvasSlice';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import {
setAspectRatio,
setShouldLockAspectRatio,
} from 'features/parameters/store/generationSlice';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FaLock } from 'react-icons/fa';
import { MdOutlineSwapVert } from 'react-icons/md';
import ParamAspectRatio from '../../Core/ParamAspectRatio';
import ParamBoundingBoxHeight from './ParamBoundingBoxHeight';
import ParamBoundingBoxWidth from './ParamBoundingBoxWidth';
const sizeOptsSelector = createSelector(
[generationSelector, canvasSelector],
(generation, canvas) => {
const { shouldFitToWidthHeight, shouldLockAspectRatio } = generation;
const { boundingBoxDimensions } = canvas;
return {
shouldFitToWidthHeight,
shouldLockAspectRatio,
boundingBoxDimensions,
};
}
);
export default function ParamBoundingBoxSize() {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const { shouldLockAspectRatio, boundingBoxDimensions } =
useAppSelector(sizeOptsSelector);
const handleLockRatio = useCallback(() => {
dispatch(
setAspectRatio(boundingBoxDimensions.width / boundingBoxDimensions.height)
);
dispatch(setShouldLockAspectRatio(!shouldLockAspectRatio));
}, [shouldLockAspectRatio, boundingBoxDimensions, dispatch]);
return (
<Flex
sx={{
@ -49,6 +82,14 @@ export default function ParamBoundingBoxSize() {
fontSize={20}
onClick={() => dispatch(flipBoundingBoxAxes())}
/>
<IAIIconButton
tooltip={t('ui.lockRatio')}
aria-label={t('ui.lockRatio')}
size="sm"
icon={<FaLock />}
isChecked={shouldLockAspectRatio}
onClick={handleLockRatio}
/>
</Flex>
<ParamBoundingBoxWidth />
<ParamBoundingBoxHeight />

View File

@ -2,7 +2,10 @@ import { ButtonGroup, Flex } from '@chakra-ui/react';
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIButton from 'common/components/IAIButton';
import { setAspectRatio } from 'features/parameters/store/generationSlice';
import {
setAspectRatio,
setShouldLockAspectRatio,
} from 'features/parameters/store/generationSlice';
import { activeTabNameSelector } from '../../../../ui/store/uiSelectors';
const aspectRatios = [
@ -34,7 +37,10 @@ export default function ParamAspectRatio() {
isDisabled={
activeTabName === 'img2img' ? !shouldFitToWidthHeight : false
}
onClick={() => dispatch(setAspectRatio(ratio.value))}
onClick={() => {
dispatch(setAspectRatio(ratio.value));
dispatch(setShouldLockAspectRatio(false));
}}
>
{ratio.name}
</IAIButton>

View File

@ -1,22 +1,54 @@
import { Flex, Spacer, Text } from '@chakra-ui/react';
import { RootState } from 'app/store/store';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton';
import { toggleSize } from 'features/parameters/store/generationSlice';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import {
setAspectRatio,
setShouldLockAspectRatio,
toggleSize,
} from 'features/parameters/store/generationSlice';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FaLock } from 'react-icons/fa';
import { MdOutlineSwapVert } from 'react-icons/md';
import { activeTabNameSelector } from '../../../../ui/store/uiSelectors';
import ParamAspectRatio from './ParamAspectRatio';
import ParamHeight from './ParamHeight';
import ParamWidth from './ParamWidth';
import { activeTabNameSelector } from '../../../../ui/store/uiSelectors';
const sizeOptsSelector = createSelector(
[generationSelector, activeTabNameSelector],
(generation, activeTabName) => {
const { shouldFitToWidthHeight, shouldLockAspectRatio, width, height } =
generation;
return {
activeTabName,
shouldFitToWidthHeight,
shouldLockAspectRatio,
width,
height,
};
}
);
export default function ParamSize() {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const shouldFitToWidthHeight = useAppSelector(
(state: RootState) => state.generation.shouldFitToWidthHeight
);
const activeTabName = useAppSelector(activeTabNameSelector);
const {
activeTabName,
shouldFitToWidthHeight,
shouldLockAspectRatio,
width,
height,
} = useAppSelector(sizeOptsSelector);
const handleLockRatio = useCallback(() => {
dispatch(setAspectRatio(width / height));
dispatch(setShouldLockAspectRatio(!shouldLockAspectRatio));
}, [shouldLockAspectRatio, width, height, dispatch]);
return (
<Flex
sx={{
@ -57,6 +89,17 @@ export default function ParamSize() {
}
onClick={() => dispatch(toggleSize())}
/>
<IAIIconButton
tooltip={t('ui.lockRatio')}
aria-label={t('ui.lockRatio')}
size="sm"
icon={<FaLock />}
isChecked={shouldLockAspectRatio}
isDisabled={
activeTabName === 'img2img' ? !shouldFitToWidthHeight : false
}
onClick={handleLockRatio}
/>
</Flex>
<Flex gap={2} alignItems="center">
<Flex gap={2} flexDirection="column" width="full">

View File

@ -62,6 +62,7 @@ export interface GenerationState {
shouldUseCpuNoise: boolean;
shouldShowAdvancedOptions: boolean;
aspectRatio: number | null;
shouldLockAspectRatio: boolean;
}
export const initialGenerationState: GenerationState = {
@ -101,6 +102,7 @@ export const initialGenerationState: GenerationState = {
shouldUseCpuNoise: true,
shouldShowAdvancedOptions: false,
aspectRatio: null,
shouldLockAspectRatio: false,
};
const initialState: GenerationState = initialGenerationState;
@ -272,6 +274,15 @@ export const generationSlice = createSlice({
state.height = roundToMultiple(state.width / newAspectRatio, 8);
}
},
setShouldLockAspectRatio: (state, action: PayloadAction<boolean>) => {
if (
action.payload === false &&
![null, 2 / 3, 16 / 9, 1 / 1].includes(state.aspectRatio)
) {
state.aspectRatio = null;
}
state.shouldLockAspectRatio = action.payload;
},
},
extraReducers: (builder) => {
builder.addCase(configChanged, (state, action) => {
@ -342,6 +353,7 @@ export const {
shouldUseCpuNoiseChanged,
setShouldShowAdvancedOptions,
setAspectRatio,
setShouldLockAspectRatio,
vaePrecisionChanged,
} = generationSlice.actions;