[Code Splitting] Bounding Box Options

Isolated all bounding box components to trigger unnecessary re-renders. Still need to fix  bounding box  triggering re-renders on the control panel inside the canvas itself. But the options panel should be a good to go with this change.
This commit is contained in:
blessedcoolant 2022-11-02 07:40:31 +13:00 committed by Lincoln Stein
parent 2e562742c1
commit 868e4b2db8
12 changed files with 282 additions and 255 deletions

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>InvokeAI - A Stable Diffusion Toolkit</title> <title>InvokeAI - A Stable Diffusion Toolkit</title>
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" /> <link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
<script type="module" crossorigin src="./assets/index.f51a2644.js"></script> <script type="module" crossorigin src="./assets/index.9ad2f384.js"></script>
<link rel="stylesheet" href="./assets/index.14c578ee.css"> <link rel="stylesheet" href="./assets/index.14c578ee.css">
</head> </head>

View File

@ -1,209 +0,0 @@
import { Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import _ from 'lodash';
import { BiHide, BiReset, BiShow } from 'react-icons/bi';
import {
RootState,
useAppDispatch,
useAppSelector,
} from '../../../../app/store';
import IAICheckbox from '../../../../common/components/IAICheckbox';
import IAIIconButton from '../../../../common/components/IAIIconButton';
import IAINumberInput from '../../../../common/components/IAINumberInput';
import IAISlider from '../../../../common/components/IAISlider';
import { roundDownToMultiple } from '../../../../common/util/roundDownToMultiple';
import {
InpaintingState,
setBoundingBoxDimensions,
setShouldLockBoundingBox,
setShouldShowBoundingBox,
setShouldShowBoundingBoxFill,
} from '../../../tabs/Inpainting/inpaintingSlice';
const boundingBoxDimensionsSelector = createSelector(
(state: RootState) => state.inpainting,
(inpainting: InpaintingState) => {
const {
canvasDimensions,
boundingBoxDimensions,
shouldShowBoundingBox,
shouldShowBoundingBoxFill,
shouldLockBoundingBox,
} = inpainting;
return {
canvasDimensions,
boundingBoxDimensions,
shouldShowBoundingBox,
shouldShowBoundingBoxFill,
shouldLockBoundingBox,
};
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
},
}
);
const BoundingBoxSettings = () => {
const dispatch = useAppDispatch();
const {
canvasDimensions,
boundingBoxDimensions,
shouldShowBoundingBox,
shouldShowBoundingBoxFill,
shouldLockBoundingBox,
} = useAppSelector(boundingBoxDimensionsSelector);
const handleChangeBoundingBoxWidth = (v: number) => {
dispatch(
setBoundingBoxDimensions({
...boundingBoxDimensions,
width: Math.floor(v),
})
);
};
const handleChangeBoundingBoxHeight = (v: number) => {
dispatch(
setBoundingBoxDimensions({
...boundingBoxDimensions,
height: Math.floor(v),
})
);
};
const handleChangeShouldShowBoundingBoxFill = () => {
dispatch(setShouldShowBoundingBoxFill(!shouldShowBoundingBoxFill));
};
const handleChangeShouldLockBoundingBox = () => {
dispatch(setShouldLockBoundingBox(!shouldLockBoundingBox));
};
const handleResetWidth = () => {
dispatch(
setBoundingBoxDimensions({
...boundingBoxDimensions,
width: Math.floor(canvasDimensions.width),
})
);
};
const handleResetHeight = () => {
dispatch(
setBoundingBoxDimensions({
...boundingBoxDimensions,
height: Math.floor(canvasDimensions.height),
})
);
};
const handleShowBoundingBox = () =>
dispatch(setShouldShowBoundingBox(!shouldShowBoundingBox));
return (
<div className="inpainting-bounding-box-settings">
<div className="inpainting-bounding-box-header">
<p>Inpaint Box</p>
<IAIIconButton
aria-label="Toggle Bounding Box Visibility"
icon={
shouldShowBoundingBox ? <BiShow size={22} /> : <BiHide size={22} />
}
onClick={handleShowBoundingBox}
background={'none'}
padding={0}
/>
</div>
<div className="inpainting-bounding-box-settings-items">
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
<IAISlider
isDisabled={shouldLockBoundingBox}
label="Box W"
min={64}
max={roundDownToMultiple(canvasDimensions.width, 64)}
step={64}
value={boundingBoxDimensions.width}
onChange={handleChangeBoundingBoxWidth}
width={'5rem'}
/>
<IAINumberInput
isDisabled={shouldLockBoundingBox}
value={boundingBoxDimensions.width}
onChange={handleChangeBoundingBoxWidth}
min={64}
max={roundDownToMultiple(canvasDimensions.width, 64)}
step={64}
width={'5rem'}
/>
<IAIIconButton
size={'sm'}
aria-label={'Reset Width'}
tooltip={'Reset Width'}
onClick={handleResetWidth}
icon={<BiReset />}
styleClass="inpainting-bounding-box-reset-icon-btn"
isDisabled={
shouldLockBoundingBox ||
canvasDimensions.width === boundingBoxDimensions.width
}
/>
</div>
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
<IAISlider
isDisabled={shouldLockBoundingBox}
label="Box H"
min={64}
max={roundDownToMultiple(canvasDimensions.height, 64)}
step={64}
value={boundingBoxDimensions.height}
onChange={handleChangeBoundingBoxHeight}
width={'5rem'}
/>
<IAINumberInput
isDisabled={shouldLockBoundingBox}
value={boundingBoxDimensions.height}
onChange={handleChangeBoundingBoxHeight}
min={64}
max={roundDownToMultiple(canvasDimensions.height, 64)}
step={64}
padding="0"
width={'5rem'}
/>
<IAIIconButton
size={'sm'}
aria-label={'Reset Height'}
tooltip={'Reset Height'}
onClick={handleResetHeight}
icon={<BiReset />}
styleClass="inpainting-bounding-box-reset-icon-btn"
isDisabled={
shouldLockBoundingBox ||
canvasDimensions.height === boundingBoxDimensions.height
}
/>
</div>
<Flex alignItems={'center'} justifyContent={'space-between'}>
<IAICheckbox
label="Darken Outside Box"
isChecked={shouldShowBoundingBoxFill}
onChange={handleChangeShouldShowBoundingBoxFill}
styleClass="inpainting-bounding-box-darken"
/>
<IAICheckbox
label="Lock Bounding Box"
isChecked={shouldLockBoundingBox}
onChange={handleChangeShouldLockBoundingBox}
styleClass="inpainting-bounding-box-darken"
/>
</Flex>
</div>
</div>
);
};
export default BoundingBoxSettings;

