First pass on Canvas options panel

This commit is contained in:
psychedelicious 2022-11-20 19:58:47 +11:00 committed by blessedcoolant
parent 7dff8ccd31
commit 80f6f9a931
8 changed files with 88 additions and 260 deletions

View File

@ -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"
/>
);
}

View File

@ -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
/>
);
}

View File

@ -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"
/>
);
}

View File

@ -24,7 +24,7 @@
}
p {
font-weight: bold;
// font-weight: bold;
}
}

View File

@ -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>
);

View File

@ -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}
/>
);
}

View File

@ -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>
);
}

View File

@ -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 />
</>
);
}