mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
First pass on Canvas options panel
This commit is contained in:
parent
7dff8ccd31
commit
80f6f9a931
@ -1,31 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import IAICheckbox from 'common/components/IAICheckbox';
|
||||
import { setShouldDarkenOutsideBoundingBox } from 'features/canvas/store/canvasSlice';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
|
||||
const selector = createSelector(
|
||||
canvasSelector,
|
||||
(canvas) => canvas.shouldDarkenOutsideBoundingBox
|
||||
);
|
||||
|
||||
export default function BoundingBoxDarkenOutside() {
|
||||
const dispatch = useAppDispatch();
|
||||
const shouldDarkenOutsideBoundingBox = useAppSelector(selector);
|
||||
|
||||
const handleChangeShouldShowBoundingBoxFill = () => {
|
||||
dispatch(
|
||||
setShouldDarkenOutsideBoundingBox(!shouldDarkenOutsideBoundingBox)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<IAICheckbox
|
||||
label="Darken Outside Box"
|
||||
isChecked={shouldDarkenOutsideBoundingBox}
|
||||
onChange={handleChangeShouldShowBoundingBoxFill}
|
||||
styleClass="inpainting-bounding-box-darken"
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
import React from 'react';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||
|
||||
import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
|
||||
import _ from 'lodash';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
|
||||
const selector = createSelector(
|
||||
canvasSelector,
|
||||
(canvas) => {
|
||||
const { stageDimensions, boundingBoxDimensions, shouldLockBoundingBox } =
|
||||
canvas;
|
||||
return {
|
||||
stageDimensions,
|
||||
boundingBoxDimensions,
|
||||
shouldLockBoundingBox,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: _.isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
type BoundingBoxDimensionSlidersType = {
|
||||
dimension: 'width' | 'height';
|
||||
label: string;
|
||||
};
|
||||
|
||||
export default function BoundingBoxDimensionSlider(
|
||||
props: BoundingBoxDimensionSlidersType
|
||||
) {
|
||||
const { dimension, label } = props;
|
||||
const dispatch = useAppDispatch();
|
||||
const { shouldLockBoundingBox, stageDimensions, boundingBoxDimensions } =
|
||||
useAppSelector(selector);
|
||||
|
||||
const canvasDimension = stageDimensions[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 (
|
||||
<IAISlider
|
||||
label={label}
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimension, 64)}
|
||||
step={64}
|
||||
value={boundingBoxDimension}
|
||||
onChange={handleBoundingBoxDimension}
|
||||
handleReset={handleResetDimension}
|
||||
isSliderDisabled={shouldLockBoundingBox}
|
||||
isInputDisabled={shouldLockBoundingBox}
|
||||
isResetDisabled={
|
||||
shouldLockBoundingBox || canvasDimension === boundingBoxDimension
|
||||
}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import IAICheckbox from 'common/components/IAICheckbox';
|
||||
import { setShouldLockBoundingBox } from 'features/canvas/store/canvasSlice';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
|
||||
const selector = createSelector(
|
||||
canvasSelector,
|
||||
(canvas) => canvas.shouldLockBoundingBox
|
||||
);
|
||||
|
||||
export default function BoundingBoxLock() {
|
||||
const shouldLockBoundingBox = useAppSelector(selector);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleChangeShouldLockBoundingBox = () => {
|
||||
dispatch(setShouldLockBoundingBox(!shouldLockBoundingBox));
|
||||
};
|
||||
return (
|
||||
<IAICheckbox
|
||||
label="Lock Bounding Box"
|
||||
isChecked={shouldLockBoundingBox}
|
||||
onChange={handleChangeShouldLockBoundingBox}
|
||||
styleClass="inpainting-bounding-box-darken"
|
||||
/>
|
||||
);
|
||||
}
|
@ -24,7 +24,7 @@
|
||||
}
|
||||
|
||||
p {
|
||||
font-weight: bold;
|
||||
// font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,97 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import BoundingBoxDarkenOutside from './BoundingBoxDarkenOutside';
|
||||
import BoundingBoxDimensionSlider from './BoundingBoxDimensionSlider';
|
||||
import BoundingBoxLock from './BoundingBoxLock';
|
||||
import BoundingBoxVisibility from './BoundingBoxVisibility';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||
import _ from 'lodash';
|
||||
|
||||
const selector = createSelector(
|
||||
canvasSelector,
|
||||
(canvas) => {
|
||||
const { boundingBoxDimensions } = canvas;
|
||||
return {
|
||||
boundingBoxDimensions,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: _.isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const BoundingBoxSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { boundingBoxDimensions } = useAppSelector(selector);
|
||||
|
||||
const handleChangeWidth = (v: number) => {
|
||||
dispatch(
|
||||
setBoundingBoxDimensions({
|
||||
...boundingBoxDimensions,
|
||||
width: Math.floor(v),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleChangeHeight = (v: number) => {
|
||||
dispatch(
|
||||
setBoundingBoxDimensions({
|
||||
...boundingBoxDimensions,
|
||||
height: Math.floor(v),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleResetWidth = () => {
|
||||
dispatch(
|
||||
setBoundingBoxDimensions({
|
||||
...boundingBoxDimensions,
|
||||
width: Math.floor(512),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleResetHeight = () => {
|
||||
dispatch(
|
||||
setBoundingBoxDimensions({
|
||||
...boundingBoxDimensions,
|
||||
height: Math.floor(512),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="inpainting-bounding-box-settings">
|
||||
<div className="inpainting-bounding-box-header">
|
||||
<p>Inpaint Box</p>
|
||||
<BoundingBoxVisibility />
|
||||
<p>Canvas Bounding Box</p>
|
||||
</div>
|
||||
<div className="inpainting-bounding-box-settings-items">
|
||||
<BoundingBoxDimensionSlider dimension="width" label="Box W" />
|
||||
<BoundingBoxDimensionSlider dimension="height" label="Box H" />
|
||||
<Flex alignItems={'center'} justifyContent={'space-between'}>
|
||||
<BoundingBoxDarkenOutside />
|
||||
<BoundingBoxLock />
|
||||
</Flex>
|
||||
<IAISlider
|
||||
label={'Width'}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
value={boundingBoxDimensions.width}
|
||||
onChange={handleChangeWidth}
|
||||
handleReset={handleResetWidth}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
/>
|
||||
<IAISlider
|
||||
label={'Height'}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
value={boundingBoxDimensions.height}
|
||||
onChange={handleChangeHeight}
|
||||
handleReset={handleResetHeight}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { BiHide, BiShow } from 'react-icons/bi';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import { setShouldShowBoundingBox } from 'features/canvas/store/canvasSlice';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
|
||||
const selector = createSelector(
|
||||
canvasSelector,
|
||||
(canvas) => canvas.shouldShowBoundingBox
|
||||
);
|
||||
|
||||
export default function BoundingBoxVisibility() {
|
||||
const shouldShowBoundingBox = useAppSelector(selector);
|
||||
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}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
import { useToast } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { setClearBrushHistory } from 'features/canvas/store/canvasSlice';
|
||||
import _ from 'lodash';
|
||||
|
||||
const selector = createSelector(
|
||||
canvasSelector,
|
||||
(canvas) => {
|
||||
const { pastLayerStates, futureLayerStates } = canvas;
|
||||
return {
|
||||
mayClearBrushHistory:
|
||||
futureLayerStates.length > 0 || pastLayerStates.length > 0
|
||||
? false
|
||||
: true,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: _.isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export default function ClearBrushHistory() {
|
||||
const dispatch = useAppDispatch();
|
||||
const toast = useToast();
|
||||
|
||||
const { mayClearBrushHistory } = useAppSelector(selector);
|
||||
|
||||
const handleClearBrushHistory = () => {
|
||||
dispatch(setClearBrushHistory());
|
||||
toast({
|
||||
title: 'Brush Stroke History Cleared',
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<IAIButton
|
||||
onClick={handleClearBrushHistory}
|
||||
tooltip="Clears brush stroke history"
|
||||
disabled={mayClearBrushHistory}
|
||||
styleClass="inpainting-options-btn"
|
||||
>
|
||||
Clear Brush History
|
||||
</IAIButton>
|
||||
);
|
||||
}
|
@ -1,13 +1,11 @@
|
||||
import BoundingBoxSettings from './BoundingBoxSettings/BoundingBoxSettings';
|
||||
import InpaintReplace from './InpaintReplace';
|
||||
import ClearBrushHistory from './ClearBrushHistory';
|
||||
|
||||
export default function InpaintingSettings() {
|
||||
return (
|
||||
<>
|
||||
<InpaintReplace />
|
||||
<BoundingBoxSettings />
|
||||
<ClearBrushHistory />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user