View File

@ -0,0 +1,28 @@
import React from 'react';
import {
RootState,
useAppDispatch,
useAppSelector,
} from '../../../../../app/store';
import IAICheckbox from '../../../../../common/components/IAICheckbox';
import { setShouldShowBoundingBoxFill } from '../../../../tabs/Inpainting/inpaintingSlice';
export default function BoundingBoxDarkenOutside() {
const dispatch = useAppDispatch();
const shouldShowBoundingBoxFill = useAppSelector(
(state: RootState) => state.inpainting.shouldShowBoundingBoxFill
);
const handleChangeShouldShowBoundingBoxFill = () => {
dispatch(setShouldShowBoundingBoxFill(!shouldShowBoundingBoxFill));
};
return (
<IAICheckbox
label="Darken Outside Box"
isChecked={shouldShowBoundingBoxFill}
onChange={handleChangeShouldShowBoundingBoxFill}
styleClass="inpainting-bounding-box-darken"
/>
);
}

View File

@ -0,0 +1,128 @@
import React from 'react';
import IAISlider from '../../../../../common/components/IAISlider';
import IAINumberInput from '../../../../../common/components/IAINumberInput';
import IAIIconButton from '../../../../../common/components/IAIIconButton';
import { BiReset } from 'react-icons/bi';
import {
RootState,
useAppDispatch,
useAppSelector,
} from '../../../../../app/store';
import { createSelector } from '@reduxjs/toolkit';
import {
InpaintingState,
setBoundingBoxDimensions,
} from '../../../../tabs/Inpainting/inpaintingSlice';
import { roundDownToMultiple } from '../../../../../common/util/roundDownToMultiple';
import _ from 'lodash';
const boundingBoxDimensionsSelector = createSelector(
(state: RootState) => state.inpainting,
(inpainting: InpaintingState) => {
const { canvasDimensions, boundingBoxDimensions, shouldLockBoundingBox } =
inpainting;
return {
canvasDimensions,
boundingBoxDimensions,
shouldLockBoundingBox,
};
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
},
}
);
type BoundingBoxDimensionSlidersType = {
dimension: 'width' | 'height';
};
export default function BoundingBoxDimensionSlider(
props: BoundingBoxDimensionSlidersType
) {
const { dimension } = props;
const dispatch = useAppDispatch();
const { shouldLockBoundingBox, canvasDimensions, boundingBoxDimensions } =
useAppSelector(boundingBoxDimensionsSelector);
const canvasDimension = canvasDimensions[dimension];
const boundingBoxDimension = boundingBoxDimensions[dimension];
const handleBoundingBoxDimension = (v: number) => {
if (dimension == 'width') {
dispatch(
setBoundingBoxDimensions({
...boundingBoxDimensions,
width: Math.floor(v),
})
);
}
if (dimension == 'height') {
dispatch(
setBoundingBoxDimensions({
...boundingBoxDimensions,
height: Math.floor(v),
})
);
}
};
const handleResetDimension = () => {
if (dimension == 'width') {
dispatch(
setBoundingBoxDimensions({
...boundingBoxDimensions,
width: Math.floor(canvasDimension),
})
);
}
if (dimension == 'height') {
dispatch(
setBoundingBoxDimensions({
...boundingBoxDimensions,
height: Math.floor(canvasDimension),
})
);
}
};
return (
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
<IAISlider
isDisabled={shouldLockBoundingBox}
label="Box H"
min={64}
max={roundDownToMultiple(canvasDimension, 64)}
step={64}
value={boundingBoxDimension}
onChange={handleBoundingBoxDimension}
width={'5rem'}
/>
<IAINumberInput
isDisabled={shouldLockBoundingBox}
value={boundingBoxDimension}
onChange={handleBoundingBoxDimension}
min={64}
max={roundDownToMultiple(canvasDimension, 64)}
step={64}
padding="0"
width={'5rem'}
/>
<IAIIconButton
size={'sm'}
aria-label={'Reset Height'}
tooltip={'Reset Height'}
onClick={handleResetDimension}
icon={<BiReset />}
styleClass="inpainting-bounding-box-reset-icon-btn"
isDisabled={
shouldLockBoundingBox || canvasDimension === boundingBoxDimension
}
/>
</div>
);
}

