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 {
|
p {
|
||||||
font-weight: bold;
|
// font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,97 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import BoundingBoxDarkenOutside from './BoundingBoxDarkenOutside';
|
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import BoundingBoxDimensionSlider from './BoundingBoxDimensionSlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import BoundingBoxLock from './BoundingBoxLock';
|
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
import BoundingBoxVisibility from './BoundingBoxVisibility';
|
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 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 (
|
return (
|
||||||
<div className="inpainting-bounding-box-settings">
|
<div className="inpainting-bounding-box-settings">
|
||||||
<div className="inpainting-bounding-box-header">
|
<div className="inpainting-bounding-box-header">
|
||||||
<p>Inpaint Box</p>
|
<p>Canvas Bounding Box</p>
|
||||||
<BoundingBoxVisibility />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="inpainting-bounding-box-settings-items">
|
<div className="inpainting-bounding-box-settings-items">
|
||||||
<BoundingBoxDimensionSlider dimension="width" label="Box W" />
|
<IAISlider
|
||||||
<BoundingBoxDimensionSlider dimension="height" label="Box H" />
|
label={'Width'}
|
||||||
<Flex alignItems={'center'} justifyContent={'space-between'}>
|
min={64}
|
||||||
<BoundingBoxDarkenOutside />
|
max={1024}
|
||||||
<BoundingBoxLock />
|
step={64}
|
||||||
</Flex>
|
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>
|
||||||
</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 BoundingBoxSettings from './BoundingBoxSettings/BoundingBoxSettings';
|
||||||
import InpaintReplace from './InpaintReplace';
|
import InpaintReplace from './InpaintReplace';
|
||||||
import ClearBrushHistory from './ClearBrushHistory';
|
|
||||||
|
|
||||||
export default function InpaintingSettings() {
|
export default function InpaintingSettings() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InpaintReplace />
|
<InpaintReplace />
|
||||||
<BoundingBoxSettings />
|
<BoundingBoxSettings />
|
||||||
<ClearBrushHistory />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user