View File

@ -0,0 +1,27 @@
import React from 'react';
import {
RootState,
useAppDispatch,
useAppSelector,
} from '../../../../../app/store';
import IAICheckbox from '../../../../../common/components/IAICheckbox';
import { setShouldLockBoundingBox } from '../../../../tabs/Inpainting/inpaintingSlice';
export default function BoundingBoxLock() {
const shouldLockBoundingBox = useAppSelector(
(state: RootState) => state.inpainting.shouldLockBoundingBox
);
const dispatch = useAppDispatch();
const handleChangeShouldLockBoundingBox = () => {
dispatch(setShouldLockBoundingBox(!shouldLockBoundingBox));
};
return (
<IAICheckbox
label="Lock Bounding Box"
isChecked={shouldLockBoundingBox}
onChange={handleChangeShouldLockBoundingBox}
styleClass="inpainting-bounding-box-darken"
/>
);
}

View File

@ -0,0 +1,26 @@
import { Flex } from '@chakra-ui/react';
import BoundingBoxDarkenOutside from './BoundingBoxDarkenOutside';
import BoundingBoxDimensionSlider from './BoundingBoxDimensionSlider';
import BoundingBoxLock from './BoundingBoxLock';
import BoundingBoxVisibility from './BoundingBoxVisibility';
const BoundingBoxSettings = () => {
return (
<div className="inpainting-bounding-box-settings">
<div className="inpainting-bounding-box-header">
<p>Inpaint Box</p>
<BoundingBoxVisibility />
</div>
<div className="inpainting-bounding-box-settings-items">
<BoundingBoxDimensionSlider dimension="width" />
<BoundingBoxDimensionSlider dimension="height" />
<Flex alignItems={'center'} justifyContent={'space-between'}>
<BoundingBoxDarkenOutside />
<BoundingBoxLock />
</Flex>
</div>
</div>
);
};
export default BoundingBoxSettings;

View File

@ -0,0 +1,28 @@
import React from 'react';
import { BiHide, BiShow } from 'react-icons/bi';
import {
RootState,
useAppDispatch,
useAppSelector,
} from '../../../../../app/store';
import IAIIconButton from '../../../../../common/components/IAIIconButton';
import { setShouldShowBoundingBox } from '../../../../tabs/Inpainting/inpaintingSlice';
export default function BoundingBoxVisibility() {
const shouldShowBoundingBox = useAppSelector(
(state: RootState) => state.inpainting.shouldShowBoundingBox
);
const dispatch = useAppDispatch();
const handleShowBoundingBox = () =>
dispatch(setShouldShowBoundingBox(!shouldShowBoundingBox));
return (
<IAIIconButton
aria-label="Toggle Bounding Box Visibility"
icon={shouldShowBoundingBox ? <BiShow size={22} /> : <BiHide size={22} />}
onClick={handleShowBoundingBox}
background={'none'}
padding={0}
/>
);
}

View File

@ -1,4 +1,4 @@
import BoundingBoxSettings from './BoundingBoxSettings'; import BoundingBoxSettings from './BoundingBoxSettings/BoundingBoxSettings';
import InpaintReplace from './InpaintReplace'; import InpaintReplace from './InpaintReplace';
import ClearBrushHistory from './ClearBrushHistory'; import ClearBrushHistory from './ClearBrushHistory';

View File

@ -170,7 +170,6 @@ const InvokeOptionsPanel = (props: Props) => {
</h1> </h1>
</div> </div>
)} )}
{children} {children}
</div> </div>
</div> </div>

View File

@ -23,7 +23,7 @@
@use '../features/options/MainOptions/MainOptions.scss'; @use '../features/options/MainOptions/MainOptions.scss';
@use '../features/options/AccordionItems/AdvancedSettings.scss'; @use '../features/options/AccordionItems/AdvancedSettings.scss';
@use '../features/options/AdvancedOptions/Upscale/UpscaleOptions.scss'; @use '../features/options/AdvancedOptions/Upscale/UpscaleOptions.scss';
@use '../features/options/AdvancedOptions/Inpainting/BoundingBoxSettings.scss'; @use '../features/options/AdvancedOptions/Inpainting/BoundingBoxSettings/BoundingBoxSettings.scss';
@use '../features/system/ProgressBar.scss'; @use '../features/system/ProgressBar.scss';
// gallery // gallery